Skip to content

Commit 3f05339

Browse files
committed
servicex codegen to return transformer image and tag
1 parent 3904300 commit 3f05339

File tree

5 files changed

+116
-17
lines changed

5 files changed

+116
-17
lines changed

poetry.lock

Lines changed: 21 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Flask-WTF = "^1.0.1"
1414
itsdangerous = "^2.1.2"
1515
Werkzeug = "^2.2.2"
1616
Jinja2 = "^3.1.2"
17+
requests-toolbelt = "^0.10.1"
1718

1819
[tool.poetry.group.test]
1920
optional = true

servicex_codegen/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@
3333
#
3434
import os
3535

36-
from flask import Flask
36+
from flask import Flask, jsonify
3737
from flask_restful import Api
38+
3839
from servicex_codegen.post_operation import GeneratedCode
3940

4041

4142
def handle_invalid_usage(error: BaseException):
42-
from flask import jsonify
4343
response = jsonify({"message": str(error)})
4444
response.status_code = 400
4545
return response

servicex_codegen/post_operation.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import zipfile
3636
from tempfile import TemporaryDirectory
3737

38-
from flask import request, Response
38+
from flask import Response, current_app, request
3939
from flask_restful import Resource
40+
from requests_toolbelt import MultipartEncoder
41+
4042
from servicex_codegen.code_generator import CodeGenerator, GeneratedFileResult
4143

4244

@@ -83,18 +85,29 @@ def stream_generated_code(self, generated_code_result: GeneratedFileResult) -> b
8385
def post(self):
8486
try:
8587
with TemporaryDirectory() as tempdir:
86-
code = request.data.decode('utf8')
87-
generated_code_result = self.code_generator.generate_code(code, cache_path=tempdir)
88+
body = request.get_json()
89+
generated_code_result = self.code_generator.generate_code(
90+
body["code"], cache_path=tempdir)
8891

8992
zip_data = self.stream_generated_code(generated_code_result)
93+
transformer_image = body["transformer_image"] if "transformer_image" in body else current_app.config.get(
94+
"DEFAULT_TRANSFORMER_IMAGE")
95+
transformer_tag = body["transformer_tag"] if "transformer_tag" in body else current_app.config.get(
96+
"DEFAULT_TRANSFORMER_TAG")
9097
# Send the response back to you-know-what.
98+
99+
m = MultipartEncoder(
100+
fields={'transformer_image': transformer_image, 'transformer_tag': transformer_tag,
101+
'zip_data': zip_data}
102+
)
103+
91104
response = Response(
92-
response=zip_data,
93-
status=200, mimetype='application/octet-stream')
105+
response=m.to_string(),
106+
status=200, mimetype=m.content_type)
94107
return response
95108
except BaseException as e:
96109
print(str(e))
97-
import traceback
98110
import sys
111+
import traceback
99112
traceback.print_exc(file=sys.stdout)
100113
return {'Message': str(e)}, 500

tests/test_post_operation.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import os
3030
import zipfile
3131
from tempfile import TemporaryDirectory
32+
from unittest.mock import patch
3233

34+
from requests_toolbelt.multipart import decoder
3335
from servicex_codegen import create_app
3436
from servicex_codegen.code_generator import (GenerateCodeException,
3537
GeneratedFileResult)
@@ -51,7 +53,7 @@ def check_zip_file(zip_data: bytes, expected_file_count):
5153

5254

5355
class TestPostOperation:
54-
def test_post_good_query(self, mocker):
56+
def test_post_good_query_with_params(self, mocker):
5557
"""Produce code for a simple good query"""
5658

5759
with TemporaryDirectory() as tempdir, \
@@ -68,11 +70,79 @@ def test_post_good_query(self, mocker):
6870
}
6971
app = create_app(config, provided_translator=mock_ast_translator)
7072
client = app.test_client()
73+
74+
print(app.config)
75+
76+
select_stmt = "(call ResultTTree (call Select (call SelectMany (call EventDataset (list 'localds://did_01')" # noqa: E501
77+
78+
response = client.post("/servicex/generated-code", json={
79+
"transformer_image": "sslhep/servicex_func_adl_xaod_transformer",
80+
"transformer_tag": "develop",
81+
"code": select_stmt
82+
})
83+
84+
boundary = str(response.data[2:34], 'utf-8')
85+
content_type = f"multipart/form-data; boundary={boundary}"
86+
decoder_parts = decoder.MultipartDecoder(response.data, content_type)
87+
88+
transformer_image = str(decoder_parts.parts[0].content, 'utf-8')
89+
transformer_tag = str(decoder_parts.parts[1].content, 'utf-8')
90+
zip_file = decoder_parts.parts[2].content
91+
92+
print("Transformer Image: ", transformer_image)
93+
print("Transformer Tag: ", transformer_tag)
94+
print("Zip File: ", zip_file)
95+
96+
assert response.status_code == 200
97+
check_zip_file(zip_file, 2)
98+
# Capture the temporary directory that was generated
99+
cache_dir = mock_ast_translator.generate_code.call_args[1]['cache_path']
100+
mock_ast_translator.generate_code.assert_called_with(select_stmt,
101+
cache_path=cache_dir)
102+
103+
def test_post_good_query_without_params(self, mocker):
104+
"""Produce code for a simple good query"""
105+
106+
with TemporaryDirectory() as tempdir, \
107+
open(os.path.join(tempdir, "baz.txt"), 'w'),\
108+
open(os.path.join(tempdir, "foo.txt"), 'w'):
109+
110+
mock_ast_translator = mocker.Mock()
111+
mock_ast_translator.generate_code = mocker.Mock(
112+
return_value=GeneratedFileResult(hash="1234", output_dir=tempdir)
113+
)
114+
115+
config = {
116+
'TARGET_BACKEND': 'uproot',
117+
'DEFAULT_TRANSFORMER_IMAGE': 'sslhep/servicex_func_adl_xaod_transformer',
118+
'DEFAULT_TRANSFORMER_TAG': 'develop'
119+
}
120+
121+
app = create_app(config, provided_translator=mock_ast_translator)
122+
client = app.test_client()
123+
124+
print(app.config)
125+
71126
select_stmt = "(call ResultTTree (call Select (call SelectMany (call EventDataset (list 'localds://did_01')" # noqa: E501
72127

73-
response = client.post("/servicex/generated-code", data=select_stmt)
128+
response = client.post("/servicex/generated-code", json={
129+
"code": select_stmt
130+
})
131+
132+
boundary = str(response.data[2:34], 'utf-8')
133+
content_type = f"multipart/form-data; boundary={boundary}"
134+
decoder_parts = decoder.MultipartDecoder(response.data, content_type)
135+
136+
transformer_image = str(decoder_parts.parts[0].content, 'utf-8')
137+
transformer_tag = str(decoder_parts.parts[1].content, 'utf-8')
138+
zip_file = decoder_parts.parts[2].content
139+
140+
print("Transformer Image: ", transformer_image)
141+
print("Transformer Tag: ", transformer_tag)
142+
print("Zip File: ", zip_file)
143+
74144
assert response.status_code == 200
75-
check_zip_file(response.data, 2)
145+
check_zip_file(zip_file, 2)
76146
# Capture the temporary directory that was generated
77147
cache_dir = mock_ast_translator.generate_code.call_args[1]['cache_path']
78148
mock_ast_translator.generate_code.assert_called_with(select_stmt,

0 commit comments

Comments
 (0)