Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/SDK/Language/Python.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,12 @@ public function getFiles()
'template' => 'python/package/exception.py.twig',
'minify' => false,
],
[
'scope' => 'default',
'destination' => '{{ spec.title | caseSnake}}/input_file.py',
'template' => 'python/package/input_file.py.twig',
'minify' => false,
],
[
'scope' => 'default',
'destination' => '{{ spec.title | caseSnake}}/service.py',
Expand Down
55 changes: 53 additions & 2 deletions templates/python/package/client.py.twig
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import io
import requests
import os
from .input_file import InputFile
from .exception import {{spec.title | caseUcfirst}}Exception

class Client:
def __init__(self):
self._chunk_size = 5*1024*1024
self._self_signed = False
self._endpoint = '{{spec.endpoint}}'
self._global_headers = {
Expand Down Expand Up @@ -61,8 +64,8 @@ class Client:
del headers['content-type']

for key in data.copy():
if isinstance(data[key], io.BufferedIOBase):
files[key] = data[key]
if isinstance(data[key], InputFile):
files[key] = (data[key].name, data[key].file)
del data[key]
response = None
try:
Expand Down Expand Up @@ -95,6 +98,54 @@ class Client:
else:
raise {{spec.title | caseUcfirst}}Exception(e)

def chunked_upload(
self,
path,
headers = None,
params = None,
param_name = '',
on_progress = None,
):
file_path = str(params[param_name])
file_name = os.path.basename(file_path)
size = os.stat(file_path).st_size

if size < self._chunk_size:
slice = open(file_path, 'rb').read()
params[param_name] = InputFile(file_path, file_name, slice)
return self.call(
'post',
path,
headers,
params
)

input = open(file_path, 'rb')
offset = 0

while offset < size:
slice = input.read(self._chunk_size) or input.read(size - offset)

params[param_name] = InputFile(file_path, file_name, slice)
headers["content-range"] = f'bytes {offset}-{min((offset + self._chunk_size) - 1, size)}/{size}'

result = self.call(
'post',
path,
headers,
params,
)

offset = offset + self._chunk_size

if "$id" in result:
headers["x-{{ spec.title | caseLower }}-id"] = result["$id"]

if on_progress is not None:
on_progress(min(offset, size)/size * 100)

return result

def flatten(self, data, prefix=''):
output = {}
i = 0
Expand Down
5 changes: 5 additions & 0 deletions templates/python/package/input_file.py.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class InputFile:
def __init__(self, path, name, file):
self.path = path
self.name = name
self.file = file
19 changes: 18 additions & 1 deletion templates/python/package/services/service.py.twig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class {{ service.name | caseUcfirst }}(Service):
super({{ service.name | caseUcfirst }}, self).__init__(client)
{% for method in service.methods %}

def {{ method.name | caseSnake }}(self{% if method.parameters.all|length > 0 %}, {% endif %}{% for parameter in method.parameters.all %}{{ parameter.name | escapeKeyword | caseSnake }}{% if not parameter.required %} = None{% endif %}{% if not loop.last %}, {% endif %}{% endfor %}):
def {{ method.name | caseSnake }}(self{% if method.parameters.all|length > 0 %}, {% endif %}{% for parameter in method.parameters.all %}{{ parameter.name | escapeKeyword | caseSnake }}{% if not parameter.required %} = None{% endif %}{% if not loop.last %}, {% endif %}{% endfor %}{% if 'multipart/form-data' in method.consumes %}, on_progress = None{% endif %}):
{% if method.title %}
"""{{ method.title }}"""

Expand Down Expand Up @@ -40,6 +40,22 @@ class {{ service.name | caseUcfirst }}(Service):
params['{{ parameter.name }}'] = {{ parameter.name | escapeKeyword | caseSnake }}

{% endfor %}
{% if 'multipart/form-data' in method.consumes %}
{% for parameter in method.parameters.all %}
{% if parameter.type == 'file' %}
param_name = '{{ parameter.name }}'

{% endif %}
{% endfor %}
return self.client.chunked_upload(path, {
{% for parameter in method.parameters.header %}
'{{ parameter.name }}': {{ parameter.name | escapeKeyword | caseSnake }},
{% endfor %}
{% for key, header in method.headers %}
'{{ key }}': '{{ header }}',
{% endfor %}
}, params, param_name, on_progress)
{% else %}
return self.client.call('{{ method.method | caseLower }}', path, {
{% for parameter in method.parameters.header %}
'{{ parameter.name }}': {{ parameter.name | escapeKeyword | caseSnake }},
Expand All @@ -48,4 +64,5 @@ class {{ service.name | caseUcfirst }}(Service):
'{{ key }}': '{{ header }}',
{% endfor %}
}, params)
{% endif %}
{% endfor %}
9 changes: 5 additions & 4 deletions tests/SDKTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,18 +289,19 @@ class SDKTest extends TestCase
'build' => [
'cp tests/languages/python/tests.py tests/sdks/python/test.py',
'echo "" > tests/sdks/python/__init__.py',
'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor python:3.8 pip install -r tests/sdks/python/requirements.txt --upgrade',
'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor python:3.10-alpine pip install -r tests/sdks/python/requirements.txt --upgrade',
],
'envs' => [
'python-3.9' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.8-alpine python tests/sdks/python/test.py',
'python-3.8' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.7-alpine python tests/sdks/python/test.py',
'python-3.10' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.10-alpine python tests/sdks/python/test.py',
'python-3.9' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.9-alpine python tests/sdks/python/test.py',
'python-3.8' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.8-alpine python tests/sdks/python/test.py',
'python-3.7' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.7-alpine python tests/sdks/python/test.py',
'python-3.6' => 'docker run --rm -v $(pwd):/app -w /app --env PIP_TARGET=tests/sdks/python/vendor --env PYTHONPATH=tests/sdks/python/vendor python:3.7-alpine python tests/sdks/python/test.py',
],
'expectedOutput' => [
...FOO_RESPONSES,
...BAR_RESPONSES,
...GENERAL_RESPONSES,
'POST:/v1/mock/tests/general/upload:passed',
...EXCEPTION_RESPONSES,
],
],
Expand Down
5 changes: 4 additions & 1 deletion tests/languages/python/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@
response = general.redirect()
print(response['result'])

response = general.upload('string', 123, ['string in array'], open('./tests/resources/file.png', 'rb'))
response = general.upload('string', 123, ['string in array'], './tests/resources/file.png')
print(response['result'])

response = general.upload('string', 123, ['string in array'], './tests/resources/large_file.mp4')
print(response['result'])

try:
Expand Down
Binary file added tests/resources/large_file.mp4
Binary file not shown.