cwms-python 1.0.9__tar.gz → 1.1.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.
- {cwms_python-1.0.9 → cwms_python-1.1.0}/PKG-INFO +4 -1
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/__init__.py +3 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/locations/gate_changes.py +3 -3
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/locations/lookups.py +10 -6
- cwms_python-1.1.0/cwms/locks/locks.py +198 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/outlets/outlets.py +1 -1
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/projects/projects.py +4 -4
- cwms_python-1.1.0/cwms/projects/water_supply/water_contracts.py +234 -0
- cwms_python-1.1.0/cwms/projects/water_supply/water_users.py +198 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/pyproject.toml +10 -1
- {cwms_python-1.0.9 → cwms_python-1.1.0}/LICENSE +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/README.md +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/api.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/catalog/blobs.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/catalog/catalog.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/catalog/clobs.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/cwms_types.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/forecast/forecast_instance.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/forecast/forecast_spec.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/levels/location_levels.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/levels/specified_levels.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/locations/location_groups.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/locations/physical_locations.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/measurements/measurements.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/outlets/virtual_outlets.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/projects/project_lock_rights.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/projects/project_locks.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/projects/water_supply/accounting.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/properties/properties.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/ratings/ratings.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/ratings/ratings_spec.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/ratings/ratings_template.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/standard_text/standard_text.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_bin.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_group.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_identifier.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_profile.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_profile_instance.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_profile_parser.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/timeseries/timeseries_txt.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/turbines/turbines.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/users/users.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/cwms/utils/__init__.py +0 -0
- {cwms_python-1.0.9 → cwms_python-1.1.0}/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
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
20
|
Requires-Dist: numpy (>=1.23.5,<3) ; python_version >= "3.9" and python_version < "3.13"
|
|
20
21
|
Requires-Dist: numpy (>=2.1.0,<3) ; python_version == "3.13"
|
|
21
22
|
Requires-Dist: numpy (>=2.3.3,<3) ; python_version >= "3.14"
|
|
@@ -23,6 +24,8 @@ Requires-Dist: pandas (>=2.3.3,<3.0.0)
|
|
|
23
24
|
Requires-Dist: requests (>=2.32.4,<3.0.0) ; python_version == "3.9"
|
|
24
25
|
Requires-Dist: requests (>=2.33.0,<3.0.0) ; python_version >= "3.10"
|
|
25
26
|
Requires-Dist: requests-toolbelt (>=1.0.0,<2.0.0)
|
|
27
|
+
Requires-Dist: urllib3 (>=2.6.3,<2.7) ; python_version == "3.9"
|
|
28
|
+
Requires-Dist: urllib3 (>=2.7.0,<3.0.0) ; python_version >= "3.10"
|
|
26
29
|
Project-URL: Repository, https://github.com/HydrologicEngineeringCenter/cwms-python
|
|
27
30
|
Description-Content-Type: text/markdown
|
|
28
31
|
|
|
@@ -12,6 +12,7 @@ from cwms.locations.gate_changes import *
|
|
|
12
12
|
from cwms.locations.location_groups import *
|
|
13
13
|
from cwms.locations.lookups import *
|
|
14
14
|
from cwms.locations.physical_locations import *
|
|
15
|
+
from cwms.locks.locks import *
|
|
15
16
|
from cwms.measurements.measurements import *
|
|
16
17
|
from cwms.outlets.outlets import *
|
|
17
18
|
from cwms.outlets.virtual_outlets import *
|
|
@@ -19,6 +20,8 @@ from cwms.projects.project_lock_rights import *
|
|
|
19
20
|
from cwms.projects.project_locks import *
|
|
20
21
|
from cwms.projects.projects import *
|
|
21
22
|
from cwms.projects.water_supply.accounting import *
|
|
23
|
+
from cwms.projects.water_supply.water_contracts import *
|
|
24
|
+
from cwms.projects.water_supply.water_users import *
|
|
22
25
|
from cwms.properties.properties import *
|
|
23
26
|
from cwms.ratings.ratings import *
|
|
24
27
|
from cwms.ratings.ratings_spec import *
|
|
@@ -62,7 +62,7 @@ def get_all_gate_changes(
|
|
|
62
62
|
"unit-system": unit_system,
|
|
63
63
|
"page-size": page_size,
|
|
64
64
|
}
|
|
65
|
-
response = api.get(endpoint, params=params)
|
|
65
|
+
response = api.get(endpoint, params=params, api_version=1)
|
|
66
66
|
return Data(response)
|
|
67
67
|
|
|
68
68
|
|
|
@@ -144,7 +144,7 @@ def store_gate_change(
|
|
|
144
144
|
params = {
|
|
145
145
|
"fail-if-exists": fail_if_exists,
|
|
146
146
|
}
|
|
147
|
-
return api.post(endpoint, data=gate_change_data, params=params)
|
|
147
|
+
return api.post(endpoint, data=gate_change_data, params=params, api_version=1)
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
def delete_gate_change(
|
|
@@ -182,4 +182,4 @@ def delete_gate_change(
|
|
|
182
182
|
"override-protection": override_protection,
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
return api.delete(endpoint, params=params)
|
|
185
|
+
return api.delete(endpoint, params=params, api_version=1)
|
|
@@ -123,14 +123,16 @@ def update_lookup(data: JSON, category: str, prefix: str) -> None:
|
|
|
123
123
|
api.patch(endpoint, data, params, api_version=1)
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
def delete_lookup(
|
|
126
|
+
def delete_lookup(
|
|
127
|
+
display_value: str, category: str, prefix: str, office_id: str
|
|
128
|
+
) -> None:
|
|
127
129
|
"""
|
|
128
130
|
Deletes a specified lookup entry.
|
|
129
131
|
|
|
130
132
|
Parameters
|
|
131
133
|
----------
|
|
132
|
-
|
|
133
|
-
Specifies the
|
|
134
|
+
display_value : str
|
|
135
|
+
Specifies the display value of the lookup type to be deleted.
|
|
134
136
|
category : str
|
|
135
137
|
Specifies the category id of the lookup type to be deleted.
|
|
136
138
|
prefix : str
|
|
@@ -153,9 +155,11 @@ def delete_lookup(name: str, category: str, prefix: str, office_id: str) -> None
|
|
|
153
155
|
ServerError
|
|
154
156
|
If a 500 range error code response is returned from the server.
|
|
155
157
|
"""
|
|
156
|
-
if not all([
|
|
157
|
-
raise ValueError(
|
|
158
|
+
if not all([display_value, category, prefix, office_id]):
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"Display Value, Category, Prefix, and Office ID must be specified"
|
|
161
|
+
)
|
|
158
162
|
|
|
159
|
-
endpoint = f"{ENDPOINT}/{
|
|
163
|
+
endpoint = f"{ENDPOINT}/{display_value}"
|
|
160
164
|
params = {"category": category, "prefix": prefix, "office": office_id}
|
|
161
165
|
api.delete(endpoint, params, api_version=1)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Copyright (c) 2026
|
|
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 typing import Optional
|
|
7
|
+
|
|
8
|
+
import cwms.api as api
|
|
9
|
+
from cwms.cwms_types import JSON, Data, DeleteMethod
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_lock(name: str, office_id: str, unit: Optional[str] = "SI") -> Data:
|
|
13
|
+
"""
|
|
14
|
+
Get a specified lock with the given office and name.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
office_id : str
|
|
19
|
+
The office ID of the lock to retrieve. (Query)
|
|
20
|
+
name : str
|
|
21
|
+
The name of the lock to retrieve. (Query)
|
|
22
|
+
unit : str
|
|
23
|
+
The unit system to use for the response. Defaults to "SI". (Query)
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
Data
|
|
28
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
29
|
+
|
|
30
|
+
Raises
|
|
31
|
+
------
|
|
32
|
+
ValueError
|
|
33
|
+
If any required path parameters are None.
|
|
34
|
+
ClientError
|
|
35
|
+
If a 400-level error occurs.
|
|
36
|
+
NoDataFoundError
|
|
37
|
+
If a 404-level error occurs.
|
|
38
|
+
ServerError
|
|
39
|
+
If a 500-level error occurs.
|
|
40
|
+
"""
|
|
41
|
+
if not all([office_id, name]):
|
|
42
|
+
raise ValueError("Office and Name must be provided.")
|
|
43
|
+
|
|
44
|
+
endpoint = f"projects/locks/{name}"
|
|
45
|
+
|
|
46
|
+
params = {"office": office_id, "unit": unit}
|
|
47
|
+
|
|
48
|
+
response = api.get(endpoint, params, api_version=1)
|
|
49
|
+
return Data(response)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_locks(office_id: str, project_id: str) -> Data:
|
|
53
|
+
"""
|
|
54
|
+
Get all locks for the given office and project.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
office_id : str
|
|
59
|
+
The office ID of the locks to retrieve. (Query)
|
|
60
|
+
project_id : str
|
|
61
|
+
The project ID of the locks to retrieve. (Query)
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
Data
|
|
66
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
67
|
+
|
|
68
|
+
Raises
|
|
69
|
+
------
|
|
70
|
+
ValueError
|
|
71
|
+
If any required path parameters are None.
|
|
72
|
+
ClientError
|
|
73
|
+
If a 400-level error occurs.
|
|
74
|
+
NoDataFoundError
|
|
75
|
+
If a 404-level error occurs.
|
|
76
|
+
ServerError
|
|
77
|
+
If a 500-level error occurs.
|
|
78
|
+
"""
|
|
79
|
+
if not all([office_id, project_id]):
|
|
80
|
+
raise ValueError("Office and Project ID must be provided.")
|
|
81
|
+
|
|
82
|
+
endpoint = "projects/locks"
|
|
83
|
+
|
|
84
|
+
params = {"office": office_id, "project-id": project_id}
|
|
85
|
+
|
|
86
|
+
response = api.get(endpoint, params, api_version=1)
|
|
87
|
+
return Data(response)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def create_lock(data: JSON, fail_if_exists: bool = True) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Create CWMS Lock.
|
|
93
|
+
|
|
94
|
+
Parameters
|
|
95
|
+
----------
|
|
96
|
+
data : JSON
|
|
97
|
+
Lock successfully stored to CWMS. (Body)
|
|
98
|
+
fail_if_exists : bool, optional
|
|
99
|
+
Create will fail if provided ID already exists. Default: True. (Query)
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
None
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
ValueError
|
|
108
|
+
If any required parameters are None.
|
|
109
|
+
ClientError
|
|
110
|
+
If a 400-level error occurs.
|
|
111
|
+
NoDataFoundError
|
|
112
|
+
If a 404-level error occurs.
|
|
113
|
+
ServerError
|
|
114
|
+
If a 500-level error occurs.
|
|
115
|
+
"""
|
|
116
|
+
if not data:
|
|
117
|
+
raise ValueError("Data must be provided and cannot be empty.")
|
|
118
|
+
|
|
119
|
+
endpoint = "projects/locks"
|
|
120
|
+
params = {"fail-if-exists": fail_if_exists}
|
|
121
|
+
|
|
122
|
+
api.post(endpoint, data, params, api_version=1)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def delete_lock(
|
|
126
|
+
name: str, office_id: str, method: DeleteMethod = DeleteMethod.DELETE_KEY
|
|
127
|
+
) -> None:
|
|
128
|
+
"""
|
|
129
|
+
Delete CWMS Lock
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
name : str
|
|
134
|
+
Specifies the name of the lock to be deleted. (Path)
|
|
135
|
+
office_id : str
|
|
136
|
+
Specifies the owning office of the lock to be deleted. (Query)
|
|
137
|
+
method : DeleteMethod, optional
|
|
138
|
+
Specifies the delete method used. Defaults to "DELETE_KEY". (Query)
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
None
|
|
143
|
+
|
|
144
|
+
Raises
|
|
145
|
+
------
|
|
146
|
+
ValueError
|
|
147
|
+
If any required parameters are None.
|
|
148
|
+
ClientError
|
|
149
|
+
If a 400-level error occurs.
|
|
150
|
+
NoDataFoundError
|
|
151
|
+
If a 404-level error occurs.
|
|
152
|
+
ServerError
|
|
153
|
+
If a 500-level error occurs.
|
|
154
|
+
"""
|
|
155
|
+
if not all([name, office_id]):
|
|
156
|
+
raise ValueError("Name and Office ID must be provided.")
|
|
157
|
+
|
|
158
|
+
endpoint = f"projects/locks/{name}"
|
|
159
|
+
params = {"office": office_id, "method": method.name}
|
|
160
|
+
|
|
161
|
+
api.delete(endpoint, params, api_version=1)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def update_lock(name: str, office_id: str, new_name: str) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Rename CWMS Lock
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
name : str
|
|
171
|
+
Specifies the name of the lock to be renamed. (Path)
|
|
172
|
+
office_id : str
|
|
173
|
+
Specifies the owning office of the lock to be renamed. (Query)
|
|
174
|
+
new_name : str
|
|
175
|
+
Specifies the new lock name. (Query)
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
None
|
|
180
|
+
|
|
181
|
+
Raises
|
|
182
|
+
------
|
|
183
|
+
ValueError
|
|
184
|
+
If any required parameters are None.
|
|
185
|
+
ClientError
|
|
186
|
+
If a 400-level error occurs.
|
|
187
|
+
NoDataFoundError
|
|
188
|
+
If a 404-level error occurs.
|
|
189
|
+
ServerError
|
|
190
|
+
If a 500-level error occurs.
|
|
191
|
+
"""
|
|
192
|
+
if not all([name, office_id, new_name]):
|
|
193
|
+
raise ValueError("Name, Office ID, and New Name must be provided.")
|
|
194
|
+
|
|
195
|
+
endpoint = f"projects/locks/{name}"
|
|
196
|
+
params = {"office": office_id, "name": new_name}
|
|
197
|
+
|
|
198
|
+
api.patch(endpoint, None, params, api_version=1)
|
|
@@ -87,7 +87,7 @@ def get_projects(
|
|
|
87
87
|
"page": page,
|
|
88
88
|
"page-size": page_size,
|
|
89
89
|
}
|
|
90
|
-
response = api.get(endpoint, params)
|
|
90
|
+
response = api.get(endpoint, params, api_version=1)
|
|
91
91
|
return Data(response)
|
|
92
92
|
|
|
93
93
|
|
|
@@ -208,7 +208,7 @@ def rename_project(office_id: str, old_name: str, new_name: str) -> None:
|
|
|
208
208
|
|
|
209
209
|
endpoint = f"projects/{old_name}"
|
|
210
210
|
params = {"office": office_id, "name": new_name}
|
|
211
|
-
api.patch(endpoint=endpoint, params=params)
|
|
211
|
+
api.patch(endpoint=endpoint, params=params, api_version=1)
|
|
212
212
|
|
|
213
213
|
|
|
214
214
|
def store_project(data: JSON, fail_if_exists: Optional[bool] = True) -> None:
|
|
@@ -243,7 +243,7 @@ def store_project(data: JSON, fail_if_exists: Optional[bool] = True) -> None:
|
|
|
243
243
|
|
|
244
244
|
endpoint = "projects"
|
|
245
245
|
params = {"fail-if-exists": fail_if_exists}
|
|
246
|
-
api.post(endpoint, data, params)
|
|
246
|
+
api.post(endpoint, data, params, api_version=1)
|
|
247
247
|
|
|
248
248
|
|
|
249
249
|
def status_update(
|
|
@@ -306,4 +306,4 @@ def status_update(
|
|
|
306
306
|
"begin": (begin.isoformat() if begin else None),
|
|
307
307
|
"end": (end.isoformat() if end else None),
|
|
308
308
|
}
|
|
309
|
-
api.post(endpoint, None, params)
|
|
309
|
+
api.post(endpoint, None, params, api_version=1)
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Copyright (c) 2026
|
|
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
|
+
import cwms.api as api
|
|
7
|
+
from cwms.cwms_types import JSON, Data, DeleteMethod
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_water_contract(
|
|
11
|
+
office_id: str, project_id: str, water_user: str, contract_name: str
|
|
12
|
+
) -> Data:
|
|
13
|
+
"""
|
|
14
|
+
Return a specified water contract
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
office_id : str
|
|
19
|
+
The office Id the contract is associated with. (Path)
|
|
20
|
+
project_id : str
|
|
21
|
+
The project Id the contract is associated with. (Path)
|
|
22
|
+
water_user : str
|
|
23
|
+
The water user the contract is associated with. (Path)
|
|
24
|
+
contract_name : str
|
|
25
|
+
The name of the contract to retrieve. (Path)
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
Data
|
|
30
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
31
|
+
|
|
32
|
+
Raises
|
|
33
|
+
------
|
|
34
|
+
ValueError
|
|
35
|
+
If any required path parameters are None.
|
|
36
|
+
ClientError
|
|
37
|
+
If a 400-level error occurs.
|
|
38
|
+
NoDataFoundError
|
|
39
|
+
If a 404-level error occurs.
|
|
40
|
+
ServerError
|
|
41
|
+
If a 500-level error occurs.
|
|
42
|
+
"""
|
|
43
|
+
if not all([office_id, project_id, water_user, contract_name]):
|
|
44
|
+
raise ValueError(
|
|
45
|
+
"Office, project_id, water_user, and contract_name must be provided."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}/contracts/{contract_name}"
|
|
49
|
+
|
|
50
|
+
response = api.get(endpoint, api_version=1)
|
|
51
|
+
return Data(response)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_water_contracts(office_id: str, project_id: str, water_user: str) -> Data:
|
|
55
|
+
"""
|
|
56
|
+
Return all water contracts for the specified water user, project, and office
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
office_id : str
|
|
61
|
+
The office Id the contract is associated with. (Path)
|
|
62
|
+
project_id : str
|
|
63
|
+
The project Id the contract is associated with. (Path)
|
|
64
|
+
water_user : str
|
|
65
|
+
The water user the contract is associated with. (Path)
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
Data
|
|
70
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
71
|
+
|
|
72
|
+
Raises
|
|
73
|
+
------
|
|
74
|
+
ValueError
|
|
75
|
+
If any required path parameters are None.
|
|
76
|
+
ClientError
|
|
77
|
+
If a 400-level error occurs.
|
|
78
|
+
NoDataFoundError
|
|
79
|
+
If a 404-level error occurs.
|
|
80
|
+
ServerError
|
|
81
|
+
If a 500-level error occurs.
|
|
82
|
+
"""
|
|
83
|
+
if not all([office_id, project_id, water_user]):
|
|
84
|
+
raise ValueError("Office, project_id, and water_user must be provided.")
|
|
85
|
+
|
|
86
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}/contracts"
|
|
87
|
+
|
|
88
|
+
response = api.get(endpoint, api_version=1)
|
|
89
|
+
return Data(response)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def create_water_contract(
|
|
93
|
+
water_user: str,
|
|
94
|
+
data: JSON,
|
|
95
|
+
fail_if_exists: bool = True,
|
|
96
|
+
ignore_nulls: bool = False,
|
|
97
|
+
) -> None:
|
|
98
|
+
"""
|
|
99
|
+
Create a new water contract
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
water_user : str
|
|
104
|
+
The water user the contract is associated with. (Path)
|
|
105
|
+
data : JSON
|
|
106
|
+
Water contract successfully stored to CWMS. (Body)
|
|
107
|
+
fail_if_exists : bool, optional
|
|
108
|
+
If true, the contract will not be stored if it already exists.
|
|
109
|
+
Default: True (Query)
|
|
110
|
+
ignore_nulls : bool, optional
|
|
111
|
+
If true, null fields will be ignored when storing the contract.
|
|
112
|
+
Default: False (Query)
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
None
|
|
117
|
+
|
|
118
|
+
Raises
|
|
119
|
+
------
|
|
120
|
+
ValueError
|
|
121
|
+
If any required path parameters are None.
|
|
122
|
+
ClientError
|
|
123
|
+
If a 400-level error occurs.
|
|
124
|
+
NoDataFoundError
|
|
125
|
+
If a 404-level error occurs.
|
|
126
|
+
ServerError
|
|
127
|
+
If a 500-level error occurs.
|
|
128
|
+
"""
|
|
129
|
+
if not water_user:
|
|
130
|
+
raise ValueError("Water User must be provided.")
|
|
131
|
+
if not data:
|
|
132
|
+
raise ValueError("Data must be provided and cannot be empty.")
|
|
133
|
+
|
|
134
|
+
# Note the office ID and project ID are not used by CDA
|
|
135
|
+
endpoint = f"projects/{water_user}/{water_user}/water-user/{water_user}/contracts"
|
|
136
|
+
params = {
|
|
137
|
+
"fail-if-exists": fail_if_exists,
|
|
138
|
+
"ignore-nulls": ignore_nulls,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
api.post(endpoint, data, params, api_version=1)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def delete_water_contract(
|
|
145
|
+
office_id: str,
|
|
146
|
+
project_id: str,
|
|
147
|
+
water_user: str,
|
|
148
|
+
contract_name: str,
|
|
149
|
+
method: DeleteMethod = DeleteMethod.DELETE_KEY,
|
|
150
|
+
) -> None:
|
|
151
|
+
"""
|
|
152
|
+
Delete a specified water contract
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
office_id : str
|
|
157
|
+
The office Id the contract is associated with. (Path)
|
|
158
|
+
project_id : str
|
|
159
|
+
The project Id the contract is associated with. (Path)
|
|
160
|
+
water_user : str
|
|
161
|
+
The water user the contract is associated with. (Path)
|
|
162
|
+
contract_name : str
|
|
163
|
+
The name of the contract to be deleted. (Path)
|
|
164
|
+
method : DeleteMethod, optional
|
|
165
|
+
Specifies the delete method used. Defaults to DELETE_KEY. (Query)
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
None
|
|
170
|
+
|
|
171
|
+
Raises
|
|
172
|
+
------
|
|
173
|
+
ValueError
|
|
174
|
+
If any required path parameters are None.
|
|
175
|
+
ClientError
|
|
176
|
+
If a 400-level error occurs.
|
|
177
|
+
NoDataFoundError
|
|
178
|
+
If a 404-level error occurs.
|
|
179
|
+
ServerError
|
|
180
|
+
If a 500-level error occurs.
|
|
181
|
+
"""
|
|
182
|
+
if not all([office_id, project_id, water_user, contract_name]):
|
|
183
|
+
raise ValueError(
|
|
184
|
+
"Office, Project ID, Water User, and Contract Name must be provided."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}/contracts/{contract_name}"
|
|
188
|
+
params = {"method": method.name}
|
|
189
|
+
|
|
190
|
+
api.delete(endpoint, params, api_version=1)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def update_water_contract(
|
|
194
|
+
contract_name: str,
|
|
195
|
+
new_contract_name: str,
|
|
196
|
+
data: JSON,
|
|
197
|
+
) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Updates a water contract in CWMS.
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
contract_name : str
|
|
204
|
+
The name of the contract to be updated. (Path)
|
|
205
|
+
new_contract_name : str
|
|
206
|
+
The new name of the contract. (Query)
|
|
207
|
+
data : JSON
|
|
208
|
+
Water contract successfully updated in CWMS. (Body)
|
|
209
|
+
|
|
210
|
+
Returns
|
|
211
|
+
-------
|
|
212
|
+
None
|
|
213
|
+
|
|
214
|
+
Raises
|
|
215
|
+
------
|
|
216
|
+
ValueError
|
|
217
|
+
If any required path parameters are None.
|
|
218
|
+
ClientError
|
|
219
|
+
If a 400-level error occurs.
|
|
220
|
+
NoDataFoundError
|
|
221
|
+
If a 404-level error occurs.
|
|
222
|
+
ServerError
|
|
223
|
+
If a 500-level error occurs.
|
|
224
|
+
"""
|
|
225
|
+
if not all([contract_name, new_contract_name]):
|
|
226
|
+
raise ValueError("Contract Name and New Contract Name must be provided.")
|
|
227
|
+
if not data:
|
|
228
|
+
raise ValueError("Data must be provided and cannot be empty.")
|
|
229
|
+
|
|
230
|
+
endpoint = f"projects/{contract_name}/{contract_name}/water-user/{contract_name}/contracts/{contract_name}"
|
|
231
|
+
|
|
232
|
+
params = {"contract-name": new_contract_name}
|
|
233
|
+
|
|
234
|
+
api.patch(endpoint, data, params, api_version=1)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Copyright (c) 2026
|
|
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
|
+
import cwms.api as api
|
|
7
|
+
from cwms.cwms_types import JSON, Data
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_water_user(office_id: str, project_id: str, water_user: str) -> Data:
|
|
11
|
+
"""
|
|
12
|
+
Gets a specified water user.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
office_id : str
|
|
17
|
+
The office Id the contract is associated with. (Path)
|
|
18
|
+
project_id : str
|
|
19
|
+
The project Id the contract is associated with. (Path)
|
|
20
|
+
water_user : str
|
|
21
|
+
The water user the contract is associated with. (Path)
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
Data
|
|
26
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
27
|
+
|
|
28
|
+
Raises
|
|
29
|
+
------
|
|
30
|
+
ValueError
|
|
31
|
+
If any required path parameters are None.
|
|
32
|
+
ClientError
|
|
33
|
+
If a 400-level error occurs.
|
|
34
|
+
NoDataFoundError
|
|
35
|
+
If a 404-level error occurs.
|
|
36
|
+
ServerError
|
|
37
|
+
If a 500-level error occurs.
|
|
38
|
+
"""
|
|
39
|
+
if not all([office_id, project_id, water_user]):
|
|
40
|
+
raise ValueError("Office, project_id, and water_user must be provided.")
|
|
41
|
+
|
|
42
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}"
|
|
43
|
+
|
|
44
|
+
response = api.get(endpoint, api_version=1)
|
|
45
|
+
return Data(response)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_water_users(office_id: str, project_id: str) -> Data:
|
|
49
|
+
"""
|
|
50
|
+
Gets a specified water user.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
office_id : str
|
|
55
|
+
The office Id the contract is associated with. (Path)
|
|
56
|
+
project_id : str
|
|
57
|
+
The project Id the contract is associated with. (Path)
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
Data
|
|
62
|
+
The JSON response from CWMS Data API wrapped in a Data object.
|
|
63
|
+
|
|
64
|
+
Raises
|
|
65
|
+
------
|
|
66
|
+
ValueError
|
|
67
|
+
If any required path parameters are None.
|
|
68
|
+
ClientError
|
|
69
|
+
If a 400-level error occurs.
|
|
70
|
+
NoDataFoundError
|
|
71
|
+
If a 404-level error occurs.
|
|
72
|
+
ServerError
|
|
73
|
+
If a 500-level error occurs.
|
|
74
|
+
"""
|
|
75
|
+
if not all([office_id, project_id]):
|
|
76
|
+
raise ValueError("Office and Project ID must be provided.")
|
|
77
|
+
|
|
78
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user"
|
|
79
|
+
|
|
80
|
+
response = api.get(endpoint, api_version=1)
|
|
81
|
+
return Data(response)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def create_water_user(data: JSON, fail_if_exists: bool = True) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Stores a water user to CWMS.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
data : JSON
|
|
91
|
+
Water user successfully stored to CWMS. (Body)
|
|
92
|
+
fail_if_exists : bool, optional
|
|
93
|
+
If true, the operation will fail if the water user already exists.
|
|
94
|
+
Default: true (Query)
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
None
|
|
99
|
+
|
|
100
|
+
Raises
|
|
101
|
+
------
|
|
102
|
+
ValueError
|
|
103
|
+
If any required path parameters are None.
|
|
104
|
+
ClientError
|
|
105
|
+
If a 400-level error occurs.
|
|
106
|
+
NoDataFoundError
|
|
107
|
+
If a 404-level error occurs.
|
|
108
|
+
ServerError
|
|
109
|
+
If a 500-level error occurs.
|
|
110
|
+
"""
|
|
111
|
+
if not data:
|
|
112
|
+
raise ValueError("Data must be provided and cannot be empty.")
|
|
113
|
+
|
|
114
|
+
endpoint = "projects/office/project/water-user"
|
|
115
|
+
params = {"fail-if-exists": fail_if_exists}
|
|
116
|
+
|
|
117
|
+
api.post(endpoint, data, params, api_version=1)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def delete_water_user(office_id: str, project_id: str, water_user: str) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Deletes a specified water user.
|
|
123
|
+
|
|
124
|
+
Parameters
|
|
125
|
+
----------
|
|
126
|
+
office_id : str
|
|
127
|
+
The office Id the contract is associated with. (Path)
|
|
128
|
+
project_id : str
|
|
129
|
+
The project Id the contract is associated with. (Path)
|
|
130
|
+
water_user : str
|
|
131
|
+
The water user the contract is associated with. (Path)
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
None
|
|
136
|
+
|
|
137
|
+
Raises
|
|
138
|
+
------
|
|
139
|
+
ValueError
|
|
140
|
+
If any required path parameters are None.
|
|
141
|
+
ClientError
|
|
142
|
+
If a 400-level error occurs.
|
|
143
|
+
NoDataFoundError
|
|
144
|
+
If a 404-level error occurs.
|
|
145
|
+
ServerError
|
|
146
|
+
If a 500-level error occurs.
|
|
147
|
+
"""
|
|
148
|
+
if not all([office_id, project_id, water_user]):
|
|
149
|
+
raise ValueError("Office, Project ID, and Water User must be provided.")
|
|
150
|
+
|
|
151
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}"
|
|
152
|
+
|
|
153
|
+
api.delete(endpoint, api_version=1)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def update_water_user(
|
|
157
|
+
office_id: str, project_id: str, water_user: str, data: JSON, name: str
|
|
158
|
+
) -> None:
|
|
159
|
+
"""
|
|
160
|
+
Updates a water user in CWMS.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
office_id : str
|
|
165
|
+
The office Id the contract is associated with. (Path)
|
|
166
|
+
project_id : str
|
|
167
|
+
The project Id the contract is associated with. (Path)
|
|
168
|
+
water_user : str
|
|
169
|
+
The water user the contract is associated with. (Path)
|
|
170
|
+
data : JSON
|
|
171
|
+
Water user entity data in JSON format. (Body)
|
|
172
|
+
name : str
|
|
173
|
+
Specifies the new name of the water user entity. (Query)
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
None
|
|
178
|
+
|
|
179
|
+
Raises
|
|
180
|
+
------
|
|
181
|
+
ValueError
|
|
182
|
+
If any required path parameters are None.
|
|
183
|
+
ClientError
|
|
184
|
+
If a 400-level error occurs.
|
|
185
|
+
NoDataFoundError
|
|
186
|
+
If a 404-level error occurs.
|
|
187
|
+
ServerError
|
|
188
|
+
If a 500-level error occurs.
|
|
189
|
+
"""
|
|
190
|
+
if not all([office_id, project_id, water_user, name]):
|
|
191
|
+
raise ValueError("Office, Project ID, Water User, and Name must be provided.")
|
|
192
|
+
if not data:
|
|
193
|
+
raise ValueError("Data must be provided and cannot be empty.")
|
|
194
|
+
|
|
195
|
+
endpoint = f"projects/{office_id}/{project_id}/water-user/{water_user}"
|
|
196
|
+
params = {"name": name}
|
|
197
|
+
|
|
198
|
+
api.patch(endpoint, data, params, api_version=1)
|
|
@@ -3,7 +3,7 @@ name = "cwms-python"
|
|
|
3
3
|
repository = "https://github.com/HydrologicEngineeringCenter/cwms-python"
|
|
4
4
|
|
|
5
5
|
# Managed by Release Please; runtime versions come from package metadata.
|
|
6
|
-
version = "1.0
|
|
6
|
+
version = "1.1.0"
|
|
7
7
|
|
|
8
8
|
packages = [
|
|
9
9
|
{ include = "cwms" },
|
|
@@ -28,6 +28,11 @@ requests = [
|
|
|
28
28
|
{version = "^2.32.4", python = ">=3.9,<3.10"},
|
|
29
29
|
{version = "^2.33.0", python = ">=3.10"},
|
|
30
30
|
]
|
|
31
|
+
# Keep the Python 3.9 fallback while requiring patched releases on newer Python.
|
|
32
|
+
urllib3 = [
|
|
33
|
+
{version = ">=2.6.3,<2.7", python = ">=3.9,<3.10"},
|
|
34
|
+
{version = "^2.7.0", python = ">=3.10"},
|
|
35
|
+
]
|
|
31
36
|
|
|
32
37
|
[tool.poetry.group.dev.dependencies]
|
|
33
38
|
black = [
|
|
@@ -46,6 +51,10 @@ pytest-cov = "^4.1.0"
|
|
|
46
51
|
pandas-stubs = "^2.2.1.240316"
|
|
47
52
|
types-requests = "^2.31.0.20240311"
|
|
48
53
|
yamlfix = "^1.16.0"
|
|
54
|
+
setuptools = [
|
|
55
|
+
{version = ">=82.0.1,<83", python = ">=3.9,<3.10"},
|
|
56
|
+
{version = ">=83.0.0", python = ">=3.10"},
|
|
57
|
+
]
|
|
49
58
|
|
|
50
59
|
[build-system]
|
|
51
60
|
requires = ["poetry-core"]
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|