cwms-python 1.0.0__tar.gz → 1.0.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 (39) hide show
  1. {cwms_python-1.0.0 → cwms_python-1.0.1}/PKG-INFO +1 -1
  2. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/api.py +32 -11
  3. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries.py +2 -2
  4. {cwms_python-1.0.0 → cwms_python-1.0.1}/pyproject.toml +1 -1
  5. {cwms_python-1.0.0 → cwms_python-1.0.1}/LICENSE +0 -0
  6. {cwms_python-1.0.0 → cwms_python-1.0.1}/README.md +0 -0
  7. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/__init__.py +0 -0
  8. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/catalog/blobs.py +0 -0
  9. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/catalog/catalog.py +0 -0
  10. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/catalog/clobs.py +0 -0
  11. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/cwms_types.py +0 -0
  12. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/forecast/forecast_instance.py +0 -0
  13. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/forecast/forecast_spec.py +0 -0
  14. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/levels/location_levels.py +0 -0
  15. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/levels/specified_levels.py +0 -0
  16. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/locations/gate_changes.py +0 -0
  17. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/locations/location_groups.py +0 -0
  18. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/locations/physical_locations.py +0 -0
  19. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/measurements/measurements.py +0 -0
  20. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/outlets/outlets.py +0 -0
  21. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/outlets/virtual_outlets.py +0 -0
  22. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/projects/project_lock_rights.py +0 -0
  23. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/projects/project_locks.py +0 -0
  24. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/projects/projects.py +0 -0
  25. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/projects/water_supply/accounting.py +0 -0
  26. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/ratings/ratings.py +0 -0
  27. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/ratings/ratings_spec.py +0 -0
  28. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/ratings/ratings_template.py +0 -0
  29. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/standard_text/standard_text.py +0 -0
  30. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_bin.py +0 -0
  31. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_group.py +0 -0
  32. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_identifier.py +0 -0
  33. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_profile.py +0 -0
  34. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_profile_instance.py +0 -0
  35. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_profile_parser.py +0 -0
  36. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/timeseries/timeseries_txt.py +0 -0
  37. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/turbines/turbines.py +0 -0
  38. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/utils/__init__.py +0 -0
  39. {cwms_python-1.0.0 → cwms_python-1.0.1}/cwms/utils/checks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cwms-python
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: Corps water management systems (CWMS) REST API for Data Retrieval of USACE water data
5
5
  License: LICENSE
6
6
  License-File: LICENSE
@@ -29,6 +29,7 @@ the error.
29
29
  import base64
30
30
  import json
31
31
  import logging
32
+ from http import HTTPStatus
32
33
  from json import JSONDecodeError
33
34
  from typing import Any, Optional, cast
34
35
 
@@ -72,9 +73,9 @@ class InvalidVersion(Exception):
72
73
  class ApiError(Exception):
73
74
  """CWMS Data Api Error.
74
75
 
75
- This class is a light wrapper around a `requests.Response` object. Its primary purpose
76
- is to generate an error message that includes the request URL and provide additional
77
- information to the user to help them resolve the error.
76
+ Light wrapper around a response-like object (e.g., requests.Response or a
77
+ test stub with url, status_code, reason, and content attributes). Produces
78
+ a concise, single-line error message with an optional hint.
78
79
  """
79
80
 
80
81
  def __init__(self, response: Response):
@@ -91,23 +92,37 @@ class ApiError(Exception):
91
92
  message += "."
92
93
 
93
94
  # Add additional context to help the user resolve the issue.
94
- if hint := self.hint():
95
+ hint = self.hint()
96
+ if hint:
95
97
  message += f" {hint}"
96
98
 
97
- if content := self.response.content:
98
- message += f" {content.decode('utf8')}"
99
+ # Optional content (decoded if bytes)
100
+ content = getattr(self.response, "content", None)
101
+ if content:
102
+ if isinstance(content, bytes):
103
+ try:
104
+ text = content.decode("utf-8", errors="replace")
105
+ except Exception:
106
+ text = repr(content)
107
+ else:
108
+ text = str(content)
109
+ message += f" {text}"
99
110
 
100
111
  return message
101
112
 
102
113
  def hint(self) -> str:
103
- """Return a message with additional information on how to resolve the error."""
114
+ """Return a short hint based on HTTP status code."""
115
+ status = getattr(self.response, "status_code", None)
104
116
 
105
- if self.response.status_code == 400:
117
+ if status == 429:
118
+ return "Too many requests made."
119
+ if status == 400:
106
120
  return "Check that your parameters are correct."
107
- elif self.response.status_code == 404:
121
+ if status == 404:
108
122
  return "May be the result of an empty query."
109
- else:
110
- return ""
123
+
124
+ # No hint for other codes
125
+ return ""
111
126
 
112
127
 
113
128
  def init_session(
@@ -227,6 +242,12 @@ def _process_response(response: Response) -> Any:
227
242
  return response.text
228
243
  if content_type.startswith("image/"):
229
244
  return base64.b64encode(response.content).decode("utf-8")
245
+ # Handle excel content types
246
+ if content_type in [
247
+ "application/vnd.ms-excel",
248
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
249
+ ]:
250
+ return response.content
230
251
  # Fallback for remaining content types
231
252
  return response.content.decode("utf-8")
232
253
  except JSONDecodeError as error:
@@ -606,8 +606,8 @@ def store_timeseries(
606
606
  for chunk in chunks:
607
607
  future = executor.submit(
608
608
  api.post, # The function to execute
609
- endpoint, # The chunk of data to store
610
- data,
609
+ endpoint,
610
+ chunk, # The chunk of data to store
611
611
  params,
612
612
  )
613
613
  futures.append(future) # Add the future to the list
@@ -2,7 +2,7 @@
2
2
  name = "cwms-python"
3
3
  repository = "https://github.com/HydrologicEngineeringCenter/cwms-python"
4
4
 
5
- version = "1.0.0"
5
+ version = "1.0.1"
6
6
 
7
7
 
8
8
  packages = [
File without changes
File without changes