From: Armin Ronacher Date: Thu, 5 Apr 2007 09:21:38 +0000 (+0200) Subject: [svn] moved some of the documentation into docstrings X-Git-Tag: 2.0rc1~373 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=5a8e49723a7aa1f2ee740fc20f2048a1e5a05fcb;p=jinja2.git [svn] moved some of the documentation into docstrings --HG-- branch : trunk --- diff --git a/CHANGES b/CHANGES index 435d009..77aee3f 100644 --- a/CHANGES +++ b/CHANGES @@ -15,7 +15,7 @@ Version 1.1 - improved security system regarding function calls. -- added `lipsum` function +- added `lipsum` function to generate random text. - strings without unicode characters are processed as binary strings now to workaround problems with `datetime.strftime` which only accepts @@ -25,6 +25,12 @@ Version 1.1 - silent variable name failure is now toggleable +- fixed issue with old-style classes not implementing `__getitem__` + (thanks to Axel Böhm for discovering that bug) + +- added a bunch of new docstrings to the Jinja classes. Makes fun now to + use pydoc :-) + Version 1.0 ----------- diff --git a/docs/generate.py b/docs/generate.py index a6dbb4e..9ae42f4 100755 --- a/docs/generate.py +++ b/docs/generate.py @@ -101,6 +101,13 @@ def generate_list_of_loaders(): return '\n\n'.join(result) +def generate_environment_doc(): + from jinja.environment import Environment + return '%s\n\n%s' % ( + inspect.getdoc(Environment), + inspect.getdoc(Environment.__init__) + ) + e = Environment() PYGMENTS_FORMATTER = HtmlFormatter(style='pastie', cssclass='syntax') @@ -108,6 +115,7 @@ PYGMENTS_FORMATTER = HtmlFormatter(style='pastie', cssclass='syntax') LIST_OF_FILTERS = generate_list_of_filters() LIST_OF_TESTS = generate_list_of_tests() LIST_OF_LOADERS = generate_list_of_loaders() +ENVIRONMENT_DOC = generate_environment_doc() FULL_TEMPLATE = e.from_string('''\ ' source = translator.translate() - return Template(environment, - compile(source, filename, 'exec')) + return Template(environment, compile(source, filename, 'exec')) process = staticmethod(process) # -- private helper methods def indent(self, text): """ - Indent the current text. + Indent the current text. This does only indent the + first line. """ return (' ' * (self.indention * 4)) + text @@ -236,7 +266,9 @@ class PythonTranslator(Translator): def handle_node(self, node): """ - Handle one node + Handle one node. Resolves the correct callback functions defined + in the callback mapping. This also raises the `TemplateSyntaxError` + for unsupported syntax elements such as list comprehensions. """ if node.__class__ in self.handlers: out = self.handlers[node.__class__](node) @@ -249,10 +281,19 @@ class PythonTranslator(Translator): return out def reset(self): + """ + Reset translation variables such as indention, cycle id + or the require_translations flag. + """ self.indention = 0 self.last_cycle_id = 0 + self.require_translations = False def translate(self): + """ + Translate the node defined in the constructor after + resetting the translator. + """ self.reset() return self.handle_node(self.node) @@ -377,6 +418,9 @@ class PythonTranslator(Translator): str(name), _to_tuple(tmp) )) + + # blocks must always be defined. even if it's empty. some + # features depend on it lines.append('\nblocks = {\n%s\n}' % ',\n'.join(dict_lines)) # now get the real source lines and map the debugging symbols @@ -439,8 +483,8 @@ class PythonTranslator(Translator): # simple loops else: - write('context[\'loop\'] = loop = LoopContext(%s, context[\'loop\'], None)' % - self.handle_node(node.seq)) + write('context[\'loop\'] = loop = LoopContext(%s, ' + 'context[\'loop\'], None)' % self.handle_node(node.seq)) write('for %s in loop:' % self.handle_node(node.item) ) @@ -469,7 +513,8 @@ class PythonTranslator(Translator): self.indention += 1 write('yield None') self.indention -= 2 - write('context[\'loop\'] = LoopContext(None, context[\'loop\'], buffereater(forloop))') + write('context[\'loop\'] = LoopContext(None, context[\'loop\'], ' + 'buffereater(forloop))') write('for item in forloop(%s):' % self.handle_node(node.seq)) self.indention += 1 write('yield item') @@ -526,9 +571,11 @@ class PythonTranslator(Translator): self.indention -= 1 if hardcoded: - write('yield finish_var(context.current[%r].cycle(), context)' % name) + write('yield finish_var(context.current[%r].cycle(), ' + 'context)' % name) else: - write('yield finish_var(context.current[%r].cycle(%s), context)' % ( + write('yield finish_var(context.current[%r].cycle(%s), ' + 'context)' % ( name, self.handle_node(node.seq) )) @@ -558,7 +605,8 @@ class PythonTranslator(Translator): write('argcount = len(args)') tmp = [] for idx, (name, n) in enumerate(node.arguments): - tmp.append('\'%s\': (argcount > %d and (args[%d],) or (%s,))[0]' % ( + tmp.append('\'%s\': (argcount > %d and (args[%d],) ' + 'or (%s,))[0]' % ( name, idx, idx, @@ -575,7 +623,8 @@ class PythonTranslator(Translator): self.indention += 1 write('yield False') self.indention -= 2 - buf.append(self.indent('context[%r] = buffereater(macro)' % node.name)) + buf.append(self.indent('context[%r] = buffereater(macro)' % + node.name)) return '\n'.join(buf) @@ -605,7 +654,8 @@ class PythonTranslator(Translator): self.indention += 1 write('yield None') self.indention -= 2 - write('yield %s' % self.filter('u\'\'.join(filtered())', node.filters)) + write('yield %s' % self.filter('u\'\'.join(filtered())', + node.filters)) return '\n'.join(buf) def handle_block(self, node, level=0): @@ -790,7 +840,8 @@ class PythonTranslator(Translator): else: args.append(self.handle_node(arg)) if not (args or kwargs or star_args or dstar_args): - return 'call_function_simple(%s, context)' % self.handle_node(node.node) + return 'call_function_simple(%s, context)' % \ + self.handle_node(node.node) return 'call_function(%s, context, %s, {%s}, %s, %s)' % ( self.handle_node(node.node), _to_tuple(args), diff --git a/jinja/utils.py b/jinja/utils.py index 2b0a4cf..cb21986 100644 --- a/jinja/utils.py +++ b/jinja/utils.py @@ -21,6 +21,9 @@ from jinja.nodes import Trans from jinja.datastructure import Context, TemplateData from jinja.exceptions import SecurityException, TemplateNotFound +#: the python2.4 version of deque is missing the remove method +#: because a for loop with a lookup for the missing value written +#: in python is slower we just use deque if we have python2.5 or higher if sys.version_info >= (2, 5): from collections import deque else: @@ -316,7 +319,10 @@ def raise_syntax_error(exception, env, source=None): def collect_translations(ast): """ - Collect all translatable strings for the given ast. + Collect all translatable strings for the given ast. The + return value is a list of tuples in the form ``(lineno, singular, + plural)``. If a translation doesn't require a plural form the + third item is `None`. """ todo = [ast] result = [] @@ -428,23 +434,36 @@ class CacheDict(object): self._append = self._queue.append def copy(self): + """ + Return an shallow copy of the instance. + """ rv = CacheDict(self.capacity) rv._mapping.update(self._mapping) rv._queue = self._queue[:] return rv def get(self, key, default=None): + """ + Return an item from the cache dict or `default` + """ if key in self: return self[key] return default def setdefault(self, key, default=None): + """ + Set `default` if the key is not in the cache otherwise + leave unchanged. Return the value of this key. + """ if key in self: return self[key] self[key] = default return default def clear(self): + """ + Clear the cache dict. + """ self._mapping.clear() try: self._queue.clear() @@ -452,9 +471,15 @@ class CacheDict(object): del self._queue[:] def __contains__(self, key): + """ + Check if a key exists in this cache dict. + """ return key in self._mapping def __len__(self): + """ + Return the current size of the cache dict. + """ return len(self._mapping) def __repr__(self): @@ -464,6 +489,12 @@ class CacheDict(object): ) def __getitem__(self, key): + """ + Get an item from the cache dict. Moves the item up so that + it has the highest priority then. + + Raise an `KeyError` if it does not exist. + """ rv = self._mapping[key] if self._queue[-1] != key: self._remove(key) @@ -471,6 +502,10 @@ class CacheDict(object): return rv def __setitem__(self, key, value): + """ + Sets the value for an item. Moves the item up so that it + has the highest priority then. + """ if key in self._mapping: self._remove(key) elif len(self._mapping) == self.capacity: @@ -479,16 +514,38 @@ class CacheDict(object): self._mapping[key] = value def __delitem__(self, key): + """ + Remove an item from the cache dict. + Raise an `KeyError` if it does not exist. + """ del self._mapping[key] self._remove(key) def __iter__(self): + """ + Iterate over all values in the cache dict, ordered by + the most recent usage. + """ try: return reversed(self._queue) except NameError: return iter(self._queue[::-1]) def __reversed__(self): + """ + Iterate over the values in the cache dict, oldest items + coming first. + """ return iter(self._queue) __copy__ = copy + + def __deepcopy__(self): + """ + Return a deep copy of the cache dict. + """ + from copy import deepcopy + rv = CacheDict(self.capacity) + rv._mapping = deepcopy(self._mapping) + rv._queue = deepcopy(self._queue) + return rv