Has anyone tried this snippet flask config based static folder code cnippet?
The code:
import flask
class MyFlask(flask.Flask):
#property
def static_folder(self):
if self.config.get('STATIC_FOLDER') is not None:
return os.path.join(self.root_path,
self.config.get('STATIC_FOLDER'))
#static_folder.setter
def static_folder(self, value):
self.config.get('STATIC_FOLDER') = value
# Now these are equivalent:
app = Flask(__name__, static_folder='foo')
app = MyFlask(__name__)
app.config['STATIC_FOLDER'] = 'foo'
In my case in complains about this line:
self.config.get('STATIC_FOLDER') = value
The error message: Can't assign to function call
Does anyone how to set the static_folder from the config.py file in Flask?
Okay, I assume you want to use a custom path to the static folder for whatever reason. I wanted to do the same for the sake of better app modularity.
Here's my app folder structure:
instance/
core/
|_templates/
|_static/
|_views.py
run.py
config.py
As you can see, my static folder is inside the core folder.
In run.py, you can do the following:
app = Flask(__name__, static_url_path=None)
if __name__ == '__main__':
app.config.from_object('config')
# config file has STATIC_FOLDER='/core/static'
app.static_url_path=app.config.get('STATIC_FOLDER')
# set the absolute path to the static folder
app.static_folder=app.root_path + app.static_url_path
print(app.static_url_path)
print(app.static_folder)
app.run(
host=app.config.get('HOST'),
port=app.config.get('PORT'),
threaded=True
)
This is what I did, and it works perfectly fine. I'm using flask 0.12.
I don't know anything about that snippet, but
some_function(...) = some_value
is never valid Python (Python doesn't have l-values). It looks like config has a dict-like interface, so the offending line should probably just be
self.config['STATIC_FOLDER'] = value
Probably a copy-and-paste error from the getter definition above the setter.
app = Flask(__name__, static_url_path="/STATIC_FOLDER", static_folder='STATIC_FOLDER')
Yes, In one of my projects I am using/setting a custom path for STATIC_FOLDER. You can set the path to STATIC_FOLDER in config.py like below:
STATIC_PATH = '<project-name>/<path-to-static-folder>/'
ex:
STATIC_PATH = 'myApp/static/'
If you can write your project structure then I can answer it as per your requirements.
FYI if you want your directory to be outside of the server directory the best solutions I found so far are either to make a copy of your directory into the server directory before startup in your main(), or to create a symlink.
Related
I'm initializing app using connexion 2.4.0 library like this:
connex_app = connexion.App(__name__, specification_dir='./')
app = connex_app.app
I need to specify the path to my static and templates directories somehow since they are not located in the root directory.
In Flask I would use something like this
app = Flask(__name__, static_folder='../frontEnd/static', template_folder='../frontEnd/templates')
I know that connexion looks for static and templates in the root by default, but is there any way to indicate another path?
Has an opening issue about this problem:
https://github.com/zalando/connexion/issues/441
And a opening pull request:
https://github.com/zalando/connexion/pull/710
But the problem is not solved.
You can you this approach How to set static_url_path in Flask application just remember to use app.app to access the flask instance.
This is now possible following the merge of https://github.com/spec-first/connexion/pull/1173
You can now specify these arguments in the server_args constructor argument e.g.
connexion.FlaskApp(
server_args={'static_url_path': '/your/path/'}
)
Gids is technically correct, you can now pass flask keyword arguments to the created app.
The correct combination for your two code snippets would be:
connex_app = connexion.App(__name__, specification_dir='./', server_args={'static_folder'='../frontEnd/static', 'template_folder'='../frontEnd/templates'})
app = connex_app.app
The parameter is not read from files other than the run.py . run.py is the Flask startup script
from run.py :
from flask import Flask
app = Flask(__name__)
print(app.config["PARAMETER"])
From any other python file in project following error is returned :
KeyError: 'PARAMETER'
How to read configuration file from other locations within project other than startup script file ?
Update :
Reading config file :
app.config.from_pyfile(os.path.join(".", "myconfig.conf"))
Contents of myconfig.conf :
PARAMETER = "test"
I think you just simply missed loading parameters.
If you do inline loadign of parameters, you would specifiy it as:
from flask import Flask
app = Flask(__name__)
app.config['PARAMETER_1'] = 'test'
assert app.config["PARAMETER_1"] == 'test'
The code above works, now how can one load similar data from file?
# prepare file
from pathlib import Path
Path("myconfig.conf").write_text("PARAMETER_2 = 'test2'\n")
# load it
app.config.from_pyfile("myconfig.conf")
# test it
assert app.config["PARAMETER_2"] == 'test2'
You can't print the PARAMETER key after the creation of the app because there is no any key into its configuration object which its name is PARAMETER. In order to do it, first create the app, import a simple object which holds the configuration and then use app.config.from_object(Config)
#config.py
class Config(object):
PARAMETER = 'my-parameter-value'
#you can add another keys
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
#__init__.py
from config import Config
app = Flask(__name__);
app.config.from_object(Config)
My goal is to set LIBSASS_STYLE="expanded" via flask_assets.Bundle. The webassets libsass documentation says I can do it, but doesn't say how.
My base app controller looks like the following.
from flask import Flask, render_template
from flask_assets import Environment, Bundle
app = Flask(__name__)
# ... Typical flask controller stuff
if __name__ == "__main__":
assets = Environment(app)
css = Bundle(
'sass/*.scss', # input scss files
filters='libsass', # to be compiled by libsass
output='css/style.css' # and outputed to style.css
)
assets.register("asset_css", css)
app.run(debug=True)
This outputs a valid css file (which is great) but not in the format that I desire since I simply have no idea where I can slip any libsass options.
Any help on this issue is greatly welcome. Thanks!
You need to instantiate libsass filter explicitly to pass options to it
from flask_assets import Bundle
from webassets.filter import get_filter
libsass = get_filter(
'libsass',
as_output=True,
style='compressed',
)
css = Bundle(
'sass/*.scss',
filters=(libsass),
output='css/style.css'
)
I'm trying to use Flask-Scss to compile a scss file in my flask app. Here is my app:
from flask import Flask, jsonify, render_template, request
from flask_scss import Scss
app = Flask(__name__)
app.debug = True
Scss(app, static_dir='static', asset_dir='assets/scss/')
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
This file is in a directory that also contains a static directory and assets directory. Furthermore, assets contains a scss directory, which holds the file test.scss. When I run the app, I don't see any css files getting created inside of static. Can someone please tell me what I'm doing wrong?
You have to put absolute path for it to work. Assuming your structure is app/init.py then this should be your code:
Scss(app, static_dir='app/static', asset_dir='app/assets/scss')
NOTE: Don't forget to reload the page for the compiling to happen. If you don't reload the page then scss files will not be compiled to css.
I recommend using libsass, it works for both Sass and SCSS files. After you import sass simply use the compile function with the dirname keyword argument, like this:
sass.compile(dirname=('path/to/source', 'path/to/target'))
You also have the option to set the output style, for example:
sass.compile(dirname=('path/to/source', 'path/to/target'), output_style='compressed')
If you want to watch a file or directory for automatic compilation on every edit use boussole.
So I have successfully deployed an app using webapp2/jinja2 and a Paste server, but am having trouble serving static stylesheets.
I have had luck accessing static files via this method, as well as implementing a StaticFileHandler I found with some google-fu:
import os
import mimetypes
import webapp2
import logging
class StaticFileHandler(webapp2.RequestHandler):
def get(self, path):
abs_path = os.path.abspath(os.path.join(self.app.config.get('webapp2_static.static_file_path', 'static'), path))
if os.path.isdir(abs_path) or abs_path.find(os.getcwd()) != 0:
self.response.set_status(403)
return
try:
f = open(abs_path, 'r')
self.response.headers.add_header('Content-Type', mimetypes.guess_type(abs_path)[0])
self.response.out.write(f.read())
f.close()
except:
self.response.set_status(404)
where my main app routing looks like:
app = webapp2.WSGIApplication([('/', HelloWorld),
(r'/display', DisplayHandler),
(r'/static/(.+)', StaticFileHandler)
], debug=True)
My css files are in a folder under the app root: /static/css/main.css
I can access the file via direct url, and even link it as a stylesheet, but the styles won't apply. Any ideas? Is there another way to serve stylesheets? Some way to implement an app.yaml similar to GAE?
you dont need a static file handler.
upload the app with the static file folder by adding this to your app.yaml
- url: /static/
static_dir: static
docs are here: https://developers.google.com/appengine/docs/python/config/appconfig#Static_Directory_Handlers
edit:
see answer below in comments
#Mnemon, hats off to you for solving my problem. I would upvote you but I'm not allowed to do that. You convinced me that if it's not the only webapp2 way without GAE, it's at least a way that will work.
But also I can contribute that your solution is now installable as "pip install webapp2_static", from pipi--- by an author who seems to be using his real name... you I'm sure. Other webapp2 docs that I found helpful are available here.
I'm implementing your code on a Linux desktop development server, using paste, which you also used:
def main():
from paste import httpserver
httpserver.serve(app, host='127.0.0.1', port='8080')
But with the code as you have it above (which appears to be utterly identical to that of webapp2_static.py file), I don't find that putting my css files in a folder named static in the app root works as you said.
For example, I have /home/user/proj/public_html/app/app.py, where the py file contains your code plus other "views" for my ultra-simple site. (I don't know how paste really works, so maybe for now the public_html is just in there for reference so that I don't become confused when I'm uploading stuff onto the production server.)
So if I put the css stylesheets into a folder named /static, then, if I put /static in as either a subdirectory of /app or of /public_html I find that neither location works; I must instead make it a subdirectory of /proj.
I wasn't expecting that, but the cure for me is to change the default 'static' in your app.configure.get(..., 'static') call, to 'public_html/app/static'. Then it works, with the /static folder inside /app.
Similarly using the pipi code with './app/static/ in place of the default 'static' doesn't work; I found that I need ./public_html/app/static instead (or maybe it was just /public_html/app/static or even public_html/app/static... I forgot... one of those worked).
I tested how your computation of abs_path works and have reworked it in the code below, in which I have junked your approach in favor of something more Djangoesque. To wit, in my one app py file I put at the top the following:
STATIC_DIR = os.sep + 'tostatic' + os.path.abspath(os.path.dirname(__file__)) + os.sep + 'static'
Then in the page to which I want to add css, my Home page in my case, I put a very readable:
<link href="{{STATIC_DIR}}/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css">
For the "view" that generates my Home page I have (env is a jinja2 Environment object that takes a template loader as an argument):
class Home(webapp2.RequestHandler):
def get(self):
template = env.get_template('index.html')
template_values = {'STATIC_DIR': STATIC_DIR }
self.response.write(template.render(template_values))
And finally the URL routing is as in:
app = webapp2.WSGIApplication(
[
(r'/', Home),
(r'/tostatic/(.+)', StaticView),
], debug=True)
The view for the static file serving is now:
class StaticView(webapp2.RequestHandler):
def get(self, path):
path = os.sep + path
try:
f = open(path, 'r')
self.response.headers.add_header('Content-Type', mimetypes.guess_type(path)[0])
self.response.out.write(f.read())
f.close()
except Exception, e:
print 'Problem in StaticView:', e
self.response.set_status(404)
To finally close, the problem that I had with your approach is the one that I and other near noobs have with the departure of URLs from the legacy association with the file system. In your approach "static" is both a sub-directory and a string between slashes at the front of the URL that tells the interpreter which view (which webapp2.RequestHandler subclass) to run. You take the /static from the rest of the URL and then later hard-code it back on. And when it comes time to decide what to put in for href in the tag the HTML page coder has to remember that duplicity. With the {{STATIC_DIR}} template variable approach it's clear what to do. And it's easy to redefine the location of the static files--- only the STATIC_DIR declaration has to be changed.
I found that self.response.set_status(404) shows up in Firebug, but not Firefox. Evidently with webapp2 you must provide and serve your own HTTP status code pages.
self.response.headers.add_header('Content-Type', mimetypes.guess_type(abs_path)[0])
self.response.headers['Content-Type'] = mimetypes.guess_type(abs_path)[0]