I am trying to show the list of connected devices in browser using flask. I enabled flask on port 8000:
in server.py:
#server.route('/devices',methods = ['GET'])
def status():
return app.stat()
if __name__ == '__main__':
app.run()
in app.py:
def stat():
return(glob.glob("/dev/tty57") + glob.glob("/dev/tty9"))
And this is my test:
url = "http://127.0.0.1:8000"
response = requests.get(url + "").text
print response
but I keep getting this error:
"TypeError": 'list' object is not callable.
Am I doing sth wrong in checking if ttyUSB, ... and other devices existing?
The problem is that your endpoint is returning a list. Flask only likes certain return types. The two that are probably the most common are
a Response object
a str (along with unicode in Python 2.x)
You can also return any callable, such as a function.
If you want to return a list of devices you have a couple of options. You can return the list as a string
#server.route('/devices')
def status():
return ','.join(app.statusOfDevices())
or you if you want to be able to treat each device as a separate value, you can return a JSON response
from flask.json import jsonify
#server.route('/devices')
def status():
return jsonify({'devices': app.statusOfDevices()})
# an alternative with a complete Response object
# return flask.Response(jsonify({'devices': app.statusOfDevices()}), mimetype='application/json')
Related
So this is my code.
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
app.config['DEBUG'] = True
api = Api(app)
# Make the WSGI interface available at the top level so wfastcgi can get it.
wsgi_app = app.wsgi_app
class Default(Resource):
def get(self, name):
"""Renders a sample page."""
return "Hello " + name
class LiveStats(Resource):
def get(self, url):
return "Trying to get " + url
# data = request.get(url)
# return data
api.add_resource(Default, '/default/<string:name>') # Route_1
api.add_resource(LiveStats, '/liveStats/<path:url>') # Route_2
if __name__ == '__main__':
import os
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
app.run(HOST, PORT)
Now firstly this post helped a lot. how-to-pass-urls-as-parameters-in-a-get-request-within-python-flask-restplus
Changing what I originally had.
api.add_resource(LiveStats, '/liveStats/<string:url>') # Route_2
to this
api.add_resource(LiveStats, '/liveStats/<path:url>') # Route_2
got rid of 404 errors that I had but now I am noticing that it's not passing all of the url.
Example if I try this
localhost:60933/liveStats/http://address/Statistics?NoLogo=1%26KSLive=1
I get this
Trying to get http://address/Statistics
so it has taken off ?NoLogo=1%26KSLive=1
How do you prevent this?
All characters after the ? are considered parameters. From the docs:
To access parameters submitted in the URL (?key=value) you can use the args attribute:
searchword = request.args.get('key', '')
We recommend accessing URL
parameters with get or by catching the KeyError because users might
change the URL and presenting them a 400 bad request page in that case
is not user friendly.
For a full list of methods and attributes of the request object, head
over to the Request documentation.
Maybe you could encode the query string in a way that you can retrieve it as a single parameter on the back end, but not sure it would be useful.
If you don't want to access the args individually, you can access the full query string:
request.query_string
Putting this all together I think this will work for you:
class LiveStats(Resource):
def get(self, url):
return "Trying to get " + url + request.query_string
I'm working on a simple REST service with flask, the method deleteTweets() can't retrieve the URL parameter i'm sending, so tried to print to see what is sending but i get this error line.
File "C:\Path\HomeController.py", line 26, in deleteTwee
ts
id = request.args.get['id']
AttributeError: 'function' object has no attribute 'args'
127.0.0.1 - - [17/Jan/2018 12:00:05] "DELETE /api/deleteTweet?id=ABC HTTP/1.1" 500
This the code:
import json
import Service
from flask import Flask, render_template,jsonify,request
app = Flask(__name__)
apiUrl='/api'
#app.route('/')
def hello_world():
return render_template("/home.html", code=400)
#app.route(apiUrl+'/getData', methods=['GET'])
def test_request():
list = [15,21,8]
return jsonify(list)
#app.route(apiUrl+'/getTweets', methods=['GET'])
def request():
return Service.getAlltwits()
#app.route(apiUrl+'/deleteTweet', methods=['DELETE'])
def deleteTweets():
id = request.args.get['id']
print(id)
return
It's very simple but not sure what i did missed.
also tried with id = request.args.get('id')
You're doing the correct thing - and you're importing request.
But you have a function named request as well, and this function overwrites the former name (which is the actual flask request):
#app.route(apiUrl+'/getTweets', methods=['GET'])
def request():
return Service.getAlltwits()
Change the name to get_tweets instead:
#app.route(apiUrl+'/getTweets', methods=['GET'])
def get_tweets():
return Service.getAlltwits()
You've defined a function called request, which has therefore hidden the global request variable. Rename your route function.
I would like to route to a different Flask views based on the Accept HTTP header, for example:
#api.route('/test', accept='text/html')
def test_html():
return "<html><body>Test</body></html>"
#api.route('/test', accept='text/json')
def test_json():
return jsonify(test="Test")
I haven't found relevant option in Werkzeug Rule constructor, which is used by Flask. Is it a missing feature or is it possible to achieve the same effect differently, for example by intercepting and modifying URL path before routing?
I don't want to merge the views into one because it would complicate code significantly, there are many of them and they reside in different blueprints.
I am aware that similar question has been asked, but nobody answered it using Flask. It's possible to do it in different web frameworks, for example in Pyramid using predicates - sample code can be found in this answer.
I know this is an old question but I ended up here looking for something similar so I hope it helps someone else.
flask_accept has the functionality to handle different Accept types through different routes.
from flask import Flask, jsonify
from flask_accept import accept
app = Flask(__name__)
#app.route('/')
#accept('text/html')
def hello_world():
return 'Hello World!'
#hello_world.support('application/json')
def hello_world_json():
return jsonify(result="Hello World!")
if __name__ == '__main__':
app.run()
if you just want to reject requests depending on whether they are a specific data type you could also use Flask-Negotiate
from flask import Flask
from flask_negotiate import consumes, produces
app = Flask(__name__)
#app.route('/consumes_json_only')
#consumes('application/json')
def consumes_json_only():
return 'consumes json only'
When one tries to access the endpoint without a valid Accept header:
$ curl localhost:5000 -I
HTTP 415 (Unsupported Media Type)
I wrote a decorator which does that (copying here for posterity). It's just a rough idea that could be improved further (e.g. returning 406 Not Acceptable response instead of using the default handler when there are no handlers that match given MIME type). More explanations are in the comments.
import functools
from flask import Flask, request, jsonify
app = Flask(__name__)
def accept(func_or_mimetype=None):
"""Decorator which allows to use multiple MIME type handlers for a single
endpoint.
"""
# Default MIME type.
mimetype = 'text/html'
class Accept(object):
def __init__(self, func):
self.default_mimetype = mimetype
self.accept_handlers = {mimetype: func}
functools.update_wrapper(self, func)
def __call__(self, *args, **kwargs):
default = self.default_mimetype
mimetypes = request.accept_mimetypes
best = mimetypes.best_match(self.accept_handlers.keys(), default)
# In case of Accept: */*, choose default handler.
if best != default and mimetypes[best] == mimetypes[default]:
best = default
return self.accept_handlers[best](*args, **kwargs)
def accept(self, mimetype):
"""Register a MIME type handler."""
def decorator(func):
self.accept_handlers[mimetype] = func
return func
return decorator
# If decorator is called without argument list, return Accept instance.
if callable(func_or_mimetype):
return Accept(func_or_mimetype)
# Otherwise set new MIME type (if provided) and let Accept act as a
# decorator.
if func_or_mimetype is not None:
mimetype = func_or_mimetype
return Accept
#app.route('/')
#accept # Or: #accept('text/html')
def index():
return '<strong>foobar</strong>'
#index.accept('application/json')
def index_json():
return jsonify(foobar=True)
#index.accept('text/plain')
def index_text():
return 'foobar\n', 200, {'Content-Type': 'text/plain'}
You can return different response types based on the Accept header using request. Example.
if request.accept_mimetypes['application/json']:
return jsonify(<object>), '200 OK'
I am trying to show the list of connected devices in browser using flask. I enabled flask on port 8000:
in server.py:
#server.route('/devices',methods = ['GET'])
def status():
return app.stat()
if __name__ == '__main__':
app.run()
in app.py:
def stat():
return(glob.glob("/dev/tty57") + glob.glob("/dev/tty9"))
And this is my test:
url = "http://127.0.0.1:8000"
response = requests.get(url + "").text
print response
but I keep getting this error:
"TypeError": 'list' object is not callable.
Am I doing sth wrong in checking if ttyUSB, ... and other devices existing?
The problem is that your endpoint is returning a list. Flask only likes certain return types. The two that are probably the most common are
a Response object
a str (along with unicode in Python 2.x)
You can also return any callable, such as a function.
If you want to return a list of devices you have a couple of options. You can return the list as a string
#server.route('/devices')
def status():
return ','.join(app.statusOfDevices())
or you if you want to be able to treat each device as a separate value, you can return a JSON response
from flask.json import jsonify
#server.route('/devices')
def status():
return jsonify({'devices': app.statusOfDevices()})
# an alternative with a complete Response object
# return flask.Response(jsonify({'devices': app.statusOfDevices()}), mimetype='application/json')
In my Flask application, I want to expose a URI like this:
http://<base_uri>/some_string
and I wish to handle requests to it differently depending on whether some_string is an integer or not.
With Sinatra I can achieve that via "passing" as shown below:
get '/:some_string' do
if is_integer(:some_string)
'Your URI contains an integer'
else
pass # This will pass the request on the the method below which can handle it
end
get '/*' do
'Your URI contains some string'
end
Here the call pass in the first route lets the second route process the request if :some_string is not an integer.
I couldn't find any equivalent functionality in Flask. Can someone please suggest a solution in Flask?
Type conversion in url routes can do this for you:
from flask import Flask
import unittest
app = Flask(__name__)
app.debug = True
#app.route('/<int:thing>')
def num(thing):
return 'INT'
#app.route('/<thing>')
def string(thing):
return 'STR'
class TestDispatch(unittest.TestCase):
def setUp(self):
self.client = app.test_client()
def test_int(self):
resp = self.client.get('/10')
self.assertEqual("INT", resp.data)
def test_str(self):
resp = self.client.get('/hello')
self.assertEqual("STR", resp.data)
if __name__ == '__main__':
unittest.main()