Skip to content

Commit 2e99bee

Browse files
author
Doug Schmidt
authored
Merge pull request #296 from DougSchmidt-AI/feature/PF-1383-AccessPrivateApisFromPython
PF-1383 - Added ease-of-use access to some private APIs from Python
2 parents 1fde91e + f469a66 commit 2e99bee

File tree

4 files changed

+75
-8
lines changed

4 files changed

+75
-8
lines changed

TimeSeries/PublicApis/Python/ApprovalReport/timeseries_client.py

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime
66
from datetime import timedelta
77
from functools import total_ordering
8+
from urllib.parse import urlparse
89
import os
910
import platform
1011
import pyrfc3339
@@ -477,6 +478,19 @@ def _reauthenticate(self, response, *args, **kwargs):
477478

478479
return new_response
479480

481+
def _create_authenticated_endpoint(self, root_path: str, verify=True) -> TimeSeriesSession:
482+
"""
483+
Creates an authenticated endpoint to something other than the public API surface.
484+
485+
:param root_path: The path to the endpoint on the AQTS app server
486+
:param verify: The standard requests library certificate check
487+
:return: An authenticated session for making requests to the end point
488+
"""
489+
url = urlparse(self.publish.base_url)
490+
session = TimeSeriesSession(f'{url.scheme}://{url.hostname}', root_path, verify=verify)
491+
session.set_session_token(self.publish.headers['X-Authentication-Token'])
492+
return session
493+
480494
def isVersionLessThan(self, source_version, target_version=None):
481495
"""
482496
Is the source version strictly less than the target version.

TimeSeries/PublicApis/Python/Readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ $ pip install requests pytz pyrfc3339
1414
```
1515

1616
## Revision History
17+
- 2022-Feb-28 - Added `_create_authenticated_endpoint()` method to access extended API endpoints
1718
- 2021-Dec-14 - Improved parsing of location identifiers, and automatically re-authenticate if a session times out.
1819
- 2020-Dec-07 - Added `flattenResponse()` method to project grades, approvals, qualifiers, and notes to points
1920
- 2021-Sep-04 - Improved format of web service error messages for AQTS and AQSamples

TimeSeries/PublicApis/Python/WindRose/timeseries_client.py

+46-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime
66
from datetime import timedelta
77
from functools import total_ordering
8+
from urllib.parse import urlparse
89
import os
910
import platform
1011
import pyrfc3339
@@ -423,6 +424,8 @@ def __init__(self, hostname, username="admin", password="admin", verify=True):
423424
self.acquisition = TimeSeriesSession(hostname, "/AQUARIUS/Acquisition/v2", verify=verify)
424425
self.provisioning = TimeSeriesSession(hostname, "/AQUARIUS/Provisioning/v1", verify=verify)
425426

427+
self._configure_reauthentication(username, password)
428+
426429
# Authenticate once
427430
self.connect(username, password)
428431

@@ -447,10 +450,47 @@ def connect(self, username, password):
447450
self.acquisition.set_session_token(token)
448451
self.provisioning.set_session_token(token)
449452

453+
return token
454+
450455
def disconnect(self):
451456
"""Destroys the authenticated session"""
452457
self.publish.delete('/session')
453458

459+
def _configure_reauthentication(self, username, password):
460+
self._username = username
461+
self._password = password
462+
self._reauthenticating = False
463+
self._reauthenticate_session = requests.Session()
464+
465+
self.publish.hooks['response'].append(self._reauthenticate)
466+
self.acquisition.hooks['response'].append(self._reauthenticate)
467+
self.provisioning.hooks['response'].append(self._reauthenticate)
468+
469+
def _reauthenticate(self, response, *args, **kwargs):
470+
if response.status_code == 401 and not self._reauthenticating:
471+
self._reauthenticating = True
472+
token = self.connect(self._username, self._password)
473+
474+
response.request.headers.update({"X-Authentication-Token": token})
475+
476+
new_response = self._reauthenticate_session.send(response.request, **kwargs)
477+
self._reauthenticating = False
478+
479+
return new_response
480+
481+
def _create_authenticated_endpoint(self, root_path: str, verify=True) -> TimeSeriesSession:
482+
"""
483+
Creates an authenticated endpoint to something other than the public API surface.
484+
485+
:param root_path: The path to the endpoint on the AQTS app server
486+
:param verify: The standard requests library certificate check
487+
:return: An authenticated session for making requests to the end point
488+
"""
489+
url = urlparse(self.publish.base_url)
490+
session = TimeSeriesSession(f'{url.scheme}://{url.hostname}', root_path, verify=verify)
491+
session.set_session_token(self.publish.headers['X-Authentication-Token'])
492+
return session
493+
454494
def isVersionLessThan(self, source_version, target_version=None):
455495
"""
456496
Is the source version strictly less than the target version.
@@ -517,12 +557,11 @@ def getTimeSeriesUniqueId(self, timeSeriesIdentifier):
517557
:param timeSeriesIdentifier: The identifier to lookup
518558
:return: The unique ID of the series
519559
"""
520-
parts = timeSeriesIdentifier.split('@')
521-
522-
if len(parts) < 2:
560+
match = re.search('[^\\\\]@(?P<location>.+)$', timeSeriesIdentifier)
561+
if not match:
523562
return timeSeriesIdentifier
524563

525-
location = parts[1]
564+
location = match.group('location')
526565

527566
# Get the descriptions from the location
528567
try:
@@ -541,12 +580,11 @@ def getTimeSeriesUniqueId(self, timeSeriesIdentifier):
541580

542581
def getLocationIdentifier(self, timeSeriesOrRatingModelIdentifier):
543582
"""Extracts the location identifier from a 'Parameter.Label@Location' time-series or rating model identifier"""
544-
parts = timeSeriesOrRatingModelIdentifier.split('@')
545-
546-
if len(parts) < 2:
583+
match = re.search('[^\\\\]@(?P<location>.+)$', timeSeriesOrRatingModelIdentifier)
584+
if not match:
547585
raise LocationNotFoundException(timeSeriesOrRatingModelIdentifier)
548586

549-
return parts[1]
587+
return match.group('location')
550588

551589
def getLocationData(self, identifier):
552590
"""Gets the location data"""

TimeSeries/PublicApis/Python/timeseries_client.py

+14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime
66
from datetime import timedelta
77
from functools import total_ordering
8+
from urllib.parse import urlparse
89
import os
910
import platform
1011
import pyrfc3339
@@ -477,6 +478,19 @@ def _reauthenticate(self, response, *args, **kwargs):
477478

478479
return new_response
479480

481+
def _create_authenticated_endpoint(self, root_path: str, verify=True) -> TimeSeriesSession:
482+
"""
483+
Creates an authenticated endpoint to something other than the public API surface.
484+
485+
:param root_path: The path to the endpoint on the AQTS app server
486+
:param verify: The standard requests library certificate check
487+
:return: An authenticated session for making requests to the end point
488+
"""
489+
url = urlparse(self.publish.base_url)
490+
session = TimeSeriesSession(f'{url.scheme}://{url.hostname}', root_path, verify=verify)
491+
session.set_session_token(self.publish.headers['X-Authentication-Token'])
492+
return session
493+
480494
def isVersionLessThan(self, source_version, target_version=None):
481495
"""
482496
Is the source version strictly less than the target version.

0 commit comments

Comments
 (0)