How to make apscheduler not double execute? [duplicate] - python

This question already has answers here:
Why does running the Flask dev server run itself twice?
(7 answers)
Closed 12 months ago.
I have the apscheduler working but for some reason when it writes to my file it makes a double-entry every time the BackgroundScheduler is called.
I'm not understanding why it writes 2 lines and the timestamp will be varied by a few milliseconds in the .txt file
I only want the 1 entry, so I can eventually have it written to a database but I need to understand what is making it double executes
I don't see where in my code that it would make it double write.
Please help thank you in advanced
main.py
from flask import Flask, render_template
from flask_caching import Cache
from flask_bootstrap import Bootstrap
from flask_ckeditor import CKEditor
from datetime import date
from apscheduler.schedulers.background import BackgroundScheduler
from market_data import MarketData
import os
sched = BackgroundScheduler()
sched.start()
current_year = date.today().year
data = MarketData()
def grab_every_five():
p_data = get_c_data()
with open(file='data.txt', mode='a', encoding='utf-8') as f:
f.write(f'{p_data}\n')
sched.add_job(grab_every_five, 'interval', minutes=1)
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
app = Flask(__name__)
cache.init_app(app)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
ckeditor = CKEditor(app)
Bootstrap(app)
#app.route('/', methods=['GET', 'POST'])
def home_page():
c_data = get_c_data()
return render_template("index.html",
year=current_year,
asset_count="{:,.0f}".format(c_data['active']),
fiat_total="{:,.2f}".format(c_data['total_market_cap']),
per_asset="{:,.2f}".format(c_data['value_per_active']),
per_all_asset="{:,.2f}".format(c_data['value_per_all']),
new_asset="{:,}".format(c_data['total_asset']),
country="{:,.2f}".format(c_data['asset_per_country']),
all_asset="{:,}".format(c_data['total_asset']),
time_stamp = c_data['time_stamp']
)
#cache.cached(timeout=60, key_prefix='c_data_cache')
def get_c_data():
temp_data = data.get_data()
return temp_data
if __name__ == "__main__":
app.run(debug=True)

Ok i found the answer in this post apscheduler in Flask executes twice
It turns out with debug mode on it has the reloader also load an instance of the apscheduler
The easiest and fastest fix was to turn off the reloader as mentioned in the article I've linked to
I just had to add this line of code:
app.run(use_reloader=False)

Related

SQLAlchemy queries in a function scheduled to run every hour on Flask using APScheduler

For my flask app I have a folder called 'flaskblog'.
In the same directory I have run.py:
from flaskblog import app, db
db.init_app(app)
if __name__ == '__main__':
app.run(debug=True, port=5000)
Inside flaskblog folder init.py:
#...some more code
from flask import Flask
app = Flask(__name__)
app.config.from_object(Config)
#.. and so on
def register_app(app):
"""Create an application."""
main_blueprint = Blueprint('main', __name__)
app.register_blueprint(main_blueprint)
return app
register_app(app)
# import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
# define the job
from flaskblog.models import Chatmessage
from datetime import datetime, timedelta
def hello_job():
today = datetime.today()
start_date = today - timedelta(days=1)
end_date = today + timedelta(days=1)
messages = Chatmessage.query.filter(Chatmessage.date_sent <= end_date).\
filter(Chatmessage.date_sent >= start_date).all()
print(today, start_date, end_date)
print('Hello Job! The time is: ')
# init BackgroundScheduler job
scheduler = BackgroundScheduler()
# in your case you could change seconds to hours
scheduler.add_job(hello_job, trigger='interval', seconds=10)
scheduler.start()
#find correct place to put job starts
I am trying to schedule a function to run every now and then like explained in this question:
How to schedule a function to run every hour on Flask?
The problem is that I want to use models, Flask-SQLAlchemy.. like Model.query... but it cannot be used before applications is registered "register_app(app)" because of circular imports. So I put schedule after comment "#import BackgroundScheduler" in my code.
Is it a correct way to do it? I get the doubt from reloading visual code debugger and seeing that function hello_job() from last reload is still running, or if app fails to load function hello_job() starts to run anyways. So am afraid it could have issues on production server.
You can do something like this
in your init.py
...
scheduler = BackgroundScheduler()
scheduler.start()
atexit.register(lambda: scheduler.shutdown())
...
#at the end
import job
in a job.py
from init import scheduler
cron_time = '0 * * * *'
#scheduler.scheduled_job(CronTrigger.from_crontab(cron_time), id='hello_job')
def hello_job():
...

Python Tkinter with Flask API and Subprocess

Could I run a function from another python file inside subprocess?
I use pyinstaller to convert the tkinter to an executable file. As much as possible I would like to deploy/run the .exe file to another computer without installing python.
#gui.py
from tkinter import *
import os
import subprocess
root = Tk()
root.geometry("300x150")
def backendStart():
subprocess.Popen(["test.py"], shell=True)
label = Label(root, text="Connection String", fg="grey", font=("Helvetica", 15, "bold"))
label.pack(pady=(0,3))
root.after_idle(backendStart)
root.mainloop()
Here is my sample app.py
from flask import Flask, jsonify
from flask_restful import Api, Resource
from flask_socketio import SocketIO, emit
from flask_cors import CORS
import random
from connection import cursor
app = Flask(__name__)
app.config["DEBUG"] = True
api = Api(app)
CORS(app)
socketio = SocketIO(app, cors_allowed_origins="*")
#socketio.on("connect")
def ClientConnection():
print("Client is Connected")
#socketio.on("realtime", namespace="/sample-socket")
def RealTimeData():
while True:
num = random.randint(1, 100)
emit("data", {"random": num})
socketio.sleep(1)
#socketio.on("disconnect")
def ClientDisconnected():
print("client has disconnected")
class HomePage(Resource):
def get(self):
return jsonify(msg="hello world")
api.add_resource(HomePage, "/")
if __name__ == '__main__':
socketio.run(app, host="192.168.0.109", port=5000)
Currently I made a .spec file for configurating the names, logo, and files/libs included. The .exe file work as long as I pasted the app.py inside the build folder along with the connection.py for the database.
But with this set up I do need to install python along with the libraries I used for the app.py and connection.py
Could I run a function from another
python file inside subprocess?
you can use multiprocessing.Process()
Edit:
For an expert's answer, see here
Alternate solution:
Lets say you want to run app.exe (which is app.py), you can pack all of them into one folder (--onedir) and put those exe's and pyd's subfolders.... together, like
gui
----flask (and other folders)
----*.pyd
----app.exe
----gui.exe
----python39.dll
you will need a custom spec file to do that.
see https://pyinstaller.readthedocs.io/en/stable/spec-files.html#multipackage-bundles

Python 3.8 module duplication and app object scope within imported functions

I'm confused about import of custom modules. As you can see in the code below, in main I first import all libraries needed by everything AND that I duplicated those imports in my i_setup_functions.py file. Leaving any of them out of either file created errors. Same with duplication of "app = Flask(name)". I really hope that redundancy is not correct and there is some simple way to fix this. All I want to do is include setup for sessions, email, data connection, etc. Only showing sessions here for simplicity sake.
BTW: The entire app worked bug-free until I tried to modularize.
Error message:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
That error message points to a line in a function in the middle of main.py that tries to create a session.
Thanks for any ideas you all can share!
main.py:
from flask import session
import random
from datetime import datetime, timedelta
from i_setup_functions import setup_sessions
app = Flask(__name__)
# is the following line even necessary in either module?
application = app
setup_sessions()
setup_mail()
setup_logging()
[snip]
# Error here:
​session["id_user"] = id_user
i_setup_functions.py
from flask import session
import random
from datetime import datetime, timedelta
from i_setup_functions import setup_sessions
app = Flask(__name__)
application = app
def setup_sessions():
random.seed(datetime.now())
app.config['SECRET_KEY'] = str(random.randint(1, 500)) + "jibber" + str(random.randint(1, 500)) + "jabber"
app.permanent_session_lifetime = timedelta(days=30)
return True
You are creating two (or more?) separate apps and setting the SECRET_KEY to the one that isn't serving your application.
To fix this remove all app = Flask(__name__) calls from all modules except main.py. Then, pass the app you create in main.py to all the places you need it.
from flask import session
import random
from datetime import datetime, timedelta
from i_setup_functions import setup_sessions
app = Flask(__name__)
setup_sessions(app)
setup_mail(app)
setup_logging(app)
[snip]
​session["id_user"] = id_user

Python Mock Test

I am trying to mock test an endpoint that gets the time and date.
I have viewed several tutorials and python docs, but I am still getting stumped by the mock test.
Any help is appreciated greatly
from flask import Flask, redirect, url_for
import json
import urllib.request
import requests
app = Flask(__name__)
#app.route('/')
def welcome():
return "Hello"
#app.route('/<zone>')
def Endpoint(zone):
address = f"http://worldclockapi.com/api/json/{zone}/now"
response = urllib.request.urlopen(address)
result = json.loads(response.read())
time = result['currentDateTime']
return time
if __name__ == "__main__":
app.run(debug=True)
My attempt.
I think I am still calling the external element.
I want to use a fake JSON string and actually mock with that.
The first test passes when I run it. But I don't think it is a true mock.
#!/usr/bin/python
import unittest
from unittest import TestCase
from unittest.mock import patch, Mock
#name of endpoint program
import question
class TestingMock(TestCase):
#patch('question.Endpoint')
def test_call(self, MockTime):
current = MockTime()
current.posts.return_value = [
{"$id": "1", "currentDateTime": "2020-07-17T12:31-04:00", "utcOffset": "-04:00:00"}
]
response = current.posts()
self.assertIsNotNone(response)
self.assertIsInstance(response[0], dict)
#patch('question.Endpoint')
def test_response(mock_get):
mock_get.return_value.ok = True
respond = question.Endpoint()
assert_is_not_none(respond)
if __name__ == '__main__':
unittest.main()
You are conflicting with your root URL handler. Try changing #app.route('/<zone>') to #app.route('/time/<zone>'), then navigate to that url

Python program seems to be running twice [duplicate]

This question already has answers here:
How to stop Flask from initialising twice in Debug Mode? [duplicate]
(2 answers)
Closed 8 years ago.
I have a python program which is running Flask. I noticed a strange thing, it looks like the program is running twice, which I do not want.
Here is the file for starting the program(runserver.py, in the root folder /):
from myapp import app
if __name__ == "__main__":
print "woho"
app.run(host='0.0.0.0',debug=True)
When running this, I can see two "woho" in the terminal, indicating that something is strange.
in the folder /myapp I have __init__.py:
from flask import Flask
app = Flask(__name__)
import myapp.views
and then in my views.py (also in /myapp) I have all the views like:
from myapp import app
from flask import render_template
#app.route('/')
def index():
return render_template('index.html')
it's due to the reloader of flask/werkzeug, which reloads automatically when you change the code.
so give debug=False if you don't want/need that, e.g. for "production".
How to stop Flask from initialising twice in Debug Mode?

Categories

Resources