tensogram-xarray 0.14.0__py3-none-any.whl

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.
@@ -0,0 +1,91 @@
1
+ # (C) Copyright 2026- ECMWF and individual contributors.
2
+ #
3
+ # This software is licensed under the terms of the Apache Licence Version 2.0
4
+ # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ # In applying this licence, ECMWF does not waive the privileges and immunities
6
+ # granted to it by virtue of its status as an intergovernmental organisation nor
7
+ # does it submit to any jurisdiction.
8
+
9
+ """User-specified dimension and variable mapping.
10
+
11
+ Handles the ``dim_names`` and ``variable_key`` parameters that let callers
12
+ control how tensogram data maps to xarray dimensions and variable names.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from collections.abc import Sequence
18
+ from typing import Any
19
+
20
+
21
+ def resolve_dim_names(
22
+ ndim: int,
23
+ user_dim_names: Sequence[str] | None,
24
+ ) -> list[str]:
25
+ """Return dimension names for a tensor with *ndim* axes.
26
+
27
+ If *user_dim_names* is provided, it must have exactly *ndim* entries.
28
+ Otherwise generic ``dim_0``, ``dim_1``, ... names are generated.
29
+ """
30
+ if user_dim_names is not None:
31
+ names = list(user_dim_names)
32
+ if len(names) != ndim:
33
+ msg = (
34
+ f"dim_names has {len(names)} entries but tensor has {ndim} "
35
+ f"dimensions. Provide exactly {ndim} names."
36
+ )
37
+ raise ValueError(msg)
38
+ return names
39
+ return [f"dim_{i}" for i in range(ndim)]
40
+
41
+
42
+ def _resolve_dotted(meta: dict[str, Any], dotted_key: str) -> Any:
43
+ """Resolve a dotted key path like ``mars.param`` in a nested dict."""
44
+ parts = dotted_key.split(".")
45
+ current: Any = meta
46
+ for part in parts:
47
+ if not isinstance(current, dict) or part not in current:
48
+ return None
49
+ current = current[part]
50
+ return current
51
+
52
+
53
+ # Dotted-path metadata keys to try for variable naming, in priority order.
54
+ # Must match the priority chain in tensogram-zarr's mapping.py.
55
+ _VARIABLE_NAME_KEYS = [
56
+ "name",
57
+ "mars.param",
58
+ "param",
59
+ "mars.shortName",
60
+ "shortName",
61
+ ]
62
+
63
+
64
+ def resolve_variable_name(
65
+ obj_index: int,
66
+ per_object_meta: dict[str, Any],
67
+ variable_key: str | None,
68
+ ) -> str:
69
+ """Determine the xarray variable name for a data object.
70
+
71
+ If *variable_key* is given (e.g. ``"mars.param"``), the value at that
72
+ dotted path in the per-object metadata is used. Otherwise the function
73
+ tries ``_VARIABLE_NAME_KEYS`` in priority order, then falls back to a
74
+ generic ``"object_<index>"`` name.
75
+
76
+ The priority chain matches ``tensogram-zarr``'s ``resolve_variable_name``
77
+ so that the same ``.tgm`` file produces consistent variable names
78
+ regardless of which backend opens it.
79
+ """
80
+ source = per_object_meta or {}
81
+
82
+ # Try explicit key first, then the standard priority chain.
83
+ keys_to_try = [variable_key] if variable_key else []
84
+ keys_to_try.extend(_VARIABLE_NAME_KEYS)
85
+
86
+ for key in keys_to_try:
87
+ val = _resolve_dotted(source, key)
88
+ if val is not None:
89
+ return str(val)
90
+
91
+ return f"object_{obj_index}"