Skip to content

Commit

Permalink
Breaking changes (#154)
Browse files Browse the repository at this point in the history
* Breaking changes:
- SumoClient .get() and .delete() no longer decodes the response;
instead, the response object is returned.
- Instead of keyword parameters, SumoClient .get() takes the parameter
'params', which is a dict.
- The parameter 'params' is also added to a few other methods. In
particular, it is now possible to pass a '$pit' parameter to the
DELETE handler for 'pit'.

* (reformatted with black.

---------

Co-authored-by: Raymond Wiker <[email protected]>
  • Loading branch information
rwiker and rwiker authored Oct 5, 2023
1 parent b8fc568 commit 17ed752
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 60 deletions.
71 changes: 23 additions & 48 deletions src/sumo/wrapper/sumo_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ._auth_provider import get_auth_provider
from .config import APP_REGISTRATION, TENANT_ID, AUTHORITY_HOST_URI

from ._decorators import http_unpack, raise_for_status, http_retry
from ._decorators import raise_for_status, http_retry

logger = logging.getLogger("sumo.wrapper")

Expand Down Expand Up @@ -47,7 +47,14 @@ def __init__(
refresh_token = None
if token:
logger.debug("Token provided")
payload = self.__decode_token(token)

payload = None
try:
payload = jwt.decode(
token, options={"verify_signature": False}
)
except jwt.InvalidTokenError:
pass

if payload:
logger.debug(f"Token decoded as JWT, payload: {payload}")
Expand Down Expand Up @@ -101,49 +108,14 @@ def blob_client(self) -> BlobClient:

return self._blob_client

def __decode_token(self, token: str) -> dict:
"""
Decodes a Json Web Token, returns the payload as a dictionary.
Args:
token: Token to decode
Returns:
Decoded Json Web Token (None if token can't be decoded)
"""

try:
payload = jwt.decode(token, options={"verify_signature": False})
return payload
except jwt.InvalidTokenError:
return None

def _process_params(self, params_dict: dict) -> dict:
"""Convert a dictionary of query parameters to Sumo friendly format.
Args:
params_dict: Dictionary of query parameters
Returns:
Dictionary of processed parameters
"""

prefixed_params = {}

for param_key in params_dict:
prefixed_params[f"${param_key}"] = params_dict[param_key]

return None if prefixed_params == {} else prefixed_params

@http_unpack
@raise_for_status
@http_retry
def get(self, path: str, **params) -> dict:
def get(self, path: str, params: dict = None) -> dict:
"""Performs a GET-request to the Sumo API.
Args:
path: Path to a Sumo endpoint
params: Keyword arguments treated as query parameters
params: query parameters, as dictionary
Returns:
Sumo JSON response as a dictionary
Expand Down Expand Up @@ -175,7 +147,7 @@ def get(self, path: str, **params) -> dict:

response = httpx.get(
f"{self.base_url}{path}",
params=self._process_params(params),
params=params,
headers=headers,
follow_redirects=True,
timeout=DEFAULT_TIMEOUT,
Expand All @@ -201,6 +173,7 @@ def post(
path: Path to a Sumo endpoint
blob: Blob payload
json: Json payload
params: query parameters, as dictionary
Returns:
Sumo response object
Expand Down Expand Up @@ -300,14 +273,14 @@ def put(

return response

@http_unpack
@raise_for_status
@http_retry
def delete(self, path: str) -> dict:
def delete(self, path: str, params: dict = None) -> dict:
"""Performs a DELETE-request to the Sumo API.
Args:
path: Path to a Sumo endpoint
params: query parameters, as dictionary
Returns:
Sumo JSON resposne as a dictionary
Expand All @@ -331,6 +304,7 @@ def delete(self, path: str) -> dict:
response = httpx.delete(
f"{self.base_url}{path}",
headers=headers,
params=params,
timeout=DEFAULT_TIMEOUT,
)

Expand All @@ -354,15 +328,14 @@ def getLogger(self, name):
logger.addHandler(handler)
return logger

@http_unpack
@raise_for_status
@http_retry
async def get_async(self, path: str, **params):
async def get_async(self, path: str, params: dict = None):
"""Performs an async GET-request to the Sumo API.
Args:
path: Path to a Sumo endpoint
params: Keyword arguments treated as query parameters
params: query parameters, as dictionary
Returns:
Sumo JSON response as a dictionary
Expand Down Expand Up @@ -394,7 +367,7 @@ async def get_async(self, path: str, **params):
async with httpx.AsyncClient() as client:
response = await client.get(
f"{self.base_url}{path}",
params=self._process_params(params),
params=params,
headers=headers,
timeout=DEFAULT_TIMEOUT,
)
Expand All @@ -419,6 +392,7 @@ async def post_async(
path: Path to a Sumo endpoint
blob: Blob payload
json: Json payload
params: query parameters, as dictionary
Returns:
Sumo response object
Expand Down Expand Up @@ -522,14 +496,14 @@ async def put_async(

return response

@http_unpack
@raise_for_status
@http_retry
async def delete_async(self, path: str) -> dict:
async def delete_async(self, path: str, params: dict = None) -> dict:
"""Performs an async DELETE-request to the Sumo API.
Args:
path: Path to a Sumo endpoint
params: query parameters, as dictionary
Returns:
Sumo JSON resposne as a dictionary
Expand All @@ -554,6 +528,7 @@ async def delete_async(self, path: str) -> dict:
response = await client.delete(
url=f"{self.base_url}{path}",
headers=headers,
params=params,
timeout=DEFAULT_TIMEOUT,
)

Expand Down
37 changes: 25 additions & 12 deletions tests/test_sumo_thin_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _get_blob_uri(C, object_id):


def _download_object(C, object_id):
json = C.api.get(f"/objects('{object_id}')")
json = C.api.get(f"/objects('{object_id}')").json()

return json

Expand All @@ -56,12 +56,14 @@ def _upload_child_level_json(C, parent_id, json):
response = C.api.post(f"/objects('{parent_id}')", json=json)

if not 200 <= response.status_code < 202:
raise Exception(f"Response: {response.status_code}, Text: {response.text}")
raise Exception(
f"Response: {response.status_code}, Text: {response.text}"
)
return response


def _delete_object(C, object_id):
response = C.api.delete(f"/objects('{object_id}')")
response = C.api.delete(f"/objects('{object_id}')").json()

return response

Expand Down Expand Up @@ -111,7 +113,9 @@ def test_upload_search_delete_ensemble_child(token):

fmu_surface_metadata["fmu"]["case"]["uuid"] = case_uuid

fmu_surface_id = fmu_surface_metadata.get("fmu").get("realization").get("id")
fmu_surface_id = (
fmu_surface_metadata.get("fmu").get("realization").get("id")
)
response_surface = _upload_child_level_json(
C=C, parent_id=case_id, json=fmu_surface_metadata
)
Expand All @@ -123,22 +127,28 @@ def test_upload_search_delete_ensemble_child(token):
blob_url = response_surface.json().get("blob_url")

# Upload BLOB
response_blob = _upload_blob(C=C, blob=B, url=blob_url, object_id=surface_id)
response_blob = _upload_blob(
C=C, blob=B, url=blob_url, object_id=surface_id
)
assert 200 <= response_blob.status_code <= 202

sleep(4)

# Search for ensemble
query = f"fmu.case.uuid:{case_uuid}"

search_results = C.api.get("/searchroot", query=query, select=["_source"])
search_results = C.api.get(
"/searchroot", params={"$query": query, "$select": ["_source"]}
).json()

hits = search_results.get("hits").get("hits")
assert len(hits) == 1
assert hits[0].get("_id") == case_id

# Search for child object
search_results = C.api.get("/search", query=query, select=["_source"])
search_results = C.api.get(
"/search", {"$query": query, "$select": ["_source"]}
).json()

total = search_results.get("hits").get("total").get("value")
assert total == 2
Expand All @@ -147,7 +157,7 @@ def test_upload_search_delete_ensemble_child(token):
assert get_result["_id"] == surface_id

# Search for blob
bin_obj = C.api.get(f"/objects('{surface_id}')/blob")
bin_obj = C.api.get(f"/objects('{surface_id}')/blob").content
assert bin_obj == B

# Delete Ensemble
Expand All @@ -157,14 +167,18 @@ def test_upload_search_delete_ensemble_child(token):
sleep(40)

# Search for ensemble
search_results = C.api.get("/searchroot", query=query, select=["_source"])
search_results = C.api.get(
"/searchroot", {"$query": query, "$select": ["_source"]}
).json()

hits = search_results.get("hits").get("hits")

assert len(hits) == 0

# Search for child object
search_results = C.api.get("/search", query=query, select=["_source"])
search_results = C.api.get(
"/search", {"$query": query, "$select": ["_source"]}
).json()
total = search_results.get("hits").get("total").get("value")
assert total == 0

Expand All @@ -189,12 +203,11 @@ def test_upload_duplicate_ensemble(token):

with open("tests/testdata/case.yml", "r") as stream:
fmu_metadata2 = yaml.safe_load(stream)

case_uuid = str(uuid.uuid4())
fmu_metadata1["fmu"]["case"]["uuid"] = case_uuid
fmu_metadata2["fmu"]["case"]["uuid"] = case_uuid


# upload case metadata, get object_id
response1 = _upload_parent_object(C=C, json=fmu_metadata1)
assert 200 <= response1.status_code <= 202
Expand Down

0 comments on commit 17ed752

Please sign in to comment.