freva-client 2502.0.0__py3-none-any.whl → 2506.0.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 freva-client might be problematic. Click here for more details.
- freva_client/__init__.py +1 -1
- freva_client/auth.py +234 -102
- freva_client/cli/auth_cli.py +13 -19
- freva_client/cli/cli_parser.py +2 -0
- freva_client/cli/databrowser_cli.py +304 -82
- freva_client/query.py +201 -47
- freva_client/utils/auth_utils.py +240 -0
- freva_client/utils/databrowser_utils.py +8 -3
- {freva_client-2502.0.0.dist-info → freva_client-2506.0.0.dist-info}/METADATA +1 -2
- freva_client-2506.0.0.dist-info/RECORD +20 -0
- {freva_client-2502.0.0.dist-info → freva_client-2506.0.0.dist-info}/WHEEL +1 -1
- freva_client-2502.0.0.dist-info/RECORD +0 -19
- {freva_client-2502.0.0.data → freva_client-2506.0.0.data}/data/share/freva/freva.toml +0 -0
- {freva_client-2502.0.0.dist-info → freva_client-2506.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -7,7 +7,7 @@ import json
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from tempfile import NamedTemporaryFile
|
|
10
|
-
from typing import Dict, List,
|
|
10
|
+
from typing import Dict, List, Optional, Tuple, Union, cast
|
|
11
11
|
|
|
12
12
|
import typer
|
|
13
13
|
import xarray as xr
|
|
@@ -19,16 +19,6 @@ from freva_client.utils import exception_handler, logger
|
|
|
19
19
|
from .cli_utils import parse_cli_args, version_callback
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def _auth(url: str, token: Optional[str]) -> None:
|
|
23
|
-
if token:
|
|
24
|
-
auth = Auth()
|
|
25
|
-
auth.set_token(
|
|
26
|
-
access_token=token, expires=auth.token_expiration_time.timestamp()
|
|
27
|
-
)
|
|
28
|
-
else:
|
|
29
|
-
raise ValueError("`--access-token` is required for authentication.")
|
|
30
|
-
|
|
31
|
-
|
|
32
22
|
class UniqKeys(str, Enum):
|
|
33
23
|
"""Literal implementation for the cli."""
|
|
34
24
|
|
|
@@ -47,7 +37,7 @@ class Flavours(str, Enum):
|
|
|
47
37
|
user = "user"
|
|
48
38
|
|
|
49
39
|
|
|
50
|
-
class
|
|
40
|
+
class SelectMethod(str, Enum):
|
|
51
41
|
"""Literal implementation for the cli."""
|
|
52
42
|
|
|
53
43
|
strict = "strict"
|
|
@@ -55,18 +45,44 @@ class TimeSelect(str, Enum):
|
|
|
55
45
|
file = "file"
|
|
56
46
|
|
|
57
47
|
@staticmethod
|
|
58
|
-
def get_help() -> str:
|
|
59
|
-
"""Generate the help string.
|
|
48
|
+
def get_help(context: str) -> str:
|
|
49
|
+
"""Generate the help string for time or bbox selection methods.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
context: str, default: "time"
|
|
54
|
+
Either "time" or "bbox" to generate appropriate help text.
|
|
55
|
+
"""
|
|
56
|
+
examples = {
|
|
57
|
+
"time": ("2000 to 2012", "2010 to 2020"),
|
|
58
|
+
"bbox": ("-10 10 -10 10", "0 5 0 5"),
|
|
59
|
+
}
|
|
60
|
+
descriptions = {
|
|
61
|
+
"time": {
|
|
62
|
+
"unit": "time period",
|
|
63
|
+
"start_end": "start or end period",
|
|
64
|
+
"subset": "time period",
|
|
65
|
+
},
|
|
66
|
+
"bbox": {
|
|
67
|
+
"unit": "spatial extent",
|
|
68
|
+
"start_end": "any part of the extent",
|
|
69
|
+
"subset": "spatial extent",
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
context_info = descriptions.get(context, descriptions["time"])
|
|
74
|
+
example = examples.get(context, examples["time"])
|
|
75
|
+
|
|
60
76
|
return (
|
|
61
|
-
"Operator that specifies how the
|
|
77
|
+
f"Operator that specifies how the {context_info['unit']} is selected. "
|
|
62
78
|
"Choose from flexible (default), strict or file. "
|
|
63
79
|
"``strict`` returns only those files that have the *entire* "
|
|
64
|
-
"
|
|
65
|
-
"not select files containing data from
|
|
66
|
-
"the ``strict`` method. ``flexible`` will select those files "
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
80
|
+
f"{context_info['unit']} covered. The {context} search ``{example[0]}`` "
|
|
81
|
+
f"will not select files containing data from {example[1]} with "
|
|
82
|
+
"the ``strict`` method. ``flexible`` will select those files as "
|
|
83
|
+
f"``flexible`` returns those files that have {context_info['start_end']} "
|
|
84
|
+
f"covered. ``file`` will only return files where the entire "
|
|
85
|
+
f"{context_info['subset']} is contained within *one single* file."
|
|
70
86
|
)
|
|
71
87
|
|
|
72
88
|
|
|
@@ -124,11 +140,11 @@ def metadata_search(
|
|
|
124
140
|
"of climate datasets to query."
|
|
125
141
|
),
|
|
126
142
|
),
|
|
127
|
-
time_select:
|
|
143
|
+
time_select: SelectMethod = typer.Option(
|
|
128
144
|
"flexible",
|
|
129
145
|
"-ts",
|
|
130
146
|
"--time-select",
|
|
131
|
-
help=
|
|
147
|
+
help=SelectMethod.get_help("time"),
|
|
132
148
|
),
|
|
133
149
|
time: Optional[str] = typer.Option(
|
|
134
150
|
None,
|
|
@@ -144,6 +160,24 @@ def metadata_search(
|
|
|
144
160
|
" valid."
|
|
145
161
|
),
|
|
146
162
|
),
|
|
163
|
+
bbox: Optional[Tuple[float, float, float, float]] = typer.Option(
|
|
164
|
+
None,
|
|
165
|
+
"-b",
|
|
166
|
+
"--bbox",
|
|
167
|
+
help=(
|
|
168
|
+
"Special search facet to refine/subset search results by spatial "
|
|
169
|
+
"extent. This can be a string representation of a bounding box. "
|
|
170
|
+
"The bounding box has to follow the format ``min_lon max_lon "
|
|
171
|
+
"min_lat,max_lat``. Valid strings are ``-10 10 -10 10`` to "
|
|
172
|
+
"``0 5 0 5``."
|
|
173
|
+
),
|
|
174
|
+
),
|
|
175
|
+
bbox_select: SelectMethod = typer.Option(
|
|
176
|
+
"flexible",
|
|
177
|
+
"-bs",
|
|
178
|
+
"--bbox-select",
|
|
179
|
+
help=SelectMethod.get_help("bbox"),
|
|
180
|
+
),
|
|
147
181
|
extended_search: bool = typer.Option(
|
|
148
182
|
False,
|
|
149
183
|
"-e",
|
|
@@ -188,13 +222,10 @@ def metadata_search(
|
|
|
188
222
|
result = databrowser.metadata_search(
|
|
189
223
|
*(facets or []),
|
|
190
224
|
time=time or "",
|
|
191
|
-
time_select=
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
flavour=
|
|
195
|
-
Literal["freva", "cmip6", "cmip5", "cordex", "nextgems", "user"],
|
|
196
|
-
flavour.value,
|
|
197
|
-
),
|
|
225
|
+
time_select=time_select.value,
|
|
226
|
+
bbox=bbox or None,
|
|
227
|
+
bbox_select=bbox_select.value,
|
|
228
|
+
flavour=flavour.value,
|
|
198
229
|
host=host,
|
|
199
230
|
extended_search=extended_search,
|
|
200
231
|
multiversion=multiversion,
|
|
@@ -248,19 +279,21 @@ def data_search(
|
|
|
248
279
|
"of climate datasets to query."
|
|
249
280
|
),
|
|
250
281
|
),
|
|
251
|
-
time_select:
|
|
282
|
+
time_select: SelectMethod = typer.Option(
|
|
252
283
|
"flexible",
|
|
253
284
|
"-ts",
|
|
254
285
|
"--time-select",
|
|
255
|
-
help=
|
|
286
|
+
help=SelectMethod.get_help("time"),
|
|
256
287
|
),
|
|
257
288
|
zarr: bool = typer.Option(False, "--zarr", help="Create zarr stream files."),
|
|
258
|
-
|
|
289
|
+
token_file: Optional[Path] = typer.Option(
|
|
259
290
|
None,
|
|
260
|
-
"--
|
|
291
|
+
"--token-file",
|
|
292
|
+
"-t",
|
|
261
293
|
help=(
|
|
262
|
-
"
|
|
263
|
-
"
|
|
294
|
+
"Instead of authenticating via code based authentication flow "
|
|
295
|
+
"you can set the path to the json file that contains a "
|
|
296
|
+
"`refresh token` containing a refresh_token key."
|
|
264
297
|
),
|
|
265
298
|
),
|
|
266
299
|
time: Optional[str] = typer.Option(
|
|
@@ -277,6 +310,24 @@ def data_search(
|
|
|
277
310
|
" valid."
|
|
278
311
|
),
|
|
279
312
|
),
|
|
313
|
+
bbox: Optional[Tuple[float, float, float, float]] = typer.Option(
|
|
314
|
+
None,
|
|
315
|
+
"-b",
|
|
316
|
+
"--bbox",
|
|
317
|
+
help=(
|
|
318
|
+
"Special search facet to refine/subset search results by spatial "
|
|
319
|
+
"extent. This can be a string representation of a bounding box. "
|
|
320
|
+
"The bounding box has to follow the format ``min_lon max_lon "
|
|
321
|
+
"min_lat max_lat``. Valid strings are ``-10 10 -10 10`` to "
|
|
322
|
+
"``0 5 0 5``."
|
|
323
|
+
),
|
|
324
|
+
),
|
|
325
|
+
bbox_select: SelectMethod = typer.Option(
|
|
326
|
+
"flexible",
|
|
327
|
+
"-bs",
|
|
328
|
+
"--bbox-select",
|
|
329
|
+
help=SelectMethod.get_help("bbox"),
|
|
330
|
+
),
|
|
280
331
|
parse_json: bool = typer.Option(
|
|
281
332
|
False, "-j", "--json", help="Parse output in json format."
|
|
282
333
|
),
|
|
@@ -313,12 +364,11 @@ def data_search(
|
|
|
313
364
|
result = databrowser(
|
|
314
365
|
*(facets or []),
|
|
315
366
|
time=time or "",
|
|
316
|
-
time_select=
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
uniq_key=cast(Literal["uri", "file"], uniq_key.value),
|
|
367
|
+
time_select=time_select.value,
|
|
368
|
+
bbox=bbox or None,
|
|
369
|
+
bbox_select=bbox_select.value,
|
|
370
|
+
flavour=flavour.value,
|
|
371
|
+
uniq_key=uniq_key.value,
|
|
322
372
|
host=host,
|
|
323
373
|
fail_on_error=False,
|
|
324
374
|
multiversion=multiversion,
|
|
@@ -326,7 +376,7 @@ def data_search(
|
|
|
326
376
|
**(parse_cli_args(search_keys or [])),
|
|
327
377
|
)
|
|
328
378
|
if zarr:
|
|
329
|
-
|
|
379
|
+
Auth(token_file).authenticate(host=host, _cli=True)
|
|
330
380
|
if parse_json:
|
|
331
381
|
print(json.dumps(sorted(result)))
|
|
332
382
|
else:
|
|
@@ -374,11 +424,11 @@ def intake_catalogue(
|
|
|
374
424
|
"of climate datasets to query."
|
|
375
425
|
),
|
|
376
426
|
),
|
|
377
|
-
time_select:
|
|
427
|
+
time_select: SelectMethod = typer.Option(
|
|
378
428
|
"flexible",
|
|
379
429
|
"-ts",
|
|
380
430
|
"--time-select",
|
|
381
|
-
help=
|
|
431
|
+
help=SelectMethod.get_help("time"),
|
|
382
432
|
),
|
|
383
433
|
time: Optional[str] = typer.Option(
|
|
384
434
|
None,
|
|
@@ -394,15 +444,34 @@ def intake_catalogue(
|
|
|
394
444
|
" valid."
|
|
395
445
|
),
|
|
396
446
|
),
|
|
447
|
+
bbox: Optional[Tuple[float, float, float, float]] = typer.Option(
|
|
448
|
+
None,
|
|
449
|
+
"-b",
|
|
450
|
+
"--bbox",
|
|
451
|
+
help=(
|
|
452
|
+
"Special search facet to refine/subset search results by spatial "
|
|
453
|
+
"extent. This can be a string representation of a bounding box. "
|
|
454
|
+
"The bounding box has to follow the format ``min_lon max_lon "
|
|
455
|
+
"min_lat max_lat``. Valid strings are ``-10 10 -10 10`` to "
|
|
456
|
+
"``0 5 0 5``."
|
|
457
|
+
),
|
|
458
|
+
),
|
|
459
|
+
bbox_select: SelectMethod = typer.Option(
|
|
460
|
+
"flexible",
|
|
461
|
+
"-bs",
|
|
462
|
+
"--bbox-select",
|
|
463
|
+
help=SelectMethod.get_help("bbox"),
|
|
464
|
+
),
|
|
397
465
|
zarr: bool = typer.Option(
|
|
398
466
|
False, "--zarr", help="Create zarr stream files, as catalogue targets."
|
|
399
467
|
),
|
|
400
|
-
|
|
468
|
+
token_file: Optional[Path] = typer.Option(
|
|
401
469
|
None,
|
|
402
|
-
"--
|
|
470
|
+
"--token-file",
|
|
403
471
|
help=(
|
|
404
|
-
"
|
|
405
|
-
"
|
|
472
|
+
"Instead of authenticating via code based authentication flow "
|
|
473
|
+
"you can set the path to the json file that contains a "
|
|
474
|
+
"`refresh token` containing a refresh_token key."
|
|
406
475
|
),
|
|
407
476
|
),
|
|
408
477
|
filename: Optional[Path] = typer.Option(
|
|
@@ -444,12 +513,11 @@ def intake_catalogue(
|
|
|
444
513
|
result = databrowser(
|
|
445
514
|
*(facets or []),
|
|
446
515
|
time=time or "",
|
|
447
|
-
time_select=
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
uniq_key=cast(Literal["uri", "file"], uniq_key.value),
|
|
516
|
+
time_select=time_select.value,
|
|
517
|
+
bbox=bbox or None,
|
|
518
|
+
bbox_select=bbox_select.value,
|
|
519
|
+
flavour=flavour.value,
|
|
520
|
+
uniq_key=uniq_key.value,
|
|
453
521
|
host=host,
|
|
454
522
|
fail_on_error=False,
|
|
455
523
|
multiversion=multiversion,
|
|
@@ -457,13 +525,145 @@ def intake_catalogue(
|
|
|
457
525
|
**(parse_cli_args(search_keys or [])),
|
|
458
526
|
)
|
|
459
527
|
if zarr:
|
|
460
|
-
|
|
528
|
+
Auth(token_file).authenticate(host=host, _cli=True)
|
|
461
529
|
with NamedTemporaryFile(suffix=".json") as temp_f:
|
|
462
530
|
result._create_intake_catalogue_file(str(filename or temp_f.name))
|
|
463
531
|
if not filename:
|
|
464
532
|
print(Path(temp_f.name).read_text())
|
|
465
533
|
|
|
466
534
|
|
|
535
|
+
@databrowser_app.command(
|
|
536
|
+
name="stac-catalogue", help="Create a static STAC catalogue from the search."
|
|
537
|
+
)
|
|
538
|
+
@exception_handler
|
|
539
|
+
def stac_catalogue(
|
|
540
|
+
search_keys: Optional[List[str]] = typer.Argument(
|
|
541
|
+
default=None,
|
|
542
|
+
help="Refine your data search with this `key=value` pair search "
|
|
543
|
+
"parameters. The parameters could be, depending on the DRS standard, "
|
|
544
|
+
"flavour product, project model etc.",
|
|
545
|
+
),
|
|
546
|
+
facets: Optional[List[str]] = typer.Option(
|
|
547
|
+
None,
|
|
548
|
+
"--facet",
|
|
549
|
+
help=(
|
|
550
|
+
"If you are not sure about the correct search key's you can use"
|
|
551
|
+
" the ``--facet`` flag to search of any matching entries. For "
|
|
552
|
+
"example --facet 'era5' would allow you to search for any entries"
|
|
553
|
+
" containing era5, regardless of project, product etc."
|
|
554
|
+
),
|
|
555
|
+
),
|
|
556
|
+
uniq_key: UniqKeys = typer.Option(
|
|
557
|
+
"file",
|
|
558
|
+
"--uniq-key",
|
|
559
|
+
"-u",
|
|
560
|
+
help=(
|
|
561
|
+
"The type of search result, which can be either “file” "
|
|
562
|
+
"or “uri”. This parameter determines whether the search will be "
|
|
563
|
+
"based on file paths or Uniform Resource Identifiers"
|
|
564
|
+
),
|
|
565
|
+
),
|
|
566
|
+
flavour: Flavours = typer.Option(
|
|
567
|
+
"freva",
|
|
568
|
+
"--flavour",
|
|
569
|
+
"-f",
|
|
570
|
+
help=(
|
|
571
|
+
"The Data Reference Syntax (DRS) standard specifying the type "
|
|
572
|
+
"of climate datasets to query."
|
|
573
|
+
),
|
|
574
|
+
),
|
|
575
|
+
time_select: SelectMethod = typer.Option(
|
|
576
|
+
"flexible",
|
|
577
|
+
"-ts",
|
|
578
|
+
"--time-select",
|
|
579
|
+
help=SelectMethod.get_help("time"),
|
|
580
|
+
),
|
|
581
|
+
time: Optional[str] = typer.Option(
|
|
582
|
+
None,
|
|
583
|
+
"-t",
|
|
584
|
+
"--time",
|
|
585
|
+
help=(
|
|
586
|
+
"Special search facet to refine/subset search results by time. "
|
|
587
|
+
"This can be a string representation of a time range or a single "
|
|
588
|
+
"time step. The time steps have to follow ISO-8601. Valid strings "
|
|
589
|
+
"are ``%Y-%m-%dT%H:%M`` to ``%Y-%m-%dT%H:%M`` for time ranges and "
|
|
590
|
+
"``%Y-%m-%dT%H:%M``. **Note**: You don't have to give the full "
|
|
591
|
+
"string format to subset time steps ``%Y``, ``%Y-%m`` etc are also"
|
|
592
|
+
" valid."
|
|
593
|
+
),
|
|
594
|
+
),
|
|
595
|
+
bbox: Optional[Tuple[float, float, float, float]] = typer.Option(
|
|
596
|
+
None,
|
|
597
|
+
"-b",
|
|
598
|
+
"--bbox",
|
|
599
|
+
help=(
|
|
600
|
+
"Special search facet to refine/subset search results by spatial "
|
|
601
|
+
"extent. This can be a string representation of a bounding box. "
|
|
602
|
+
"The bounding box has to follow the format ``min_lon max_lon "
|
|
603
|
+
"min_lat max_lat``. Valid strings are ``-10 10 -10 10`` to "
|
|
604
|
+
"``0 5 0 5``."
|
|
605
|
+
),
|
|
606
|
+
),
|
|
607
|
+
bbox_select: SelectMethod = typer.Option(
|
|
608
|
+
"flexible",
|
|
609
|
+
"-bs",
|
|
610
|
+
"--bbox-select",
|
|
611
|
+
help=SelectMethod.get_help("bbox"),
|
|
612
|
+
),
|
|
613
|
+
host: Optional[str] = typer.Option(
|
|
614
|
+
None,
|
|
615
|
+
"--host",
|
|
616
|
+
help=(
|
|
617
|
+
"Set the hostname of the databrowser, if not set (default) "
|
|
618
|
+
"the hostname is read from a config file"
|
|
619
|
+
),
|
|
620
|
+
),
|
|
621
|
+
verbose: int = typer.Option(0, "-v", help="Increase verbosity", count=True),
|
|
622
|
+
multiversion: bool = typer.Option(
|
|
623
|
+
False,
|
|
624
|
+
"--multi-version",
|
|
625
|
+
help="Select all versions and not just the latest version (default).",
|
|
626
|
+
),
|
|
627
|
+
version: Optional[bool] = typer.Option(
|
|
628
|
+
False,
|
|
629
|
+
"-V",
|
|
630
|
+
"--version",
|
|
631
|
+
help="Show version an exit",
|
|
632
|
+
callback=version_callback,
|
|
633
|
+
),
|
|
634
|
+
filename: Optional[Path] = typer.Option(
|
|
635
|
+
None,
|
|
636
|
+
"-o",
|
|
637
|
+
"--filename",
|
|
638
|
+
help=(
|
|
639
|
+
"Path to the file where the static STAC catalogue, "
|
|
640
|
+
"should be written to. If you don't specify or the path "
|
|
641
|
+
"does not exist, the file will be created in the current "
|
|
642
|
+
"working directory. "
|
|
643
|
+
),
|
|
644
|
+
),
|
|
645
|
+
) -> None:
|
|
646
|
+
"""Create a STAC catalogue for climate datasets based on the specified
|
|
647
|
+
Data Reference Syntax (DRS) standard (flavour) and the type of search
|
|
648
|
+
result (uniq_key), which can be either "file" or "uri"."""
|
|
649
|
+
logger.set_verbosity(verbose)
|
|
650
|
+
result = databrowser(
|
|
651
|
+
*(facets or []),
|
|
652
|
+
time=time or "",
|
|
653
|
+
time_select=time_select.value,
|
|
654
|
+
bbox=bbox or None,
|
|
655
|
+
bbox_select=bbox_select.value,
|
|
656
|
+
flavour=flavour.value,
|
|
657
|
+
uniq_key=uniq_key.value,
|
|
658
|
+
host=host,
|
|
659
|
+
fail_on_error=False,
|
|
660
|
+
multiversion=multiversion,
|
|
661
|
+
stream_zarr=False,
|
|
662
|
+
**(parse_cli_args(search_keys or [])),
|
|
663
|
+
)
|
|
664
|
+
print(result.stac_catalogue(filename=filename))
|
|
665
|
+
|
|
666
|
+
|
|
467
667
|
@databrowser_app.command(
|
|
468
668
|
name="data-count", help="Count the databrowser search results"
|
|
469
669
|
)
|
|
@@ -500,11 +700,11 @@ def count_values(
|
|
|
500
700
|
"of climate datasets to query."
|
|
501
701
|
),
|
|
502
702
|
),
|
|
503
|
-
time_select:
|
|
703
|
+
time_select: SelectMethod = typer.Option(
|
|
504
704
|
"flexible",
|
|
505
705
|
"-ts",
|
|
506
706
|
"--time-select",
|
|
507
|
-
help=
|
|
707
|
+
help=SelectMethod.get_help("time"),
|
|
508
708
|
),
|
|
509
709
|
time: Optional[str] = typer.Option(
|
|
510
710
|
None,
|
|
@@ -520,6 +720,24 @@ def count_values(
|
|
|
520
720
|
" valid."
|
|
521
721
|
),
|
|
522
722
|
),
|
|
723
|
+
bbox: Optional[Tuple[float, float, float, float]] = typer.Option(
|
|
724
|
+
None,
|
|
725
|
+
"-b",
|
|
726
|
+
"--bbox",
|
|
727
|
+
help=(
|
|
728
|
+
"Special search facet to refine/subset search results by spatial "
|
|
729
|
+
"extent. This can be a string representation of a bounding box. "
|
|
730
|
+
"The bounding box has to follow the format ``min_lon max_lon "
|
|
731
|
+
"min_lat max_lat``. Valid strings are ``-10 10 -10 10`` to "
|
|
732
|
+
"``0 5 0 5``."
|
|
733
|
+
),
|
|
734
|
+
),
|
|
735
|
+
bbox_select: SelectMethod = typer.Option(
|
|
736
|
+
"flexible",
|
|
737
|
+
"-bs",
|
|
738
|
+
"--bbox-select",
|
|
739
|
+
help=SelectMethod.get_help("bbox"),
|
|
740
|
+
),
|
|
523
741
|
extended_search: bool = typer.Option(
|
|
524
742
|
False,
|
|
525
743
|
"-e",
|
|
@@ -564,16 +782,19 @@ def count_values(
|
|
|
564
782
|
result: Union[int, Dict[str, Dict[str, int]]] = 0
|
|
565
783
|
search_kws = parse_cli_args(search_keys or [])
|
|
566
784
|
time = cast(str, time or search_kws.pop("time", ""))
|
|
785
|
+
bbox = cast(
|
|
786
|
+
Optional[Tuple[float, float, float, float]],
|
|
787
|
+
bbox or search_kws.pop("bbox", None),
|
|
788
|
+
)
|
|
567
789
|
facets = facets or []
|
|
568
790
|
if detail:
|
|
569
791
|
result = databrowser.count_values(
|
|
570
792
|
*facets,
|
|
571
793
|
time=time or "",
|
|
572
|
-
time_select=
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
),
|
|
794
|
+
time_select=time_select.value,
|
|
795
|
+
bbox=bbox or None,
|
|
796
|
+
bbox_select=bbox_select.value,
|
|
797
|
+
flavour=flavour.value,
|
|
577
798
|
host=host,
|
|
578
799
|
extended_search=extended_search,
|
|
579
800
|
multiversion=multiversion,
|
|
@@ -585,15 +806,10 @@ def count_values(
|
|
|
585
806
|
databrowser(
|
|
586
807
|
*facets,
|
|
587
808
|
time=time or "",
|
|
588
|
-
time_select=
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
flavour=
|
|
592
|
-
Literal[
|
|
593
|
-
"freva", "cmip6", "cmip5", "cordex", "nextgems", "user"
|
|
594
|
-
],
|
|
595
|
-
flavour.value,
|
|
596
|
-
),
|
|
809
|
+
time_select=time_select.value,
|
|
810
|
+
bbox=bbox or None,
|
|
811
|
+
bbox_select=bbox_select.value,
|
|
812
|
+
flavour=flavour.value,
|
|
597
813
|
host=host,
|
|
598
814
|
multiversion=multiversion,
|
|
599
815
|
fail_on_error=False,
|
|
@@ -642,18 +858,21 @@ def user_data_add(
|
|
|
642
858
|
"the hostname is read from a config file."
|
|
643
859
|
),
|
|
644
860
|
),
|
|
645
|
-
|
|
861
|
+
token_file: Optional[Path] = typer.Option(
|
|
646
862
|
None,
|
|
647
|
-
"--
|
|
648
|
-
help=
|
|
863
|
+
"--token-file",
|
|
864
|
+
help=(
|
|
865
|
+
"Instead of authenticating via code based authentication flow "
|
|
866
|
+
"you can set the path to the json file that contains a "
|
|
867
|
+
"`refresh token` containing a refresh_token key."
|
|
868
|
+
),
|
|
649
869
|
),
|
|
650
870
|
verbose: int = typer.Option(0, "-v", help="Increase verbosity", count=True),
|
|
651
871
|
) -> None:
|
|
652
872
|
"""Add user data into the databrowser."""
|
|
653
873
|
logger.set_verbosity(verbose)
|
|
654
874
|
logger.debug("Checking if the user has the right to add data")
|
|
655
|
-
|
|
656
|
-
_auth(result._cfg.auth_url, access_token)
|
|
875
|
+
Auth(token_file).authenticate(host=host, _cli=True)
|
|
657
876
|
|
|
658
877
|
facet_dict = {}
|
|
659
878
|
if facets:
|
|
@@ -695,18 +914,21 @@ def user_data_delete(
|
|
|
695
914
|
"the hostname is read from a config file."
|
|
696
915
|
),
|
|
697
916
|
),
|
|
698
|
-
|
|
917
|
+
token_file: Optional[Path] = typer.Option(
|
|
699
918
|
None,
|
|
700
|
-
"--
|
|
701
|
-
help=
|
|
919
|
+
"--token-file",
|
|
920
|
+
help=(
|
|
921
|
+
"Instead of authenticating via code based authentication flow "
|
|
922
|
+
"you can set the path to the json file that contains a "
|
|
923
|
+
"`refresh token` containing a refresh_token key."
|
|
924
|
+
),
|
|
702
925
|
),
|
|
703
926
|
verbose: int = typer.Option(0, "-v", help="Increase verbosity", count=True),
|
|
704
927
|
) -> None:
|
|
705
928
|
"""Delete user data from the databrowser."""
|
|
706
929
|
logger.set_verbosity(verbose)
|
|
707
930
|
logger.debug("Checking if the user has the right to delete data")
|
|
708
|
-
|
|
709
|
-
_auth(result._cfg.auth_url, access_token)
|
|
931
|
+
Auth(token_file).authenticate(host=host, _cli=True)
|
|
710
932
|
|
|
711
933
|
search_key_dict = {}
|
|
712
934
|
if search_keys:
|