climate-ref 0.5.0__py3-none-any.whl → 0.5.1__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.
@@ -1,7 +1,9 @@
1
+ import enum
2
+ from collections.abc import Mapping
1
3
  from typing import TYPE_CHECKING, Any, ClassVar
2
4
 
3
5
  from loguru import logger
4
- from sqlalchemy import Column, ForeignKey, Text
6
+ from sqlalchemy import Column, ForeignKey, Text, event
5
7
  from sqlalchemy.orm import Mapped, mapped_column, relationship
6
8
 
7
9
  from climate_ref.models.base import Base, CreatedUpdatedMixin
@@ -11,9 +13,23 @@ if TYPE_CHECKING:
11
13
  from climate_ref.models.execution import Execution
12
14
 
13
15
 
16
+ class MetricValueType(enum.Enum):
17
+ """
18
+ Type of metric value
19
+
20
+ This is used to determine how the metric value should be interpreted.
21
+ """
22
+
23
+ # The value is a single number
24
+ SCALAR = "scalar"
25
+
26
+ # The value is a list of numbers
27
+ SERIES = "series"
28
+
29
+
14
30
  class MetricValue(CreatedUpdatedMixin, Base):
15
31
  """
16
- Represents a single diagnostic value
32
+ Represents a single metric value
17
33
 
18
34
  This value has a number of dimensions which are used to query the diagnostic value.
19
35
  These dimensions describe aspects such as the type of statistic being measured,
@@ -26,14 +42,24 @@ class MetricValue(CreatedUpdatedMixin, Base):
26
42
 
27
43
  __tablename__ = "metric_value"
28
44
 
45
+ __mapper_args__: ClassVar[Mapping[str, str]] = { # type: ignore
46
+ "polymorphic_on": "type",
47
+ }
48
+
29
49
  id: Mapped[int] = mapped_column(primary_key=True)
30
50
  execution_id: Mapped[int] = mapped_column(ForeignKey("execution.id"))
31
51
 
32
- value: Mapped[float] = mapped_column()
33
52
  attributes: Mapped[dict[str, Any]] = mapped_column()
34
53
 
35
54
  execution: Mapped["Execution"] = relationship(back_populates="values")
36
55
 
56
+ type: Mapped[MetricValueType] = mapped_column()
57
+ """
58
+ Type of metric value
59
+
60
+ This value is used to determine how the metric value should be interpreted.
61
+ """
62
+
37
63
  _cv_dimensions: ClassVar[list[str]] = []
38
64
 
39
65
  @property
@@ -55,13 +81,7 @@ class MetricValue(CreatedUpdatedMixin, Base):
55
81
  return dims
56
82
 
57
83
  def __repr__(self) -> str:
58
- return (
59
- f"<MetricValue "
60
- f"id={self.id} "
61
- f"execution={self.execution} "
62
- f"value={self.value} "
63
- f"dimensions={self.dimensions}>"
64
- )
84
+ return f"<MetricValue id={self.id} execution={self.execution} dimensions={self.dimensions}>"
65
85
 
66
86
  @staticmethod
67
87
  def build_dimension_column(dimension: Dimension) -> Column[str]:
@@ -143,7 +163,22 @@ class MetricValue(CreatedUpdatedMixin, Base):
143
163
  for key in keys:
144
164
  cls._cv_dimensions.remove(key)
145
165
 
146
- assert not len(cls._cv_dimensions) # noqa
166
+ assert not len(cls._cv_dimensions)
167
+
168
+
169
+ class ScalarMetricValue(MetricValue):
170
+ """
171
+ A scalar value with an associated dimensions
172
+
173
+ This is a subclass of MetricValue that is used to represent a scalar value.
174
+ """
175
+
176
+ __mapper_args__: ClassVar[Mapping[str, Any]] = { # type: ignore
177
+ "polymorphic_identity": MetricValueType.SCALAR,
178
+ }
179
+
180
+ # This is a scalar value
181
+ value: Mapped[float] = mapped_column(nullable=True)
147
182
 
148
183
  @classmethod
149
184
  def build(
@@ -158,7 +193,7 @@ class MetricValue(CreatedUpdatedMixin, Base):
158
193
  Build a MetricValue from a collection of dimensions and a value
159
194
 
160
195
  This is a helper method that validates the dimensions supplied and provides an interface
161
- similar to [climate_ref_core.pycmec.metric.MetricValue][].
196
+ similar to [climate_ref_core.metric_values.ScalarMetricValue][].
162
197
 
163
198
  Parameters
164
199
  ----------
@@ -187,9 +222,99 @@ class MetricValue(CreatedUpdatedMixin, Base):
187
222
  if k not in cls._cv_dimensions:
188
223
  raise KeyError(f"Unknown dimension column '{k}'")
189
224
 
190
- return MetricValue(
225
+ return ScalarMetricValue(
191
226
  execution_id=execution_id,
192
227
  value=value,
193
228
  attributes=attributes,
194
229
  **dimensions,
195
230
  )
231
+
232
+
233
+ class SeriesMetricValue(MetricValue):
234
+ """
235
+ A scalar value with an associated dimensions
236
+
237
+ This is a subclass of MetricValue that is used to represent a scalar value.
238
+ """
239
+
240
+ __mapper_args__: ClassVar[Mapping[str, Any]] = { # type: ignore
241
+ "polymorphic_identity": MetricValueType.SERIES,
242
+ }
243
+
244
+ # This is a scalar value
245
+ values: Mapped[list[float | int]] = mapped_column(nullable=True)
246
+ index: Mapped[list[float | int | str]] = mapped_column(nullable=True)
247
+ index_name: Mapped[str] = mapped_column(nullable=True)
248
+
249
+ @classmethod
250
+ def build( # noqa: PLR0913
251
+ cls,
252
+ *,
253
+ execution_id: int,
254
+ values: list[float | int],
255
+ index: list[float | int | str],
256
+ index_name: str,
257
+ dimensions: dict[str, str],
258
+ attributes: dict[str, Any] | None,
259
+ ) -> "MetricValue":
260
+ """
261
+ Build a database object from a series
262
+
263
+ Parameters
264
+ ----------
265
+ execution_id
266
+ Execution that created the diagnostic value
267
+ values
268
+ 1-d array of values
269
+ index
270
+ 1-d array of index values
271
+ index_name
272
+ Name of the index. Used for presentation purposes
273
+ dimensions
274
+ Dimensions that describe the diagnostic execution result
275
+ attributes
276
+ Optional additional attributes to describe the value,
277
+ but are not in the controlled vocabulary.
278
+
279
+ Raises
280
+ ------
281
+ KeyError
282
+ If an unknown dimension was supplied.
283
+
284
+ Dimensions must exist in the controlled vocabulary.
285
+ ValueError
286
+ If the length of values and index do not match.
287
+
288
+ Returns
289
+ -------
290
+ Newly created MetricValue
291
+ """
292
+ for k in dimensions:
293
+ if k not in cls._cv_dimensions:
294
+ raise KeyError(f"Unknown dimension column '{k}'")
295
+
296
+ if len(values) != len(index):
297
+ raise ValueError(f"Index length ({len(index)}) must match values length ({len(values)})")
298
+
299
+ return SeriesMetricValue(
300
+ execution_id=execution_id,
301
+ values=values,
302
+ index=index,
303
+ index_name=index_name,
304
+ attributes=attributes,
305
+ **dimensions,
306
+ )
307
+
308
+
309
+ @event.listens_for(SeriesMetricValue, "before_insert")
310
+ @event.listens_for(SeriesMetricValue, "before_update")
311
+ def validate_series_lengths(mapper: Any, connection: Any, target: SeriesMetricValue) -> None:
312
+ """
313
+ Validate that values and index have matching lengths
314
+
315
+ This is done on insert and update to ensure that the database is consistent.
316
+ """
317
+ if target.values is not None and target.index is not None and len(target.values) != len(target.index):
318
+ raise ValueError(
319
+ f"Index length ({len(target.index)}) must match values length ({len(target.values)})"
320
+ )
@@ -139,7 +139,7 @@ class ProviderRegistry:
139
139
  provider.configure(config)
140
140
  providers.append(provider)
141
141
 
142
- with db.session.begin_nested():
142
+ with db.session.begin():
143
143
  for provider in providers:
144
144
  _register_provider(db, provider)
145
145
 
climate_ref/solver.py CHANGED
@@ -25,21 +25,16 @@ from climate_ref.models import Provider as ProviderModel
25
25
  from climate_ref.models.execution import Execution
26
26
  from climate_ref.provider_registry import ProviderRegistry
27
27
  from climate_ref_core.constraints import apply_constraint
28
- from climate_ref_core.datasets import DatasetCollection, ExecutionDatasetCollection, SourceDatasetType
28
+ from climate_ref_core.datasets import (
29
+ DatasetCollection,
30
+ ExecutionDatasetCollection,
31
+ Selector,
32
+ SourceDatasetType,
33
+ )
29
34
  from climate_ref_core.diagnostics import DataRequirement, Diagnostic, ExecutionDefinition
30
35
  from climate_ref_core.exceptions import InvalidDiagnosticException
31
36
  from climate_ref_core.providers import DiagnosticProvider
32
37
 
33
- SelectorKey = tuple[tuple[str, str], ...]
34
- """
35
- Type describing the key used to identify a group of datasets
36
-
37
- This is a tuple of tuples, where each inner tuple contains a metadata and dimension value
38
- that was used to group the datasets together.
39
-
40
- This SelectorKey type must be hashable, as it is used as a key in a dictionary.
41
- """
42
-
43
38
 
44
39
  @frozen
45
40
  class DiagnosticExecution:
@@ -81,20 +76,14 @@ class DiagnosticExecution:
81
76
  return "__".join(key_values)
82
77
 
83
78
  @property
84
- def selectors(self) -> dict[str, SelectorKey]:
79
+ def selectors(self) -> dict[str, Selector]:
85
80
  """
86
81
  Collection of selectors used to identify the datasets
87
82
 
88
83
  These are the key, value pairs that were selected during the initial group-by,
89
84
  for each data requirement.
90
85
  """
91
- # The "value" of SourceType is used here so this can be stored in the db
92
- s = {}
93
- for source_type in SourceDatasetType.ordered():
94
- if source_type not in self.datasets:
95
- continue
96
- s[source_type.value] = self.datasets[source_type].selector
97
- return s
86
+ return self.datasets.selectors
98
87
 
99
88
  def build_execution_definition(self, output_root: pathlib.Path) -> ExecutionDefinition:
100
89
  """
@@ -107,6 +96,7 @@ class DiagnosticExecution:
107
96
  fragment = pathlib.Path() / self.provider.slug / self.diagnostic.slug / self.datasets.hash
108
97
 
109
98
  return ExecutionDefinition(
99
+ diagnostic=self.diagnostic,
110
100
  root_directory=output_root,
111
101
  output_directory=output_root / fragment,
112
102
  key=self.dataset_key,
@@ -116,7 +106,7 @@ class DiagnosticExecution:
116
106
 
117
107
  def extract_covered_datasets(
118
108
  data_catalog: pd.DataFrame, requirement: DataRequirement
119
- ) -> dict[SelectorKey, pd.DataFrame]:
109
+ ) -> dict[Selector, pd.DataFrame]:
120
110
  """
121
111
  Determine the different diagnostic executions that should be performed with the current data catalog
122
112
  """
@@ -140,8 +130,8 @@ def extract_covered_datasets(
140
130
 
141
131
  for name, group in groups:
142
132
  if requirement.group_by is None:
143
- assert len(groups) == 1 # noqa: S101
144
- group_keys: SelectorKey = ()
133
+ assert len(groups) == 1
134
+ group_keys: Selector = ()
145
135
  else:
146
136
  group_keys = tuple(zip(requirement.group_by, name))
147
137
  constrained_group = _process_group_constraints(data_catalog, group, requirement)
@@ -238,12 +228,12 @@ def _solve_from_data_requirements(
238
228
  diagnostic=diagnostic,
239
229
  datasets=ExecutionDatasetCollection(
240
230
  {
241
- key: DatasetCollection(
242
- datasets=dataset_groups[key][dataset_group_key],
243
- slug_column=get_dataset_adapter(key.value).slug_column,
244
- selector=dataset_group_key,
231
+ source_type: DatasetCollection(
232
+ datasets=dataset_groups[source_type][selector],
233
+ slug_column=get_dataset_adapter(source_type.value).slug_column,
234
+ selector=selector,
245
235
  )
246
- for key, dataset_group_key in zip(dataset_groups.keys(), items)
236
+ for source_type, selector in zip(dataset_groups.keys(), items)
247
237
  }
248
238
  ),
249
239
  )
@@ -341,7 +331,7 @@ def solve_required_executions(
341
331
 
342
332
  # Use a transaction to make sure that the models
343
333
  # are created correctly before potentially executing out of process
344
- with db.session.begin(nested=True):
334
+ with db.session.begin():
345
335
  diagnostic = (
346
336
  db.session.query(DiagnosticModel)
347
337
  .join(DiagnosticModel.provider)
@@ -386,8 +376,6 @@ def solve_required_executions(
386
376
  execution.register_datasets(db, definition.datasets)
387
377
 
388
378
  executor.run(
389
- provider=potential_execution.provider,
390
- diagnostic=potential_execution.diagnostic,
391
379
  definition=definition,
392
380
  execution=execution,
393
381
  )
climate_ref/testing.py CHANGED
@@ -10,7 +10,7 @@ from loguru import logger
10
10
  from climate_ref.config import Config
11
11
  from climate_ref.database import Database
12
12
  from climate_ref.executor import handle_execution_result
13
- from climate_ref.models import Execution
13
+ from climate_ref.models import Execution, ExecutionGroup
14
14
  from climate_ref_core.dataset_registry import dataset_registry_manager, fetch_all_files
15
15
  from climate_ref_core.diagnostics import Diagnostic, ExecutionResult
16
16
  from climate_ref_core.pycmec.metric import CMECMetric
@@ -26,7 +26,7 @@ def _determine_test_directory() -> Path | None:
26
26
 
27
27
 
28
28
  TEST_DATA_DIR = _determine_test_directory()
29
- SAMPLE_DATA_VERSION = "v0.5.0"
29
+ SAMPLE_DATA_VERSION = "v0.5.2"
30
30
 
31
31
 
32
32
  def fetch_sample_data(force_cleanup: bool = False, symlink: bool = False) -> None:
@@ -82,10 +82,16 @@ def validate_result(diagnostic: Diagnostic, config: Config, result: ExecutionRes
82
82
  This should only be used by the test suite as it will create a fake
83
83
  database entry for the diagnostic execution result.
84
84
  """
85
- # Add a fake item in the Database
85
+ # Add a fake execution/execution group in the Database
86
86
  database = Database.from_config(config)
87
+ execution_group = ExecutionGroup(
88
+ diagnostic_id=1, key=result.definition.key, dirty=True, selectors=result.definition.datasets.selectors
89
+ )
90
+ database.session.add(execution_group)
91
+ database.session.flush()
92
+
87
93
  execution = Execution(
88
- execution_group_id=1,
94
+ execution_group_id=execution_group.id,
89
95
  dataset_hash=result.definition.datasets.hash,
90
96
  output_fragment=str(result.definition.output_fragment()),
91
97
  )
@@ -96,9 +102,7 @@ def validate_result(diagnostic: Diagnostic, config: Config, result: ExecutionRes
96
102
 
97
103
  # Validate bundles
98
104
  metric_bundle = CMECMetric.load_from_json(result.to_output_path(result.metric_bundle_filename))
99
- assert diagnostic.facets == tuple(metric_bundle.DIMENSIONS.root["json_structure"]), (
100
- metric_bundle.DIMENSIONS.root["json_structure"]
101
- )
105
+ assert diagnostic.facets == tuple(metric_bundle.DIMENSIONS.root["json_structure"])
102
106
  CMECOutput.load_from_json(result.to_output_path(result.output_bundle_filename))
103
107
 
104
108
  # Create a fake log file if one doesn't exist
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: climate-ref
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Application which runs the CMIP Rapid Evaluation Framework
5
5
  Author-email: Jared Lewis <jared.lewis@climate-resource.com>, Mika Pflueger <mika.pflueger@climate-resource.com>, Bouwe Andela <b.andela@esciencecenter.nl>, Jiwoo Lee <lee1043@llnl.gov>, Min Xu <xum1@ornl.gov>, Nathan Collier <collierno@ornl.gov>, Dora Hegedus <dora.hegedus@stfc.ac.uk>
6
6
  License: Apache-2.0
@@ -28,6 +28,7 @@ Requires-Dist: platformdirs>=4.3.6
28
28
  Requires-Dist: setuptools>=75.8.0
29
29
  Requires-Dist: sqlalchemy>=2.0.36
30
30
  Requires-Dist: tomlkit>=0.13.2
31
+ Requires-Dist: tqdm>=4.67.1
31
32
  Requires-Dist: typer>=0.12.5
32
33
  Provides-Extra: celery
33
34
  Requires-Dist: climate-ref-celery>=0.5.0; extra == 'celery'
@@ -36,6 +37,7 @@ Requires-Dist: climate-ref-esmvaltool>=0.5.0; extra == 'metrics'
36
37
  Requires-Dist: climate-ref-ilamb>=0.5.0; extra == 'metrics'
37
38
  Requires-Dist: climate-ref-pmp>=0.5.0; extra == 'metrics'
38
39
  Provides-Extra: postgres
40
+ Requires-Dist: alembic-postgresql-enum>=1.7.0; extra == 'postgres'
39
41
  Requires-Dist: psycopg2-binary>=2.9.2; extra == 'postgres'
40
42
  Description-Content-Type: text/markdown
41
43
 
@@ -0,0 +1,47 @@
1
+ climate_ref/__init__.py,sha256=OJl5EnjLyEoCQpa0zQ8edV8EcU2YxBJ0xjermIlm9Bw,820
2
+ climate_ref/_config_helpers.py,sha256=-atI5FX7SukhLE_jz_rL-EHQ7s0YYqKu3dSFYWxSyMU,6632
3
+ climate_ref/alembic.ini,sha256=WRvbwSIFuZ7hWNMnR2-yHPJAwYUnwhvRYBzkJhtpGdg,3535
4
+ climate_ref/config.py,sha256=kvF1DOsMDwic_AZiG6IOZ1tWbrQfE0iRrK-uRn-mNDc,15028
5
+ climate_ref/constants.py,sha256=9RaNLgUSuQva7ki4eRW3TjOKeVP6T81QNiu0veB1zVk,111
6
+ climate_ref/database.py,sha256=LJ6s5qSPJz4yaCzNjJZ-Mw71hquhnx0IKW32VulkuIs,7293
7
+ climate_ref/provider_registry.py,sha256=0oVHQrnFenEQhCUqhrZAUnF6r83VCbXrQVbbo8Bh96c,4109
8
+ climate_ref/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ climate_ref/solver.py,sha256=_QteO9AP1FR-P0W7WzwgntMh4VvpMAkhn02ikw-KDf8,13625
10
+ climate_ref/testing.py,sha256=O36cliznD1sj04xmsqFgowCXC-CoVpfLFbSPfzZbshI,4105
11
+ climate_ref/cli/__init__.py,sha256=1SjCNQ2fV5GtQX_TS77rNlf0h_ECGAup58WYGlcOTTs,4112
12
+ climate_ref/cli/_utils.py,sha256=6bIb8zEVvzXyKpv8MG58T-T2L2jH-G8WNrOOGpz3uCw,1918
13
+ climate_ref/cli/config.py,sha256=8I6CLdqKgTu6yaASy-qG0T839Fc0lDZtLSZ6YCc4wOY,520
14
+ climate_ref/cli/datasets.py,sha256=4k5iSeft5klYKFPBPkmN9sw1RNT7WWp6eI2RPxPT-SM,7519
15
+ climate_ref/cli/executions.py,sha256=sZXyVFYWML5mD7dE8xlsqyunsrwOIweTBDEUKCjXEpo,6798
16
+ climate_ref/cli/providers.py,sha256=eS9IaQxW8zGxidr8TWt7thdMU5JH53u4T3xbcIe2C_E,2455
17
+ climate_ref/cli/solve.py,sha256=1_7Y2Cs6pVCk8Yz1n_NuVhi7WdhfNbtPicbyT804ttE,656
18
+ climate_ref/dataset_registry/obs4ref_reference.txt,sha256=1NodZd3tOS9Z1Afpb_Oq4obp4OGAFDSAwEl3FssPwAQ,251
19
+ climate_ref/dataset_registry/sample_data.txt,sha256=ZQ-bPuBkwaChSYtEVFamg97qu-76oiOVEWn7l9HWYDc,14746
20
+ climate_ref/datasets/__init__.py,sha256=PV3u5ZmhyfcHbKqySgwVA8m4-naZgxzydLXSBqdTGLM,1171
21
+ climate_ref/datasets/base.py,sha256=sgfR548rLZRNPIaZKKXmGp8E_dyoAW1NONZnuVbFXa0,8286
22
+ climate_ref/datasets/cmip6.py,sha256=Dhq97ow8OmTshDCaL7vfrwn83Nfi6SY8uxJHeY4ZDHk,6083
23
+ climate_ref/datasets/obs4mips.py,sha256=PQhI3QKlYA9L2d_MpnlcVrUn4irMG7Iu-II8l1ncjUs,7032
24
+ climate_ref/datasets/pmp_climatology.py,sha256=goHDc_3B2Wdiy_hmpERNvWDdDYZACPOyFDt3Du6nGc0,534
25
+ climate_ref/datasets/utils.py,sha256=iLJO7h4G3DWsRe9hIC4qkIyi5_zIW1ZMw-FDASLujtM,359
26
+ climate_ref/executor/__init__.py,sha256=DooN4jQudmLHyw24IfqNfWynfa1vEolLs-mZ7uY8O0k,604
27
+ climate_ref/executor/local.py,sha256=W62scL2UTtBurhYQz9hVIHrYiq9-FeMKRdnajqiohN0,7753
28
+ climate_ref/executor/result_handling.py,sha256=UxhOTTe1a1p1sU1mZuFTChvhz06CbjY_NFl9BuWYj48,7885
29
+ climate_ref/executor/synchronous.py,sha256=o4TndsoKMu9AzJYLkusU9lRkgHCy6HcCP46tEs6o86U,1895
30
+ climate_ref/migrations/README,sha256=xM5osYbyEbEFA2eh5kwary_oh-5VFWtDubA-vgWwvlE,935
31
+ climate_ref/migrations/env.py,sha256=I3anCdIHAZlYDXpTrAeHlNieLd7-0t_xknuG1tzgNWE,4252
32
+ climate_ref/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
33
+ climate_ref/migrations/versions/2025-05-02T1418_341a4aa2551e_regenerate.py,sha256=S8Q4THCI4TPnlaQHgQJUCiNW5LAyQClaiTB-0dwhtXU,14050
34
+ climate_ref/migrations/versions/2025-05-09T2032_03dbb4998e49_series_metric_value.py,sha256=s9nZ_l64pSF7sWN53rRPCQlqW_xHqR8tlWhU-ovmsME,2043
35
+ climate_ref/models/__init__.py,sha256=rUDKRANeAEAHVOrzJVIZoZ99dDG5O4AGzHmOpC876Nc,801
36
+ climate_ref/models/base.py,sha256=YMyovT2Z_tRv59zz6qC9YCCDodhO3x6OLnFdBtPJkho,1271
37
+ climate_ref/models/dataset.py,sha256=Rpwrx0HqOJBHs4Sb4n6B0In__Uo0PqXSZKvZR-juGCg,7491
38
+ climate_ref/models/diagnostic.py,sha256=YB6xzbEXdpz2j-Ddf19RV8mAiWBrkmtRmiAEUV3tl4Q,1762
39
+ climate_ref/models/execution.py,sha256=lRCpaKLSR7rZbuoL94GW76tm9wLMsSDoIOA7bIa6xgY,9848
40
+ climate_ref/models/metric_value.py,sha256=44OLcZz-qLx-p_9w7YWDKpD5S7Y9HyTKKsvSb77RBro,10190
41
+ climate_ref/models/provider.py,sha256=RAE2qAAxwObu-72CdK4kt5ACMmKYEn07WJm7DU9hF28,990
42
+ climate_ref-0.5.1.dist-info/METADATA,sha256=nOjrD0Q5EZuPUJO3pnmtaRNEkYP-CWKnnn4Q6kh-VAU,4123
43
+ climate_ref-0.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
+ climate_ref-0.5.1.dist-info/entry_points.txt,sha256=IaggEJlDIhoYWXdXJafacWbWtCcoEqUKceP1qD7_7vU,44
45
+ climate_ref-0.5.1.dist-info/licenses/LICENCE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
46
+ climate_ref-0.5.1.dist-info/licenses/NOTICE,sha256=4qTlax9aX2-mswYJuVrLqJ9jK1IkN5kSBqfVvYLF3Ws,128
47
+ climate_ref-0.5.1.dist-info/RECORD,,
@@ -1,44 +0,0 @@
1
- climate_ref/__init__.py,sha256=OJl5EnjLyEoCQpa0zQ8edV8EcU2YxBJ0xjermIlm9Bw,820
2
- climate_ref/_config_helpers.py,sha256=-atI5FX7SukhLE_jz_rL-EHQ7s0YYqKu3dSFYWxSyMU,6632
3
- climate_ref/alembic.ini,sha256=WRvbwSIFuZ7hWNMnR2-yHPJAwYUnwhvRYBzkJhtpGdg,3535
4
- climate_ref/config.py,sha256=QW1HOLajC2Gc5xZnrGQ8YLAver3BAlVBrfl1kVd_IyM,15072
5
- climate_ref/constants.py,sha256=rFk3XxNuP0lkzTvUneIhNLq16uadXsT45aUFIlSiBmg,111
6
- climate_ref/database.py,sha256=RCffNHbJcxxukN6PIOXBTW9TALE2rRsxU0chJHxyNK4,7257
7
- climate_ref/provider_registry.py,sha256=P35H4VFcsxJ8-Ly4Czwi_gelDU_nF5RiqSC-iBcx_Ws,4116
8
- climate_ref/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- climate_ref/solver.py,sha256=Hpb_3g-hYWopuBYyqaEtOgfuLOHfZpWbwP1rco802uE,14310
10
- climate_ref/testing.py,sha256=rUdtU8a4p2OV35IO87veW0mEB9C4Bqwe7BBQU6BILhs,3889
11
- climate_ref/cli/__init__.py,sha256=RSzaFkgwn1qWRBVbWlDKtNrIxLvQ2T7IWDBIqptpjjU,3658
12
- climate_ref/cli/_utils.py,sha256=6bIb8zEVvzXyKpv8MG58T-T2L2jH-G8WNrOOGpz3uCw,1918
13
- climate_ref/cli/config.py,sha256=8I6CLdqKgTu6yaASy-qG0T839Fc0lDZtLSZ6YCc4wOY,520
14
- climate_ref/cli/datasets.py,sha256=SLl88S3BxKPRbHy9OJ1ymhMnxDmkadFO_BZTIeLR0k8,7367
15
- climate_ref/cli/executions.py,sha256=6cnMxPK4ZydscUw_Mk9RMISNjP2Yr98BgsOsei8fQ7w,6799
16
- climate_ref/cli/providers.py,sha256=XVZQsZoEqiCBvgSmp6cNf0mCTxeq_Ycoc6DwVxWDYKg,2521
17
- climate_ref/cli/solve.py,sha256=D6rAivfm_yl1TTey_zc4KKwZ96LGGF8N1wHjcJ_0XpE,703
18
- climate_ref/dataset_registry/obs4ref_reference.txt,sha256=1NodZd3tOS9Z1Afpb_Oq4obp4OGAFDSAwEl3FssPwAQ,251
19
- climate_ref/dataset_registry/sample_data.txt,sha256=aKl9tfO4vknZ5X2mmdyxKOv-nyWhkPDXnpDoNLLTzE8,11892
20
- climate_ref/datasets/__init__.py,sha256=PV3u5ZmhyfcHbKqySgwVA8m4-naZgxzydLXSBqdTGLM,1171
21
- climate_ref/datasets/base.py,sha256=XplxCu4bfFmNHp2q8tHT26lB0RHv5swK0QqfUmuMO-c,8154
22
- climate_ref/datasets/cmip6.py,sha256=Dhq97ow8OmTshDCaL7vfrwn83Nfi6SY8uxJHeY4ZDHk,6083
23
- climate_ref/datasets/obs4mips.py,sha256=PQhI3QKlYA9L2d_MpnlcVrUn4irMG7Iu-II8l1ncjUs,7032
24
- climate_ref/datasets/pmp_climatology.py,sha256=goHDc_3B2Wdiy_hmpERNvWDdDYZACPOyFDt3Du6nGc0,534
25
- climate_ref/datasets/utils.py,sha256=iLJO7h4G3DWsRe9hIC4qkIyi5_zIW1ZMw-FDASLujtM,359
26
- climate_ref/executor/__init__.py,sha256=vUkE5Izfietvc57gA8LTdaD5IErKVebcE6qO7M7sCRo,9286
27
- climate_ref/executor/local.py,sha256=3icom02FCHiN0tIpsXR9tvn8-cQrUyoY-LlbHapbTx4,2920
28
- climate_ref/migrations/README,sha256=xM5osYbyEbEFA2eh5kwary_oh-5VFWtDubA-vgWwvlE,935
29
- climate_ref/migrations/env.py,sha256=b8om-LvFhVo_2BgaRsR8LcPQ-YcevjWikaWE6uhScAs,4213
30
- climate_ref/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
31
- climate_ref/migrations/versions/2025-05-02T1418_341a4aa2551e_regenerate.py,sha256=349kbd58NdFHqqUAPDX1kR9RUOcxT2zXh9v9yg9-Je8,15533
32
- climate_ref/models/__init__.py,sha256=dFyqfhTffZz4m06xD4SyvRL9kIBRyVYetHwOxFGy4VM,713
33
- climate_ref/models/base.py,sha256=cMjNpGNU7pxRi9A5KXEmQIA9pvQDwqGCwo539yndpGY,1199
34
- climate_ref/models/dataset.py,sha256=Rpwrx0HqOJBHs4Sb4n6B0In__Uo0PqXSZKvZR-juGCg,7491
35
- climate_ref/models/diagnostic.py,sha256=YB6xzbEXdpz2j-Ddf19RV8mAiWBrkmtRmiAEUV3tl4Q,1762
36
- climate_ref/models/execution.py,sha256=lRCpaKLSR7rZbuoL94GW76tm9wLMsSDoIOA7bIa6xgY,9848
37
- climate_ref/models/metric_value.py,sha256=Sfjem65ih9g6WDpjGsiOphSjhYQ1ZAYUPZmsKyb_psU,6452
38
- climate_ref/models/provider.py,sha256=RAE2qAAxwObu-72CdK4kt5ACMmKYEn07WJm7DU9hF28,990
39
- climate_ref-0.5.0.dist-info/METADATA,sha256=pTjBsQveKvV8KGgvD9fy8LoxQ5CS-1ruBoFM4ReeLvY,4028
40
- climate_ref-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
- climate_ref-0.5.0.dist-info/entry_points.txt,sha256=IaggEJlDIhoYWXdXJafacWbWtCcoEqUKceP1qD7_7vU,44
42
- climate_ref-0.5.0.dist-info/licenses/LICENCE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
43
- climate_ref-0.5.0.dist-info/licenses/NOTICE,sha256=4qTlax9aX2-mswYJuVrLqJ9jK1IkN5kSBqfVvYLF3Ws,128
44
- climate_ref-0.5.0.dist-info/RECORD,,