slide2vec 4.6.2__tar.gz → 4.6.4__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 (97) hide show
  1. {slide2vec-4.6.2 → slide2vec-4.6.4}/PKG-INFO +1 -1
  2. {slide2vec-4.6.2 → slide2vec-4.6.4}/pyproject.toml +2 -2
  3. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/__init__.py +1 -1
  4. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/conch.py +12 -0
  5. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/hibou.py +6 -0
  6. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/midnight.py +6 -0
  7. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/musk.py +5 -0
  8. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/config.py +25 -7
  9. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/PKG-INFO +1 -1
  10. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_regression_core.py +28 -0
  11. {slide2vec-4.6.2 → slide2vec-4.6.4}/LICENSE +0 -0
  12. {slide2vec-4.6.2 → slide2vec-4.6.4}/README.md +0 -0
  13. {slide2vec-4.6.2 → slide2vec-4.6.4}/setup.cfg +0 -0
  14. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/__main__.py +0 -0
  15. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/api.py +0 -0
  16. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/artifacts.py +0 -0
  17. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/cli.py +0 -0
  18. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/configs/__init__.py +0 -0
  19. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/configs/default.yaml +0 -0
  20. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/configs/resources.py +0 -0
  21. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/data/__init__.py +0 -0
  22. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/data/dataset.py +0 -0
  23. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/data/tile_reader.py +0 -0
  24. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/data/tile_store.py +0 -0
  25. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/distributed/__init__.py +0 -0
  26. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/distributed/direct_embed_worker.py +0 -0
  27. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/distributed/pipeline_worker.py +0 -0
  28. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/__init__.py +0 -0
  29. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/base.py +0 -0
  30. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/__init__.py +0 -0
  31. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/gigapath.py +0 -0
  32. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/hoptimus.py +0 -0
  33. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/lunit.py +0 -0
  34. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/__init__.py +0 -0
  35. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/blocks.py +0 -0
  36. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/case.py +0 -0
  37. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/loading.py +0 -0
  38. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/slide.py +0 -0
  39. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/moozy/types.py +0 -0
  40. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/phikon.py +0 -0
  41. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/prism.py +0 -0
  42. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/prost40m.py +0 -0
  43. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/titan.py +0 -0
  44. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/uni.py +0 -0
  45. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/models/virchow.py +0 -0
  46. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/registry.py +0 -0
  47. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/encoders/validation.py +0 -0
  48. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/inference.py +0 -0
  49. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/progress.py +0 -0
  50. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/__init__.py +0 -0
  51. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/artifacts_collect.py +0 -0
  52. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/batching.py +0 -0
  53. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/cpu_budget.py +0 -0
  54. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/distributed.py +0 -0
  55. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/distributed_stage.py +0 -0
  56. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/embedding.py +0 -0
  57. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/embedding_persist.py +0 -0
  58. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/embedding_pipeline.py +0 -0
  59. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/hierarchical.py +0 -0
  60. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/manifest.py +0 -0
  61. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/model_settings.py +0 -0
  62. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/patient_pipeline.py +0 -0
  63. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/persist_callbacks.py +0 -0
  64. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/persistence.py +0 -0
  65. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/process_list.py +0 -0
  66. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/progress_bridge.py +0 -0
  67. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/registry.py +0 -0
  68. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/serialization.py +0 -0
  69. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/slide_encode.py +0 -0
  70. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/tiling.py +0 -0
  71. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/tiling_pipeline.py +0 -0
  72. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/types.py +0 -0
  73. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/runtime/worker_io.py +0 -0
  74. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/__init__.py +0 -0
  75. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/coordinates.py +0 -0
  76. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/log_utils.py +0 -0
  77. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/tiling_io.py +0 -0
  78. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec/utils/utils.py +0 -0
  79. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/SOURCES.txt +0 -0
  80. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/dependency_links.txt +0 -0
  81. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/entry_points.txt +0 -0
  82. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/not-zip-safe +0 -0
  83. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/requires.txt +0 -0
  84. {slide2vec-4.6.2 → slide2vec-4.6.4}/slide2vec.egg-info/top_level.txt +0 -0
  85. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_architecture_runtime_split.py +0 -0
  86. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_attention_extraction.py +0 -0
  87. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_dense_extraction.py +0 -0
  88. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_dense_locality_gated.py +0 -0
  89. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_encoder_registry.py +0 -0
  90. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_hs2p_package_cutover.py +0 -0
  91. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_output_consistency.py +0 -0
  92. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_progress.py +0 -0
  93. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_regression_inference.py +0 -0
  94. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_regression_models.py +0 -0
  95. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_runtime_batching.py +0 -0
  96. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_tile_store.py +0 -0
  97. {slide2vec-4.6.2 → slide2vec-4.6.4}/tests/test_tiling_pipeline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slide2vec
3
- Version: 4.6.2
3
+ Version: 4.6.4
4
4
  Summary: Embedding of whole slide images with Foundation Models
5
5
  Author-email: Clément Grisi <clement.grisi@radboudumc.nl>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "slide2vec"
7
- version = "4.6.2"
7
+ version = "4.6.4"
8
8
  description = "Embedding of whole slide images with Foundation Models"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -164,7 +164,7 @@ no_implicit_reexport = true
164
164
  max-line-length = 160
165
165
 
166
166
  [tool.bumpver]
167
- current_version = "4.6.2"
167
+ current_version = "4.6.4"
168
168
  version_pattern = "MAJOR.MINOR.PATCH"
169
169
  commit = false # We do version bumping in CI, not as a commit
170
170
  tag = false # Git tag already exists — we don't auto-tag
@@ -11,7 +11,7 @@ from slide2vec.api import (
11
11
  from slide2vec.artifacts import HierarchicalEmbeddingArtifact, SlideEmbeddingArtifact, TileEmbeddingArtifact
12
12
 
13
13
 
14
- __version__ = "4.6.2"
14
+ __version__ = "4.6.4"
15
15
 
16
16
  __all__ = [
17
17
  "Model",
@@ -141,6 +141,13 @@ class CONCH(TileEncoder):
141
141
  def encode_dim(self) -> int:
142
142
  return 512
143
143
 
144
+ @property
145
+ def patch_size(self) -> tuple[int, int]:
146
+ # The CONCH vision trunk is a timm ViT-B/16; expose its patch size so the
147
+ # dense path can resolve the token grid. open_clip builds the trunk without
148
+ # dynamic_img_size, so dense extraction must use the native 448 window.
149
+ return _patch_size_from_trunk(self._model.visual.trunk)
150
+
144
151
  @property
145
152
  def device(self) -> torch.device:
146
153
  return self._device
@@ -204,6 +211,11 @@ class CONCHv15(TileEncoder):
204
211
  def encode_dim(self) -> int:
205
212
  return 768
206
213
 
214
+ @property
215
+ def patch_size(self) -> tuple[int, int]:
216
+ # CONCHv15's TITAN trunk is a timm ViT; expose its patch size for the dense path.
217
+ return _patch_size_from_trunk(self._model.trunk)
218
+
207
219
  @property
208
220
  def device(self) -> torch.device:
209
221
  return self._device
@@ -123,6 +123,12 @@ class _HibouBase(TileEncoder):
123
123
  def encode_dim(self) -> int:
124
124
  return self._encode_dim
125
125
 
126
+ @property
127
+ def patch_size(self) -> tuple[int, int]:
128
+ # HF Dinov2-style config carries the patch size; expose it for the dense path.
129
+ patch = int(self._model.config.patch_size)
130
+ return patch, patch
131
+
126
132
  @property
127
133
  def device(self) -> torch.device:
128
134
  return self._device
@@ -124,6 +124,12 @@ class Midnight(TileEncoder):
124
124
  def encode_dim(self) -> int:
125
125
  return 3072
126
126
 
127
+ @property
128
+ def patch_size(self) -> tuple[int, int]:
129
+ # HF Dinov2-style config carries the patch size; expose it for the dense path.
130
+ patch = int(self._model.config.patch_size)
131
+ return patch, patch
132
+
127
133
  @property
128
134
  def device(self) -> torch.device:
129
135
  return self._device
@@ -114,6 +114,11 @@ class MUSK(TileEncoder):
114
114
  def encode_dim(self) -> int:
115
115
  return 2048 if self._output_variant == "ms_aug" else 1024 # cls
116
116
 
117
+ @property
118
+ def patch_size(self) -> tuple[int, int]:
119
+ # BEiT3 vision embedding carries the patch size; expose it for the dense path.
120
+ return _as_hw(self._model.beit3.vision_embed.patch_size)
121
+
117
122
  @property
118
123
  def device(self) -> torch.device:
119
124
  return self._device
@@ -41,6 +41,21 @@ def _encoder_derived_cfg(model_name: str) -> dict:
41
41
  }
42
42
 
43
43
 
44
+ def _fill_null_encoder_defaults(cfg, encoder_defaults: dict) -> None:
45
+ """Fill null leaves with encoder defaults after user/CLI config merging."""
46
+ defaults_cfg = OmegaConf.create(encoder_defaults)
47
+ for path in (
48
+ "tiling.params.requested_tile_size_px",
49
+ "tiling.params.requested_spacing_um",
50
+ "speed.precision",
51
+ ):
52
+ if OmegaConf.select(cfg, path) is not None:
53
+ continue
54
+ default_value = OmegaConf.select(defaults_cfg, path)
55
+ if default_value is not None:
56
+ OmegaConf.update(cfg, path, default_value, merge=False)
57
+
58
+
44
59
  def validate_model_recommended_settings(cfg, *, run_on_cpu: bool = False) -> None:
45
60
  from slide2vec.encoders.registry import encoder_registry
46
61
  from slide2vec.encoders.validation import validate_encoder_config
@@ -88,14 +103,17 @@ def get_cfg_from_args(args):
88
103
 
89
104
  default_cfg = OmegaConf.create(default_config)
90
105
  model_name = OmegaConf.select(requested_cfg, "model.name")
91
- spacing = OmegaConf.select(requested_cfg, "tiling.params.requested_spacing_um")
92
- tile_size = OmegaConf.select(requested_cfg, "tiling.params.requested_tile_size_px")
93
- if model_name and (spacing is None or tile_size is None):
94
- encoder_defaults = _encoder_derived_cfg(model_name)
95
- if encoder_defaults:
96
- default_cfg = OmegaConf.merge(default_cfg, OmegaConf.create(encoder_defaults))
97
-
98
106
  cfg = OmegaConf.merge(default_cfg, user_cfg, cli_cfg)
107
+ if model_name and any(
108
+ OmegaConf.select(cfg, path) is None
109
+ for path in (
110
+ "tiling.params.requested_tile_size_px",
111
+ "tiling.params.requested_spacing_um",
112
+ "speed.precision",
113
+ )
114
+ ):
115
+ encoder_defaults = _encoder_derived_cfg(model_name)
116
+ _fill_null_encoder_defaults(cfg, encoder_defaults)
99
117
  OmegaConf.resolve(cfg)
100
118
  validate_model_recommended_settings(cfg, run_on_cpu=bool(getattr(args, "run_on_cpu", False)))
101
119
  return cfg
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: slide2vec
3
- Version: 4.6.2
3
+ Version: 4.6.4
4
4
  Summary: Embedding of whole slide images with Foundation Models
5
5
  Author-email: Clément Grisi <clement.grisi@radboudumc.nl>
6
6
  License-Expression: Apache-2.0
@@ -79,6 +79,34 @@ def test_get_cfg_from_args_fills_missing_preprocessing_from_single_spacing_model
79
79
  assert cfg.tiling.params.requested_tile_size_px == 448
80
80
 
81
81
 
82
+ def test_get_cfg_from_args_fills_null_spacing_from_model_default(tmp_path: Path):
83
+ pytest.importorskip("omegaconf")
84
+
85
+ from slide2vec.utils.config import get_cfg_from_args
86
+
87
+ cfg_path = tmp_path / "config.yaml"
88
+ cfg_path.write_text(
89
+ "\n".join(
90
+ [
91
+ "csv: /tmp/slides.csv",
92
+ "output_dir: /tmp/output",
93
+ "model:",
94
+ " name: conchv15",
95
+ "tiling:",
96
+ " params:",
97
+ " requested_spacing_um:",
98
+ " requested_tile_size_px: 448",
99
+ ]
100
+ )
101
+ )
102
+ args = SimpleNamespace(config_file=str(cfg_path), output_dir=None, opts=[], run_on_cpu=False)
103
+
104
+ cfg = get_cfg_from_args(args)
105
+
106
+ assert cfg.tiling.params.requested_spacing_um == pytest.approx(0.5)
107
+ assert cfg.tiling.params.requested_tile_size_px == 448
108
+
109
+
82
110
  def test_get_cfg_from_args_rejects_models_with_ambiguous_spacing_defaults(tmp_path: Path):
83
111
  pytest.importorskip("omegaconf")
84
112
 
File without changes
File without changes
File without changes
File without changes
File without changes