From 491ad40ae0c370be1410f07d9990501897a6e3bc Mon Sep 17 00:00:00 2001 From: mperryman2 Date: Tue, 7 Jul 2026 14:41:40 +0000 Subject: [PATCH 1/3] Add USE_NEW_LRTS_IDS module variable, getter, and setter to api. --- cwms/api.py | 77 +++++++++++++++++++++++++++++++++++++++++++++----- pyproject.toml | 2 +- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/cwms/api.py b/cwms/api.py index 4f82099..d6505b1 100644 --- a/cwms/api.py +++ b/cwms/api.py @@ -48,6 +48,9 @@ API_ROOT = "https://cwms-data.usace.army.mil/cwms-data/" API_VERSION = 2 +# Specify whether LRTS will use new ID format +USE_NEW_LRTS_IDS = False + # Initialize a non-authenticated session with the default root URL and set default pool connections. retry_strategy = Retry( @@ -168,6 +171,7 @@ def init_session( api_key: Optional[str] = None, token: Optional[str] = None, pool_connections: int = 100, + use_new_lrts_format: bool = False, ) -> BaseUrlSession: """Specify a root URL and authentication credentials for the CWMS Data API. @@ -186,7 +190,7 @@ def init_session( Returns the updated session object. """ - global SESSION + global SESSION, USE_NEW_LRTS_IDS if api_root: # Ensure the API_ROOT ends with a single slash api_root = api_root.rstrip("/") + "/" @@ -206,11 +210,19 @@ def init_session( # Ensure we don't provide the bearer text twice if token.lower().startswith("bearer "): token = token[7:] - SESSION.headers.update({"Authorization": "Bearer " + token}) + SESSION.headers.update({ + "Authorization": "Bearer " + token, + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + }) elif api_key: if api_key.startswith("apikey "): api_key = api_key.replace("apikey ", "") - SESSION.headers.update({"Authorization": "apikey " + api_key}) + SESSION.headers.update({ + "Authorization": "apikey " + api_key, + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + }) + + USE_NEW_LRTS_IDS = use_new_lrts_format return SESSION @@ -224,6 +236,43 @@ def return_base_url() -> str: return str(SESSION.base_url) +def set_use_new_lrts_ids(state: bool) -> None: + """Sets whether the new LRTS identifer format is used for subsequent operations. + + The old Local Regular Time Series (LRTS) identifier format is the same as the + Pseudo-Regular Time Series (PRTS) identifier format, where both prepend a tilde + character ('~') to valid Regular Time Series (RTS) interval identifiers (e.g., + ~6Hours, ~1Day). + + The new LRTS identifiers instead append "Local" to valid RTS interval identifiers + (e.g., 6HoursLocal, 1DayLocal), leaving the old format to specify only PRTS. + + Args: + state: Whether the new LRTS identifier format is used + """ + + global USE_NEW_LRTS_IDS + + USE_NEW_LRTS_IDS = state + +def get_use_new_lrts_ids() -> bool: + """Gets whether the new LRTS identifer format is used for subsequent operations. + + The old Local Regular Time Series (LRTS) identifier format is the same as the + Pseudo-Regular Time Series (PRTS) identifier format, where both prepend a tilde + character ('~') to valid Regular Time Series (RTS) interval identifiers (e.g., + ~6Hours, ~1Day). + + The new LRTS identifiers instead append "Local" to valid RTS interval identifiers + (e.g., 6HoursLocal, 1DayLocal), leaving the old format to specify only PRTS. + + Returns: + Whether the new LRTS identifier format is used + """ + + global USE_NEW_LRTS_IDS + + return USE_NEW_LRTS_IDS def api_version_text(api_version: int) -> str: """Initialize CDA request headers. @@ -329,7 +378,10 @@ def get( ApiError: If an error response is return by the API. """ - headers = {"Accept": api_version_text(api_version)} + headers = { + "Accept": api_version_text(api_version), + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + } try: with SESSION.get(endpoint, params=params, headers=headers) as response: if not response.ok: @@ -389,7 +441,11 @@ def _post_function( ) -> Any: # post requires different headers than get for - headers = {"accept": "*/*", "Content-Type": api_version_text(api_version)} + headers = { + "accept": "*/*", + "Content-Type": api_version_text(api_version), + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + } if isinstance(data, dict) or isinstance(data, list): data = json.dumps(data) try: @@ -487,7 +543,11 @@ def patch( ApiError: If an error response is return by the API. """ - headers = {"accept": "*/*", "Content-Type": api_version_text(api_version)} + headers = { + "accept": "*/*", + "Content-Type": api_version_text(api_version), + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + } if data and isinstance(data, dict) or isinstance(data, list): data = json.dumps(data) @@ -522,7 +582,10 @@ def delete( ApiError: If an error response is return by the API. """ - headers = {"Accept": api_version_text(api_version)} + headers = { + "Accept": api_version_text(api_version), + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + } try: with SESSION.delete(endpoint, params=params, headers=headers) as response: if not response.ok: diff --git a/pyproject.toml b/pyproject.toml index 45e7ed9..4c2dde1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "cwms-python" repository = "https://github.com/HydrologicEngineeringCenter/cwms-python" -version = "1.0.8" +version = "1.0.9" packages = [ { include = "cwms" }, From 52536dc9291ea5dfe46f20872cd83a7fe589612a Mon Sep 17 00:00:00 2001 From: mperryman2 Date: Tue, 7 Jul 2026 15:02:58 +0000 Subject: [PATCH 2/3] format with black --- cwms/api.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/cwms/api.py b/cwms/api.py index d6505b1..20d2c2c 100644 --- a/cwms/api.py +++ b/cwms/api.py @@ -210,17 +210,21 @@ def init_session( # Ensure we don't provide the bearer text twice if token.lower().startswith("bearer "): token = token[7:] - SESSION.headers.update({ - "Authorization": "Bearer " + token, - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() - }) + SESSION.headers.update( + { + "Authorization": "Bearer " + token, + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), + } + ) elif api_key: if api_key.startswith("apikey "): api_key = api_key.replace("apikey ", "") - SESSION.headers.update({ - "Authorization": "apikey " + api_key, - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() - }) + SESSION.headers.update( + { + "Authorization": "apikey " + api_key, + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), + } + ) USE_NEW_LRTS_IDS = use_new_lrts_format @@ -236,6 +240,7 @@ def return_base_url() -> str: return str(SESSION.base_url) + def set_use_new_lrts_ids(state: bool) -> None: """Sets whether the new LRTS identifer format is used for subsequent operations. @@ -255,6 +260,7 @@ def set_use_new_lrts_ids(state: bool) -> None: USE_NEW_LRTS_IDS = state + def get_use_new_lrts_ids() -> bool: """Gets whether the new LRTS identifer format is used for subsequent operations. @@ -274,6 +280,7 @@ def get_use_new_lrts_ids() -> bool: return USE_NEW_LRTS_IDS + def api_version_text(api_version: int) -> str: """Initialize CDA request headers. @@ -380,7 +387,7 @@ def get( headers = { "Accept": api_version_text(api_version), - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), } try: with SESSION.get(endpoint, params=params, headers=headers) as response: @@ -444,7 +451,7 @@ def _post_function( headers = { "accept": "*/*", "Content-Type": api_version_text(api_version), - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), } if isinstance(data, dict) or isinstance(data, list): data = json.dumps(data) @@ -546,7 +553,7 @@ def patch( headers = { "accept": "*/*", "Content-Type": api_version_text(api_version), - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), } if data and isinstance(data, dict) or isinstance(data, list): @@ -584,7 +591,7 @@ def delete( headers = { "Accept": api_version_text(api_version), - "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower() + "X-CWMS-LRTS-Formatting": str(USE_NEW_LRTS_IDS).lower(), } try: with SESSION.delete(endpoint, params=params, headers=headers) as response: From b10eee662463ba18fe930e25aaea15a780d5d77a Mon Sep 17 00:00:00 2001 From: mperryman2 Date: Wed, 8 Jul 2026 14:40:47 +0000 Subject: [PATCH 3/3] trivial change for force rebuild --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4c2dde1..fd6c3eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,3 +43,4 @@ comments_min_spaces_from_content = 1 whitelines = 1 explicit_start = false preserve_quotes = true +