Skip to content

Commit 296a295

Browse files
committed
Updates
1 parent 8c50f62 commit 296a295

26 files changed

Lines changed: 469 additions & 184 deletions

src/steamship/app/lambda_handler.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,29 @@ def _handler(event: Dict, context: Dict = None) -> Response:
2020
configDict=event.get("clientConfig", None)
2121
)
2222
except SteamshipError as se:
23+
logging.error(se)
2324
return Response.from_obj(se)
2425
except Exception as ex:
26+
logging.error(ex)
2527
return Response.error(code=500, message="Plugin/App handler was unable to create Steamship client.", exception=ex)
2628

2729
app = None
2830

2931
try:
3032
request = Request.from_dict(event)
3133
except SteamshipError as se:
34+
logging.error(se)
3235
return Response.from_obj(se)
3336
except Exception as ex:
37+
logging.error(ex)
3438
return Response.error(code=500, message="Plugin/App handler was unable to parse inbound request.", exception=ex)
3539

3640
try:
3741
app = App(client=client, config=request.invocation.config)
3842
except SteamshipError as se:
3943
return Response.from_obj(se)
4044
except Exception as ex:
45+
logging.error(ex)
4146
return Response.error(code=500, message="Handler was unable to initialize plugin/app.", exception=ex)
4247

4348
if app is None:
@@ -47,9 +52,17 @@ def _handler(event: Dict, context: Dict = None) -> Response:
4752
response = app(request)
4853
return Response.from_obj(response)
4954
except SteamshipError as se:
55+
logging.error(se)
5056
return Response.from_obj(se)
5157
except Exception as ex:
52-
return Response.error(code=500, message="Handler was unable to run app/plugin method", exception=ex)
58+
logging.error(ex)
59+
appVerb = None
60+
appPath = None
61+
if request:
62+
if request.invocation:
63+
appPath = request.invocation.appPath
64+
appVerb = request.invocation.httpVerb
65+
return Response.error(code=500, message="Handler was unable to run app/plugin method {} {}".format(appVerb, appPath), exception=ex)
5366

5467
def handler(event: Dict, context: Dict = None) -> dict:
5568
response = _handler(event, context)

src/steamship/app/request.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class Request:
5959
def from_dict(d: dict) -> "Request":
6060
invocation = Invocation.from_dict(d.get('invocation', dict()))
6161
clientConfig = Configuration.from_dict(d.get('clientConfig', dict()))
62-
logging.info("App layer got invocation {} {}".format(type(invocation), invocation))
6362
return Request(
6463
clientConfig=clientConfig,
6564
invocation=invocation

src/steamship/app/response.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,21 @@
22
import io
33
import logging
44
from dataclasses import dataclass
5-
from typing import Dict, Any, Generic, TypeVar
5+
from typing import Dict, Any, Generic, TypeVar, Union
66

77
from steamship.base.binary_utils import flexi_create
88
from steamship.base import SteamshipError
99
from steamship.base.tasks import Task, TaskState
10+
from steamship.base.mime_types import MimeTypes, ContentEncodings
1011

1112

1213
@dataclass
1314
class Http():
1415
status: int = None
16+
# If true, we're signaling to the Steamship Proxy that the `data` field of the SteamshipResponse object
17+
# has been wrapped in base64. In this situation, we can return the bytes within directly to the Proxy
18+
# caller without interpreting it.
19+
base64Wrapped: bool = None
1520
headers: Dict[str, str] = None
1621

1722
T = TypeVar('T')
@@ -31,7 +36,7 @@ def __init__(
3136
data: any = None,
3237
string: str = None,
3338
json: Any = None,
34-
bytes: io.BytesIO = None,
39+
bytes: Union[bytes, io.BytesIO] = None,
3540
mimeType = None
3641
):
3742
# Note:
@@ -44,7 +49,7 @@ def __init__(
4449

4550
# Handle the core data
4651
try:
47-
data, mimeType = flexi_create(
52+
data, mimeType, encoding = flexi_create(
4853
data=data,
4954
string=string,
5055
json=json,
@@ -54,17 +59,27 @@ def __init__(
5459

5560
self.data = data
5661

57-
# Set the mime type if not already set
62+
if mimeType is None:
63+
mimeType = MimeTypes.BINARY
64+
5865
if mimeType is not None:
66+
if self.http.headers is None:
67+
self.http.headers = dict()
5968
self.http.headers["Content-Type"] = mimeType
69+
70+
if encoding == ContentEncodings.BASE64:
71+
self.http.base64Wrapped = True
72+
6073
except Exception as ex:
74+
logging.error("Exception within Response.__init__. {}".format(ex))
6175
if error is not None:
6276
if error.message:
6377
error.message = "{}. Also found error - unable to serialize data to response. {}".format(error.message, ex)
6478
else:
6579
error.message = "Unable to serialize data to response. {}".format(ex)
6680
else:
6781
error = SteamshipError(message="Unable to serialize data to response. {}".format(ex))
82+
logging.error(error)
6883

6984
# Handle the task provided
7085
if status is None:

src/steamship/base/binary_utils.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import dataclasses
33
import io
44
import json as jsonlib
5-
from typing import Any, Tuple
5+
import logging
6+
from typing import Any, Tuple, Union
7+
from steamship.base.error import SteamshipError
68

7-
from steamship.base.mime_types import MimeTypes
9+
from steamship.base.mime_types import MimeTypes, ContentEncodings
810

911

1012
def guess_mime(obj: Any, provided_mime: str = None) -> str:
@@ -14,15 +16,24 @@ def guess_mime(obj: Any, provided_mime: str = None) -> str:
1416
return MimeTypes.TXT
1517
return MimeTypes.BINARY
1618

19+
def to_b64(obj: Any) -> str:
20+
ret_bytes = obj
21+
if type(obj) == bytes:
22+
ret_bytes = obj
23+
elif type(obj) == str:
24+
ret_bytes = ret_bytes.encode('utf-8')
25+
else:
26+
ret_bytes = str(obj).encode('utf-8')
27+
return base64.b64encode(ret_bytes).decode('utf-8')
1728

1829
def flexi_create(
1930
base64string: str = None,
2031
data: Any = None,
2132
string: str = None,
2233
json: Any = None,
23-
bytes: io.BytesIO = None,
34+
bytes: Union[bytes, io.BytesIO] = None,
2435
mimeType=None,
25-
alwaysBase64=False) -> Tuple[Any, str]:
36+
alwaysBase64=False) -> Tuple[Any, Union[None, str], Union[None, str]]:
2637
"""
2738
It's convenient for some constructors to accept a variety of input types:
2839
- data (your chocie)
@@ -33,38 +44,46 @@ def flexi_create(
3344
.. And have them all homogenized.
3445
"""
3546

36-
if base64string is not None:
37-
return base64string, mimeType or MimeTypes.BINARY
47+
try:
48+
if base64string is not None:
49+
logging.error("B64")
50+
return base64string, mimeType or MimeTypes.BINARY, ContentEncodings.BASE64
3851

39-
ret_data = None
40-
ret_mime = None
52+
ret_data = None # the body of the result
53+
ret_mime = None # for the Content-Type field
54+
ret_encoding = None # for the Content-Encoding field
55+
is_b64 = False
4156

42-
if data is not None:
43-
ret_data, ret_mime = data, guess_mime(data, mimeType)
57+
if data is not None:
58+
ret_data, ret_mime = data, mimeType or guess_mime(data, mimeType)
4459

45-
elif string is not None:
46-
ret_data, ret_mime = string, mimeType or MimeTypes.TXT
60+
elif string is not None:
61+
ret_data, ret_mime = string, mimeType or MimeTypes.TXT
4762

48-
elif json is not None:
49-
if dataclasses.is_dataclass(json):
50-
ret_data, ret_mime = jsonlib.dumps(dataclasses.asdict(json)), mimeType or MimeTypes.JSON
51-
else:
52-
ret_data, ret_mime = jsonlib.dumps(json), mimeType or MimeTypes.JSON
63+
elif json is not None:
64+
if dataclasses.is_dataclass(json):
65+
ret_data, ret_mime = dataclasses.asdict(json), mimeType or MimeTypes.JSON
66+
else:
67+
ret_data, ret_mime = json, mimeType or MimeTypes.JSON
5368

54-
if ret_data is not None:
55-
if alwaysBase64 is False:
56-
return ret_data, ret_mime
69+
elif bytes is not None:
70+
if isinstance(bytes, io.BytesIO):
71+
bytes = bytes.getvalue() # Turn it into regular bytes
72+
ret_data, ret_mime = base64.b64encode(bytes).decode('utf-8'), mimeType or ret_mime or MimeTypes.BINARY
73+
is_b64 = True
74+
ret_encoding = ContentEncodings.BASE64
5775

58-
ret_bytes = ret_data
59-
if type(ret_data) == bytes:
60-
ret_bytes = ret_data
61-
elif type(ret_data) == str:
62-
ret_bytes = ret_bytes.encode('utf-8')
63-
else:
64-
ret_bytes = str(ret_data).encode('utf-8')
65-
return base64.b64encode(ret_bytes).decode('utf-8'), ret_mime or MimeTypes.BINARY
76+
if ret_data is not None:
77+
logging.error("had ret data")
78+
if alwaysBase64 is False:
79+
return ret_data, ret_mime, ret_encoding
80+
if is_b64 is True:
81+
return ret_data, ret_mime, ContentEncodings.BASE64
82+
else:
83+
return to_b64(ret_data), ret_mime or MimeTypes.BINARY, ContentEncodings.BASE64
6684

67-
if bytes is not None:
68-
return base64.b64encode(bytes).decode('utf-8'), mimeType or MimeTypes.BINARY
69-
70-
return None, None
85+
return None, None, None
86+
except Exception as ex:
87+
logging.error("Exception thrown trying to encode data")
88+
logging.error(ex)
89+
raise SteamshipError(message="There was an exception thrown while trying to encode your app/plugin data.", error=ex)

src/steamship/base/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,9 @@ def call(
248248
url = self._url(
249249
appCall=appCall,
250250
appOwner=appOwner,
251-
operation=operation
251+
operation=operation,
252252
)
253+
253254
headers = self._headers(
254255
spaceId=spaceId,
255256
spaceHandle=spaceHandle,

src/steamship/base/mime_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class MimeTypes:
1717
RTF = "application/rtf"
1818
BINARY = "application/octet-stream"
1919

20+
class ContentEncodings:
21+
BASE64 = "base64"
2022

2123
TEXT_MIME_TYPES = [
2224
MimeTypes.TXT,

src/steamship/base/tasks.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,14 @@ def update(self, other: "Task"):
291291
self.maxRetries = None
292292
self.retries = None
293293

294-
def add_comment(self, externalId: str = None, externalType: str = None, externalGroup: str = None,
295-
metadata: any = None, upsert: bool = True) -> IResponse[TaskComment]:
294+
def add_comment(
295+
self,
296+
externalId: str = None,
297+
externalType: str = None,
298+
externalGroup: str = None,
299+
metadata: any = None,
300+
upsert: bool = True
301+
) -> IResponse[TaskComment]:
296302
return TaskComment.create(
297303
client=self.client,
298304
taskId=self.taskId,

src/steamship/data/app_instance.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from dataclasses import dataclass
22
from typing import Dict
33

4+
from steamship.data.space import Space
45
from steamship.base import Client, Request
56

67

@@ -32,6 +33,7 @@ class AppInstance:
3233
invocationURL: str = None
3334
config: Dict[str, any] = None
3435
spaceId: str = None
36+
spaceHandle: str = None
3537

3638
@staticmethod
3739
def from_dict(d: any, client: Client = None) -> "AppInstance":
@@ -49,7 +51,8 @@ def from_dict(d: any, client: Client = None) -> "AppInstance":
4951
userId=d.get('userId', None),
5052
invocationURL=d.get('invocationURL', None),
5153
config= d.get('config', None),
52-
spaceId= d.get('spaceId', None)
54+
spaceId= d.get('spaceId', None),
55+
spaceHandle= d.get('spaceHandle', None)
5356
)
5457

5558
@staticmethod
@@ -86,11 +89,23 @@ def delete(self) -> "AppInstance":
8689
expect=AppInstance
8790
)
8891

92+
def load_missing_vals(self):
93+
if self.client is not None and self.spaceHandle is None and self.spaceId is not None:
94+
# Get the spaceHandle
95+
space = Space.get(self.client, id=self.spaceId)
96+
if space and space.data:
97+
self.spaceHandle = space.data.handle
98+
8999
def get(self, path: str, **kwargs):
100+
self.load_missing_vals()
90101
if path[0] == '/':
91102
path = path[1:]
92103
return self.client.get(
93-
'/_/_/{}'.format(path),
104+
'/{}/{}/{}'.format(
105+
self.spaceHandle or "/",
106+
self.handle or "/",
107+
path
108+
),
94109
payload=kwargs,
95110
appCall=True,
96111
appOwner=self.userHandle,
@@ -100,10 +115,15 @@ def get(self, path: str, **kwargs):
100115
)
101116

102117
def post(self, path: str, **kwargs):
118+
self.load_missing_vals()
103119
if path[0] == '/':
104120
path = path[1:]
105121
return self.client.post(
106-
'/_/_/{}'.format(path),
122+
'/{}/{}/{}'.format(
123+
self.spaceHandle or "/",
124+
self.handle or "/",
125+
path
126+
),
107127
payload=kwargs,
108128
appCall=True,
109129
appOwner=self.userHandle,

src/steamship/data/file.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def __init__(
173173
json: io.BytesIO = None,
174174
mimeType: str = None
175175
):
176-
data, mimeType = flexi_create(
176+
data, mimeType, encoding = flexi_create(
177177
data=data,
178178
string=string,
179179
json=json,

0 commit comments

Comments
 (0)