cwms-cli 0.7.2__tar.gz → 0.7.4__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.2 → cwms_cli-0.7.4}/PKG-INFO +3 -2
  2. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/commands_cwms.py +13 -9
  3. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/shef/import_infile.py +61 -3
  4. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/users.py +1 -1
  5. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/timeseries/timeseries_ids.py +1 -0
  6. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/pyproject.toml +13 -4
  7. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/LICENSE +0 -0
  8. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/README.md +0 -0
  9. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/__init__.py +0 -0
  10. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/__main__.py +0 -0
  11. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/_generated/__init__.py +0 -0
  12. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/_generated/ownership_data.py +0 -0
  13. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/callbacks/__init__.py +0 -0
  14. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/blob.py +0 -0
  15. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/clob.py +0 -0
  16. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/.gitignore +0 -0
  17. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/README.md +0 -0
  18. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/__init__.py +0 -0
  19. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/__main__.py +0 -0
  20. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/config.py +0 -0
  21. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/doclinks.py +0 -0
  22. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/examples/complete_config.json +0 -0
  23. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/parser.py +0 -0
  24. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/__init__.py +0 -0
  25. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/data/.gitignore +0 -0
  26. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/data/expected_brok_output.json +0 -0
  27. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/data/sample_brok.csv +0 -0
  28. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/data/sample_config.json +0 -0
  29. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/skip_test_integration_pipeline.py +0 -0
  30. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/test_dateutils.py +0 -0
  31. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/test_expressions.py +0 -0
  32. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/test_fileio.py +0 -0
  33. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/tests/test_main.py +0 -0
  34. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/transform.py +0 -0
  35. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/utils/__init__.py +0 -0
  36. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/utils/dateutils.py +0 -0
  37. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/utils/expression.py +0 -0
  38. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/utils/fileio.py +0 -0
  39. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/utils/logging.py +0 -0
  40. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/csv2cwms/writer.py +0 -0
  41. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/shef/__init__.py +0 -0
  42. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/shef/import_critfile.py +0 -0
  43. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/commands/shef/shef_parameters.csv +0 -0
  44. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/README.md +0 -0
  45. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/__init__.py +0 -0
  46. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/__main__.py +0 -0
  47. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/location/location.py +0 -0
  48. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/location/location_ids.py +0 -0
  49. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/location/location_ids_bygroup.py +0 -0
  50. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/root.py +0 -0
  51. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/timeseries/timeseries.py +0 -0
  52. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/load/timeseries/timeseries_data.py +0 -0
  53. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/ownership.py +0 -0
  54. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/requirements.py +0 -0
  55. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/__init__.py +0 -0
  56. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/__main__.py +0 -0
  57. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/getUSGS_ratings_cda.py +0 -0
  58. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/getusgs_cda.py +0 -0
  59. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/getusgs_measurements_cda.py +0 -0
  60. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/usgs/rating_ini_file_import.py +0 -0
  61. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/__init__.py +0 -0
  62. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/auth.py +0 -0
  63. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/callback_success.html +0 -0
  64. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/click_help.py +0 -0
  65. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/colors.py +0 -0
  66. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/deps.py +0 -0
  67. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/friendly_errors.py +0 -0
  68. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/intervals.py +0 -0
  69. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/io.py +0 -0
  70. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/links.py +0 -0
  71. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/logging/__init__.py +0 -0
  72. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/logging/formatters.py +0 -0
  73. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/ssl_errors.py +0 -0
  74. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/update.py +0 -0
  75. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/cwmscli/utils/version.py +0 -0
  76. {cwms_cli-0.7.2 → cwms_cli-0.7.4}/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.2
3
+ Version: 0.7.4
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
@@ -18,7 +18,8 @@ Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Programming Language :: Python :: 3.14
19
19
  Requires-Dist: click (>=8.1.8,<9.0.0)
20
20
  Requires-Dist: colorama (>=0.4.6,<0.5.0)
21
- Requires-Dist: requests (>=2.30.0,<3.0.0)
21
+ Requires-Dist: requests (>=2.32.0,<3.0.0) ; python_version == "3.9"
22
+ Requires-Dist: requests (>=2.33.0,<3.0.0) ; python_version >= "3.10"
22
23
  Project-URL: Repository, https://github.com/HydrologicEngineeringCenter/cwms-cli
23
24
  Description-Content-Type: text/markdown
24
25
 
@@ -283,7 +283,15 @@ def shef_import_crit(filename, office, api_root, api_key, api_key_loc, dry_run):
283
283
  # ================================================================================
284
284
  @shef_group.command(
285
285
  "import_infile",
286
- help="Import SHEF .in file into timeseries group for SHEF file processing",
286
+ help=(
287
+ "Import a legacy exportShef .in configuration file into a CWMS "
288
+ "timeseries group (default category 'SHEF Export'). Each entry "
289
+ "becomes a group member whose alias-id encodes the SHEF location, "
290
+ "PE code, send code, duration, and (optionally) units. "
291
+ "If the bulk save fails, each TSID is validated via "
292
+ "get_timeseries_identifier; missing TSIDs are logged and skipped, "
293
+ "and the save is retried with the surviving entries."
294
+ ),
287
295
  )
288
296
  @click.option(
289
297
  "-f",
@@ -484,15 +492,13 @@ def update_cli_cmd(target_version: Optional[str], pre: bool, yes: bool) -> None:
484
492
  @click.group(
485
493
  "blob",
486
494
  help="Manage CWMS Blobs (upload, download, delete, update, list)",
487
- epilog=textwrap.dedent(
488
- """
495
+ epilog=textwrap.dedent("""
489
496
  Example Usage:\n
490
497
  - Store a PDF/image as a CWMS blob with optional description\n
491
498
  - Download a blob by id to your local filesystem\n
492
499
  - Update a blob's name/description/mime-type\n
493
500
  - Bulk list blobs for an office
494
- """
495
- ),
501
+ """),
496
502
  )
497
503
  def blob_group():
498
504
  pass
@@ -700,14 +706,12 @@ def list_cmd(**kwargs):
700
706
  @click.group(
701
707
  "clob",
702
708
  help="Manage CWMS Clobs (upload, download, delete, update, list)",
703
- epilog=textwrap.dedent(
704
- """
709
+ epilog=textwrap.dedent("""
705
710
  Example Usage:\n
706
711
  - Download a clob by id to your local filesystem\n
707
712
  - Update a clob's name/description/mime-type\n
708
713
  - Bulk list clobs for an office
709
- """
710
- ),
714
+ """),
711
715
  )
712
716
  @requires(reqs.cwms)
713
717
  def clob_group():
@@ -588,13 +588,32 @@ def build_group_json(
588
588
  # ---------------------------------------------------------------------------
589
589
 
590
590
 
591
- def store_group(
591
+ def _filter_existing_tsids(
592
+ entries: list[dict],
593
+ office_id: str,
594
+ ) -> list[dict]:
595
+ """Probe each TSID via cwms.get_timeseries_identifier and drop missing ones."""
596
+ valid: list[dict] = []
597
+ for e in entries:
598
+ try:
599
+ cwms.get_timeseries_identifier(ts_id=e["tsid"], office_id=office_id)
600
+ valid.append(e)
601
+ except Exception as exc:
602
+ log.warning(
603
+ "Skipping missing TSID '%s' (%s)",
604
+ e["tsid"],
605
+ type(exc).__name__,
606
+ )
607
+ return valid
608
+
609
+
610
+ def _save(
592
611
  group_json: dict,
593
612
  group_id: str,
594
613
  office_id: str,
595
614
  fail_if_exists: bool,
596
615
  ) -> None:
597
- """POST (create) or PATCH (update) the timeseries group in CWMS."""
616
+ """Single store/update attempt with no validation fallback."""
598
617
  try:
599
618
  cwms.store_timeseries_groups(group_json, fail_if_exists=fail_if_exists)
600
619
  log.info("SUCCESS — group stored via store_timeseries_groups.")
@@ -606,7 +625,6 @@ def store_group(
606
625
  exc,
607
626
  )
608
627
 
609
- # Fallback: update, replacing all assigned timeseries
610
628
  cwms.update_timeseries_groups(
611
629
  data=group_json,
612
630
  group_id=group_id,
@@ -616,6 +634,44 @@ def store_group(
616
634
  log.info("SUCCESS — group updated via update_timeseries_groups.")
617
635
 
618
636
 
637
+ def store_group(
638
+ group_json: dict,
639
+ group_id: str,
640
+ office_id: str,
641
+ fail_if_exists: bool,
642
+ entries: Optional[list[dict]] = None,
643
+ category_id: str = DEFAULT_CATEGORY,
644
+ ) -> None:
645
+ """POST (create) or PATCH (update) the timeseries group in CWMS.
646
+
647
+ On failure, validate each TSID individually, drop any that don't exist in
648
+ CWMS, and retry the save with the surviving entries.
649
+ """
650
+ try:
651
+ _save(group_json, group_id, office_id, fail_if_exists)
652
+ return
653
+ except Exception as exc:
654
+ if entries is None:
655
+ raise
656
+ log.warning(
657
+ "Group save failed (%s: %s) — validating each TSID and retrying ...",
658
+ type(exc).__name__,
659
+ exc,
660
+ )
661
+
662
+ valid = _filter_existing_tsids(entries, office_id)
663
+ if not valid:
664
+ log.error("No valid TSIDs remain after validation — nothing to store.")
665
+ return
666
+ if len(valid) == len(entries):
667
+ log.error("All TSIDs validated but save still failed; re-raising.")
668
+ raise
669
+
670
+ log.info("Retrying save with %d/%d valid TSIDs.", len(valid), len(entries))
671
+ retry_json = build_group_json(valid, group_id, office_id, category_id)
672
+ _save(retry_json, group_id, office_id, fail_if_exists=False)
673
+
674
+
619
675
  # ---------------------------------------------------------------------------
620
676
  # Importable function for CLI integration
621
677
  # ---------------------------------------------------------------------------
@@ -713,6 +769,8 @@ def import_shef_infile(
713
769
  group_id=group_name,
714
770
  office_id=office_id,
715
771
  fail_if_exists=fail_if_exists,
772
+ entries=entries,
773
+ category_id=category_id,
716
774
  )
717
775
 
718
776
  log.info(
@@ -126,7 +126,7 @@ def _existing_user_name(users: list[dict], user_name: str) -> Optional[str]:
126
126
 
127
127
 
128
128
  def _split_roles(
129
- raw_roles: Optional[Union[tuple[str, ...], list[str]]] = None
129
+ raw_roles: Optional[Union[tuple[str, ...], list[str]]] = None,
130
130
  ) -> list[str]:
131
131
  if not raw_roles:
132
132
  return []
@@ -1,4 +1,5 @@
1
1
  # cwmscli/load/timeseries_ids.py
2
+ import logging
2
3
  from typing import Optional
3
4
 
4
5
  import click
@@ -2,7 +2,7 @@
2
2
  name = "cwms-cli"
3
3
  repository = "https://github.com/HydrologicEngineeringCenter/cwms-cli"
4
4
 
5
- version = "0.7.2"
5
+ version = "0.7.4"
6
6
 
7
7
 
8
8
  packages = [
@@ -20,17 +20,26 @@ authors = ["Eric Novotny <eric.v.novotny@usace.army.mil>", "Charles Graham <char
20
20
  [tool.poetry.dependencies]
21
21
  python = "^3.9"
22
22
  click = "^8.1.8"
23
- requests = "^2.30.0"
23
+ requests = [
24
+ { version = "^2.33.0", python = ">=3.10" },
25
+ { version = "^2.32.0", python = ">=3.9,<3.10" },
26
+ ]
24
27
  hecdss = { version = ">=0.1.24", optional = true } # Via https://github.com/HydrologicEngineeringCenter/hec-python-library/blob/main/hec/shared.py#L9-10
25
28
  cwms-python = { version = ">=1.0.7", optional = true}
26
29
  colorama = "^0.4.6"
27
30
 
28
31
  [tool.poetry.group.dev.dependencies]
29
- black = "^24.2.0"
32
+ black = [
33
+ { version = "^26.3.1", python = ">=3.10" },
34
+ { version = "^24.2.0", python = ">=3.9,<3.10" },
35
+ ]
30
36
  isort = "^5.13.2"
31
37
  mypy = "^1.9.0"
32
38
  pre-commit = "^3.6.2"
33
- pytest = "^8.3.5"
39
+ pytest = [
40
+ { version = "^9.0.3", python = ">=3.10" },
41
+ { version = "^8.3.5", python = ">=3.9,<3.10" },
42
+ ]
34
43
  #pytest-cov = "^4.1.0"
35
44
  #pandas-stubs = "^2.2.1.240316"
36
45
  yamlfix = "^1.16.0"
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