Source code for tes.utils
"""Exceptions and utilities."""
import json
import re
from typing import Any, Dict, Type
from tes.models import (Task, Input, Output, Resources, Executor,
TaskLog, ExecutorLog, OutputFileLog)
first_cap_re = re.compile('(.)([A-Z][a-z]+)')
all_cap_re = re.compile('([a-z0-9])([A-Z])')
[docs]
def camel_to_snake(name: str) -> str:
"""Converts camelCase to snake_case.
Args:
name: String to convert.
Returns:
Converted string.
"""
s1 = first_cap_re.sub(r'\1_\2', name)
return all_cap_re.sub(r'\1_\2', s1).lower()
[docs]
class UnmarshalError(Exception):
"""Raised when a JSON string cannot be unmarshalled to a TES model."""
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args, **kwargs)
[docs]
class TimeoutError(Exception):
def __init__(self, *args, **kwargs):
Exception.__init__(self, *args, **kwargs)
[docs]
def unmarshal(j: Any, o: Type, convert_camel_case=True) -> Any:
"""Unmarshal a JSON string to a TES model.
Args:
j: JSON string or dictionary to unmarshal.
o: TES model to unmarshal to.
convert_camel_case: Convert values in `j` from camelCase to snake_case.
Returns:
Unmarshalled TES model.
Raises:
UnmarshalError: If `j` cannot be unmarshalled to `o`.
"""
m: Any = None
if isinstance(j, str):
try:
m = json.loads(j)
except json.decoder.JSONDecodeError:
raise UnmarshalError("Unable to decode JSON string: %s" % j)
elif j is None:
return None
else:
m = j
if not isinstance(m, dict):
raise TypeError("j must be a dictionary, a JSON string evaluation to "
"a dictionary, or None")
d: Dict[str, Any] = {}
if convert_camel_case:
for k, v in m.items():
d[camel_to_snake(k)] = v
else:
d = m
fullOmap = {
"Executor": {
"logs": ExecutorLog
},
"Task": {
"logs": TaskLog,
"inputs": Input,
"outputs": Output,
"resources": Resources,
"executors": Executor
},
"TaskLog": {
"outputs": OutputFileLog,
"logs": ExecutorLog
},
"ListTasksResponse": {
"tasks": Task,
}
}
def _unmarshal(v: Any, obj: Type) -> Any:
if isinstance(v, list):
field = []
for item in v:
field.append(unmarshal(item, obj))
else:
field = unmarshal(v, obj)
return field
r = {}
for k, v in d.items():
field = v
omap = fullOmap.get(o.__name__, {})
if k in omap:
obj = omap[k]
field = _unmarshal(v, obj)
r[k] = field
try:
output = o(**r)
except Exception as e:
msg = "%s could not be unmarshalled to type: %s" % (j, o.__name__) + \
"\n" + \
"%s: %s" % (type(e).__name__, e)
raise UnmarshalError(msg)
return output