summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2017-12-21 09:47:05 +0100
committerGuido Günther <agx@sigxcpu.org>2017-12-21 10:07:23 +0100
commitbec30b02537672617c36a23190e7a4813eb49d4f (patch)
tree97f65a281bf0a5fd60dd3a09022b1b3fceb54fac
Initial commit
-rw-r--r--.travis.yml12
-rw-r--r--README.rst33
-rw-r--r--dev_requirements.txt1
-rw-r--r--flask_xstatic.py91
-rw-r--r--setup.cfg3
-rwxr-xr-xsetup.py42
6 files changed, 182 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b1b767c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+---
+sudo: false
+language: python
+
+python:
+ - "2.7"
+ - "3.5"
+ - "3.6"
+
+install: "pip install -r dev_requirements.txt"
+script:
+ - flake8
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..a003141
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,33 @@
+Flask-XStatic
+=============
+
+A flask extionsion to serve xstatic files. Can be useful if you don't use an
+asset pipeline and server e.g. xstatic packaged javascript files directly.
+
+Setup
+-----
+Upon initialization tell flask about the xstatic modules you want to
+use::
+
+ app = Flask(__name__)
+ app.config.from_object(__name__)
+ app.config.update(dict(
+ XSTATIC_MODULES="bootstrap_scss,jquery",
+ ))
+ xstaticfiles = XStaticFiles(app)
+
+Serving files
+-------------
+Install a minimal route handler::
+
+ @app.route('/xstatic/<module>/<path:filename>')
+ def xstatic(module, filename):
+ return xstaticfiles.serve_or_404(module, filename)
+
+In your templates you can then use xstatic_url_for::
+
+ <script type=text/javascript src="{{ xstatic_url_for(module='jquery', path='jquery.min.js') }}"></script>
+
+This has the advantage that you can later serve files from a static
+web server by adjusting 'XSTATIC_ROOT' and 'XSTATIC_PROTO' without
+having to modify any code.
diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..56a1631
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1 @@
+flake8==3.5.0
diff --git a/flask_xstatic.py b/flask_xstatic.py
new file mode 100644
index 0000000..df90f64
--- /dev/null
+++ b/flask_xstatic.py
@@ -0,0 +1,91 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2017 Guido Guenther <agx@sigxcpu.org>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+Tiny flask extionsion to serve xstatic files
+"""
+
+import os
+from flask import current_app, abort
+from flask.helpers import send_file
+import xstatic.main
+
+# Find the stack on which we want to store the sqlalchemy session.
+# Starting with Flask 0.9, the _app_ctx_stack is the correct one,
+# before that we need to use the _request_ctx_stack.
+try:
+ from flask import _app_ctx_stack as stack
+except ImportError:
+ from flask import _request_ctx_stack as stack
+
+
+class XStaticFiles(object):
+
+ def __init__(self, app=None):
+ self.app = app
+ if app is not None:
+ self.init_app(app)
+
+ def init_app(self, app):
+ app.config.setdefault('XSTATIC_MODULES', None)
+ app.config.setdefault('XSTATIC_ROOT', '/xstatic')
+ app.config.setdefault('XSTATIC_PROTO', 'http')
+ # Use the newstyle teardown_appcontext if it's available,
+ # otherwise fall back to the request context
+ if hasattr(app, 'teardown_appcontext'):
+ app.teardown_appcontext(self.teardown)
+ else:
+ app.teardown_request(self.teardown)
+
+ self.app.jinja_env.globals['xstatic_url_for'] = self.url_for
+
+ def _load(self):
+ modules = current_app.config['XSTATIC_MODULES']
+ if not modules:
+ return {}
+ modules = modules.split(',')
+ pkg = __import__('xstatic.pkg', fromlist=modules)
+ url = current_app.config['XSTATIC_ROOT']
+ proto = current_app.config['XSTATIC_PROTO']
+ xss = {}
+ for name in modules:
+ mod = getattr(pkg, name)
+ xs = xstatic.main.XStatic(mod, root_url=url, protocol=proto)
+ xss[xs.name] = xs
+ return xss
+
+ def teardown(self, exception):
+ pass
+
+ @property
+ def xss(self):
+ ctx = stack.top
+ if ctx is not None:
+ if not hasattr(ctx, 'xss'):
+ ctx.xss = self._load()
+ return ctx.xss
+
+ def url_for(self, module, path):
+ return self.xss[module].url_for(path)
+
+ def serve(self, module, path):
+ return send_file(os.path.join(self.xss[module].base_dir, path))
+
+ def serve_or_404(self, module, path):
+ try:
+ return self.serve(module, path)
+ except FileNotFoundError:
+ abort(404)
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..5d08e9c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+# E501: ignore line length
+ignore=E501
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..d6f699e
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python3
+# vim: set fileencoding=utf-8 :
+"""
+Flask-XStatic
+-------------
+
+Make using xstatic files simple
+"""
+from setuptools import setup
+
+
+def readme():
+ with open('README.rst') as file:
+ return file.read()
+
+
+setup(
+ name='Flask-XStatic',
+ version='0.0.1',
+ url='http://github.com/agx/flask-xstatic',
+ license='LGPLv3+',
+ author='Guio Günther',
+ author_email='agx@sigxcpu.org',
+ description='Easily use XStatic files in flask',
+ long_description=readme(),
+ py_modules=['flask_xstatic'],
+ zip_safe=False,
+ include_package_data=True,
+ platforms='any',
+ install_requires=[
+ 'Flask'
+ ],
+ classifiers=[
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+ 'Topic :: Software Development :: Libraries :: Python Modules'
+ ]
+)