cwms-cli 0.1.1__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.
- cwms_cli-0.1.1.dist-info/METADATA +40 -0
- cwms_cli-0.1.1.dist-info/RECORD +41 -0
- cwms_cli-0.1.1.dist-info/WHEEL +4 -0
- cwms_cli-0.1.1.dist-info/entry_points.txt +3 -0
- cwms_cli-0.1.1.dist-info/licenses/LICENSE +21 -0
- cwmscli/__init__.py +12 -0
- cwmscli/__main__.py +15 -0
- cwmscli/callbacks/__init__.py +18 -0
- cwmscli/commands/blob.py +439 -0
- cwmscli/commands/commands_cwms.py +227 -0
- cwmscli/commands/csv2cwms/.gitignore +3 -0
- cwmscli/commands/csv2cwms/README.md +51 -0
- cwmscli/commands/csv2cwms/__init__.py +5 -0
- cwmscli/commands/csv2cwms/__main__.py +265 -0
- cwmscli/commands/csv2cwms/examples/complete_config.json +19 -0
- cwmscli/commands/csv2cwms/examples/hourly.json +243 -0
- cwmscli/commands/csv2cwms/examples/minutes.json +315 -0
- cwmscli/commands/csv2cwms/tests/__init__.py +0 -0
- cwmscli/commands/csv2cwms/tests/data/.gitignore +1 -0
- cwmscli/commands/csv2cwms/tests/data/expected_brok_output.json +278 -0
- cwmscli/commands/csv2cwms/tests/data/sample_brok.csv +9 -0
- cwmscli/commands/csv2cwms/tests/data/sample_config.json +45 -0
- cwmscli/commands/csv2cwms/tests/skip_test_integration_pipeline.py +35 -0
- cwmscli/commands/csv2cwms/tests/test_dateutils.py +68 -0
- cwmscli/commands/csv2cwms/tests/test_expressions.py +49 -0
- cwmscli/commands/csv2cwms/tests/test_fileio.py +43 -0
- cwmscli/commands/csv2cwms/utils/__init__.py +5 -0
- cwmscli/commands/csv2cwms/utils/dateutils.py +105 -0
- cwmscli/commands/csv2cwms/utils/expression.py +39 -0
- cwmscli/commands/csv2cwms/utils/fileio.py +26 -0
- cwmscli/commands/csv2cwms/utils/logging.py +80 -0
- cwmscli/commands/csv2cwms/utils/terminal.py +45 -0
- cwmscli/commands/shef_critfile_import.py +146 -0
- cwmscli/requirements.py +25 -0
- cwmscli/usgs/__init__.py +161 -0
- cwmscli/usgs/getUSGS_ratings_cda.py +346 -0
- cwmscli/usgs/getusgs_cda.py +345 -0
- cwmscli/usgs/getusgs_measurements_cda.py +961 -0
- cwmscli/usgs/rating_ini_file_import.py +130 -0
- cwmscli/utils/__init__.py +68 -0
- cwmscli/utils/deps.py +102 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def read_config(config_path):
|
|
7
|
+
"""Read the configuration file"""
|
|
8
|
+
if not config_path.endswith(".json"):
|
|
9
|
+
raise ValueError("Configuration file must be a JSON file.")
|
|
10
|
+
with open(config_path, "r") as f:
|
|
11
|
+
config = json.load(f)
|
|
12
|
+
return config
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def load_csv(file_path):
|
|
16
|
+
"""Load the CSV file and return the data."""
|
|
17
|
+
if not file_path.endswith(".csv"):
|
|
18
|
+
raise ValueError("Data file must be a CSV file.")
|
|
19
|
+
if not os.path.exists(file_path):
|
|
20
|
+
raise FileNotFoundError(
|
|
21
|
+
f"File not found: {file_path}. Be sure to set the path correctly in the configuration file. And use the argument --data-path to specify the directory containing the data files."
|
|
22
|
+
)
|
|
23
|
+
with open(file_path, "r") as f:
|
|
24
|
+
reader = csv.reader(f)
|
|
25
|
+
data = list(reader)
|
|
26
|
+
return data
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from logging.handlers import RotatingFileHandler
|
|
3
|
+
|
|
4
|
+
from .terminal import colorize
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger("csv2cwms")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ColorFormatter(logging.Formatter):
|
|
10
|
+
"""Logging Formatter that colorizes the level name."""
|
|
11
|
+
|
|
12
|
+
LEVEL_COLORS = {
|
|
13
|
+
logging.DEBUG: "cyan",
|
|
14
|
+
logging.INFO: "blue",
|
|
15
|
+
logging.WARNING: "yellow",
|
|
16
|
+
logging.ERROR: "red",
|
|
17
|
+
logging.CRITICAL: "magenta",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
def formatTime(self, record, datefmt=None):
|
|
21
|
+
"""Override to colorize asctime in gray."""
|
|
22
|
+
timestr = super().formatTime(record, datefmt)
|
|
23
|
+
return colorize(timestr, "gray")
|
|
24
|
+
|
|
25
|
+
def format(self, record):
|
|
26
|
+
level_color = self.LEVEL_COLORS.get(record.levelno, "reset")
|
|
27
|
+
record.levelname = colorize(record.levelname, level_color)
|
|
28
|
+
return super().format(record)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def setup_logger(
|
|
32
|
+
log_path: str = "",
|
|
33
|
+
max_log_size_mb: int = 5,
|
|
34
|
+
backup_count: int = 3,
|
|
35
|
+
show_console: bool = True,
|
|
36
|
+
verbose: bool = False,
|
|
37
|
+
):
|
|
38
|
+
"""Set up logger with rotating file handler
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
log_path (str): Path to the log file
|
|
42
|
+
max_log_size_mb (int): Maximum log file size in MB before rotating
|
|
43
|
+
backup_count (int): Number of backup log files to keep
|
|
44
|
+
show_console (bool): Log to console as well as file
|
|
45
|
+
|
|
46
|
+
# Example usage
|
|
47
|
+
logger.info("This is an info message")
|
|
48
|
+
logger.error("This is an error message")
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
logger: logging.Logger
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
# Remove the default logger handlers from cwms-cli so we can set up our own
|
|
55
|
+
root = logging.getLogger()
|
|
56
|
+
for h in root.handlers[:]:
|
|
57
|
+
root.removeHandler(h)
|
|
58
|
+
# Create formatter and attach to handler
|
|
59
|
+
formatter = ColorFormatter(
|
|
60
|
+
"[%(asctime)s] [%(levelname)s] %(message)s", "%Y-%m-%d %H:%M:%S"
|
|
61
|
+
)
|
|
62
|
+
# Setup the logger if it has not already been configured
|
|
63
|
+
logger.setLevel(logging.DEBUG if verbose else logging.INFO)
|
|
64
|
+
if log_path:
|
|
65
|
+
# Create rotating file handler
|
|
66
|
+
file_handler = RotatingFileHandler(
|
|
67
|
+
log_path, maxBytes=max_log_size_mb * 1024 * 1024, backupCount=backup_count
|
|
68
|
+
)
|
|
69
|
+
file_handler.setLevel(logging.DEBUG)
|
|
70
|
+
|
|
71
|
+
file_handler.setFormatter(formatter)
|
|
72
|
+
logger.addHandler(file_handler)
|
|
73
|
+
|
|
74
|
+
# Setup console handler if needed
|
|
75
|
+
if not logger.hasHandlers() or show_console:
|
|
76
|
+
console_handler = logging.StreamHandler()
|
|
77
|
+
console_handler.setFormatter(formatter)
|
|
78
|
+
logger.addHandler(console_handler)
|
|
79
|
+
logger.debug(f"Logger configured with log file: {log_path}")
|
|
80
|
+
return logger
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
def colorize_count(valid: int, total: int) -> str:
|
|
2
|
+
"""Colorize the count based on the percentage of valid data.
|
|
3
|
+
Args:
|
|
4
|
+
valid (int): Number of valid data.
|
|
5
|
+
total (int): Total number of data.
|
|
6
|
+
Returns:
|
|
7
|
+
str: ANSI Escape Code representing the colorized count status.
|
|
8
|
+
"""
|
|
9
|
+
percent = valid / total if total else 0
|
|
10
|
+
|
|
11
|
+
if valid == 0:
|
|
12
|
+
color = "red"
|
|
13
|
+
elif percent >= 0.95:
|
|
14
|
+
color = "green"
|
|
15
|
+
else:
|
|
16
|
+
color = "yellow"
|
|
17
|
+
|
|
18
|
+
return f"{colorize(f'{valid}/{total}', color)}"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def colorize(text: str, color: str) -> str:
|
|
22
|
+
"""Colorize the text with ANSI Escape Codes provided a color
|
|
23
|
+
Args:
|
|
24
|
+
text (str): Text to colorize.
|
|
25
|
+
color (str): Color to use.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
str: ANSI Escape Code representing the colorized count status.
|
|
29
|
+
"""
|
|
30
|
+
COLORS = {
|
|
31
|
+
"red": "\033[91m",
|
|
32
|
+
"green": "\033[92m",
|
|
33
|
+
"yellow": "\033[93m",
|
|
34
|
+
"blue": "\033[94m",
|
|
35
|
+
"magenta": "\033[95m",
|
|
36
|
+
"cyan": "\033[96m",
|
|
37
|
+
"white": "\033[97m",
|
|
38
|
+
"gray": "\033[90m",
|
|
39
|
+
"reset": "\033[0m",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if color not in COLORS:
|
|
43
|
+
return text
|
|
44
|
+
|
|
45
|
+
return f"{COLORS.get(color.lower(), COLORS['reset'])}{text}{COLORS['reset']}"
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import re
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
|
|
5
|
+
import cwms
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def import_shef_critfile(
|
|
10
|
+
file_path: str,
|
|
11
|
+
office_id: str,
|
|
12
|
+
api_root: str,
|
|
13
|
+
api_key: str,
|
|
14
|
+
group_id: str = "SHEF Data Acquisition",
|
|
15
|
+
category_id: str = "Data Acquisition",
|
|
16
|
+
group_office_id: str = "CWMS",
|
|
17
|
+
category_office_id: str = "CWMS",
|
|
18
|
+
replace_assigned_ts: bool = False,
|
|
19
|
+
) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Processes a .crit file and saves the information to the SHEF Data Acquisition time series group.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
file_path : str
|
|
26
|
+
Path to the .crit file.
|
|
27
|
+
office_id : str
|
|
28
|
+
The ID of the office associated with the specified timeseries.
|
|
29
|
+
group_id : str, optional
|
|
30
|
+
The specified group associated with the timeseries data. Defaults to "SHEF Data Acquisition".
|
|
31
|
+
category_id : str, optional
|
|
32
|
+
The category ID that contains the timeseries group. Defaults to "Data Acquisition".
|
|
33
|
+
group_office_id : str, optional
|
|
34
|
+
The specified office group associated with the timeseries data. Defaults to "CWMS".
|
|
35
|
+
replace_assigned_ts : bool, optional
|
|
36
|
+
Specifies whether to unassign all existing time series before assigning new time series specified in the content body. Default is False.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
None
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
api_key = "apikey " + api_key
|
|
44
|
+
cwms.api.init_session(api_root=api_root, api_key=api_key)
|
|
45
|
+
logging.info(f"CDA connection: {api_root}")
|
|
46
|
+
|
|
47
|
+
# Parse the file and get the parsed data
|
|
48
|
+
parsed_data = parse_crit_file(file_path)
|
|
49
|
+
logging.info("CRIT file has been parsed")
|
|
50
|
+
# df = pd.DataFrame()
|
|
51
|
+
logging.info(f"Saving Timeseries IDs to group: {group_id}")
|
|
52
|
+
for data in parsed_data:
|
|
53
|
+
# Create DataFrame for the current row
|
|
54
|
+
try:
|
|
55
|
+
df = create_df(office_id, data["Timeseries ID"], data["Alias"])
|
|
56
|
+
|
|
57
|
+
# Generate JSON dictionary
|
|
58
|
+
json_dict = cwms.timeseries_group_df_to_json(
|
|
59
|
+
data=df,
|
|
60
|
+
group_id=group_id,
|
|
61
|
+
group_office_id=group_office_id,
|
|
62
|
+
category_office_id=category_office_id,
|
|
63
|
+
category_id=category_id,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
cwms.update_timeseries_groups(
|
|
67
|
+
group_id=group_id,
|
|
68
|
+
office_id=office_id,
|
|
69
|
+
replace_assigned_ts=replace_assigned_ts,
|
|
70
|
+
data=json_dict,
|
|
71
|
+
)
|
|
72
|
+
logging.info(
|
|
73
|
+
f'SUCCESS Stored timeseries ID {data["Timeseries ID"]} to {group_id}'
|
|
74
|
+
)
|
|
75
|
+
except Exception as error:
|
|
76
|
+
logging.error(
|
|
77
|
+
f'FAIL Data could not be stored to CWMS database for --> {data["Timeseries ID"]},{data["Alias"]} error = {error}'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def parse_crit_file(file_path: str) -> List[Dict[str, str]]:
|
|
82
|
+
"""
|
|
83
|
+
Parses a .crit file into a dictionary containing timeseries ID and Alias.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
file_path : str
|
|
88
|
+
Path to the .crit file.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
List[Dict[str, str]]
|
|
93
|
+
A list of dictionaries with "Alias" and "Timeseries ID" as keys.
|
|
94
|
+
"""
|
|
95
|
+
parsed_data = []
|
|
96
|
+
with open(file_path, "r") as file:
|
|
97
|
+
for line in file:
|
|
98
|
+
# Ignore comment lines and empty lines
|
|
99
|
+
if line.startswith("#") or not line.strip():
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
# Extract alias, timeseries ID, and TZ
|
|
103
|
+
match = re.match(r"([^=]+)=([^;]+);(.+)", line.strip())
|
|
104
|
+
|
|
105
|
+
if match:
|
|
106
|
+
alias = match.group(1).strip()
|
|
107
|
+
timeseries_id = match.group(2).strip()
|
|
108
|
+
alias2 = match.group(3).strip()
|
|
109
|
+
|
|
110
|
+
parsed_data.append(
|
|
111
|
+
{
|
|
112
|
+
"Alias": alias + ":" + alias2,
|
|
113
|
+
"Timeseries ID": timeseries_id,
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return parsed_data
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def create_df(office_id: str, ts_id: str, alias: str) -> pd.DataFrame:
|
|
121
|
+
"""
|
|
122
|
+
Appends a row to the DataFrame.
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
df : pandas.DataFrame
|
|
127
|
+
The DataFrame to append to.
|
|
128
|
+
office_id : str
|
|
129
|
+
The ID of the office associated with the specified timeseries.
|
|
130
|
+
tsId : str
|
|
131
|
+
The timeseries ID from the file.
|
|
132
|
+
alias : str
|
|
133
|
+
The alias from the file.
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
pandas.DataFrame
|
|
137
|
+
The updated DataFrame.
|
|
138
|
+
"""
|
|
139
|
+
data = {
|
|
140
|
+
"office-id": [office_id],
|
|
141
|
+
"timeseries-id": [ts_id],
|
|
142
|
+
"alias-id": [alias],
|
|
143
|
+
}
|
|
144
|
+
# df = pd.concat([df, pd.DataFrame(data)])
|
|
145
|
+
df = pd.DataFrame(data)
|
|
146
|
+
return df
|
cwmscli/requirements.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# A file containing shared minimum version requirements for dependencies
|
|
2
|
+
# used by the `@requires` decorator in `cwmscli.utils.deps`.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
cwms = {
|
|
6
|
+
"module": "cwms",
|
|
7
|
+
"package": "cwms-python",
|
|
8
|
+
"version": "0.8.0",
|
|
9
|
+
"desc": "CWMS REST API Python client",
|
|
10
|
+
"link": "https://github.com/HydrologicEngineeringCenter/cwms-python",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
requests = {
|
|
14
|
+
"module": "requests",
|
|
15
|
+
"version": "2.30.0",
|
|
16
|
+
"desc": "Required for HTTP API access",
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
dataretrieval = {
|
|
20
|
+
"module": "dataretrieval",
|
|
21
|
+
"package": "dataretrieval",
|
|
22
|
+
"version": "1.0.10",
|
|
23
|
+
"desc": "Loading hydrologic data from USGS",
|
|
24
|
+
"link": "https://github.com/DOI-USGS/dataretrieval-python",
|
|
25
|
+
}
|
cwmscli/usgs/__init__.py
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from cwmscli import requirements as reqs
|
|
4
|
+
from cwmscli.utils.deps import requires
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@click.group()
|
|
8
|
+
def usgs_group():
|
|
9
|
+
"""USGS utilities"""
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from cwmscli import requirements as reqs
|
|
16
|
+
from cwmscli.utils import (
|
|
17
|
+
api_key_loc_option,
|
|
18
|
+
api_key_option,
|
|
19
|
+
api_root_option,
|
|
20
|
+
get_api_key,
|
|
21
|
+
office_option,
|
|
22
|
+
)
|
|
23
|
+
from cwmscli.utils.deps import requires
|
|
24
|
+
|
|
25
|
+
days_back_option = click.option(
|
|
26
|
+
"-d",
|
|
27
|
+
"--days_back",
|
|
28
|
+
default="1",
|
|
29
|
+
type=float,
|
|
30
|
+
help="Days back from current time to get data. Can be decimal and integer values",
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@usgs_group.command(
|
|
35
|
+
"timeseries", help="Get USGS timeseries values and store into CWMS database"
|
|
36
|
+
)
|
|
37
|
+
@office_option
|
|
38
|
+
@days_back_option
|
|
39
|
+
@api_root_option
|
|
40
|
+
@api_key_option
|
|
41
|
+
@api_key_loc_option
|
|
42
|
+
@click.option(
|
|
43
|
+
"-b",
|
|
44
|
+
"--backfill",
|
|
45
|
+
default=None,
|
|
46
|
+
type=str,
|
|
47
|
+
help='Backfill timeseries ids, use list of timeseries ids (e.g. "ts_id1, ts_id2") to attempt to backfill a subset of timeseries with USGS data',
|
|
48
|
+
)
|
|
49
|
+
@requires(reqs.cwms, reqs.requests)
|
|
50
|
+
def getusgs_timeseries(office, days_back, api_root, api_key, api_key_loc, backfill):
|
|
51
|
+
from cwmscli.usgs.getusgs_cda import getusgs_cda
|
|
52
|
+
|
|
53
|
+
if backfill is not None:
|
|
54
|
+
backfill_list = backfill.replace(" ", "").split(",")
|
|
55
|
+
else:
|
|
56
|
+
backfill_list = None
|
|
57
|
+
|
|
58
|
+
api_key = get_api_key(api_key, api_key_loc)
|
|
59
|
+
getusgs_cda(
|
|
60
|
+
api_root=api_root,
|
|
61
|
+
office_id=office,
|
|
62
|
+
days_back=days_back,
|
|
63
|
+
api_key=api_key,
|
|
64
|
+
backfill_tsids=backfill_list,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@usgs_group.command("ratings", help="Get USGS ratings and store into CWMS database")
|
|
69
|
+
@office_option
|
|
70
|
+
@days_back_option
|
|
71
|
+
@api_root_option
|
|
72
|
+
@api_key_option
|
|
73
|
+
@api_key_loc_option
|
|
74
|
+
@requires(reqs.cwms, reqs.requests, reqs.dataretrieval)
|
|
75
|
+
def getusgs_ratings(office, days_back, api_root, api_key, api_key_loc):
|
|
76
|
+
from cwmscli.usgs.getUSGS_ratings_cda import getusgs_rating_cda
|
|
77
|
+
|
|
78
|
+
api_key = get_api_key(api_key, api_key_loc)
|
|
79
|
+
getusgs_rating_cda(
|
|
80
|
+
api_root=api_root,
|
|
81
|
+
office_id=office,
|
|
82
|
+
days_back=days_back,
|
|
83
|
+
api_key=api_key,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@usgs_group.command(
|
|
88
|
+
"ratings-ini-file-import",
|
|
89
|
+
help="Store rating ini file information into database to be used with getusgs_ratings",
|
|
90
|
+
)
|
|
91
|
+
@click.option(
|
|
92
|
+
"-f",
|
|
93
|
+
"--filename",
|
|
94
|
+
required=True,
|
|
95
|
+
type=str,
|
|
96
|
+
help="filename of ratings ini file to be processed",
|
|
97
|
+
)
|
|
98
|
+
@api_root_option
|
|
99
|
+
@api_key_option
|
|
100
|
+
@api_key_loc_option
|
|
101
|
+
@requires(reqs.cwms, reqs.requests)
|
|
102
|
+
def ratingsinifileimport(filename, api_root, api_key, api_key_loc):
|
|
103
|
+
from cwmscli.usgs.rating_ini_file_import import rating_ini_file_import
|
|
104
|
+
|
|
105
|
+
api_key = get_api_key(api_key, api_key_loc)
|
|
106
|
+
rating_ini_file_import(api_root=api_root, api_key=api_key, ini_filename=filename)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@usgs_group.command("measurements", help="Store USGS measurements into CWMS database")
|
|
110
|
+
@click.option(
|
|
111
|
+
"-d",
|
|
112
|
+
"--days_back_modified",
|
|
113
|
+
default="2",
|
|
114
|
+
help="Days back from current time measurements have been modified in USGS database. Can be integer value",
|
|
115
|
+
)
|
|
116
|
+
@click.option(
|
|
117
|
+
"-c",
|
|
118
|
+
"--days_back_collected",
|
|
119
|
+
default="365",
|
|
120
|
+
help="Days back from current time measurements have been collected. Can be integer value",
|
|
121
|
+
)
|
|
122
|
+
@office_option
|
|
123
|
+
@api_root_option
|
|
124
|
+
@api_key_option
|
|
125
|
+
@api_key_loc_option
|
|
126
|
+
@click.option(
|
|
127
|
+
"-b",
|
|
128
|
+
"--backfill",
|
|
129
|
+
default=None,
|
|
130
|
+
type=str,
|
|
131
|
+
help="Backfill POR data, use list of USGS IDs (e.g. 05057200, 05051300) or the word 'group' to attempt to backfill all sites in the OFFICE id's Data Acquisition->USGS Measurements group",
|
|
132
|
+
)
|
|
133
|
+
@requires(reqs.cwms, reqs.requests, reqs.dataretrieval)
|
|
134
|
+
def getusgs_measurements(
|
|
135
|
+
days_back_modified,
|
|
136
|
+
days_back_collected,
|
|
137
|
+
office,
|
|
138
|
+
api_root,
|
|
139
|
+
api_key,
|
|
140
|
+
api_key_loc,
|
|
141
|
+
backfill,
|
|
142
|
+
):
|
|
143
|
+
from cwmscli.usgs.getusgs_measurements_cda import getusgs_measurement_cda
|
|
144
|
+
|
|
145
|
+
backfill_group = False
|
|
146
|
+
backfill_list = False
|
|
147
|
+
if backfill is not None:
|
|
148
|
+
if "group" in backfill:
|
|
149
|
+
backfill_group = True
|
|
150
|
+
elif type(backfill) == str:
|
|
151
|
+
backfill_list = backfill.replace(" ", "").split(",")
|
|
152
|
+
api_key = get_api_key(api_key, api_key_loc)
|
|
153
|
+
getusgs_measurement_cda(
|
|
154
|
+
api_root=api_root,
|
|
155
|
+
office_id=office,
|
|
156
|
+
api_key=api_key,
|
|
157
|
+
days_back_modified=days_back_modified,
|
|
158
|
+
days_back_collected=days_back_collected,
|
|
159
|
+
backfill_list=backfill_list,
|
|
160
|
+
backfill_group=backfill_group,
|
|
161
|
+
)
|