0

I am trying to upload a file to a server, using python. The API of the server has to accept the file, together with some other parameters.

This is why i open the file, and then i create a dictionary, containing the file and the other parameters that the web app accepts, and then encode it and perform a POST request with the item.

This is the code:

from urllib import request
from urllib.parse import urlencode
import json
with open('README.md', 'rb') as f:
          upload_credentials = {
            "file": f,
            "descr": "testing",
            "title": "READMEE.md",
            "contentType": "text",
            "editor": username,
          }
          url_for_upload = "" #here you place the upload URL
          
          req = request.Request(url_for_upload, method="POST")
          form_data = urlencode(upload_credentials)
          form_data = form_data.encode()
    
          response = request.urlopen(req, data=form_data)
          http_status_code = response.getcode()
          content = response.read()
          print(http_status_code)
          print(content)

However, i get an error in this line: response = request.urlopen(req, data=form_data) The server responds with a 500 HTTP Status Code.

This is what i get as an error message:

raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 500:

500 error codes can mean a lot of things and i do not know how to progress any further, as everything i did seems by the book...

Does anyone have the experience, given the info provided here, to guide me to some potential solution?

EDIT: I am trying to replicate working js code that does the same thing. This is it:

<input type="file" />
<button onclick="upload()">Upload data</button>
<script>
          upload = async() =>
          {             
             const fileField = document.querySelector('input[type="file"]');
             await uploadDoc(fileField.files[0] );
          };
          
          uploadDoc = async( file ) =>
          {             
              let fd = new FormData();
              fd.append( 'file', file ); 
              fd.append( 'descr', 'demo_upload' );
              fd.append( 'title', name );
              fd.append( 'contentType', 'text' );
              fd.append( 'editor', user );
              let resp = await fetch( url, { method: 'POST', mode: 'cors', body: fd }); 
          };
</script>
user1584421
  • 3,499
  • 11
  • 46
  • 86
  • What value should file have in the dict? the contents of the file? cause right now it just has the file handle reference. – Chris Doyle Jan 14 '22 at 10:27
  • are you trying to stream the file? you add the filehandle to your "upload_credentials" – Patrick Artner Jan 14 '22 at 10:28
  • Could you provide the docs to the API you are using? – S P Sharan Jan 14 '22 at 10:28
  • shouldn't `"file": f` rather be `"file": f.read()` ? – mrxra Jan 14 '22 at 10:30
  • @SPSharan The server accepts a POST request to a particular url. You can see in the updated question an example of the form that it accepts. – user1584421 Jan 14 '22 at 10:36
  • @mrxra Thanks. I also tried this and i got the same error. – user1584421 Jan 14 '22 at 10:37
  • it appears to me you are just posting a json blob instead of sending form data....maybe this might help https://stackoverflow.com/a/12385661/12693728 – mrxra Jan 14 '22 at 11:00
  • I am not quite sure that your JS `file` is a filehandle - it may be that it is just a filename-string-path and some more magic is happening inside fech() in JS to make that valid - maybe check that and go from there – Patrick Artner Jan 14 '22 at 11:06
  • You're overwriting the credentials with your second assignment to `form_data`. –  Jan 14 '22 at 11:12

1 Answers1

1

The js code is doing a multipart/form-data post request.
I do not believe urllib supports multipart/form-data, you can use request instead.

import requests 
with open('README.md', 'rb') as f:
    files = {"file": f}
    upload_credentials = {
        "descr": "testing",
        "title": "READMEE.md",
        "contentType": "text",
        "editor": username,
    }
    r = requests.post("http://httpbin.org/post", files=files, data=upload_credentials) 
    print(r.status_code)
    print(r.text)
Musa
  • 96,336
  • 17
  • 118
  • 137