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.
...
@@ -6,12 +6,11 @@ This module provides a Template class.
"""
"""
import
cgi
import
cgi
import
collections
import
re
import
sys
import
sys
from
.context
import
Context
from
.context
import
Context
from
.loader
import
Loader
from
.loader
import
Loader
from
.renderengine
import
RenderEngine
markupsafe
=
None
markupsafe
=
None
...
@@ -21,46 +20,8 @@ except ImportError:
...
@@ -21,46 +20,8 @@ except ImportError:
pass
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
):
class
Template
(
object
):
tag_re
=
None
otag
=
'{{'
ctag
=
'}}'
modifiers
=
Modifiers
()
def
__init__
(
self
,
template
=
None
,
load_template
=
None
,
output_encoding
=
None
,
escape
=
None
,
def
__init__
(
self
,
template
=
None
,
load_template
=
None
,
output_encoding
=
None
,
escape
=
None
,
default_encoding
=
None
,
decode_errors
=
'strict'
):
default_encoding
=
None
,
decode_errors
=
'strict'
):
"""
"""
...
@@ -125,8 +86,6 @@ class Template(object):
...
@@ -125,8 +86,6 @@ class Template(object):
self
.
output_encoding
=
output_encoding
self
.
output_encoding
=
output_encoding
self
.
template
=
template
self
.
template
=
template
self
.
_compile_regexps
()
def
_unicode_and_escape
(
self
,
s
):
def
_unicode_and_escape
(
self
,
s
):
if
not
isinstance
(
s
,
unicode
):
if
not
isinstance
(
s
,
unicode
):
s
=
self
.
unicode
(
s
)
s
=
self
.
unicode
(
s
)
...
@@ -159,7 +118,7 @@ class Template(object):
...
@@ -159,7 +118,7 @@ class Template(object):
"""
"""
return
self
.
_literal
(
self
.
unicode
(
s
))
return
self
.
_literal
(
self
.
unicode
(
s
))
def
_
initializ
e_context
(
self
,
context
,
**
kwargs
):
def
_
mak
e_context
(
self
,
context
,
**
kwargs
):
"""
"""
Initialize the context attribute.
Initialize the context attribute.
...
@@ -175,185 +134,17 @@ class Template(object):
...
@@ -175,185 +134,17 @@ class Template(object):
if
kwargs
:
if
kwargs
:
context
.
push
(
kwargs
)
context
.
push
(
kwargs
)
self
.
context
=
context
return
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
''
@modifiers.set
(
'{'
)
def
_make_render_engine
(
self
):
@modifiers.set
(
'&'
)
def
render_unescaped
(
self
,
tag_name
):
"""
"""
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
):
def
render
(
self
,
context
=
None
,
**
kwargs
):
"""
"""
...
@@ -375,13 +166,14 @@ class Template(object):
...
@@ -375,13 +166,14 @@ class Template(object):
These values take precedence over the context on any key conflicts.
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
template
=
self
.
template
if
not
isinstance
(
template
,
unicode
):
if
not
isinstance
(
template
,
unicode
):
template
=
self
.
unicode
(
template
)
template
=
self
.
unicode
(
template
)
result
=
self
.
_render
(
template
)
result
=
engine
.
render
(
template
,
context
)
if
self
.
output_encoding
is
not
None
:
if
self
.
output_encoding
is
not
None
:
result
=
result
.
encode
(
self
.
output_encoding
)
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):
...
@@ -38,6 +38,19 @@ class TemplateTestCase(unittest.TestCase):
"""
"""
template
.
markupsafe
=
self
.
original_markupsafe
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
):
def
test_init__escape__default_without_markupsafe
(
self
):
template
=
Template
()
template
=
Template
()
self
.
assertEquals
(
template
.
escape
(
">'"
),
">'"
)
self
.
assertEquals
(
template
.
escape
(
">'"
),
">'"
)
...
@@ -207,138 +220,60 @@ class TemplateTestCase(unittest.TestCase):
...
@@ -207,138 +220,60 @@ class TemplateTestCase(unittest.TestCase):
self
.
assertTrue
(
isinstance
(
actual
,
str
))
self
.
assertTrue
(
isinstance
(
actual
,
str
))
self
.
assertEquals
(
actual
,
'Poincaré'
)
self
.
assertEquals
(
actual
,
'Poincaré'
)
def
test_render__tag_in_value
(
self
):
def
test_render__nonascii_template
(
self
):
"""
Context values should not be treated as templates (issue #44).
"""
"""
template
=
Template
(
'{{test}}'
)
Test passing a non-unicode template with non-ascii characters.
context
=
{
'test'
:
'{{hello}}'
}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'{{hello}}'
)
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"
)
"""
# Check that decode_errors and default_encoding are both respected.
template
=
Template
(
'{{test}}'
)
template
.
decode_errors
=
'ignore'
context
=
{
'test'
:
'{{#hello}}'
}
template
.
default_encoding
=
'ascii'
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
template
.
render
(),
"df"
)
self
.
assertEquals
(
actual
,
'{{#hello}}'
)
def
test_render__section__lambda
(
self
):
template
.
default_encoding
=
'utf_8'
template
=
Template
(
'{{#test}}Mom{{/test}}'
)
self
.
assertEquals
(
template
.
render
(),
"déf"
)
context
=
{
'test'
:
(
lambda
text
:
'Hi
%
s'
%
text
)}
actual
=
template
.
render
(
context
)
self
.
assertEquals
(
actual
,
'Hi Mom'
)
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}}'
)
template
=
Template
()
context
=
{
'test'
:
(
lambda
text
:
'{{hi}}
%
s'
%
text
)}
template
.
load_template
=
"foo"
# in real life, this would be a function.
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
.
escape
=
lambda
s
:
s
engine
=
template
.
_make_render_engine
()
self
.
assertEquals
(
template
.
render
(
context
),
'1 < 2'
)
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.
Test that _make_render_engine() passes the right literal.
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
=
{
template
=
Template
()
"list"
:
[{
"name"
:
"Al"
},
{
"name"
:
"Bo"
}],
template
.
literal
=
"foo"
# in real life, this would be a function.
"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
.
default_encoding
=
'utf_8'
engine
=
template
.
_make_render_engine
()
self
.
assertEquals
(
template
.
render
(
context
),
u"déf
"
)
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.
engine
=
template
.
_make_render_engine
()
template
.
decode_errors
=
'ignore'
escape
=
engine
.
escape
template
.
default_encoding
=
'ascii'
self
.
assertEquals
(
template
.
render
(),
"df"
)
template
.
default_encoding
=
'utf_8'
self
.
assertEquals
(
escape
(
u"foo"
),
"**foo"
)
self
.
assertEquals
(
template
.
render
(),
"déf"
)
# 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