How to serve create-react-app from Flask? - python

How can I serve the deliverables of create-react-app via Flask?
After npm run build, this is roughly my folder tree:
src/
├── service/
│ └── app.py
└── content/
├── static
│ ├── css
│ │ └── many css files...
│ ├── js
│ │ └── many js files...
│ └── media
│ └── some images...
├── index.html
├── service-worker.js
└── manifest.json
That's the server's code:
app = Flask(__name__, template_folder='../content', static_folder='../content')
#app.route('/')
def home():
return flask.render_template('index.html')
#app.route('/static/<path:path>')
def static_files(path):
return flask.send_from_directory('../content/static', path)
if __name__ == '__main__':
app.run(debug=True)
The main html, index.html is served successfully. So are all the files under content/static/.
The files under content/ however (except index.html), are not delivered at all (error 404, not found).

Assuming you're just trying to serve a bunch of static files, that could probably be done more efficiently with a webserver like nginx.
However if you do wish to use Flask, the simplest way to do this with your exisiting directory structure is:
from flask import Flask, render_template
app = Flask(__name__,
static_url_path='',
static_folder='../content')
#app.route('/')
def index_redir():
# Reached if the user hits example.com/ instead of example.com/index.html
return render_template('index.html')
This essentially serves everything in the contents/ directory statically at the / endpoint (thanks to the static_url_path being set to an empty string)
Of course there's also the index_redir function which will render index.html if the user actually hits example.com/ instead of example.com/index.html.
This also avoids defining the static_files function from your code, as flask has the functionality to serve static files out of the box.
Again this stuff is probably better suited to nginx in a production env.

Related

Can I create a service in fastapi using an imported function from another .py file?

I have written some functions with python in separate files. My task is to transform these functions into services using fastAPI and the services should return a JSON that says if the operation is executed correctly or not (a code and a message).
For example, I have a file sum.py and inside there's a function that sums two numbers and returns the result:
def sum_of_two_numbers(a,b):
tot = a+b
return tot
Let's say I want to create a service using fastAPI, do you know if I can import sum_of_two_numbers from sum and use TestClient to complete this task without modyfing the code or re-writing it?
In this example the function is short, but have in mind my functions are different. I needed one month to write them all and make the connection to the Oracle db. While reading the documentation of fastAPI, I understood I should modify all the syntax to adapt it for fastAPI.
So, in short can I do this with fastAPI by simply importing the functions and without changing all the functions syntax? Or do you know if is there an easier way to do it?
In a basic fastapi app structure you often have something like this:
Example taken from Bastien-BO/fastapi-RBAC-microservice, inspired by Kludex/fastapi-microservices and tiangolo/full-stack-fastapi-postgresql
.
├── app
│ ├── __init__.py
│ ├── main.py
│ ├── dependencies.py
│ └── routers
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ └── models
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ └── schemas
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ └── internal
│ │ ├── __init__.py
│ │ └── crud
| | | └── user.py
| | | └── item.py
Often in your internal files you have functions or classes that you can serve with routes.
Example of a user route with internal db function call:
# app/routers/users.py
from app.internal.crud.user import crud_user
#router.get("/", response_model=List[UserOut])
async def read_users(offset: int = 0, limit: int = 100, session: Session = Depends(get_db)):
users = crud_user.get_multi(session, offset=offset, limit=limit)
return users
# app/internal/crud/user.py
def crud_user():
#do db stuff here
In this example, your sum_of_two_numbers function would be in the internal folder and you would wrap it in a route like what is done in read_users.
You should follow the user guide or the advanced user guide (fit better to your need i believe) from fastapi official doc. Also take a look at tiangolo (fastapi creator) Base Project Generator. You will have a good example on how to create a strong base for your API.

Folder structure of flask app with machine learning component

I am developing a flask based web app. A user can enter the car specifications and will get predictions of the price of the car based on a machine learning model.
I was following many tutorials on how to create a web app but I feel confused on where to put configurations on machine learning component and how to structure the code correctly.
I have the following folder structure of my project:
├── webapp
│ ├── app
│ ├── static
│ ├── templates
│ ├── routes.py
│ ├── utils.py --> utils function that are used in 'routes.py'
│ ├── src
│ ├── ml_utils.py --> functions for machine learning component
│ ├── else stuff
in routes.py:
from flask import Flask, request, render_template
from sklearn.externals import joblib
import numpy as np
from app.utils import find_freshest_model, convert_to_float, process_features_info_for_option_html, create_features
from src.ml_utils import load_features_info
app = Flask(__name__)
#app.route('/')
def home():
return render_template('index.html', car_type=option_values['car type'])
#app.route('/', methods=['POST'])
def predict():
#order features in a correct way according to order in features_info
features = create_features(request, features_info)
prediction = model.predict(features)
return render_template('index.html',
prediction_text='Your predicted car price is {} Euro'.format(prediction), quality=option_values['quality'])
if __name__ == '__main__':
model_file = find_freshest_model()
features_info = load_features_info() # containts correct order of the features and categorization of features (numerical, categorical)
option_values = process_features_info_for_option_html(features_info['features_dummy'])
model = joblib.load(model_file)
app.run(host='0.0.0.0', debug=True)
Task and Questions:
I want to prepare my app for production and to structure it better.
Should I put in init.py following code?
Regarding the code under if __name__ == '__main__':. Should I create a class modelConfigs, put it into models.py? In init.py I import modelConfigs and will initialize it routes.py.
models.py
from src.ml_utils import load_features_info
from sklearn.externals import joblib
from app.utils import find_freshest_model, process_features_info_for_option_html
class ModelConfigs:
__tablename__ = 'modelConfigs'
model = joblib.load(find_freshest_model())
features_info = load_features_info()
option_values = process_features_info_for_option_html(features_info['features_dummy'])
init.py:
from flask import Flask
app = Flask(__name__)
from app.models import ModelConfigs
model_config = ModelConfigs
from app import routes
routes.py:
from flask import request, render_template
import numpy as np
from app.utils import create_features
from app import app, model_config
#app.route('/')
def home():
return render_template('index.html', car_type=option_values['car type'])
#app.route('/', methods=['POST'])
def predict():
features = create_features(request, model_config.features_info)
prediction = np.expm1(model_config.model.predict(features))
return render_template('index.html',
prediction_text='Your predicted car price is {} Euro'.format(prediction), quality=option_values['quality'])
Flask has a feature called, "Blueprints," which allows you, separate your application into several folders so that routes and views can be kept more neatly in their own folder, yet allow one python file to call on them each individually as needed.
I mention this because it's one of the parts of Flask that Flask likes to highlight. What this does is allows you to keep your project structure cleaner, yet at the same time completely customizeable. Hypothetically you could build your own machine learning pipeline right within a blueprint, I can't think of a specific application for that - but who knows? The capability is there.
Outside of blueprints, from what I have read in a lot of different blogs and practice myself, generally for a small machine learning project, you might start off with just throwing a few things into /src since that's the, "source" folder where you put the types of things that go on the server. However you may quickly outgrow that, and need to separate your /src folder into several different folders which actually represent a legitimate data science project or pipeline structure of some type.
One way you might consider structuring your folder would be the following:
└── src
│ ├── features
│ ├── preparation
│ ├── preprocessing
│ ├── evaluation
│ └── js
└── tests
│ └── unit_tests
└── models
│ └── retrained_models
└── data
│ └── raw_data
│ └── processed_data
│ └── user_input_data
└── pipeline
│ └── model_retraining_automation_scripts
└── docs
└── Documentation
└── Notebooks
All of the above assumes you are storing everything on the server itself, which is restrictive from a data engineering perspective. Servers typically are more expensive, they run on SSD's or whatever. So if you start to grow in size and have massive amounts of data, you would need to perhaps store that in a document store such as AWS S3. If that's the case, you could think about that folder structure above to keep various operations and .py files that would perform similar functions on a small scale and translate that into a larger scale, however you might need to start storing training models as actual binaries in a database, or growing even larger, in S3 buckets, with some way of tracking what is going where, presumably a relational database.

Proper way to include builds from react apps into Flask

I have a site developed entirely using flask. It uses a Blueprint called dashboards, which hosts some views to access different visualizations, i.e dashboards/<string: dashboard_name>
I store my dashboards with an id, a name and the group it belongs to, so users can only access the visualizations from the group they also belong to.
(This is my unexperienced approach to solve this problem, so I'm also open to suggestions of a better design pattern to achieve this.)
My project kinda looks like this
app
├── dashboards
│   ├── __init__.py
│   └── views.py
├── __init__.py
├── models
│   ├── dashboard.py
│   └── __init__.p
├── static
│   ├── css
│   │   ├── styles.css
│   └── js
│   └── scripts.js
└── templates
├── base.html
└── dashboards
   ├── cat.html
   ├── clock.html
   ├── index.html
   ├── private.html
   └── public.html
my views for the Dashboard blueprint
# app/dashboards/views.py
from ..models.dashboard import Dashboard
#dashboards.route('/<string:name>')
def view_dashboard(name):
# a dictionary with dashboards available to current_user
dashboards = get_dashboards()
for dashboard in dashboards.values():
for d in dashboard:
if name == d.name:
route = 'dashboards/{dashboard}.html'.format(dashboard = d.name)
return render_template(route, dashboard=d)
else:
return render_template('404.html'), 404
and for the Dashboard blueprint
# app/dashboards/__init__.py
from flask import Blueprint
dashboards = Blueprint('dashboards', __name__)
from . import views
finally, I use the create_app pattern
# app/__init__.py
# some imports happening here
def create_app(config_name):
app = Flask(__name__)
from .dashboards import dashboards as dashboards_blueprint
app.register_blueprint(dashboards_blueprint, url_prefix='/dashboards')
return app
One level above the app, there is a manage.py that calls the create_app method, passing some configuration attributes. I believe this is a common pattern in Flask. I also believe this is not relevant to my question.
Particularly, if one deploys a react app using the create-react-app package, i.e. using npm run build, the output is a folder /build that contains the static files necessary to run the app. This folder has, for instance the following structure
├── build
│   ├── asset-manifest.json
│   ├── favicon.ico
│   ├── index.html
│   ├── manifest.json
│   ├── service-worker.js
│   └── static
│   ├── css
│   │   ├── main.<some-hash-1>.css
│   │   └── main.<some-hash-1>.css.map
│   └── js
│   ├── main.<some-hash-2>.js
│   └── main.<some-hash-2>.js.map
other files here
Now if want to plug this react-app using Flask, what I do now is to move the files in /css and /js of /build to the /static folder inside /app, and rename index.html from /build into let's say 'react-dashboard.html' and move it to templates/dashboards.
This is a very dumb approach to make basic apps working, but I don't know where to place the other files from /build, and lest about a better design pattern.
From this README I get that I can tweak the blueprint definition and move my template and static folder inside app/dashboards, but I still don't know where other files as service-worker.js, and manifests and so on.
What is the proper way to "mount" my deployed react app on my Flask application? I understand that reorganizing files from /build is something not desired.
I've solved it tweaking the blueprint
bp = Blueprint(name='myblueprint',
import_name=__name__,
static_folder='static/myblueprint',
template_folder='templates',
static_url_path='/static', # this is what myblueprint.static will point to
url_prefix='/myblueprint',
subdomain=None,
url_defaults=None,
root_path=None)
With this, my static paths inside the blueprint will point to /myblueprint/static, and I will need to modify my create-react-app build folder.
replace calls to static in every *.css, *.js and .html in /build to /myblueprint/static
rearrange folders inside /build to match my blueprint static folder.
Move /build/static to /blueprint/static
Set my own jinja template in /blueprint/templates/index.html that calls these files. Make sure this file points to the static assets in /myblueprint/static and not to /build/static.
I've created a gulpfile that will automate this process,
var gulp = require('gulp');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
// script to deploy react build into flask blueprint directory
// it replaces values and folder names
// README
// how to use this:
// in the react app, run npm run build
// copy the resulting /build folder in /myblueprint
// create a template of a template in /templates/base as index.default.html
// install gulp, gulp-replace, gulp-rename
// run gulp from /myblueprint
// replace routes inside css files
gulp.task('othertemplates', function(){
gulp.src(['./build/static/css/main.*.css'])
.pipe(replace('url(/static/media/', 'url(/myblueprint/static/media/'))
.pipe(gulp.dest('static/myblueprint/css/'));
});
// replace routes inside js files
gulp.task('jsthingtemplates', function(){
gulp.src(['./build/static/js/main.*.js'])
.pipe(replace('static/media/', 'myblueprint/static/media/'))
.pipe(gulp.dest('static/myblueprint/js/'));
});
// move other files
gulp.task('mediastuff', function(){
gulp.src(['./build/static/media/*'])
.pipe(gulp.dest('static/myblueprint/media/'));
gulp.src(['./build/asset-manifest.json'])
.pipe(gulp.dest('static/myblueprint/'));
});
// replace hashes in assets in the jinja template
gulp.task('jinjareplace', function(){
var fs = require('fs');
var assets = JSON.parse(fs.readFileSync('./build/asset-manifest.json'));
// extract hashes
let jsHashNew = assets['main.js'].match('[a-z0-9]{8}')
let cssHashNew = assets['main.css'].match('[a-z0-9]{8}')
gulp.src(['./templates/myblueprint/base/index.default.html'])
.pipe(replace('css/main.cssHash.css', `css/main.${cssHashNew}.css`))
.pipe(replace('js/main.jsHash.js', `js/main.${jsHashNew}.js`))
.pipe(rename('index.html'))
.pipe(gulp.dest('templates/myblueprint/'));
});
gulp.task('default', ['othertemplates', 'jsthingtemplates', 'mediastuff', 'jinjareplace'])
with this, you can run gulp from the same path as gulpfile.js and should have everything covered.

Flask teardown request in context of blueprint

I would like to access an sqlite3 database from a Flask application (without using Flask-SQLAlchemy, since I require fts4 functionality). I am using Flask blueprints, and I am not sure where to put the following functions (shamelessly copied from a response to this stackoverflow question):
def request_has_connection():
return hasattr(flask.g, 'dbconn')
def get_request_connection():
if not request_has_connection():
flask.g.dbconn = sqlite3.connect(DATABASE)
# Do something to make this connection transactional.
# I'm not familiar enough with SQLite to know what that is.
return flask.g.dbconn
#app.teardown_request
def close_db_connection(ex):
if request_has_connection():
conn = get_request_connection()
# Rollback
# Alternatively, you could automatically commit if ex is None
# and rollback otherwise, but I question the wisdom
# of automatically committing.
conn.close()
My file structure is:
app
├── __init__.py
├── main
│   ├── forms.py
│   ├── __init__.py
│   ├── views.py
├── models.py
├── static
└── templates
├── base.html
├── index.html
└── login.html
I want the request_has_connection() and get_request_connection() functions accessible from all view functions and maybe from models.py as well. Right now, I'm thinking they all belong in my blueprint init.py, which currently contains:
from flask import Blueprint
main = Blueprint('main',__name__)
from . import views
and that my request teardown function would be registered as
#main.teardown_request
def close_db_connection(ex):
<blah-blah-blah>
Is this right?

Get correct static urls with cherrypy dispatching of flask apps

I'm trying to use cherrypy for application dispatching with Flask. The docs give an example with a development server, but when using the cherrypy example snippet and modifying the url prefix, the page is unable to find the static folder.
My directory structure is as follows:
cherry
├── app1
│   ├── __init__.py
│   └── app1.py
├── app2
│   ├── __init__.py
│   ├── app2.py
│   ├── static
│   │   └── js.js
│   └── templates
│   └── index.html
└── cherry_app.py
Some relevant files:
## cherry_app.py
from cherrypy import wsgiserver
from app1.app1 import app as app1
from app2.app2 import app as app2
d = wsgiserver.WSGIPathInfoDispatcher({'/first': app1,
'/second': app2,
})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 9999), d)
if __name__ == '__main__':
try:
print 'Start at 0.0.0.0:9999'
server.start()
except KeyboardInterrupt:
server.stop()
## app2.py
from flask import Flask, send_file
import flask
app = Flask(__name__)
#app.route("/")
def root():
return ("Hello World!\nThis is the second app. Url is %s"
% flask.url_for('root'))
#app.route("/index")
def index():
return send_file('templates/index.html')
if __name__ == "__main__":
app.run()
## index.html
<script src="/static/js.js"></script>
JS loaded?
## js.js
alert('Loaded!');
Going to http://0.0.0.0:9999/second/ correctly tells me that the Url is /second/, and the javascript is loaded when I go to http://0.0.0.0:9999/second/static/js.js. But the html gives the error GET http://0.0.0.0:9999/static/js.js 404 (Not Found). It appears it doesn't know to use the prefix /second when looking for /static even when I change the line:
app = Flask(__name__, static_url_path='/second/static')
How can I get the webpage to correctly load the static files? Preferrably without html templating (like jinja).
Did you try to use url_for to locate static files? Here is the static files section in Flask quickstart.
So in your situation, modify src value of script element in index.html:
<script src="{{ url_for("static", "js.js") }}"></script>
The second argument js.js should be the relative path of static file (say js.js) to the static folder. So if the directory structure of static looks like:
static/scripts/js.js
just replace js.js with scripts/js.js:
<script src="{{ url_for("static", "scripts/js.js") }}"></script>
Hope this will make sense.

Categories

Resources