merge kaps
[libfirm] / scripts / jinja2 / utils.py
1 # -*- coding: utf-8 -*-
2 """
3     jinja2.utils
4     ~~~~~~~~~~~~
5
6     Utility functions.
7
8     :copyright: (c) 2010 by the Jinja Team.
9     :license: BSD, see LICENSE for more details.
10 """
11 import re
12 import sys
13 import errno
14 try:
15     from thread import allocate_lock
16 except ImportError:
17     from dummy_thread import allocate_lock
18 from collections import deque
19 from itertools import imap
20
21
22 _word_split_re = re.compile(r'(\s+)')
23 _punctuation_re = re.compile(
24     '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
25         '|'.join(imap(re.escape, ('(', '<', '&lt;'))),
26         '|'.join(imap(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
27     )
28 )
29 _simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
30 _striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
31 _entity_re = re.compile(r'&([^;]+);')
32 _letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
33 _digits = '0123456789'
34
35 # special singleton representing missing values for the runtime
36 missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
37
38 # internal code
39 internal_code = set()
40
41
42 # concatenate a list of strings and convert them to unicode.
43 # unfortunately there is a bug in python 2.4 and lower that causes
44 # unicode.join trash the traceback.
45 _concat = u''.join
46 try:
47     def _test_gen_bug():
48         raise TypeError(_test_gen_bug)
49         yield None
50     _concat(_test_gen_bug())
51 except TypeError, _error:
52     if not _error.args or _error.args[0] is not _test_gen_bug:
53         def concat(gen):
54             try:
55                 return _concat(list(gen))
56             except:
57                 # this hack is needed so that the current frame
58                 # does not show up in the traceback.
59                 exc_type, exc_value, tb = sys.exc_info()
60                 raise exc_type, exc_value, tb.tb_next
61     else:
62         concat = _concat
63     del _test_gen_bug, _error
64
65
66 # for python 2.x we create outselves a next() function that does the
67 # basics without exception catching.
68 try:
69     next = next
70 except NameError:
71     def next(x):
72         return x.next()
73
74
75 # if this python version is unable to deal with unicode filenames
76 # when passed to encode we let this function encode it properly.
77 # This is used in a couple of places.  As far as Jinja is concerned
78 # filenames are unicode *or* bytestrings in 2.x and unicode only in
79 # 3.x because compile cannot handle bytes
80 if sys.version_info < (3, 0):
81     def _encode_filename(filename):
82         if isinstance(filename, unicode):
83             return filename.encode('utf-8')
84         return filename
85 else:
86     def _encode_filename(filename):
87         assert filename is None or isinstance(filename, str), \
88             'filenames must be strings'
89         return filename
90
91 from keyword import iskeyword as is_python_keyword
92
93
94 # common types.  These do exist in the special types module too which however
95 # does not exist in IronPython out of the box.  Also that way we don't have
96 # to deal with implementation specific stuff here
97 class _C(object):
98     def method(self): pass
99 def _func():
100     yield None
101 FunctionType = type(_func)
102 GeneratorType = type(_func())
103 MethodType = type(_C.method)
104 CodeType = type(_C.method.func_code)
105 try:
106     raise TypeError()
107 except TypeError:
108     _tb = sys.exc_info()[2]
109     TracebackType = type(_tb)
110     FrameType = type(_tb.tb_frame)
111 del _C, _tb, _func
112
113
114 def contextfunction(f):
115     """This decorator can be used to mark a function or method context callable.
116     A context callable is passed the active :class:`Context` as first argument when
117     called from the template.  This is useful if a function wants to get access
118     to the context or functions provided on the context object.  For example
119     a function that returns a sorted list of template variables the current
120     template exports could look like this::
121
122         @contextfunction
123         def get_exported_names(context):
124             return sorted(context.exported_vars)
125     """
126     f.contextfunction = True
127     return f
128
129
130 def environmentfunction(f):
131     """This decorator can be used to mark a function or method as environment
132     callable.  This decorator works exactly like the :func:`contextfunction`
133     decorator just that the first argument is the active :class:`Environment`
134     and not context.
135     """
136     f.environmentfunction = True
137     return f
138
139
140 def internalcode(f):
141     """Marks the function as internally used"""
142     internal_code.add(f.func_code)
143     return f
144
145
146 def is_undefined(obj):
147     """Check if the object passed is undefined.  This does nothing more than
148     performing an instance check against :class:`Undefined` but looks nicer.
149     This can be used for custom filters or tests that want to react to
150     undefined variables.  For example a custom default filter can look like
151     this::
152
153         def default(var, default=''):
154             if is_undefined(var):
155                 return default
156             return var
157     """
158     from jinja2.runtime import Undefined
159     return isinstance(obj, Undefined)
160
161
162 def consume(iterable):
163     """Consumes an iterable without doing anything with it."""
164     for event in iterable:
165         pass
166
167
168 def clear_caches():
169     """Jinja2 keeps internal caches for environments and lexers.  These are
170     used so that Jinja2 doesn't have to recreate environments and lexers all
171     the time.  Normally you don't have to care about that but if you are
172     messuring memory consumption you may want to clean the caches.
173     """
174     from jinja2.environment import _spontaneous_environments
175     from jinja2.lexer import _lexer_cache
176     _spontaneous_environments.clear()
177     _lexer_cache.clear()
178
179
180 def import_string(import_name, silent=False):
181     """Imports an object based on a string.  This use useful if you want to
182     use import paths as endpoints or something similar.  An import path can
183     be specified either in dotted notation (``xml.sax.saxutils.escape``)
184     or with a colon as object delimiter (``xml.sax.saxutils:escape``).
185
186     If the `silent` is True the return value will be `None` if the import
187     fails.
188
189     :return: imported object
190     """
191     try:
192         if ':' in import_name:
193             module, obj = import_name.split(':', 1)
194         elif '.' in import_name:
195             items = import_name.split('.')
196             module = '.'.join(items[:-1])
197             obj = items[-1]
198         else:
199             return __import__(import_name)
200         return getattr(__import__(module, None, None, [obj]), obj)
201     except (ImportError, AttributeError):
202         if not silent:
203             raise
204
205
206 def open_if_exists(filename, mode='rb'):
207     """Returns a file descriptor for the filename if that file exists,
208     otherwise `None`.
209     """
210     try:
211         return open(filename, mode)
212     except IOError, e:
213         if e.errno not in (errno.ENOENT, errno.EISDIR):
214             raise
215
216
217 def pformat(obj, verbose=False):
218     """Prettyprint an object.  Either use the `pretty` library or the
219     builtin `pprint`.
220     """
221     try:
222         from pretty import pretty
223         return pretty(obj, verbose=verbose)
224     except ImportError:
225         from pprint import pformat
226         return pformat(obj)
227
228
229 def urlize(text, trim_url_limit=None, nofollow=False):
230     """Converts any URLs in text into clickable links. Works on http://,
231     https:// and www. links. Links can have trailing punctuation (periods,
232     commas, close-parens) and leading punctuation (opening parens) and
233     it'll still do the right thing.
234
235     If trim_url_limit is not None, the URLs in link text will be limited
236     to trim_url_limit characters.
237
238     If nofollow is True, the URLs in link text will get a rel="nofollow"
239     attribute.
240     """
241     trim_url = lambda x, limit=trim_url_limit: limit is not None \
242                          and (x[:limit] + (len(x) >=limit and '...'
243                          or '')) or x
244     words = _word_split_re.split(unicode(escape(text)))
245     nofollow_attr = nofollow and ' rel="nofollow"' or ''
246     for i, word in enumerate(words):
247         match = _punctuation_re.match(word)
248         if match:
249             lead, middle, trail = match.groups()
250             if middle.startswith('www.') or (
251                 '@' not in middle and
252                 not middle.startswith('http://') and
253                 len(middle) > 0 and
254                 middle[0] in _letters + _digits and (
255                     middle.endswith('.org') or
256                     middle.endswith('.net') or
257                     middle.endswith('.com')
258                 )):
259                 middle = '<a href="http://%s"%s>%s</a>' % (middle,
260                     nofollow_attr, trim_url(middle))
261             if middle.startswith('http://') or \
262                middle.startswith('https://'):
263                 middle = '<a href="%s"%s>%s</a>' % (middle,
264                     nofollow_attr, trim_url(middle))
265             if '@' in middle and not middle.startswith('www.') and \
266                not ':' in middle and _simple_email_re.match(middle):
267                 middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
268             if lead + middle + trail != word:
269                 words[i] = lead + middle + trail
270     return u''.join(words)
271
272
273 def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
274     """Generate some lorem impsum for the template."""
275     from jinja2.constants import LOREM_IPSUM_WORDS
276     from random import choice, randrange
277     words = LOREM_IPSUM_WORDS.split()
278     result = []
279
280     for _ in xrange(n):
281         next_capitalized = True
282         last_comma = last_fullstop = 0
283         word = None
284         last = None
285         p = []
286
287         # each paragraph contains out of 20 to 100 words.
288         for idx, _ in enumerate(xrange(randrange(min, max))):
289             while True:
290                 word = choice(words)
291                 if word != last:
292                     last = word
293                     break
294             if next_capitalized:
295                 word = word.capitalize()
296                 next_capitalized = False
297             # add commas
298             if idx - randrange(3, 8) > last_comma:
299                 last_comma = idx
300                 last_fullstop += 2
301                 word += ','
302             # add end of sentences
303             if idx - randrange(10, 20) > last_fullstop:
304                 last_comma = last_fullstop = idx
305                 word += '.'
306                 next_capitalized = True
307             p.append(word)
308
309         # ensure that the paragraph ends with a dot.
310         p = u' '.join(p)
311         if p.endswith(','):
312             p = p[:-1] + '.'
313         elif not p.endswith('.'):
314             p += '.'
315         result.append(p)
316
317     if not html:
318         return u'\n\n'.join(result)
319     return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
320
321
322 class Markup(unicode):
323     r"""Marks a string as being safe for inclusion in HTML/XML output without
324     needing to be escaped.  This implements the `__html__` interface a couple
325     of frameworks and web applications use.  :class:`Markup` is a direct
326     subclass of `unicode` and provides all the methods of `unicode` just that
327     it escapes arguments passed and always returns `Markup`.
328
329     The `escape` function returns markup objects so that double escaping can't
330     happen.  If you want to use autoescaping in Jinja just enable the
331     autoescaping feature in the environment.
332
333     The constructor of the :class:`Markup` class can be used for three
334     different things:  When passed an unicode object it's assumed to be safe,
335     when passed an object with an HTML representation (has an `__html__`
336     method) that representation is used, otherwise the object passed is
337     converted into a unicode string and then assumed to be safe:
338
339     >>> Markup("Hello <em>World</em>!")
340     Markup(u'Hello <em>World</em>!')
341     >>> class Foo(object):
342     ...  def __html__(self):
343     ...   return '<a href="#">foo</a>'
344     ...
345     >>> Markup(Foo())
346     Markup(u'<a href="#">foo</a>')
347
348     If you want object passed being always treated as unsafe you can use the
349     :meth:`escape` classmethod to create a :class:`Markup` object:
350
351     >>> Markup.escape("Hello <em>World</em>!")
352     Markup(u'Hello &lt;em&gt;World&lt;/em&gt;!')
353
354     Operations on a markup string are markup aware which means that all
355     arguments are passed through the :func:`escape` function:
356
357     >>> em = Markup("<em>%s</em>")
358     >>> em % "foo & bar"
359     Markup(u'<em>foo &amp; bar</em>')
360     >>> strong = Markup("<strong>%(text)s</strong>")
361     >>> strong % {'text': '<blink>hacker here</blink>'}
362     Markup(u'<strong>&lt;blink&gt;hacker here&lt;/blink&gt;</strong>')
363     >>> Markup("<em>Hello</em> ") + "<foo>"
364     Markup(u'<em>Hello</em> &lt;foo&gt;')
365     """
366     __slots__ = ()
367
368     def __new__(cls, base=u'', encoding=None, errors='strict'):
369         if hasattr(base, '__html__'):
370             base = base.__html__()
371         if encoding is None:
372             return unicode.__new__(cls, base)
373         return unicode.__new__(cls, base, encoding, errors)
374
375     def __html__(self):
376         return self
377
378     def __add__(self, other):
379         if hasattr(other, '__html__') or isinstance(other, basestring):
380             return self.__class__(unicode(self) + unicode(escape(other)))
381         return NotImplemented
382
383     def __radd__(self, other):
384         if hasattr(other, '__html__') or isinstance(other, basestring):
385             return self.__class__(unicode(escape(other)) + unicode(self))
386         return NotImplemented
387
388     def __mul__(self, num):
389         if isinstance(num, (int, long)):
390             return self.__class__(unicode.__mul__(self, num))
391         return NotImplemented
392     __rmul__ = __mul__
393
394     def __mod__(self, arg):
395         if isinstance(arg, tuple):
396             arg = tuple(imap(_MarkupEscapeHelper, arg))
397         else:
398             arg = _MarkupEscapeHelper(arg)
399         return self.__class__(unicode.__mod__(self, arg))
400
401     def __repr__(self):
402         return '%s(%s)' % (
403             self.__class__.__name__,
404             unicode.__repr__(self)
405         )
406
407     def join(self, seq):
408         return self.__class__(unicode.join(self, imap(escape, seq)))
409     join.__doc__ = unicode.join.__doc__
410
411     def split(self, *args, **kwargs):
412         return map(self.__class__, unicode.split(self, *args, **kwargs))
413     split.__doc__ = unicode.split.__doc__
414
415     def rsplit(self, *args, **kwargs):
416         return map(self.__class__, unicode.rsplit(self, *args, **kwargs))
417     rsplit.__doc__ = unicode.rsplit.__doc__
418
419     def splitlines(self, *args, **kwargs):
420         return map(self.__class__, unicode.splitlines(self, *args, **kwargs))
421     splitlines.__doc__ = unicode.splitlines.__doc__
422
423     def unescape(self):
424         r"""Unescape markup again into an unicode string.  This also resolves
425         known HTML4 and XHTML entities:
426
427         >>> Markup("Main &raquo; <em>About</em>").unescape()
428         u'Main \xbb <em>About</em>'
429         """
430         from jinja2.constants import HTML_ENTITIES
431         def handle_match(m):
432             name = m.group(1)
433             if name in HTML_ENTITIES:
434                 return unichr(HTML_ENTITIES[name])
435             try:
436                 if name[:2] in ('#x', '#X'):
437                     return unichr(int(name[2:], 16))
438                 elif name.startswith('#'):
439                     return unichr(int(name[1:]))
440             except ValueError:
441                 pass
442             return u''
443         return _entity_re.sub(handle_match, unicode(self))
444
445     def striptags(self):
446         r"""Unescape markup into an unicode string and strip all tags.  This
447         also resolves known HTML4 and XHTML entities.  Whitespace is
448         normalized to one:
449
450         >>> Markup("Main &raquo;  <em>About</em>").striptags()
451         u'Main \xbb About'
452         """
453         stripped = u' '.join(_striptags_re.sub('', self).split())
454         return Markup(stripped).unescape()
455
456     @classmethod
457     def escape(cls, s):
458         """Escape the string.  Works like :func:`escape` with the difference
459         that for subclasses of :class:`Markup` this function would return the
460         correct subclass.
461         """
462         rv = escape(s)
463         if rv.__class__ is not cls:
464             return cls(rv)
465         return rv
466
467     def make_wrapper(name):
468         orig = getattr(unicode, name)
469         def func(self, *args, **kwargs):
470             args = _escape_argspec(list(args), enumerate(args))
471             _escape_argspec(kwargs, kwargs.iteritems())
472             return self.__class__(orig(self, *args, **kwargs))
473         func.__name__ = orig.__name__
474         func.__doc__ = orig.__doc__
475         return func
476
477     for method in '__getitem__', 'capitalize', \
478                   'title', 'lower', 'upper', 'replace', 'ljust', \
479                   'rjust', 'lstrip', 'rstrip', 'center', 'strip', \
480                   'translate', 'expandtabs', 'swapcase', 'zfill':
481         locals()[method] = make_wrapper(method)
482
483     # new in python 2.5
484     if hasattr(unicode, 'partition'):
485         partition = make_wrapper('partition'),
486         rpartition = make_wrapper('rpartition')
487
488     # new in python 2.6
489     if hasattr(unicode, 'format'):
490         format = make_wrapper('format')
491
492     # not in python 3
493     if hasattr(unicode, '__getslice__'):
494         __getslice__ = make_wrapper('__getslice__')
495
496     del method, make_wrapper
497
498
499 def _escape_argspec(obj, iterable):
500     """Helper for various string-wrapped functions."""
501     for key, value in iterable:
502         if hasattr(value, '__html__') or isinstance(value, basestring):
503             obj[key] = escape(value)
504     return obj
505
506
507 class _MarkupEscapeHelper(object):
508     """Helper for Markup.__mod__"""
509
510     def __init__(self, obj):
511         self.obj = obj
512
513     __getitem__ = lambda s, x: _MarkupEscapeHelper(s.obj[x])
514     __str__ = lambda s: str(escape(s.obj))
515     __unicode__ = lambda s: unicode(escape(s.obj))
516     __repr__ = lambda s: str(escape(repr(s.obj)))
517     __int__ = lambda s: int(s.obj)
518     __float__ = lambda s: float(s.obj)
519
520
521 class LRUCache(object):
522     """A simple LRU Cache implementation."""
523
524     # this is fast for small capacities (something below 1000) but doesn't
525     # scale.  But as long as it's only used as storage for templates this
526     # won't do any harm.
527
528     def __init__(self, capacity):
529         self.capacity = capacity
530         self._mapping = {}
531         self._queue = deque()
532         self._postinit()
533
534     def _postinit(self):
535         # alias all queue methods for faster lookup
536         self._popleft = self._queue.popleft
537         self._pop = self._queue.pop
538         if hasattr(self._queue, 'remove'):
539             self._remove = self._queue.remove
540         self._wlock = allocate_lock()
541         self._append = self._queue.append
542
543     def _remove(self, obj):
544         """Python 2.4 compatibility."""
545         for idx, item in enumerate(self._queue):
546             if item == obj:
547                 del self._queue[idx]
548                 break
549
550     def __getstate__(self):
551         return {
552             'capacity':     self.capacity,
553             '_mapping':     self._mapping,
554             '_queue':       self._queue
555         }
556
557     def __setstate__(self, d):
558         self.__dict__.update(d)
559         self._postinit()
560
561     def __getnewargs__(self):
562         return (self.capacity,)
563
564     def copy(self):
565         """Return an shallow copy of the instance."""
566         rv = self.__class__(self.capacity)
567         rv._mapping.update(self._mapping)
568         rv._queue = deque(self._queue)
569         return rv
570
571     def get(self, key, default=None):
572         """Return an item from the cache dict or `default`"""
573         try:
574             return self[key]
575         except KeyError:
576             return default
577
578     def setdefault(self, key, default=None):
579         """Set `default` if the key is not in the cache otherwise
580         leave unchanged. Return the value of this key.
581         """
582         try:
583             return self[key]
584         except KeyError:
585             self[key] = default
586             return default
587
588     def clear(self):
589         """Clear the cache."""
590         self._wlock.acquire()
591         try:
592             self._mapping.clear()
593             self._queue.clear()
594         finally:
595             self._wlock.release()
596
597     def __contains__(self, key):
598         """Check if a key exists in this cache."""
599         return key in self._mapping
600
601     def __len__(self):
602         """Return the current size of the cache."""
603         return len(self._mapping)
604
605     def __repr__(self):
606         return '<%s %r>' % (
607             self.__class__.__name__,
608             self._mapping
609         )
610
611     def __getitem__(self, key):
612         """Get an item from the cache. Moves the item up so that it has the
613         highest priority then.
614
615         Raise an `KeyError` if it does not exist.
616         """
617         rv = self._mapping[key]
618         if self._queue[-1] != key:
619             try:
620                 self._remove(key)
621             except ValueError:
622                 # if something removed the key from the container
623                 # when we read, ignore the ValueError that we would
624                 # get otherwise.
625                 pass
626             self._append(key)
627         return rv
628
629     def __setitem__(self, key, value):
630         """Sets the value for an item. Moves the item up so that it
631         has the highest priority then.
632         """
633         self._wlock.acquire()
634         try:
635             if key in self._mapping:
636                 try:
637                     self._remove(key)
638                 except ValueError:
639                     # __getitem__ is not locked, it might happen
640                     pass
641             elif len(self._mapping) == self.capacity:
642                 del self._mapping[self._popleft()]
643             self._append(key)
644             self._mapping[key] = value
645         finally:
646             self._wlock.release()
647
648     def __delitem__(self, key):
649         """Remove an item from the cache dict.
650         Raise an `KeyError` if it does not exist.
651         """
652         self._wlock.acquire()
653         try:
654             del self._mapping[key]
655             try:
656                 self._remove(key)
657             except ValueError:
658                 # __getitem__ is not locked, it might happen
659                 pass
660         finally:
661             self._wlock.release()
662
663     def items(self):
664         """Return a list of items."""
665         result = [(key, self._mapping[key]) for key in list(self._queue)]
666         result.reverse()
667         return result
668
669     def iteritems(self):
670         """Iterate over all items."""
671         return iter(self.items())
672
673     def values(self):
674         """Return a list of all values."""
675         return [x[1] for x in self.items()]
676
677     def itervalue(self):
678         """Iterate over all values."""
679         return iter(self.values())
680
681     def keys(self):
682         """Return a list of all keys ordered by most recent usage."""
683         return list(self)
684
685     def iterkeys(self):
686         """Iterate over all keys in the cache dict, ordered by
687         the most recent usage.
688         """
689         return reversed(tuple(self._queue))
690
691     __iter__ = iterkeys
692
693     def __reversed__(self):
694         """Iterate over the values in the cache dict, oldest items
695         coming first.
696         """
697         return iter(tuple(self._queue))
698
699     __copy__ = copy
700
701
702 # register the LRU cache as mutable mapping if possible
703 try:
704     from collections import MutableMapping
705     MutableMapping.register(LRUCache)
706 except ImportError:
707     pass
708
709
710 class Cycler(object):
711     """A cycle helper for templates."""
712
713     def __init__(self, *items):
714         if not items:
715             raise RuntimeError('at least one item has to be provided')
716         self.items = items
717         self.reset()
718
719     def reset(self):
720         """Resets the cycle."""
721         self.pos = 0
722
723     @property
724     def current(self):
725         """Returns the current item."""
726         return self.items[self.pos]
727
728     def next(self):
729         """Goes one item ahead and returns it."""
730         rv = self.current
731         self.pos = (self.pos + 1) % len(self.items)
732         return rv
733
734
735 class Joiner(object):
736     """A joining helper for templates."""
737
738     def __init__(self, sep=u', '):
739         self.sep = sep
740         self.used = False
741
742     def __call__(self):
743         if not self.used:
744             self.used = True
745             return u''
746         return self.sep
747
748
749 # we have to import it down here as the speedups module imports the
750 # markup type which is define above.
751 try:
752     from jinja2._speedups import escape, soft_unicode
753 except ImportError:
754     def escape(s):
755         """Convert the characters &, <, >, ' and " in string s to HTML-safe
756         sequences.  Use this if you need to display text that might contain
757         such characters in HTML.  Marks return value as markup string.
758         """
759         if hasattr(s, '__html__'):
760             return s.__html__()
761         return Markup(unicode(s)
762             .replace('&', '&amp;')
763             .replace('>', '&gt;')
764             .replace('<', '&lt;')
765             .replace("'", '&#39;')
766             .replace('"', '&#34;')
767         )
768
769     def soft_unicode(s):
770         """Make a string unicode if it isn't already.  That way a markup
771         string is not converted back to unicode.
772         """
773         if not isinstance(s, unicode):
774             s = unicode(s)
775         return s
776
777
778 # partials
779 try:
780     from functools import partial
781 except ImportError:
782     class partial(object):
783         def __init__(self, _func, *args, **kwargs):
784             self._func = _func
785             self._args = args
786             self._kwargs = kwargs
787         def __call__(self, *args, **kwargs):
788             kwargs.update(self._kwargs)
789             return self._func(*(self._args + args), **kwargs)