cwms-python 0.1.0__tar.gz → 0.3.0__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 (46) hide show
  1. cwms_python-0.3.0/LICENSE +21 -0
  2. cwms_python-0.3.0/PKG-INFO +95 -0
  3. cwms_python-0.3.0/README.md +73 -0
  4. cwms_python-0.3.0/cwms/__init__.py +13 -0
  5. cwms_python-0.3.0/cwms/_constants.py +33 -0
  6. cwms_python-0.3.0/cwms/api.py +294 -0
  7. cwms_python-0.3.0/cwms/core.py +26 -0
  8. cwms_python-0.3.0/cwms/exceptions.py +131 -0
  9. cwms_python-0.3.0/cwms/forecast/forecast_instance.py +260 -0
  10. cwms_python-0.3.0/cwms/forecast/forecast_spec.py +227 -0
  11. cwms_python-0.3.0/cwms/levels/location_levels.py +484 -0
  12. cwms_python-0.3.0/cwms/locations/physical_locations.py +47 -0
  13. cwms_python-0.3.0/cwms/timeseries/timeseries.py +208 -0
  14. cwms_python-0.3.0/cwms/timeseries/timeseries_bin.py +219 -0
  15. cwms_python-0.3.0/cwms/timeseries/timeseries_txt.py +373 -0
  16. cwms_python-0.3.0/cwms/types.py +67 -0
  17. cwms_python-0.3.0/cwms/utils.py +85 -0
  18. cwms_python-0.3.0/pyproject.toml +43 -0
  19. cwms-python-0.1.0/.github/workflows/publish-to-test-pypi.yml +0 -117
  20. cwms-python-0.1.0/CWMS/.ipynb_checkpoints/__init__-checkpoint.py +0 -11
  21. cwms-python-0.1.0/CWMS/.ipynb_checkpoints/core-checkpoint.py +0 -0
  22. cwms-python-0.1.0/CWMS/.ipynb_checkpoints/cwms_loc-checkpoint.py +0 -38
  23. cwms-python-0.1.0/CWMS/.ipynb_checkpoints/cwms_ts-checkpoint.py +0 -47
  24. cwms-python-0.1.0/CWMS/.ipynb_checkpoints/utils-checkpoint.py +0 -52
  25. cwms-python-0.1.0/CWMS/__init__.py +0 -11
  26. cwms-python-0.1.0/CWMS/__pycache__/__init__.cpython-39.pyc +0 -0
  27. cwms-python-0.1.0/CWMS/__pycache__/core.cpython-39.pyc +0 -0
  28. cwms-python-0.1.0/CWMS/__pycache__/cwms_loc.cpython-39.pyc +0 -0
  29. cwms-python-0.1.0/CWMS/__pycache__/cwms_ts.cpython-39.pyc +0 -0
  30. cwms-python-0.1.0/CWMS/__pycache__/utils.cpython-39.pyc +0 -0
  31. cwms-python-0.1.0/CWMS/core.py +0 -21
  32. cwms-python-0.1.0/CWMS/cwms_loc.py +0 -58
  33. cwms-python-0.1.0/CWMS/cwms_ts.py +0 -182
  34. cwms-python-0.1.0/CWMS/utils.py +0 -79
  35. cwms-python-0.1.0/LICENSE +0 -24
  36. cwms-python-0.1.0/PKG-INFO +0 -72
  37. cwms-python-0.1.0/README.md +0 -49
  38. cwms-python-0.1.0/cwms_python.egg-info/PKG-INFO +0 -72
  39. cwms-python-0.1.0/cwms_python.egg-info/SOURCES.txt +0 -26
  40. cwms-python-0.1.0/cwms_python.egg-info/dependency_links.txt +0 -1
  41. cwms-python-0.1.0/cwms_python.egg-info/requires.txt +0 -10
  42. cwms-python-0.1.0/cwms_python.egg-info/top_level.txt +0 -1
  43. cwms-python-0.1.0/pyproject.toml +0 -48
  44. cwms-python-0.1.0/setup.cfg +0 -4
  45. cwms-python-0.1.0/setup.py +0 -24
  46. cwms-python-0.1.0/tests/__init__.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Hydrologic Engineering Center
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.1
2
+ Name: cwms-python
3
+ Version: 0.3.0
4
+ Summary: Corps water managerment systems (CWMS) REST API for Data Retrieval of USACE water data
5
+ License: LICENSE
6
+ Keywords: USACE,water data
7
+ Author: Eric Novotny
8
+ Author-email: eric.v.novotny@usace.army.mil
9
+ Requires-Python: >=3.9,<4.0
10
+ Classifier: License :: Other/Proprietary License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Requires-Dist: numpy (>=1.26.4,<2.0.0)
17
+ Requires-Dist: pandas (>=2.1.3,<3.0.0)
18
+ Requires-Dist: requests (>=2.31.0,<3.0.0)
19
+ Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
20
+ Description-Content-Type: text/markdown
21
+
22
+ # CWMSpy
23
+
24
+ CWMS REST API for Data Retrieval
25
+
26
+ ## Requirements.
27
+
28
+ Python 3.9+
29
+
30
+ ## Installation & Usage
31
+
32
+ ### pip install
33
+
34
+ ```sh
35
+ pip install cwms-python
36
+ ```
37
+
38
+ Then import the package:
39
+
40
+ ```python
41
+ import cwms
42
+ ```
43
+
44
+ ## Getting Started
45
+
46
+ ```python
47
+ import cwms
48
+ from datetime import datetime, timedelta
49
+
50
+ end = datetime.now()
51
+ begin = end - timedelta(days = 10)
52
+ data = cwms.get_timeseries(p_tsId='Some.Fully.Qualified.Ts.Id',begin = begin, end = end)
53
+
54
+ #a cwms data object will be provided this object containes both the JSON as well
55
+ #as the values converted into a dataframe
56
+
57
+ #display the dataframe
58
+
59
+ df = data.df
60
+ print(df)
61
+ ```
62
+
63
+ ```
64
+ date-time value quality-code
65
+ 0 2024-04-23 08:15:00 86.57 3
66
+ 1 2024-04-23 08:30:00 86.57 3
67
+ 2 2024-04-23 08:45:00 86.58 3
68
+ 3 2024-04-23 09:00:00 86.58 3
69
+ 4 2024-04-23 09:15:00 86.58 3
70
+ 5 2024-04-23 09:30:00 86.58 3
71
+ 6 2024-04-23 09:45:00 86.59 3
72
+ 7 2024-04-23 10:00:00 86.58 3
73
+ ```
74
+
75
+ ```python
76
+ #display JSON
77
+ json = data.JSON
78
+ print(json)
79
+ ```
80
+
81
+ ```
82
+ {'name': 'Some.Fully.Qualified.Ts.Id',
83
+ 'office-id': 'MVP',
84
+ 'units': 'ft',
85
+ 'values': [['2024-04-23T08:15:00', 86.57, 3],
86
+ ['2024-04-23T08:30:00', 86.57, 3],
87
+ ['2024-04-23T08:45:00', 86.57999999999997, 3],
88
+ ['2024-04-23T09:00:00', 86.57999999999997, 3],
89
+ ['2024-04-23T09:15:00', 86.57999999999997, 3],
90
+ ['2024-04-23T09:30:00', 86.57999999999997, 3],
91
+ ['2024-04-23T09:45:00', 86.59, 3],
92
+ ['2024-04-23T10:00:00', 86.57999999999997, 3]],
93
+ 'version-date': None}
94
+ ```
95
+
@@ -0,0 +1,73 @@
1
+ # CWMSpy
2
+
3
+ CWMS REST API for Data Retrieval
4
+
5
+ ## Requirements.
6
+
7
+ Python 3.9+
8
+
9
+ ## Installation & Usage
10
+
11
+ ### pip install
12
+
13
+ ```sh
14
+ pip install cwms-python
15
+ ```
16
+
17
+ Then import the package:
18
+
19
+ ```python
20
+ import cwms
21
+ ```
22
+
23
+ ## Getting Started
24
+
25
+ ```python
26
+ import cwms
27
+ from datetime import datetime, timedelta
28
+
29
+ end = datetime.now()
30
+ begin = end - timedelta(days = 10)
31
+ data = cwms.get_timeseries(p_tsId='Some.Fully.Qualified.Ts.Id',begin = begin, end = end)
32
+
33
+ #a cwms data object will be provided this object containes both the JSON as well
34
+ #as the values converted into a dataframe
35
+
36
+ #display the dataframe
37
+
38
+ df = data.df
39
+ print(df)
40
+ ```
41
+
42
+ ```
43
+ date-time value quality-code
44
+ 0 2024-04-23 08:15:00 86.57 3
45
+ 1 2024-04-23 08:30:00 86.57 3
46
+ 2 2024-04-23 08:45:00 86.58 3
47
+ 3 2024-04-23 09:00:00 86.58 3
48
+ 4 2024-04-23 09:15:00 86.58 3
49
+ 5 2024-04-23 09:30:00 86.58 3
50
+ 6 2024-04-23 09:45:00 86.59 3
51
+ 7 2024-04-23 10:00:00 86.58 3
52
+ ```
53
+
54
+ ```python
55
+ #display JSON
56
+ json = data.JSON
57
+ print(json)
58
+ ```
59
+
60
+ ```
61
+ {'name': 'Some.Fully.Qualified.Ts.Id',
62
+ 'office-id': 'MVP',
63
+ 'units': 'ft',
64
+ 'values': [['2024-04-23T08:15:00', 86.57, 3],
65
+ ['2024-04-23T08:30:00', 86.57, 3],
66
+ ['2024-04-23T08:45:00', 86.57999999999997, 3],
67
+ ['2024-04-23T09:00:00', 86.57999999999997, 3],
68
+ ['2024-04-23T09:15:00', 86.57999999999997, 3],
69
+ ['2024-04-23T09:30:00', 86.57999999999997, 3],
70
+ ['2024-04-23T09:45:00', 86.59, 3],
71
+ ['2024-04-23T10:00:00', 86.57999999999997, 3]],
72
+ 'version-date': None}
73
+ ```
@@ -0,0 +1,13 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ from .api import *
4
+
5
+ # from .core import CwmsApiSession
6
+ from .levels.location_levels import *
7
+ from .locations.physical_locations import *
8
+ from .timeseries.timeseries import *
9
+
10
+ try:
11
+ __version__ = version("cwms-python")
12
+ except PackageNotFoundError:
13
+ __version__ = "version-unknown"
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2024
2
+ # United States Army Corps of Engineers - Hydrologic Engineering Center (USACE/HEC)
3
+ # All Rights Reserved. USACE PROPRIETARY/CONFIDENTIAL.
4
+ # Source may not be released without written approval from HEC
5
+
6
+
7
+ HEADER_JSON_V1 = "application/json"
8
+ HEADER_JSON_V2 = "application/json;version=2"
9
+
10
+ OFFICE_PARAM = "office"
11
+ TEMPLATE_ID_MASK_PARAM = "template-id-mask"
12
+ FAIL_IF_EXISTS = "fail-if-exists"
13
+ UNIT = "unit"
14
+ DATUM = "datum"
15
+ BEGIN = "begin"
16
+ END = "end"
17
+ PAGE_SIZE = "page-size"
18
+ PAGE = "page"
19
+ NAME = "name"
20
+ TIMEZONE = "timezone"
21
+ EFFECTIVE_DATE = "effective-date"
22
+ CASCADE_DELETE = "cascade-delete"
23
+ BINARY_TYPE_MASK = "binary-type-mask"
24
+ REPLACE_ALL = "replace-all"
25
+ VERSION_DATE = "version-date"
26
+ DESIGNATOR = "designator"
27
+ FORECAST_DATE = "forecast-date"
28
+ ISSUE_DATE = "issue-date"
29
+ ID_MASK = "id_mask"
30
+ DESIGNATOR_MASK = "designator-mask"
31
+ LOCATION_MASK = "location-mask"
32
+ SOURCE_ENTITY = "source-entity"
33
+ METHOD = "method"
@@ -0,0 +1,294 @@
1
+ """ Session management and REST functions for CWMS Data API.
2
+
3
+ This module provides functions for making REST calls to the CWMS Data API (CDA). These
4
+ functions should be used internally to interact with the API. The user should not have to
5
+ interact with these directly.
6
+
7
+ The `init_session()` function can be used to specify an alternative root URL, and to
8
+ provide an authentication key (if required). If `init_session()` is not called, the
9
+ default root URL (see `API_ROOT` below) will be used, and no authentication keys will be
10
+ included when making API calls.
11
+
12
+ Example: Initializing a session
13
+
14
+ # Specify an alternate URL
15
+ init_session(api_root="https://example.com/cwms-data")
16
+
17
+ # Specify an alternate URL and an auth key
18
+ init_session(api_root="https://example.com/cwms-data", api_key="API_KEY")
19
+
20
+ Functions which make API calls that _may_ return a JSON response will return a `dict`
21
+ containing the deserialized data. If the API response does not include data, an empty
22
+ `dict` will be returned.
23
+
24
+ In the event the API returns an error response, the function will raise an `APIError`
25
+ which includes the response object and provides some hints to the user on how to address
26
+ the error.
27
+ """
28
+
29
+ import json
30
+ import logging
31
+ from json import JSONDecodeError
32
+ from typing import Optional, cast
33
+
34
+ from requests import Response
35
+ from requests_toolbelt import sessions # type: ignore
36
+ from requests_toolbelt.sessions import BaseUrlSession # type: ignore
37
+
38
+ from cwms.types import JSON, RequestParams
39
+
40
+ # Specify the default API root URL and version.
41
+ API_ROOT = "https://cwms-data.usace.army.mil/cwms-data/"
42
+ API_VERSION = 2
43
+
44
+ # Initialize a non-authenticated session with the default root URL.
45
+ SESSION = sessions.BaseUrlSession(base_url=API_ROOT)
46
+
47
+
48
+ class InvalidVersion(Exception):
49
+ pass
50
+
51
+
52
+ class ApiError(Exception):
53
+ """CWMS Data Api Error.
54
+
55
+ This class is a light wrapper around a `requests.Response` object. Its primary purpose
56
+ is to generate an error message that includes the request URL and provide additional
57
+ information to the user to help them resolve the error.
58
+ """
59
+
60
+ def __init__(self, response: Response):
61
+ self.response = response
62
+
63
+ def __str__(self) -> str:
64
+ # Include the request URL in the error message.
65
+ message = f"CWMS API Error ({self.response.url})"
66
+
67
+ # If a reason is provided in the response, add it to the message.
68
+ if reason := self.response.reason:
69
+ message += f" {reason}"
70
+
71
+ message += "."
72
+
73
+ # Add additional context to help the user resolve the issue.
74
+ if hint := self.hint():
75
+ message += f" {hint}"
76
+
77
+ if content := self.response.content:
78
+ message += f" {content.decode('utf8')}"
79
+
80
+ return message
81
+
82
+ def hint(self) -> str:
83
+ """Return a message with additional information on how to resolve the error."""
84
+
85
+ if self.response.status_code == 400:
86
+ return "Check that your parameters are correct."
87
+ elif self.response.status_code == 404:
88
+ return "May be the result of an empty query."
89
+ else:
90
+ return ""
91
+
92
+
93
+ def init_session(
94
+ *, api_root: Optional[str] = None, api_key: Optional[str] = None
95
+ ) -> BaseUrlSession:
96
+ """Specify a root URL and authentication key for the CWMS Data API.
97
+
98
+ This function can be used to change the root URL used when interacting with the CDA.
99
+ All API calls made after this function is called will use the specified URL. If an
100
+ authentication key is given it will be included in all future request headers.
101
+
102
+ Keyword Args:
103
+ api_root (optional): The root URL for the CWMS Data API.
104
+ api_key (optional): An authentication key.
105
+
106
+ Returns:
107
+ Returns the updated session object.
108
+ """
109
+
110
+ global SESSION
111
+
112
+ if api_root:
113
+ logging.debug(f"Initializing root URL: api_root={api_root}")
114
+ SESSION = sessions.BaseUrlSession(base_url=api_root)
115
+
116
+ if api_key:
117
+ logging.debug(f"Setting authorization key: api_key={api_key}")
118
+ SESSION.headers.update({"Authorization": api_key})
119
+
120
+ return SESSION
121
+
122
+
123
+ def return_base_url() -> str:
124
+ """returns the base URL for the CDA instance that is connected to.
125
+
126
+ Returns:
127
+ str: base URL
128
+ """
129
+
130
+ return str(SESSION.base_url)
131
+
132
+
133
+ def api_version_text(api_version: int) -> str:
134
+ """Initialize CDA request headers.
135
+
136
+ The CDA supports multiple versions. To request a specific version, the version number
137
+ must be included in the request headers.
138
+
139
+ Args:
140
+ api_version: The CDA version to use for the request.
141
+
142
+ Returns:
143
+ A dict containing the request headers.
144
+
145
+ Raises:
146
+ InvalidVersion: If an unsupported API version is specified.
147
+ """
148
+
149
+ if api_version == 1:
150
+ version = "application/json"
151
+ elif api_version == 2:
152
+ version = "application/json;version=2"
153
+ else:
154
+ raise InvalidVersion(f"API version {api_version} is not supported.")
155
+
156
+ return version
157
+
158
+
159
+ def get(
160
+ endpoint: str,
161
+ params: Optional[RequestParams] = None,
162
+ *,
163
+ api_version: int = API_VERSION,
164
+ ) -> JSON:
165
+ """Make a GET request to the CWMS Data API.
166
+
167
+ Args:
168
+ endpoint: The CDA endpoint for the record(s).
169
+ params (optional): Query parameters for the request.
170
+
171
+ Keyword Args:
172
+ api_version (optional): The CDA version to use for the request. If not specified,
173
+ the default API_VERSION will be used.
174
+
175
+ Returns:
176
+ The deserialized JSON response data.
177
+
178
+ Raises:
179
+ ApiError: If an error response is return by the API.
180
+ """
181
+
182
+ headers = {"Accept": api_version_text(api_version)}
183
+ response = SESSION.get(endpoint, params=params, headers=headers)
184
+
185
+ if response.status_code != 200:
186
+ logging.error(f"CDA Error: response={response}")
187
+ raise ApiError(response)
188
+
189
+ try:
190
+ return cast(JSON, response.json())
191
+ except JSONDecodeError as error:
192
+ logging.error(f"Error decoding CDA response: {error}")
193
+ return {}
194
+
195
+
196
+ def post(
197
+ endpoint: str,
198
+ data: JSON,
199
+ params: Optional[RequestParams] = None,
200
+ *,
201
+ api_version: int = API_VERSION,
202
+ ) -> None:
203
+ """Make a POST request to the CWMS Data API.
204
+
205
+ Args:
206
+ endpoint: The CDA endpoint for the record type.
207
+ data: A dict containing the new record data. Must be JSON-serializable.
208
+ params (optional): Query parameters for the request.
209
+
210
+ Keyword Args:
211
+ api_version (optional): The CDA version to use for the request. If not specified,
212
+ the default API_VERSION will be used.
213
+
214
+ Returns:
215
+ The deserialized JSON response data.
216
+
217
+ Raises:
218
+ ApiError: If an error response is return by the API.
219
+ """
220
+
221
+ # post requires different headers than get for
222
+ headers = {"accept": "*/*", "Content-Type": api_version_text(api_version)}
223
+
224
+ response = SESSION.post(
225
+ endpoint, params=params, headers=headers, data=json.dumps(data)
226
+ )
227
+
228
+ if response.status_code != 200:
229
+ logging.error(f"CDA Error: response={response}")
230
+ raise ApiError(response)
231
+
232
+
233
+ def patch(
234
+ endpoint: str,
235
+ data: JSON,
236
+ params: Optional[RequestParams] = None,
237
+ *,
238
+ api_version: int = API_VERSION,
239
+ ) -> None:
240
+ """Make a PATCH request to the CWMS Data API.
241
+
242
+ Args:
243
+ endpoint: The CDA endpoint for the record.
244
+ data: A dict containing the updated record data. Must be JSON-serializable.
245
+ params (optional): Query parameters for the request.
246
+
247
+ Keyword Args:
248
+ api_version (optional): The CDA version to use for the request. If not specified,
249
+ the default API_VERSION will be used.
250
+
251
+ Returns:
252
+ The deserialized JSON response data.
253
+
254
+ Raises:
255
+ ApiError: If an error response is return by the API.
256
+ """
257
+
258
+ headers = {"accept": "*/*", "Content-Type": api_version_text(api_version)}
259
+
260
+ response = SESSION.patch(
261
+ endpoint, params=params, headers=headers, data=json.dumps(data)
262
+ )
263
+
264
+ if response.status_code != 200:
265
+ logging.error(f"CDA Error: response={response}")
266
+ raise ApiError(response)
267
+
268
+
269
+ def delete(
270
+ endpoint: str,
271
+ params: Optional[RequestParams] = None,
272
+ *,
273
+ api_version: int = API_VERSION,
274
+ ) -> None:
275
+ """Make a DELETE request to the CWMS Data API.
276
+
277
+ Args:
278
+ endpoint: The CDA endpoint for the record.
279
+ params (optional): Query parameters for the request.
280
+
281
+ Keyword Args:
282
+ api_version (optional): The CDA version to use for the request. If not specified,
283
+ the default API_VERSION will be used.
284
+
285
+ Raises:
286
+ ApiError: If an error response is return by the API.
287
+ """
288
+
289
+ headers = {"Accept": api_version_text(api_version)}
290
+ response = SESSION.delete(endpoint, params=params, headers=headers)
291
+
292
+ if response.status_code != 200:
293
+ logging.error(f"CDA Error: response={response}")
294
+ raise ApiError(response)
@@ -0,0 +1,26 @@
1
+ from typing import Optional
2
+
3
+ from requests_toolbelt import sessions # type: ignore
4
+ from requests_toolbelt.sessions import BaseUrlSession # type: ignore
5
+
6
+
7
+ class CwmsApiSession:
8
+ def __init__(self, api_root: str, api_key: Optional[str] = None):
9
+ if api_root is None:
10
+ raise ValueError("CWMS API root URL cannot be None")
11
+ self.__session = sessions.BaseUrlSession(base_url=api_root)
12
+ if api_key is not None:
13
+ self.__session.headers.update({"Authorization": api_key})
14
+
15
+ def get_session(self) -> BaseUrlSession:
16
+ return self.__session
17
+
18
+
19
+ class _CwmsBase:
20
+ def __init__(self, cwms_api_session: CwmsApiSession):
21
+ if cwms_api_session is None:
22
+ raise ValueError("CWMS API session information cannot be None")
23
+ self._cwms_api_session = cwms_api_session
24
+
25
+ def get_session(self) -> BaseUrlSession:
26
+ return self._cwms_api_session.get_session()
@@ -0,0 +1,131 @@
1
+ # Copyright (c) 2024
2
+ # United States Army Corps of Engineers - Hydrologic Engineering Center (USACE/HEC)
3
+ # All Rights Reserved. USACE PROPRIETARY/CONFIDENTIAL.
4
+ # Source may not be released without written approval from HEC
5
+
6
+ from requests.exceptions import HTTPError
7
+ from requests.models import Response
8
+
9
+
10
+ class CwmsDataApiError(HTTPError):
11
+ """
12
+ Class representing an error thrown by the CwmsDataApi.
13
+
14
+ This class inherits from the requests.exceptions HTTPError class.
15
+
16
+ Attributes
17
+ ----------
18
+ incident_identifier : str
19
+ The incident identifier extracted from the response object.
20
+ response : Response
21
+ The response from the server
22
+ request : Request
23
+ The request made to the server
24
+ """
25
+
26
+ def __init__(self, message: str, response: Response):
27
+ """
28
+ Parameters
29
+ ----------
30
+ message : str
31
+ The message to be passed to the parent class constructor.
32
+ response : Response
33
+ The response object containing information about the incident identifier.
34
+
35
+ """
36
+ if response.text:
37
+ self.incident_identifier = response.json().get("incidentIdentifier")
38
+ super().__init__(message, response=response)
39
+
40
+
41
+ class ClientError(CwmsDataApiError):
42
+ """
43
+ ClientError
44
+ Exception class representing the error when an error code in the 400 range is returned for a request.
45
+
46
+ Attributes
47
+ ----------
48
+ incident_identifier : str
49
+ The incident identifier extracted from the response object.
50
+ response : Response
51
+ The response from the server
52
+ request : Request
53
+ The request made to the server
54
+ """
55
+
56
+ def __init__(self, response: Response):
57
+ """
58
+ Parameters
59
+ ----------
60
+ response : Response
61
+ The response object that triggered the error.
62
+ """
63
+ message = (
64
+ f"CWMS Client error occurred for request:\n{response.request.url}\n"
65
+ f"Response was:\n{response.text}"
66
+ )
67
+ super().__init__(message, response=response)
68
+
69
+
70
+ class ServerError(CwmsDataApiError):
71
+ """
72
+ ServerError
73
+ Exception class representing the error when an error code in the 500 range is returned for a request.
74
+
75
+ Attributes
76
+ ----------
77
+ incident_identifier : str
78
+ The incident identifier extracted from the response object.
79
+ response : Response
80
+ The response from the server
81
+ request : Request
82
+ The request made to the server
83
+ """
84
+
85
+ def __init__(self, response: Response):
86
+ """
87
+ Constructs a ServerError instance.
88
+
89
+ Parameters
90
+ ----------
91
+ response : Response
92
+ The response object from the CWMS server.
93
+
94
+ """
95
+ message = (
96
+ f"CWMS Server error occurred for request:\n{response.request.url}\n"
97
+ f"Response was:\n{response.text}"
98
+ )
99
+ super().__init__(message, response=response)
100
+
101
+
102
+ class NoDataFoundError(CwmsDataApiError):
103
+ """
104
+ NoDataFoundError
105
+ Exception class representing the error when no data is found for a request and an error code 404 is returned.
106
+
107
+ Attributes
108
+ ----------
109
+ incident_identifier : str
110
+ The incident identifier extracted from the response object.
111
+ response : Response
112
+ The response from the server
113
+ request : Request
114
+ The request made to the server
115
+ """
116
+
117
+ def __init__(self, response: Response):
118
+ """
119
+ Constructs a NoDataFoundError instance.
120
+
121
+ Parameters
122
+ ----------
123
+ response : Response
124
+ The response object from the CWMS server.
125
+
126
+ """
127
+ message = (
128
+ f"No data found for request:\n{response.request.url}\n"
129
+ f"Response was:\n{response.text}"
130
+ )
131
+ super().__init__(message, response=response)