This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 4 years ago.
I'm creating a game on Flask and want to have a counter across the entire session. I put together some psuedo code for the general outline of the project. Basically it's a script that pulls a random question from a database, collects user input, returns the correct answer, and then starts over again at the user input route. I want to add a counter that will appears regardless of the function of route. I looked into Flask sessions, but it was confusing where or how to implement... any thoughts/ suggestions? Sessions or otherwise?
get_db_info():
connects to a database
#app.route('/questions')
def user_input():
collects user input and puts into variable
#app.route('/answers')
def results():
if user input = results:
print(correct!)
elif:
print(incorrect)
renders back to user_input()
You already mention sessions, I think they are the solution to your problem:
Flask-Session is an extension for Flask that adds support for
Server-side Session to your application.
Here is an example of doing this with a session. It stores three counters, one for total accesses to the app and two for accesses to individual routes. If you call /A three times and then /B, it will give you
accessed B 1 times, accessed app 4 times
from flask import Flask, session
from flask_session import Session
app = Flask(__name__)
# Check Configuration section for more details
SESSION_TYPE = 'filesystem'
app.config.from_object(__name__)
Session(app)
#app.route('/')
def reset():
session["counterA"]=0
session["counterB"]=0
session["counterTotal"]=0
return "all counters were reset"
#app.route('/A')
def routeA():
if not "counterA" in session:
session["counterA"]=0
if not "counterTotal" in session:
session["counterTotal"]=0
session["counterA"]+=1
session["counterTotal"]+=1
return "accessed A {} times, accessed app {} times".format(session["counterA"], session["counterTotal"])
#app.route('/B')
def routeB():
if not "counterB" in session:
session["counterB"] = 0
if not "counterTotal" in session:
session["counterTotal"] = 0
session["counterB"] += 1
session["counterTotal"] += 1
return "accessed B {} times, accessed app {} times".format(session["counterB"], session["counterTotal"])
if __name__ == '__main__':
app.run()
The session behaves like a dictionary and is available across all routes. You can simply put your counter there.
For the sake of completeness, a solution without sessions is also possible:
In principle, the flask routes behave just like python functions.
So the following will work:
counter = 0
#app.route('/questions')
def user_input():
global counter
print(counter)
counter+=1
#app.route('/answers')
def results():
global counter
print(counter)
counter+=1
I would discourage the use of globals, they can make your code very hard to read and are not thread safe.
Related
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
What is the g object in this Flask code?
(1 answer)
Closed 1 year ago.
I'm trying to share a variable I defined in my main function with a flask app which is imported from another file. First I tried to solve it via a classic global variable which did not bring me any further, until I stumbled over the concept of flask.g and the app context.
So I tried the following: I have two files in the same directory, a main.py:
# main.py
import app
from flask import g
if __name__ == "__main__":
with app.app.app_context():
g.value = "Hello World"
app.app.run(debug=True, threaded=True, host='localhost', port=5000)
and a app.py:
# app.py
from flask import Flask, g
app = Flask(__name__)
#app.route('/helloworld')
def send_response():
return g.value
However, when I request at http://localhost:5000/helloworld I get
AttributeError: '_AppCtxGlobals' object has no attribute 'value'
So it seems that setting the value g.value in one file is not reflected in the app.
I'm a beginner in Flask and it is very likely I did not get the concept right.
Similar questions did not get me any answer I could use to fix the issue:
Flask passing global variable, python-How to set global variables in Flask?, Preserving global state in a flask application
Help would be much appreciated!
Just use a regular Python module-level variable.
# app.py
g = "Example"
#app.route("/example")
def example_endpoint():
return g
# main.py
import app
app.g = "Hello"
Quoting the same page you linked:
The application context is created and destroyed as necessary. When a Flask application begins handling a request, it pushes an application context and a request context. When the request ends it pops the request context then the application context. Typically, an application context will have the same lifetime as a request.
So your setting flask.g outside of a request context (in your main.py) doesn't carry your value to anywhere.
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 4 years ago.
I'm trying to build reply bot by using line api and python 2.7.15 .
this is my code
from flask import Flask, request, abort
from linebot import (LineBotApi, WebhookHandler)
from linebot.exceptions import (InvalidSignatureError)
from linebot.models import (MessageEvent, TextMessage, TextSendMessage,)
app = Flask(__name__)
line_bot_api = LineBotApi('UIXwXWExxxxxxxxxxxxxxxxxxxxxxxxxxxx')
handler = WebhookHandler('458033a97c124xxxxxxxxxxxxxxxxxxxxx')
number = 1
#app.route("/")
def hello():
return str(number)
#app.route("/webhook", methods=['POST'])
def webhook():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
#handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
text = event.message.text
user_id = event.source.user_id
if(text == 'inc'):
#set global variable here
number += 1
line_bot_api.push_message(user_id,TextSendMessage(text=str(number)))
if __name__ == "__main__":
app.run()
then i implement this on heroku and i try chatting with my bot,
first i send messageinc, he reply me 2
then i try send inc once again ,he reply me 3 and i try again he replies me 1
i try send inc once again he reply me 4
what wrong? why my number doesn't continue?
Python backend apps are typically deployed in multiprocess configuration (the front server - apache, ngnix or whatever - runs multiple parallel processes to handle incoming requests), and any request can be served by any process. Global variables are per-process, so which state you will find your global depends on which process served the request. Conclusion: don't use global variables to store application state - use a shared database (of any kind, it doesn't have to be a SQL database, it just have to be shared amongst all processes).
This question already has an answer here:
Testing code that requires a Flask app or request context
(1 answer)
Closed 4 years ago.
I'm making a web application using flask framework. To display a web page using flask, I use a render_template() function.
For example:
#app.route('/restaurants/<int:restaurant_id>/')
def restaurantMenu(restaurant_id):
try:
# pdb.set_trace()
session = get_session()
restaurant = session.query(Restaurant).filter_by(id=restaurant_id).one()
if restaurant is not None:
menu_items = session.query(MenuItem).filter(
MenuItem.restaurant_id == restaurant.id
)
session.close()
if menu_items is not None:
return render_template('menu.html', restaurant=restaurant, items=menu_items)
except NoResultFound:
return render_template('error.html', error_message='No such restaurant id.')
And
#app.route('/')
def welcomePage():
return render_template('index.html')
How do I write test cases for functions like these? I'm new to testing so I wanted to write test cases for my code.
You can create a test app in your tests and call it very simply, like so:
app = create_app().test_client()
result = app.get('/')
assert('something' in result.data)
That gives you the general idea - it's pretty easy to work with. More information can be found in the Flask Testing Docs: http://flask.pocoo.org/docs/0.10/testing/
For a while now I am trying to learn how to use Ajax with Flask. On the official website of flask there is an example:
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/_add_numbers')
def add_numbers():
a = request.args.get('a', 0, type=int)
b = request.args.get('b', 0, type=int)
return jsonify(result=a + b)
#app.route('/')
def index():
return render_template('index.html')
It works for me well. But I am looking for the following program:
a jQuery code sends an initial number to the python app
the python app stores the number and responds 'received: [the number]'
while true: the python app waits for requests 'increase' for which it adds 1 to the number and returns it
The jQuery part doesn't matter, I can do that but I am not sure how to implement the python part:
#app.route('/_inc_number')
def inc_number():
n = request.args.get('n', 0, type=int)
while true:
req = request.args.get('req', 0, type=string)
if req == 'increase':
n = n + 1
return n #It exits the function. how respond without quit?
Please explain me how I can data back? I am new to both Ajax and Flask too, and I suspect that it is not "real" ajax...Is that right? How would you implement a simple function with the same functionality in flask?
I think what you are missing is that each time the client requests a number increase there is an independent request. Your inc_number handler would be coded as follows:
#app.route('/_inc_number')
def inc_number():
n = request.args.get('n', 0, type=int)
n = n + 1
return n
Then from the jQuery side you have to invoke an independent Ajax request each time you want to increase the number.
Note that with this type of solution the jQuery app is the one that keeps track of the current value of the counter, and it has to send it to Flask with each request. Another possibility would be to have the Flask side remember the number in a user session. For that type of solution your Flask app would have two view functions:
from flask import session
# you need to set a SECRET_KEY in configuration, used to sign the user session
#app.route('/set_number')
def set_number():
# store n in the user session
session['n'] = request.args.get('n', 0, type=int)
#app.route('/inc_number')
def inc_number():
session['n'] = session['n'] + 1
return session['n']
With this solution now jQuery can set the number and not have to send it every time when it invokes inc_number.
I hope this helps.
HTTP requests don't have a memory, they are independent of each other. It means when your Python app gets a request, it does something, sends a response immediately and quits. That's the nature of HTTP.
If you want something persistent (like your number) that lives through more requests, you need:
Persistent storage on the server. It can be a file, a database, or in case of Flask simply an object (variable) in memory.
Identify the user between separate requests. That's what session handling and cookies are for.
A very primitive method (shouldn't be used on production system):
persistent storage: create a global dict (called num) in main()
in index():
create a random session identifier (si)
set num[si] = 0
send si as a cookie
in inc_number() use si from cookie (sent back by the browser) to increase the appropriate num[si]
I'm new to python and wondering if it is possible using BaseHTTPServer to store a global var that is accessible to all requests? Basically I have an async process that requires a POST back into the server as a separate request from the original request, that I would like to write back through to the original request, via a token I'd generate.
No.
To maintain state, you'll need a web framework that supports global variables across requests, or some kind of session management.
Flask is super easy to get up and running and has sessions available.
import flask
app = flask.Flask(__name__)
#app.route('/')
def index():
flask.session['post_token'] = MakeToken()
return '...Content...'
#app.route('/poster', methods=['POST'])
def poster():
if flask.session['post_token']:
DO STUFF HERE
# set the secret key. keep this really secret:
app.secret_key = 'A0Zr98j/3yX R~XHH!jxxxRT'