euler-eval 2.10.0__tar.gz → 2.11.0__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 (56) hide show
  1. {euler_eval-2.10.0 → euler_eval-2.11.0}/PKG-INFO +1 -1
  2. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/cli.py +5 -25
  3. euler_eval-2.11.0/euler_eval/config_paths.py +125 -0
  4. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/data.py +3 -3
  5. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/PKG-INFO +1 -1
  6. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/SOURCES.txt +1 -0
  7. {euler_eval-2.10.0 → euler_eval-2.11.0}/pyproject.toml +1 -1
  8. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_config.py +19 -0
  9. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_data_builders.py +11 -0
  10. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_save_results.py +15 -0
  11. {euler_eval-2.10.0 → euler_eval-2.11.0}/README.md +0 -0
  12. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/__init__.py +0 -0
  13. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/evaluate.py +0 -0
  14. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/__init__.py +0 -0
  15. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/absrel.py +0 -0
  16. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/daniel_error.py +0 -0
  17. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_binned_error.py +0 -0
  18. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_edge_f1.py +0 -0
  19. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/depth_standard.py +0 -0
  20. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/fid_kid.py +0 -0
  21. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/gpu_depth_batch.py +0 -0
  22. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/gpu_image_batch.py +0 -0
  23. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/high_freq_energy.py +0 -0
  24. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/lpips_metric.py +0 -0
  25. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/normal_consistency.py +0 -0
  26. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/psnr.py +0 -0
  27. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_edge_f1.py +0 -0
  28. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_lpips.py +0 -0
  29. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rgb_psnr_ssim.py +0 -0
  30. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rho_a.py +0 -0
  31. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/rmse.py +0 -0
  32. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/scale_invariant_log.py +0 -0
  33. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/ssim.py +0 -0
  34. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/tail_errors.py +0 -0
  35. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/metrics/utils.py +0 -0
  36. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/sanity_checker.py +0 -0
  37. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval/utils/hierarchy_parser.py +0 -0
  38. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/dependency_links.txt +0 -0
  39. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/entry_points.txt +0 -0
  40. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/requires.txt +0 -0
  41. {euler_eval-2.10.0 → euler_eval-2.11.0}/euler_eval.egg-info/top_level.txt +0 -0
  42. {euler_eval-2.10.0 → euler_eval-2.11.0}/init_cache.py +0 -0
  43. {euler_eval-2.10.0 → euler_eval-2.11.0}/setup.cfg +0 -0
  44. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_alignment.py +0 -0
  45. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_cli_device.py +0 -0
  46. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_data.py +0 -0
  47. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_depth_alignment_output.py +0 -0
  48. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_depth_standard.py +0 -0
  49. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_evaluate_helpers.py +0 -0
  50. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_init_cache.py +0 -0
  51. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_integration.py +0 -0
  52. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_meta_output.py +0 -0
  53. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_metrics_utils.py +0 -0
  54. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_rgb_fid_output.py +0 -0
  55. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_rho_a.py +0 -0
  56. {euler_eval-2.10.0 → euler_eval-2.11.0}/tests/test_sparse_depth.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: euler-eval
3
- Version: 2.10.0
3
+ Version: 2.11.0
4
4
  Summary: Depth map evaluation toolkit with comprehensive metrics
5
5
  Author: Depth Eval Contributors
6
6
  License: MIT
@@ -13,8 +13,8 @@ import zipfile
13
13
  from pathlib import Path
14
14
 
15
15
  import torch
16
- from euler_loading import Modality
17
16
 
17
+ from .config_paths import normalize_modality_path
18
18
  from .data import (
19
19
  build_depth_eval_dataset,
20
20
  build_rays_eval_dataset,
@@ -41,22 +41,6 @@ except ImportError:
41
41
  from euler_metric_naming import AxisDeclaration, MetricDescription, MetricNamespace
42
42
 
43
43
 
44
- def _normalize_modality_path(
45
- path: str | Path,
46
- *,
47
- modality_key: str,
48
- split: str | None = None,
49
- ) -> Path:
50
- """Return the filesystem/archive root for an euler-loading modality path."""
51
- modality = Modality(
52
- str(path),
53
- modality_type=modality_key,
54
- metadata_scope=modality_key,
55
- split=split,
56
- )
57
- return Path(modality.path)
58
-
59
-
60
44
  # ── Eval namespace ──────────────────────────────────────────────────────────
61
45
  # MetricNamespace subclass for eval context with custom axis declarations,
62
46
  # following the Normed Metric Namespacing convention (§3.6, §4, §5.2).
@@ -616,9 +600,8 @@ def validate_gt_config(gt: dict) -> None:
616
600
  "camera_extrinsics",
617
601
  ):
618
602
  if modality in gt and "path" in gt[modality]:
619
- p = _normalize_modality_path(
603
+ p = normalize_modality_path(
620
604
  gt[modality]["path"],
621
- modality_key=modality,
622
605
  split=gt[modality].get("split"),
623
606
  )
624
607
  if not p.exists():
@@ -645,9 +628,8 @@ def validate_dataset_entry(entry: dict, index: int) -> None:
645
628
 
646
629
  for modality in ("rgb", "depth", "rays"):
647
630
  if modality in entry and "path" in entry[modality]:
648
- p = _normalize_modality_path(
631
+ p = normalize_modality_path(
649
632
  entry[modality]["path"],
650
- modality_key=modality,
651
633
  split=entry[modality].get("split"),
652
634
  )
653
635
  if not p.exists():
@@ -775,9 +757,8 @@ def save_results(
775
757
  and "path" in dataset_config[modality]
776
758
  ):
777
759
  output_file = (
778
- _normalize_modality_path(
760
+ normalize_modality_path(
779
761
  dataset_config[modality]["path"],
780
- modality_key=modality,
781
762
  split=dataset_config[modality].get("split"),
782
763
  )
783
764
  / "eval.json"
@@ -787,9 +768,8 @@ def save_results(
787
768
  for mod in ("depth", "rgb", "rays"):
788
769
  if mod in dataset_config and "path" in dataset_config[mod]:
789
770
  output_file = (
790
- _normalize_modality_path(
771
+ normalize_modality_path(
791
772
  dataset_config[mod]["path"],
792
- modality_key=mod,
793
773
  split=dataset_config[mod].get("split"),
794
774
  )
795
775
  / "eval.json"
@@ -0,0 +1,125 @@
1
+ """Helpers for euler-loading modality path selectors in config files."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from urllib.parse import parse_qsl
8
+
9
+ from ds_crawler import validate_metadata_scope
10
+ from ds_crawler.zip_utils import validate_split_name
11
+ from euler_loading import Modality
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class ModalityPath:
16
+ path: str
17
+ split: str | None = None
18
+ metadata_scope: str | None = None
19
+
20
+
21
+ def _parse_inline_scope(path: str) -> tuple[str, str | None]:
22
+ candidate_path, sep, fragment = path.rpartition("#")
23
+ if not sep:
24
+ return path, None
25
+
26
+ params = parse_qsl(fragment, keep_blank_values=True)
27
+ scope_values = [value for key, value in params if key == "scope"]
28
+ if not scope_values:
29
+ return path, None
30
+
31
+ unsupported = [key for key, _ in params if key != "scope"]
32
+ if unsupported:
33
+ raise ValueError(
34
+ "Unsupported modality path fragment parameter(s): "
35
+ f"{', '.join(sorted(set(unsupported)))}. "
36
+ "Only '#scope=<metadata_scope>' is supported."
37
+ )
38
+ if len(scope_values) > 1:
39
+ raise ValueError("Modality path may contain at most one '#scope=' selector.")
40
+
41
+ return candidate_path, validate_metadata_scope(scope_values[0])
42
+
43
+
44
+ def _parse_inline_split(path: str) -> tuple[str, str | None]:
45
+ colon_pos = path.rfind(":")
46
+ if colon_pos <= 1:
47
+ return path, None
48
+
49
+ candidate_split = path[colon_pos + 1 :]
50
+ candidate_path = path[:colon_pos]
51
+
52
+ try:
53
+ split = validate_split_name(candidate_split)
54
+ except ValueError:
55
+ return path, None
56
+
57
+ return candidate_path, split
58
+
59
+
60
+ def parse_modality_path(
61
+ path: str | Path,
62
+ *,
63
+ split: str | None = None,
64
+ metadata_scope: str | None = None,
65
+ ) -> ModalityPath:
66
+ """Parse euler-loading inline split/scope selectors from a config path."""
67
+ raw_path = str(path)
68
+ parsed_path, inline_scope = _parse_inline_scope(raw_path)
69
+ parsed_path, inline_split = _parse_inline_split(parsed_path)
70
+
71
+ if inline_split is not None and split is not None:
72
+ raise ValueError(
73
+ f"Modality path {raw_path!r} contains an inline split "
74
+ f"({inline_split!r}) but an explicit split={split!r} was also "
75
+ "provided. Use one or the other, not both."
76
+ )
77
+
78
+ normalized_scope = (
79
+ validate_metadata_scope(metadata_scope)
80
+ if metadata_scope is not None
81
+ else None
82
+ )
83
+ if inline_scope is not None:
84
+ if normalized_scope is not None and normalized_scope != inline_scope:
85
+ raise ValueError(
86
+ f"Modality path {raw_path!r} contains an inline metadata scope "
87
+ f"({inline_scope!r}) but an explicit "
88
+ f"metadata_scope={metadata_scope!r} was also provided. Use one "
89
+ "metadata scope selector."
90
+ )
91
+ normalized_scope = inline_scope
92
+
93
+ return ModalityPath(
94
+ path=parsed_path,
95
+ split=split if split is not None else inline_split,
96
+ metadata_scope=normalized_scope,
97
+ )
98
+
99
+
100
+ def normalize_modality_path(path: str | Path, *, split: str | None = None) -> Path:
101
+ """Return the filesystem/archive root for a config modality path."""
102
+ return Path(parse_modality_path(path, split=split).path)
103
+
104
+
105
+ def build_modality(
106
+ *,
107
+ path: str | Path,
108
+ modality_key: str,
109
+ split: str | None = None,
110
+ loader=None,
111
+ used_as: str | None = None,
112
+ ) -> Modality:
113
+ """Create a Modality after parsing inline config selectors locally."""
114
+ parsed = parse_modality_path(
115
+ path,
116
+ split=split,
117
+ )
118
+ return Modality(
119
+ path=parsed.path,
120
+ loader=loader,
121
+ used_as=used_as,
122
+ modality_type=modality_key,
123
+ metadata_scope=parsed.metadata_scope or modality_key,
124
+ split=parsed.split,
125
+ )
@@ -13,6 +13,7 @@ import torch
13
13
  from ds_crawler import get_dataset_contract, index_dataset_from_path
14
14
  from euler_loading import Modality, MultiModalDataset, resolve_loader_module
15
15
 
16
+ from .config_paths import build_modality
16
17
  from .metrics.utils import convert_planar_to_radial
17
18
 
18
19
  # ---------------------------------------------------------------------------
@@ -574,12 +575,11 @@ def _modality(
574
575
  used_as: Optional[str] = None,
575
576
  ) -> Modality:
576
577
  """Create an euler-loading modality with an explicit metadata selector."""
577
- return Modality(
578
+ return build_modality(
578
579
  path=path,
579
580
  loader=loader,
580
581
  used_as=used_as,
581
- modality_type=modality_key,
582
- metadata_scope=modality_key,
582
+ modality_key=modality_key,
583
583
  split=split,
584
584
  )
585
585
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: euler-eval
3
- Version: 2.10.0
3
+ Version: 2.11.0
4
4
  Summary: Depth map evaluation toolkit with comprehensive metrics
5
5
  Author: Depth Eval Contributors
6
6
  License: MIT
@@ -3,6 +3,7 @@ init_cache.py
3
3
  pyproject.toml
4
4
  euler_eval/__init__.py
5
5
  euler_eval/cli.py
6
+ euler_eval/config_paths.py
6
7
  euler_eval/data.py
7
8
  euler_eval/evaluate.py
8
9
  euler_eval/sanity_checker.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "euler-eval"
7
- version = "2.10.0"
7
+ version = "2.11.0"
8
8
  description = "Depth map evaluation toolkit with comprehensive metrics"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -65,6 +65,25 @@ class TestValidateGtConfig:
65
65
  gt = {"rgb": {"path": f"{rgb_path}#scope=rgb"}}
66
66
  validate_gt_config(gt)
67
67
 
68
+ def test_inline_scope_intrinsics_gt_path_is_valid(self, tmp_path):
69
+ depth_path = tmp_path / "depth"
70
+ depth_path.mkdir()
71
+ intrinsics_path = tmp_path / "frame_camera_trainvaltest.zip"
72
+ with zipfile.ZipFile(intrinsics_path, "w") as zf:
73
+ zf.writestr("dummy.txt", "x")
74
+ gt = {
75
+ "depth": {"path": str(depth_path)},
76
+ "intrinsics": {"path": f"{intrinsics_path}#scope=intrinsics"},
77
+ }
78
+ validate_gt_config(gt)
79
+
80
+ def test_inline_split_and_scope_gt_path_is_valid(self, tmp_path):
81
+ rgb_path = tmp_path / "reference.zip"
82
+ with zipfile.ZipFile(rgb_path, "w") as zf:
83
+ zf.writestr("dummy.txt", "x")
84
+ gt = {"rgb": {"path": f"{rgb_path}:fog_day#scope=rgb"}}
85
+ validate_gt_config(gt)
86
+
68
87
  def test_sparse_depth_requires_projection_modalities(self, tmp_path):
69
88
  sparse_path = tmp_path / "sparse_depth"
70
89
  sparse_path.mkdir()
@@ -192,3 +192,14 @@ def test_sky_mask_loader_resolution_strips_inline_split(monkeypatch):
192
192
  assert calls == [
193
193
  ("/datasets/shared.zip", {"metadata_scope": "segmentation"}),
194
194
  ]
195
+
196
+
197
+ def test_modality_parses_inline_split_and_scope():
198
+ modality = data._modality(
199
+ path="/datasets/frame_camera_trainvaltest.zip:fog_day#scope=intrinsics",
200
+ modality_key="intrinsics",
201
+ )
202
+
203
+ assert modality.path == "/datasets/frame_camera_trainvaltest.zip"
204
+ assert modality.split == "fog_day"
205
+ assert modality.metadata_scope == "intrinsics"
@@ -229,6 +229,21 @@ class TestSaveResultsZip:
229
229
  stored = json.loads(zf.read("eval.json"))
230
230
  assert stored == results
231
231
 
232
+ def test_inline_zip_scope_writes_eval_json_into_zip(self, tmp_path):
233
+ zp = tmp_path / "dataset.zip"
234
+ with zipfile.ZipFile(zp, "w") as zf:
235
+ zf.writestr("image_001.png", b"\x89PNG")
236
+
237
+ results = {"rgb": {"psnr": 30.0}}
238
+ config = {"name": "model", "rgb": {"path": f"{zp}#scope=rgb"}}
239
+ out = save_results(results, config, modality="rgb")
240
+
241
+ assert out == zp / "eval.json"
242
+ with zipfile.ZipFile(zp, "r") as zf:
243
+ assert "eval.json" in zf.namelist()
244
+ stored = json.loads(zf.read("eval.json"))
245
+ assert stored == results
246
+
232
247
  def test_preserves_existing_zip_contents(self, tmp_path):
233
248
  zp = tmp_path / "dataset.zip"
234
249
  with zipfile.ZipFile(zp, "w") as zf:
File without changes
File without changes
File without changes