OceanDataStore 0.3.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.
- OceanDataStore/__init__.py +21 -0
- OceanDataStore/catalog/__init__.py +12 -0
- OceanDataStore/catalog/oceandatacatalog.py +1242 -0
- OceanDataStore/catalog/stac/README.md +34 -0
- OceanDataStore/catalog/stac/__init__.py +30 -0
- OceanDataStore/catalog/stac/create_noc_stac.py +109 -0
- OceanDataStore/catalog/stac/npd_era5_collection.py +364 -0
- OceanDataStore/catalog/stac/npd_jra55_collection.py +196 -0
- OceanDataStore/catalog/stac/ods_obs_collection.py +534 -0
- OceanDataStore/catalog/stac/rapid_evo_collection.py +309 -0
- OceanDataStore/catalog/stac/template_collection.py +85 -0
- OceanDataStore/catalog/stac/utils.py +476 -0
- OceanDataStore/cli/__init__.py +34 -0
- OceanDataStore/cli/arg_parser.py +182 -0
- OceanDataStore/cli/cli.py +203 -0
- OceanDataStore/cli/exceptions.py +83 -0
- OceanDataStore/cli/icechunk.py +888 -0
- OceanDataStore/cli/logging.py +52 -0
- OceanDataStore/cli/object_store.py +293 -0
- OceanDataStore/cli/utils.py +275 -0
- OceanDataStore/cli/zarr.py +870 -0
- OceanDataStore/data/ARMOR3D/create_ARMOR3D_P1M-m_monthly_climatology.py +135 -0
- OceanDataStore/data/ARMOR3D/download_ARMOR3D_0.125def_P1M-m_1993_2024.py +33 -0
- OceanDataStore/data/ARMOR3D/run_create_ARMOR3D_P1M-m_monthly_climatology.slurm +32 -0
- OceanDataStore/data/ARMOR3D/run_send_ARMOR3D_P1M-m_climatology_to_os.slurm +32 -0
- OceanDataStore/data/ARMOR3D/run_send_ARMOR3D_P1M-m_monthly_to_os.slurm +32 -0
- OceanDataStore/data/ARMOR3D/run_update_ARMOR3D_P1m-m_monthly_to_os.slurm +32 -0
- OceanDataStore/data/ARMOR3D/send_ARMOR3D_P1m-m_monthly_climatology_to_os.py +99 -0
- OceanDataStore/data/ARMOR3D/send_ARMOR3D_P1m-m_monthly_to_os.py +147 -0
- OceanDataStore/data/ARMOR3D/update_ARMOR3D_P1m-m_monthly_to_os.py +143 -0
- OceanDataStore/data/EN.4.2.2/create_EN4.2.2_analysis_g10_climatology.py +162 -0
- OceanDataStore/data/EN.4.2.2/download_EN4.2.2_analysis_g10_data.sh +51 -0
- OceanDataStore/data/EN.4.2.2/run_send_EN4.2.2_analysis_g10_climatology_to_os.slurm +32 -0
- OceanDataStore/data/EN.4.2.2/run_send_EN4.2.2_analysis_g10_monthly_to_os.slurm +32 -0
- OceanDataStore/data/EN.4.2.2/run_update_EN4.2.2_analysis_g10_monthly_to_os.slurm +32 -0
- OceanDataStore/data/EN.4.2.2/send_EN4.2.2_analysis_g10_monthly_climatology_to_os.py +76 -0
- OceanDataStore/data/EN.4.2.2/send_EN4.2.2_analysis_g10_monthly_to_os.py +165 -0
- OceanDataStore/data/EN.4.2.2/update_EN4.2.2_analysis_g10_monthly_to_os.py +161 -0
- OceanDataStore/data/ERA5/create_ERA5_daily_climatology.py +110 -0
- OceanDataStore/data/ERA5/create_ERA5_daily_mean.py +69 -0
- OceanDataStore/data/ERA5/create_ERA5_monthly_mean.py +74 -0
- OceanDataStore/data/ERA5/run_create_ERA5_daily_climatology.slurm +54 -0
- OceanDataStore/data/ERA5/run_send_ERA5_daily_climatology_to_os.slurm +32 -0
- OceanDataStore/data/ERA5/run_send_ERA5_daily_to_os.slurm +32 -0
- OceanDataStore/data/ERA5/run_send_ERA5_monthly_to_os.slurm +32 -0
- OceanDataStore/data/ERA5/run_update_ERA5_daily_to_os.slurm +32 -0
- OceanDataStore/data/ERA5/run_update_ERA5_monthly_to_os.slurm +32 -0
- OceanDataStore/data/ERA5/send_ERA5_daily_climatology_to_os.py +159 -0
- OceanDataStore/data/ERA5/send_ERA5_daily_to_os.py +141 -0
- OceanDataStore/data/ERA5/send_ERA5_monthly_to_os.py +173 -0
- OceanDataStore/data/ERA5/update_ERA5_daily_to_os.py +141 -0
- OceanDataStore/data/ERA5/update_ERA5_monthly_to_os.py +169 -0
- OceanDataStore/data/HadISST/download_HadISST1_data.sh +43 -0
- OceanDataStore/data/HadISST/run_send_HadISST1_monthly_to_os.slurm +32 -0
- OceanDataStore/data/HadISST/send_HadISST1_monthly_to_os.py +133 -0
- OceanDataStore/data/NSIDC/download_NSIDC_monthly_1979_2025_data.sh +54 -0
- OceanDataStore/data/NSIDC/process_NSIDC_SSI_Antarctic_data.py +130 -0
- OceanDataStore/data/NSIDC/process_NSIDC_SSI_Arctic_data.py +129 -0
- OceanDataStore/data/NSIDC/run_send_NSIDC_v4.0_to_OS.slurm +32 -0
- OceanDataStore/data/NSIDC/send_NSIDC_SII_v4.0_to_os.py +140 -0
- OceanDataStore/data/OISST/create_OISSTv2_daily_climatology.py +83 -0
- OceanDataStore/data/OISST/download_oisstv2_data.sh +43 -0
- OceanDataStore/data/OISST/run_create_OISSTv2_daily_climatology.slurm +44 -0
- OceanDataStore/data/OISST/run_send_OISSTv2_daily_climatology_to_os.slurm +32 -0
- OceanDataStore/data/OISST/run_send_OISSTv2_daily_to_os.slurm +32 -0
- OceanDataStore/data/OISST/run_send_OISSTv2_monthly_climatology_to_os.slurm +32 -0
- OceanDataStore/data/OISST/run_send_OISSTv2_monthly_to_os.slurm +32 -0
- OceanDataStore/data/OISST/run_update_OISSTv2_daily_to_os.slurm +32 -0
- OceanDataStore/data/OISST/send_OISSTv2_daily_climatology_to_os.py +154 -0
- OceanDataStore/data/OISST/send_OISSTv2_daily_ltm_climatology_to_os.py +151 -0
- OceanDataStore/data/OISST/send_OISSTv2_daily_to_os.py +142 -0
- OceanDataStore/data/OISST/send_OISSTv2_monthly_climatology_to_os.py +150 -0
- OceanDataStore/data/OISST/send_OISSTv2_monthly_to_os.py +145 -0
- OceanDataStore/data/OISST/update_OISSTv2_daily_to_os.py +142 -0
- OceanDataStore/data/OSTIA/create_OSTIA_daily_climatology.py +120 -0
- OceanDataStore/data/OSTIA/download_OSTIA_NRT.py +42 -0
- OceanDataStore/data/OSTIA/download_OSTIA_REP_1981_2025.py +42 -0
- OceanDataStore/data/OSTIA/run_create_OSTIA_daily_climatology.slurm +54 -0
- OceanDataStore/data/OSTIA/run_send_OSTIA_daily_climatology_to_os.slurm +32 -0
- OceanDataStore/data/OSTIA/run_send_OSTIA_nrt_daily_to_os.slurm +32 -0
- OceanDataStore/data/OSTIA/run_send_OSTIA_rep_daily_to_os.slurm +32 -0
- OceanDataStore/data/OSTIA/run_update_OSTIA_daily_to_os.slurm +33 -0
- OceanDataStore/data/OSTIA/send_OSTIA_daily_climatology_to_os.py +194 -0
- OceanDataStore/data/OSTIA/send_OSTIA_nrt_daily_to_os.py +141 -0
- OceanDataStore/data/OSTIA/send_OSTIA_rep_daily_to_os.py +145 -0
- OceanDataStore/data/OSTIA/update_OSTIA_copernicus_nrt_daily_to_os.py +144 -0
- OceanDataStore/data/OSTIA/update_OSTIA_nrt_daily_to_os.py +137 -0
- OceanDataStore/data/WOA23/download_WOA23_climatology.sh +41 -0
- OceanDataStore/data/WOA23/run_send_WOA23_annual_climatology_to_os.slurm +32 -0
- OceanDataStore/data/WOA23/run_send_WOA23_monthly_climatology_to_os.slurm +32 -0
- OceanDataStore/data/WOA23/send_WOA23_annual_climatology_to_os.py +263 -0
- OceanDataStore/data/WOA23/send_WOA23_monthly_climatology_to_os.py +292 -0
- OceanDataStore/data/update_icechunk_repo_attrs.py +76 -0
- OceanDataStore/data/update_noc_npd_era5v1_attrs.py +172 -0
- OceanDataStore/data/utils.py +506 -0
- OceanDataStore/zarr.py +993 -0
- oceandatastore-0.3.0.dist-info/METADATA +184 -0
- oceandatastore-0.3.0.dist-info/RECORD +104 -0
- oceandatastore-0.3.0.dist-info/WHEEL +5 -0
- oceandatastore-0.3.0.dist-info/entry_points.txt +2 -0
- oceandatastore-0.3.0.dist-info/licenses/LICENSE +201 -0
- oceandatastore-0.3.0.dist-info/scm_file_list.json +154 -0
- oceandatastore-0.3.0.dist-info/scm_version.json +8 -0
- oceandatastore-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# Copyright 2026 National Oceanography Centre
|
|
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
|
+
# http://www.apache.org/licenses/LICENSE-2.0.
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
11
|
+
# implied. See the License for the specific language governing
|
|
12
|
+
# permissions and limitations under the License.
|
|
13
|
+
# ===================================================================
|
|
14
|
+
"""
|
|
15
|
+
arg_parser.py
|
|
16
|
+
|
|
17
|
+
Description:
|
|
18
|
+
This module defines the argument parser for the OceanDataStore command
|
|
19
|
+
line interface.
|
|
20
|
+
|
|
21
|
+
Authors:
|
|
22
|
+
- Ollie Tooth
|
|
23
|
+
- Joao Morado
|
|
24
|
+
- Tobias Ferreira
|
|
25
|
+
"""
|
|
26
|
+
import json
|
|
27
|
+
import argparse
|
|
28
|
+
|
|
29
|
+
from OceanDataStore import __version__
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_parser():
|
|
33
|
+
"""Create the argument parser."""
|
|
34
|
+
parser = argparse.ArgumentParser(
|
|
35
|
+
description=f"OceanDataStore {__version__} command line interface",
|
|
36
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Send and Update are mutually exclusive operations
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"action",
|
|
42
|
+
choices=["send_to_zarr", "update_zarr", "send_to_icechunk", "update_icechunk", "list"],
|
|
43
|
+
help="Specify the action: 'send_to_zarr' or 'send_to_icechunk' to send a file(s) to an object store, "
|
|
44
|
+
"'update_zarr' or 'update_icechunk' to update an existing object, or 'list' to list the files in a bucket.",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Always required
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
"-f",
|
|
50
|
+
"--filepaths",
|
|
51
|
+
dest="filepaths",
|
|
52
|
+
help="Paths to the files to send.",
|
|
53
|
+
nargs="+",
|
|
54
|
+
required=True,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"-c",
|
|
59
|
+
"--credentials",
|
|
60
|
+
dest="store_credentials_json",
|
|
61
|
+
help="Path to the JSON file containing the credentials for the object store.",
|
|
62
|
+
required=True,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
parser.add_argument(
|
|
66
|
+
"-b",
|
|
67
|
+
"--bucket",
|
|
68
|
+
dest="bucket",
|
|
69
|
+
help="Bucket name.",
|
|
70
|
+
required=True,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Optional arguments
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"-p",
|
|
76
|
+
"--prefix",
|
|
77
|
+
dest="object_prefix",
|
|
78
|
+
help="Object prefix.",
|
|
79
|
+
default=None,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"-ad",
|
|
84
|
+
"--append-dim",
|
|
85
|
+
dest="append_dim",
|
|
86
|
+
help="Append dimension.",
|
|
87
|
+
default="time_counter",
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
parser.add_argument(
|
|
91
|
+
"-v",
|
|
92
|
+
"--variables",
|
|
93
|
+
dest="variables",
|
|
94
|
+
help="Variables to send to store. Default None will send all variables.",
|
|
95
|
+
nargs="+",
|
|
96
|
+
default=None,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"-cs",
|
|
101
|
+
"--chunk-strategy",
|
|
102
|
+
dest="chunk_strategy",
|
|
103
|
+
help="Chunk strategy as a JSON string. E.g., '{\"time_counter\": 1, \"x\": 100, \"y\": 100}'",
|
|
104
|
+
type=json.loads,
|
|
105
|
+
default=None,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
parser.add_argument(
|
|
109
|
+
"-dc",
|
|
110
|
+
"--dask-configuration",
|
|
111
|
+
dest="dask_config_json",
|
|
112
|
+
help="Path to the JSON file defining the Dask Local Cluster configuration.",
|
|
113
|
+
default=None,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"-gf",
|
|
118
|
+
"--grid-filepath",
|
|
119
|
+
dest="grid_filepath",
|
|
120
|
+
help="File path to model grid file containing domain information.",
|
|
121
|
+
default=None,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
parser.add_argument(
|
|
125
|
+
"-uc",
|
|
126
|
+
"--update-coords",
|
|
127
|
+
dest="update_coords",
|
|
128
|
+
help="Coordinate dimensions to update as a JSON string. E.g., '{\"nav_lon\": \"glamt\", \"nav_lat\": \"gphit\"}'",
|
|
129
|
+
type=json.loads,
|
|
130
|
+
default=None,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
parser.add_argument(
|
|
134
|
+
"-at",
|
|
135
|
+
"--attributes",
|
|
136
|
+
dest="attrs",
|
|
137
|
+
help="Attributes to add to the dataset as a JSON string. E.g., '{\"title\": \"my_dataset\"}'",
|
|
138
|
+
type=json.loads,
|
|
139
|
+
default=None,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
parser.add_argument(
|
|
143
|
+
"-zv",
|
|
144
|
+
"--zarr-version",
|
|
145
|
+
dest="zarr_version",
|
|
146
|
+
help="Zarr version used to create the zarr store. Options are 2 (v2) or 3 (v3).",
|
|
147
|
+
default=3,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
parser.add_argument(
|
|
151
|
+
"-br",
|
|
152
|
+
"--branch",
|
|
153
|
+
dest="branch",
|
|
154
|
+
help="Branch of Icechunk repository to commit changes to.",
|
|
155
|
+
default="main",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
parser.add_argument(
|
|
159
|
+
"-cm",
|
|
160
|
+
"--commit_message",
|
|
161
|
+
dest="commit_message",
|
|
162
|
+
help="Commit message to be recorded when committing changes to Icechunk repository.",
|
|
163
|
+
default="Add new data to my Icechunk repository",
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
parser.add_argument(
|
|
167
|
+
"-vc",
|
|
168
|
+
"--variable-commits",
|
|
169
|
+
dest="var_commits",
|
|
170
|
+
action="store_true",
|
|
171
|
+
help="Send variables to Icechunk repository using independent commits.",
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
parser.add_argument(
|
|
175
|
+
"-ic",
|
|
176
|
+
"--icechunk-configuration",
|
|
177
|
+
dest="icechunk_config_json",
|
|
178
|
+
help="Path to the JSON file defining the Icechunk storage and repository configurations.",
|
|
179
|
+
default=None,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return parser
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# Copyright 2026 National Oceanography Centre
|
|
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
|
+
# http://www.apache.org/licenses/LICENSE-2.0.
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
11
|
+
# implied. See the License for the specific language governing
|
|
12
|
+
# permissions and limitations under the License.
|
|
13
|
+
# ===================================================================
|
|
14
|
+
"""
|
|
15
|
+
cli.py
|
|
16
|
+
|
|
17
|
+
Description:
|
|
18
|
+
This module defines the command line interface for the OceanDataStore
|
|
19
|
+
package.
|
|
20
|
+
|
|
21
|
+
Authors:
|
|
22
|
+
- Ollie Tooth
|
|
23
|
+
- Joao Morado
|
|
24
|
+
- Tobias Ferreira
|
|
25
|
+
"""
|
|
26
|
+
import sys
|
|
27
|
+
import json
|
|
28
|
+
import logging
|
|
29
|
+
|
|
30
|
+
from OceanDataStore.cli import (
|
|
31
|
+
send_to_zarr,
|
|
32
|
+
send_to_icechunk,
|
|
33
|
+
update_zarr,
|
|
34
|
+
update_icechunk,
|
|
35
|
+
list_objects
|
|
36
|
+
)
|
|
37
|
+
from OceanDataStore.cli.arg_parser import create_parser
|
|
38
|
+
from OceanDataStore.cli.logging import initialise_logging
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def process_action(args):
|
|
44
|
+
"""Process the selected action."""
|
|
45
|
+
if len(sys.argv) == 1:
|
|
46
|
+
args.parser.print_help()
|
|
47
|
+
sys.exit(0)
|
|
48
|
+
|
|
49
|
+
# === Process Arguments === #
|
|
50
|
+
if args.variables is not None:
|
|
51
|
+
variables = list(args.variables)
|
|
52
|
+
else:
|
|
53
|
+
variables = None
|
|
54
|
+
|
|
55
|
+
if args.filepaths is not None:
|
|
56
|
+
if len(args.filepaths) > 1:
|
|
57
|
+
filepaths = list(args.filepaths)
|
|
58
|
+
else:
|
|
59
|
+
filepaths = args.filepaths
|
|
60
|
+
|
|
61
|
+
if args.zarr_version is not None:
|
|
62
|
+
zarr_version = int(args.zarr_version)
|
|
63
|
+
|
|
64
|
+
if args.dask_config_json is None:
|
|
65
|
+
dask_config = {
|
|
66
|
+
"config_kwargs": None,
|
|
67
|
+
"cluster_kwargs": None,
|
|
68
|
+
}
|
|
69
|
+
else:
|
|
70
|
+
dask_config = json.load(open(args.dask_config_json))
|
|
71
|
+
if "config_kwargs" not in dask_config:
|
|
72
|
+
raise ValueError("config_kwargs not found in Dask configuration.")
|
|
73
|
+
if "cluster_kwargs" not in dask_config:
|
|
74
|
+
raise ValueError("cluster_kwargs not found in Dask configuration.")
|
|
75
|
+
|
|
76
|
+
if args.icechunk_config_json is None:
|
|
77
|
+
# Default: use Icechunk configuration for JASMIN OS:
|
|
78
|
+
icechunk_config = {
|
|
79
|
+
"storage_config_kwargs": {"region": "", "force_path_style": True},
|
|
80
|
+
"repository_config_kwargs": {},
|
|
81
|
+
"storage_settings_kwargs": {"unsafe_use_conditional_update": False, "unsafe_use_conditional_create": False},
|
|
82
|
+
}
|
|
83
|
+
else:
|
|
84
|
+
icechunk_config = json.load(open(args.icechunk_config_json))
|
|
85
|
+
if "storage_config_kwargs" not in icechunk_config:
|
|
86
|
+
raise ValueError("storage_config_kwargs not found in Icechunk configuration.")
|
|
87
|
+
if "repository_config_kwargs" not in icechunk_config:
|
|
88
|
+
raise ValueError("repository_config_kwargs not found in Icechunk configuration.")
|
|
89
|
+
if "storage_settings_kwargs" not in icechunk_config:
|
|
90
|
+
raise ValueError("storage_settings_kwargs not found in Icechunk configuration.")
|
|
91
|
+
|
|
92
|
+
# === Process Actions === #
|
|
93
|
+
if args.action == "send_to_zarr":
|
|
94
|
+
|
|
95
|
+
send_to_zarr(
|
|
96
|
+
file=filepaths,
|
|
97
|
+
bucket=args.bucket,
|
|
98
|
+
object_prefix=args.object_prefix,
|
|
99
|
+
store_credentials_json=args.store_credentials_json,
|
|
100
|
+
variables=variables,
|
|
101
|
+
append_dim=args.append_dim,
|
|
102
|
+
grid_filepath=args.grid_filepath,
|
|
103
|
+
update_coords=args.update_coords,
|
|
104
|
+
rechunk=args.chunk_strategy,
|
|
105
|
+
attrs=args.attrs,
|
|
106
|
+
client=None,
|
|
107
|
+
dask_config_kwargs=dask_config["config_kwargs"],
|
|
108
|
+
dask_cluster_kwargs=dask_config["cluster_kwargs"],
|
|
109
|
+
zarr_version=zarr_version,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
elif args.action == "update_zarr":
|
|
113
|
+
|
|
114
|
+
update_zarr(
|
|
115
|
+
file=filepaths,
|
|
116
|
+
bucket=args.bucket,
|
|
117
|
+
object_prefix=args.object_prefix,
|
|
118
|
+
store_credentials_json=args.store_credentials_json,
|
|
119
|
+
variables=variables,
|
|
120
|
+
append_dim=args.append_dim,
|
|
121
|
+
grid_filepath=args.grid_filepath,
|
|
122
|
+
update_coords=args.update_coords,
|
|
123
|
+
rechunk=args.chunk_strategy,
|
|
124
|
+
attrs=args.attrs,
|
|
125
|
+
client=None,
|
|
126
|
+
dask_config_kwargs=dask_config["config_kwargs"],
|
|
127
|
+
dask_cluster_kwargs=dask_config["cluster_kwargs"],
|
|
128
|
+
zarr_version=zarr_version,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
elif args.action == "send_to_icechunk":
|
|
132
|
+
|
|
133
|
+
send_to_icechunk(
|
|
134
|
+
file=filepaths,
|
|
135
|
+
bucket=args.bucket,
|
|
136
|
+
object_prefix=args.object_prefix,
|
|
137
|
+
store_credentials_json=args.store_credentials_json,
|
|
138
|
+
variables=variables,
|
|
139
|
+
append_dim=args.append_dim,
|
|
140
|
+
grid_filepath=args.grid_filepath,
|
|
141
|
+
update_coords=args.update_coords,
|
|
142
|
+
rechunk=args.chunk_strategy,
|
|
143
|
+
attrs=args.attrs,
|
|
144
|
+
branch=args.branch,
|
|
145
|
+
commit_message=args.commit_message,
|
|
146
|
+
variable_commits=args.var_commits,
|
|
147
|
+
dask_config_kwargs=dask_config["config_kwargs"],
|
|
148
|
+
dask_cluster_kwargs=dask_config["cluster_kwargs"],
|
|
149
|
+
icechunk_config=icechunk_config,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
elif args.action == "update_icechunk":
|
|
153
|
+
|
|
154
|
+
if args.var_commits:
|
|
155
|
+
logger.warning("The --var-commits flag will be ignored when updating an Icechunk repository.")
|
|
156
|
+
|
|
157
|
+
update_icechunk(
|
|
158
|
+
file=filepaths,
|
|
159
|
+
bucket=args.bucket,
|
|
160
|
+
object_prefix=args.object_prefix,
|
|
161
|
+
store_credentials_json=args.store_credentials_json,
|
|
162
|
+
variables=variables,
|
|
163
|
+
append_dim=args.append_dim,
|
|
164
|
+
grid_filepath=args.grid_filepath,
|
|
165
|
+
update_coords=args.update_coords,
|
|
166
|
+
rechunk=args.chunk_strategy,
|
|
167
|
+
attrs=args.attrs,
|
|
168
|
+
branch=args.branch,
|
|
169
|
+
commit_message=args.commit_message,
|
|
170
|
+
dask_config_kwargs=dask_config["config_kwargs"],
|
|
171
|
+
dask_cluster_kwargs=dask_config["cluster_kwargs"],
|
|
172
|
+
icechunk_config=icechunk_config,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
elif args.action == "list":
|
|
176
|
+
|
|
177
|
+
if args.object_prefix is not None:
|
|
178
|
+
dest = f"{args.bucket}/{args.object_prefix}"
|
|
179
|
+
else:
|
|
180
|
+
dest = args.bucket
|
|
181
|
+
|
|
182
|
+
list_objects(
|
|
183
|
+
dest=dest,
|
|
184
|
+
store_credentials_json=args.store_credentials_json,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
else:
|
|
188
|
+
raise NotImplementedError(f"Action {args.action} not implemented.")
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def ods():
|
|
192
|
+
"""
|
|
193
|
+
Run the OceanDataStore CLI.
|
|
194
|
+
"""
|
|
195
|
+
initialise_logging()
|
|
196
|
+
|
|
197
|
+
parser = create_parser()
|
|
198
|
+
args = parser.parse_args()
|
|
199
|
+
|
|
200
|
+
process_action(args)
|
|
201
|
+
|
|
202
|
+
logging.info("✔ OceanDataStore terminated successfully ✔")
|
|
203
|
+
sys.exit(0)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# Copyright 2026 National Oceanography Centre
|
|
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
|
+
# http://www.apache.org/licenses/LICENSE-2.0.
|
|
7
|
+
#
|
|
8
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
9
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
10
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
11
|
+
# implied. See the License for the specific language governing
|
|
12
|
+
# permissions and limitations under the License.
|
|
13
|
+
# ===================================================================
|
|
14
|
+
"""
|
|
15
|
+
exceptions.py
|
|
16
|
+
|
|
17
|
+
Description:
|
|
18
|
+
This module defines exceptions classes to be
|
|
19
|
+
raised when performing sanity checks.
|
|
20
|
+
|
|
21
|
+
Authors:
|
|
22
|
+
- Joao Morado
|
|
23
|
+
- Tobias Ferreira
|
|
24
|
+
- Ollie Tooth
|
|
25
|
+
"""
|
|
26
|
+
import logging
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ObjectNotFound(Exception):
|
|
30
|
+
"""Exception raised for when an object is not found in the object store."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, object_name):
|
|
33
|
+
"""Initialise the exception."""
|
|
34
|
+
message = f"Object '{object_name}' not found in the object store."
|
|
35
|
+
logging.warning(message)
|
|
36
|
+
super().__init__(message)
|
|
37
|
+
|
|
38
|
+
class AppendDimensionError(Exception):
|
|
39
|
+
"""
|
|
40
|
+
Exception raised when attempting to modify values along append dimension.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, dim):
|
|
44
|
+
"""Initialise the exception."""
|
|
45
|
+
message = f"Cannot prepend to existing values along append dimension {dim}."
|
|
46
|
+
logging.warning(message)
|
|
47
|
+
super().__init__(message)
|
|
48
|
+
|
|
49
|
+
class DimensionNotFound(Exception):
|
|
50
|
+
"""Exception raised when a dimension is missing."""
|
|
51
|
+
|
|
52
|
+
def __init__(self, dim, object_name):
|
|
53
|
+
"""Initialise the exception."""
|
|
54
|
+
message = f"Dimension {dim} is not found in {object_name}."
|
|
55
|
+
logging.warning(message)
|
|
56
|
+
super().__init__(message)
|
|
57
|
+
|
|
58
|
+
class DimensionSizeError(Exception):
|
|
59
|
+
"""Exception raised when a dimension has incorrect size."""
|
|
60
|
+
|
|
61
|
+
def __init__(self, dim, size, expected_size):
|
|
62
|
+
"""Initialise the exception."""
|
|
63
|
+
message = f"Dimension {dim} has size {size}, expected {expected_size}."
|
|
64
|
+
logging.warning(message)
|
|
65
|
+
super().__init__(message)
|
|
66
|
+
|
|
67
|
+
class AppendDimensionSizeError(Exception):
|
|
68
|
+
"""Exception raised when an append dimension has incorrect size."""
|
|
69
|
+
|
|
70
|
+
def __init__(self, dim, size, expected_size):
|
|
71
|
+
"""Initialise the exception."""
|
|
72
|
+
message = f"Append dimension {dim} has {size} overlapping values, expected {expected_size}."
|
|
73
|
+
logging.warning(message)
|
|
74
|
+
super().__init__(message)
|
|
75
|
+
|
|
76
|
+
class ChunkSizeError(Exception):
|
|
77
|
+
"""Exception raised when data chunks do not match zarr store chunks."""
|
|
78
|
+
|
|
79
|
+
def __init__(self, chunks, store_chunks):
|
|
80
|
+
"""Initialise the exception."""
|
|
81
|
+
message = f"Specified chunks are {chunks}, expected {store_chunks}."
|
|
82
|
+
logging.warning(message)
|
|
83
|
+
super().__init__(message)
|