in with the new. i have the bits in places where i think they should be, now i just need to work on the import scheme layout
This commit is contained in:
parent
ee16a68bbd
commit
d0dc89ea80
8 changed files with 1574 additions and 0 deletions
310
flask/helpers.py
Normal file
310
flask/helpers.py
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
# try to load the best simplejson implementation available. If JSON
|
||||
# is not installed, we add a failing class.
|
||||
json_available = True
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
json_available = False
|
||||
|
||||
def _assert_have_json():
|
||||
"""Helper function that fails if JSON is unavailable."""
|
||||
if not json_available:
|
||||
raise RuntimeError('simplejson not installed')
|
||||
|
||||
# figure out if simplejson escapes slashes. This behaviour was changed
|
||||
# from one version to another without reason.
|
||||
if not json_available or '\\/' not in json.dumps('/'):
|
||||
|
||||
def _tojson_filter(*args, **kwargs):
|
||||
if __debug__:
|
||||
_assert_have_json()
|
||||
return json.dumps(*args, **kwargs).replace('/', '\\/')
|
||||
else:
|
||||
_tojson_filter = json.dumps
|
||||
|
||||
def jsonify(*args, **kwargs):
|
||||
"""Creates a :class:`~flask.Response` with the JSON representation of
|
||||
the given arguments with an `application/json` mimetype. The arguments
|
||||
to this function are the same as to the :class:`dict` constructor.
|
||||
|
||||
Example usage::
|
||||
|
||||
@app.route('/_get_current_user')
|
||||
def get_current_user():
|
||||
return jsonify(username=g.user.username,
|
||||
email=g.user.email,
|
||||
id=g.user.id)
|
||||
|
||||
This will send a JSON response like this to the browser::
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"email": "admin@localhost",
|
||||
"id": 42
|
||||
}
|
||||
|
||||
This requires Python 2.6 or an installed version of simplejson. For
|
||||
security reasons only objects are supported toplevel. For more
|
||||
information about this, have a look at :ref:`json-security`.
|
||||
|
||||
.. versionadded:: 0.2
|
||||
"""
|
||||
if __debug__:
|
||||
_assert_have_json()
|
||||
return current_app.response_class(json.dumps(dict(*args, **kwargs),
|
||||
indent=None if request.is_xhr else 2), mimetype='application/json')
|
||||
|
||||
|
||||
|
||||
def url_for(endpoint, **values):
|
||||
"""Generates a URL to the given endpoint with the method provided.
|
||||
The endpoint is relative to the active module if modules are in use.
|
||||
|
||||
Here some examples:
|
||||
|
||||
==================== ======================= =============================
|
||||
Active Module Target Endpoint Target Function
|
||||
==================== ======================= =============================
|
||||
`None` ``'index'`` `index` of the application
|
||||
`None` ``'.index'`` `index` of the application
|
||||
``'admin'`` ``'index'`` `index` of the `admin` module
|
||||
any ``'.index'`` `index` of the application
|
||||
any ``'admin.index'`` `index` of the `admin` module
|
||||
==================== ======================= =============================
|
||||
|
||||
Variable arguments that are unknown to the target endpoint are appended
|
||||
to the generated URL as query arguments.
|
||||
|
||||
For more information, head over to the :ref:`Quickstart <url-building>`.
|
||||
|
||||
:param endpoint: the endpoint of the URL (name of the function)
|
||||
:param values: the variable arguments of the URL rule
|
||||
:param _external: if set to `True`, an absolute URL is generated.
|
||||
"""
|
||||
ctx = _request_ctx_stack.top
|
||||
if '.' not in endpoint:
|
||||
mod = ctx.request.module
|
||||
if mod is not None:
|
||||
endpoint = mod + '.' + endpoint
|
||||
elif endpoint.startswith('.'):
|
||||
endpoint = endpoint[1:]
|
||||
external = values.pop('_external', False)
|
||||
return ctx.url_adapter.build(endpoint, values, force_external=external)
|
||||
|
||||
|
||||
def get_template_attribute(template_name, attribute):
|
||||
"""Loads a macro (or variable) a template exports. This can be used to
|
||||
invoke a macro from within Python code. If you for example have a
|
||||
template named `_cider.html` with the following contents:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
{% macro hello(name) %}Hello {{ name }}!{% endmacro %}
|
||||
|
||||
You can access this from Python code like this::
|
||||
|
||||
hello = get_template_attribute('_cider.html', 'hello')
|
||||
return hello('World')
|
||||
|
||||
.. versionadded:: 0.2
|
||||
|
||||
:param template_name: the name of the template
|
||||
:param attribute: the name of the variable of macro to acccess
|
||||
"""
|
||||
return getattr(current_app.jinja_env.get_template(template_name).module,
|
||||
attribute)
|
||||
|
||||
|
||||
def flash(message, category='message'):
|
||||
"""Flashes a message to the next request. In order to remove the
|
||||
flashed message from the session and to display it to the user,
|
||||
the template has to call :func:`get_flashed_messages`.
|
||||
|
||||
.. versionchanged: 0.3
|
||||
`category` parameter added.
|
||||
|
||||
:param message: the message to be flashed.
|
||||
:param category: the category for the message. The following values
|
||||
are recommended: ``'message'`` for any kind of message,
|
||||
``'error'`` for errors, ``'info'`` for information
|
||||
messages and ``'warning'`` for warnings. However any
|
||||
kind of string can be used as category.
|
||||
"""
|
||||
session.setdefault('_flashes', []).append((category, message))
|
||||
|
||||
|
||||
def get_flashed_messages(with_categories=False):
|
||||
"""Pulls all flashed messages from the session and returns them.
|
||||
Further calls in the same request to the function will return
|
||||
the same messages. By default just the messages are returned,
|
||||
but when `with_categories` is set to `True`, the return value will
|
||||
be a list of tuples in the form ``(category, message)`` instead.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. sourcecode:: html+jinja
|
||||
|
||||
{% for category, msg in get_flashed_messages(with_categories=true) %}
|
||||
<p class=flash-{{ category }}>{{ msg }}
|
||||
{% endfor %}
|
||||
|
||||
.. versionchanged:: 0.3
|
||||
`with_categories` parameter added.
|
||||
|
||||
:param with_categories: set to `True` to also receive categories.
|
||||
"""
|
||||
flashes = _request_ctx_stack.top.flashes
|
||||
if flashes is None:
|
||||
_request_ctx_stack.top.flashes = flashes = session.pop('_flashes', [])
|
||||
if not with_categories:
|
||||
return [x[1] for x in flashes]
|
||||
return flashes
|
||||
|
||||
|
||||
|
||||
def send_file(filename_or_fp, mimetype=None, as_attachment=False,
|
||||
attachment_filename=None):
|
||||
"""Sends the contents of a file to the client. This will use the
|
||||
most efficient method available and configured. By default it will
|
||||
try to use the WSGI server's file_wrapper support. Alternatively
|
||||
you can set the application's :attr:`~Flask.use_x_sendfile` attribute
|
||||
to ``True`` to directly emit an `X-Sendfile` header. This however
|
||||
requires support of the underlying webserver for `X-Sendfile`.
|
||||
|
||||
By default it will try to guess the mimetype for you, but you can
|
||||
also explicitly provide one. For extra security you probably want
|
||||
to sent certain files as attachment (HTML for instance).
|
||||
|
||||
Please never pass filenames to this function from user sources without
|
||||
checking them first. Something like this is usually sufficient to
|
||||
avoid security problems::
|
||||
|
||||
if '..' in filename or filename.startswith('/'):
|
||||
abort(404)
|
||||
|
||||
.. versionadded:: 0.2
|
||||
|
||||
:param filename_or_fp: the filename of the file to send. This is
|
||||
relative to the :attr:`~Flask.root_path` if a
|
||||
relative path is specified.
|
||||
Alternatively a file object might be provided
|
||||
in which case `X-Sendfile` might not work and
|
||||
fall back to the traditional method.
|
||||
:param mimetype: the mimetype of the file if provided, otherwise
|
||||
auto detection happens.
|
||||
:param as_attachment: set to `True` if you want to send this file with
|
||||
a ``Content-Disposition: attachment`` header.
|
||||
:param attachment_filename: the filename for the attachment if it
|
||||
differs from the file's filename.
|
||||
"""
|
||||
if isinstance(filename_or_fp, basestring):
|
||||
filename = filename_or_fp
|
||||
file = None
|
||||
else:
|
||||
file = filename_or_fp
|
||||
filename = getattr(file, 'name', None)
|
||||
if filename is not None:
|
||||
filename = os.path.join(current_app.root_path, filename)
|
||||
if mimetype is None and (filename or attachment_filename):
|
||||
mimetype = mimetypes.guess_type(filename or attachment_filename)[0]
|
||||
if mimetype is None:
|
||||
mimetype = 'application/octet-stream'
|
||||
|
||||
headers = Headers()
|
||||
if as_attachment:
|
||||
if attachment_filename is None:
|
||||
if filename is None:
|
||||
raise TypeError('filename unavailable, required for '
|
||||
'sending as attachment')
|
||||
attachment_filename = os.path.basename(filename)
|
||||
headers.add('Content-Disposition', 'attachment',
|
||||
filename=attachment_filename)
|
||||
|
||||
if current_app.use_x_sendfile and filename:
|
||||
if file is not None:
|
||||
file.close()
|
||||
headers['X-Sendfile'] = filename
|
||||
data = None
|
||||
else:
|
||||
if file is None:
|
||||
file = open(filename, 'rb')
|
||||
data = wrap_file(request.environ, file)
|
||||
|
||||
return Response(data, mimetype=mimetype, headers=headers,
|
||||
direct_passthrough=True)
|
||||
|
||||
|
||||
def render_template(template_name, **context):
|
||||
"""Renders a template from the template folder with the given
|
||||
context.
|
||||
|
||||
:param template_name: the name of the template to be rendered
|
||||
:param context: the variables that should be available in the
|
||||
context of the template.
|
||||
"""
|
||||
current_app.update_template_context(context)
|
||||
return current_app.jinja_env.get_template(template_name).render(context)
|
||||
|
||||
|
||||
def render_template_string(source, **context):
|
||||
"""Renders a template from the given template source string
|
||||
with the given context.
|
||||
|
||||
:param template_name: the sourcecode of the template to be
|
||||
rendered
|
||||
:param context: the variables that should be available in the
|
||||
context of the template.
|
||||
"""
|
||||
current_app.update_template_context(context)
|
||||
return current_app.jinja_env.from_string(source).render(context)
|
||||
|
||||
|
||||
|
||||
def _get_package_path(name):
|
||||
"""Returns the path to a package or cwd if that cannot be found."""
|
||||
try:
|
||||
return os.path.abspath(os.path.dirname(sys.modules[name].__file__))
|
||||
except (KeyError, AttributeError):
|
||||
return os.getcwd()
|
||||
|
||||
|
||||
|
||||
class _PackageBoundObject(object):
|
||||
|
||||
def __init__(self, import_name):
|
||||
#: The name of the package or module. Do not change this once
|
||||
#: it was set by the constructor.
|
||||
self.import_name = import_name
|
||||
|
||||
#: Where is the app root located?
|
||||
self.root_path = _get_package_path(self.import_name)
|
||||
|
||||
def open_resource(self, resource):
|
||||
"""Opens a resource from the application's resource folder. To see
|
||||
how this works, consider the following folder structure::
|
||||
|
||||
/myapplication.py
|
||||
/schemal.sql
|
||||
/static
|
||||
/style.css
|
||||
/templates
|
||||
/layout.html
|
||||
/index.html
|
||||
|
||||
If you want to open the `schema.sql` file you would do the
|
||||
following::
|
||||
|
||||
with app.open_resource('schema.sql') as f:
|
||||
contents = f.read()
|
||||
do_something_with(contents)
|
||||
|
||||
:param resource: the name of the resource. To access resources within
|
||||
subfolders use forward slashes as separator.
|
||||
"""
|
||||
if pkg_resources is None:
|
||||
return open(os.path.join(self.root_path, resource), 'rb')
|
||||
return pkg_resources.resource_stream(self.import_name, resource)
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue