1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
# -*- coding: utf-8 -*-
"""
plnt.utils
~~~~~~~~~~
The planet utilities.
:copyright: 2007 Pallets
:license: BSD-3-Clause
"""
import re
from os import path
from jinja2 import Environment
from jinja2 import FileSystemLoader
from werkzeug._compat import unichr
from werkzeug.local import Local
from werkzeug.local import LocalManager
from werkzeug.routing import Map
from werkzeug.routing import Rule
from werkzeug.utils import cached_property
from werkzeug.wrappers import Response
# context locals. these two objects are use by the application to
# bind objects to the current context. A context is defined as the
# current thread and the current greenlet if there is greenlet support.
# the `get_request` and `get_application` functions look up the request
# and application objects from this local manager.
local = Local()
local_manager = LocalManager([local])
# proxy objects
request = local("request")
application = local("application")
url_adapter = local("url_adapter")
# let's use jinja for templates this time
template_path = path.join(path.dirname(__file__), "templates")
jinja_env = Environment(loader=FileSystemLoader(template_path))
# the collected url patterns
url_map = Map([Rule("/shared/<path:file>", endpoint="shared")])
endpoints = {}
_par_re = re.compile(r"\n{2,}")
_entity_re = re.compile(r"&([^;]+);")
_striptags_re = re.compile(r"(<!--.*-->|<[^>]*>)")
try:
from html.entities import name2codepoint
except ImportError:
from htmlentitydefs import name2codepoint
html_entities = name2codepoint.copy()
html_entities["apos"] = 39
del name2codepoint
def expose(url_rule, endpoint=None, **kwargs):
"""Expose this function to the web layer."""
def decorate(f):
e = endpoint or f.__name__
endpoints[e] = f
url_map.add(Rule(url_rule, endpoint=e, **kwargs))
return f
return decorate
def render_template(template_name, **context):
"""Render a template into a response."""
tmpl = jinja_env.get_template(template_name)
context["url_for"] = url_for
return Response(tmpl.render(context), mimetype="text/html")
def nl2p(s):
"""Add paragraphs to a text."""
return u"\n".join(u"<p>%s</p>" % p for p in _par_re.split(s))
def url_for(endpoint, **kw):
"""Simple function for URL generation."""
return url_adapter.build(endpoint, kw)
def strip_tags(s):
"""Resolve HTML entities and remove tags from a string."""
def handle_match(m):
name = m.group(1)
if name in html_entities:
return unichr(html_entities[name])
if name[:2] in ("#x", "#X"):
try:
return unichr(int(name[2:], 16))
except ValueError:
return u""
elif name.startswith("#"):
try:
return unichr(int(name[1:]))
except ValueError:
return u""
return u""
return _entity_re.sub(handle_match, _striptags_re.sub("", s))
class Pagination(object):
"""
Paginate a SQLAlchemy query object.
"""
def __init__(self, query, per_page, page, endpoint):
self.query = query
self.per_page = per_page
self.page = page
self.endpoint = endpoint
@cached_property
def entries(self):
return (
self.query.offset((self.page - 1) * self.per_page)
.limit(self.per_page)
.all()
)
@cached_property
def count(self):
return self.query.count()
@property
def has_previous(self):
"""Return True if there are pages before the current one."""
return self.page > 1
@property
def has_next(self):
"""Return True if there are pages after the current one."""
return self.page < self.pages
@property
def previous(self):
"""Return the URL for the previous page."""
return url_for(self.endpoint, page=self.page - 1)
@property
def next(self):
"""Return the URL for the next page."""
return url_for(self.endpoint, page=self.page + 1)
@property
def pages(self):
"""Return the number of pages."""
return max(0, self.count - 1) // self.per_page + 1
|