cwms-cli 0.7.0__tar.gz → 0.7.1__tar.gz

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.
Files changed (76) hide show
  1. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/PKG-INFO +1 -1
  2. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/blob.py +20 -9
  3. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/clob.py +13 -10
  4. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/__init__.py +61 -0
  5. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/pyproject.toml +1 -1
  6. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/LICENSE +0 -0
  7. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/README.md +0 -0
  8. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/__init__.py +0 -0
  9. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/__main__.py +0 -0
  10. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/_generated/__init__.py +0 -0
  11. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/_generated/ownership_data.py +0 -0
  12. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/callbacks/__init__.py +0 -0
  13. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/commands_cwms.py +0 -0
  14. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/.gitignore +0 -0
  15. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/README.md +0 -0
  16. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/__init__.py +0 -0
  17. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/__main__.py +0 -0
  18. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/config.py +0 -0
  19. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/doclinks.py +0 -0
  20. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/examples/complete_config.json +0 -0
  21. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/parser.py +0 -0
  22. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/__init__.py +0 -0
  23. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/data/.gitignore +0 -0
  24. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/data/expected_brok_output.json +0 -0
  25. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/data/sample_brok.csv +0 -0
  26. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/data/sample_config.json +0 -0
  27. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/skip_test_integration_pipeline.py +0 -0
  28. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/test_dateutils.py +0 -0
  29. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/test_expressions.py +0 -0
  30. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/test_fileio.py +0 -0
  31. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/tests/test_main.py +0 -0
  32. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/transform.py +0 -0
  33. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/utils/__init__.py +0 -0
  34. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/utils/dateutils.py +0 -0
  35. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/utils/expression.py +0 -0
  36. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/utils/fileio.py +0 -0
  37. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/utils/logging.py +0 -0
  38. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/csv2cwms/writer.py +0 -0
  39. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/shef/__init__.py +0 -0
  40. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/shef/import_critfile.py +0 -0
  41. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/shef/import_infile.py +0 -0
  42. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/shef/shef_parameters.csv +0 -0
  43. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/commands/users.py +0 -0
  44. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/README.md +0 -0
  45. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/__init__.py +0 -0
  46. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/__main__.py +0 -0
  47. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/location/location.py +0 -0
  48. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/location/location_ids.py +0 -0
  49. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/location/location_ids_bygroup.py +0 -0
  50. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/root.py +0 -0
  51. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/timeseries/timeseries.py +0 -0
  52. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/timeseries/timeseries_data.py +0 -0
  53. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/load/timeseries/timeseries_ids.py +0 -0
  54. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/ownership.py +0 -0
  55. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/requirements.py +0 -0
  56. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/__init__.py +0 -0
  57. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/__main__.py +0 -0
  58. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/getUSGS_ratings_cda.py +0 -0
  59. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/getusgs_cda.py +0 -0
  60. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/getusgs_measurements_cda.py +0 -0
  61. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/usgs/rating_ini_file_import.py +0 -0
  62. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/auth.py +0 -0
  63. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/callback_success.html +0 -0
  64. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/click_help.py +0 -0
  65. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/colors.py +0 -0
  66. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/deps.py +0 -0
  67. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/friendly_errors.py +0 -0
  68. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/intervals.py +0 -0
  69. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/io.py +0 -0
  70. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/links.py +0 -0
  71. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/logging/__init__.py +0 -0
  72. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/logging/formatters.py +0 -0
  73. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/ssl_errors.py +0 -0
  74. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/update.py +0 -0
  75. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/version.py +0 -0
  76. {cwms_cli-0.7.0 → cwms_cli-0.7.1}/cwmscli/utils/version_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cwms-cli
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Command line utilities for Corps Water Management Systems (CWMS) python scripts. This is a collection of shared scripts across the enterprise Water Management Enterprise System (WMES) teams.
5
5
  License: LICENSE
6
6
  License-File: LICENSE
@@ -11,10 +11,12 @@ from typing import Optional, Sequence, Tuple, Union
11
11
 
12
12
  from cwmscli.utils import (
13
13
  colors,
14
+ format_local_download_error,
14
15
  get_api_key,
15
16
  has_invalid_chars,
16
17
  init_cwms_session,
17
18
  log_scoped_read_hint,
19
+ validate_default_download_dest,
18
20
  )
19
21
  from cwmscli.utils.click_help import DOCS_BASE_URL
20
22
  from cwmscli.utils.deps import requires
@@ -109,6 +111,14 @@ def _save_blob_content(
109
111
  return dest
110
112
 
111
113
 
114
+ def _default_download_dest(blob_id: str) -> str:
115
+ return validate_default_download_dest(
116
+ blob_id,
117
+ resource_name="Blob",
118
+ docs_url=BLOB_DOCS_URL,
119
+ )
120
+
121
+
112
122
  def _blob_media_type(cwms_module, office: str, blob_id: str) -> Optional[str]:
113
123
  try:
114
124
  result = cwms_module.get_blobs(office_id=office, blob_id_like=blob_id)
@@ -602,7 +612,7 @@ def download_cmd(
602
612
 
603
613
  try:
604
614
  blob_content = cwms.get_blob(office_id=office, blob_id=bid)
605
- target = dest or bid
615
+ target = dest or _default_download_dest(bid)
606
616
  _save_blob_content(
607
617
  blob_content,
608
618
  dest=target,
@@ -621,14 +631,15 @@ def download_cmd(
621
631
  )
622
632
  sys.exit(1)
623
633
  except Exception as e:
624
- logging.error(f"Failed to download: {e}")
625
- log_scoped_read_hint(
626
- credential_kind=credential_kind,
627
- anonymous=anonymous,
628
- office=office,
629
- action="download",
630
- resource="blob content",
631
- )
634
+ logging.error(format_local_download_error(e, BLOB_DOCS_URL))
635
+ if not isinstance(e, (OSError, ValueError)):
636
+ log_scoped_read_hint(
637
+ credential_kind=credential_kind,
638
+ anonymous=anonymous,
639
+ office=office,
640
+ action="download",
641
+ resource="blob content",
642
+ )
632
643
  sys.exit(1)
633
644
 
634
645
 
@@ -9,7 +9,13 @@ import pandas as pd
9
9
  import requests
10
10
  from cwms import api as cwms_api
11
11
 
12
- from cwmscli.utils import get_api_key, has_invalid_chars, log_scoped_read_hint
12
+ from cwmscli.utils import (
13
+ format_local_download_error,
14
+ get_api_key,
15
+ has_invalid_chars,
16
+ log_scoped_read_hint,
17
+ validate_default_download_dest,
18
+ )
13
19
 
14
20
 
15
21
  def _join_api_url(api_root: str, path: str) -> str:
@@ -29,6 +35,10 @@ def _write_clob_content(content: str, dest: str) -> str:
29
35
  return dest
30
36
 
31
37
 
38
+ def _default_download_dest(clob_id: str) -> str:
39
+ return validate_default_download_dest(clob_id, resource_name="Clob")
40
+
41
+
32
42
  def _clob_endpoint_id(clob_id: str) -> tuple[str, Optional[str]]:
33
43
  normalized = clob_id.upper()
34
44
  if has_invalid_chars(normalized):
@@ -198,7 +208,7 @@ def download_cmd(
198
208
  content = str(payload)
199
209
  else:
200
210
  content = _get_special_clob_text(office=office, clob_id=query_id)
201
- target = dest or bid
211
+ target = dest or _default_download_dest(bid)
202
212
  _write_clob_content(content, target)
203
213
  logging.info(f"Downloaded clob to: {target}")
204
214
  except requests.HTTPError as e:
@@ -213,14 +223,7 @@ def download_cmd(
213
223
  )
214
224
  sys.exit(1)
215
225
  except Exception as e:
216
- logging.error(f"Failed to download: {e}")
217
- log_scoped_read_hint(
218
- api_key=resolved_api_key,
219
- anonymous=anonymous,
220
- office=office,
221
- action="download",
222
- resource="clob content",
223
- )
226
+ logging.error(format_local_download_error(e, ""))
224
227
  sys.exit(1)
225
228
 
226
229
 
@@ -1,4 +1,5 @@
1
1
  import logging as py_logging
2
+ import re
2
3
  import time
3
4
  from pathlib import Path
4
5
  from typing import Optional, Union
@@ -235,6 +236,66 @@ def log_scoped_read_hint(
235
236
  )
236
237
 
237
238
 
239
+ def format_local_download_error(error: Exception, docs_url: str) -> str:
240
+ if isinstance(error, (OSError, ValueError)):
241
+ message = (
242
+ f"{colors.c('Failed to download:', 'red', bright=True)} {error}. "
243
+ f"If this is a local destination/path issue, pass "
244
+ f"{colors.c('--dest', 'cyan', bright=True)} explicitly."
245
+ )
246
+ if docs_url:
247
+ message = (
248
+ f"{message} {colors.c('Docs:', 'blue', bright=True)} "
249
+ f"{colors.c(docs_url, 'blue', bright=True)}"
250
+ )
251
+ return message
252
+ return f"{colors.c('Failed to download:', 'red', bright=True)} {error}"
253
+
254
+
255
+ def validate_default_download_dest(
256
+ raw_id: str,
257
+ *,
258
+ resource_name: str,
259
+ docs_url: str = "",
260
+ ) -> str:
261
+ if raw_id is None:
262
+ raise ValueError(
263
+ f"{resource_name} ID must include a non-root destination name. "
264
+ f"Pass --dest explicitly if needed."
265
+ )
266
+
267
+ if raw_id.startswith("//") or raw_id.startswith("\\\\"):
268
+ raise ValueError(
269
+ f"{resource_name} ID must resolve to a relative local path. "
270
+ f"Pass --dest explicitly if needed."
271
+ )
272
+
273
+ target = raw_id.lstrip("/\\")
274
+ if not target:
275
+ message = (
276
+ f"{resource_name} ID must include a non-root destination name. "
277
+ f"Pass --dest explicitly if needed."
278
+ )
279
+ if docs_url:
280
+ message = f"{message} Docs: {docs_url}"
281
+ raise ValueError(message)
282
+
283
+ if re.match(r"^[A-Za-z]:", target):
284
+ raise ValueError(
285
+ f"{resource_name} ID must resolve to a relative local path. "
286
+ f"Pass --dest explicitly if needed."
287
+ )
288
+
289
+ parts = re.split(r"[\\/]", target)
290
+ if any(part in {"", ".", ".."} for part in parts):
291
+ raise ValueError(
292
+ f"{resource_name} ID must resolve to a relative local path. "
293
+ f"Pass --dest explicitly if needed."
294
+ )
295
+
296
+ return target
297
+
298
+
238
299
  def common_api_options(f):
239
300
  f = log_level_option(f)
240
301
  f = office_option(f)
@@ -2,7 +2,7 @@
2
2
  name = "cwms-cli"
3
3
  repository = "https://github.com/HydrologicEngineeringCenter/cwms-cli"
4
4
 
5
- version = "0.7.0"
5
+ version = "0.7.1"
6
6
 
7
7
 
8
8
  packages = [
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes