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 have a problem with the global variable in Flask.
from flask import Flask, redirect
app = Flask(__name__)
#app.route('/')
def define_x():
global x
x = 10
return redirect('/test')
#app.route('/test')
def test_x():
return str(x)
if __name__ == '__main__':
app.run()
There is an error when url redirect:
NameError: global name 'x' is not defined
But if I define 'x' on the top of the function:
from flask import Flask, redirect
app = Flask(__name__)
x = None
#app.route('/')
def define_x():
global x
x = 10
return redirect('/test')
#app.route('/test')
def test_x():
return str(x)
if __name__ == '__main__':
app.run()
the redirect page return None not 10.
Just add
x = None
at top of script
Related
I would like to run an infinite loop in flask, which do something with a global list.
I'd like to append the list through an API call, and process data from the updated list.
What is the problem?
Usage: you run flask application, and call localhost:5000/ to append the list.
It will return the new list, but in the loop, it remains the initial list.
Thanks
import time
from flask import Flask
from multiprocessing import Process, Value
app = Flask(__name__)
stuff = [1, 2]
#app.route('/', methods=['GET'])
def index():
global stuff
stuff.append(max(stuff) + 1)
print('in request, stuff: ', stuff)
return ', '.join(map(str, stuff))
def print_stuff():
global stuff
print('in loop, stuff: ', stuff)
def record_loop(loop_on):
while True:
if loop_on.value == True:
print_stuff()
time.sleep(1)
if __name__ == "__main__":
recording_on = Value('b', True)
p = Process(target=record_loop, args=(recording_on,))
p.start()
app.run(debug=True, use_reloader=False)
p.join()
I found the working solution:
import time
from flask import Flask
from flask_apscheduler import APScheduler
app = Flask(__name__)
scheduler = APScheduler()
i = 0
def scheduleTask():
global i
print("This test runs every 1 seconds", i)
time.sleep(2)
#app.route('/')
def hello():
global i
i += 1
return str(i)
if __name__ == '__main__':
scheduler.add_job(id = 'Scheduled Task', func=scheduleTask, trigger="interval", seconds=1)
scheduler.start()
app.run(host="0.0.0.0")
I have a basic flask API running :
u/app.route('/helloworld', methods = ['GET'])
def first_api():
hname = "hello"
lhname = "world"
print(hname+lhanme)
Now I need to add some unit tests to it, and here is my unit test file:
import json
def test_index(app, client):
res = client.get('/helloworld')
assert res.status_code == 200
assert "hello" in res.data
How can I pass value for variables hname and lhname from this unit test?
Here is my conf file for pytest:
import pytest
from app import app as flask_app
u/pytest.fixture
def app():
return flask_app
u/pytest.fixture
def client(app):
return app.test_client()
You have a little mistake in your endpoint. You want it to return the string instead of printing it. Please consider the following example:
from flask import Flask, request
flask_app = Flask(__name__)
app = flask_app
#app.route('/helloworld', methods = ['GET'])
def first_api():
hname = request.args.get("hname")
lhname = request.args.get("lname")
print(hname)
return hname + lhname
def test_index(app):
client = app.test_client()
hname = "hello"
lname = "world"
res = client.get('/helloworld?hname={}&lname={}'.format(hname, lname))
assert res.status_code == 200
assert "hello" in res.data.decode("UTF-8")
if __name__ == "__main__":
test_index(app)
I'm playing with Flask a little, for my application I would require a global storage which is updated by a Thread running in the background on the server. I found this question about global context and the answer from Johan Gov seems to work if I init the server using /create explicitly:
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
#app.route("/create")
def create():
cache['foo'] = 0
return jsonify(cache['foo'])
#app.route("/increment")
def increment():
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
app.run()
If I try to call the init automaticaly however, it fails as apparently no cache["foo"] is known.
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
def create(): #create does not have a route anymore
cache['foo'] = 0
#app.route("/increment")
def increment():
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
create() #initialize by default
app.run()
Why is this happening? How can I initialize global state before starting the Application?
You can use the Cache as your app property, i always use this when i want to avoid awkward global definitions, just define the cache like this:
# here u create a "cache" attribute for the app.
app.cache = {}
app.cache['foo'] = 0
# then after that when calling in a route:
# notice that we don't need the global keyword since we are using the app.
#app.route("/increment")
def increment():
app.cache = app.cache + 1
return jsonify(app.cache)
I even used relatively big objects like deep learning models using this method and had not problems at all.
tbh, the above code work for me without any change and I'm able to read and increment counter.
Try below code with global variable
from flask import Flask
from flask.json import jsonify
app = Flask(__name__)
cache = {}
def create(): # create does not have a route anymore
global cache
cache['foo'] = 0
#app.route("/increment")
def increment():
global cache
cache['foo'] = cache['foo'] + 1
return jsonify(cache['foo'])
#app.route("/read")
def read():
return jsonify(cache['foo'])
if __name__ == '__main__':
create() # initialize by default
app.run()
I want to know how to return render_template('start-crawl.html') and have a function run at the same time. Once the function completes I want to return render_template('finish-crawl.html').
from flask import Flask, render_template, request, make_response, redirect, url_for
from flask_executor import Executor
app = Flask(__name__)
executor = Executor(app)
has_ran = False
#app.route('/', methods=["POST", "GET"])
def index():
if request.method == "POST":
usr_input = form["usr_input"]
def func():
"""
some code
global has_ran
has_ran = True
"""
executor.submit(func)
try:
return render_template('start-crawl.html')
finally:
x = 5 # Use this variable for loop but other than that it is useless
while x == 5:
if has_ran:
return render_template('finish.html')
else:
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
How I want this code to function is when func() is called through executor.submit(func), it starts running it and while it's running return render_template('start-crawl.html'). After executor.submit(func) finishes, it return render_template('finish.html'). Currently what happens is when I press submit on the form, the page keeps loading and then return render_template('finish.html') without return render_template('start.html'). What is the problem here?
I've got 2 python files. This is the first one:
class Downloader():
def __init__(self):
baseURL = 'https://example.com'
def getDownloadLink(self):
#linkBase = input("Text: ")
responseBase = requests.get(linkBase).content
soupBase = BeautifulSoup(responseBase, 'lxml')
And second python file:
from flask import Flask
from flask import request
from flask import render_template
from firstFile import Downloader
app = Flask(__name__)
#app.route('/')
def my_form():
return render_template("form.html")
#app.route('/', methods=['POST'])
def my_form_post():
linkBase = request.form['text']
#processed_text = text.upper()
return Downloader().getDownloadLink()
if __name__ == '__main__':
app.run()
It gives me error:
NameError: name 'linkBase' is not defined
Is it possible to connect linkBase from first file with linkBase in second file ?
The problem here is that you're trying to access a variable that doesn't exist in the scope of your getDownloadLink function.
One solution would be to add linkBase as an argument:
def getDownloadLink(self, linkBase):
responseBase = requests.get(linkBase).content
soupBase = BeautifulSoup(responseBase, 'lxml')
And then modify your route to send the value to the function:
#app.route('/', methods=['POST'])
def my_form_post():
linkBase = request.form['text']
return Downloader().getDownloadLink(linkBase)
Modify your code to pass the value as an argument:
class Downloader():
def __init__(self):
baseURL = 'https://example.com'
def getDownloadLink(self, linkBase):
#linkBase = input("Text: ")
responseBase = requests.get(linkBase).content
soupBase = BeautifulSoup(responseBase, 'lxml')
Second file:
from flask import Flask
from flask import request
from flask import render_template
from firstFile import Downloader
app = Flask(__name__)
#app.route('/')
def my_form():
return render_template("form.html")
#app.route('/', methods=['POST'])
def my_form_post():
linkBase = request.form['text']
#processed_text = text.upper()
return Downloader().getDownloadLink(linkBase)
if __name__ == '__main__':
app.run()