firecube 0.1.4__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.
Files changed (197) hide show
  1. firecube/__init__.py +23 -0
  2. firecube/__main__.py +20 -0
  3. firecube/_version.py +46 -0
  4. firecube/cli/_audience.py +135 -0
  5. firecube/cli/_command_schemas.py +112 -0
  6. firecube/cli/_ctx.py +85 -0
  7. firecube/cli/_errors.py +115 -0
  8. firecube/cli/_formatter.py +195 -0
  9. firecube/cli/_product.py +47 -0
  10. firecube/cli/_rename_hints.py +123 -0
  11. firecube/cli/_shared_options.py +247 -0
  12. firecube/cli/_slot_env.py +102 -0
  13. firecube/cli/_slot_planning.py +95 -0
  14. firecube/cli/_typed_options.py +181 -0
  15. firecube/cli/_uri_policy.py +110 -0
  16. firecube/cli/advise.py +321 -0
  17. firecube/cli/archive.py +870 -0
  18. firecube/cli/catalog.py +196 -0
  19. firecube/cli/chunks/__init__.py +74 -0
  20. firecube/cli/chunks/_claims.py +229 -0
  21. firecube/cli/chunks/_common.py +84 -0
  22. firecube/cli/chunks/_delete.py +376 -0
  23. firecube/cli/chunks/_list.py +334 -0
  24. firecube/cli/chunks/_manager.py +161 -0
  25. firecube/cli/chunks/_runs.py +294 -0
  26. firecube/cli/chunks/_snapshots.py +165 -0
  27. firecube/cli/completion.py +73 -0
  28. firecube/cli/main.py +866 -0
  29. firecube/cli/parquet.py +289 -0
  30. firecube/cli/plugins/__init__.py +28 -0
  31. firecube/cli/plugins/commands.py +262 -0
  32. firecube/cli/plugins/introspect.py +304 -0
  33. firecube/cli/plugins/mgmt.py +198 -0
  34. firecube/cli/plugins/registry.py +132 -0
  35. firecube/cli/zarr.py +1043 -0
  36. firecube/core/__init__.py +14 -0
  37. firecube/core/api.py +88 -0
  38. firecube/core/cf/__init__.py +23 -0
  39. firecube/core/cf/check_ids.py +126 -0
  40. firecube/core/cf/report.py +57 -0
  41. firecube/core/cf/validator.py +313 -0
  42. firecube/core/config.py +307 -0
  43. firecube/core/controlplane/__init__.py +47 -0
  44. firecube/core/controlplane/_event_processor.py +136 -0
  45. firecube/core/controlplane/_helpers.py +114 -0
  46. firecube/core/controlplane/_projection.py +253 -0
  47. firecube/core/controlplane/_snapshot.py +215 -0
  48. firecube/core/controlplane/_wal_reader.py +402 -0
  49. firecube/core/controlplane/_wal_writer.py +589 -0
  50. firecube/core/controlplane/claims.py +294 -0
  51. firecube/core/controlplane/deletion.py +704 -0
  52. firecube/core/controlplane/events.py +219 -0
  53. firecube/core/controlplane/manager.py +990 -0
  54. firecube/core/controlplane/metrics.py +97 -0
  55. firecube/core/controlplane/repo.py +804 -0
  56. firecube/core/controlplane/repo_utils.py +73 -0
  57. firecube/core/controlplane/time_dim.py +111 -0
  58. firecube/core/controlplane/types.py +445 -0
  59. firecube/core/credentials.py +36 -0
  60. firecube/core/duckdb/__init__.py +27 -0
  61. firecube/core/duckdb/bridge.py +82 -0
  62. firecube/core/duckdb/io.py +30 -0
  63. firecube/core/errors.py +74 -0
  64. firecube/core/filesystem/__init__.py +60 -0
  65. firecube/core/filesystem/_obstore_compat.py +60 -0
  66. firecube/core/filesystem/fsspec_backend.py +308 -0
  67. firecube/core/filesystem/instrumentation.py +260 -0
  68. firecube/core/filesystem/obstore_backend.py +406 -0
  69. firecube/core/filesystem/ops.py +412 -0
  70. firecube/core/filesystem/protocol.py +130 -0
  71. firecube/core/filesystem/store_factory.py +149 -0
  72. firecube/core/formats/__init__.py +46 -0
  73. firecube/core/formats/_iso.py +84 -0
  74. firecube/core/formats/discovery.py +165 -0
  75. firecube/core/formats/hdf5.py +137 -0
  76. firecube/core/formats/netcdf.py +226 -0
  77. firecube/core/formats/zip.py +192 -0
  78. firecube/core/intake.py +530 -0
  79. firecube/core/observability/__init__.py +72 -0
  80. firecube/core/observability/_state.py +24 -0
  81. firecube/core/observability/logging.py +147 -0
  82. firecube/core/observability/metrics.py +230 -0
  83. firecube/core/observability/telemetry/__init__.py +87 -0
  84. firecube/core/observability/telemetry/pushgateway.py +339 -0
  85. firecube/core/observability/telemetry/sinks.py +155 -0
  86. firecube/core/observability/tracing.py +126 -0
  87. firecube/core/product/__init__.py +45 -0
  88. firecube/core/product/identity.py +76 -0
  89. firecube/core/product/resolver.py +121 -0
  90. firecube/core/product/target.py +120 -0
  91. firecube/core/runtime.py +187 -0
  92. firecube/core/slot_index.py +205 -0
  93. firecube/core/storage/__init__.py +45 -0
  94. firecube/core/storage/binding.py +39 -0
  95. firecube/core/storage/cache_key.py +40 -0
  96. firecube/core/storage/completion.py +245 -0
  97. firecube/core/storage/driver_config.py +125 -0
  98. firecube/core/storage/results.py +30 -0
  99. firecube/core/storage/session.py +431 -0
  100. firecube/core/storage/transfer.py +142 -0
  101. firecube/core/storage/uri.py +173 -0
  102. firecube/core/tensogram/__init__.py +37 -0
  103. firecube/core/tensogram/_compat.py +36 -0
  104. firecube/core/tensogram/controlplane_codec.py +230 -0
  105. firecube/core/tensogram/converter.py +390 -0
  106. firecube/core/tensogram/metadata.py +274 -0
  107. firecube/core/tensogram/restore.py +303 -0
  108. firecube/core/tensogram/schema.py +93 -0
  109. firecube/core/uris.py +182 -0
  110. firecube/core/workspaces.py +68 -0
  111. firecube/core/zarr/__init__.py +69 -0
  112. firecube/core/zarr/_reserved_attrs.py +47 -0
  113. firecube/core/zarr/_reserved_root_attrs.py +74 -0
  114. firecube/core/zarr/io.py +88 -0
  115. firecube/core/zarr/layers.py +184 -0
  116. firecube/core/zarr/multires.py +178 -0
  117. firecube/core/zarr/region_writer.py +782 -0
  118. firecube/core/zarr/scrub.py +200 -0
  119. firecube/core/zarr/state.py +258 -0
  120. firecube/core/zarr/time_decode.py +71 -0
  121. firecube/core/zarr/validation.py +622 -0
  122. firecube/ingestor/__init__.py +27 -0
  123. firecube/ingestor/api.py +215 -0
  124. firecube/ingestor/config/__init__.py +19 -0
  125. firecube/ingestor/config/coercion.py +157 -0
  126. firecube/ingestor/config/engine.py +188 -0
  127. firecube/ingestor/contracts/__init__.py +14 -0
  128. firecube/ingestor/contracts/interfaces.py +235 -0
  129. firecube/ingestor/devtools/_templates/__init__.py +14 -0
  130. firecube/ingestor/devtools/_templates/ingestor_base.py.tpl +72 -0
  131. firecube/ingestor/devtools/_templates/ingestor_direct_zarr.py.tpl +66 -0
  132. firecube/ingestor/devtools/_templates/ingestor_parquet.py.tpl +59 -0
  133. firecube/ingestor/devtools/_templates/ingestor_zarr.py.tpl +55 -0
  134. firecube/ingestor/devtools/_templates/readme.md.tpl +40 -0
  135. firecube/ingestor/devtools/scaffolding.py +229 -0
  136. firecube/ingestor/errors.py +79 -0
  137. firecube/ingestor/extensions/_binning.py +152 -0
  138. firecube/ingestor/extensions/duck.py +153 -0
  139. firecube/ingestor/extensions/grid.py +287 -0
  140. firecube/ingestor/extensions/healpix.py +330 -0
  141. firecube/ingestor/registry/__init__.py +14 -0
  142. firecube/ingestor/registry/loader.py +144 -0
  143. firecube/ingestor/registry/metadata.py +97 -0
  144. firecube/ingestor/registry/version_compat.py +95 -0
  145. firecube/ingestor/runtime/__init__.py +14 -0
  146. firecube/ingestor/runtime/aggregation.py +112 -0
  147. firecube/ingestor/runtime/base.py +836 -0
  148. firecube/ingestor/runtime/base_hooks.py +129 -0
  149. firecube/ingestor/runtime/batching.py +161 -0
  150. firecube/ingestor/runtime/configure.py +195 -0
  151. firecube/ingestor/runtime/coverage.py +177 -0
  152. firecube/ingestor/runtime/engine.py +793 -0
  153. firecube/ingestor/runtime/parallel_evidence.py +75 -0
  154. firecube/ingestor/runtime/parallel_execution_state.py +28 -0
  155. firecube/ingestor/runtime/parallel_gate.py +164 -0
  156. firecube/ingestor/runtime/parallel_run_id.py +48 -0
  157. firecube/ingestor/runtime/preflight.py +40 -0
  158. firecube/ingestor/runtime/recording.py +425 -0
  159. firecube/ingestor/runtime/resume_guard.py +556 -0
  160. firecube/ingestor/runtime/resume_types.py +65 -0
  161. firecube/ingestor/runtime/telemetry.py +171 -0
  162. firecube/ingestor/runtime/tensogram/__init__.py +14 -0
  163. firecube/ingestor/runtime/tensogram/strategy.py +164 -0
  164. firecube/ingestor/runtime/workspace.py +220 -0
  165. firecube/ingestor/runtime/zarr/__init__.py +34 -0
  166. firecube/ingestor/runtime/zarr/append.py +466 -0
  167. firecube/ingestor/runtime/zarr/append_services.py +650 -0
  168. firecube/ingestor/runtime/zarr/batch_runner.py +190 -0
  169. firecube/ingestor/runtime/zarr/contracts.py +58 -0
  170. firecube/ingestor/runtime/zarr/existing_cube_check.py +282 -0
  171. firecube/ingestor/runtime/zarr/resume_cache.py +92 -0
  172. firecube/ingestor/runtime/zarr/staged_metadata.py +249 -0
  173. firecube/ingestor/runtime/zarr/strategies/__init__.py +15 -0
  174. firecube/ingestor/runtime/zarr/strategies/append.py +172 -0
  175. firecube/ingestor/runtime/zarr/strategies/indexed_region.py +426 -0
  176. firecube/ingestor/runtime/zarr/write.py +212 -0
  177. firecube/ingestor/runtime/zarr/write_context.py +139 -0
  178. firecube/ingestor/templates/__init__.py +19 -0
  179. firecube/ingestor/templates/config.py +118 -0
  180. firecube/ingestor/templates/direct_zarr.py +790 -0
  181. firecube/ingestor/templates/generic.py +462 -0
  182. firecube/ingestor/templates/generic_tensogram.py +170 -0
  183. firecube/ingestor/types/__init__.py +19 -0
  184. firecube/ingestor/types/config.py +89 -0
  185. firecube/ingestor/types/context.py +409 -0
  186. firecube/ingestor/types/manifest.py +53 -0
  187. firecube/ingestor/types/planned_range.py +152 -0
  188. firecube/ingestor/types/result_metrics.py +386 -0
  189. firecube/ingestor/utils/__init__.py +14 -0
  190. firecube/ingestor/utils/duckdb_utils.py +235 -0
  191. firecube/ingestor/validation.py +55 -0
  192. firecube-0.1.4.dist-info/METADATA +242 -0
  193. firecube-0.1.4.dist-info/RECORD +197 -0
  194. firecube-0.1.4.dist-info/WHEEL +4 -0
  195. firecube-0.1.4.dist-info/entry_points.txt +2 -0
  196. firecube-0.1.4.dist-info/licenses/AUTHORS.md +5 -0
  197. firecube-0.1.4.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,139 @@
1
+ # Copyright 2025-2026 EUMETSAT
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Zarr write-session context manager.
16
+
17
+ Encapsulates Dask scheduler validation, ``dask.config.set`` context,
18
+ ``zarr.config`` async-concurrency settings, and write-lock acquisition
19
+ into a single reusable context manager.
20
+
21
+ Extracted from ``GenericZarrIngestor._process_batch()`` so that any
22
+ write strategy can share identical scheduler/lock policy.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import contextlib
28
+ import threading
29
+ from typing import Any
30
+
31
+ from firecube.ingestor.api import ConfigurationError
32
+
33
+ _VALID_SCHEDULERS: frozenset[str] = frozenset(
34
+ {
35
+ "synchronous",
36
+ "sync",
37
+ "single-threaded",
38
+ "threads",
39
+ "threading",
40
+ "processes",
41
+ "multiprocessing",
42
+ "distributed",
43
+ }
44
+ )
45
+
46
+
47
+ class ZarrWriteContext:
48
+ """Context manager for Zarr write sessions.
49
+
50
+ Validates Dask scheduler configuration, sets ``zarr.config``
51
+ async-concurrency, activates the appropriate ``dask.config`` scope,
52
+ and acquires the caller-supplied write lock.
53
+
54
+ Parameters
55
+ ----------
56
+ write_lock:
57
+ A ``threading.Lock`` (or compatible) used to serialize Zarr writes.
58
+ configured_scheduler:
59
+ Explicit Dask scheduler name (e.g. ``"synchronous"``, ``"threads"``),
60
+ or *None* to keep the ambient default.
61
+ write_threads:
62
+ Number of Dask worker threads for chunk-level parallelism.
63
+ ``0`` means "use the configured scheduler as-is".
64
+ async_concurrency:
65
+ Zarr async pipeline concurrency. ``10`` is the default sentinel
66
+ value; setting both *write_threads > 0* **and** a non-default
67
+ concurrency raises ``ConfigurationError``.
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ *,
73
+ write_lock: threading.Lock,
74
+ configured_scheduler: str | None = None,
75
+ write_threads: int = 0,
76
+ async_concurrency: int = 10,
77
+ ) -> None:
78
+ self._write_lock = write_lock
79
+ self._configured_scheduler = configured_scheduler
80
+ self._write_threads = write_threads
81
+ self._async_concurrency = async_concurrency
82
+
83
+ self._exit_stack: contextlib.ExitStack | None = None
84
+
85
+ def _validate(self) -> None:
86
+ if self._configured_scheduler and self._configured_scheduler not in _VALID_SCHEDULERS:
87
+ raise ConfigurationError(
88
+ f"Invalid dask_scheduler={self._configured_scheduler!r}. "
89
+ f"Valid options: {sorted(_VALID_SCHEDULERS)}"
90
+ )
91
+
92
+ if self._write_threads > 0 and self._async_concurrency != 10:
93
+ raise ConfigurationError(
94
+ "dask_write_threads and zarr_async_concurrency are mutually exclusive. "
95
+ "dask_write_threads uses dask threads for chunk-level parallelism; "
96
+ "zarr_async_concurrency uses zarr's internal async pipeline. "
97
+ "Using both causes contention and degrades performance. "
98
+ "Pick one strategy."
99
+ )
100
+
101
+ def __enter__(self) -> ZarrWriteContext:
102
+ self._validate()
103
+
104
+ import dask.config as dask_config
105
+ import zarr as _zarr
106
+
107
+ effective_scheduler = self._configured_scheduler or dask_config.get(
108
+ "scheduler", default=None
109
+ )
110
+
111
+ if self._write_threads > 0 or effective_scheduler == "synchronous":
112
+ _zarr.config.set({"async.concurrency": 1})
113
+ else:
114
+ _zarr.config.set({"async.concurrency": self._async_concurrency})
115
+
116
+ if self._write_threads > 0:
117
+ dask_ctx: Any = dask_config.set(scheduler="threads", num_workers=self._write_threads)
118
+ elif self._configured_scheduler:
119
+ dask_ctx = dask_config.set(scheduler=self._configured_scheduler)
120
+ else:
121
+ dask_ctx = contextlib.nullcontext()
122
+
123
+ stack = contextlib.ExitStack()
124
+ self._exit_stack = stack
125
+ try:
126
+ stack.enter_context(self._write_lock) # type: ignore[arg-type]
127
+ stack.enter_context(dask_ctx)
128
+ except BaseException:
129
+ stack.close()
130
+ self._exit_stack = None
131
+ raise
132
+
133
+ return self
134
+
135
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool:
136
+ if self._exit_stack is not None:
137
+ self._exit_stack.__exit__(exc_type, exc_val, exc_tb)
138
+ self._exit_stack = None
139
+ return False
@@ -0,0 +1,19 @@
1
+ # Copyright 2025-2026 EUMETSAT
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Internal template implementations for Firecube ingestor.
16
+
17
+ Plugin authors should import templates via ``firecube.ingestor.api``.
18
+ This package is not part of the public SDK surface.
19
+ """
@@ -0,0 +1,118 @@
1
+ # Copyright 2025-2026 EUMETSAT
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Template-specific configuration for Firecube ingestors.
16
+
17
+ These configurations control the output format logic (Zarr chunks, Parquet partitions)
18
+ and are owned by the `Generic[Type]Ingestor` templates.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from dataclasses import dataclass
24
+ from typing import Any, TypeVar, get_type_hints
25
+
26
+ from firecube.ingestor.config.engine import config_keys
27
+
28
+ T = TypeVar("T", bound="TemplateConfig")
29
+
30
+ ZARR_MULTI_RES_REMOVED_MESSAGE = (
31
+ "zarr_multi_res during ingest has been removed; "
32
+ "run 'firecube zarr multires <target>' after ingestion instead."
33
+ )
34
+
35
+
36
+ @dataclass
37
+ class TemplateConfig:
38
+ """Base for template configurations."""
39
+
40
+ @classmethod
41
+ def from_options(cls: type[T], options: dict[str, Any]) -> T:
42
+ from firecube.ingestor.config.coercion import coerce_cli_value
43
+
44
+ if cls is ZarrTemplateConfig and "zarr_multi_res" in options:
45
+ raise ValueError(ZARR_MULTI_RES_REMOVED_MESSAGE)
46
+
47
+ known = config_keys(cls)
48
+ unknown = set(options.keys()) - known
49
+ if unknown:
50
+ raise ValueError(
51
+ f"Unknown Template options: {', '.join(sorted(unknown))}. "
52
+ f"Valid keys: {', '.join(sorted(known))}"
53
+ )
54
+
55
+ type_hints = get_type_hints(cls)
56
+ init_kwargs = {}
57
+ for key, value in options.items():
58
+ target_type = type_hints.get(key)
59
+ init_kwargs[key] = coerce_cli_value(value, target_type, key)
60
+ return cls(**init_kwargs)
61
+
62
+
63
+ @dataclass
64
+ class ZarrTemplateConfig(TemplateConfig):
65
+ """Configuration for GenericZarrIngestor.
66
+
67
+ Attributes:
68
+ zarr_chunk_shape: Optional per-dimension inner chunk sizes.
69
+ zarr_sharding: Enable Zarr v3 sharding.
70
+ zarr_shard_shape: Optional per-dimension shard sizes.
71
+ zarr_compression: Compression setting. ``False`` disables compression,
72
+ ``True`` selects the default codec, and a string selects a codec name.
73
+ zarr_consolidate: Consolidate Zarr metadata after writes.
74
+ zarr_time_encoding: Optional time encoding override.
75
+ zarr_async_concurrency: Async write concurrency used by Zarr.
76
+ dask_scheduler: Optional Dask scheduler override.
77
+ dask_write_threads: Optional write-thread count for Dask-backed writes.
78
+ """
79
+
80
+ zarr_chunk_shape: dict[str, int] | None = None
81
+ zarr_sharding: bool = False
82
+ zarr_shard_shape: dict[str, int] | None = None
83
+ zarr_compression: bool | str = False
84
+ zarr_consolidate: bool = False
85
+ zarr_time_encoding: str | None = None
86
+ zarr_async_concurrency: int = 10
87
+ dask_scheduler: str | None = None
88
+ dask_write_threads: int = 0
89
+
90
+
91
+ @dataclass
92
+ class ParquetTemplateConfig(TemplateConfig):
93
+ """Configuration for GenericParquetIngestor.
94
+
95
+ Attributes:
96
+ parquet_partition_by: Optional Hive-style partition columns.
97
+ parquet_row_group_size: Optional rows per Parquet row group.
98
+ """
99
+
100
+ parquet_partition_by: list[str] | None = None
101
+ parquet_row_group_size: int | None = None
102
+
103
+
104
+ @dataclass
105
+ class TensogramTemplateConfig(TemplateConfig):
106
+ """Configuration for GenericTensogramIngestor.
107
+
108
+ Attributes:
109
+ tensogram_compression: Compression codec for Tensogram output.
110
+ tensogram_message_granularity: Message grouping strategy.
111
+ tensogram_allow_nan: Permit NaN values in archive output.
112
+ tensogram_allow_inf: Permit infinite values in archive output.
113
+ """
114
+
115
+ tensogram_compression: str = "zstd"
116
+ tensogram_message_granularity: str = "per_variable"
117
+ tensogram_allow_nan: bool = True
118
+ tensogram_allow_inf: bool = True