如何使用Flask test_client上传多个文件?

时间:2017-11-10 05:28:44

标签: python flask python-unittest web-api-testing multiple-file-upload

如何使用Flask test_client将多个文件上传到一个API端点?

我尝试使用Flask test_client将多个文件上传到接受多个文件的Web服务,以将它们合并为一个大文件。

我的控制器看起来像这样:

@app.route("/combine/file", methods=["POST"])
@flask_login.login_required
def combine_files():

  user = flask_login.current_user

  combined_file_name = request.form.get("file_name")

  # Store file locally
  file_infos = []
  for file_data in request.files.getlist('file[]'):

    # Get the content of the file
    file_temp_path="/tmp/{}-request.csv".format(file_id)
    file_data.save(file_temp_path)

    # Create a namedtuple with information about the file
    FileInfo = namedtuple("FileInfo", ["id", "name", "path"])
    file_infos.append(
      FileInfo(
        id=file_id,
        name=file_data.filename,
        path=file_temp_path
      )
    )
    ...

我的测试代码如下:

def test_combine_file(get_project_files):

project = get_project_files["project"]

r = web_client.post(
    "/combine/file",
    content_type='multipart/form-data',
    buffered=True,
    follow_redirects=True,
    data={
        "project_id": project.project_id,
        "file_name": "API Test Combined File",
        "file": [
            (open("data/CC-Th0-MolsPerCell.csv", "rb"), "CC-Th0-MolsPerCell.csv"),
            (open("data/CC-Th1-MolsPerCell.csv", "rb"), "CC-Th1-MolsPerCell.csv")
]})
response_data = json.loads(r.data)

assert "status" in response_data
assert response_data["status"] == "OK"

但是,我无法让test_client实际上传这两个文件。如果指定了多个文件,则在API代码循环时file_data为空。我用两个"文件"尝试了我自己的ImmutableDict。条目,文件元组列表,文件元组元组,我能想到的任何东西。

在Flask test_client中指定多个要上传的文件的API有哪些?我无法在网络上找到这个! :(

3 个答案:

答案 0 :(得分:2)

执行此操作的另一种方法-如果要在此处显式命名文件上传(我的用例是使用两个CSV,但可以是任何东西),则使用test_client就像这样:

   resp = test_client.post(
                           '/data_upload_api', # flask route
                           file_upload_one=[open(FILE_PATH, 'rb')],
                           file_upload_two=[open(FILE_PATH_2, 'rb')]
                           )

使用此语法,可以通过以下方式访问这些文件:

request.files['file_upload_one'] # etc.

答案 1 :(得分:1)

测试客户端获取文件对象列表(由open()返回),因此这是我使用的测试实用程序:

def multi_file_upload(test_client, src_file_paths, dest_folder):
    files = []
    try:
        files = [open(fpath, 'rb') for fpath in src_file_paths]
        return test_client.post('/api/upload/', data={
            'files': files,
            'dest': dest_folder
        })
    finally:
        for fp in files:
            fp.close()

我认为如果你丢失了元组(但保留open() s),那么你的代码可能会有效。

答案 2 :(得分:1)

您应该只发送带有您想要的文件名的数据对象:

test_client.post('/api/upload', 
                 data={'title': 'upload sample', 
                       'file1': (io.BytesIO(b'get something'), 'file1'), 
                       'file2': (io.BytesIO(b'forthright'), 'file2')},  
                 content_type='multipart/form-data')