parseo 0.4.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.
- parseo/__init__.py +53 -0
- parseo/_epsg_lookup.py +145 -0
- parseo/_field_mappings.py +219 -0
- parseo/_json.py +14 -0
- parseo/_tile_systems.py +51 -0
- parseo/assembler.py +225 -0
- parseo/cli.py +383 -0
- parseo/parser.py +784 -0
- parseo/schema_registry.py +246 -0
- parseo/schemas/copernicus/clms/clc/clc_filename_v1_0_0.json +48 -0
- parseo/schemas/copernicus/clms/clc/clc_filename_v1_1_0.json +65 -0
- parseo/schemas/copernicus/clms/clcplus/ras/clcplus_filename_v0_0_0.json +90 -0
- parseo/schemas/copernicus/clms/clcplus/ras/clcplus_filename_v0_0_1.json +80 -0
- parseo/schemas/copernicus/clms/egms/egms_gnss_model_filename_v0_0_0.json +46 -0
- parseo/schemas/copernicus/clms/egms/egms_l2a_product_filename_v0_0_0.json +71 -0
- parseo/schemas/copernicus/clms/egms/egms_l3_velocity_grid_filename_v0_0_0.json +64 -0
- parseo/schemas/copernicus/clms/euhydro/euhydro_filename_v0_0_0.json +115 -0
- parseo/schemas/copernicus/clms/euhydro/euhydro_filename_v0_0_1.json +103 -0
- parseo/schemas/copernicus/clms/hr-vpp/st_filename_v0_0_0.json +82 -0
- parseo/schemas/copernicus/clms/hr-vpp/vi_filename_v0_0_0.json +89 -0
- parseo/schemas/copernicus/clms/hr-vpp/vpp_filename_v0_0_0.json +109 -0
- parseo/schemas/copernicus/clms/hr-wsi/cc_filename_v0_0_0.json +84 -0
- parseo/schemas/copernicus/clms/hr-wsi/fsc_filename_v0_0_0.json +88 -0
- parseo/schemas/copernicus/clms/hr-wsi/gfsc_filename_v0_0_0.json +83 -0
- parseo/schemas/copernicus/clms/hr-wsi/icd_filename_v0_0_0.json +96 -0
- parseo/schemas/copernicus/clms/hr-wsi/sp_filename_v0_0_0.json +177 -0
- parseo/schemas/copernicus/clms/hr-wsi/sws_filename_v0_0_0.json +83 -0
- parseo/schemas/copernicus/clms/hr-wsi/wcd_filename_v0_0_0.json +96 -0
- parseo/schemas/copernicus/clms/hr-wsi/wds_filename_v0_0_0.json +83 -0
- parseo/schemas/copernicus/clms/hr-wsi/wic_comb_filename_v0_0_0.json +82 -0
- parseo/schemas/copernicus/clms/hr-wsi/wic_filename_v0_0_0.json +90 -0
- parseo/schemas/copernicus/clms/hrl/fty_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/hrl/gra_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/hrl/ibu_filename_v0_0_0.json +57 -0
- parseo/schemas/copernicus/clms/hrl/imp_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/hrl/nvlcc_filename_v0_0_0.json +73 -0
- parseo/schemas/copernicus/clms/hrl/nvlcc_filename_v0_0_1.json +89 -0
- parseo/schemas/copernicus/clms/hrl/nvlcc_filename_v0_0_2.json +89 -0
- parseo/schemas/copernicus/clms/hrl/swf_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/hrl/swf_filename_v0_0_1.json +49 -0
- parseo/schemas/copernicus/clms/hrl/swf_filename_v0_0_2.json +93 -0
- parseo/schemas/copernicus/clms/hrl/swf_filename_v0_0_3.json +99 -0
- parseo/schemas/copernicus/clms/hrl/tcd_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/hrl/vlcc_filename_v0_0_0.json +105 -0
- parseo/schemas/copernicus/clms/hrl/waw_filename_v0_0_0.json +48 -0
- parseo/schemas/copernicus/clms/n2k/n2k_filename_v1_0_0.json +43 -0
- parseo/schemas/copernicus/clms/pa/pa_filename_v1_0_0.json +99 -0
- parseo/schemas/copernicus/clms/riparian-zones/rpz_filename_v0_0_0.json +50 -0
- parseo/schemas/copernicus/clms/urban-atlas/ua_dhm_filename_v0_0_0.json +53 -0
- parseo/schemas/copernicus/clms/urban-atlas/ua_filename_v0_0_0.json +105 -0
- parseo/schemas/copernicus/clms/urban-atlas/ua_stl_filename_v0_0_0.json +89 -0
- parseo/schemas/copernicus/sentinel/s1_filename_v1_0_0.json +78 -0
- parseo/schemas/copernicus/sentinel/s2_filename_v1_0_0.json +62 -0
- parseo/schemas/copernicus/sentinel/s3_filename_v1_0_0.json +22 -0
- parseo/schemas/copernicus/sentinel/s4_filename_v1_0_0.json +21 -0
- parseo/schemas/copernicus/sentinel/s5p_filename_v1_0_0.json +21 -0
- parseo/schemas/copernicus/sentinel/s6_filename_v1_0_0.json +23 -0
- parseo/schemas/eumetsat/metop_filename_v1_0_0.json +68 -0
- parseo/schemas/eumetsat/mtg_filename_v1_0_0.json +65 -0
- parseo/schemas/nasa/modis_filename_v1_0_0.json +54 -0
- parseo/schemas/usgs/landsat/landsat_filename_v1_0_0.json +50 -0
- parseo/stac_http.py +267 -0
- parseo/stac_scraper.py +115 -0
- parseo/template.py +78 -0
- parseo-0.4.4.dist-info/METADATA +402 -0
- parseo-0.4.4.dist-info/RECORD +70 -0
- parseo-0.4.4.dist-info/WHEEL +5 -0
- parseo-0.4.4.dist-info/entry_points.txt +2 -0
- parseo-0.4.4.dist-info/licenses/LICENSE.txt +287 -0
- parseo-0.4.4.dist-info/top_level.txt +1 -0
parseo/cli.py
ADDED
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# src/parseo/cli.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from typing import Any
|
|
8
|
+
from typing import Dict
|
|
9
|
+
from typing import List
|
|
10
|
+
from typing import Union
|
|
11
|
+
|
|
12
|
+
from parseo import __version__
|
|
13
|
+
from parseo.assembler import assemble
|
|
14
|
+
from parseo.assembler import assemble_auto
|
|
15
|
+
from parseo.parser import ParseError
|
|
16
|
+
from parseo.parser import describe_schema # parser helpers
|
|
17
|
+
from parseo.parser import parse
|
|
18
|
+
from parseo.parser import parse_auto
|
|
19
|
+
from parseo.schema_registry import discover_families
|
|
20
|
+
from parseo.stac_http import StacClientError
|
|
21
|
+
from parseo.stac_http import list_collections_http
|
|
22
|
+
from parseo.stac_http import sample_collection_filenames
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# ---------- small utilities ----------
|
|
26
|
+
|
|
27
|
+
def _build_arg_parser() -> argparse.ArgumentParser:
|
|
28
|
+
ap = argparse.ArgumentParser(prog="parseo", description="parsEO CLI")
|
|
29
|
+
ap.add_argument(
|
|
30
|
+
"--version",
|
|
31
|
+
action="version",
|
|
32
|
+
version=f"parseo version {__version__}",
|
|
33
|
+
help="Show the installed parseo version and exit",
|
|
34
|
+
)
|
|
35
|
+
sp = ap.add_subparsers(dest="cmd", required=True)
|
|
36
|
+
|
|
37
|
+
# parse
|
|
38
|
+
p_parse = sp.add_parser("parse", help="Parse a filename")
|
|
39
|
+
p_parse.add_argument("filename")
|
|
40
|
+
p_parse.add_argument(
|
|
41
|
+
"--output",
|
|
42
|
+
help="Write the JSON result to this file instead of stdout. Use '-' for stdout.",
|
|
43
|
+
)
|
|
44
|
+
p_parse.add_argument(
|
|
45
|
+
"--schema",
|
|
46
|
+
help="Path to a schema JSON file to parse with instead of auto-detection.",
|
|
47
|
+
)
|
|
48
|
+
p_parse.add_argument(
|
|
49
|
+
"--family",
|
|
50
|
+
help="Schema family to use for parsing (e.g. 'S2', 'LANDSAT'). When omitted, auto-detection is used.",
|
|
51
|
+
)
|
|
52
|
+
p_parse.add_argument(
|
|
53
|
+
"--ignore-case",
|
|
54
|
+
action="store_true",
|
|
55
|
+
help="Perform case-insensitive matching (default is case-sensitive).",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
# list-schemas
|
|
59
|
+
p_list = sp.add_parser("list-schemas", help="List available schema families")
|
|
60
|
+
p_list.add_argument(
|
|
61
|
+
"--family",
|
|
62
|
+
help="Only include schemas belonging to this mission family (e.g. 'S2').",
|
|
63
|
+
)
|
|
64
|
+
p_list.add_argument(
|
|
65
|
+
"--status",
|
|
66
|
+
help="Only include schemas whose lifecycle status matches this value (case-insensitive).",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# schema-info
|
|
70
|
+
p_info = sp.add_parser("schema-info", help="Show details for a mission family")
|
|
71
|
+
p_info.add_argument("family", help="Mission family name, e.g. 'S2'")
|
|
72
|
+
p_info.add_argument(
|
|
73
|
+
"--version",
|
|
74
|
+
help="Inspect a specific schema version (defaults to the current version).",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# stac-sample
|
|
78
|
+
p_stac = sp.add_parser(
|
|
79
|
+
"stac-sample",
|
|
80
|
+
help="Print sample asset filenames from a STAC collection",
|
|
81
|
+
)
|
|
82
|
+
p_stac.add_argument("collection", help="STAC collection ID")
|
|
83
|
+
p_stac.add_argument(
|
|
84
|
+
"--samples", type=int, default=5, help="Number of filenames to list"
|
|
85
|
+
)
|
|
86
|
+
p_stac.add_argument(
|
|
87
|
+
"--stac-url",
|
|
88
|
+
required=True,
|
|
89
|
+
help="Base URL of the STAC API",
|
|
90
|
+
)
|
|
91
|
+
p_stac.add_argument(
|
|
92
|
+
"--asset-role",
|
|
93
|
+
help="Only include assets whose roles contain this value",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# list-stac-collections
|
|
97
|
+
p_stac_list = sp.add_parser(
|
|
98
|
+
"list-stac-collections",
|
|
99
|
+
help="List collection IDs available in a STAC API",
|
|
100
|
+
)
|
|
101
|
+
p_stac_list.add_argument(
|
|
102
|
+
"--stac-url",
|
|
103
|
+
required=True,
|
|
104
|
+
help="Base URL of the STAC API",
|
|
105
|
+
)
|
|
106
|
+
p_stac_list.add_argument(
|
|
107
|
+
"--deep",
|
|
108
|
+
action="store_true",
|
|
109
|
+
help="Recursively follow child catalogs to list nested collections",
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# assemble
|
|
113
|
+
p_asm = sp.add_parser(
|
|
114
|
+
"assemble",
|
|
115
|
+
help=(
|
|
116
|
+
"Assemble a filename from fields. "
|
|
117
|
+
"Provide key=value pairs OR pipe a JSON object to stdin. "
|
|
118
|
+
"Schema is auto-selected using the schema's first compulsory field as defined by the template."
|
|
119
|
+
),
|
|
120
|
+
)
|
|
121
|
+
p_asm.add_argument(
|
|
122
|
+
"fields",
|
|
123
|
+
nargs="*",
|
|
124
|
+
help="key=value pairs (optional if you pipe a JSON object to stdin).",
|
|
125
|
+
)
|
|
126
|
+
p_asm.add_argument(
|
|
127
|
+
"--fields-json",
|
|
128
|
+
help="JSON string with fields, or '-' to read JSON from stdin.",
|
|
129
|
+
)
|
|
130
|
+
p_asm.add_argument(
|
|
131
|
+
"--family",
|
|
132
|
+
help="Schema family to use when assembling the filename.",
|
|
133
|
+
)
|
|
134
|
+
p_asm.add_argument(
|
|
135
|
+
"--version",
|
|
136
|
+
help="Schema version to use (requires --family).",
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
return ap
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _kv_pairs_to_dict(pairs: List[str]) -> Dict[str, str]:
|
|
143
|
+
out: Dict[str, str] = {}
|
|
144
|
+
for p in pairs:
|
|
145
|
+
if "=" not in p:
|
|
146
|
+
raise SystemExit(f"Invalid field '{p}'. Use key=value.")
|
|
147
|
+
k, v = p.split("=", 1)
|
|
148
|
+
k = k.strip()
|
|
149
|
+
v = v.strip()
|
|
150
|
+
if not k:
|
|
151
|
+
raise SystemExit(f"Invalid field '{p}': empty key.")
|
|
152
|
+
if k in out:
|
|
153
|
+
raise SystemExit(f"Duplicate field '{k}'.")
|
|
154
|
+
out[k] = v
|
|
155
|
+
return out
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _stdin_text() -> str:
|
|
159
|
+
if sys.stdin and not sys.stdin.closed and not sys.stdin.isatty():
|
|
160
|
+
return sys.stdin.read()
|
|
161
|
+
return ""
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _normalize_fields_payload(payload: Any, *, source: str) -> Dict[str, Any]:
|
|
165
|
+
"""Return a dictionary of fields from an arbitrary JSON payload."""
|
|
166
|
+
if isinstance(payload, dict):
|
|
167
|
+
if "fields" in payload:
|
|
168
|
+
fields = payload["fields"]
|
|
169
|
+
if not isinstance(fields, dict):
|
|
170
|
+
raise SystemExit(
|
|
171
|
+
f"{source} contains 'fields' but it is not a JSON object."
|
|
172
|
+
)
|
|
173
|
+
return fields
|
|
174
|
+
return payload
|
|
175
|
+
raise SystemExit(f"{source} must decode to a JSON object.")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _resolve_fields(args) -> Dict[str, Any]:
|
|
179
|
+
"""
|
|
180
|
+
Merge sources in priority:
|
|
181
|
+
1) --fields-json if provided (string or '-')
|
|
182
|
+
2) JSON from stdin if available and no positional fields
|
|
183
|
+
3) positional key=value pairs
|
|
184
|
+
"""
|
|
185
|
+
# 1) --fields-json
|
|
186
|
+
if args.fields_json:
|
|
187
|
+
if args.fields_json == "-":
|
|
188
|
+
raw = _stdin_text()
|
|
189
|
+
if not raw.strip():
|
|
190
|
+
raise SystemExit("--fields-json '-' set but stdin is empty.")
|
|
191
|
+
try:
|
|
192
|
+
payload = json.loads(raw)
|
|
193
|
+
except json.JSONDecodeError as e:
|
|
194
|
+
raise SystemExit(f"--fields-json '-' is not valid JSON: {e}")
|
|
195
|
+
return _normalize_fields_payload(payload, source="--fields-json '-'")
|
|
196
|
+
else:
|
|
197
|
+
try:
|
|
198
|
+
payload = json.loads(args.fields_json)
|
|
199
|
+
except json.JSONDecodeError as e:
|
|
200
|
+
raise SystemExit(f"--fields-json is not valid JSON: {e}")
|
|
201
|
+
return _normalize_fields_payload(payload, source="--fields-json")
|
|
202
|
+
|
|
203
|
+
# 2) stdin JSON (only if no positional fields were given)
|
|
204
|
+
if not args.fields:
|
|
205
|
+
raw = _stdin_text()
|
|
206
|
+
if raw.strip():
|
|
207
|
+
try:
|
|
208
|
+
payload = json.loads(raw)
|
|
209
|
+
except json.JSONDecodeError as e:
|
|
210
|
+
raise SystemExit(f"Stdin is not valid JSON: {e}")
|
|
211
|
+
return _normalize_fields_payload(payload, source="Stdin")
|
|
212
|
+
|
|
213
|
+
# 3) positional k=v pairs
|
|
214
|
+
if args.fields:
|
|
215
|
+
return _kv_pairs_to_dict(args.fields)
|
|
216
|
+
|
|
217
|
+
raise SystemExit(
|
|
218
|
+
"No fields provided. Supply key=value pairs, "
|
|
219
|
+
"or pass --fields-json, or pipe a JSON object via stdin."
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# ---------- main ----------
|
|
224
|
+
|
|
225
|
+
def main(argv: Union[List[str], None] = None) -> int:
|
|
226
|
+
argv = argv if argv is not None else sys.argv[1:]
|
|
227
|
+
ap = _build_arg_parser()
|
|
228
|
+
args = ap.parse_args(argv)
|
|
229
|
+
|
|
230
|
+
if args.cmd == "parse":
|
|
231
|
+
try:
|
|
232
|
+
if args.schema:
|
|
233
|
+
res = parse(args.filename, schema_path=args.schema, ignore_case=args.ignore_case)
|
|
234
|
+
elif args.family:
|
|
235
|
+
res = parse(args.filename, family=args.family, ignore_case=args.ignore_case)
|
|
236
|
+
else:
|
|
237
|
+
res = parse_auto(args.filename, ignore_case=args.ignore_case)
|
|
238
|
+
except ParseError as exc:
|
|
239
|
+
hint = ""
|
|
240
|
+
family = getattr(exc, "match_family", None)
|
|
241
|
+
if family:
|
|
242
|
+
hint = (
|
|
243
|
+
f"\nHint: use `parseo schema-info {family}` to inspect the schema."
|
|
244
|
+
)
|
|
245
|
+
raise SystemExit(f"{exc}{hint}")
|
|
246
|
+
out = {
|
|
247
|
+
"valid": bool(getattr(res, "valid", False)),
|
|
248
|
+
"fields": getattr(res, "fields", None),
|
|
249
|
+
}
|
|
250
|
+
version = getattr(res, "version", None)
|
|
251
|
+
if version:
|
|
252
|
+
out["version"] = version
|
|
253
|
+
status = getattr(res, "status", None)
|
|
254
|
+
if status:
|
|
255
|
+
out["status"] = status
|
|
256
|
+
mfam = getattr(res, "match_family", None)
|
|
257
|
+
if mfam:
|
|
258
|
+
out["match_family"] = mfam
|
|
259
|
+
payload = json.dumps(out, indent=2, ensure_ascii=False)
|
|
260
|
+
if args.output and args.output != "-":
|
|
261
|
+
try:
|
|
262
|
+
with open(args.output, "w", encoding="utf-8") as fh:
|
|
263
|
+
fh.write(f"{payload}\n")
|
|
264
|
+
except OSError as exc:
|
|
265
|
+
raise SystemExit(f"Failed to write to '{args.output}': {exc}") from exc
|
|
266
|
+
else:
|
|
267
|
+
print(payload)
|
|
268
|
+
return 0
|
|
269
|
+
|
|
270
|
+
if args.cmd == "list-schemas":
|
|
271
|
+
rows: list[tuple[str, str, str, str]] = []
|
|
272
|
+
catalog = discover_families()
|
|
273
|
+
status_filter = args.status.lower() if args.status else None
|
|
274
|
+
prefix_filter: str | None = None
|
|
275
|
+
exact_family: str | None = None
|
|
276
|
+
if args.family:
|
|
277
|
+
if ":" in args.family:
|
|
278
|
+
prefix_filter = args.family.lower()
|
|
279
|
+
else:
|
|
280
|
+
fam_upper = args.family.upper()
|
|
281
|
+
if fam_upper in catalog:
|
|
282
|
+
exact_family = fam_upper
|
|
283
|
+
else:
|
|
284
|
+
prefix_filter = args.family.lower()
|
|
285
|
+
for fam in sorted(catalog):
|
|
286
|
+
meta = catalog[fam]
|
|
287
|
+
schema_id = meta.get("schema_id")
|
|
288
|
+
if not isinstance(schema_id, str):
|
|
289
|
+
continue
|
|
290
|
+
if prefix_filter and not schema_id.lower().startswith(prefix_filter):
|
|
291
|
+
continue
|
|
292
|
+
if exact_family and fam != exact_family:
|
|
293
|
+
continue
|
|
294
|
+
versions = meta.get("versions", {})
|
|
295
|
+
if not isinstance(versions, dict):
|
|
296
|
+
continue
|
|
297
|
+
for ver in sorted(versions):
|
|
298
|
+
data = versions[ver]
|
|
299
|
+
status = ""
|
|
300
|
+
path_str = ""
|
|
301
|
+
if isinstance(data, dict):
|
|
302
|
+
status = str(data.get("status") or "")
|
|
303
|
+
path = data.get("path")
|
|
304
|
+
path_str = str(path) if path is not None else ""
|
|
305
|
+
elif isinstance(data, tuple) and len(data) == 2:
|
|
306
|
+
path, status_val = data
|
|
307
|
+
status = status_val or ""
|
|
308
|
+
path_str = str(path)
|
|
309
|
+
if status_filter and status.lower() != status_filter:
|
|
310
|
+
continue
|
|
311
|
+
rows.append((schema_id, ver, status, path_str))
|
|
312
|
+
if rows:
|
|
313
|
+
rows.sort(key=lambda r: (r[0], r[1]))
|
|
314
|
+
headers = ("SCHEMA_ID", "VERSION", "STATUS", "FILE")
|
|
315
|
+
widths = [len(h) for h in headers]
|
|
316
|
+
for row in rows:
|
|
317
|
+
for i in range(3):
|
|
318
|
+
widths[i] = max(widths[i], len(row[i]))
|
|
319
|
+
line_fmt = f"{{:{widths[0]}}} {{:{widths[1]}}} {{:{widths[2]}}} {{}}"
|
|
320
|
+
print(line_fmt.format(*headers))
|
|
321
|
+
for row in rows:
|
|
322
|
+
print(line_fmt.format(*row))
|
|
323
|
+
else:
|
|
324
|
+
if args.family and not status_filter:
|
|
325
|
+
target = "family" if exact_family else "prefix"
|
|
326
|
+
print(f"No schemas found for {target} '{args.family}'.")
|
|
327
|
+
elif args.family and status_filter:
|
|
328
|
+
target = "family" if exact_family else "prefix"
|
|
329
|
+
print(
|
|
330
|
+
f"No schemas found for {target} '{args.family}' with status '{args.status}'."
|
|
331
|
+
)
|
|
332
|
+
elif status_filter:
|
|
333
|
+
print(f"No schemas found with status '{args.status}'.")
|
|
334
|
+
else:
|
|
335
|
+
print("No schemas found.")
|
|
336
|
+
return 0
|
|
337
|
+
|
|
338
|
+
if args.cmd == "schema-info":
|
|
339
|
+
try:
|
|
340
|
+
info = describe_schema(args.family, version=args.version)
|
|
341
|
+
except KeyError as e:
|
|
342
|
+
raise SystemExit(str(e))
|
|
343
|
+
print(json.dumps(info, indent=2, ensure_ascii=False))
|
|
344
|
+
return 0
|
|
345
|
+
|
|
346
|
+
if args.cmd == "list-stac-collections":
|
|
347
|
+
for cid in list_collections_http(base_url=args.stac_url, deep=args.deep):
|
|
348
|
+
print(cid)
|
|
349
|
+
return 0
|
|
350
|
+
|
|
351
|
+
if args.cmd == "stac-sample":
|
|
352
|
+
samples = sample_collection_filenames(
|
|
353
|
+
args.collection,
|
|
354
|
+
args.samples,
|
|
355
|
+
base_url=args.stac_url,
|
|
356
|
+
asset_role=args.asset_role,
|
|
357
|
+
)
|
|
358
|
+
for cid in sorted(samples):
|
|
359
|
+
print(f"{cid}:")
|
|
360
|
+
for fn in samples[cid]:
|
|
361
|
+
print(f" {fn}")
|
|
362
|
+
return 0
|
|
363
|
+
|
|
364
|
+
if args.cmd == "assemble":
|
|
365
|
+
fields = _resolve_fields(args)
|
|
366
|
+
if args.version and not args.family:
|
|
367
|
+
raise SystemExit("--version requires --family to be set.")
|
|
368
|
+
if args.family:
|
|
369
|
+
out = assemble(fields, family=args.family, version=args.version)
|
|
370
|
+
else:
|
|
371
|
+
out = assemble_auto(fields)
|
|
372
|
+
print(out)
|
|
373
|
+
return 0
|
|
374
|
+
|
|
375
|
+
ap.print_help()
|
|
376
|
+
return 1
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
if __name__ == "__main__":
|
|
380
|
+
try:
|
|
381
|
+
raise SystemExit(main())
|
|
382
|
+
except StacClientError as e:
|
|
383
|
+
raise SystemExit(str(e)) from e
|