metadata-crawler 2510.1.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.
Potentially problematic release.
This version of metadata-crawler might be problematic. Click here for more details.
- metadata_crawler/__init__.py +263 -0
- metadata_crawler/__main__.py +8 -0
- metadata_crawler/_version.py +1 -0
- metadata_crawler/api/__init__.py +1 -0
- metadata_crawler/api/cli.py +57 -0
- metadata_crawler/api/config.py +831 -0
- metadata_crawler/api/drs_config.toml +440 -0
- metadata_crawler/api/index.py +151 -0
- metadata_crawler/api/metadata_stores.py +755 -0
- metadata_crawler/api/mixin/__init__.py +7 -0
- metadata_crawler/api/mixin/lookup_mixin.py +112 -0
- metadata_crawler/api/mixin/lookup_tables.py +10010 -0
- metadata_crawler/api/mixin/path_mixin.py +46 -0
- metadata_crawler/api/mixin/template_mixin.py +145 -0
- metadata_crawler/api/storage_backend.py +277 -0
- metadata_crawler/backends/__init__.py +1 -0
- metadata_crawler/backends/intake.py +211 -0
- metadata_crawler/backends/posix.py +121 -0
- metadata_crawler/backends/s3.py +140 -0
- metadata_crawler/backends/swift.py +305 -0
- metadata_crawler/cli.py +547 -0
- metadata_crawler/data_collector.py +278 -0
- metadata_crawler/ingester/__init__.py +1 -0
- metadata_crawler/ingester/mongo.py +206 -0
- metadata_crawler/ingester/solr.py +282 -0
- metadata_crawler/logger.py +153 -0
- metadata_crawler/py.typed +0 -0
- metadata_crawler/run.py +419 -0
- metadata_crawler/utils/__init__.py +482 -0
- metadata_crawler/utils/cftime_utils.py +207 -0
- metadata_crawler-2510.1.0.dist-info/METADATA +401 -0
- metadata_crawler-2510.1.0.dist-info/RECORD +35 -0
- metadata_crawler-2510.1.0.dist-info/WHEEL +4 -0
- metadata_crawler-2510.1.0.dist-info/entry_points.txt +14 -0
- metadata_crawler-2510.1.0.dist-info/licenses/LICENSE +28 -0
metadata_crawler/cli.py
ADDED
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
"""Command line interface for the data crawler."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import inspect
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from functools import partial
|
|
11
|
+
from json import dumps
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import (
|
|
14
|
+
Annotated,
|
|
15
|
+
Any,
|
|
16
|
+
Callable,
|
|
17
|
+
Dict,
|
|
18
|
+
List,
|
|
19
|
+
Optional,
|
|
20
|
+
Tuple,
|
|
21
|
+
Union,
|
|
22
|
+
cast,
|
|
23
|
+
get_args,
|
|
24
|
+
get_origin,
|
|
25
|
+
get_type_hints,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from rich_argparse import ArgumentDefaultsRichHelpFormatter
|
|
29
|
+
|
|
30
|
+
from metadata_crawler import add, delete, get_config, index
|
|
31
|
+
|
|
32
|
+
from ._version import __version__
|
|
33
|
+
from .api.metadata_stores import CatalogueBackends, IndexName
|
|
34
|
+
from .backends.intake import IntakePath
|
|
35
|
+
from .logger import (
|
|
36
|
+
THIS_NAME,
|
|
37
|
+
apply_verbosity,
|
|
38
|
+
logger,
|
|
39
|
+
)
|
|
40
|
+
from .utils import exception_handler, load_plugins
|
|
41
|
+
|
|
42
|
+
StorageScalar = Union[str, int, float, bool]
|
|
43
|
+
StorageOptions = Dict[str, StorageScalar]
|
|
44
|
+
KwargValue = Union[
|
|
45
|
+
str, int, float, Path, StorageOptions, List[str], List[int], None
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def walk_catalogue(
|
|
50
|
+
path: str,
|
|
51
|
+
storage_options: Optional[Dict[str, Any]] = None,
|
|
52
|
+
**kwargs: Any,
|
|
53
|
+
) -> int:
|
|
54
|
+
"""Recursively traverse an intake catalogue.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
^^^^^^^^^^
|
|
58
|
+
|
|
59
|
+
path:
|
|
60
|
+
The path to the intake catalogue
|
|
61
|
+
storage_options:
|
|
62
|
+
Optional configuration passed to open catalogues residing on non posix
|
|
63
|
+
storage backends, such as S3/MinIO
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
async def _walk(path: str, **storage_options: Any) -> int:
|
|
67
|
+
num_items = 0
|
|
68
|
+
ip = IntakePath(**storage_options)
|
|
69
|
+
async for md in ip.walk(path):
|
|
70
|
+
print(md)
|
|
71
|
+
num_items += 1
|
|
72
|
+
return num_items
|
|
73
|
+
|
|
74
|
+
storage_options = storage_options or {}
|
|
75
|
+
return asyncio.run(_walk(path, **storage_options))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _flatten(inp: Union[List[str], List[List[str]]]) -> List[str]:
|
|
79
|
+
|
|
80
|
+
out = []
|
|
81
|
+
for item in inp:
|
|
82
|
+
out += item if isinstance(item, list) else [item]
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _process_storage_option(option: str) -> Union[str, bool, int, float]:
|
|
87
|
+
|
|
88
|
+
if option.lower() in ("false", "true"):
|
|
89
|
+
return option.lower() == "true"
|
|
90
|
+
try:
|
|
91
|
+
return int(option)
|
|
92
|
+
except ValueError:
|
|
93
|
+
pass
|
|
94
|
+
try:
|
|
95
|
+
return float(option)
|
|
96
|
+
except ValueError:
|
|
97
|
+
pass
|
|
98
|
+
return option
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def display_config(
|
|
102
|
+
config: Optional[Union[Path, str]], json: bool = False, **kwargs: Any
|
|
103
|
+
) -> None:
|
|
104
|
+
"""Display the config file."""
|
|
105
|
+
cfg = get_config(config)
|
|
106
|
+
if json is False:
|
|
107
|
+
print(cfg.dumps())
|
|
108
|
+
else:
|
|
109
|
+
print(dumps(cfg.merged_doc, indent=3))
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class ArgParse:
|
|
113
|
+
"""Command line interface definition.
|
|
114
|
+
|
|
115
|
+
Properties
|
|
116
|
+
----------
|
|
117
|
+
kwargs: dict[str, Union[str, float, Path]]
|
|
118
|
+
property holding all parsed keyword arguments.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
kwargs: Optional[Dict[str, KwargValue]] = None
|
|
122
|
+
verbose: int = 0
|
|
123
|
+
epilog: str = (
|
|
124
|
+
"See also "
|
|
125
|
+
"https://metadata-crawler.readthedocs.io"
|
|
126
|
+
" for a detailed documentation."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def __init__(self) -> None:
|
|
130
|
+
"""Instantiate the CLI class."""
|
|
131
|
+
self.verbose: int = 0
|
|
132
|
+
self.parser = argparse.ArgumentParser(
|
|
133
|
+
prog=THIS_NAME,
|
|
134
|
+
description="Add/Remove metadata to/from a metadata index.",
|
|
135
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
136
|
+
epilog=self.epilog,
|
|
137
|
+
)
|
|
138
|
+
self.parser.add_argument(
|
|
139
|
+
"-V",
|
|
140
|
+
"--version",
|
|
141
|
+
action="version",
|
|
142
|
+
version=f"%(prog)s {__version__}",
|
|
143
|
+
help="Print the version end exit",
|
|
144
|
+
)
|
|
145
|
+
self._add_general_config_to_parser(self.parser)
|
|
146
|
+
self.subparsers = self.parser.add_subparsers(
|
|
147
|
+
description="Collect or ingest metadata",
|
|
148
|
+
required=True,
|
|
149
|
+
)
|
|
150
|
+
self._add_config_parser()
|
|
151
|
+
self._add_walk_catalogue()
|
|
152
|
+
self._add_crawler_subcommand()
|
|
153
|
+
self._index_submcommands()
|
|
154
|
+
|
|
155
|
+
def _add_config_parser(self) -> None:
|
|
156
|
+
parser = self.subparsers.add_parser(
|
|
157
|
+
"config",
|
|
158
|
+
description="Display config",
|
|
159
|
+
help="Display config",
|
|
160
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
161
|
+
epilog=self.epilog,
|
|
162
|
+
)
|
|
163
|
+
parser.add_argument(
|
|
164
|
+
"-c",
|
|
165
|
+
"--config",
|
|
166
|
+
help="Path to the config_file",
|
|
167
|
+
type=Path,
|
|
168
|
+
)
|
|
169
|
+
parser.add_argument(
|
|
170
|
+
"--json", help="Print in json format.", action="store_true"
|
|
171
|
+
)
|
|
172
|
+
parser.set_defaults(apply_func=display_config)
|
|
173
|
+
parser.add_argument(
|
|
174
|
+
"-v",
|
|
175
|
+
"--verbose",
|
|
176
|
+
action="count",
|
|
177
|
+
default=self.verbose,
|
|
178
|
+
help="Increase the verbosity level.",
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
def _add_crawler_subcommand(self) -> None:
|
|
182
|
+
"""Add sub command for crawling metadata."""
|
|
183
|
+
parser = self.subparsers.add_parser(
|
|
184
|
+
"add",
|
|
185
|
+
description="Harvest (add) metadata",
|
|
186
|
+
help="Harvest (crawl) metadata",
|
|
187
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
188
|
+
epilog=self.epilog,
|
|
189
|
+
)
|
|
190
|
+
parser.add_argument(
|
|
191
|
+
"store",
|
|
192
|
+
type=str,
|
|
193
|
+
help="Path to the intake catalogue",
|
|
194
|
+
)
|
|
195
|
+
parser.add_argument(
|
|
196
|
+
"--catalogue-backend",
|
|
197
|
+
"-cb",
|
|
198
|
+
type=str,
|
|
199
|
+
help="Source type of the catalogue backend.",
|
|
200
|
+
choices=CatalogueBackends.__members__.keys(),
|
|
201
|
+
default=list(CatalogueBackends.__members__.keys())[0],
|
|
202
|
+
)
|
|
203
|
+
parser.add_argument(
|
|
204
|
+
"--data-store-prefix",
|
|
205
|
+
"--prefix",
|
|
206
|
+
type=str,
|
|
207
|
+
help=(
|
|
208
|
+
"Set the path prefix for the metadata store, this can either be"
|
|
209
|
+
" an absolute path or if absolute path is given a path prefix"
|
|
210
|
+
" relative to the yaml catalogue file."
|
|
211
|
+
),
|
|
212
|
+
default="metadata",
|
|
213
|
+
)
|
|
214
|
+
parser.add_argument(
|
|
215
|
+
"-c",
|
|
216
|
+
"--config-file",
|
|
217
|
+
"--config-dir",
|
|
218
|
+
type=Path,
|
|
219
|
+
help="Directory holding the metadata and server settings.",
|
|
220
|
+
default=os.environ.get("EVALUATION_SYSTEM_CONFIG_DIR"),
|
|
221
|
+
)
|
|
222
|
+
parser.add_argument(
|
|
223
|
+
"-b",
|
|
224
|
+
"--batch-size",
|
|
225
|
+
type=int,
|
|
226
|
+
default=25_000,
|
|
227
|
+
help="Set the batch size for ingestion.",
|
|
228
|
+
)
|
|
229
|
+
parser.add_argument(
|
|
230
|
+
"--scan-concurrency",
|
|
231
|
+
"--concurrency",
|
|
232
|
+
type=int,
|
|
233
|
+
default=1024,
|
|
234
|
+
help="Level of aync concurrency for data discovery.",
|
|
235
|
+
)
|
|
236
|
+
parser.add_argument(
|
|
237
|
+
"-d",
|
|
238
|
+
"--data-object",
|
|
239
|
+
"--data-obj",
|
|
240
|
+
type=str,
|
|
241
|
+
help="Objects (directories or catalogue files) that are processed.",
|
|
242
|
+
default=None,
|
|
243
|
+
action="append",
|
|
244
|
+
),
|
|
245
|
+
parser.add_argument(
|
|
246
|
+
"-ds",
|
|
247
|
+
"--data-set",
|
|
248
|
+
type=str,
|
|
249
|
+
help=(
|
|
250
|
+
"The name of the dataset(s) that are processed. "
|
|
251
|
+
"names can contain wildcards such as ``xces-*``."
|
|
252
|
+
),
|
|
253
|
+
default=None,
|
|
254
|
+
action="append",
|
|
255
|
+
)
|
|
256
|
+
parser.add_argument(
|
|
257
|
+
"-p",
|
|
258
|
+
"--password",
|
|
259
|
+
help=(
|
|
260
|
+
"Ask for a password and set it to the DRS_STORAGE_PASSWD "
|
|
261
|
+
"env variable."
|
|
262
|
+
),
|
|
263
|
+
action="store_true",
|
|
264
|
+
)
|
|
265
|
+
parser.add_argument(
|
|
266
|
+
"--n-procs",
|
|
267
|
+
"--procs",
|
|
268
|
+
help="Set the number of parallel processes for collecting.",
|
|
269
|
+
type=int,
|
|
270
|
+
default=None,
|
|
271
|
+
)
|
|
272
|
+
parser.add_argument(
|
|
273
|
+
"--latest-version",
|
|
274
|
+
type=str,
|
|
275
|
+
default=IndexName().latest,
|
|
276
|
+
help="Name of the core holding 'latest' metadata.",
|
|
277
|
+
)
|
|
278
|
+
parser.add_argument(
|
|
279
|
+
"--all-versions",
|
|
280
|
+
type=str,
|
|
281
|
+
default=IndexName().all,
|
|
282
|
+
help="Name of the core holding 'all' metadata versions.",
|
|
283
|
+
)
|
|
284
|
+
parser.add_argument(
|
|
285
|
+
"--comp-level",
|
|
286
|
+
"-z",
|
|
287
|
+
help="Set the compression level for compressing files.",
|
|
288
|
+
default=4,
|
|
289
|
+
type=int,
|
|
290
|
+
)
|
|
291
|
+
parser.add_argument(
|
|
292
|
+
"--storage_option",
|
|
293
|
+
"-s",
|
|
294
|
+
help=(
|
|
295
|
+
"Set additional storage options for adding metadata to the"
|
|
296
|
+
"metadata store"
|
|
297
|
+
),
|
|
298
|
+
action="append",
|
|
299
|
+
nargs=2,
|
|
300
|
+
)
|
|
301
|
+
parser.add_argument(
|
|
302
|
+
"--fail-under",
|
|
303
|
+
help=" Fail if less than X of the discovered files could be indexed.",
|
|
304
|
+
type=int,
|
|
305
|
+
default=-1,
|
|
306
|
+
)
|
|
307
|
+
parser.add_argument(
|
|
308
|
+
"--shadow",
|
|
309
|
+
help=(
|
|
310
|
+
"'Shadow' these storage options. This is useful to hide secrets "
|
|
311
|
+
"in public data catalogues."
|
|
312
|
+
),
|
|
313
|
+
action="append",
|
|
314
|
+
default=None,
|
|
315
|
+
nargs="+",
|
|
316
|
+
)
|
|
317
|
+
self._add_general_config_to_parser(parser)
|
|
318
|
+
parser.set_defaults(apply_func=add)
|
|
319
|
+
|
|
320
|
+
def _add_general_config_to_parser(
|
|
321
|
+
self, parser: argparse.ArgumentParser
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Add the most common arguments to a given parser."""
|
|
324
|
+
parser.add_argument(
|
|
325
|
+
"-v",
|
|
326
|
+
"--verbose",
|
|
327
|
+
action="count",
|
|
328
|
+
default=self.verbose,
|
|
329
|
+
help="Increase the verbosity level.",
|
|
330
|
+
)
|
|
331
|
+
parser.add_argument(
|
|
332
|
+
"--log-suffix",
|
|
333
|
+
type=str,
|
|
334
|
+
help="Add a suffix to the log file output.",
|
|
335
|
+
default=None,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def _add_walk_catalogue(self) -> None:
|
|
339
|
+
"""Add a subcommand for walking an intake catalogue."""
|
|
340
|
+
parser = self.subparsers.add_parser(
|
|
341
|
+
"walk-intake",
|
|
342
|
+
description="Walk an intake catalogue",
|
|
343
|
+
help="Walk an intake catalogue",
|
|
344
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
345
|
+
epilog=self.epilog,
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
parser.add_argument(
|
|
349
|
+
"path",
|
|
350
|
+
type=str,
|
|
351
|
+
help="Path/Url to the intake catalogue",
|
|
352
|
+
)
|
|
353
|
+
parser.add_argument(
|
|
354
|
+
"--storage_option",
|
|
355
|
+
"-s",
|
|
356
|
+
help=(
|
|
357
|
+
"Set additional storage options for adding metadata to the"
|
|
358
|
+
"metadata store"
|
|
359
|
+
),
|
|
360
|
+
action="append",
|
|
361
|
+
nargs=2,
|
|
362
|
+
)
|
|
363
|
+
parser.add_argument(
|
|
364
|
+
"-v",
|
|
365
|
+
"--verbose",
|
|
366
|
+
action="count",
|
|
367
|
+
default=self.verbose,
|
|
368
|
+
help="Increase the verbosity level.",
|
|
369
|
+
)
|
|
370
|
+
parser.set_defaults(apply_func=walk_catalogue)
|
|
371
|
+
|
|
372
|
+
def _index_submcommands(self) -> None:
|
|
373
|
+
"""Add sub command for adding metadata to the solr server."""
|
|
374
|
+
entry_point = "metadata_crawler.ingester"
|
|
375
|
+
for plugin, cls in load_plugins(entry_point).items():
|
|
376
|
+
cli_methods: Dict[str, Callable[..., Any]] = {}
|
|
377
|
+
for name in ("index", "delete"):
|
|
378
|
+
method = getattr(cls, name, None)
|
|
379
|
+
if hasattr(method, "_cli_help"):
|
|
380
|
+
cli_methods[name] = cast(Callable[..., Any], method)
|
|
381
|
+
if cli_methods:
|
|
382
|
+
subparser = self.subparsers.add_parser(
|
|
383
|
+
plugin,
|
|
384
|
+
help=cls.__doc__,
|
|
385
|
+
description=cls.__doc__,
|
|
386
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
387
|
+
epilog=self.epilog,
|
|
388
|
+
)
|
|
389
|
+
cmd_parser = subparser.add_subparsers(required=True)
|
|
390
|
+
for name, method in cli_methods.items():
|
|
391
|
+
parser = cmd_parser.add_parser(
|
|
392
|
+
name,
|
|
393
|
+
help=getattr(method, "_cli_help", ""),
|
|
394
|
+
description=getattr(method, "_cli_help", ""),
|
|
395
|
+
formatter_class=ArgumentDefaultsRichHelpFormatter,
|
|
396
|
+
epilog=self.epilog,
|
|
397
|
+
)
|
|
398
|
+
parser.add_argument(
|
|
399
|
+
"-b",
|
|
400
|
+
"--batch-size",
|
|
401
|
+
type=int,
|
|
402
|
+
default=5_000,
|
|
403
|
+
help="Set the batch size for indexing.",
|
|
404
|
+
)
|
|
405
|
+
parser.add_argument(
|
|
406
|
+
"--storage_option",
|
|
407
|
+
"-s",
|
|
408
|
+
help=(
|
|
409
|
+
"Set additional storage options for adding metadata to "
|
|
410
|
+
" the metadata store"
|
|
411
|
+
),
|
|
412
|
+
action="append",
|
|
413
|
+
nargs=2,
|
|
414
|
+
)
|
|
415
|
+
params = inspect.signature(method).parameters
|
|
416
|
+
annotations = get_type_hints(method, include_extras=True)
|
|
417
|
+
for param_name, param in params.items():
|
|
418
|
+
if param_name == "self":
|
|
419
|
+
continue
|
|
420
|
+
cli_meta = None
|
|
421
|
+
base_type = None
|
|
422
|
+
ann = annotations.get(param_name, None)
|
|
423
|
+
|
|
424
|
+
# 1) Annotated[...] style
|
|
425
|
+
if get_origin(ann) is Annotated:
|
|
426
|
+
base_type, *extras = get_args(ann)
|
|
427
|
+
# find the dict emitted by cli_parameter()
|
|
428
|
+
cli_meta = next(
|
|
429
|
+
(
|
|
430
|
+
e
|
|
431
|
+
for e in extras
|
|
432
|
+
if isinstance(e, dict) and "args" in e
|
|
433
|
+
),
|
|
434
|
+
None,
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
# 2) default-as-parameter style
|
|
438
|
+
if (
|
|
439
|
+
cli_meta is None
|
|
440
|
+
and isinstance(param.default, dict)
|
|
441
|
+
and "args" in param.default
|
|
442
|
+
):
|
|
443
|
+
cli_meta = param.default
|
|
444
|
+
# annotation is the base type
|
|
445
|
+
base_type = ann if ann is not inspect._empty else None
|
|
446
|
+
|
|
447
|
+
# if we found a cli_meta, wire it up
|
|
448
|
+
if cli_meta:
|
|
449
|
+
arg_names = cli_meta["args"]
|
|
450
|
+
add_kwargs = {
|
|
451
|
+
k: v for k, v in cli_meta.items() if k != "args"
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
# preserve any explicit default
|
|
455
|
+
if (
|
|
456
|
+
param.default is not inspect._empty
|
|
457
|
+
and cli_meta is not param.default
|
|
458
|
+
):
|
|
459
|
+
add_kwargs["default"] = param.default
|
|
460
|
+
|
|
461
|
+
# enforce the base type if supplied
|
|
462
|
+
if base_type and "type" not in add_kwargs:
|
|
463
|
+
add_kwargs["type"] = base_type
|
|
464
|
+
parser.add_argument(
|
|
465
|
+
*arg_names, dest=param_name, **add_kwargs
|
|
466
|
+
)
|
|
467
|
+
if name == "index":
|
|
468
|
+
parser.add_argument(
|
|
469
|
+
"catalogue_files",
|
|
470
|
+
help="File path to the metadata store.",
|
|
471
|
+
type=str,
|
|
472
|
+
nargs="*",
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
parser.set_defaults(
|
|
476
|
+
apply_func=partial(index, index_system=plugin)
|
|
477
|
+
)
|
|
478
|
+
else:
|
|
479
|
+
parser.set_defaults(
|
|
480
|
+
apply_func=partial(delete, index_system=plugin)
|
|
481
|
+
)
|
|
482
|
+
self._add_general_config_to_parser(parser)
|
|
483
|
+
|
|
484
|
+
def parse_args(self, argv: list[str]) -> argparse.Namespace:
|
|
485
|
+
"""Parse the arguments for the command line interface.
|
|
486
|
+
|
|
487
|
+
Parameters
|
|
488
|
+
----------
|
|
489
|
+
argv: list[str]
|
|
490
|
+
List of command line arguments that is parsed.
|
|
491
|
+
|
|
492
|
+
Returns
|
|
493
|
+
-------
|
|
494
|
+
argparse.Namespace
|
|
495
|
+
"""
|
|
496
|
+
args = self.parser.parse_args(argv)
|
|
497
|
+
self.kwargs = {
|
|
498
|
+
k: v
|
|
499
|
+
for (k, v) in args._get_kwargs()
|
|
500
|
+
if k
|
|
501
|
+
not in (
|
|
502
|
+
"apply_func",
|
|
503
|
+
"verbose",
|
|
504
|
+
"version",
|
|
505
|
+
"storage_option",
|
|
506
|
+
"shadow",
|
|
507
|
+
)
|
|
508
|
+
}
|
|
509
|
+
storage_option_pairs: List[Tuple[str, str]] = (
|
|
510
|
+
getattr(args, "storage_option", None) or []
|
|
511
|
+
)
|
|
512
|
+
so: StorageOptions = {}
|
|
513
|
+
for option, value in storage_option_pairs:
|
|
514
|
+
so[option] = _process_storage_option(value)
|
|
515
|
+
if getattr(args, "shadow", None) or []:
|
|
516
|
+
self.kwargs["shadow"] = _flatten(args.shadow)
|
|
517
|
+
self.kwargs["storage_options"] = so
|
|
518
|
+
self.verbose = args.verbose
|
|
519
|
+
self.kwargs["verbosity"] = self.verbose
|
|
520
|
+
return args
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
def _run(
|
|
524
|
+
parser: argparse.Namespace,
|
|
525
|
+
**kwargs: KwargValue,
|
|
526
|
+
) -> None:
|
|
527
|
+
"""Apply the parsed method."""
|
|
528
|
+
old_level = apply_verbosity(
|
|
529
|
+
getattr(parser, "verbose", 0), suffix=getattr(parser, "log_suffix", None)
|
|
530
|
+
)
|
|
531
|
+
try:
|
|
532
|
+
parser.apply_func(**kwargs)
|
|
533
|
+
except Exception as error:
|
|
534
|
+
exception_handler(error)
|
|
535
|
+
finally:
|
|
536
|
+
logger.set_level(old_level)
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
def cli(sys_args: list[str] | None = None) -> None:
|
|
540
|
+
"""Methods that creates the command line argument parser."""
|
|
541
|
+
try:
|
|
542
|
+
parser = ArgParse()
|
|
543
|
+
args = parser.parse_args(sys_args or sys.argv[1:])
|
|
544
|
+
kwargs = parser.kwargs or {}
|
|
545
|
+
_run(args, **kwargs)
|
|
546
|
+
except KeyboardInterrupt:
|
|
547
|
+
raise SystemExit("Exiting program")
|