Handle upload bugfix (#886)
This commit is contained in:
parent
24c08d6ee0
commit
5ad3882898
@ -504,10 +504,14 @@ def upload(app: App):
|
|||||||
|
|
||||||
# Get the state for the session.
|
# Get the state for the session.
|
||||||
state = app.state_manager.get_state(token)
|
state = app.state_manager.get_state(token)
|
||||||
|
|
||||||
|
# get the current state(parent state/substate)
|
||||||
|
path = handler.split(".")[:-1]
|
||||||
|
current_state = state.get_substate(path)
|
||||||
handler_upload_param: Tuple = ()
|
handler_upload_param: Tuple = ()
|
||||||
|
|
||||||
# get handler function
|
# get handler function
|
||||||
func = getattr(state, handler.split(".")[-1])
|
func = getattr(current_state, handler.split(".")[-1])
|
||||||
|
|
||||||
# check if there exists any handler args with annotation, List[UploadFile]
|
# check if there exists any handler args with annotation, List[UploadFile]
|
||||||
for k, v in inspect.getfullargspec(
|
for k, v in inspect.getfullargspec(
|
||||||
|
@ -244,6 +244,129 @@ def upload_state(tmp_path):
|
|||||||
return FileUploadState
|
return FileUploadState
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def upload_sub_state(tmp_path):
|
||||||
|
"""Create upload substate.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tmp_path: pytest tmp_path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The state
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
class FileState(pc.State):
|
||||||
|
"""The base state."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FileUploadState(FileState):
|
||||||
|
"""The substate for uploading a file."""
|
||||||
|
|
||||||
|
img_list: List[str]
|
||||||
|
|
||||||
|
async def handle_upload2(self, files):
|
||||||
|
"""Handle the upload of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
files: The uploaded files.
|
||||||
|
"""
|
||||||
|
for file in files:
|
||||||
|
upload_data = await file.read()
|
||||||
|
outfile = f"{tmp_path}/{file.filename}"
|
||||||
|
|
||||||
|
# Save the file.
|
||||||
|
with open(outfile, "wb") as file_object:
|
||||||
|
file_object.write(upload_data)
|
||||||
|
|
||||||
|
# Update the img var.
|
||||||
|
self.img_list.append(file.filename)
|
||||||
|
|
||||||
|
async def multi_handle_upload(self, files: List[pc.UploadFile]):
|
||||||
|
"""Handle the upload of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
files: The uploaded files.
|
||||||
|
"""
|
||||||
|
for file in files:
|
||||||
|
upload_data = await file.read()
|
||||||
|
outfile = f"{tmp_path}/{file.filename}"
|
||||||
|
|
||||||
|
# Save the file.
|
||||||
|
with open(outfile, "wb") as file_object:
|
||||||
|
file_object.write(upload_data)
|
||||||
|
|
||||||
|
# Update the img var.
|
||||||
|
self.img_list.append(file.filename)
|
||||||
|
|
||||||
|
return FileUploadState
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def upload_grand_sub_state(tmp_path):
|
||||||
|
"""Create upload grand-state.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tmp_path: pytest tmp_path
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The state
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
class BaseFileState(pc.State):
|
||||||
|
"""The base state."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FileSubState(BaseFileState):
|
||||||
|
"""The substate."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FileUploadState(FileSubState):
|
||||||
|
"""The grand-substate for uploading a file."""
|
||||||
|
|
||||||
|
img_list: List[str]
|
||||||
|
|
||||||
|
async def handle_upload2(self, files):
|
||||||
|
"""Handle the upload of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
files: The uploaded files.
|
||||||
|
"""
|
||||||
|
for file in files:
|
||||||
|
upload_data = await file.read()
|
||||||
|
outfile = f"{tmp_path}/{file.filename}"
|
||||||
|
|
||||||
|
# Save the file.
|
||||||
|
with open(outfile, "wb") as file_object:
|
||||||
|
file_object.write(upload_data)
|
||||||
|
|
||||||
|
# Update the img var.
|
||||||
|
self.img_list.append(file.filename)
|
||||||
|
|
||||||
|
async def multi_handle_upload(self, files: List[pc.UploadFile]):
|
||||||
|
"""Handle the upload of a file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
files: The uploaded files.
|
||||||
|
"""
|
||||||
|
for file in files:
|
||||||
|
upload_data = await file.read()
|
||||||
|
outfile = f"{tmp_path}/{file.filename}"
|
||||||
|
|
||||||
|
# Save the file.
|
||||||
|
with open(outfile, "wb") as file_object:
|
||||||
|
file_object.write(upload_data)
|
||||||
|
|
||||||
|
# Update the img var.
|
||||||
|
self.img_list.append(file.filename)
|
||||||
|
|
||||||
|
return FileUploadState
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def base_config_values() -> Dict:
|
def base_config_values() -> Dict:
|
||||||
"""Get base config values.
|
"""Get base config values.
|
||||||
|
@ -412,11 +412,38 @@ async def test_dict_mutation_detection__plain_list(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_upload_file(upload_state):
|
@pytest.mark.parametrize(
|
||||||
|
"fixture, expected",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"upload_state",
|
||||||
|
{"file_upload_state": {"img_list": ["image1.jpg", "image2.jpg"]}},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"upload_sub_state",
|
||||||
|
{
|
||||||
|
"file_state.file_upload_state": {
|
||||||
|
"img_list": ["image1.jpg", "image2.jpg"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"upload_grand_sub_state",
|
||||||
|
{
|
||||||
|
"base_file_state.file_sub_state.file_upload_state": {
|
||||||
|
"img_list": ["image1.jpg", "image2.jpg"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_upload_file(fixture, request, expected):
|
||||||
"""Test that file upload works correctly.
|
"""Test that file upload works correctly.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
upload_state: the state
|
fixture: The state.
|
||||||
|
request: Fixture request.
|
||||||
|
expected: Expected delta
|
||||||
"""
|
"""
|
||||||
data = b"This is binary data"
|
data = b"This is binary data"
|
||||||
|
|
||||||
@ -424,7 +451,7 @@ async def test_upload_file(upload_state):
|
|||||||
bio = io.BytesIO()
|
bio = io.BytesIO()
|
||||||
bio.write(data)
|
bio.write(data)
|
||||||
|
|
||||||
app = App(state=upload_state)
|
app = App(state=request.getfixturevalue(fixture))
|
||||||
|
|
||||||
file1 = UploadFile(
|
file1 = UploadFile(
|
||||||
filename="token:file_upload_state.multi_handle_upload:True:image1.jpg",
|
filename="token:file_upload_state.multi_handle_upload:True:image1.jpg",
|
||||||
@ -439,17 +466,19 @@ async def test_upload_file(upload_state):
|
|||||||
fn = upload(app)
|
fn = upload(app)
|
||||||
result = await fn([file1, file2]) # type: ignore
|
result = await fn([file1, file2]) # type: ignore
|
||||||
assert isinstance(result, StateUpdate)
|
assert isinstance(result, StateUpdate)
|
||||||
assert result.delta == {
|
assert result.delta == expected
|
||||||
"file_upload_state": {"img_list": ["image1.jpg", "image2.jpg"]}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_upload_file_without_annotation(upload_state):
|
@pytest.mark.parametrize(
|
||||||
|
"fixture", ["upload_state", "upload_sub_state", "upload_grand_sub_state"]
|
||||||
|
)
|
||||||
|
async def test_upload_file_without_annotation(fixture, request):
|
||||||
"""Test that an error is thrown when there's no param annotated with pc.UploadFile or List[UploadFile].
|
"""Test that an error is thrown when there's no param annotated with pc.UploadFile or List[UploadFile].
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
upload_state: the state
|
fixture: The state.
|
||||||
|
request: Fixture request.
|
||||||
"""
|
"""
|
||||||
data = b"This is binary data"
|
data = b"This is binary data"
|
||||||
|
|
||||||
@ -457,15 +486,15 @@ async def test_upload_file_without_annotation(upload_state):
|
|||||||
bio = io.BytesIO()
|
bio = io.BytesIO()
|
||||||
bio.write(data)
|
bio.write(data)
|
||||||
|
|
||||||
app = App(state=upload_state)
|
app = App(state=request.getfixturevalue(fixture))
|
||||||
|
|
||||||
file1 = UploadFile(
|
file1 = UploadFile(
|
||||||
filename="token:upload_state.handle_upload2:True:image1.jpg",
|
filename="token:file_upload_state.handle_upload2:True:image1.jpg",
|
||||||
file=bio,
|
file=bio,
|
||||||
content_type="image/jpeg",
|
content_type="image/jpeg",
|
||||||
)
|
)
|
||||||
file2 = UploadFile(
|
file2 = UploadFile(
|
||||||
filename="token:upload_state.handle_upload2:True:image2.jpg",
|
filename="token:file_upload_state.handle_upload2:True:image2.jpg",
|
||||||
file=bio,
|
file=bio,
|
||||||
content_type="image/jpeg",
|
content_type="image/jpeg",
|
||||||
)
|
)
|
||||||
@ -474,5 +503,5 @@ async def test_upload_file_without_annotation(upload_state):
|
|||||||
await fn([file1, file2])
|
await fn([file1, file2])
|
||||||
assert (
|
assert (
|
||||||
err.value.args[0]
|
err.value.args[0]
|
||||||
== "`upload_state.handle_upload2` handler should have a parameter annotated as List[pc.UploadFile]"
|
== "`file_upload_state.handle_upload2` handler should have a parameter annotated as List[pc.UploadFile]"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user