Handle upload bugfix (#886)

This commit is contained in:
Elijah Ahianyo 2023-04-26 19:56:34 +00:00 committed by GitHub
parent 24c08d6ee0
commit 5ad3882898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 169 additions and 13 deletions

View File

@ -504,10 +504,14 @@ def upload(app: App):
# Get the state for the session.
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 = ()
# 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]
for k, v in inspect.getfullargspec(

View File

@ -244,6 +244,129 @@ def upload_state(tmp_path):
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
def base_config_values() -> Dict:
"""Get base config values.

View File

@ -412,11 +412,38 @@ async def test_dict_mutation_detection__plain_list(
@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.
Args:
upload_state: the state
fixture: The state.
request: Fixture request.
expected: Expected delta
"""
data = b"This is binary data"
@ -424,7 +451,7 @@ async def test_upload_file(upload_state):
bio = io.BytesIO()
bio.write(data)
app = App(state=upload_state)
app = App(state=request.getfixturevalue(fixture))
file1 = UploadFile(
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)
result = await fn([file1, file2]) # type: ignore
assert isinstance(result, StateUpdate)
assert result.delta == {
"file_upload_state": {"img_list": ["image1.jpg", "image2.jpg"]}
}
assert result.delta == expected
@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].
Args:
upload_state: the state
fixture: The state.
request: Fixture request.
"""
data = b"This is binary data"
@ -457,15 +486,15 @@ async def test_upload_file_without_annotation(upload_state):
bio = io.BytesIO()
bio.write(data)
app = App(state=upload_state)
app = App(state=request.getfixturevalue(fixture))
file1 = UploadFile(
filename="token:upload_state.handle_upload2:True:image1.jpg",
filename="token:file_upload_state.handle_upload2:True:image1.jpg",
file=bio,
content_type="image/jpeg",
)
file2 = UploadFile(
filename="token:upload_state.handle_upload2:True:image2.jpg",
filename="token:file_upload_state.handle_upload2:True:image2.jpg",
file=bio,
content_type="image/jpeg",
)
@ -474,5 +503,5 @@ async def test_upload_file_without_annotation(upload_state):
await fn([file1, file2])
assert (
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]"
)