Flask Error json not serialized - python

I have created an application that uses commandline and call the program.
from flask import Flask, jsonify, make_response, request
import os
import subprocess
import json
app = Flask(__name__)
#app.route('/api/v1.0/qanda/', methods=['GET'])
def people_api():
text = request.args.get('text')
Answer = subprocess.Popen(['programcall', repr(text)],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
if text is None:
make_response(jsonify({'error': 'Missing text parameter'}), 400)
return jsonify(Answer)
app.run('0.0.0.0')
What I am trying to get is the PRETTY JSON OUTPUT on the application when I hit the browser URL. I tried to display the output but it was not pretty Json and most of the time jsonify was giving error: JSON is not serialized.
Kindly show me the way through which I can display the proper result using my application
One error which I can across is this:
Answer = Answer + subprocess.Popen(['programcall', repr(text)],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
TypeError: can only concatenate list (not "bytes") to list

You need to wait for your subprocess to finish before you can read the output. That is why sometimes you get the error and sometimes not because sometimes the process finishes and you have the output.

Related

URL Encode String in Python Flask API?

I have made a REST API using Python-Flask, now the input for api_call is supposed to be a string and that string needs to have special characters included. The problem occurs here is that when I make the request with http://127.0.0.1:5000/api/<your string>, the browser redirected it as a Google Search Query and sometimes it just throw the Not Found 404 error and this only occurs when I use some special characters in my string like ?. Is there a way to encode the string before calling the api? What I have done is I have made an another program that urlencode the string passed and redirect it to my api call but that doesn't seem like the correct way to call api.
Here's my API code:
# Importing Libraries
from flask import Flask, jsonify, request
# Creating Flask App
app = Flask(__name__)
#app.route('/')
def index():
'''
index function, to inform user of the API route.
params: None
return: None
'''
return f"Visit:<br><strong>{request.url}api/(your string)</strong><br>to get the api response"
#app.route('/api/<string:body>')
def sample(body):
# the code for this function is different and can't be shared but the output works similar
return jsonify({'length': len(body)})
if __name__ == '__main__':
app.run(debug=True)
As I have mentioned the code for the sample() function is different from the original but the output generation is completely similar, the original code is also returning the dictionary which will then be jsonified for response just like the code here. The code for string_reformat is:
# Importing Libraries
from urllib.parse import quote
# URL Encoding String
input_string = input()
print(quote(input_string))

Connect Dialogflow with Google BigQuery via Cloudfunctions with Python

I'm new on Python and cloud functions but I saw that it's possible to connect Dialogflow and GoogleBigQuery via Cloudfunctions but I do not understand how to make this, can someone explain me how to do it or if the way I'm trying to it's at least close?
import flask
from flask import Flask
from flask import request
from flask import make_response
app = Flask(__name__)
#app.route('/prueba_1', methods=['POST'])
def prueba_1():
import json
import pandas as pd
ss = pd.read_gbq("SELECT something FROM bigquery_table LIMIT 1","arbor-209819")
ll = {
"speech" : ss.to_json(),
"displayText": ss.to_json(),
"source": "apiai-weather-webhook-sample"
}
res = json.dumps(ll, indent=4)
r = make_response(res)
r.headers['Content-Type'] = 'application/json'
return r
if __name__ == '__main__':
app.run(debug=True)
Thank you so much.
You are close, your function needs to accept the request. Also, python for cloud functions removes a lot of the overhead out of the code (you will still need it for local testing though). You can follow this quickstart to get you started.
Here is an example of how it could be written:
from flask import jsonify
import pandas as pd
def prueba_1(request):
# Your code
ss = pd.read_gbq('SELECT * FROM my_dataset.my_table')
# More code
return jsonify(my_dictionary)
jsonify takes a dict object and returns an application/json Response. Remember to add pandas and pandas-gbq in your requirements.
Finally, if you are using cloud functions to set up a custom webhook for Dialogflow, remember to check the request and response formats.

Flask send_file is sending old file instead of newest

I have a flask app where using one Flask route the server creates a csv file and saves it to the server. Using a generated button on the client page, another Flask route is triggered to get the most recent file, move it to a tmp folder and send that file to the user using send_file.
Right now, when I run the process the first time and download the file, all works as expected. However, the second time I run the process, it serves me the old CSV instead of the newly generated one. This continues until I hit the refresh button on my browser.
The following is my app code:
from flask import Flask, render_template, flash, redirect, request, url_for, Response, send_file
import os
import time
import shutil
import glob
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
#app.route('/')
def index():
return render_template('index.html')
#app.route('/downloadcsv')
def downloadcsv():
current = os.getcwd()
try:
list = glob.glob('{}/*.csv'.format(current))
except:
print('No file found')
basename = os.path.basename(os.path.normpath(max(list, key=os.path.getctime)))
shutil.move(basename, './tmp/{}'.format(basename))
return send_file('./tmp/{}'.format(basename), as_attachment=True)
In case it is needed, the following is the JS code which "generates" the download button:
var download = '<div id="downloadsection" class="container-contact100-form-btn"><button id="download" class="contact100-form-btn"> <span>DOWNLOAD CSV</span></button></div>';
Please also let me know if I am over complicating the download process...
Thanks!!
send_file has a caching timeout that you are not configuring. It will send the same file that has been cached unless you tell it not to cache the file like so:
send_file('./tmp/{}'.format(basename), as_attachment=True, cache_timeout=0)
See the following references for more information:
http://flask.pocoo.org/docs/1.0/api/#flask.send_file
http://flask.pocoo.org/docs/1.0/api/#flask.Flask.get_send_file_max_age
http://flask.pocoo.org/docs/1.0/config/#SEND_FILE_MAX_AGE_DEFAULT
#ritlew pretty much answers the question, to add to his answer, After adding cache_timeout=0, clear the browser cache and hit the URL in incognito mode.
You can also try:
Disabling caching in Flask

HTTP endpoint that causes string to write to a file

the api should include one function called "write text to file" and inputs a string parameter
as for the function to write to the disk I have no problem and I implemented the code my problem is how to set the rest API using python.
EDIT:
this is my code:
from flask import (
Flask,
render_template
)
import SocketServer
import SimpleHTTPServer
import re
app = Flask(__name__, template_folder="templates")
#app.route('/index', methods=['GET'])
def index():
return 'Welcome'
#app.route('/write_text_to_file', methods=['POST'])
def write_text_to_file():
f = open("str.txt", "w+")
f.write("hello world")
f.close()
if __name__ == '__main__':
app.run(debug=True)
anyhow when I try to test my rest api:
http://127.0.0.1:5000/write_text_to_file
I am getting the following error:
Now I'm trying to test my rest-api , however how can I make my code to start the server and to the test the post request api, this is my test_class:
import requests
import unittest
API_ENDPOINT="http://127.0.0.1:5000/write_text_to_file"
class test_my_rest_api(unittest.TestCase):
def test_post_request(self):
"""start the server"""
r = requests.post(API_ENDPOINT)
res = r.text
print(res)
also when runnning my request using postman I am getting internal_server_error:
You're doing a GET request for this url, but you've specified that this endpoint can only accept POST:
#app.route('/write_text_to_file', methods=['POST'])
Also, the SocketServer and SimpleHTTPServer imports are not needed with Flask.
The method is not allowed because Chrome (or any browser) makes GET requests.
Whereas, you defined it as POST
#app.route('/write_text_to_file', methods=['POST'])
Either change it to a GET method, or use a tool such as POSTMan to perform other HTTP call types

Flask and Working outside of application context

I am testing a simple slack command, which is supposed to return a response upon invocation and then start a new thread where it will calculate new response and post it back. However, it seems like there is no way to call jsonify inside the thread, because if do that, it throws : RuntimeError: Working outside of application context.
from flask import abort, Flask, jsonify, request
import requests
import json
from dateutil.parser import parse
from threading import Thread
def backgroundworker(somedata,response_url):
payload = jsonify(
response_type='in_channel',
text="test"
)
requests.post(response_url,data=json.dumps(payload))
#app.route('/appmethodaddress',methods=['POST','GET'])
def receptionist():
response_url = request.form.get("response_url")
somedata = {}
thr = Thread(target=backgroundworker, args=[somedata,response_url])
thr.start()
return jsonify(message= "working on your request")
Is there an easy way to call jsonify inside backgroundworker ?
If you have to make a json out of it, use json.dumps() method (https://kite.com/python/docs/json.dumps).

Categories

Resources