How to create a global counter variable inside a chalice webhook - python

I am trying to create a variable that I can retrieve outside of the function counts every time a chalice webhook alert is triggered. I cannot figure out how to get the variable out of the function. Here is my code. Thank you!
from chalice import Chalice
app = Chalice(app_name='tv_alert')
counter = None
#app.route('/')
def index():
return {'hello': 'world'}
#app.route('/tv', methods=['POST'])
def tv():
request = app.current_request
webhook_message = request.json_body
if webhook_message != 0:
counter += 1
return {
'message': 'I received the webhook notification!',
'webhook_message': webhook_message
}
print(counter)

Related

How to mock a function in a flask get request?

I recently wrote a webapi and i need to test a function. But im having trouble returning the mock value. Heres my hello.py:
from flask import Flask, request
import traceback
import json
app = Flask(__name__)
#app.route("/main")
def hello_world():
return "<p>Hello, World!</p>"
def determine_env(check):
if check == 'test':
return 'test'
elif check == 'hello_prod':
return 'prod'
elif check == 'hello_dev':
return 'dev'
else:
return "you must have gotten the wrong env"
#app.route("/main/rate_and_borrow_data")
def rate_and_borrow_data():
try:
print("testing request method")
print(request.args)
directory = request.args['udl']
env = determine_env(directory)
print(env)
args = request.args.getlist("args")
print(f"The arguments are: {args}")
if request.args.get("data") == 'rate':
print("the rate is in there")
return "finished"
except:
traceback.print_exc()
return json.dumps({'error': traceback.format_exc()})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=81, debug=True)
Now i want to write unittests on this api. my directory structure is as follows:
Test-flask-connectivity > app > hello.py
> tests > test_hello.py
Inside test_hello.py, i have written the following tests:
import unittest
import requests
import os
from unittest.mock import patch
from app.hello import determine_env
class TestFlaskApi(unittest.TestCase):
def setUp(self):
self.payload = {'data': 'rate', 'file_path': 'nwklgat/test', 'args': ['AAPL', '3', 'TMI'], 'url': 'http://localhost:81/main/rate_and_borrow_data',
'udl': 'test'}
#patch('app.hello.determine_env', return_value='monkeys_love_development')
def test_rate_and_borrow_data(self, m1):
url = self.payload['url']
r = requests.get(url, params=self.payload)
if __name__ == '__main__':
unittest.main()
Now, im expecting the print statement to say "monkeys love development" for the statement
env = determine_env(directory)
since i patched the above function. But its not giving me this value. Its giving me "test". May i know what i did wrong? Thanks

Python Flask infinite loop use global list which can be extended

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")

can't initialize values before starting App in Flask

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()

Is there a way to render multiple templates and run a function at the same time in Flask?

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?

How to pass variable to the Flask function while using threading?

I want to create multiple threads and every one of them should create flask app.
I am not sure how to do it, but that's what I have:
app = Flask(__name__)
app.url_map.strict_slashes = False
#app.route('/api/v1/something/<string:FirstArgument>/<string:SecondArgument>/', methods=['POST'])
def do_it(FirstArgument, SecondArgument):
request_str = request.get_data().decode('utf-8').strip()
response = somefunction(mydata.state, request_str)
return response, 200
def run_app(this_port, mydata):
currentThread = threading.current_thread()
mydata.state = some_function_that_returns_6GB_of_data()
app.run(host='0.0.0.0',port=this_port)
if __name__ == '__main__':
mydata = threading.local()
thread1 = Thread(target=run_app, args=(4100, mydata,))
#thread2 = Thread(target=run_app, args=(4101,mydata,))
thread1.start()
#thread2.start()
For now I want to test only one thread. And I don't know how to pass mydata.state to the 'do_it'. If I add new argument (def do_it(FirstArgument, SecondArgument, mydata.state)) than Flask says that he wants to get this variable from the app.route. How can I pass this data to the do_it function?
And one more question. This program will pas N instances of state to N threads on N ports?
Or I should do something like this:
def do_it(FirstArgument, SecondArgument):
request_str = request.get_data().decode('utf-8').strip()
response = somefunction(mydata.state[threading.get_ident()], request_str)
return response, 200
def run_app(this_port, mydata):
currentThread = threading.current_thread()
mydata.state[threading.get_ident()] = some_function_that_returns_6GB_of_data()
app.run(host='0.0.0.0',port=this_port)

Categories

Resources