swagger-api / swagger-api/swagger-codegen

[python] ApiClient.prepare_post_parameters should allow for FileStorage objects in addition to file paths

Open
#7,531 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

Description

The python/flask-generate server code uses a FileStorage object to represent uploaded files.

My endpoint is supposed to call a subsequent API on another server and forward the same uploaded file, and do do this is uses an api_client as generated by the python client templates. I would like to be able to pass the FileStorage object to the api_client directly, without having to save it out to a file and then load it back in. (For one thing, if the file is small enough, the data resides in memory, but more importantly, if the file is large, then saving it off and loading it back in would result in multiple copies of the uploaded file).

However, the prepare_post_parameters expects the files parameter to be a list of objects that can be opened via an open() call. A FileStorage object is not such an object, as it's already open and ready for reading.

A simple fix would be to add a check to the file so that if it's a FileStorage object, don't bother opening it and instead just use the information available. The added benefit is that we wouldn't need to guess at the mimetype, as it would be available as a property of the object.

Swagger-codegen version

2.3.0

Swagger declaration file content or url
Command line used for generation
Steps to reproduce
Related issues/PRs
Suggest a fix/enhancement

The following would be a workable change, I think.

def prepare_post_parameters(self, post_params=None, files=None):
    """Builds form parameters.
    
    :param post_params: Normal form parameters.
    :param files: File parameters.
    :return: Form parameters with files.
    """
    params = []
    
    if post_params:
        params = post_params
    
    if files:
        for k, v in six.iteritems(files):
            if not v:
                continue
            file_names = v if type(v) is list else [v]
            for n in file_names:
                if (type(n) is FileStorage):
                    filename = n.filename
                    filedata = n.read()
                    mimetype = n.mimetype
                    params.append(
                        tuple([k, tuple([filename, filedata, mimetype])]))
                else:
                    with open(n, 'rb') as f:
                        filename = os.path.basename(f.name)
                        filedata = f.read()
                        mimetype = (mimetypes.guess_type(filename)[0] or
                                    'application/octet-stream')
                        params.append(
                            tuple([k, tuple([filename, filedata, mimetype])]))
    
    return params

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the Python client template's ApiClient.prepare_post_parameters entry point and review how its files parameter currently handles file paths. Done means FileStorage objects can be forwarded using their filename, data, and mimetype while existing file-path handling continues to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
flask, python
Domain
api, backend
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.