The key to getting this to work was in setting up the multipart-encoded files:
import requests
# Setup authentication credentials
credentials = requests.auth.HTTPBasicAuth('USERNAME','PASSWORD')
# JIRA required header (as per documentation)
headers = { 'X-Atlassian-Token': 'no-check' }
# Setup multipart-encoded file
files = [ ('file', ('file.txt', open('/path/to/file.txt','rb'), 'text/plain')) ]
# (OPTIONAL) Multiple multipart-encoded files
files = [
('file', ('file.txt', open('/path/to/file.txt','rb'), 'text/plain')),
('file', ('picture.jpg', open('/path/to/picture.jpg', 'rb'), 'image/jpeg')),
('file', ('app.exe', open('/path/to/app.exe','rb'), 'application/octet-stream'))
]
# Please note that all entries are called 'file'.
# Also, you should always open your files in binary mode when using requests.
# Run request
r = requests.post(url, auth=credentials, files=files, headers=headers)
https://2.python-requests.org/en/master/user/advanced/#post-multiple-multipart-encoded-files