attempt to fix python 2.6 issues

- by converting to Unix line endings
This commit is contained in:
Lucas Tan
2014-04-05 19:54:26 +08:00
parent 8a28cd0fb5
commit 2f70d032eb
3 changed files with 280 additions and 270 deletions

View File

@@ -1,143 +1,143 @@
from __future__ import absolute_import # noqa from __future__ import absolute_import
import io import io
from types import MethodType from types import MethodType
from django import template from django import template
from django.template import Template from django.template import Template
from django.template.loader_tags import (ExtendsNode, BlockNode, from django.template.loader_tags import (ExtendsNode, BlockNode,
BLOCK_CONTEXT_KEY) BLOCK_CONTEXT_KEY)
from compressor.exceptions import TemplateSyntaxError, TemplateDoesNotExist from compressor.exceptions import TemplateSyntaxError, TemplateDoesNotExist
from compressor.templatetags.compress import CompressorNode from compressor.templatetags.compress import CompressorNode
def patched_render(self, context): def patched_render(self, context):
# 'Fake' _render method that just returns the context instead of # 'Fake' _render method that just returns the context instead of
# rendering. It also checks whether the first node is an extend node or # rendering. It also checks whether the first node is an extend node or
# not, to be able to handle complex inheritance chain. # not, to be able to handle complex inheritance chain.
self._render_firstnode = MethodType(patched_render_firstnode, self) self._render_firstnode = MethodType(patched_render_firstnode, self)
self._render_firstnode(context) self._render_firstnode(context)
# Cleanup, uninstall our _render monkeypatch now that it has been called # Cleanup, uninstall our _render monkeypatch now that it has been called
self._render = self._old_render self._render = self._old_render
return context return context
def patched_render_firstnode(self, context): def patched_render_firstnode(self, context):
# If this template has a ExtendsNode, we want to find out what # If this template has a ExtendsNode, we want to find out what
# should be put in render_context to make the {% block ... %} # should be put in render_context to make the {% block ... %}
# tags work. # tags work.
# #
# We can't fully render the base template(s) (we don't have the # We can't fully render the base template(s) (we don't have the
# full context vars - only what's necessary to render the compress # full context vars - only what's necessary to render the compress
# nodes!), therefore we hack the ExtendsNode we found, patching # nodes!), therefore we hack the ExtendsNode we found, patching
# its get_parent method so that rendering the ExtendsNode only # its get_parent method so that rendering the ExtendsNode only
# gives us the blocks content without doing any actual rendering. # gives us the blocks content without doing any actual rendering.
extra_context = {} extra_context = {}
try: try:
firstnode = self.nodelist[0] firstnode = self.nodelist[0]
except IndexError: except IndexError:
firstnode = None firstnode = None
if isinstance(firstnode, ExtendsNode): if isinstance(firstnode, ExtendsNode):
firstnode._log = self._log firstnode._log = self._log
firstnode._log_verbosity = self._log_verbosity firstnode._log_verbosity = self._log_verbosity
firstnode._old_get_parent = firstnode.get_parent firstnode._old_get_parent = firstnode.get_parent
firstnode.get_parent = MethodType(patched_get_parent, firstnode) firstnode.get_parent = MethodType(patched_get_parent, firstnode)
try: try:
extra_context = firstnode.render(context) extra_context = firstnode.render(context)
context.render_context = extra_context.render_context context.render_context = extra_context.render_context
# We aren't rendering {% block %} tags, but we want # We aren't rendering {% block %} tags, but we want
# {{ block.super }} inside {% compress %} inside {% block %}s to # {{ block.super }} inside {% compress %} inside {% block %}s to
# work. Therefore, we need to pop() the last block context for # work. Therefore, we need to pop() the last block context for
# each block name, to emulate what would have been done if the # each block name, to emulate what would have been done if the
# {% block %} had been fully rendered. # {% block %} had been fully rendered.
for blockname in firstnode.blocks.keys(): for blockname in firstnode.blocks.keys():
context.render_context[BLOCK_CONTEXT_KEY].pop(blockname) context.render_context[BLOCK_CONTEXT_KEY].pop(blockname)
except (IOError, template.TemplateSyntaxError, except (IOError, template.TemplateSyntaxError,
template.TemplateDoesNotExist): template.TemplateDoesNotExist):
# That first node we are trying to render might cause more errors # That first node we are trying to render might cause more errors
# that we didn't catch when simply creating a Template instance # that we didn't catch when simply creating a Template instance
# above, so we need to catch that (and ignore it, just like above) # above, so we need to catch that (and ignore it, just like above)
# as well. # as well.
if self._log_verbosity > 0: if self._log_verbosity > 0:
self._log.write("Caught error when rendering extend node from " self._log.write("Caught error when rendering extend node from "
"template %s\n" % getattr(self, 'name', self)) "template %s\n" % getattr(self, 'name', self))
return None return None
finally: finally:
# Cleanup, uninstall our get_parent monkeypatch now that it has been called # Cleanup, uninstall our get_parent monkeypatch now that it has been called
firstnode.get_parent = firstnode._old_get_parent firstnode.get_parent = firstnode._old_get_parent
return extra_context return extra_context
def patched_get_parent(self, context): def patched_get_parent(self, context):
# Patch template returned by extendsnode's get_parent to make sure their # Patch template returned by extendsnode's get_parent to make sure their
# _render method is just returning the context instead of actually # _render method is just returning the context instead of actually
# rendering stuff. # rendering stuff.
# In addition, this follows the inheritance chain by looking if the first # In addition, this follows the inheritance chain by looking if the first
# node of the template is an extend node itself. # node of the template is an extend node itself.
compiled_template = self._old_get_parent(context) compiled_template = self._old_get_parent(context)
compiled_template._log = self._log compiled_template._log = self._log
compiled_template._log_verbosity = self._log_verbosity compiled_template._log_verbosity = self._log_verbosity
compiled_template._old_render = compiled_template._render compiled_template._old_render = compiled_template._render
compiled_template._render = MethodType(patched_render, compiled_template) compiled_template._render = MethodType(patched_render, compiled_template)
return compiled_template return compiled_template
class DjangoParser(object): class DjangoParser(object):
def __init__(self, charset): def __init__(self, charset):
self.charset = charset self.charset = charset
def parse(self, template_name): def parse(self, template_name):
with io.open(template_name, mode='rb') as file: with io.open(template_name, mode='rb') as file:
try: try:
return Template(file.read().decode(self.charset)) return Template(file.read().decode(self.charset))
except template.TemplateSyntaxError as e: except template.TemplateSyntaxError as e:
raise TemplateSyntaxError(str(e)) raise TemplateSyntaxError(str(e))
except template.TemplateDoesNotExist as e: except template.TemplateDoesNotExist as e:
raise TemplateDoesNotExist(str(e)) raise TemplateDoesNotExist(str(e))
def process_template(self, template, context): def process_template(self, template, context):
template._render_firstnode = MethodType(patched_render_firstnode, template) template._render_firstnode = MethodType(patched_render_firstnode, template)
template._extra_context = template._render_firstnode(context) template._extra_context = template._render_firstnode(context)
if template._extra_context is None: if template._extra_context is None:
# Something is wrong - ignore this template # Something is wrong - ignore this template
return False return False
return True return True
def get_init_context(self, offline_context): def get_init_context(self, offline_context):
return offline_context return offline_context
def process_node(self, template, context, node): def process_node(self, template, context, node):
if template._extra_context and node._block_name: if template._extra_context and node._block_name:
# Give a block context to the node if it was found inside # Give a block context to the node if it was found inside
# a {% block %}. # a {% block %}.
context['block'] = context.render_context[BLOCK_CONTEXT_KEY].get_block(node._block_name) context['block'] = context.render_context[BLOCK_CONTEXT_KEY].get_block(node._block_name)
if context['block']: if context['block']:
context['block'].context = context context['block'].context = context
def render_nodelist(self, template, context, node): def render_nodelist(self, template, context, node):
return node.nodelist.render(context) return node.nodelist.render(context)
def render_node(self, template, context, node): def render_node(self, template, context, node):
return node.render(context, forced=True) return node.render(context, forced=True)
def get_nodelist(self, node): def get_nodelist(self, node):
# Check if node is an ```if``` switch with true and false branches # Check if node is an ```if``` switch with true and false branches
if hasattr(node, 'nodelist_true') and hasattr(node, 'nodelist_false'): if hasattr(node, 'nodelist_true') and hasattr(node, 'nodelist_false'):
return node.nodelist_true + node.nodelist_false return node.nodelist_true + node.nodelist_false
return getattr(node, "nodelist", []) return getattr(node, "nodelist", [])
def walk_nodes(self, node, block_name=None): def walk_nodes(self, node, block_name=None):
for node in self.get_nodelist(node): for node in self.get_nodelist(node):
if isinstance(node, BlockNode): if isinstance(node, BlockNode):
block_name = node.name block_name = node.name
if isinstance(node, CompressorNode) and node.is_offline_compression_enabled(forced=True): if isinstance(node, CompressorNode) and node.is_offline_compression_enabled(forced=True):
node._block_name = block_name node._block_name = block_name
yield node yield node
else: else:
for node in self.walk_nodes(node, block_name=block_name): for node in self.walk_nodes(node, block_name=block_name):
yield node yield node

View File

@@ -1,125 +1,125 @@
from __future__ import absolute_import # noqa from __future__ import absolute_import
import io import io
import jinja2 import jinja2
import jinja2.ext import jinja2.ext
from jinja2 import nodes from jinja2 import nodes
from jinja2.ext import Extension from jinja2.ext import Extension
from jinja2.nodes import CallBlock, Call, ExtensionAttribute from jinja2.nodes import CallBlock, Call, ExtensionAttribute
from compressor.exceptions import TemplateSyntaxError, TemplateDoesNotExist from compressor.exceptions import TemplateSyntaxError, TemplateDoesNotExist
def flatten_context(context): def flatten_context(context):
if hasattr(context, 'dicts'): if hasattr(context, 'dicts'):
context_dict = {} context_dict = {}
for d in context.dicts: for d in context.dicts:
context_dict.update(d) context_dict.update(d)
return context_dict return context_dict
return context return context
class SpacelessExtension(Extension): class SpacelessExtension(Extension):
""" """
Functional "spaceless" extension equivalent to Django's. Functional "spaceless" extension equivalent to Django's.
See: https://github.com/django/django/blob/master/django/template/defaulttags.py See: https://github.com/django/django/blob/master/django/template/defaulttags.py
""" """
tags = set(['spaceless']) tags = set(['spaceless'])
def parse(self, parser): def parse(self, parser):
lineno = next(parser.stream).lineno lineno = next(parser.stream).lineno
body = parser.parse_statements(['name:endspaceless'], drop_needle=True) body = parser.parse_statements(['name:endspaceless'], drop_needle=True)
return nodes.CallBlock(self.call_method('_spaceless', []), return nodes.CallBlock(self.call_method('_spaceless', []),
[], [], body).set_lineno(lineno) [], [], body).set_lineno(lineno)
def _spaceless(self, caller): def _spaceless(self, caller):
from django.utils.html import strip_spaces_between_tags from django.utils.html import strip_spaces_between_tags
return strip_spaces_between_tags(caller().strip()) return strip_spaces_between_tags(caller().strip())
def url_for(mod, filename): def url_for(mod, filename):
""" """
Incomplete emulation of Flask's url_for. Incomplete emulation of Flask's url_for.
""" """
from django.contrib.staticfiles.templatetags import staticfiles from django.contrib.staticfiles.templatetags import staticfiles
if mod == "static": if mod == "static":
return staticfiles.static(filename) return staticfiles.static(filename)
return "" return ""
class Jinja2Parser(object): class Jinja2Parser(object):
COMPRESSOR_ID = 'compressor.contrib.jinja2ext.CompressorExtension' COMPRESSOR_ID = 'compressor.contrib.jinja2ext.CompressorExtension'
def __init__(self, charset, env): def __init__(self, charset, env):
self.charset = charset self.charset = charset
self.env = env self.env = env
def parse(self, template_name): def parse(self, template_name):
with io.open(template_name, mode='rb') as file: with io.open(template_name, mode='rb') as file:
try: try:
template = self.env.parse(file.read().decode(self.charset)) template = self.env.parse(file.read().decode(self.charset))
except jinja2.TemplateSyntaxError as e: except jinja2.TemplateSyntaxError as e:
raise TemplateSyntaxError(str(e)) raise TemplateSyntaxError(str(e))
except jinja2.TemplateNotFound as e: except jinja2.TemplateNotFound as e:
raise TemplateDoesNotExist(str(e)) raise TemplateDoesNotExist(str(e))
return template return template
def process_template(self, template, context): def process_template(self, template, context):
return True return True
def get_init_context(self, offline_context): def get_init_context(self, offline_context):
# Don't need to add filters and tests to the context, as Jinja2 will # Don't need to add filters and tests to the context, as Jinja2 will
# automatically look for them in self.env.filters and self.env.tests. # automatically look for them in self.env.filters and self.env.tests.
# This is tested by test_complex and test_templatetag. # This is tested by test_complex and test_templatetag.
# Allow offline context to override the globals. # Allow offline context to override the globals.
context = self.env.globals.copy() context = self.env.globals.copy()
context.update(offline_context) context.update(offline_context)
return context return context
def process_node(self, template, context, node): def process_node(self, template, context, node):
pass pass
def _render_nodes(self, template, context, nodes): def _render_nodes(self, template, context, nodes):
compiled_node = self.env.compile(jinja2.nodes.Template(nodes)) compiled_node = self.env.compile(jinja2.nodes.Template(nodes))
template = jinja2.Template.from_code(self.env, compiled_node, {}) template = jinja2.Template.from_code(self.env, compiled_node, {})
flat_context = flatten_context(context) flat_context = flatten_context(context)
return template.render(flat_context) return template.render(flat_context)
def render_nodelist(self, template, context, node): def render_nodelist(self, template, context, node):
return self._render_nodes(template, context, node.body) return self._render_nodes(template, context, node.body)
def render_node(self, template, context, node): def render_node(self, template, context, node):
return self._render_nodes(template, context, [node]) return self._render_nodes(template, context, [node])
def get_nodelist(self, node): def get_nodelist(self, node):
body = getattr(node, "body", getattr(node, "nodes", [])) body = getattr(node, "body", getattr(node, "nodes", []))
if isinstance(node, jinja2.nodes.If): if isinstance(node, jinja2.nodes.If):
return body + node.else_ return body + node.else_
return body return body
def walk_nodes(self, node, block_name=None): def walk_nodes(self, node, block_name=None):
for node in self.get_nodelist(node): for node in self.get_nodelist(node):
if (isinstance(node, CallBlock) and if (isinstance(node, CallBlock) and
isinstance(node.call, Call) and isinstance(node.call, Call) and
isinstance(node.call.node, ExtensionAttribute) and isinstance(node.call.node, ExtensionAttribute) and
node.call.node.identifier == self.COMPRESSOR_ID): node.call.node.identifier == self.COMPRESSOR_ID):
node.call.node.name = '_compress_forced' node.call.node.name = '_compress_forced'
yield node yield node
else: else:
for node in self.walk_nodes(node, block_name=block_name): for node in self.walk_nodes(node, block_name=block_name):
yield node yield node

14
tox.ini
View File

@@ -20,6 +20,16 @@ three =
BeautifulSoup4 BeautifulSoup4
jingo jingo
coffin coffin
three_two =
flake8
coverage
html5lib
mock
jinja2==2.6
lxml
BeautifulSoup4
jingo
coffin
[tox] [tox]
envlist = envlist =
@@ -54,7 +64,7 @@ deps =
basepython = python3.2 basepython = python3.2
deps = deps =
Django>=1.6,<1.7 Django>=1.6,<1.7
{[deps]three} {[deps]three_two}
[testenv:py27-1.6.X] [testenv:py27-1.6.X]
basepython = python2.7 basepython = python2.7
@@ -80,7 +90,7 @@ basepython = python3.2
deps = deps =
Django>=1.5,<1.6 Django>=1.5,<1.6
django-discover-runner django-discover-runner
{[deps]three} {[deps]three_two}
[testenv:py27-1.5.X] [testenv:py27-1.5.X]
basepython = python2.7 basepython = python2.7