Skip to content

Commit

Permalink
add form parsing test
Browse files Browse the repository at this point in the history
  • Loading branch information
okigan committed Mar 15, 2024
1 parent dc25c12 commit 9d622e8
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 26 deletions.
54 changes: 28 additions & 26 deletions awscurl/awscurl.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import sys
import re

from typing import IO, List, Optional, Tuple, Union
from typing import IO, Dict, List, Optional, Tuple, Union
import urllib
from urllib.parse import quote

Expand Down Expand Up @@ -434,53 +434,55 @@ def load_aws_config(access_key, secret_key, security_token, credentials_path, pr
return access_key, secret_key, security_token


def __process_form_data(form_data: List[str]) -> Optional[List[Tuple[str, Union[str, Tuple[str, Union[IO, Tuple[IO, str]]]]]]]:
def process_form_data(form_data: List[str]) -> Dict[str, Union[Tuple[str, IO[bytes]], Tuple[str, IO[bytes], str], Tuple[str, IO[bytes], str, Dict[str, str]]]]:
"""
Process form data to prepare files for uploading with optional MIME types,
supporting specific form field names for each file.
Process form data to prepare files for uploading, supporting specific form field names for each file
and accommodating the `requests` library files parameter format. This function is intended for internal
use within this module.
Args:
form_data (list of str): Each string in the list should be formatted as
'fieldname=@filepath[;type=mimetype]'.
form_data: Each string in the list should be formatted as 'fieldname=@filepath[;type=mimetype]'.
Examples:
- Simple file upload with field name:
'[email protected]'
This will upload a file located at 'portrait.jpg' with the field name 'profile'.
- Simple file upload with field name: '[email protected]'
This will upload a file located at 'portrait.jpg' under the field name 'profile'.
- File upload with field name and MIME type:
'[email protected];type=application/pdf'
- File upload with field name and MIME type: '[email protected];type=application/pdf'
This uploads 'report.pdf' as 'document', with an explicit MIME type 'application/pdf'.
- Multiple file uploads:
['[email protected]', '[email protected];type=application/msword']
- Multiple file uploads: ['[email protected]', '[email protected];type=application/msword']
This example shows how to upload multiple files with different field names and specifying
MIME type for one of the files.
Returns:
list of tuple: A list where each tuple represents a file to be uploaded. Each tuple is
(fieldname, filetuple), where 'filetuple' is either (filepath, fileobject)
or (filepath, (fileobject, mimetype)) if a MIME type is specified.
A dictionary where keys are the form field names and the values are file-tuples compatible
with the `requests` library. The file-tuple can be a 2-tuple ('filename', fileobj),
3-tuple ('filename', fileobj, 'content_type'), or a 4-tuple
('filename', fileobj, 'content_type', custom_headers) if additional headers are needed.
"""
files: Dict[str, Union[Tuple[str, IO[bytes]], Tuple[str, IO[bytes], str], Tuple[str, IO[bytes], str, Dict[str, str]]]] = {}

if form_data is None:
return None
return files

files = []
for file_arg in form_data:
# Splitting the argument into its components: field name, file path, and optional MIME type
parts = file_arg.split(';')
field_name, file_path = parts[0].split('=', 1)
file_path = file_path[1:] # Remove the '@' at the beginning
mime_type = None

# Look for an optional MIME type specification
for part in parts[1:]:
for part in parts:
if part.startswith('type='):
mime_type = part[5:]
mime_type = part.split('=', 1)[1]
break # Assuming only one MIME type specification, break after finding

file_obj: IO[bytes] = open(file_path, 'rb')
file_tuple: Union[Tuple[str, IO[bytes]], Tuple[str, IO[bytes], str]] = (file_path.split('/')[-1], file_obj)
if mime_type:
file_tuple = (file_path.split('/')[-1], file_obj, mime_type)

files[field_name] = file_tuple

# Adding the file to the list, including the MIME type if specified
file_tuple = (file_path, (open(file_path, 'rb'), mime_type)) if mime_type else (file_path, open(file_path, 'rb'))
files.append((field_name, file_tuple))
return files


Expand Down Expand Up @@ -546,7 +548,7 @@ def inner_main(argv):
with open(filename, read_mode) as post_data_file:
data = post_data_file.read()

files = __process_form_data(args.form)
files = process_form_data(args.form)

if args.header is None:
args.header = default_headers
Expand Down
44 changes: 44 additions & 0 deletions tests/form_parsing_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python


from unittest import TestCase

from awscurl import awscurl

__author__ = 'iokulist'

import unittest
from typing import Dict, Tuple, Union, IO
from awscurl.awscurl import process_form_data

class TestProcessFormData(unittest.TestCase):
def test_single_file_upload(self):
form_data = ['[email protected]']
result = process_form_data(form_data)
self.assertIn('profile', result)
self.assertTrue(isinstance(result['profile'], Tuple))
self.assertEqual(result['profile'][0], 'README.md')

def test_file_upload_with_mime(self):
form_data = ['[email protected];type=application/pdf']
result = process_form_data(form_data)
self.assertIn('document', result)
self.assertTrue(isinstance(result['document'], Tuple))
self.assertEqual(result['document'][0], 'README.md')
self.assertEqual(result['document'][2], 'application/pdf')

def test_multiple_file_uploads(self):
form_data = [
'[email protected]',
'resume=@LICENSE;type=application/vnd.openxmlformats-officedocument.wordprocessingml.document'
]
result = process_form_data(form_data)
self.assertIn('photo', result)
self.assertIn('resume', result)
self.assertTrue(isinstance(result['photo'], Tuple))
self.assertTrue(isinstance(result['resume'], Tuple))
self.assertEqual(result['resume'][2], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')

if __name__ == '__main__':
unittest.main()

0 comments on commit 9d622e8

Please sign in to comment.