diff --git a/VERSION b/VERSION index baa88dee..fa2f20a3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.1 (2012-08-28 20:38:06) rc4 +Version 2.00.1 (2012-08-28 21:11:21) rc4 diff --git a/gluon/html.py b/gluon/html.py index 3e9bb778..2d6b8131 100644 --- a/gluon/html.py +++ b/gluon/html.py @@ -1686,14 +1686,14 @@ class INPUT(DIV): if name is None or name == '': return True name = str(name) - + request_vars_get = self.request_vars.get if self['_type'] != 'checkbox': self['old_value'] = self['value'] or self['_value'] or '' - value = self.request_vars.get(name, '') + value = request_vars_get(name, '') self['value'] = value else: self['old_value'] = self['value'] or False - value = self.request_vars.get(name) + value = request_vars_get(name) if isinstance(value, (tuple, list)): self['value'] = self['_value'] in value else: @@ -1936,14 +1936,15 @@ class FORM(DIV): # check formname and formkey status = True - if self.session: - formkey = self.session.get('_formkey[%s]' % self.formname, None) + request_vars = self.request_vars + if session: + formkey = session.get('_formkey[%s]' % formname, None) # check if user tampering with form and void CSRF - if formkey != self.request_vars._formkey: + if formkey != request_vars._formkey: status = False - if self.formname != self.request_vars._formname: + if formname != request_vars._formname: status = False - if status and self.session: + if status and session: # check if editing a record that has been modified by the server if hasattr(self,'record_hash') and self.record_hash != formkey: status = False diff --git a/gluon/template.py b/gluon/template.py index c1d71188..a8481338 100644 --- a/gluon/template.py +++ b/gluon/template.py @@ -15,10 +15,10 @@ Contributors: """ import os -import re import cgi import cStringIO import logging +from re import compile, sub, escape, DOTALL try: # have web2py from restricted import RestrictedError @@ -57,6 +57,18 @@ class SuperNode(Node): def __repr__(self): return "%s->%s" % (self.name, self.value) +def output_aux(node,blocks): + # If we have a block level + # If we can override this block. + # Override block from vars. + # Else we take the default + # Else its just a string + return (blocks[node.name].output(blocks) + if node.name in blocks else + node.output(blocks)) \ + if isinstance(node, BlockNode) \ + else str(node) + class BlockNode(Node): """ Block Container. @@ -81,8 +93,7 @@ class BlockNode(Node): def __repr__(self): lines = ['%sblock %s%s' % (self.left,self.name,self.right)] - for node in self.nodes: - lines.append(str(node)) + lines += [str(node) for node in self.nodes] lines.append('%send%s' % (self.left, self.right)) return ''.join(lines) @@ -90,11 +101,8 @@ class BlockNode(Node): """ Get this BlockNodes content, not including child Nodes """ - lines = [] - for node in self.nodes: - if not isinstance(node, BlockNode): - lines.append(str(node)) - return ''.join(lines) + return ''.join(str(node) for node in self.nodes \ + if not isinstance(node, BlockNode)) def append(self, node): """ @@ -122,30 +130,14 @@ class BlockNode(Node): else: raise TypeError("Invalid type; must be instance of ``BlockNode``. %s" % other) + def output(self, blocks): """ Merges all nodes into a single string. - blocks -- Dictionary of blocks that are extending from this template. """ - lines = [] - # Get each of our nodes - for node in self.nodes: - # If we have a block level node. - if isinstance(node, BlockNode): - # If we can override this block. - if node.name in blocks: - # Override block from vars. - lines.append(blocks[node.name].output(blocks)) - # Else we take the default - else: - lines.append(node.output(blocks)) - # Else its just a string - else: - lines.append(str(node)) - # Now combine all of our lines together. - return ''.join(lines) + return ''.join(output_aux(node,blocks) for node in self.nodes) class Content(BlockNode): """ @@ -165,29 +157,13 @@ class Content(BlockNode): self.pre_extend = pre_extend def __str__(self): - lines = [] - # For each of our nodes - for node in self.nodes: - # If it is a block node. - if isinstance(node, BlockNode): - # And the node has a name that corresponds with a block in us - if node.name in self.blocks: - # Use the overriding output. - lines.append(self.blocks[node.name].output(self.blocks)) - else: - # Otherwise we just use the nodes output. - lines.append(node.output(self.blocks)) - else: - # It is just a string, so include it. - lines.append(str(node)) - # Merge our list together. - return ''.join(lines) + return ''.join(output_aux(node,self.blocks) for node in self.nodes) def _insert(self, other, index = 0): """ Inserts object at index. """ - if isinstance(other, str) or isinstance(other, Node): + if isinstance(other, (str, Node)): self.nodes.insert(index, other) else: raise TypeError("Invalid type, must be instance of ``str`` or ``Node``.") @@ -201,8 +177,7 @@ class Content(BlockNode): if isinstance(other, (list, tuple)): # Must reverse so the order stays the same. other.reverse() - for item in other: - self._insert(item, index) + (self._insert(item, index) for item in other) else: self._insert(other, index) @@ -210,7 +185,7 @@ class Content(BlockNode): """ Adds a node to list. If it is a BlockNode then we assign a block for it. """ - if isinstance(node, str) or isinstance(node, Node): + if isinstance(node, (str, Node)): self.nodes.append(node) if isinstance(node, BlockNode): self.blocks[node.name] = node @@ -233,18 +208,18 @@ class Content(BlockNode): class TemplateParser(object): default_delimiters = ('{{','}}') - r_tag = re.compile(r'(\{\{.*?\}\})', re.DOTALL) + r_tag = compile(r'(\{\{.*?\}\})', DOTALL) - r_multiline = re.compile(r'(""".*?""")|(\'\'\'.*?\'\'\')', re.DOTALL) + r_multiline = compile(r'(""".*?""")|(\'\'\'.*?\'\'\')', DOTALL) # These are used for re-indentation. # Indent + 1 - re_block = re.compile('^(elif |else:|except:|except |finally:).*$', - re.DOTALL) + re_block = compile('^(elif |else:|except:|except |finally:).*$',DOTALL) + # Indent - 1 - re_unblock = re.compile('^(return|continue|break|raise)( .*)?$', re.DOTALL) + re_unblock = compile('^(return|continue|break|raise)( .*)?$', DOTALL) # Indent - 1 - re_pass = re.compile('^pass( .*)?$', re.DOTALL) + re_pass = compile('^pass( .*)?$', DOTALL) def __init__(self, text, name = "ParserContainer", @@ -291,13 +266,16 @@ class TemplateParser(object): # allow optional alternative delimiters self.delimiters = delimiters if delimiters != self.default_delimiters: - escaped_delimiters = (re.escape(delimiters[0]),re.escape(delimiters[1])) - self.r_tag = re.compile(r'(%s.*?%s)' % escaped_delimiters, re.DOTALL) + escaped_delimiters = (escape(delimiters[0]), + escape(delimiters[1])) + self.r_tag = compile(r'(%s.*?%s)' % escaped_delimiters, DOTALL) elif hasattr(context.get('response',None),'delimiters'): if context['response'].delimiters != self.default_delimiters: - escaped_delimiters = (re.escape(context['response'].delimiters[0]), - re.escape(context['response'].delimiters[1])) - self.r_tag = re.compile(r'(%s.*?%s)' % escaped_delimiters,re.DOTALL) + escaped_delimiters = ( + escape(context['response'].delimiters[0]), + escape(context['response'].delimiters[1])) + self.r_tag = compile(r'(%s.*?%s)' % escaped_delimiters, + DOTALL) # Create a root level Content that everything will go into. self.content = Content(name=name) @@ -524,17 +502,19 @@ class TemplateParser(object): # the parent nodes. self.content.nodes = [] + t_content = t.content + # Set our include, unique by filename - t.content.blocks['__include__' + filename] = buf + t_content.blocks['__include__' + filename] = buf # Make sure our pre_extended nodes go first - t.content.insert(pre) + t_content.insert(pre) # Then we extend our blocks - t.content.extend(self.content) + t_content.extend(self.content) # Work off the parent node. - self.content = t.content + self.content = t_content def parse(self, text): @@ -553,69 +533,20 @@ class TemplateParser(object): ij = self.r_tag.split(text) # j = current index # i = current item + stack = self.stack for j in range(len(ij)): i = ij[j] if i: - if len(self.stack) == 0: + if not stack: self._raise_error('The "end" tag is unmatched, please check if you have a starting "block" tag') # Our current element in the stack. - top = self.stack[-1] + top = stack[-1] if in_tag: line = i - # If we are missing any strings!!!! - # This usually happens with the following example - # template code - # - # {{a = '}}'}} - # or - # {{a = '}}blahblah{{'}} - # - # This will fix these - # This is commented out because the current template - # system has this same limitation. Since this has a - # performance hit on larger templates, I do not recommend - # using this code on production systems. This is still here - # for "i told you it *can* be fixed" purposes. - # - # -# if line.count("'") % 2 != 0 or line.count('"') % 2 != 0: -# -# # Look ahead -# la = 1 -# nextline = ij[j+la] -# -# # As long as we have not found our ending -# # brackets keep going -# while '}}' not in nextline: -# la += 1 -# nextline += ij[j+la] -# # clear this line, so we -# # don't attempt to parse it -# # this is why there is an "if i" -# # around line 530 -# ij[j+la] = '' -# -# # retrieve our index. -# index = nextline.index('}}') -# -# # Everything before the new brackets -# before = nextline[:index+2] -# -# # Everything after -# after = nextline[index+2:] -# -# # Make the next line everything after -# # so it parses correctly, this *should* be -# # all html -# ij[j+1] = after -# -# # Add everything before to the current line -# line += before - # Get rid of '{{' and '}}' line = line[2:-2].strip() @@ -633,9 +564,9 @@ class TemplateParser(object): # Perform block comment escaping. # This performs escaping ON anything # in between """ and """ - line = re.sub(TemplateParser.r_multiline, - remove_newline, - line) + line = sub(TemplateParser.r_multiline, + remove_newline, + line) if line.startswith('='): # IE: {{=response.title}} @@ -672,7 +603,7 @@ class TemplateParser(object): self.lexers[name](parser = self, value = value, top = top, - stack = self.stack,) + stack = stack) elif name == '=': # So we have a variable to insert into @@ -693,7 +624,7 @@ class TemplateParser(object): # so anything after this gets added # to this node. This allows us to # "nest" nodes. - self.stack.append(node) + stack.append(node) elif name == 'end' and not value.startswith('='): # We are done with this node. @@ -702,7 +633,7 @@ class TemplateParser(object): self.blocks[top.name] = top # Pop it. - self.stack.pop() + stack.pop() elif name == 'super' and not value.startswith('='): # Get our correct target name @@ -757,17 +688,17 @@ class TemplateParser(object): # So we can properly put a response.write() in place. continuation = False len_parsed = 0 - for k in range(len(tokens)): + for k, token in enumerate(tokens): - tokens[k] = tokens[k].strip() - len_parsed += len(tokens[k]) + token = tokens[k] = token.strip() + len_parsed += len(token) - if tokens[k].startswith('='): - if tokens[k].endswith('\\'): + if token.startswith('='): + if token.endswith('\\'): continuation = True - tokens[k] = "\n%s(%s" % (self.writer, tokens[k][1:].strip()) + tokens[k] = "\n%s(%s" % (self.writer, token[1:].strip()) else: - tokens[k] = "\n%s(%s)" % (self.writer, tokens[k][1:].strip()) + tokens[k] = "\n%s(%s)" % (self.writer, token[1:].strip()) elif continuation: tokens[k] += ')' continuation = False