patchworks 0.11.5__tar.gz → 0.11.6__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 (69) hide show
  1. {patchworks-0.11.5 → patchworks-0.11.6}/PKG-INFO +1 -1
  2. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/profile/slurm/config.yaml +8 -6
  3. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/rules/common.smk +6 -0
  4. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/rules/convert.smk +2 -0
  5. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/rules/merge.smk +2 -0
  6. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/rules/segment.smk +4 -0
  7. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/scripts/_pw.py +51 -0
  8. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/scripts/convert.py +3 -0
  9. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/scripts/merge.py +2 -1
  10. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/scripts/prepare_tiles.py +2 -1
  11. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/scripts/segment_tile.py +2 -1
  12. {patchworks-0.11.5 → patchworks-0.11.6}/.github/workflows/docs.yml +0 -0
  13. {patchworks-0.11.5 → patchworks-0.11.6}/.github/workflows/lint.yml +0 -0
  14. {patchworks-0.11.5 → patchworks-0.11.6}/.github/workflows/release.yml +0 -0
  15. {patchworks-0.11.5 → patchworks-0.11.6}/.gitignore +0 -0
  16. {patchworks-0.11.5 → patchworks-0.11.6}/.markdownlint-cli2.yaml +0 -0
  17. {patchworks-0.11.5 → patchworks-0.11.6}/README.md +0 -0
  18. {patchworks-0.11.5 → patchworks-0.11.6}/cliff.toml +0 -0
  19. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/chunks.md +0 -0
  20. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/cluster.md +0 -0
  21. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/io.md +0 -0
  22. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/merge_tile_labels.md +0 -0
  23. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/plugins/cellpose.md +0 -0
  24. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/plugins/napari.md +0 -0
  25. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/plugins/ome_zarr.md +0 -0
  26. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/relabel.md +0 -0
  27. {patchworks-0.11.5 → patchworks-0.11.6}/docs/api/tile_process.md +0 -0
  28. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/cellpose_2d.md +0 -0
  29. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/cellpose_2d.py +0 -0
  30. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/cellpose_3d.md +0 -0
  31. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/cellpose_3d.py +0 -0
  32. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/custom.md +0 -0
  33. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/custom_method.py +0 -0
  34. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/standalone_merge.md +0 -0
  35. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/stardist.md +0 -0
  36. {patchworks-0.11.5 → patchworks-0.11.6}/docs/examples/stardist_2d.py +0 -0
  37. {patchworks-0.11.5 → patchworks-0.11.6}/docs/getting_started.md +0 -0
  38. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/gpu_distributed.md +0 -0
  39. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/merging.md +0 -0
  40. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/ome_zarr_napari.md +0 -0
  41. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/performance.md +0 -0
  42. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/pitfalls.md +0 -0
  43. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/skip_empty.md +0 -0
  44. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/snakemake.md +0 -0
  45. {patchworks-0.11.5 → patchworks-0.11.6}/docs/guide/tiling.md +0 -0
  46. {patchworks-0.11.5 → patchworks-0.11.6}/docs/index.md +0 -0
  47. {patchworks-0.11.5 → patchworks-0.11.6}/mkdocs.yml +0 -0
  48. {patchworks-0.11.5 → patchworks-0.11.6}/pyproject.toml +0 -0
  49. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/__init__.py +0 -0
  50. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_chunks.py +0 -0
  51. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_cluster.py +0 -0
  52. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_core.py +0 -0
  53. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_distributed.py +0 -0
  54. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_io.py +0 -0
  55. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_merge.py +0 -0
  56. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/_relabel.py +0 -0
  57. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/plugins/__init__.py +0 -0
  58. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/plugins/cellpose.py +0 -0
  59. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/plugins/napari.py +0 -0
  60. {patchworks-0.11.5 → patchworks-0.11.6}/src/patchworks/plugins/ome_zarr.py +0 -0
  61. {patchworks-0.11.5 → patchworks-0.11.6}/tests/test_core.py +0 -0
  62. {patchworks-0.11.5 → patchworks-0.11.6}/tests/test_distributed.py +0 -0
  63. {patchworks-0.11.5 → patchworks-0.11.6}/tests/test_napari.py +0 -0
  64. {patchworks-0.11.5 → patchworks-0.11.6}/tests/test_ome_zarr.py +0 -0
  65. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/.snakemake/iocache/latest.pkl +0 -0
  66. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/README.md +0 -0
  67. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/Snakefile +0 -0
  68. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/config/config.yaml +0 -0
  69. {patchworks-0.11.5 → patchworks-0.11.6}/workflow/pixi.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: patchworks
3
- Version: 0.11.5
3
+ Version: 0.11.6
4
4
  Summary: Tiled processing of arbitrarily large images with globally consistent labels
5
5
  Project-URL: Homepage, https://github.com/imcf/patchworks
6
6
  Project-URL: Issues, https://github.com/imcf/patchworks/issues
@@ -17,7 +17,7 @@ keep-going: true
17
17
 
18
18
  # Defaults for every rule (CPU jobs).
19
19
  default-resources:
20
- slurm_partition: "cpu"
20
+ slurm_partition: "scicore"
21
21
  # slurm_account: "my_account"
22
22
  mem_mb: 16000
23
23
  cpus_per_task: 4
@@ -32,12 +32,14 @@ set-resources:
32
32
  prepare:
33
33
  mem_mb: 32000
34
34
  runtime: 120
35
- segment: # one GPU per tile — this is what spreads Cellpose across GPUs
36
- slurm_partition: "gpu"
37
- slurm_extra: "'--gres=gpu:1'"
38
- mem_mb: 32000
35
+ segment:
36
+ # one GPU per tile — this is what spreads Cellpose across GPUs
37
+ slurm_partition: "rtx4090"
38
+ gpu: 1
39
+ qos: "rtx4090-6hours" # scicore: <partition>-<duration> QOS
40
+ mem_mb: 32000 # plenty — a tile used ~1G; the failure was a Python error
39
41
  cpus_per_task: 4
40
- runtime: 120
42
+ runtime: 360 # 6 hours — must match the QOS, NOT 120 (=2h → killed early)
41
43
  merge:
42
44
  mem_mb: 128000
43
45
  cpus_per_task: 8
@@ -15,6 +15,12 @@ STAGE = f"{WORK}/stage.zarr"
15
15
  STAGE_OK = f"{STAGE}.done"
16
16
 
17
17
 
18
+ # Logs: one shared file for the sequential CPU steps (convert/prepare/merge),
19
+ # one file per tile for the GPU segment jobs.
20
+ LOGS = f"{WORK}/logs"
21
+ STEPLOG = f"{LOGS}/steps.log"
22
+
23
+
18
24
  def occupied_done(wildcards):
19
25
  """Per-tile markers for the occupied tiles (resolved after the checkpoint)."""
20
26
  tiles = checkpoints.prepare.get().output.tiles
@@ -4,5 +4,7 @@ rule convert:
4
4
  output:
5
5
  # marker file inside the store; existence => skip re-conversion.
6
6
  IMAGE_OK,
7
+ log:
8
+ STEPLOG,
7
9
  script:
8
10
  "../scripts/convert.py"
@@ -5,5 +5,7 @@ rule merge:
5
5
  occupied_done,
6
6
  output:
7
7
  touch(f"{WORK}/labels.done"),
8
+ log:
9
+ STEPLOG,
8
10
  script:
9
11
  "../scripts/merge.py"
@@ -6,6 +6,8 @@ checkpoint prepare:
6
6
  output:
7
7
  tiles=TILES,
8
8
  stage=touch(STAGE_OK),
9
+ log:
10
+ STEPLOG,
9
11
  script:
10
12
  "../scripts/prepare_tiles.py"
11
13
 
@@ -18,5 +20,7 @@ rule segment:
18
20
  image=IMAGE_OK,
19
21
  output:
20
22
  f"{WORK}/seg/{{index}}.done",
23
+ log:
24
+ f"{LOGS}/segment/{{index}}.log",
21
25
  script:
22
26
  "../scripts/segment_tile.py"
@@ -8,11 +8,62 @@ these helpers only turn the Snakemake config into the right arguments.
8
8
  from __future__ import annotations
9
9
 
10
10
  import json
11
+ import logging
12
+ import sys
11
13
  from pathlib import Path
12
14
 
13
15
  from patchworks import load_ome_zarr
14
16
 
15
17
 
18
+ class _Tee:
19
+ """Write to several streams at once (e.g. the SLURM log and a file)."""
20
+
21
+ def __init__(self, *streams):
22
+ self._streams = streams
23
+
24
+ def write(self, data):
25
+ for stream in self._streams:
26
+ stream.write(data)
27
+
28
+ def flush(self):
29
+ for stream in self._streams:
30
+ stream.flush()
31
+
32
+
33
+ def start_log(path, *, append=True):
34
+ """Tee stdout/stderr (and logging) into ``path``.
35
+
36
+ Captures prints, tracebacks and library logging into a file in the work
37
+ directory, independent of the (often empty) SLURM job log. Line-buffered,
38
+ so output up to a crash or OOM kill is preserved.
39
+
40
+ Parameters
41
+ ----------
42
+ path : str or Path
43
+ Log file to write. Parent directories are created.
44
+ append : bool, optional
45
+ Append to an existing log (keep retry history) instead of truncating.
46
+ Default True.
47
+
48
+ Returns
49
+ -------
50
+ TextIO
51
+ The open log file (kept open for the lifetime of the process).
52
+ """
53
+ path = Path(path)
54
+ path.parent.mkdir(parents=True, exist_ok=True)
55
+ handle = open(path, "a" if append else "w", buffering=1)
56
+ sys.stdout = _Tee(sys.__stdout__, handle)
57
+ sys.stderr = _Tee(sys.__stderr__, handle)
58
+ logging.basicConfig(
59
+ level=logging.INFO,
60
+ format="%(asctime)s %(levelname)s %(name)s: %(message)s",
61
+ handlers=[logging.StreamHandler(sys.stdout)],
62
+ force=True,
63
+ )
64
+ return handle
65
+
66
+
16
67
  def open_image(work_dir, channel, level):
17
68
  """Open the converted image for segmentation.
18
69
 
@@ -8,6 +8,9 @@ conversion is not redone. To force a fresh conversion, delete ``image.zarr``
8
8
 
9
9
  from patchworks.plugins.ome_zarr import to_ome_zarr
10
10
 
11
+ from _pw import start_log
12
+
13
+ start_log(snakemake.log[0]) # noqa: F821
11
14
  cfg = snakemake.config # noqa: F821 (injected by Snakemake)
12
15
  chunks = cfg.get("convert_chunks")
13
16
  to_ome_zarr(
@@ -11,8 +11,9 @@ from pathlib import Path
11
11
  from patchworks import merge_tile_labels
12
12
  from patchworks.plugins.ome_zarr import write_labels
13
13
 
14
- from _pw import stage_path
14
+ from _pw import stage_path, start_log
15
15
 
16
+ start_log(snakemake.log[0]) # noqa: F821
16
17
  cfg = snakemake.config # noqa: F821
17
18
  work_dir = cfg["work_dir"]
18
19
  image_store = str(Path(work_dir) / "image.zarr")
@@ -11,8 +11,9 @@ from patchworks import (
11
11
  spatial_tiles,
12
12
  )
13
13
 
14
- from _pw import open_image, stage_path
14
+ from _pw import open_image, stage_path, start_log
15
15
 
16
+ start_log(snakemake.log[0]) # noqa: F821
16
17
  cfg = snakemake.config # noqa: F821
17
18
  work_dir = cfg["work_dir"]
18
19
  image = open_image(work_dir, cfg["channel"], cfg["level"])
@@ -6,8 +6,9 @@ run in parallel. Each job writes a disjoint chunk of the stage store.
6
6
 
7
7
  from patchworks import stage_tile
8
8
 
9
- from _pw import build_fn, load_tiles_json, open_image, stage_path
9
+ from _pw import build_fn, load_tiles_json, open_image, stage_path, start_log
10
10
 
11
+ start_log(snakemake.log[0]) # noqa: F821
11
12
  cfg = snakemake.config # noqa: F821
12
13
  index = int(snakemake.wildcards.index) # noqa: F821
13
14
  work_dir = cfg["work_dir"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes