Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pystache_custom
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
pystache_custom
Commits
b6018af6
Commit
b6018af6
authored
Dec 21, 2011
by
Chris Jerdonek
Browse files
Options
Browse Files
Download
Plain Diff
Merge 'issue_58' into development: closing issue #58 (RenderEngine class)
parents
73f3d72f
331f149e
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
488 additions
and
334 deletions
+488
-334
pystache/renderengine.py
+258
-0
pystache/template.py
+12
-220
tests/test_renderengine.py
+169
-0
tests/test_template.py
+49
-114
No files found.
pystache/renderengine.py
0 → 100644
View file @
b6018af6
# coding: utf-8
"""
Defines a class responsible for rendering logic.
"""
import
collections
import
re
try
:
# The collections.Callable class is not available until Python 2.6.
import
collections.Callable
def
check_callable
(
it
):
return
isinstance
(
it
,
collections
.
Callable
)
except
ImportError
:
def
check_callable
(
it
):
return
hasattr
(
it
,
'__call__'
)
class
Modifiers
(
dict
):
"""Dictionary with a decorator for assigning functions to keys."""
def
set
(
self
,
key
):
"""
Return a decorator that assigns the given function to the given key.
>>> modifiers = {}
>>> @modifiers.set('P')
... def render_tongue(self, tag_name=None, context=None):
... return ":P
%
s"
%
tag_name
>>> modifiers
{'P': <function render_tongue at 0x...>}
"""
def
decorate
(
func
):
self
[
key
]
=
func
return
func
return
decorate
class
RenderEngine
(
object
):
"""
Provides a render() method.
This class is meant only for internal use by the Template class.
"""
tag_re
=
None
otag
=
'{{'
ctag
=
'}}'
modifiers
=
Modifiers
()
def
__init__
(
self
,
load_template
=
None
,
literal
=
None
,
escape
=
None
):
"""
Arguments:
escape: a function that takes a unicode or str string,
converts it to unicode, and escapes and returns it.
literal: a function that converts a unicode or str string
to unicode without escaping, and returns it.
"""
self
.
escape
=
escape
self
.
literal
=
literal
self
.
load_template
=
load_template
def
render
(
self
,
template
,
context
):
"""
Arguments:
template: a unicode template string.
context: a Context instance.
"""
self
.
context
=
context
self
.
_compile_regexps
()
return
self
.
_render
(
template
)
def
_compile_regexps
(
self
):
"""
Compile and set the regular expression attributes.
This method uses the current values for the otag and ctag attributes.
"""
tags
=
{
'otag'
:
re
.
escape
(
self
.
otag
),
'ctag'
:
re
.
escape
(
self
.
ctag
)
}
# The section contents include white space to comply with the spec's
# requirement that sections not alter surrounding whitespace.
section
=
r"
%(otag)
s([#|^])([^\}]*)
%(ctag)
s(.+?)
%(otag)
s/\2
%(ctag)
s"
%
tags
self
.
section_re
=
re
.
compile
(
section
,
re
.
M
|
re
.
S
)
tag
=
r"
%(otag)
s(#|=|&|!|>|\{)?(.+?)\1?
%(ctag)
s+"
%
tags
self
.
tag_re
=
re
.
compile
(
tag
)
def
_render_tags
(
self
,
template
):
output
=
[]
while
True
:
parts
=
self
.
tag_re
.
split
(
template
,
maxsplit
=
1
)
output
.
append
(
parts
[
0
])
if
len
(
parts
)
<
2
:
# Then there was no match.
break
start
,
tag_type
,
tag_name
,
template
=
parts
tag_name
=
tag_name
.
strip
()
func
=
self
.
modifiers
[
tag_type
]
tag_value
=
func
(
self
,
tag_name
)
# Appending the tag value to the output prevents treating the
# value as a template string (bug: issue #44).
output
.
append
(
tag_value
)
output
=
""
.
join
(
output
)
return
output
def
_render_dictionary
(
self
,
template
,
context
):
self
.
context
.
push
(
context
)
out
=
self
.
_render
(
template
)
self
.
context
.
pop
()
return
out
def
_render_list
(
self
,
template
,
listing
):
insides
=
[]
for
item
in
listing
:
insides
.
append
(
self
.
_render_dictionary
(
template
,
item
))
return
''
.
join
(
insides
)
@modifiers.set
(
None
)
def
_render_tag
(
self
,
tag_name
):
"""
Return the value of a variable as an escaped unicode string.
"""
raw
=
self
.
context
.
get
(
tag_name
,
''
)
# For methods with no return value
#
# We use "==" rather than "is" to compare integers, as using "is" relies
# on an implementation detail of CPython. The test about rendering
# zeroes failed while using PyPy when using "is".
# See issue #34: https://github.com/defunkt/pystache/issues/34
if
not
raw
and
raw
!=
0
:
if
tag_name
==
'.'
:
raw
=
self
.
context
.
top
()
else
:
return
''
# If we don't first convert to a string type, the call to self._unicode_and_escape()
# will yield an error like the following:
#
# TypeError: coercing to Unicode: need string or buffer, ... found
#
if
not
isinstance
(
raw
,
basestring
):
raw
=
str
(
raw
)
return
self
.
escape
(
raw
)
@modifiers.set
(
'!'
)
def
_render_comment
(
self
,
tag_name
):
return
''
@modifiers.set
(
'>'
)
def
_render_partial
(
self
,
template_name
):
markup
=
self
.
load_template
(
template_name
)
return
self
.
_render
(
markup
)
@modifiers.set
(
'='
)
def
_change_delimiter
(
self
,
tag_name
):
"""
Change the current delimiter.
"""
self
.
otag
,
self
.
ctag
=
tag_name
.
split
(
' '
)
self
.
_compile_regexps
()
return
''
@modifiers.set
(
'{'
)
@modifiers.set
(
'&'
)
def
render_unescaped
(
self
,
tag_name
):
"""
Render a tag without escaping it.
"""
return
self
.
literal
(
self
.
context
.
get
(
tag_name
,
''
))
def
_render
(
self
,
template
):
"""
Arguments:
template: a unicode template string.
"""
output
=
[]
while
True
:
parts
=
self
.
section_re
.
split
(
template
,
maxsplit
=
1
)
start
=
self
.
_render_tags
(
parts
[
0
])
output
.
append
(
start
)
if
len
(
parts
)
<
2
:
# Then there was no match.
break
section_type
,
section_key
,
section_contents
,
template
=
parts
[
1
:]
section_key
=
section_key
.
strip
()
section_value
=
self
.
context
.
get
(
section_key
,
None
)
rendered
=
''
# Callable
if
section_value
and
check_callable
(
section_value
):
rendered
=
section_value
(
section_contents
)
# Dictionary
elif
section_value
and
hasattr
(
section_value
,
'keys'
)
and
hasattr
(
section_value
,
'__getitem__'
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Lists
elif
section_value
and
hasattr
(
section_value
,
'__iter__'
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_list
(
section_contents
,
section_value
)
# Other objects
elif
section_value
and
isinstance
(
section_value
,
object
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Falsey and Negated or Truthy and Not Negated
elif
(
not
section_value
and
section_type
==
'^'
)
or
(
section_value
and
section_type
!=
'^'
):
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Render template prior to section too
output
.
append
(
rendered
)
output
=
""
.
join
(
output
)
return
output
pystache/template.py
View file @
b6018af6
...
...
@@ -6,12 +6,11 @@ This module provides a Template class.
"""
import
cgi
import
collections
import
re
import
sys
from
.context
import
Context
from
.loader
import
Loader
from
.renderengine
import
RenderEngine
markupsafe
=
None
...
...
@@ -21,46 +20,8 @@ except ImportError:
pass
try
:
# The collections.Callable class is not available until Python 2.6.
import
collections.Callable
def
check_callable
(
it
):
return
isinstance
(
it
,
collections
.
Callable
)
except
ImportError
:
def
check_callable
(
it
):
return
hasattr
(
it
,
'__call__'
)
class
Modifiers
(
dict
):
"""Dictionary with a decorator for assigning functions to keys."""
def
set
(
self
,
key
):
"""
Return a decorator that assigns the given function to the given key.
>>> modifiers = {}
>>> @modifiers.set('P')
... def render_tongue(self, tag_name=None, context=None):
... return ":P
%
s"
%
tag_name
>>> modifiers
{'P': <function render_tongue at 0x...>}
"""
def
decorate
(
func
):
self
[
key
]
=
func
return
func
return
decorate
class
Template
(
object
):
tag_re
=
None
otag
=
'{{'
ctag
=
'}}'
modifiers
=
Modifiers
()
def
__init__
(
self
,
template
=
None
,
load_template
=
None
,
output_encoding
=
None
,
escape
=
None
,
default_encoding
=
None
,
decode_errors
=
'strict'
):
"""
...
...
@@ -125,8 +86,6 @@ class Template(object):
self
.
output_encoding
=
output_encoding
self
.
template
=
template
self
.
_compile_regexps
()
def
_unicode_and_escape
(
self
,
s
):
if
not
isinstance
(
s
,
unicode
):
s
=
self
.
unicode
(
s
)
...
...
@@ -159,7 +118,7 @@ class Template(object):
"""
return
self
.
_literal
(
self
.
unicode
(
s
))
def
_
initializ
e_context
(
self
,
context
,
**
kwargs
):
def
_
mak
e_context
(
self
,
context
,
**
kwargs
):
"""
Initialize the context attribute.
...
...
@@ -175,185 +134,17 @@ class Template(object):
if
kwargs
:
context
.
push
(
kwargs
)
self
.
context
=
context
def
_compile_regexps
(
self
):
"""
Compile and set the regular expression attributes.
This method uses the current values for the otag and ctag attributes.
"""
tags
=
{
'otag'
:
re
.
escape
(
self
.
otag
),
'ctag'
:
re
.
escape
(
self
.
ctag
)
}
# The section contents include white space to comply with the spec's
# requirement that sections not alter surrounding whitespace.
section
=
r"
%(otag)
s([#|^])([^\}]*)
%(ctag)
s(.+?)
%(otag)
s/\2
%(ctag)
s"
%
tags
self
.
section_re
=
re
.
compile
(
section
,
re
.
M
|
re
.
S
)
tag
=
r"
%(otag)
s(#|=|&|!|>|\{)?(.+?)\1?
%(ctag)
s+"
%
tags
self
.
tag_re
=
re
.
compile
(
tag
)
def
_render
(
self
,
template
):
"""
Arguments:
template: a unicode template string.
"""
output
=
[]
while
True
:
parts
=
self
.
section_re
.
split
(
template
,
maxsplit
=
1
)
start
=
self
.
_render_tags
(
parts
[
0
])
output
.
append
(
start
)
if
len
(
parts
)
<
2
:
# Then there was no match.
break
section_type
,
section_key
,
section_contents
,
template
=
parts
[
1
:]
section_key
=
section_key
.
strip
()
section_value
=
self
.
context
.
get
(
section_key
,
None
)
rendered
=
''
# Callable
if
section_value
and
check_callable
(
section_value
):
rendered
=
section_value
(
section_contents
)
# Dictionary
elif
section_value
and
hasattr
(
section_value
,
'keys'
)
and
hasattr
(
section_value
,
'__getitem__'
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Lists
elif
section_value
and
hasattr
(
section_value
,
'__iter__'
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_list
(
section_contents
,
section_value
)
# Other objects
elif
section_value
and
isinstance
(
section_value
,
object
):
if
section_type
!=
'^'
:
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Falsey and Negated or Truthy and Not Negated
elif
(
not
section_value
and
section_type
==
'^'
)
or
(
section_value
and
section_type
!=
'^'
):
rendered
=
self
.
_render_dictionary
(
section_contents
,
section_value
)
# Render template prior to section too
output
.
append
(
rendered
)
output
=
""
.
join
(
output
)
return
output
def
_render_tags
(
self
,
template
):
output
=
[]
while
True
:
parts
=
self
.
tag_re
.
split
(
template
,
maxsplit
=
1
)
output
.
append
(
parts
[
0
])
if
len
(
parts
)
<
2
:
# Then there was no match.
break
start
,
tag_type
,
tag_name
,
template
=
parts
tag_name
=
tag_name
.
strip
()
func
=
self
.
modifiers
[
tag_type
]
tag_value
=
func
(
self
,
tag_name
)
# Appending the tag value to the output prevents treating the
# value as a template string (bug: issue #44).
output
.
append
(
tag_value
)
output
=
""
.
join
(
output
)
return
output
def
_render_dictionary
(
self
,
template
,
context
):
self
.
context
.
push
(
context
)
template
=
Template
(
template
,
load_template
=
self
.
load_template
,
escape
=
self
.
escape
,
default_encoding
=
self
.
default_encoding
,
decode_errors
=
self
.
decode_errors
)
out
=
template
.
render
(
self
.
context
)
self
.
context
.
pop
()
return
out
def
_render_list
(
self
,
template
,
listing
):
insides
=
[]
for
item
in
listing
:
insides
.
append
(
self
.
_render_dictionary
(
template
,
item
))
return
''
.
join
(
insides
)
@modifiers.set
(
None
)
def
_render_tag
(
self
,
tag_name
):
"""
Return the value of a variable as an escaped unicode string.
"""
raw
=
self
.
context
.
get
(
tag_name
,
''
)
# For methods with no return value
#
# We use "==" rather than "is" to compare integers, as using "is" relies
# on an implementation detail of CPython. The test about rendering
# zeroes failed while using PyPy when using "is".
# See issue #34: https://github.com/defunkt/pystache/issues/34
if
not
raw
and
raw
!=
0
:
if
tag_name
==
'.'
:
raw
=
self
.
context
.
top
()
else
:
return
''
# If we don't first convert to a string type, the call to self._unicode_and_escape()
# will yield an error like the following:
#
# TypeError: coercing to Unicode: need string or buffer, ... found
#
if
not
isinstance
(
raw
,
basestring
):
raw
=
str
(
raw
)
return
self
.
_unicode_and_escape
(
raw
)
@modifiers.set
(
'!'
)
def
_render_comment
(
self
,
tag_name
):
return
''
@modifiers.set
(
'>'
)
def
_render_partial
(
self
,
template_name
):
markup
=
self
.
load_template
(
template_name
)
template
=
Template
(
markup
,
load_template
=
self
.
load_template
,
escape
=
self
.
escape
,
default_encoding
=
self
.
default_encoding
,
decode_errors
=
self
.
decode_errors
)
return
template
.
render
(
self
.
context
)
@modifiers.set
(
'='
)
def
_change_delimiter
(
self
,
tag_name
):
"""
Change the current delimiter.
"""
self
.
otag
,
self
.
ctag
=
tag_name
.
split
(
' '
)
self
.
_compile_regexps
()
return
''
return
context
@modifiers.set
(
'{'
)
@modifiers.set
(
'&'
)
def
render_unescaped
(
self
,
tag_name
):
def
_make_render_engine
(
self
):
"""
Re
nder a tag without escaping it
.
Re
turn a RenderEngine instance for rendering
.
"""
return
self
.
literal
(
self
.
context
.
get
(
tag_name
,
''
))
engine
=
RenderEngine
(
load_template
=
self
.
load_template
,
literal
=
self
.
literal
,
escape
=
self
.
_unicode_and_escape
)
return
engine
def
render
(
self
,
context
=
None
,
**
kwargs
):
"""
...
...
@@ -375,13 +166,14 @@ class Template(object):
These values take precedence over the context on any key conflicts.
"""
self
.
_initialize_context
(
context
,
**
kwargs
)
engine
=
self
.
_make_render_engine
()
context
=
self
.
_make_context
(
context
,
**
kwargs
)
template
=
self
.
template
if
not
isinstance
(
template
,
unicode
):
template
=
self
.
unicode
(
template
)
result
=
self
.
_render
(
template
)
result
=
engine
.
render
(
template
,
context
)
if
self
.
output_encoding
is
not
None
:
result
=
result
.
encode
(
self
.
output_encoding
)
...
...
tests/test_renderengine.py
0 → 100644
View file @
b6018af6
# coding: utf-8
"""
Unit tests of renderengine.py.
"""
import
cgi
import
unittest
from
pystache.context
import
Context
from
pystache.renderengine
import
RenderEngine
class
RenderEngineTestCase
(
unittest
.
TestCase
):
"""Test the RenderEngine class."""
def
_engine
(
self
):
"""
Create and return a default RenderEngine for testing.
"""
load_template
=
None
to_unicode
=
unicode
escape
=
lambda
s
:
cgi
.
escape
(
to_unicode
(
s
))
literal
=
to_unicode
engine
=
RenderEngine
(
literal
=
literal
,
escape
=
escape
,
load_template
=
None
)
return
engine
def
_assert_render
(
self
,
expected
,
template
,
*
context
,
**
kwargs
):
partials
=
kwargs
.
get
(
'partials'
)
engine
=
kwargs
.
get
(
'engine'
,
self
.
_engine
())
if
partials
is
not
None
:
engine
.
load_template
=
lambda
key
:
partials
[
key
]
context
=
Context
(
*
context
)
actual
=
engine
.
render
(
template
,
context
)
self
.
assertEquals
(
actual
,
expected
)
def
test_init
(
self
):
"""
Test that __init__() stores all of the arguments correctly.
"""
# In real-life, these arguments would be functions
engine
=
RenderEngine
(
load_template
=
"load_template"
,
literal
=
"literal"
,
escape
=
"escape"
)
self
.
assertEquals
(
engine
.
escape
,
"escape"
)
self
.
assertEquals
(
engine
.
literal
,
"literal"
)
self
.
assertEquals
(
engine
.
load_template
,
"load_template"
)
def
test_render
(
self
):
self
.
_assert_render
(
'Hi Mom'
,
'Hi {{person}}'
,
{
'person'
:
'Mom'
})
def
test_render__load_template
(
self
):
"""
Test that render() uses the load_template attribute.
"""
engine
=
self
.
_engine
()
partials
=
{
'partial'
:
"{{person}}"
}
engine
.
load_template
=
lambda
key
:
partials
[
key
]
self
.
_assert_render
(
'Hi Mom'
,
'Hi {{>partial}}'
,
{
'person'
:
'Mom'
},
engine
=
engine
)
def
test_render__literal
(
self
):
"""
Test that render() uses the literal attribute.
"""
engine
=
self
.
_engine
()
engine
.
literal
=
lambda
s
:
s
.
upper
()
self
.
_assert_render
(
'bar BAR'
,
'{{foo}} {{{foo}}}'
,
{
'foo'
:
'bar'
},
engine
=
engine
)
def
test_render__escape
(
self
):
"""
Test that render() uses the escape attribute.
"""
engine
=
self
.
_engine
()
engine
.
escape
=
lambda
s
:
"**"
+
s
self
.
_assert_render
(
'**bar bar'
,
'{{foo}} {{{foo}}}'
,
{
'foo'
:
'bar'
},
engine
=
engine
)
def
test_render_with_partial
(
self
):
partials
=
{
'partial'
:
"{{person}}"
}
self
.
_assert_render
(
'Hi Mom'
,
'Hi {{>partial}}'
,
{
'person'
:
'Mom'
},
partials
=
partials
)
def
test_render__section_context_values
(
self
):
"""
Test that escape and literal work on context values in sections.
"""
engine
=
self
.
_engine
()
engine
.
escape
=
lambda
s
:
"**"
+
s
engine
.
literal
=
lambda
s
:
s
.
upper
()
template
=
'{{#test}}{{foo}} {{{foo}}}{{/test}}'
context
=
{
'test'
:
{
'foo'
:
'bar'
}}
self
.
_assert_render
(
'**bar BAR'
,
template
,
context
,
engine
=
engine
)
def
test_render__partial_context_values
(
self
):
"""
Test that escape and literal work on context values in partials.
"""
engine
=
self
.
_engine
()
engine
.
escape
=
lambda
s
:
"**"
+
s
engine
.
literal
=
lambda
s
:
s
.
upper
()
partials
=
{
'partial'
:
'{{foo}} {{{foo}}}'
}
self
.
_assert_render
(
'**bar BAR'
,
'{{>partial}}'
,
{
'foo'
:
'bar'
},
engine
=
engine
,
partials
=
partials
)
def
test_render__list_referencing_outer_context
(
self
):
"""
Check that list items can access the parent context.
For sections whose value is a list, check that items in the list
have access to the values inherited from the parent context
when rendering.
"""
context
=
{
"list"
:
[{
"name"
:
"Al"
},
{
"name"
:
"Bo"
}],
"greeting"
:
"Hi"
,
}
template
=
"{{#list}}{{name}}: {{greeting}}; {{/list}}"
self
.
_assert_render
(
"Al: Hi; Bo: Hi; "
,
template
,
context
)
def
test_render__tag_in_value
(
self
):
"""
Context values should not be treated as templates (issue #44).
"""
template
=
'{{test}}'
context
=
{
'test'
:
'{{hello}}'
}
self
.
_assert_render
(
'{{hello}}'
,
template
,
context
)
def
test_render__section_in_value
(
self
):
"""
Context values should not be treated as templates (issue #44).
"""
template
=
'{{test}}'
context
=
{
'test'
:
'{{#hello}}'
}
self
.
_assert_render
(
'{{#hello}}'
,
template
,
context
)
def
test_render__section__lambda
(
self
):
template
=
'{{#test}}Mom{{/test}}'
context
=
{
'test'
:
(
lambda
text
:
'Hi
%
s'
%
text
)}
self
.
_assert_render
(
'Hi Mom'
,
template
,
context
)
def
test_render__section__lambda__tag_in_output
(
self
):
"""
Check that callable output isn't treated as a template string (issue #46).
"""
template
=
'{{#test}}Mom{{/test}}'
context
=
{
'test'
:
(
lambda
text
:
'{{hi}}
%
s'
%
text
)}
self
.
_assert_render
(
'{{hi}} Mom'
,
template
,
context
)
tests/test_template.py
View file @
b6018af6
...
...
@@ -38,6 +38,19 @@ class TemplateTestCase(unittest.TestCase):
"""
template
.
markupsafe
=
self
.
original_markupsafe
def
test__was_markupsafe_imported
(
self
):
"""
Test that our helper function works.
"""
markupsafe
=
None
try
:
import
markupsafe
except
:
pass
self
.
assertEquals
(
bool
(
markupsafe
),
self
.
_was_markupsafe_imported
())
def
test_init__escape__default_without_markupsafe
(
self
):
template
=
Template
()
self
.
assertEquals
(
template
.
escape
(
">'"
),
">'"
)
...
...
@@ -207,138 +220,60 @@ class TemplateTestCase(unittest.TestCase):
self
.
assertTrue
(
isinstance
(
actual
,
str
))
self
.
assertEquals
(
actual
,
'Poincaré'
)
def
test_render__tag_in_value
(
self
):
"""
Context values should not be treated as templates (issue #44).
def
test_render__nonascii_template
(
self
):
"""
template
=
Template
(
'{{test}}'
)
context
=
{
'test'
:
'{{hello}}'
}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'{{hello}}'
)
Test passing a non-unicode template with non-ascii characters.
def
test_render__section_in_value
(
self
):
"""
Context values should not be treated as templates (issue #44).
template
=
Template
(
"déf"
,
output_encoding
=
"utf-8"
)
"""
template
=
Template
(
'{{test}}'
)
context
=
{
'test'
:
'{{#hello}}'
}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'{{#hello}}'
)
# Check that decode_errors and default_encoding are both respected.
template
.
decode_errors
=
'ignore'
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(),
"df"
)
def
test_render__section__lambda
(
self
):
template
=
Template
(
'{{#test}}Mom{{/test}}'
)
context
=
{
'test'
:
(
lambda
text
:
'Hi
%
s'
%
text
)}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'Hi Mom'
)
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
template
.
render
(),
"déf"
)
def
test_render__section__lambda__tag_in_output
(
self
):
# By testing that Template.render() constructs the RenderEngine instance
# correctly, we no longer need to test the rendering code paths through
# the Template. We can test rendering paths through only the RenderEngine
# for the same amount of code coverage.
def
test_make_render_engine__load_template
(
self
):
"""
Check that callable output isn't treated as a template string (issue #46)
.
Test that _make_render_engine() passes the right load_template
.
"""
template
=
Template
(
'{{#test}}Mom{{/test}}'
)
context
=
{
'test'
:
(
lambda
text
:
'{{hi}}
%
s'
%
text
)}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'{{hi}} Mom'
)
def
test_render__html_escape
(
self
):
context
=
{
'test'
:
'1 < 2'
}
template
=
Template
(
'{{test}}'
)
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
def
test_render__html_escape_disabled
(
self
):
context
=
{
'test'
:
'1 < 2'
}
template
=
Template
(
'{{test}}'
)
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
template
.
escape
=
lambda
s
:
s
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
def
test_render__html_escape_disabled_with_partial
(
self
):
context
=
{
'test'
:
'1 < 2'
}
load_template
=
lambda
name
:
'{{test}}'
template
=
Template
(
'{{>partial}}'
,
load_template
=
load_template
)
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
template
.
escape
=
lambda
s
:
s
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
def
test_render__html_escape_disabled_with_non_false_value
(
self
):
context
=
{
'section'
:
{
'test'
:
'1 < 2'
}}
template
=
Template
(
'{{#section}}{{test}}{{/section}}'
)
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
template
=
Template
()
template
.
load_template
=
"foo"
# in real life, this would be a function.
template
.
escape
=
lambda
s
:
s
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
engine
=
template
.
_make_render_engine
()
self
.
assertEquals
(
engine
.
load_template
,
"foo"
)
def
test_
render__list_referencing_outer_context
(
self
):
def
test_
make_render_engine__literal
(
self
):
"""
Check that list items can access the parent context.
For sections whose value is a list, check that items in the list
have access to the values inherited from the parent context
when rendering.
Test that _make_render_engine() passes the right literal.
"""
context
=
{
"list"
:
[{
"name"
:
"Al"
},
{
"name"
:
"Bo"
}],
"greeting"
:
"Hi"
,
}
template
=
Template
(
"{{#list}}{{name}}: {{greeting}}; {{/list}}"
)
self
.
assertEquals
(
template
.
render
(
context
),
"Al: Hi; Bo: Hi; "
)
def
test_render__encoding_in_context_value
(
self
):
template
=
Template
(
'{{test}}'
)
context
=
{
'test'
:
"déf"
}
template
.
decode_errors
=
'ignore'
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(
context
),
"df"
)
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
template
.
render
(
context
),
u"déf"
)
def
test_render__encoding_in_section_context_value
(
self
):
template
=
Template
(
'{{#test}}{{foo}}{{/test}}'
)
context
=
{
'test'
:
{
'foo'
:
"déf"
}}
template
.
decode_errors
=
'ignore'
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(
context
),
"df"
)
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
template
.
render
(
context
),
u"déf"
)
def
test_render__encoding_in_partial_context_value
(
self
):
load_template
=
lambda
x
:
"{{foo}}"
template
=
Template
(
'{{>partial}}'
,
load_template
=
load_template
)
context
=
{
'foo'
:
"déf"
}
template
.
decode_errors
=
'ignore'
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(
context
),
"df"
)
template
=
Template
()
template
.
literal
=
"foo"
# in real life, this would be a function.
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
template
.
render
(
context
),
u"déf
"
)
engine
=
template
.
_make_render_engine
()
self
.
assertEquals
(
engine
.
literal
,
"foo
"
)
def
test_
render__nonascii_templat
e
(
self
):
def
test_
make_render_engine__escap
e
(
self
):
"""
Test
passing a non-unicode template with non-ascii characters
.
Test
that _make_render_engine() passes the right escape
.
"""
template
=
Template
(
"déf"
,
output_encoding
=
"utf-8"
)
template
=
Template
()
template
.
unicode
=
lambda
s
:
s
.
upper
()
# a test version.
template
.
escape
=
lambda
s
:
"**"
+
s
# a test version.
# Check that decode_errors and default_encoding are both respected.
template
.
decode_errors
=
'ignore'
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(),
"df"
)
engine
=
template
.
_make_render_engine
()
escape
=
engine
.
escape
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
template
.
render
(),
"déf"
)
self
.
assertEquals
(
escape
(
u"foo"
),
"**foo"
)
# Test that escape converts str strings to unicode first.
self
.
assertEquals
(
escape
(
"foo"
),
"**FOO"
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment