Flask update

This commit is contained in:
Ruud
2011-08-24 20:59:59 +02:00
parent 970b400a0c
commit d7f758dff4
90 changed files with 3328 additions and 1236 deletions
+1 -5
View File
@@ -27,11 +27,7 @@
:license: BSD, see LICENSE for more details.
"""
__docformat__ = 'restructuredtext en'
try:
__version__ = __import__('pkg_resources') \
.get_distribution('Jinja2').version
except Exception:
__version__ = 'unknown'
__version__ = '2.7-dev'
# high level interface
from jinja2.environment import Environment, Template
+26 -14
View File
@@ -20,7 +20,6 @@ import marshal
import tempfile
import cPickle as pickle
import fnmatch
from cStringIO import StringIO
try:
from hashlib import sha1
except ImportError:
@@ -28,6 +27,26 @@ except ImportError:
from jinja2.utils import open_if_exists
# marshal works better on 3.x, one hack less required
if sys.version_info > (3, 0):
from io import BytesIO
marshal_dump = marshal.dump
marshal_load = marshal.load
else:
from cStringIO import StringIO as BytesIO
def marshal_dump(code, f):
if isinstance(f, file):
marshal.dump(code, f)
else:
f.write(marshal.dumps(code))
def marshal_load(f):
if isinstance(f, file):
return marshal.load(f)
return marshal.loads(f.read())
bc_version = 2
# magic version used to only change with new jinja versions. With 2.6
@@ -71,12 +90,7 @@ class Bucket(object):
if self.checksum != checksum:
self.reset()
return
# now load the code. Because marshal is not able to load
# from arbitrary streams we have to work around that
if isinstance(f, file):
self.code = marshal.load(f)
else:
self.code = marshal.loads(f.read())
self.code = marshal_load(f)
def write_bytecode(self, f):
"""Dump the bytecode into the file or file like object passed."""
@@ -84,18 +98,15 @@ class Bucket(object):
raise TypeError('can\'t write empty bucket')
f.write(bc_magic)
pickle.dump(self.checksum, f, 2)
if isinstance(f, file):
marshal.dump(self.code, f)
else:
f.write(marshal.dumps(self.code))
marshal_dump(self.code, f)
def bytecode_from_string(self, string):
"""Load bytecode from a string."""
self.load_bytecode(StringIO(string))
self.load_bytecode(BytesIO(string))
def bytecode_to_string(self):
"""Return the bytecode as string."""
out = StringIO()
out = BytesIO()
self.write_bytecode(out)
return out.getvalue()
@@ -153,9 +164,10 @@ class BytecodeCache(object):
"""Returns the unique hash key for this template name."""
hash = sha1(name.encode('utf-8'))
if filename is not None:
filename = '|' + filename
if isinstance(filename, unicode):
filename = filename.encode('utf-8')
hash.update('|' + filename)
hash.update(filename)
return hash.hexdigest()
def get_source_checksum(self, source):
+6 -9
View File
@@ -127,12 +127,10 @@ class Identifiers(object):
self.undeclared.discard(name)
self.declared.add(name)
def is_declared(self, name, local_only=False):
def is_declared(self, name):
"""Check if a name is declared in this or an outer scope."""
if name in self.declared_locally or name in self.declared_parameter:
return True
if local_only:
return False
return name in self.declared
def copy(self):
@@ -193,12 +191,12 @@ class Frame(object):
rv.identifiers.__dict__.update(self.identifiers.__dict__)
return rv
def inspect(self, nodes, hard_scope=False):
def inspect(self, nodes):
"""Walk the node and check for identifiers. If the scope is hard (eg:
enforce on a python level) overrides from outer scopes are tracked
differently.
"""
visitor = FrameIdentifierVisitor(self.identifiers, hard_scope)
visitor = FrameIdentifierVisitor(self.identifiers)
for node in nodes:
visitor.visit(node)
@@ -275,9 +273,8 @@ class UndeclaredNameVisitor(NodeVisitor):
class FrameIdentifierVisitor(NodeVisitor):
"""A visitor for `Frame.inspect`."""
def __init__(self, identifiers, hard_scope):
def __init__(self, identifiers):
self.identifiers = identifiers
self.hard_scope = hard_scope
def visit_Name(self, node):
"""All assignments to names go through this function."""
@@ -286,7 +283,7 @@ class FrameIdentifierVisitor(NodeVisitor):
elif node.ctx == 'param':
self.identifiers.declared_parameter.add(node.name)
elif node.ctx == 'load' and not \
self.identifiers.is_declared(node.name, self.hard_scope):
self.identifiers.is_declared(node.name):
self.identifiers.undeclared.add(node.name)
def visit_If(self, node):
@@ -658,7 +655,7 @@ class CodeGenerator(NodeVisitor):
children = node.iter_child_nodes()
children = list(children)
func_frame = frame.inner()
func_frame.inspect(children, hard_scope=True)
func_frame.inspect(children)
# variables that are undeclared (accessed before declaration) and
# declared locally *and* part of an outside scope raise a template
+7 -1
View File
@@ -45,7 +45,13 @@ class TracebackFrameProxy(object):
def set_next(self, next):
if tb_set_next is not None:
tb_set_next(self.tb, next and next.tb or None)
try:
tb_set_next(self.tb, next and next.tb or None)
except Exception:
# this function can fail due to all the hackery it does
# on various python implementations. We just catch errors
# down and ignore them if necessary.
pass
self._tb_next = next
@property
+28 -16
View File
@@ -53,7 +53,7 @@ def make_attrgetter(environment, attribute):
passed object with the rules of the environment. Dots are allowed
to access attributes of attributes.
"""
if '.' not in attribute:
if not isinstance(attribute, basestring) or '.' not in attribute:
return lambda x: environment.getitem(x, attribute)
attribute = attribute.split('.')
def attrgetter(item):
@@ -338,21 +338,33 @@ def do_random(environment, seq):
def do_filesizeformat(value, binary=False):
"""Format the value like a 'human-readable' file size (i.e. 13 KB,
4.1 MB, 102 bytes, etc). Per default decimal prefixes are used (mega,
giga, etc.), if the second parameter is set to `True` the binary
prefixes are used (mebi, gibi).
"""Format the value like a 'human-readable' file size (i.e. 13 kB,
4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
Giga, etc.), if the second parameter is set to `True` the binary
prefixes are used (Mebi, Gibi).
"""
bytes = float(value)
base = binary and 1024 or 1000
middle = binary and 'i' or ''
if bytes < base:
return "%d Byte%s" % (bytes, bytes != 1 and 's' or '')
elif bytes < base * base:
return "%.1f K%sB" % (bytes / base, middle)
elif bytes < base * base * base:
return "%.1f M%sB" % (bytes / (base * base), middle)
return "%.1f G%sB" % (bytes / (base * base * base), middle)
prefixes = [
(binary and "KiB" or "kB"),
(binary and "MiB" or "MB"),
(binary and "GiB" or "GB"),
(binary and "TiB" or "TB"),
(binary and "PiB" or "PB"),
(binary and "EiB" or "EB"),
(binary and "ZiB" or "ZB"),
(binary and "YiB" or "YB")
]
if bytes == 1:
return "1 Byte"
elif bytes < base:
return "%d Bytes" % bytes
else:
for i, prefix in enumerate(prefixes):
unit = base * base ** (i + 1)
if bytes < unit:
return "%.1f %s" % ((bytes / unit), prefix)
return "%.1f %s" % ((bytes / unit), prefix)
def do_pprint(value, verbose=False):
@@ -431,8 +443,8 @@ def do_truncate(s, length=255, killwords=False, end='...'):
result.append(end)
return u' '.join(result)
def do_wordwrap(s, width=79, break_long_words=True):
@environmentfilter
def do_wordwrap(environment, s, width=79, break_long_words=True):
"""
Return a copy of the string passed to the filter wrapped after
``79`` characters. You can override this default using the first
@@ -440,7 +452,7 @@ def do_wordwrap(s, width=79, break_long_words=True):
split words apart if they are longer than `width`.
"""
import textwrap
return u'\n'.join(textwrap.wrap(s, width=width, expand_tabs=False,
return environment.newline_sequence.join(textwrap.wrap(s, width=width, expand_tabs=False,
replace_whitespace=False,
break_long_words=break_long_words))
+1 -2
View File
@@ -251,8 +251,7 @@ class PackageLoader(BaseLoader):
for filename in self.provider.resource_listdir(path):
fullname = path + '/' + filename
if self.provider.resource_isdir(fullname):
for item in _walk(fullname):
results.append(item)
_walk(fullname)
else:
results.append(fullname[offset:].lstrip('/'))
_walk(path)
-2
View File
@@ -75,8 +75,6 @@ class TemplateReference(object):
def __getitem__(self, name):
blocks = self.__context.blocks[name]
wrap = self.__context.eval_ctx.autoescape and \
Markup or (lambda x: x)
return BlockReference(name, self.__context, blocks, 0)
def __repr__(self):
+15
View File
@@ -11,6 +11,12 @@
import re
from jinja2.runtime import Undefined
try:
from collections import Mapping as MappingType
except ImportError:
import UserDict
MappingType = (UserDict.UserDict, UserDict.DictMixin, dict)
# nose, nothing here to test
__test__ = False
@@ -83,6 +89,14 @@ def test_string(value):
return isinstance(value, basestring)
def test_mapping(value):
"""Return true if the object is a mapping (dict etc.).
.. versionadded:: 2.6
"""
return isinstance(value, MappingType)
def test_number(value):
"""Return true if the variable is a number."""
return isinstance(value, (int, long, float, complex))
@@ -137,6 +151,7 @@ TESTS = {
'lower': test_lower,
'upper': test_upper,
'string': test_string,
'mapping': test_mapping,
'number': test_number,
'sequence': test_sequence,
'iterable': test_iterable,
+9 -2
View File
@@ -85,8 +85,8 @@ class FilterTestCase(JinjaTestCase):
)
out = tmpl.render()
assert out == (
'100 Bytes|1.0 KB|1.0 MB|1.0 GB|1000.0 GB|'
'100 Bytes|1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB'
'100 Bytes|0.0 kB|0.0 MB|0.0 GB|0.0 TB|100 Bytes|'
'1000 Bytes|1.0 KiB|0.9 MiB|0.9 GiB'
)
def test_first(self):
@@ -288,6 +288,13 @@ class FilterTestCase(JinjaTestCase):
""
]
def test_groupby_tuple_index(self):
tmpl = env.from_string('''
{%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
{{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
{%- endfor %}''')
assert tmpl.render() == 'a:1:2|b:1|'
def test_groupby_multidot(self):
class Date(object):
def __init__(self, day, month, year):
+8 -2
View File
@@ -48,10 +48,16 @@ class TestsTestCase(JinjaTestCase):
{{ range is callable }}
{{ 42 is callable }}
{{ range(5) is iterable }}
{{ {} is mapping }}
{{ mydict is mapping }}
{{ [] is mapping }}
''')
assert tmpl.render().split() == [
class MyDict(dict):
pass
assert tmpl.render(mydict=MyDict()).split() == [
'False', 'True', 'False', 'True', 'True', 'False',
'True', 'True', 'True', 'True', 'False', 'True'
'True', 'True', 'True', 'True', 'False', 'True',
'True', 'True', 'False'
]
def test_sequence(self):