Post multipart form with multiple file uploads using python requests - python-3.x

I have demographics information extracted for some people in the form of list of python dictionaries(each dict for an individual). Also I need to upload the document from where I extracted the data (pdf/word). I tried Multipart form submission using Python requests which because of some reason does not seem to work.
The API expects two keys 'files' and 'data'
'files' is a list of file objects
'data' is a list of dicts which is stringified using json.dumps (API requirements)
pay_part= [{"umr":"","age":"","gender":"","first_name":"","middle_name":"","last_name":"","phone":"","address":"","admission_date":"","lab":"","discharge_date":"","ip_number":"","diagnosis":"","reason":"","treatment":"","medications":"","expired_date":"","instructions":"","review_date":"","procedure":"","notes":"","physician":"","filename":""},{"umr":"","age":"","gender":"","first_name":"","middle_name":"","last_name":"","phone":"","address":"","admission_date":"","lab":"","discharge_date":"","ip_number":"","diagnosis":"","reason":"","treatment":"","medications":"","expired_date":"","instructions":"","review_date":"","procedure":"","notes":"","physician":"","filename":""}]
multipart_data = MultipartEncoder(
fields={
"file":[('file.docx',open('13427.docx', 'rb'),'text/plain'),
('file.docx',open('13427.docx', 'rb'),'text/plain')],
"payload": json.dumps(pay_part)
}
)
response = requests.post(url, data=multipart_data, headers={'Content-Type': 'multipart_data.content_type; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW', 'userid': sUserID,'metaid': metaid,'postman-token':postmanToken})
print(response.text)
While forming the multipart form object I get an error
"AttributeError: 'tuple' object has no attribute 'encode'".
I believe this has to do something with creating file objects as a binary and storing in list.
Thanks in advance!

I got it to work!
Just send your json object using the argument ‘data’ and a list of your file objects using the argument ‘files’ as shown below.
I removed from the header argument “'Content-Type': 'multipart_data.content_type; boundary=---WebKitFormBoundary7MA4YWxkTrZu0gW'”
The post request was made as a multipart post
Code:-
fields={'payload': json.dumps(pay_part)})
response = requests.post(url, data=fields,files =[('file',open('13385.docx', 'rb')),('file',open('13385.docx', 'rb'))], headers={'userid': sUserID,'metaid': metaid,'postman-token':postmanToken})
print(response.text)

Related

How to POST a single parameter as JSON in FastAPI?

I have a working model using transformers pipeline and I want to use it with FastAPI to send post requisitions and get the response.
The model works this way:
#Loading the model
classifier = pipeline(path_to_model)
#Making predictions:
classifier(txt)
The output is a list of dicts.
My code is:
app = FastAPI()
#app.post("/predictions")
def extract_predictions(text):
text = text.lower()
out=classifier(text)
return {
"text_message": text,
"predictions": out
}
I can get predictions if I use localhost:8000/docs, but when I use postman or insominia and body(JSON) {"text":"any string"} I get "field_required"
The model takes a string as an input and my postman request uses a JSON body. How can I update model to get the input as JSON?
The text attribute, as is currently defined, is expected to be a query parameter, not body (JSON) parameter. Hence, you can either send it as a query parameter when POSTing your request, or define it using Body field (e.g., text: str = Body(..., embed=True)), so that is expected in the body of the request as JSON. Please have a look at the answers here and here for more details.

Looking for approach to post long text to slack through python script

I had written a code in python to fetch the huge set (80 lines) of data from DB, now I would like to post that data in slack through webhook. I tried posting the data directly,but its not working for me, so I decided to save the data in txt/.png file and post it in slack
I tried below code in python after saving my data in report.txt file, but its not helping me
headers = {
'Content-type': 'application/json',
}
data = open('\\results\report.txt')
response = requests.post('https://jjjjjjj.slack.com/services/mywebhook', headers=headers, data=data)
Please share me the Curl command which will fit in python script to post the attachment in slack or please suggest me any better approach to post more than 50 lines for data to slack
I would suggest to upload long text as text file. That way Slack will automatically format it with a preview and users can click on it to see the whole content.
To upload a file you need to use files_upload API method. With it you can also include an initial message with your upload.
Here is an example using the standard Slack library. Here I am reading the data from a file, but you would of course use your data instead:
import slack
import os
# init slack client with access token
slack_token = os.environ['SLACK_TOKEN']
client = slack.WebClient(token=slack_token)
# fetch demo text from file
with open('long.txt', 'r', encoding='utf-8') as f:
text = f.read()
# upload data as file
response = client.files_upload(
content=text,
channels='general',
filename='long.txt',
title='Very long text',
initial_comment='Here is the very long text as requested:'
)
assert response['ok']
The trick is to use content not file to pass the data. If you use file the API will try to load a file from your filesystem.
The below code works fine for me..... :)
headers = { 'Authorization': 'Bearer xxxx-XXXXX-XXXXX', #Bot Token }
files = {
'file': ('LocationOfthefile\report.txt', open('LocationOfthefile\report.txt', 'rb')),
'initial_comment': (None, 'Some Text For Header'),
'channels': (None, 'Channel_Names'),
}
response = requests.post('slack.com/api/files.upload', headers=headers, files=files)

Return csv data as a result for IBM Cloud Function

I have a function written in Python for IBM cloud. Which return results as json, for the following python dictionaries:
return {"billing_for_org": output1, "billing_for_org2:": output2}
Is there a way to return this data as a CSV file? So when I invoke the api I am able to download the data as CSV file?
Here is some sample I tested. Let me know if its what you are looking for.
import sys
import csv
import io
def main(dict):
output = io.StringIO()
my_dict = {"billing_for_org": "$100", "billing_for_org2": "$200"}
w = csv.DictWriter(output, my_dict.keys())
w.writeheader()
w.writerow(my_dict)
return {"body": output.getvalue(),
"headers": {'Content-Type': 'text/csv','Content-Disposition':'attachment;filename=myfilename.csv'}}
I am not sure how you are invoking the function as Rest API or Web Action.
I tested above code as web action function and got the result. Please note that extension says http at the end of Url which makes the function to return Non-Default(Json) payloads.
Example Url - https://openwhisk.ng.bluemix.net/api/v1/web/demo_dev/hello-world/helloworld.http
Response Received -
Body:
billing_for_org,billing_for_org2
$100,$200
Headers:
Content-Type →text/csv; charset=UTF-8 Content-Length →45 Connection
→keep-alive Content-Disposition →attachment;filename=myfilename.csv
Reference -
https://console.bluemix.net/docs/openwhisk/openwhisk_webactions.html#openwhisk_webactions.
https://developer.ibm.com/answers/answers/406943/view.html

Can't extract data from RESTClient response

I am writing my first Groovy script, where I am calling a REST API.
I have the following call:
def client = new RESTClient( 'http://myServer:9000/api/resources/?format=json' )
That returns:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
I am trying to get the field level, like this:
def level_value = client.get( path : 'msr/data/level' )
However, when I print the value of the variable obtained:
println level_value.getData()
I get the whole JSON object instead of the field:
[[msr:[[data:{"level":"OK"}]], creationDate:2017-02-14T16:44:11+0000, date:2017-02-14T16:46:39+0000, id:136]]
So, what am I doing wrong?
Haven't looked at the docs for RESTClient but like Tim notes you seem to have a bit of a confusion around the rest client instance vs the respons object vs the json data. Something along the lines of:
def client = new RESTClient('http://myServer:9000/api/resources/?format=json')
def response = client.get(path: 'msr/data/level')
def level = response.data[0].msr[0].data.level
might get you your value. The main point here is that client is an instance of RESTClient, response is a response object representing the http response from the server, and response.data contains the parsed json payload in the response.
You would need to experiment with the expression on the last line to pull out the 'level' value.

pyramid FileResponse encoding

I'm trying to serve base64 encoded image files and failing. Either I get UTF-8 encoded responses or the line return response errors in an interesting way. Mostly everything I've tried can be seen as commented out code in the excerpt below. Details of the traceback follow that.
My question is: How can I return base64 encoded files?
#import base64
#with open(sPath, "rb") as image_file:
#encoded_string = base64.b64encode(image_file.read())
dContentTypes = {
'bmp' : 'image/bmp',
'cod' : 'image/cis-cod',
'git' : 'image/gif',
'ief' : 'image/ief',
'jpe' : 'image/jpeg',
.....
}
sContentType = dContentTypes[sExt]
response = FileResponse(
sPath,
request=request,
content_type= sContentType#+';base64',
#content_encoding = 'base_64'
#content_encoding = encoded_string
)
return response
Uncommenting the line #content_encoding = encoded_string gives me the error:
AssertionError: Header value b'/9j/4AAQSkZJRgABAQAA' is not a string in ('Content-Encoding', b'/9j/4AAQSkZJRgABAQAA....')
FileResponse is used specifically for uploading a file as a response (hence the path argument). In you're case you want to base64-encode the file before uploading it. This means no FileResponse.
Since you've read the file into memory you can just upload the content in a Response.
response = Response(encoded_string,
request=request,
content_type=sContentType+';base64')
I'm not actually sure how content_encoding compares to the ;base64 on the type, but I think the encoding is used more commonly for gzipped content. YMMV.
The error you are seeing is telling you that Content-Type is not a string. Content-Type is an HTTP header. And as far as I know, HTTP headers must be strings.
I believe the base64 encoded file you want to pass as the body of the response. FileResponse is not appropriate here since you presumably want to pass encoded string as the body and FileResponse expects a path that it then reads in and sets the body.

Resources