climate-ref-pmp 0.8.0__tar.gz → 0.9.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.
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/.gitignore +10 -1
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/PKG-INFO +1 -1
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/pyproject.toml +1 -1
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/__init__.py +38 -1
- climate_ref_pmp-0.9.0/tests/integration/test_diagnostics.py +137 -0
- climate_ref_pmp-0.9.0/tests/unit/test_provider.py +102 -0
- climate_ref_pmp-0.8.0/tests/integration/test_diagnostics.py +0 -27
- climate_ref_pmp-0.8.0/tests/unit/test_provider.py +0 -9
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/LICENCE +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/NOTICE +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/README.md +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/conftest.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/dataset_registry/pmp_climatology.txt +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/__init__.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/annual_cycle.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/enso.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/variability_modes.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/drivers/enso_driver.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_MoV-psl.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_MoV-ts.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_annualcycle_1-clims.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_annualcycle_2-metrics.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/pmp_driver.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/py.typed +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/requirements/conda-lock.yml +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/requirements/environment.yml +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/tests/unit/conftest.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/tests/unit/test_annual_cycle.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/tests/unit/test_enso.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/tests/unit/test_pmp_driver.py +0 -0
- {climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/tests/unit/test_variability_modes.py +0 -0
|
@@ -150,7 +150,7 @@ dmypy.json
|
|
|
150
150
|
|
|
151
151
|
# Generated output
|
|
152
152
|
out
|
|
153
|
-
.ref
|
|
153
|
+
.ref*
|
|
154
154
|
|
|
155
155
|
# Ignore copied LICENCE/NOTICE files
|
|
156
156
|
packages/*/LICENCE
|
|
@@ -158,3 +158,12 @@ packages/*/NOTICE
|
|
|
158
158
|
|
|
159
159
|
# Local directory for data
|
|
160
160
|
/data
|
|
161
|
+
|
|
162
|
+
# Generated SDK
|
|
163
|
+
/climate_ref_client
|
|
164
|
+
|
|
165
|
+
# User-specific catalog paths (test data)
|
|
166
|
+
*.paths.yaml
|
|
167
|
+
|
|
168
|
+
# Helm dependencies
|
|
169
|
+
helm/charts/*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: climate-ref-pmp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: PMP diagnostic provider for the Rapid Evaluation Framework
|
|
5
5
|
Author-email: Jiwoo Lee <jwlee@llnl.gov>, Jared Lewis <jared.lewis@climate-resource.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -6,11 +6,18 @@ from __future__ import annotations
|
|
|
6
6
|
|
|
7
7
|
import importlib.metadata
|
|
8
8
|
import os
|
|
9
|
+
from pathlib import Path
|
|
9
10
|
from typing import TYPE_CHECKING
|
|
10
11
|
|
|
12
|
+
import pooch
|
|
11
13
|
from loguru import logger
|
|
12
14
|
|
|
13
|
-
from climate_ref_core.dataset_registry import
|
|
15
|
+
from climate_ref_core.dataset_registry import (
|
|
16
|
+
DATASET_URL,
|
|
17
|
+
dataset_registry_manager,
|
|
18
|
+
fetch_all_files,
|
|
19
|
+
validate_registry_cache,
|
|
20
|
+
)
|
|
14
21
|
from climate_ref_core.providers import CondaDiagnosticProvider
|
|
15
22
|
from climate_ref_pmp.diagnostics import ENSO, AnnualCycle, ExtratropicalModesOfVariability
|
|
16
23
|
|
|
@@ -19,6 +26,8 @@ if TYPE_CHECKING:
|
|
|
19
26
|
|
|
20
27
|
__version__ = importlib.metadata.version("climate-ref-pmp")
|
|
21
28
|
|
|
29
|
+
_REGISTRY_NAME = "pmp-climatology"
|
|
30
|
+
|
|
22
31
|
|
|
23
32
|
# Create the PMP diagnostics provider
|
|
24
33
|
# PMP uses a conda environment to run the diagnostics
|
|
@@ -38,6 +47,34 @@ class PMPDiagnosticProvider(CondaDiagnosticProvider):
|
|
|
38
47
|
logger.debug("Setting env variable 'FI_PROVIDER=tcp'")
|
|
39
48
|
self.env_vars["FI_PROVIDER"] = "tcp"
|
|
40
49
|
|
|
50
|
+
def fetch_data(self, config: Config) -> None:
|
|
51
|
+
"""Fetch PMP climatology data."""
|
|
52
|
+
registry = dataset_registry_manager[_REGISTRY_NAME]
|
|
53
|
+
fetch_all_files(registry, _REGISTRY_NAME, output_dir=None)
|
|
54
|
+
|
|
55
|
+
def validate_setup(self, config: Config) -> bool:
|
|
56
|
+
"""Validate conda environment and data checksums."""
|
|
57
|
+
# First check conda environment
|
|
58
|
+
if not super().validate_setup(config):
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
# Then check data checksums
|
|
62
|
+
registry = dataset_registry_manager[_REGISTRY_NAME]
|
|
63
|
+
errors = validate_registry_cache(registry, _REGISTRY_NAME)
|
|
64
|
+
if errors:
|
|
65
|
+
for error in errors:
|
|
66
|
+
logger.error(f"{self.slug} validation failed: {error}")
|
|
67
|
+
logger.error(
|
|
68
|
+
f"Data for {self.slug} is missing or corrupted. "
|
|
69
|
+
f"Please run `ref providers setup --provider {self.slug}` to fetch data."
|
|
70
|
+
)
|
|
71
|
+
return False
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
def get_data_path(self) -> Path | None:
|
|
75
|
+
"""Get the path where PMP data is cached."""
|
|
76
|
+
return Path(pooch.os_cache("climate_ref"))
|
|
77
|
+
|
|
41
78
|
|
|
42
79
|
provider = PMPDiagnosticProvider("PMP", __version__)
|
|
43
80
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from climate_ref_pmp import provider
|
|
5
|
+
|
|
6
|
+
from climate_ref.testing import TestCaseRunner, validate_result
|
|
7
|
+
from climate_ref_core.diagnostics import Diagnostic
|
|
8
|
+
from climate_ref_core.testing import (
|
|
9
|
+
RegressionValidator,
|
|
10
|
+
TestCasePaths,
|
|
11
|
+
collect_test_case_params,
|
|
12
|
+
load_datasets_from_yaml,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.fixture(scope="session")
|
|
17
|
+
def provider_test_data_dir() -> Path:
|
|
18
|
+
"""Path to the package-local test data directory."""
|
|
19
|
+
return Path(__file__).parent.parent / "test-data"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
enso_skip_diagnostics = [
|
|
23
|
+
"enso-teleconnections",
|
|
24
|
+
"enso-clivar-teleconnections",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
diagnostics = [
|
|
28
|
+
pytest.param(
|
|
29
|
+
diagnostic,
|
|
30
|
+
id=diagnostic.slug,
|
|
31
|
+
marks=[
|
|
32
|
+
*(
|
|
33
|
+
[pytest.mark.skip(reason="ENSO diagnostics do not support the sample data")]
|
|
34
|
+
if diagnostic.slug in enso_skip_diagnostics
|
|
35
|
+
else []
|
|
36
|
+
),
|
|
37
|
+
],
|
|
38
|
+
)
|
|
39
|
+
for diagnostic in provider.diagnostics()
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
# Test case params for parameterized test_case tests
|
|
43
|
+
test_case_params = collect_test_case_params(provider)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.mark.slow
|
|
47
|
+
@pytest.mark.parametrize("diagnostic", diagnostics)
|
|
48
|
+
def test_diagnostics(diagnostic: Diagnostic, diagnostic_validation):
|
|
49
|
+
if "enso" in diagnostic.slug:
|
|
50
|
+
pytest.skip("ENSO diagnostics do not support the sample data")
|
|
51
|
+
|
|
52
|
+
validator = diagnostic_validation(diagnostic)
|
|
53
|
+
|
|
54
|
+
definition = validator.get_definition()
|
|
55
|
+
validator.execute(definition)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@pytest.mark.parametrize("diagnostic", diagnostics)
|
|
59
|
+
def test_build_results(diagnostic: Diagnostic, diagnostic_validation):
|
|
60
|
+
validator = diagnostic_validation(diagnostic)
|
|
61
|
+
|
|
62
|
+
definition = validator.get_regression_definition()
|
|
63
|
+
validator.validate(definition)
|
|
64
|
+
validator.execution_regression.check(definition.key, definition.output_directory)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.mark.parametrize("diagnostic,test_case_name", test_case_params)
|
|
68
|
+
def test_validate_test_case_regression(
|
|
69
|
+
diagnostic: Diagnostic,
|
|
70
|
+
test_case_name: str,
|
|
71
|
+
provider_test_data_dir: Path,
|
|
72
|
+
config,
|
|
73
|
+
tmp_path: Path,
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Validate pre-stored test case regression outputs as CMEC bundles.
|
|
77
|
+
|
|
78
|
+
Each diagnostic/test_case is a separate parameterized test.
|
|
79
|
+
"""
|
|
80
|
+
diagnostic.provider.configure(config)
|
|
81
|
+
|
|
82
|
+
paths = TestCasePaths.from_test_data_dir(
|
|
83
|
+
provider_test_data_dir,
|
|
84
|
+
diagnostic.slug,
|
|
85
|
+
test_case_name,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if not paths.catalog.exists():
|
|
89
|
+
pytest.skip(f"No catalog file for {diagnostic.slug}/{test_case_name}")
|
|
90
|
+
if not paths.regression.exists():
|
|
91
|
+
pytest.skip(f"No regression data for {diagnostic.slug}/{test_case_name}")
|
|
92
|
+
|
|
93
|
+
validator = RegressionValidator(
|
|
94
|
+
diagnostic=diagnostic,
|
|
95
|
+
test_case_name=test_case_name,
|
|
96
|
+
test_data_dir=provider_test_data_dir,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
definition = validator.load_regression_definition(tmp_path / diagnostic.slug / test_case_name)
|
|
100
|
+
validator.validate(definition)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@pytest.mark.slow
|
|
104
|
+
@pytest.mark.test_cases
|
|
105
|
+
@pytest.mark.parametrize("diagnostic,test_case_name", test_case_params)
|
|
106
|
+
def test_run_test_cases(
|
|
107
|
+
diagnostic: Diagnostic,
|
|
108
|
+
test_case_name: str,
|
|
109
|
+
provider_test_data_dir: Path,
|
|
110
|
+
config,
|
|
111
|
+
tmp_path: Path,
|
|
112
|
+
):
|
|
113
|
+
"""
|
|
114
|
+
Run diagnostic test cases end-to-end with ESGF data.
|
|
115
|
+
|
|
116
|
+
Requires: `ref test-cases fetch --provider pmp` to have been run first.
|
|
117
|
+
"""
|
|
118
|
+
diagnostic.provider.configure(config)
|
|
119
|
+
|
|
120
|
+
paths = TestCasePaths.from_test_data_dir(
|
|
121
|
+
provider_test_data_dir,
|
|
122
|
+
diagnostic.slug,
|
|
123
|
+
test_case_name,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if not paths.catalog.exists():
|
|
127
|
+
pytest.skip(f"No catalog file for {diagnostic.slug}/{test_case_name}")
|
|
128
|
+
|
|
129
|
+
datasets = load_datasets_from_yaml(paths.catalog)
|
|
130
|
+
|
|
131
|
+
runner = TestCaseRunner(config=config, datasets=datasets)
|
|
132
|
+
output_dir = tmp_path / diagnostic.slug / test_case_name
|
|
133
|
+
|
|
134
|
+
result = runner.run(diagnostic, test_case_name, output_dir)
|
|
135
|
+
|
|
136
|
+
assert result.successful, f"Diagnostic {diagnostic.slug} failed"
|
|
137
|
+
validate_result(diagnostic, config, result)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
import pooch
|
|
4
|
+
from climate_ref_pmp import PMPDiagnosticProvider, __version__, provider
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_provider():
|
|
8
|
+
assert provider.name == "PMP"
|
|
9
|
+
assert provider.slug == "pmp"
|
|
10
|
+
assert provider.version == __version__
|
|
11
|
+
|
|
12
|
+
assert len(provider) >= 1
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestPMPProviderHooks:
|
|
16
|
+
"""Tests for PMPDiagnosticProvider lifecycle hooks."""
|
|
17
|
+
|
|
18
|
+
def test_get_data_path(self):
|
|
19
|
+
"""Test that get_data_path returns the pooch cache path."""
|
|
20
|
+
data_path = provider.get_data_path()
|
|
21
|
+
assert data_path is not None
|
|
22
|
+
assert isinstance(data_path, Path)
|
|
23
|
+
assert data_path == Path(pooch.os_cache("climate_ref"))
|
|
24
|
+
|
|
25
|
+
def test_fetch_data(self, mocker):
|
|
26
|
+
"""Test that fetch_data calls fetch_all_files."""
|
|
27
|
+
mock_fetch = mocker.patch("climate_ref_pmp.fetch_all_files")
|
|
28
|
+
mock_config = mocker.Mock()
|
|
29
|
+
|
|
30
|
+
provider.fetch_data(mock_config)
|
|
31
|
+
|
|
32
|
+
mock_fetch.assert_called_once()
|
|
33
|
+
# Check it's using the right registry name
|
|
34
|
+
call_args = mock_fetch.call_args
|
|
35
|
+
assert call_args[0][1] == "pmp-climatology"
|
|
36
|
+
assert call_args[1]["output_dir"] is None
|
|
37
|
+
|
|
38
|
+
def test_validate_setup_env_missing(self, mocker):
|
|
39
|
+
"""Test validate_setup returns False when conda env is missing."""
|
|
40
|
+
mock_config = mocker.Mock()
|
|
41
|
+
# Mock the parent class to return False
|
|
42
|
+
mocker.patch.object(
|
|
43
|
+
PMPDiagnosticProvider.__bases__[0],
|
|
44
|
+
"validate_setup",
|
|
45
|
+
return_value=False,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
result = provider.validate_setup(mock_config)
|
|
49
|
+
assert result is False
|
|
50
|
+
|
|
51
|
+
def test_validate_setup_data_invalid(self, mocker):
|
|
52
|
+
"""Test validate_setup returns False when data validation fails."""
|
|
53
|
+
mock_config = mocker.Mock()
|
|
54
|
+
# Mock parent class to return True (conda env exists)
|
|
55
|
+
mocker.patch.object(
|
|
56
|
+
PMPDiagnosticProvider.__bases__[0],
|
|
57
|
+
"validate_setup",
|
|
58
|
+
return_value=True,
|
|
59
|
+
)
|
|
60
|
+
# Mock data validation to return errors
|
|
61
|
+
mocker.patch(
|
|
62
|
+
"climate_ref_pmp.validate_registry_cache",
|
|
63
|
+
return_value=["File missing: test.nc"],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
result = provider.validate_setup(mock_config)
|
|
67
|
+
assert result is False
|
|
68
|
+
|
|
69
|
+
def test_validate_setup_all_valid(self, mocker):
|
|
70
|
+
"""Test validate_setup returns True when all validation passes."""
|
|
71
|
+
mock_config = mocker.Mock()
|
|
72
|
+
# Mock parent class to return True (conda env exists)
|
|
73
|
+
mocker.patch.object(
|
|
74
|
+
PMPDiagnosticProvider.__bases__[0],
|
|
75
|
+
"validate_setup",
|
|
76
|
+
return_value=True,
|
|
77
|
+
)
|
|
78
|
+
# Mock data validation to return no errors
|
|
79
|
+
mocker.patch(
|
|
80
|
+
"climate_ref_pmp.validate_registry_cache",
|
|
81
|
+
return_value=[],
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
result = provider.validate_setup(mock_config)
|
|
85
|
+
assert result is True
|
|
86
|
+
|
|
87
|
+
def test_configure_sets_env_vars(self, mocker, tmp_path):
|
|
88
|
+
"""Test that configure sets the required environment variables."""
|
|
89
|
+
test_provider = PMPDiagnosticProvider("PMP-Test", "1.0")
|
|
90
|
+
mock_config = mocker.Mock()
|
|
91
|
+
mock_config.paths.software = tmp_path / "software"
|
|
92
|
+
mock_config.ignore_datasets_file = tmp_path / "ignore.yaml"
|
|
93
|
+
mock_config.ignore_datasets_file.touch()
|
|
94
|
+
|
|
95
|
+
mocker.patch.object(test_provider, "get_conda_exe", return_value=Path("/path/to/conda"))
|
|
96
|
+
|
|
97
|
+
test_provider.configure(mock_config)
|
|
98
|
+
|
|
99
|
+
assert "PCMDI_CONDA_EXE" in test_provider.env_vars
|
|
100
|
+
assert test_provider.env_vars["PCMDI_CONDA_EXE"] == "/path/to/conda"
|
|
101
|
+
assert "FI_PROVIDER" in test_provider.env_vars
|
|
102
|
+
assert test_provider.env_vars["FI_PROVIDER"] == "tcp"
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
from climate_ref_pmp import provider as pmp_provider
|
|
3
|
-
|
|
4
|
-
from climate_ref_core.diagnostics import Diagnostic
|
|
5
|
-
|
|
6
|
-
diagnostics = [pytest.param(diagnostic, id=diagnostic.slug) for diagnostic in pmp_provider.diagnostics()]
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@pytest.mark.slow
|
|
10
|
-
@pytest.mark.parametrize("diagnostic", diagnostics)
|
|
11
|
-
def test_diagnostics(diagnostic: Diagnostic, diagnostic_validation):
|
|
12
|
-
if "enso" in diagnostic.slug:
|
|
13
|
-
pytest.skip("ENSO diagnostics do not support the sample data")
|
|
14
|
-
|
|
15
|
-
validator = diagnostic_validation(diagnostic)
|
|
16
|
-
|
|
17
|
-
definition = validator.get_definition()
|
|
18
|
-
validator.execute(definition)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@pytest.mark.parametrize("diagnostic", diagnostics)
|
|
22
|
-
def test_build_results(diagnostic: Diagnostic, diagnostic_validation):
|
|
23
|
-
validator = diagnostic_validation(diagnostic)
|
|
24
|
-
|
|
25
|
-
definition = validator.get_regression_definition()
|
|
26
|
-
validator.validate(definition)
|
|
27
|
-
validator.execution_regression.check(definition.key, definition.output_directory)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/annual_cycle.py
RENAMED
|
File without changes
|
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/diagnostics/variability_modes.py
RENAMED
|
File without changes
|
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_MoV-psl.py
RENAMED
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/params/pmp_param_MoV-ts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/requirements/conda-lock.yml
RENAMED
|
File without changes
|
{climate_ref_pmp-0.8.0 → climate_ref_pmp-0.9.0}/src/climate_ref_pmp/requirements/environment.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|