import os, re
from flask import Flask, send_from_directory, json,request
from flask_socketio import SocketIO
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
import random
app = Flask(__name__, static_folder='./build/static')
# Point SQLAlchemy to your Heroku database
uri = os.getenv("DATABASE_URL") # or other relevant config var
if uri and uri.startswith("postgres://"):
uri = uri.replace("postgres://", "postgresql://", 1)
app.config['SQLALCHEMY_DATABASE_URI'] = uri
# Gets rid of a warning
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
import models
cors = CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(
app,
cors_allowed_origins="*",
json=json,
manage_session=False
)
#app.route('/', defaults={"filename": "index.html"})
#app.route('/<path:filename>')
def index(filename):
return send_from_directory('./build', filename)
# When a client connects from this Socket connection, this function is run
#socketio.on('connect')
def on_connect():
print('User connected!')
# When a client disconnects from this Socket connection, this function is run
#socketio.on('disconnect')
def on_disconnect():
print('User disconnected!')
#socketio.on('index')
def on_index():
all_students = db.Students.query.all()
random1 = random.randint(0,models.Students.query().count())
random2 = random.randint(0,models.Students.query().count())
total_table = []
for student in all_students:
total_table.append(student)
firstStudent = []
secondStudent = []
while(random2 == random1):
random2 = random.randint(0,models.Students.query().count())
firstStudent.append(total_table[random1])
secondStudent.append(total_table[random2])
twoStudents = [firstStudent,secondStudent]
socketio.emit('students', {twoStudents:twoStudents})
# Note we need to add this line so we can import app in the python shell
if __name__ == "__main__":
# Note that we don't call app.run anymore. We call socketio.run with app arg
socketio.run(
app,
)
The react end of the application launches fine with no errors, and the database has no issues. I've used this skeleton for the base of a bunch of other projects and i've never had any issues. But for some reason i'm stuck at a brick wall setting this up. I know the issue is within the #app.route('/') part of the code. i've tried hard coding the html file into the url path, but that just causes other errors like missing 1 required positional argument: 'filename' flask. Any help is greatly appreciated
I tested your configuration and it doesn't give me any errors. Nevertheless I offer you an alternative solution.
You can provide the entire react build folder as a static folder. You can then deliver the "index.html" as a single file in the root route. The prerequisite is that the prefix for the static url path is empty.
# ...
app = Flask(__name__,
static_url_path='',
static_folder='./build'
)
# ...
#app.route('/')
def index():
return app.send_static_file('index.html')
# ...
Related
[Flask SSE API doesn't work on production]
Hi, i'm facing an issue in my flask application where I have multiple regular APIs and 1 HTTP API that sends SSE to my React app. In my local development env, the app works just fine as expected. However, when I deployed it to CPanel shared hosting, I noticed that the the React app makes proper request of Content-Type text/event-stream, but received text/html response header from the API after 2 minute timeout. Is there anything wrong with how I implemented the server?
main.py
from myapplication import create_app
from flask import stream_with_context
from gevent import monkey; monkey.patch_all()
from gevent.pywsgi import WSGIServer
app = create_app()
if __name__ == '__main__':
http_server = WSGIServer(("localhost", 5000), app)
http_server.serve_forever()
myapplication/init.py
from flask import Flask
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from os import path, environ
from dotenv import load_dotenv
db = SQLAlchemy()
DATABASE_NAME = 'database.db'
load_dotenv()
def get_database_uri():
host = environ['DB_HOST']
port = environ['DB_PORT']
name = environ['DB_NAME']
username = environ['DB_USER']
password = environ['DB_PASS']
return f'postgresql+psycopg2://{username}:{password}#{host}:{port}/{name}'
def create_database(app):
if not path.exists('myapplication/' + DATABASE_NAME):
db.create_all(app=app)
print('Database created.')
def create_app():
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource = {
r"/*": {
"origins": "*"
}
})
app.config['SECRET_KEY'] = environ['SECRET_KEY']
app.config['SQLALCHEMY_DATABASE_URI'] = get_database_uri()
db.init_app(app)
from .gallery import gallery
from .document import document
from .timer import timer
from .member import member
app.register_blueprint(gallery, url_prefix='/gallery')
app.register_blueprint(document, url_prefix='/document')
app.register_blueprint(timer, url_prefix='/timer')
app.register_blueprint(member, url_prefix='/member')
from .models import Member, Gallery, Document, Timer
create_database(app)
return app
timer.py (SSE api)
global_count = '60'
global_refresh_count = '0'
#timer.route('/stream')
def get_current_stream():
def send_event():
while True:
event_payload = '{"count": "%s", "refreshCount": "%s"}'%(global_count, global_refresh_count)
data_message = f'data: {str(event_payload)}\n\n'
yield data_message
time.sleep(1)
return Response(send_event(), mimetype='text/event-stream')
Local development response:
dev response
Local development eventstream response:
dev event stream response
Production response:
prod response
CPanel python app setup:
Application startup file: passenger_wsgi.py
Application Entry point: application
passenger_wsgi.py
import imp
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))
wsgi = imp.load_source('wsgi', 'main.py')
application = wsgi.app
Please kindly help guide me folks, much appreciated!
you have to set certain headers like below
resp = Response(
send_event(),
mimetype='text/event-stream'
)
resp.headers['X-Accel-Buffering'] = 'no'
resp.headers['Cache-Control'] = 'no-cache'
return resp
and configure setting throughout your service
for example in case of nginx:
location '/' {
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 12h;
...
proxy_pass {your_route};
}
in case of gunicorn:
set timeout param to 0 when you execute it.
/{path_to}/gunicorn --workers {num_workers} --timeout 0 --bind {path} -m 007 {module}:{app_name}
Is there a way to return multiple responses to 1 get request?
I have a basic flask app where I am trying to make it run another python app and send the terminal logs to the client side.
I can return a json value but I can't return any text or the output of the terminal.
Here is the server side:
from flask import Flask, stream_with_context, request, Response
from flask_restful import Api, Resource
from flask_socketio import SocketIO
import intermedia_choose_action_flask
import subprocess
app = Flask(__name__)
api = Api(app)
socketio = SocketIO(app)
class spamblacklistsend(Resource):
def get(self):
imapp = subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockeveryone", "--ed", "test#fakeu.com"], bufsize=10, errors='replace')
imapp.app_context().push()
# p = subprocess.Popen(["python3", "/home/tech/scripts/Intermedia_automate/intermedia_choose_action.py", "--addblockeveryone", "--ed", "test#fakeu.com"], bufsize=10, errors='replace')
return imapp.app_context().push()
api.add_resource(spamblacklistsend, "/spamblacklistsend")
if __name__ == "__main__":
app.run(debug=True)
Here is the client side:
from flask import json
import requests
BASE = "http://127.0.0.1:5000/"
response = requests.get(BASE + "spamblacklistsend")
print(imapp.app_context().push())
I know that return stops the function. Is there anyway to return and continue?
I want to set a basepath for my flask application. I have mentioned one example below.
basepath = 'http://localhost:3000/api'
i have two api call one is GET and other one is POST .
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app)
api.add_resource(CreateUser, "/v1/user/create/")
api.add_resource(CreateUser, "/v1/user/details")
class CreateUser(Resource):
def post(self):
# Code for creating a user
def get(self):
# Code for get the details of user.
So here, if i want to create the user then my url will be http://localhost:3000/api/v1/user/create/
so same for GET also . So how do i achieve this ?
Initialize your Api with the path prefix:
from flask import Flask
from flask_restful import Api
app = Flask(__name__)
api = Api(app, "/api")
...
You can't change the host and port this way, you'll have to run flask with parameters:
flask run --host=127.0.0.1 --port=3000
Or you could do
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app, "/api")
...
if __name__ == "__main__":
app.run(host="127.0.0.1", port="3000")
Please keep in mind this is not intended for production environments, only for local testing. Please see https://flask.palletsprojects.com/en/1.1.x/tutorial/deploy/ for using in a production environment.
If you want to get those values from basepath, one option would be purl:
url = purl.URL('http://localhost:3000/api')
url.host() # --> "localhost"
url.port() # --> 3000
url.path() # --> "/api"
I need help in debugging -the Same Origin Policy disallows reading the remote resource at https://some-domain.com. (Reason: CORS request did not succeed) in python flask-socketio error.
I am working on a chat application using python flask-socketio. In previously I have created that application in local and it works fine as expected, while I move the below code to the server it shows the above error. The client code runs in the https servers and server code also runs on the https server I don't know why that error shows.
I have attached my code below and please give a better solution to me.
server.py
import json
import os
from flask import Flask, render_template, request,session
from flask_socketio import SocketIO, send, emit
from datetime import timedelta,datetime
from flask_cors import CORS
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secretkey'
app.config['DEBUG'] = True
app.config['CORS_HEADERS'] = 'Content-Type'
cors = CORS(app, resources={r"/*": {"origins": "*"}})
socketio = SocketIO(app)
users = {}
#app.before_request
def make_session_permanent():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=1)
#app.route('/')
##cross_origin(origin='*',headers=['Content- Type','Authorization'])
def index():
return render_template('index.html')
#socketio.on('connect')
def connect():
print("connected");
#app.route('/orginate')
def orginate():
socketio.emit('server orginated', 'Something happened on the server!')
return '<h1>Sent!</h1>'
#socketio.on('username')
def receive_username(username):
users[username] = request.sid
#users.append({username : request.sid})
#print(users)
emit('userList', users, broadcast=True)
print('Username added!')
print(users)
if _name_ == '__main__':
socketio.run(app,host='xxx.xxx.xx.x',port=5001)
client.js
var socket = io.connect("https://xxx.xxx.xx.x:5001/",{secure:false});
Screenshot 1:
This screenshot explains the access-control-allow-orgin works fine for images under static folder in flask framework
Screenshot 2:
This screenshot explains there is no access-control-orgin for socket call
You are using Flask-CORS to set up CORS on your Flask routes. You are missing a similar set up for Flask-SocketIO:
socketio = SocketIO(app, cors_allowed_origins=your_origins_here)
You can use '*' as the value to allow all origins (which I do not recommend), or set a single origin as a string, or a list of origins as a list of strings.
I've found similar questions, but they seem to only cover mocking MongoDB and don't mention Flask.
I have a Flask app and I'm trying to unit test it with PyTest (including PyTest-Mongo and PyTest-Flask). However, before I can even get to the point of writing any tests, my test script crashes. The crash happens when importing the script with my Flash app: It's trying to create the PyMongo object without a url.
My question is: How can I ensure that PyMongo is mocked correctly at this point? According to the PyTest-Mongo documentation, the MongoDB test fixture should be passed to each of the test functions, but that doesn't help me if it's crashing on import.
test_app.py:
import pytest
import pytest_mongodb
from app import app
#pytest.fixture
def client():
app.config['TESTING'] = True
return client
app.py:
import ...
app = Flask(__name__)
app.config["MONGO_DBNAME"] = os.environ.get('DB_NAME')
app.config["MONGO_URI"] = os.environ.get('MONGO_URI')
app.secret_key = os.environ.get('SECRET')
mongo = PyMongo(app)
...
if __name__ == '__main__':
app.run(host=os.environ.get('IP'),
port=int(os.environ.get('PORT')),
debug=False)
we can wrap app and mongo in a function
This works because mongo is used as a local variable.
app.py
from flask import Flask
from flask_pymongo import PyMongo
def get_app_with_config(config):
app = Flask(__name__)
app.config.from_object(config)
mongo = PyMongo(app)
#app.route("/")
def index():
pass
.
.
return app, mongo
then we can create a test file and an application execution file with different databases:
test_app.py
from app import get_app_with_config
from config import TestConfig
app, mongo = get_app_with_config(TestConfig)
run.py
from app import get_app_with_config
from config import RunConfig
app, mongo = get_app_with_config(RunConfig)
if __name__ == '__main__':
app.run(port=8000)
Sample of config.py file:
class RunConfig:
MONGO_HOST = '192.168.1.37'
MONGO_PORT = 27017
MONGO_DBNAME = 'my_database'
MONGO_URI = f"mongodb://{MONGO_HOST}:{MONGO_PORT}/{MONGO_DBNAME}"
class TestConfig:
MONGO_HOST = '192.168.1.37'
MONGO_PORT = 27017
MONGO_DBNAME = 'my_database_test'
MONGO_URI = f"mongodb://{MONGO_HOST}:{MONGO_PORT}/{MONGO_DBNAME}"
TESTING = True
Needed a quick fix so I edited app.py so that it only hard-fails if PyMongo doesn't initialise when the file is executed (i.e. it ignores PyMongo's failed initialisation when running unit-tests.)
app = Flask(__name__)
app.config["MONGO_DBNAME"] = os.environ.get('DB_NAME')
app.config["MONGO_URI"] = os.environ.get('MONGO_URI')
app.secret_key = os.environ.get('SECRET')
try:
mongodb = PyMongo(app).db
except ValueError:
"""We don't provide a URI when running unit tests, so PyMongo will fail to initialize.
This is okay because we replace it with a version for testing anyway. """
print('PyMongo not initialized!')
mongodb = None
.
.
.
if __name__ == '__main__':
if not mongodb:
print('Cannot run. PyMongo failed to initialize. Double check environment variables.')
exit(1)
app.run(host=os.environ.get('IP'),
port=int(os.environ.get('PORT')),
debug=False)
In my tests file, I just assign the mocked mongoDB client to the app in the tests that need it. Definitely not the ideal solution.
def test_redacted(client, mongodb):
app.mongodb = mongodb
...