I would like to deploy artifacts using Python (with a zip file which is like a set of artifacts and the dir-structure should be preserved - according to the docs)
When I use the following docs nothing happens (no files created in the repo) but I get an OK response:
import httplib
import base64
import os
dir = "/home/user/"
file = "archive.zip"
localfilepath = dir + file
artifactory = "www.stg.com"
url = "/artifactory/some/repo/archive.zip"
f = open(localfilepath, 'r')
filedata = f.read()
f.close()
authheader = "Basic %s" % base64.encodestring('%s:%s' % ("my-username", "my-password"))
conn = httplib.HTTPConnection(artifactory)
conn.request('PUT', url, filedata, {"Authorization": authheader, "X-Explode-Archive": "true"})
resp = conn.getresponse()
content = resp.read()
How could I make it work?
Edit: Solved it!
I put up a local artifactory and played with it, curl and requests to figure out what was going wrong. The issue is that artifactory expects the file to be uploaded in a streaming fashion. Luckily, requests also handles that easily. Here is
code I was able to get working with an artifactory instance.
import requests
import os
dir = "/home/user"
filename = "file.zip"
localfilepath = os.path.abspath(os.path.join(dir, filename))
url = "http://localhost:8081/artifactory/simple/TestRepository/file.zip"
headers = {"X-Explode-Archive": "true"}
auth = ('admin', 'password')
with open(localfilepath, 'rb') as zip_file:
files = {'file': (filename, zip_file, 'application/zip')}
resp = requests.put(url, auth=auth, headers=headers, data=zip_file)
print(resp.status_code)
Related
I'm fairly new to using the python requests library, and am currently trying to download an image off of JIRA and then upload that image to gitlab to later reference in a note, as documented here: https://docs.gitlab.com/ee/api/projects.html#upload-a-file. The image is downloading properly from JIRA (I can see and open the file), however, I am getting an error 400 Bad Request response right now when I try and post it to gitlab.
My code looks like this:
gl_url = 'https://lab.mygitlabinstance.com/api/v4/projects/%s/uploads' % gl_project_id
def image_post(image_url, file_name, jira_auth, gl_url, gl_token):
image = requests.get(
image_url,
auth=HTTPBasicAuth(*jira_auth),
stream=True)
local_file = open(file_name, 'wb')
image.raw.decode_content = True
shutil.copyfileobj(image.raw, local_file)
file = {'file': '#' + file_name}
value = requests.post(
gl_url,
headers={'PRIVATE-TOKEN': gl_token, 'Content-Type': 'multipart/form-data'},
verify=True,
files=file
)
return value
My gitlab token is working in other parts of the same program, so I don't think that that is the problem. Any help would be greatly appreciated.
Try this one:
def image_post(image_url, file_name, jira_auth, gl_url, gl_token):
image = requests.get(
image_url,
auth=HTTPBasicAuth(*jira_auth),
stream=True)
# save file locally
with open(file_name, 'wb') as f:
f.write(image.content)
# readfile and send
file = {'file': open(file_name, 'rb')}
value = requests.post(
gl_url,
headers={'PRIVATE-TOKEN': gl_token},
verify=True,
files=file
)
return value
Or probably Second one:
I'm not sure what is in your local_file, but '#'+filename is for curl syntax, here we need file content so try fix line in your example to this one: file = {'file': local_file}
I created a bot which collects info from users in a workspace. It stores this info in a csv file on the local server. How do I download said file? I got this bit of code from Stack Overflow, attempted to contact the author but didn't get any response.
import requests
url = 'https://slack-files.com/T0JU09BGC-F0UD6SJ21-a762ad74d3'
token = 'xoxp-TOKEN'
requests.get(url, headers={'Authorization': 'Bearer %s' % token})
How do I obtain the URL & token of the file? What is the token? Is it the OAuth token of the bot?
Say I wished to download the file named stats.csv from the server that was created by the slackbot and I don't have it's URL, how would I download it?
I would not recommend to patch together the URL for downloading the file yourself, because Slack might change it and then your code breaks.
Instead, first get the current URL of the file by calling the API method files.info with the file ID. Then use property url_private as URL for download. Alternatively you can also call files.list to get the list of all files with IDs and their URLs.
To ensure you have access to the file its best to use the token from it's creator, e.g. your slackbot.
I also included the code to save the downloaded data to file and some rudimentary error handling. Note that the token is excepted to be set as environment variable names SLACK_TOKEN. This is much safer than putting it directly into the code.
Here is a complete example:
import os
import requests
token = os.environ['SLACK_TOKEN']
file_id = "F12345678"
# call file info to get url
url = "https://slack.com/api/files.info"
r = requests.get(url, {"token": token, "file": file_id})
r.raise_for_status
response = r.json()
assert response["ok"]
file_name = response["file"]["name"]
file_url = response["file"]["url_private"]
print("Downloaded " + file_name)
# download file
r = requests.get(file_url, headers={'Authorization': 'Bearer %s' % token})
r.raise_for_status
file_data = r.content # get binary content
# save file to disk
with open(file_name , 'w+b') as f:
f.write(bytearray(file_data))
print("Saved " + file_name + " in current folder")
I am using Python 2.7. My Rest server side API works fine and I am able to upload a zip file using Postman. I am trying to upload a zip file using Rest client api. I tried requests package, but it is unable to send the files. I am getting an error : missing file argument.
This is my python server side code :
#ns.route('/upload_file', strict_slashes=False)
class Upload(Resource):
#api.expect(upload_parser)
def post(self):
args = upload_parser.parse_args()
file_nameup = args.file.filename
Here is the rest api client code :
import requests
from requests.auth import HTTPBasicAuth
import json
headers={'Username': 'abc#gmail.com', 'apikey':'123-e01b', 'Content-Type':'application/zip'}
f = open('C:/Users/ADMIN/Downloads/abc.zip', 'rb')
files = {"file": f}
resp = requests.post("https://.../analytics/upload_file", files=files, headers=headers )
print resp.text
print "status code " + str(resp.status_code)
if resp.status_code == 200:
print ("Success")
print resp.json()
else:
print ("Failure")
This is my error :
{"message":"Input payload validation failed","errors":{"file":"Missing required
parameter in an uploaded file"}
status code 400
Failure
In postman, I passed a zip file with in body with "file" as key and value as abc.zip file. It worked fine. I tried to use httplib library, but it fails as my post url does not contain port number. This the error with httplib :
python HttpClientEx.py
Traceback (most recent call last):
File "HttpClientEx.py", line 4, in
h = http.client.HTTPConnection(url)
File "c:\python27\Lib\httplib.py", line 736, in init
(self.host, self.port) = self._get_hostport(host, port)
File "c:\python27\Lib\httplib.py", line 777, in _get_hostport
raise InvalidURL("nonnumeric port: '%s'" % host[i+1:])
httplib.InvalidURL: nonnumeric port: '// ....net/analytics/upload_file'
How to invoke rest url post and upload a file using urllib library. Please suggest any other ways to upload file in rest client. Thanks.
I found another duplicate post :
Python Requests - Post a zip file with multipart/form-data
The solution mentioned there did not work. I found that you need to provide the full path of the file, otherwise it will not work.
Use urllib3 module.
https://urllib3.readthedocs.io/en/latest/user-guide.html
Files & binary data
For uploading files using multipart/form-data encoding you can use the same approach as Form data and specify the file field as a tuple of (file_name, file_data):
with open('example.txt') as fp:
file_data = fp.read()
r = http.request(
'POST',
'http://httpbin.org/post',
fields={
'filefield': ('example.txt', file_data),
})
json.loads(r.data.decode('utf-8'))['files']
requests library worked with below changes in my code :
import requests
from requests.auth import HTTPBasicAuth
import json
from pathlib import Path
file_ids = ''
headers={'Username': 'abc#gmail.com', 'apikey':'123-456'}
# Upload file
f = open('C:/Users/ADMIN/Downloads/abc.zip', 'rb')
files = {"file": ("C:/Users/ADMIN/Downloads/abc.zip", f)}
resp = requests.post("https:// ../analytics/upload_file", files=files, headers=headers )
print resp.text
print "status code " + str(resp.status_code)
if resp.status_code == 201:
print ("Success")
data = json.loads(resp.text)
file_ids = data['file_ids']
print file_ids
else:
print ("Failure")
I am trying to post articles using apple news API tried using the Postman following all the steps provided by documentation, as well executed the python code provided in apple documentation.
POSThttps://news-api.apple.com/channels/channelID/articles2018-02-06T05:15:53Zmultipart/form-data;
Authorization headers authorization = {str} 'HHMAC; key=ID; signature=ID; date=2018-02-07T05:15:53Z'
got: error stating Wrong singature
Python
import requests
import base64
from hashlib import sha256
import hmac
from datetime import datetime
import glob
import argparse
import os
import mimetypes
from requests.packages.urllib3.filepost import encode_multipart_formdata
from requests.packages.urllib3.fields import RequestField
arg_parser = argparse.ArgumentParser(description='Publish an article using the Apple News API')
arg_parser.add_argument('article_directory', metavar='ARTICLE_DIR', type=str, help='A directory containing an article.JSON file and resources')
args = arg_parser.parse_args()
channel_id = '[YOUR CHANNEL-ID]'
api_key_id = '[YOUR API-KEY]'
api_key_secret = '[YOUR API KEY-SECRET]'
method = 'POST'
url = 'https://news-api.apple.com/channels/%s/articles' % channel_id
session = requests.Session()
session.verify = False
def part(filename):
name = os.path.basename(filename)
with open(filename) as f:
data = f.read()
part = RequestField(name, data)
part.headers['Content-Disposition'] = 'form-data; filename="%s"; size=%d' % (name, os.stat(filename).st_size)
part.headers['Content-Type'] = 'application/JSON' if name.endswith('.JSON') else 'application/octet-stream'
return part
def send_signed_request(method, url, filenames):
body, content_type = encode_multipart_formdata([part(f) for f in filenames])
req = requests.Request(method, url, data=body, headers={'Content-Type': content_type})
req = req.prepare()
date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
canonical_request = method + url + str(date) + content_type + body
key = base64.b64decode(api_key_secret)
hashed = hmac.new(key, canonical_request, sha256)
signature = hashed.digest().encode('base64').rstrip('/n')
authorization = 'HHMAC; key=%s; signature=%s; date=%s' % (api_key_id, str(signature), date)
req.headers['Authorization'] = authorization
return session.send(req)
response = send_signed_request(method, url, glob.glob('%s/*' % args.article_directory))
print response.status_code
print response.text
error: {"errors":[{"code":"MISSING","keyPath":["article.json"]}]}
I also converted the python code to java and executed seeing the same error but able to read articles.
Question:
Any suggestions on what is going wrong or In order to create articles does apple account be approved by Apple etc. Any information would be helpfull.
This script requires a folder path as an argument. This folder has to have the following structure:
--- folder
|---- article.json
|---- image.jpg
Image files are optional if your article.json file requires them.
When the python file is executed, it should be executed like this :
python script_name.py 'folder/'
I have a REST PUT request to upload a file using the Django REST framework. Whenever I am uploading a file using the Postman REST client it works fine:
But when I try to do this with my code:
import requests
API_URL = "http://123.316.118.92:8888/api/"
API_TOKEN = "1682b28041de357d81ea81db6a228c823ad52967"
URL = API_URL + 'configuration/configlet/31'
#files = {
files = {'file': open('configlet.txt','rb')}
print URL
print "Update Url ==-------------------"
headers = {'Content-Type' : 'text/plain','Authorization':API_TOKEN}
resp = requests.put(URL,files=files,headers = headers)
print resp.text
print resp.status_code
I am getting an error on the server side:
MultiValueDictKeyError at /api/configuration/31/
"'file'"
I am passing file as key but still getting above error please do let me know what might I am doing wrong here.
This is how my Django server view looks
def put(self, request,id,format=None):
configlet = self.get_object(id)
configlet.config_path.delete(save=False)
file_obj = request.FILES['file']
configlet.config_path = file_obj
file_content = file_obj.read()
params = parse_file(file_content)
configlet.parameters = json.dumps(params)
logger.debug("File content: "+str(file_content))
configlet.save()
For this to work you need to send a multipart/form-data body. You should not be setting the content-type of the whole request to text/plain here; set only the mime-type of the one part:
files = {'file': ('configlet.txt', open('configlet.txt','rb'), 'text/plain')}
headers = {'Authorization': API_TOKEN}
resp = requests.put(URL, files=files, headers=headers)
This leaves setting the Content-Type header for the request as a whole to the library, and using files sets that to multipart/form-data for you.