Binding Flask AutoIndex to a different URL other than http://localhost? - python

I am new to Flask and want to use the following basic example (using Flask-AutoIndex) in order to list files and folders in a directory:
import os.path
from flask import Flask
from flask.ext.autoindex import AutoIndex
app = Flask(__name__)
AutoIndex(app, browse_root=os.path.curdir)
if __name__ == '__main__':
app.run()
The example works fine for me,
http://localhost/folder1/folder2
is listing the files and folders in folder2.
The problem I have is that these urls are already bound to some other functions for other purposes, and this makes AutoIndex not working properly (URL conflicts)
Is it possible to bind AutoIndex to a different URL that has an extra word "list" in it? something like:
http://localhost/list/folder1/folder2/
http://localhost/list/folder1/folder2/folder3/

This works for me:
files_index = AutoIndex(app, os.path.curdir + '/app/files', add_url_rules=False)
# Custom indexing
#app.route('/files')
#app.route('/files/<path:path>')
def autoindex(path='.'):
return files_index.render_autoindex(path)
From https://github.com/sublee/flask-autoindex/issues/16

I can't test it, but AutoIndex includes an AutoIndexBlueprint, so I wonder if you could use that to tuck it away:
# bp.py
from flask import Blueprint
from flask.ext.autoindex import AutoIndexBlueprint
auto_bp = Blueprint('auto_bp', __name__)
AutoIndexBlueprint(auto_bp, browse_root='/tmp')
Then register it on your app:
from bp import auto_bp
app.register_blueprint(auto_bp, url_prefix='/list')

Related

How to remove older css files after webassets rebuilds the scss for a python flask app?

I have a Python 3.9 flask app which uses the flask_assets library.
My flask init.py file looks like:
import logging
import os
from flask import Flask, request, current_app
from config import Config
from flask_assets import Environment
from app.utils.assets import bundles
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
assets = Environment(app)
assets.debug = True
assets.versions = 'timestamp'
# assets.cache = False
from app.main import bp as main_bp
app.register_blueprint(main_bp)
assets.register(bundles)
if not app.debug and not app.testing:
app.logger.setLevel(logging.INFO)
app.logger.info('Application starting.')
return app
Since flask_assets is built on top of webassets, I import the Environment and a css Bundle I created which compiles my scss code to css.
Here is how my Bundle looks like:
from flask_assets import Bundle
bundles = {
'css': Bundle (
'scss/_main.scss',
'scss/_base.scss',
'scss/_typography.scss',
'scss/_page_home.scss',
'scss/_page_technote.scss',
filters='pyscss',
depends=('**/*.scss'),
output='css/style.%(version)s.scss.css'
)
}
The problem I have:
Every time I make a change to my scss files, the css successfully rebuilds with a new version for cache busting. However, the older css files remain.
What's the best automatic way to remove them every time a rebuild happens? Is there any reason for keeping the older files?
Also - side question - is it possible for the Bundle object to automatically consider all files of certain type in a directory? Rather than me listing every file individually?
Here is how my files look like:
Thank you!
You can use rmtree. Even though I believe a better way exists, this does it.
from os.path import join
from shutil import rmtree
app = Flask(__name__)
rmtree(join(app.static_folder, 'css'), ignore_errors=True)
You can improve this by checking the file meta by date or similar to not delete the unchanged ones.

Is there anyway to specify templates and static folders(other than default) for Connexion app?

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

Change static folder from config in Flask

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.

Retrieving config from a blueprint in Sanic app

I have a Sanic application, and want to retrieve app.config from a blueprint as it holds MONGO_URL, and I will pass it to a repository class from the blueprint.
However, I could not find how to get app.config in a blueprint. I have also checked Flask solutions, but they are not applicable to Sanic.
My app.py:
from sanic import Sanic
from routes.authentication import auth_route
from routes.user import user_route
app = Sanic(__name__)
app.blueprint(auth_route, url_prefix="/auth")
app.blueprint(user_route, url_prefix="/user")
app.config.from_envvar('TWEETBOX_CONFIG')
app.run(host='127.0.0.1', port=8000, debug=True)
My auth blueprint:
import jwt
from sanic import Blueprint
from sanic.response import json, redirect
from domain.user import User
from repository.user_repository import UserRepository
...
auth_route = Blueprint('authentication')
mongo_url = ?????
user_repository = UserRepository(mongo_url)
...
#auth_route.route('/signin')
async def redirect_user(request):
...
The Sanic way...
Inside a view method, you can access the app instance from the request object. And, therefore access your configuration.
#auth_route.route('/signin')
async def redirect_user(request):
configuration = request.app.config
2021-10-10 Update
There are two newer ways to get to the configuration values (or, perhaps more accuratlely getting the application instance from which you can get the configuration). The first version might be more on point to answering the question of how to get to the config from the blueprint. However, the second option is probably the preferred method since it is precisely intended for this kind of use.
Alternative #1
Blueprints have access to the Sanic applications they are attached to beginning with v21.3.
Therefore, if you have a blueprint object, you can trace that back to the application instance, and therefore also the config value.
app = Sanic("MyApp")
bp = Blueprint("MyBlueprint")
app.blueprint(bp)
assert bp.apps[0] is app
The Blueprint.apps property is a set because it is possible to attach a single blueprint to multiple applications.
Alternative #2
Sanic has a built-in method for retrieving an application instance from the global scope beginning in v20.12. This means that once an application has been instantiated, you can retrieve it using: Sanic.get_app().
app = Sanic("MyApp")
assert Sanic.get_app() is app
This method will only work if there is a single Sanic instance available. If you have multiple application instances, you will need to use the optional name argument:
app1 = Sanic("MyApp")
app2 = Sanic("MyOtherApp")
assert Sanic.get_app("MyApp") is app1
I would suggest a slightly different approach, based on the 12 Factor App (very interesting read which, among others, provides a nice guideline on how to protect and isolate your sensitive info).
The general idea is to place your sensitive and configuration variables in a file that is going to be gitignored and therefore will only be available locally.
I will try to present the method I tend to use in order to be as close as possible to the 12 Factor guidelines:
Create a .env file with your project variables in it:
MONGO_URL=http://no_peeking_this_is_secret:port/
SENSITIVE_PASSWORD=for_your_eyes_only
CONFIG_OPTION_1=config_this
DEBUG=True
...
(Important) Add .env and .env.* on your .gitignore file, thus protecting your sensitive info from been uploaded to GitHub.
Create an env.example (be careful not to name it with a . in the beginning, because it will get ignored).
In that file, you can put an example of the expected configuration in order to be reproducible by simply copy, paste, rename to .env.
In a file named settings.py, use decouple.config to read your config file into variables:
from decouple import config
MONGO_URL = config('MONGO_URL')
CONFIG_OPTION_1 = config('CONFIG_OPTION_1', default='')
DEBUG = config('DEBUG', cast=bool, default=True)
...
Now you can use these variables wherever is necessary for your implementation:
myblueprint.py:
import settings
...
auth_route = Blueprint('authentication')
mongo_url = settings.MONGO_URL
user_repository = UserRepository(mongo_url)
...
As a finisher, I would like to point out that this method is framework (and even language) agnostic so you can use it on Sanic as well as Flask and everywhere you need it!
I think you can create a config.py to save your configuration, just like
config.py
config = {
'MONGO_URL':'127.0.0.1:27017'
}
and use it in app.py
from config import config
mongo_url = config['MONGO_URL']
There is a variable named current_app in Flask. You can use current_app.config["MONGO_URL"].
But I am not familiar with Sanic.

Flask: How to serve static html?

I am trying to serve a static html file, but returns a 500 error
(a copy of editor.html is on .py and templates directory)
This is all I have tried:
from flask import Flask
app = Flask(__name__, static_url_path='/templates')
#app.route('/')
def hello_world():
#return 'Hello World1!' #this works correctly!
#return render_template('editor.html')
#return render_template('/editor.html')
#return render_template(url_for('templates', filename='editor.html'))
#return app.send_static_file('editor.html') #404 error (Not Found)
return send_from_directory('templates', 'editor.html')
This is the response:
Title: 500 Internal Server Srror
Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
Reducing this to the simplest method that'll work:
Put static assets into your static subfolder.
Leave Flask set to the default, don't give it a static_url_path either.
Access static content over the pre-configured /static/ to verify the file works
If you then still want to reuse a static file, use current_app.send_static_file(), and do not use leading / slashes:
from flask import Flask, current_app
app = Flask(__name__)
#app.route('/')
def hello_world():
return current_app.send_static_file('editor.html')
This looks for the file editor.html directly inside the static folder.
This presumes that you saved the above file in a folder that has a static subfolder with a file editor.html inside that subfolder.
Some further notes:
static_url_path changes the URL static files are available at, not the location on the filesystem used to load the data from.
render_template() assumes your file is a Jinja2 template; if it is really just a static file then that is overkill and can lead to errors if there is actual executable syntax in that file that has errors or is missing context.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
#return send_file('relAdmin/login.html')
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
send_from_directory and send_file need to be imported from flask.
Your code sample would work if you do the following:
from flask import Flask, send_from_directory
app = Flask(__name__, static_url_path='/templates')
#app.route('/')
def hello_world():
return send_from_directory('templates', 'editor.html')
However, remember if this file loads other files e.g. javascript, css, etc. you would have to define routes for them too.
Also, as far as I understand, this is not the recommended method on production because it's slow.

Categories