Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Xavier Thompson
cython
Commits
3f8fefb0
Commit
3f8fefb0
authored
Jul 22, 2011
by
Mark Florisson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Tempita support
parent
2cd11fd8
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1479 additions
and
54 deletions
+1479
-54
Cython/Compiler/Code.py
Cython/Compiler/Code.py
+42
-17
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+11
-7
Cython/Compiler/MemoryView.py
Cython/Compiler/MemoryView.py
+18
-16
Cython/Tempita/__init__.py
Cython/Tempita/__init__.py
+1183
-0
Cython/Tempita/_looper.py
Cython/Tempita/_looper.py
+163
-0
Cython/Tempita/compat3.py
Cython/Tempita/compat3.py
+45
-0
Cython/Utility/MemoryView_C.c
Cython/Utility/MemoryView_C.c
+12
-13
setup.py
setup.py
+1
-0
tests/run/memslice_indexing.pyx
tests/run/memslice_indexing.pyx
+4
-1
No files found.
Cython/Compiler/Code.py
View file @
3f8fefb0
...
@@ -12,6 +12,7 @@ import os
...
@@ -12,6 +12,7 @@ import os
import
re
import
re
import
codecs
import
codecs
import
glob
import
Naming
import
Naming
import
Options
import
Options
import
StringEncoding
import
StringEncoding
...
@@ -20,6 +21,7 @@ from Scanning import SourceDescriptor
...
@@ -20,6 +21,7 @@ from Scanning import SourceDescriptor
from
Cython.StringIOTree
import
StringIOTree
from
Cython.StringIOTree
import
StringIOTree
import
DebugFlags
import
DebugFlags
import
Errors
import
Errors
from
Cython
import
Tempita
as
tempita
from
Cython.Utils
import
none_or_sub
from
Cython.Utils
import
none_or_sub
try
:
try
:
...
@@ -42,6 +44,9 @@ uncachable_builtins = [
...
@@ -42,6 +44,9 @@ uncachable_builtins = [
'WindowsError'
,
'WindowsError'
,
]
]
Cython_dir
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
)))
Utility_dir
=
os
.
path
.
join
(
Cython_dir
,
"Utility"
)
class
UtilityCodeBase
(
object
):
class
UtilityCodeBase
(
object
):
is_cython_utility
=
False
is_cython_utility
=
False
...
@@ -69,8 +74,7 @@ class UtilityCodeBase(object):
...
@@ -69,8 +74,7 @@ class UtilityCodeBase(object):
if
utilities
:
if
utilities
:
return
utilities
return
utilities
Cython_dir
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
abspath
(
__file__
)))
filename
=
os
.
path
.
join
(
Utility_dir
,
path
)
filename
=
os
.
path
.
join
(
Cython_dir
,
"Utility"
,
path
)
f
=
codecs
.
open
(
filename
,
encoding
=
'UTF-8'
)
f
=
codecs
.
open
(
filename
,
encoding
=
'UTF-8'
)
_
,
ext
=
os
.
path
.
splitext
(
path
)
_
,
ext
=
os
.
path
.
splitext
(
path
)
...
@@ -111,8 +115,8 @@ class UtilityCodeBase(object):
...
@@ -111,8 +115,8 @@ class UtilityCodeBase(object):
return
utilities
return
utilities
@
classmethod
@
classmethod
def
load_utility_from_file
(
cls
,
path
,
util_code_name
,
proto_fmt_dict
=
None
,
def
load_utility_from_file
(
cls
,
path
,
util_code_name
,
impl_fmt_dict
=
None
,
*
args
,
**
kwargs
):
context
=
None
,
**
kwargs
):
"""
"""
Load a utility code from a file specified by path (relative to
Load a utility code from a file specified by path (relative to
Cython/Utility) and name util_code_name.
Cython/Utility) and name util_code_name.
...
@@ -125,37 +129,52 @@ class UtilityCodeBase(object):
...
@@ -125,37 +129,52 @@ class UtilityCodeBase(object):
for prototypes and implementation respectively. For non-python or
for prototypes and implementation respectively. For non-python or
-cython files a // comment should be used instead.
-cython files a // comment should be used instead.
proto_fmt_dict and impl_format_dict can optionally be given to perform
If context is given, the utility is considered a tempita template.
any substitutions.
The context dict (which may be empty) will be unpacked to form
all the variables in the template.
If the @cname decorator is not used and this is a CythonUtilityCode,
If the @cname decorator is not used and this is a CythonUtilityCode,
one should pass in the 'name' keyword argument to be used for name
one should pass in the 'name' keyword argument to be used for name
mangling of such entries.
mangling of such entries.
"""
"""
proto
,
impl
=
cls
.
load_utility_as_string
(
path
,
util_code_name
)
proto
,
impl
=
cls
.
load_utility_as_string
(
path
,
util_code_name
,
context
)
if
proto
:
if
proto
is
not
None
:
if
proto_fmt_dict
:
proto
=
proto
%
proto_fmt_dict
kwargs
[
'proto'
]
=
proto
kwargs
[
'proto'
]
=
proto
if
impl
is
not
None
:
if
impl
:
if
impl_fmt_dict
:
impl
=
impl
%
impl_fmt_dict
kwargs
[
'impl'
]
=
impl
kwargs
[
'impl'
]
=
impl
if
'name'
not
in
kwargs
:
if
'name'
not
in
kwargs
:
kwargs
[
'name'
]
=
os
.
path
.
splitext
(
path
)[
0
]
kwargs
[
'name'
]
=
os
.
path
.
splitext
(
path
)[
0
]
return
cls
(
*
args
,
*
*
kwargs
)
return
cls
(
**
kwargs
)
@
classmethod
@
classmethod
def
load_utility_as_string
(
cls
,
path
,
util_code_name
):
def
load_utility_as_string
(
cls
,
path
,
util_code_name
,
context
=
None
):
"""
"""
Load a utility code as a string. Returns (proto, implementation)
Load a utility code as a string. Returns (proto, implementation)
"""
"""
utilities
=
cls
.
load_utilities_from_file
(
path
)
utilities
=
cls
.
load_utilities_from_file
(
path
)
return
utilities
[
util_code_name
]
proto
,
impl
=
utilities
[
util_code_name
]
if
proto
:
if
context
is
not
None
:
proto
=
tempita
.
sub
(
proto
,
**
context
)
if
impl
:
if
context
is
not
None
:
impl
=
tempita
.
sub
(
impl
,
**
context
)
return
proto
,
impl
@
classmethod
def
load_utility
(
cls
,
name
,
context
=
None
,
**
kwargs
):
"Load utility name with context from a utility file name.suffix"
files
=
glob
.
glob
(
os
.
path
.
join
(
Utility_dir
,
name
+
'.*'
))
if
len
(
files
)
!=
1
:
raise
ValueError
(
"Need exactly one utility file"
)
return
cls
.
load_utilities_from_file
(
files
[
0
],
name
,
context
,
**
kwargs
)
def
__str__
(
self
):
def
__str__
(
self
):
return
"<%s(%s)"
%
(
type
(
self
).
__name__
,
self
.
name
)
return
"<%s(%s)"
%
(
type
(
self
).
__name__
,
self
.
name
)
...
@@ -1275,6 +1294,12 @@ class CCodeWriter(object):
...
@@ -1275,6 +1294,12 @@ class CCodeWriter(object):
elif
fix_indent
:
elif
fix_indent
:
self
.
level
+=
1
self
.
level
+=
1
def
putln_tempita
(
self
,
code
,
**
context
):
self
.
putln
(
tempita
.
sub
(
code
,
**
context
))
def
put_tempita
(
self
,
code
,
**
context
):
self
.
put
(
tempita
.
sub
(
code
,
**
context
))
def
increase_indent
(
self
):
def
increase_indent
(
self
):
self
.
level
=
self
.
level
+
1
self
.
level
=
self
.
level
+
1
...
...
Cython/Compiler/ExprNodes.py
View file @
3f8fefb0
...
@@ -2345,8 +2345,12 @@ class IndexNode(ExprNode):
...
@@ -2345,8 +2345,12 @@ class IndexNode(ExprNode):
skip_child_analysis
=
False
skip_child_analysis
=
False
buffer_access
=
False
buffer_access
=
False
# memoryviewslice_access = False
memoryviewslice_access
=
False
if
self
.
base
.
type
.
is_buffer
or
self
.
base
.
type
.
is_memoryviewslice
:
if
(
self
.
base
.
type
.
is_memoryviewslice
and
not
self
.
indices
and
isinstance
(
self
.
index
,
EllipsisNode
)):
memoryviewslice_access
=
True
elif
self
.
base
.
type
.
is_buffer
or
self
.
base
.
type
.
is_memoryviewslice
:
if
self
.
indices
:
if
self
.
indices
:
indices
=
self
.
indices
indices
=
self
.
indices
else
:
else
:
...
@@ -2390,11 +2394,11 @@ class IndexNode(ExprNode):
...
@@ -2390,11 +2394,11 @@ class IndexNode(ExprNode):
if
self
.
type
.
is_buffer
:
if
self
.
type
.
is_buffer
:
self
.
base
.
entry
.
buffer_aux
.
writable_needed
=
True
self
.
base
.
entry
.
buffer_aux
.
writable_needed
=
True
#
elif memoryviewslice_access:
elif
memoryviewslice_access
:
#
self.type = self.base.type
self
.
type
=
self
.
base
.
type
#
self.is_memoryviewslice_access = True
self
.
is_memoryviewslice_access
=
True
#
if getting:
if
getting
:
#
error(self.pos, "memoryviews currently support setting only.")
error
(
self
.
pos
,
"memoryviews currently support setting only."
)
else
:
else
:
base_type
=
self
.
base
.
type
base_type
=
self
.
base
.
type
...
...
Cython/Compiler/MemoryView.py
View file @
3f8fefb0
...
@@ -112,7 +112,7 @@ def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, pos, code
...
@@ -112,7 +112,7 @@ def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, pos, code
for
i
in
range
(
ndim
):
for
i
in
range
(
ndim
):
code
.
putln
(
"%s.shape[%d] = %s.shape[%d];"
%
(
lhs_cname
,
i
,
rhs_cname
,
i
))
code
.
putln
(
"%s.shape[%d] = %s.shape[%d];"
%
(
lhs_cname
,
i
,
rhs_cname
,
i
))
code
.
putln
(
"%s.strides[%d] = %s.strides[%d];"
%
(
lhs_cname
,
i
,
rhs_cname
,
i
))
code
.
putln
(
"%s.strides[%d] = %s.strides[%d];"
%
(
lhs_cname
,
i
,
rhs_cname
,
i
))
#
code.putln("%s.suboffsets[%d] = %s.suboffsets[%d];" % (lhs_cname, i, rhs_cname, i))
code
.
putln
(
"%s.suboffsets[%d] = %s.suboffsets[%d];"
%
(
lhs_cname
,
i
,
rhs_cname
,
i
))
def
get_buf_flag
(
specs
):
def
get_buf_flag
(
specs
):
is_c_contig
,
is_f_contig
=
is_cf_contig
(
specs
)
is_c_contig
,
is_f_contig
=
is_cf_contig
(
specs
)
...
@@ -186,7 +186,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
...
@@ -186,7 +186,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
self
.
buf_ptr_type
=
dtype
self
.
buf_ptr_type
=
dtype
def
get_buf_suboffsetvars
(
self
):
def
get_buf_suboffsetvars
(
self
):
return
self
.
_for_all_ndim
(
"%s.
memview->view.
suboffsets[%d]"
)
return
self
.
_for_all_ndim
(
"%s.suboffsets[%d]"
)
def
get_buf_stridevars
(
self
):
def
get_buf_stridevars
(
self
):
return
self
.
_for_all_ndim
(
"%s.strides[%d]"
)
return
self
.
_for_all_ndim
(
"%s.strides[%d]"
)
...
@@ -267,7 +267,7 @@ static int %s(const __Pyx_memviewslice mvs) {
...
@@ -267,7 +267,7 @@ static int %s(const __Pyx_memviewslice mvs) {
%(for_loop)s {
%(for_loop)s {
#ifdef DEBUG
#ifdef DEBUG
/* printf("mvs.suboffsets[i] %%d
\
\
n", mvs.suboffsets[i]); */
printf("mvs.suboffsets[i] %%d
\
\
n", mvs.suboffsets[i]);
printf("mvs.strides[i] %%d
\
\
n", mvs.strides[i]);
printf("mvs.strides[i] %%d
\
\
n", mvs.strides[i]);
printf("mvs.shape[i] %%d
\
\
n", mvs.shape[i]);
printf("mvs.shape[i] %%d
\
\
n", mvs.shape[i]);
printf("size %%d
\
\
n", size);
printf("size %%d
\
\
n", size);
...
@@ -275,7 +275,7 @@ static int %s(const __Pyx_memviewslice mvs) {
...
@@ -275,7 +275,7 @@ static int %s(const __Pyx_memviewslice mvs) {
#endif
#endif
#undef DEBUG
#undef DEBUG
if(mvs.
memview->view.
suboffsets[i] >= 0) {
if(mvs.suboffsets[i] >= 0) {
return 0;
return 0;
}
}
if(size * itemsize != mvs.strides[i]) {
if(size * itemsize != mvs.strides[i]) {
...
@@ -374,13 +374,17 @@ class CopyFuncUtilCode(object):
...
@@ -374,13 +374,17 @@ class CopyFuncUtilCode(object):
mode
=
'fortran'
mode
=
'fortran'
contig_flag
=
"PyBUF_F_CONTIGUOUS"
contig_flag
=
"PyBUF_F_CONTIGUOUS"
code
.
put
(
copy_template
%
context
=
dict
(
dict
(
copy_name
=
self
.
copy_func_name
,
copy_name
=
self
.
copy_func_name
,
mode
=
mode
,
mode
=
mode
,
sizeof_dtype
=
"sizeof(%s)"
%
self
.
from_memview
.
dtype
.
declaration_code
(
''
),
sizeof_dtype
=
"sizeof(%s)"
%
self
.
from_memview
.
dtype
.
declaration_code
(
''
),
contig_flag
=
contig_flag
,
contig_flag
=
contig_flag
,
copy_contents_name
=
copy_contents_name
))
copy_contents_name
=
copy_contents_name
)
_
,
copy_code
=
UtilityCode
.
load_utility_as_string
(
"MemoryView_C.c"
,
"MemviewSliceCopyTemplate"
,
context
)
code
.
put
(
copy_code
)
def
get_copy_contents_func
(
from_mvs
,
to_mvs
,
cfunc_name
):
def
get_copy_contents_func
(
from_mvs
,
to_mvs
,
cfunc_name
):
...
@@ -744,10 +748,8 @@ def load_memview_c_utility(name, *args, **kwargs):
...
@@ -744,10 +748,8 @@ def load_memview_c_utility(name, *args, **kwargs):
def
load_memview_c_string
(
name
):
def
load_memview_c_string
(
name
):
return
UtilityCode
.
load_utility_as_string
(
"MemoryView_C.c"
,
name
)
return
UtilityCode
.
load_utility_as_string
(
"MemoryView_C.c"
,
name
)
_
,
copy_template
=
UtilityCode
.
load_utility_as_string
(
"MemoryView_C.c"
,
"MemviewSliceCopyTemplate"
)
fmt_dic
t
=
{
contex
t
=
{
'memview_struct_name'
:
memview_objstruct_cname
,
'memview_struct_name'
:
memview_objstruct_cname
,
'max_dims'
:
Options
.
buffer_max_dims
,
'max_dims'
:
Options
.
buffer_max_dims
,
'memviewslice_name'
:
memviewslice_cname
,
'memviewslice_name'
:
memviewslice_cname
,
...
@@ -755,10 +757,10 @@ fmt_dict = {
...
@@ -755,10 +757,10 @@ fmt_dict = {
memviewslice_declare_code
=
load_memview_c_utility
(
memviewslice_declare_code
=
load_memview_c_utility
(
name
=
"MemviewSliceStruct"
,
name
=
"MemviewSliceStruct"
,
proto_block
=
'utility_code_proto_before_types'
,
proto_block
=
'utility_code_proto_before_types'
,
proto_fmt_dict
=
fmt_dic
t
)
context
=
contex
t
)
memviewslice_init_code
=
load_memview_c_utility
(
memviewslice_init_code
=
load_memview_c_utility
(
name
=
"MemviewSliceInit"
,
name
=
"MemviewSliceInit"
,
proto_fmt_dic
t
=
{
'BUF_MAX_NDIMS'
:
Options
.
buffer_max_dims
},
contex
t
=
{
'BUF_MAX_NDIMS'
:
Options
.
buffer_max_dims
},
requires
=
[
memviewslice_declare_code
],
requires
=
[
memviewslice_declare_code
],
)
)
Cython/Tempita/__init__.py
0 → 100644
View file @
3f8fefb0
"""
A small templating language
This implements a small templating language. This language implements
if/elif/else, for/continue/break, expressions, and blocks of Python
code. The syntax is::
{{any expression (function calls etc)}}
{{any expression | filter}}
{{for x in y}}...{{endfor}}
{{if x}}x{{elif y}}y{{else}}z{{endif}}
{{py:x=1}}
{{py:
def foo(bar):
return 'baz'
}}
{{default var = default_value}}
{{# comment}}
You use this with the ``Template`` class or the ``sub`` shortcut.
The ``Template`` class takes the template string and the name of
the template (for errors) and a default namespace. Then (like
``string.Template``) you can call the ``tmpl.substitute(**kw)``
method to make a substitution (or ``tmpl.substitute(a_dict)``).
``sub(content, **kw)`` substitutes the template immediately. You
can use ``__name='tmpl.html'`` to set the name of the template.
If there are syntax errors ``TemplateError`` will be raised.
"""
import
re
import
sys
import
cgi
from
urllib
import
quote
as
url_quote
import
os
import
tokenize
from
cStringIO
import
StringIO
from
Cython.Tempita._looper
import
looper
from
Cython.Tempita.compat3
import
bytes
,
basestring_
,
next
,
is_unicode
,
coerce_text
__all__
=
[
'TemplateError'
,
'Template'
,
'sub'
,
'HTMLTemplate'
,
'sub_html'
,
'html'
,
'bunch'
]
in_re
=
re
.
compile
(
r'\
s+i
n\
s+
')
var_re = re.compile(r'
^
[
a
-
z_
][
a
-
z0
-
9
_
]
*
$
', re.I)
class TemplateError(Exception):
"""Exception raised while parsing a template
"""
def __init__(self, message, position, name=None):
Exception.__init__(self, message)
self.position = position
self.name = name
def __str__(self):
msg = '
'.join(self.args)
if self.position:
msg = '
%
s
at
line
%
s
column
%
s
' % (
msg, self.position[0], self.position[1])
if self.name:
msg += '
in
%
s
' % self.name
return msg
class _TemplateContinue(Exception):
pass
class _TemplateBreak(Exception):
pass
def get_file_template(name, from_template):
path = os.path.join(os.path.dirname(from_template.name), name)
return from_template.__class__.from_filename(
path, namespace=from_template.namespace,
get_template=from_template.get_template)
class Template(object):
default_namespace = {
'
start_braces
': '
{{
',
'
end_braces
': '
}}
',
'
looper
': looper,
}
default_encoding = '
utf8
'
default_inherit = None
def __init__(self, content, name=None, namespace=None, stacklevel=None,
get_template=None, default_inherit=None, line_offset=0,
delimeters=None):
self.content = content
# set delimeters
if delimeters is None:
delimeters = (self.default_namespace['
start_braces
'],
self.default_namespace['
end_braces
'])
else:
assert len(delimeters) == 2 and all([isinstance(delimeter, basestring)
for delimeter in delimeters])
self.default_namespace = self.__class__.default_namespace.copy()
self.default_namespace['
start_braces
'] = delimeters[0]
self.default_namespace['
end_braces
'] = delimeters[1]
self.delimeters = delimeters
self._unicode = is_unicode(content)
if name is None and stacklevel is not None:
try:
caller = sys._getframe(stacklevel)
except ValueError:
pass
else:
globals = caller.f_globals
lineno = caller.f_lineno
if '
__file__
' in globals:
name = globals['
__file__
']
if name.endswith('
.
pyc
') or name.endswith('
.
pyo
'):
name = name[:-1]
elif '
__name__
' in globals:
name = globals['
__name__
']
else:
name = '
<
string
>
'
if lineno:
name += '
:
%
s
' % lineno
self.name = name
self._parsed = parse(content, name=name, line_offset=line_offset, delimeters=self.delimeters)
if namespace is None:
namespace = {}
self.namespace = namespace
self.get_template = get_template
if default_inherit is not None:
self.default_inherit = default_inherit
def from_filename(cls, filename, namespace=None, encoding=None,
default_inherit=None, get_template=get_file_template):
f = open(filename, 'rb')
c = f.read()
f.close()
if encoding:
c = c.decode(encoding)
return cls(content=c, name=filename, namespace=namespace,
default_inherit=default_inherit, get_template=get_template)
from_filename = classmethod(from_filename)
def __repr__(self):
return '
<%
s
%
s
name
=%
r
>
' % (
self.__class__.__name__,
hex(id(self))[2:], self.name)
def substitute(self, *args, **kw):
if args:
if kw:
raise TypeError(
"You can only give positional *or* keyword arguments")
if len(args) > 1:
raise TypeError(
"You can only give one positional argument")
if not hasattr(args[0], '
items
'):
raise TypeError(
"If you pass in a single argument, you must pass in a dictionary-like object (with a .items() method); you gave %r"
% (args[0],))
kw = args[0]
ns = kw
ns['
__template_name__
'] = self.name
if self.namespace:
ns.update(self.namespace)
result, defs, inherit = self._interpret(ns)
if not inherit:
inherit = self.default_inherit
if inherit:
result = self._interpret_inherit(result, defs, inherit, ns)
return result
def _interpret(self, ns):
__traceback_hide__ = True
parts = []
defs = {}
self._interpret_codes(self._parsed, ns, out=parts, defs=defs)
if '
__inherit__
' in defs:
inherit = defs.pop('
__inherit__
')
else:
inherit = None
return ''.join(parts), defs, inherit
def _interpret_inherit(self, body, defs, inherit_template, ns):
__traceback_hide__ = True
if not self.get_template:
raise TemplateError(
'
You
cannot
use
inheritance
without
passing
in
get_template
',
position=None, name=self.name)
templ = self.get_template(inherit_template, self)
self_ = TemplateObject(self.name)
for name, value in defs.iteritems():
setattr(self_, name, value)
self_.body = body
ns = ns.copy()
ns['
self
'] = self_
return templ.substitute(ns)
def _interpret_codes(self, codes, ns, out, defs):
__traceback_hide__ = True
for item in codes:
if isinstance(item, basestring_):
out.append(item)
else:
self._interpret_code(item, ns, out, defs)
def _interpret_code(self, code, ns, out, defs):
__traceback_hide__ = True
name, pos = code[0], code[1]
if name == '
py
':
self._exec(code[2], ns, pos)
elif name == '
continue
':
raise _TemplateContinue()
elif name == '
break
':
raise _TemplateBreak()
elif name == '
for
':
vars, expr, content = code[2], code[3], code[4]
expr = self._eval(expr, ns, pos)
self._interpret_for(vars, expr, content, ns, out, defs)
elif name == '
cond
':
parts = code[2:]
self._interpret_if(parts, ns, out, defs)
elif name == '
expr
':
parts = code[2].split('
|
')
base = self._eval(parts[0], ns, pos)
for part in parts[1:]:
func = self._eval(part, ns, pos)
base = func(base)
out.append(self._repr(base, pos))
elif name == '
default
':
var, expr = code[2], code[3]
if var not in ns:
result = self._eval(expr, ns, pos)
ns[var] = result
elif name == '
inherit
':
expr = code[2]
value = self._eval(expr, ns, pos)
defs['
__inherit__
'] = value
elif name == '
def
':
name = code[2]
signature = code[3]
parts = code[4]
ns[name] = defs[name] = TemplateDef(self, name, signature, body=parts, ns=ns,
pos=pos)
elif name == '
comment
':
return
else:
assert 0, "Unknown code: %r" % name
def _interpret_for(self, vars, expr, content, ns, out, defs):
__traceback_hide__ = True
for item in expr:
if len(vars) == 1:
ns[vars[0]] = item
else:
if len(vars) != len(item):
raise ValueError(
'
Need
%
i
items
to
unpack
(
got
%
i
items
)
'
% (len(vars), len(item)))
for name, value in zip(vars, item):
ns[name] = value
try:
self._interpret_codes(content, ns, out, defs)
except _TemplateContinue:
continue
except _TemplateBreak:
break
def _interpret_if(self, parts, ns, out, defs):
__traceback_hide__ = True
# @@: if/else/else gets through
for part in parts:
assert not isinstance(part, basestring_)
name, pos = part[0], part[1]
if name == '
else
':
result = True
else:
result = self._eval(part[2], ns, pos)
if result:
self._interpret_codes(part[3], ns, out, defs)
break
def _eval(self, code, ns, pos):
__traceback_hide__ = True
try:
try:
value = eval(code, self.default_namespace, ns)
except SyntaxError, e:
raise SyntaxError(
'
invalid
syntax
in
expression
:
%
s
' % code)
return value
except:
exc_info = sys.exc_info()
e = exc_info[1]
if getattr(e, '
args
', None):
arg0 = e.args[0]
else:
arg0 = coerce_text(e)
e.args = (self._add_line_info(arg0, pos),)
raise exc_info[0], e, exc_info[2]
def _exec(self, code, ns, pos):
__traceback_hide__ = True
try:
exec code in self.default_namespace, ns
except:
exc_info = sys.exc_info()
e = exc_info[1]
if e.args:
e.args = (self._add_line_info(e.args[0], pos),)
else:
e.args = (self._add_line_info(None, pos),)
raise exc_info[0], e, exc_info[2]
def _repr(self, value, pos):
__traceback_hide__ = True
try:
if value is None:
return ''
if self._unicode:
try:
value = unicode(value)
except UnicodeDecodeError:
value = bytes(value)
else:
if not isinstance(value, basestring_):
value = coerce_text(value)
if (is_unicode(value)
and self.default_encoding):
value = value.encode(self.default_encoding)
except:
exc_info = sys.exc_info()
e = exc_info[1]
e.args = (self._add_line_info(e.args[0], pos),)
raise exc_info[0], e, exc_info[2]
else:
if self._unicode and isinstance(value, bytes):
if not self.default_encoding:
raise UnicodeDecodeError(
'
Cannot
decode
bytes
value
%
r
into
unicode
'
'
(
no
default_encoding
provided
)
' % value)
try:
value = value.decode(self.default_encoding)
except UnicodeDecodeError, e:
raise UnicodeDecodeError(
e.encoding,
e.object,
e.start,
e.end,
e.reason + '
in
string
%
r' % value)
elif not self._unicode and is_unicode(value):
if not self.default_encoding:
raise UnicodeEncodeError(
'
Cannot
encode
unicode
value
%
r
into
bytes
'
'
(
no
default_encoding
provided
)
' % value)
value = value.encode(self.default_encoding)
return value
def _add_line_info(self, msg, pos):
msg = "%s at line %s column %s" % (
msg, pos[0], pos[1])
if self.name:
msg += " in file %s" % self.name
return msg
def sub(content, delimeters=None, **kw):
name = kw.get('
__name
')
tmpl = Template(content, name=name, delimeters=delimeters)
return tmpl.substitute(kw)
def paste_script_template_renderer(content, vars, filename=None):
tmpl = Template(content, name=filename)
return tmpl.substitute(vars)
class bunch(dict):
def __init__(self, **kw):
for name, value in kw.iteritems():
setattr(self, name, value)
def __setattr__(self, name, value):
self[name] = value
def __getattr__(self, name):
try:
return self[name]
except KeyError:
raise AttributeError(name)
def __getitem__(self, key):
if '
default
' in self:
try:
return dict.__getitem__(self, key)
except KeyError:
return dict.__getitem__(self, '
default
')
else:
return dict.__getitem__(self, key)
def __repr__(self):
items = [
(k, v) for k, v in self.iteritems()]
items.sort()
return '
<%
s
%
s
>
' % (
self.__class__.__name__,
'
'.join(['
%
s
=%
r' % (k, v) for k, v in items]))
############################################################
## HTML Templating
############################################################
class html(object):
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
def __html__(self):
return self.value
def __repr__(self):
return '
<%
s
%
r
>
' % (
self.__class__.__name__, self.value)
def html_quote(value, force=True):
if not force and hasattr(value, '
__html__
'):
return value.__html__()
if value is None:
return ''
if not isinstance(value, basestring_):
value = coerce_text(value)
if sys.version >= "3" and isinstance(value, bytes):
value = cgi.escape(value.decode('
latin1
'), 1)
value = value.encode('
latin1
')
else:
value = cgi.escape(value, 1)
if sys.version < "3":
if is_unicode(value):
value = value.encode('
ascii
', '
xmlcharrefreplace
')
return value
def url(v):
v = coerce_text(v)
if is_unicode(v):
v = v.encode('
utf8
')
return url_quote(v)
def attr(**kw):
kw = list(kw.iteritems())
kw.sort()
parts = []
for name, value in kw:
if value is None:
continue
if name.endswith('
_
'):
name = name[:-1]
parts.append('
%
s
=
"%s"' % (html_quote(name), html_quote(value)))
return html('
'.join(parts))
class HTMLTemplate(Template):
default_namespace = Template.default_namespace.copy()
default_namespace.update(dict(
html=html,
attr=attr,
url=url,
html_quote=html_quote,
))
def _repr(self, value, pos):
if hasattr(value, '
__html__
'):
value = value.__html__()
quote = False
else:
quote = True
plain = Template._repr(self, value, pos)
if quote:
return html_quote(plain)
else:
return plain
def sub_html(content, **kw):
name = kw.get('
__name
')
tmpl = HTMLTemplate(content, name=name)
return tmpl.substitute(kw)
class TemplateDef(object):
def __init__(self, template, func_name, func_signature,
body, ns, pos, bound_self=None):
self._template = template
self._func_name = func_name
self._func_signature = func_signature
self._body = body
self._ns = ns
self._pos = pos
self._bound_self = bound_self
def __repr__(self):
return '
<
tempita
function
%
s
(
%
s
)
at
%
s
:
%
s
>
' % (
self._func_name, self._func_signature,
self._template.name, self._pos)
def __str__(self):
return self()
def __call__(self, *args, **kw):
values = self._parse_signature(args, kw)
ns = self._ns.copy()
ns.update(values)
if self._bound_self is not None:
ns['
self
'] = self._bound_self
out = []
subdefs = {}
self._template._interpret_codes(self._body, ns, out, subdefs)
return ''.join(out)
def __get__(self, obj, type=None):
if obj is None:
return self
return self.__class__(
self._template, self._func_name, self._func_signature,
self._body, self._ns, self._pos, bound_self=obj)
def _parse_signature(self, args, kw):
values = {}
sig_args, var_args, var_kw, defaults = self._func_signature
extra_kw = {}
for name, value in kw.iteritems():
if not var_kw and name not in sig_args:
raise TypeError(
'
Unexpected
argument
%
s
' % name)
if name in sig_args:
values[sig_args] = value
else:
extra_kw[name] = value
args = list(args)
sig_args = list(sig_args)
while args:
while sig_args and sig_args[0] in values:
sig_args.pop(0)
if sig_args:
name = sig_args.pop(0)
values[name] = args.pop(0)
elif var_args:
values[var_args] = tuple(args)
break
else:
raise TypeError(
'
Extra
position
arguments
:
%
s
'
% '
,
'.join(repr(v) for v in args))
for name, value_expr in defaults.iteritems():
if name not in values:
values[name] = self._template._eval(
value_expr, self._ns, self._pos)
for name in sig_args:
if name not in values:
raise TypeError(
'
Missing
argument
:
%
s
' % name)
if var_kw:
values[var_kw] = extra_kw
return values
class TemplateObject(object):
def __init__(self, name):
self.__name = name
self.get = TemplateObjectGetter(self)
def __repr__(self):
return '
<%
s
%
s
>
' % (self.__class__.__name__, self.__name)
class TemplateObjectGetter(object):
def __init__(self, template_obj):
self.__template_obj = template_obj
def __getattr__(self, attr):
return getattr(self.__template_obj, attr, Empty)
def __repr__(self):
return '
<%
s
around
%
r
>
' % (self.__class__.__name__, self.__template_obj)
class _Empty(object):
def __call__(self, *args, **kw):
return self
def __str__(self):
return ''
def __repr__(self):
return '
Empty
'
def __unicode__(self):
return u''
def __iter__(self):
return iter(())
def __bool__(self):
return False
if sys.version < "3":
__nonzero__ = __bool__
Empty = _Empty()
del _Empty
############################################################
## Lexing and Parsing
############################################################
def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=None):
"""
Lex a string into chunks:
>>> lex('
hey
')
['
hey
']
>>> lex('
hey
{{
you
}}
')
['
hey
', ('
you
', (1, 7))]
>>> lex('
hey
{{
')
Traceback (most recent call last):
...
TemplateError: No }} to finish last expression at line 1 column 7
>>> lex('
hey
}}
')
Traceback (most recent call last):
...
TemplateError: }} outside expression at line 1 column 7
>>> lex('
hey
{{
{{
')
Traceback (most recent call last):
...
TemplateError: {{ inside expression at line 1 column 10
"""
if delimeters is None:
delimeters = ( Template.default_namespace['
start_braces
'],
Template.default_namespace['
end_braces
'] )
in_expr = False
chunks = []
last = 0
last_pos = (1, 1)
token_re = re.compile(r'
%
s
|%
s
' % (re.escape(delimeters[0]),
re.escape(delimeters[1])))
for match in token_re.finditer(s):
expr = match.group(0)
pos = find_position(s, match.end(), line_offset)
if expr == delimeters[0] and in_expr:
raise TemplateError('
%
s
inside
expression
' % delimeters[0],
position=pos,
name=name)
elif expr == delimeters[1] and not in_expr:
raise TemplateError('
%
s
outside
expression
' % delimeters[1],
position=pos,
name=name)
if expr == delimeters[0]:
part = s[last:match.start()]
if part:
chunks.append(part)
in_expr = True
else:
chunks.append((s[last:match.start()], last_pos))
in_expr = False
last = match.end()
last_pos = pos
if in_expr:
raise TemplateError('
No
%
s
to
finish
last
expression
' % delimeters[1],
name=name, position=last_pos)
part = s[last:]
if part:
chunks.append(part)
if trim_whitespace:
chunks = trim_lex(chunks)
return chunks
statement_re = re.compile(r'
^
(
?
:
if
|
elif
|
for
|
def
|
inherit
|
default
|
py
:)
')
single_statements = ['
else
', '
endif
', '
endfor
', '
enddef
', '
continue
', '
break
']
trail_whitespace_re = re.compile(r'
\
n
\
r
?
[
\
t
]
*
$
')
lead_whitespace_re = re.compile(r'
^
[
\
t
]
*
\
n
')
def trim_lex(tokens):
r"""
Takes a lexed set of tokens, and removes whitespace when there is
a directive on a line by itself:
>>> tokens = lex('
{{
if
x
}}
\
nx
\
n
{{
endif
}}
\
ny
', trim_whitespace=False)
>>> tokens
[('
if
x
', (1, 3)), '
\
nx
\
n
', ('
endif
', (3, 3)), '
\
ny
']
>>> trim_lex(tokens)
[('
if
x
', (1, 3)), '
x
\
n
', ('
endif
', (3, 3)), '
y
']
"""
last_trim = None
for i in range(len(tokens)):
current = tokens[i]
if isinstance(tokens[i], basestring_):
# we don'
t
trim
this
continue
item
=
current
[
0
]
if
not
statement_re
.
search
(
item
)
and
item
not
in
single_statements
:
continue
if
not
i
:
prev
=
''
else
:
prev
=
tokens
[
i
-
1
]
if
i
+
1
>=
len
(
tokens
):
next_chunk
=
''
else
:
next_chunk
=
tokens
[
i
+
1
]
if
(
not
isinstance
(
next_chunk
,
basestring_
)
or
not
isinstance
(
prev
,
basestring_
)):
continue
prev_ok
=
not
prev
or
trail_whitespace_re
.
search
(
prev
)
if
i
==
1
and
not
prev
.
strip
():
prev_ok
=
True
if
last_trim
is
not
None
and
last_trim
+
2
==
i
and
not
prev
.
strip
():
prev_ok
=
'last'
if
(
prev_ok
and
(
not
next_chunk
or
lead_whitespace_re
.
search
(
next_chunk
)
or
(
i
==
len
(
tokens
)
-
2
and
not
next_chunk
.
strip
()))):
if
prev
:
if
((
i
==
1
and
not
prev
.
strip
())
or
prev_ok
==
'last'
):
tokens
[
i
-
1
]
=
''
else
:
m
=
trail_whitespace_re
.
search
(
prev
)
# +1 to leave the leading \n on:
prev
=
prev
[:
m
.
start
()
+
1
]
tokens
[
i
-
1
]
=
prev
if
next_chunk
:
last_trim
=
i
if
i
==
len
(
tokens
)
-
2
and
not
next_chunk
.
strip
():
tokens
[
i
+
1
]
=
''
else
:
m
=
lead_whitespace_re
.
search
(
next_chunk
)
next_chunk
=
next_chunk
[
m
.
end
():]
tokens
[
i
+
1
]
=
next_chunk
return
tokens
def
find_position
(
string
,
index
,
line_offset
):
"""Given a string and index, return (line, column)"""
leading
=
string
[:
index
].
splitlines
()
return
(
len
(
leading
)
+
line_offset
,
len
(
leading
[
-
1
])
+
1
)
def
parse
(
s
,
name
=
None
,
line_offset
=
0
,
delimeters
=
None
):
r"""
Parses a string into a kind of AST
>>> parse('{{x}}')
[('expr', (1, 3), 'x')]
>>> parse('foo')
['foo']
>>> parse('{{if x}}test{{endif}}')
[('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
>>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
>>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
[('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
>>> parse('{{py:x=1}}')
[('py', (1, 3), 'x=1')]
>>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
[('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
Some exceptions::
>>> parse('{{continue}}')
Traceback (most recent call last):
...
TemplateError: continue outside of for loop at line 1 column 3
>>> parse('{{if x}}foo')
Traceback (most recent call last):
...
TemplateError: No {{endif}} at line 1 column 3
>>> parse('{{else}}')
Traceback (most recent call last):
...
TemplateError: else outside of an if block at line 1 column 3
>>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
Traceback (most recent call last):
...
TemplateError: Unexpected endif at line 1 column 25
>>> parse('{{if}}{{endif}}')
Traceback (most recent call last):
...
TemplateError: if with no expression at line 1 column 3
>>> parse('{{for x y}}{{endfor}}')
Traceback (most recent call last):
...
TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
>>> parse('{{py:x=1\ny=2}}')
Traceback (most recent call last):
...
TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
"""
if
delimeters
is
None
:
delimeters
=
(
Template
.
default_namespace
[
'start_braces'
],
Template
.
default_namespace
[
'end_braces'
]
)
tokens
=
lex
(
s
,
name
=
name
,
line_offset
=
line_offset
,
delimeters
=
delimeters
)
result
=
[]
while
tokens
:
next_chunk
,
tokens
=
parse_expr
(
tokens
,
name
)
result
.
append
(
next_chunk
)
return
result
def
parse_expr
(
tokens
,
name
,
context
=
()):
if
isinstance
(
tokens
[
0
],
basestring_
):
return
tokens
[
0
],
tokens
[
1
:]
expr
,
pos
=
tokens
[
0
]
expr
=
expr
.
strip
()
if
expr
.
startswith
(
'py:'
):
expr
=
expr
[
3
:].
lstrip
(
'
\
t
'
)
if
expr
.
startswith
(
'
\
n
'
)
or
expr
.
startswith
(
'
\
r
'
):
expr
=
expr
.
lstrip
(
'
\
r
\
n
'
)
if
'
\
r
'
in
expr
:
expr
=
expr
.
replace
(
'
\
r
\
n
'
,
'
\
n
'
)
expr
=
expr
.
replace
(
'
\
r
'
,
''
)
expr
+=
'
\
n
'
else
:
if
'
\
n
'
in
expr
:
raise
TemplateError
(
'Multi-line py blocks must start with a newline'
,
position
=
pos
,
name
=
name
)
return
(
'py'
,
pos
,
expr
),
tokens
[
1
:]
elif
expr
in
(
'continue'
,
'break'
):
if
'for'
not
in
context
:
raise
TemplateError
(
'continue outside of for loop'
,
position
=
pos
,
name
=
name
)
return
(
expr
,
pos
),
tokens
[
1
:]
elif
expr
.
startswith
(
'if '
):
return
parse_cond
(
tokens
,
name
,
context
)
elif
(
expr
.
startswith
(
'elif '
)
or
expr
==
'else'
):
raise
TemplateError
(
'%s outside of an if block'
%
expr
.
split
()[
0
],
position
=
pos
,
name
=
name
)
elif
expr
in
(
'if'
,
'elif'
,
'for'
):
raise
TemplateError
(
'%s with no expression'
%
expr
,
position
=
pos
,
name
=
name
)
elif
expr
in
(
'endif'
,
'endfor'
,
'enddef'
):
raise
TemplateError
(
'Unexpected %s'
%
expr
,
position
=
pos
,
name
=
name
)
elif
expr
.
startswith
(
'for '
):
return
parse_for
(
tokens
,
name
,
context
)
elif
expr
.
startswith
(
'default '
):
return
parse_default
(
tokens
,
name
,
context
)
elif
expr
.
startswith
(
'inherit '
):
return
parse_inherit
(
tokens
,
name
,
context
)
elif
expr
.
startswith
(
'def '
):
return
parse_def
(
tokens
,
name
,
context
)
elif
expr
.
startswith
(
'#'
):
return
(
'comment'
,
pos
,
tokens
[
0
][
0
]),
tokens
[
1
:]
return
(
'expr'
,
pos
,
tokens
[
0
][
0
]),
tokens
[
1
:]
def
parse_cond
(
tokens
,
name
,
context
):
start
=
tokens
[
0
][
1
]
pieces
=
[]
context
=
context
+
(
'if'
,)
while
1
:
if
not
tokens
:
raise
TemplateError
(
'Missing {{endif}}'
,
position
=
start
,
name
=
name
)
if
(
isinstance
(
tokens
[
0
],
tuple
)
and
tokens
[
0
][
0
]
==
'endif'
):
return
(
'cond'
,
start
)
+
tuple
(
pieces
),
tokens
[
1
:]
next_chunk
,
tokens
=
parse_one_cond
(
tokens
,
name
,
context
)
pieces
.
append
(
next_chunk
)
def
parse_one_cond
(
tokens
,
name
,
context
):
(
first
,
pos
),
tokens
=
tokens
[
0
],
tokens
[
1
:]
content
=
[]
if
first
.
endswith
(
':'
):
first
=
first
[:
-
1
]
if
first
.
startswith
(
'if '
):
part
=
(
'if'
,
pos
,
first
[
3
:].
lstrip
(),
content
)
elif
first
.
startswith
(
'elif '
):
part
=
(
'elif'
,
pos
,
first
[
5
:].
lstrip
(),
content
)
elif
first
==
'else'
:
part
=
(
'else'
,
pos
,
None
,
content
)
else
:
assert
0
,
"Unexpected token %r at %s"
%
(
first
,
pos
)
while
1
:
if
not
tokens
:
raise
TemplateError
(
'No {{endif}}'
,
position
=
pos
,
name
=
name
)
if
(
isinstance
(
tokens
[
0
],
tuple
)
and
(
tokens
[
0
][
0
]
==
'endif'
or
tokens
[
0
][
0
].
startswith
(
'elif '
)
or
tokens
[
0
][
0
]
==
'else'
)):
return
part
,
tokens
next_chunk
,
tokens
=
parse_expr
(
tokens
,
name
,
context
)
content
.
append
(
next_chunk
)
def
parse_for
(
tokens
,
name
,
context
):
first
,
pos
=
tokens
[
0
]
tokens
=
tokens
[
1
:]
context
=
(
'for'
,)
+
context
content
=
[]
assert
first
.
startswith
(
'for '
)
if
first
.
endswith
(
':'
):
first
=
first
[:
-
1
]
first
=
first
[
3
:].
strip
()
match
=
in_re
.
search
(
first
)
if
not
match
:
raise
TemplateError
(
'Bad for (no "in") in %r'
%
first
,
position
=
pos
,
name
=
name
)
vars
=
first
[:
match
.
start
()]
if
'('
in
vars
:
raise
TemplateError
(
'You cannot have () in the variable section of a for loop (%r)'
%
vars
,
position
=
pos
,
name
=
name
)
vars
=
tuple
([
v
.
strip
()
for
v
in
first
[:
match
.
start
()].
split
(
','
)
if
v
.
strip
()])
expr
=
first
[
match
.
end
():]
while
1
:
if
not
tokens
:
raise
TemplateError
(
'No {{endfor}}'
,
position
=
pos
,
name
=
name
)
if
(
isinstance
(
tokens
[
0
],
tuple
)
and
tokens
[
0
][
0
]
==
'endfor'
):
return
(
'for'
,
pos
,
vars
,
expr
,
content
),
tokens
[
1
:]
next_chunk
,
tokens
=
parse_expr
(
tokens
,
name
,
context
)
content
.
append
(
next_chunk
)
def
parse_default
(
tokens
,
name
,
context
):
first
,
pos
=
tokens
[
0
]
assert
first
.
startswith
(
'default '
)
first
=
first
.
split
(
None
,
1
)[
1
]
parts
=
first
.
split
(
'='
,
1
)
if
len
(
parts
)
==
1
:
raise
TemplateError
(
"Expression must be {{default var=value}}; no = found in %r"
%
first
,
position
=
pos
,
name
=
name
)
var
=
parts
[
0
].
strip
()
if
','
in
var
:
raise
TemplateError
(
"{{default x, y = ...}} is not supported"
,
position
=
pos
,
name
=
name
)
if
not
var_re
.
search
(
var
):
raise
TemplateError
(
"Not a valid variable name for {{default}}: %r"
%
var
,
position
=
pos
,
name
=
name
)
expr
=
parts
[
1
].
strip
()
return
(
'default'
,
pos
,
var
,
expr
),
tokens
[
1
:]
def
parse_inherit
(
tokens
,
name
,
context
):
first
,
pos
=
tokens
[
0
]
assert
first
.
startswith
(
'inherit '
)
expr
=
first
.
split
(
None
,
1
)[
1
]
return
(
'inherit'
,
pos
,
expr
),
tokens
[
1
:]
def
parse_def
(
tokens
,
name
,
context
):
first
,
start
=
tokens
[
0
]
tokens
=
tokens
[
1
:]
assert
first
.
startswith
(
'def '
)
first
=
first
.
split
(
None
,
1
)[
1
]
if
first
.
endswith
(
':'
):
first
=
first
[:
-
1
]
if
'('
not
in
first
:
func_name
=
first
sig
=
((),
None
,
None
,
{})
elif
not
first
.
endswith
(
')'
):
raise
TemplateError
(
"Function definition doesn't end with ): %s"
%
first
,
position
=
start
,
name
=
name
)
else
:
first
=
first
[:
-
1
]
func_name
,
sig_text
=
first
.
split
(
'('
,
1
)
sig
=
parse_signature
(
sig_text
,
name
,
start
)
context
=
context
+
(
'def'
,)
content
=
[]
while
1
:
if
not
tokens
:
raise
TemplateError
(
'Missing {{enddef}}'
,
position
=
start
,
name
=
name
)
if
(
isinstance
(
tokens
[
0
],
tuple
)
and
tokens
[
0
][
0
]
==
'enddef'
):
return
(
'def'
,
start
,
func_name
,
sig
,
content
),
tokens
[
1
:]
next_chunk
,
tokens
=
parse_expr
(
tokens
,
name
,
context
)
content
.
append
(
next_chunk
)
def
parse_signature
(
sig_text
,
name
,
pos
):
tokens
=
tokenize
.
generate_tokens
(
StringIO
(
sig_text
).
readline
)
sig_args
=
[]
var_arg
=
None
var_kw
=
None
defaults
=
{}
def
get_token
(
pos
=
False
):
try
:
tok_type
,
tok_string
,
(
srow
,
scol
),
(
erow
,
ecol
),
line
=
next
(
tokens
)
except
StopIteration
:
return
tokenize
.
ENDMARKER
,
''
if
pos
:
return
tok_type
,
tok_string
,
(
srow
,
scol
),
(
erow
,
ecol
)
else
:
return
tok_type
,
tok_string
while
1
:
var_arg_type
=
None
tok_type
,
tok_string
=
get_token
()
if
tok_type
==
tokenize
.
ENDMARKER
:
break
if
tok_type
==
tokenize
.
OP
and
(
tok_string
==
'*'
or
tok_string
==
'**'
):
var_arg_type
=
tok_string
tok_type
,
tok_string
=
get_token
()
if
tok_type
!=
tokenize
.
NAME
:
raise
TemplateError
(
'Invalid signature: (%s)'
%
sig_text
,
position
=
pos
,
name
=
name
)
var_name
=
tok_string
tok_type
,
tok_string
=
get_token
()
if
tok_type
==
tokenize
.
ENDMARKER
or
(
tok_type
==
tokenize
.
OP
and
tok_string
==
','
):
if
var_arg_type
==
'*'
:
var_arg
=
var_name
elif
var_arg_type
==
'**'
:
var_kw
=
var_name
else
:
sig_args
.
append
(
var_name
)
if
tok_type
==
tokenize
.
ENDMARKER
:
break
continue
if
var_arg_type
is
not
None
:
raise
TemplateError
(
'Invalid signature: (%s)'
%
sig_text
,
position
=
pos
,
name
=
name
)
if
tok_type
==
tokenize
.
OP
and
tok_string
==
'='
:
nest_type
=
None
unnest_type
=
None
nest_count
=
0
start_pos
=
end_pos
=
None
parts
=
[]
while
1
:
tok_type
,
tok_string
,
s
,
e
=
get_token
(
True
)
if
start_pos
is
None
:
start_pos
=
s
end_pos
=
e
if
tok_type
==
tokenize
.
ENDMARKER
and
nest_count
:
raise
TemplateError
(
'Invalid signature: (%s)'
%
sig_text
,
position
=
pos
,
name
=
name
)
if
(
not
nest_count
and
(
tok_type
==
tokenize
.
ENDMARKER
or
(
tok_type
==
tokenize
.
OP
and
tok_string
==
','
))):
default_expr
=
isolate_expression
(
sig_text
,
start_pos
,
end_pos
)
defaults
[
var_name
]
=
default_expr
sig_args
.
append
(
var_name
)
break
parts
.
append
((
tok_type
,
tok_string
))
if
nest_count
and
tok_type
==
tokenize
.
OP
and
tok_string
==
nest_type
:
nest_count
+=
1
elif
nest_count
and
tok_type
==
tokenize
.
OP
and
tok_string
==
unnest_type
:
nest_count
-=
1
if
not
nest_count
:
nest_type
=
unnest_type
=
None
elif
not
nest_count
and
tok_type
==
tokenize
.
OP
and
tok_string
in
(
'('
,
'['
,
'{'
):
nest_type
=
tok_string
nest_count
=
1
unnest_type
=
{
'('
:
')'
,
'['
:
']'
,
'{'
:
'}'
}[
nest_type
]
return
sig_args
,
var_arg
,
var_kw
,
defaults
def
isolate_expression
(
string
,
start_pos
,
end_pos
):
srow
,
scol
=
start_pos
srow
-=
1
erow
,
ecol
=
end_pos
erow
-=
1
lines
=
string
.
splitlines
(
True
)
if
srow
==
erow
:
return
lines
[
srow
][
scol
:
ecol
]
parts
=
[
lines
[
srow
][
scol
:]]
parts
.
extend
(
lines
[
srow
+
1
:
erow
])
if
erow
<
len
(
lines
):
# It'll sometimes give (end_row_past_finish, 0)
parts
.
append
(
lines
[
erow
][:
ecol
])
return
''
.
join
(
parts
)
_fill_command_usage
=
"""
\
%prog [OPTIONS] TEMPLATE arg=value
Use py:arg=value to set a Python value; otherwise all values are
strings.
"""
def
fill_command
(
args
=
None
):
import
sys
import
optparse
import
pkg_resources
import
os
if
args
is
None
:
args
=
sys
.
argv
[
1
:]
dist
=
pkg_resources
.
get_distribution
(
'Paste'
)
parser
=
optparse
.
OptionParser
(
version
=
coerce_text
(
dist
),
usage
=
_fill_command_usage
)
parser
.
add_option
(
'-o'
,
'--output'
,
dest
=
'output'
,
metavar
=
"FILENAME"
,
help
=
"File to write output to (default stdout)"
)
parser
.
add_option
(
'--html'
,
dest
=
'use_html'
,
action
=
'store_true'
,
help
=
"Use HTML style filling (including automatic HTML quoting)"
)
parser
.
add_option
(
'--env'
,
dest
=
'use_env'
,
action
=
'store_true'
,
help
=
"Put the environment in as top-level variables"
)
options
,
args
=
parser
.
parse_args
(
args
)
if
len
(
args
)
<
1
:
print
(
'You must give a template filename'
)
sys
.
exit
(
2
)
template_name
=
args
[
0
]
args
=
args
[
1
:]
vars
=
{}
if
options
.
use_env
:
vars
.
update
(
os
.
environ
)
for
value
in
args
:
if
'='
not
in
value
:
print
(
'Bad argument: %r'
%
value
)
sys
.
exit
(
2
)
name
,
value
=
value
.
split
(
'='
,
1
)
if
name
.
startswith
(
'py:'
):
name
=
name
[:
3
]
value
=
eval
(
value
)
vars
[
name
]
=
value
if
template_name
==
'-'
:
template_content
=
sys
.
stdin
.
read
()
template_name
=
'<stdin>'
else
:
f
=
open
(
template_name
,
'rb'
)
template_content
=
f
.
read
()
f
.
close
()
if
options
.
use_html
:
TemplateClass
=
HTMLTemplate
else
:
TemplateClass
=
Template
template
=
TemplateClass
(
template_content
,
name
=
template_name
)
result
=
template
.
substitute
(
vars
)
if
options
.
output
:
f
=
open
(
options
.
output
,
'wb'
)
f
.
write
(
result
)
f
.
close
()
else
:
sys
.
stdout
.
write
(
result
)
if
__name__
==
'__main__'
:
fill_command
()
Cython/Tempita/_looper.py
0 → 100644
View file @
3f8fefb0
"""
Helper for looping over sequences, particular in templates.
Often in a loop in a template it's handy to know what's next up,
previously up, if this is the first or last item in the sequence, etc.
These can be awkward to manage in a normal Python loop, but using the
looper you can get a better sense of the context. Use like::
>>> for loop, item in looper(['a', 'b', 'c']):
... print loop.number, item
... if not loop.last:
... print '---'
1 a
---
2 b
---
3 c
"""
import
sys
from
Cython.Tempita.compat3
import
basestring_
__all__
=
[
'looper'
]
class
looper
(
object
):
"""
Helper for looping (particularly in templates)
Use this like::
for loop, item in looper(seq):
if loop.first:
...
"""
def
__init__
(
self
,
seq
):
self
.
seq
=
seq
def
__iter__
(
self
):
return
looper_iter
(
self
.
seq
)
def
__repr__
(
self
):
return
'<%s for %r>'
%
(
self
.
__class__
.
__name__
,
self
.
seq
)
class
looper_iter
(
object
):
def
__init__
(
self
,
seq
):
self
.
seq
=
list
(
seq
)
self
.
pos
=
0
def
__iter__
(
self
):
return
self
def
__next__
(
self
):
if
self
.
pos
>=
len
(
self
.
seq
):
raise
StopIteration
result
=
loop_pos
(
self
.
seq
,
self
.
pos
),
self
.
seq
[
self
.
pos
]
self
.
pos
+=
1
return
result
if
sys
.
version
<
"3"
:
next
=
__next__
class
loop_pos
(
object
):
def
__init__
(
self
,
seq
,
pos
):
self
.
seq
=
seq
self
.
pos
=
pos
def
__repr__
(
self
):
return
'<loop pos=%r at %r>'
%
(
self
.
seq
[
self
.
pos
],
self
.
pos
)
def
index
(
self
):
return
self
.
pos
index
=
property
(
index
)
def
number
(
self
):
return
self
.
pos
+
1
number
=
property
(
number
)
def
item
(
self
):
return
self
.
seq
[
self
.
pos
]
item
=
property
(
item
)
def
__next__
(
self
):
try
:
return
self
.
seq
[
self
.
pos
+
1
]
except
IndexError
:
return
None
__next__
=
property
(
__next__
)
if
sys
.
version
<
"3"
:
next
=
__next__
def
previous
(
self
):
if
self
.
pos
==
0
:
return
None
return
self
.
seq
[
self
.
pos
-
1
]
previous
=
property
(
previous
)
def
odd
(
self
):
return
not
self
.
pos
%
2
odd
=
property
(
odd
)
def
even
(
self
):
return
self
.
pos
%
2
even
=
property
(
even
)
def
first
(
self
):
return
self
.
pos
==
0
first
=
property
(
first
)
def
last
(
self
):
return
self
.
pos
==
len
(
self
.
seq
)
-
1
last
=
property
(
last
)
def
length
(
self
):
return
len
(
self
.
seq
)
length
=
property
(
length
)
def
first_group
(
self
,
getter
=
None
):
"""
Returns true if this item is the start of a new group,
where groups mean that some attribute has changed. The getter
can be None (the item itself changes), an attribute name like
``'.attr'``, a function, or a dict key or list index.
"""
if
self
.
first
:
return
True
return
self
.
_compare_group
(
self
.
item
,
self
.
previous
,
getter
)
def
last_group
(
self
,
getter
=
None
):
"""
Returns true if this item is the end of a new group,
where groups mean that some attribute has changed. The getter
can be None (the item itself changes), an attribute name like
``'.attr'``, a function, or a dict key or list index.
"""
if
self
.
last
:
return
True
return
self
.
_compare_group
(
self
.
item
,
self
.
__next__
,
getter
)
def
_compare_group
(
self
,
item
,
other
,
getter
):
if
getter
is
None
:
return
item
!=
other
elif
(
isinstance
(
getter
,
basestring_
)
and
getter
.
startswith
(
'.'
)):
getter
=
getter
[
1
:]
if
getter
.
endswith
(
'()'
):
getter
=
getter
[:
-
2
]
return
getattr
(
item
,
getter
)()
!=
getattr
(
other
,
getter
)()
else
:
return
getattr
(
item
,
getter
)
!=
getattr
(
other
,
getter
)
elif
hasattr
(
getter
,
'__call__'
):
return
getter
(
item
)
!=
getter
(
other
)
else
:
return
item
[
getter
]
!=
other
[
getter
]
Cython/Tempita/compat3.py
0 → 100644
View file @
3f8fefb0
import
sys
__all__
=
[
'b'
,
'basestring_'
,
'bytes'
,
'next'
,
'is_unicode'
]
if
sys
.
version
<
"3"
:
b
=
bytes
=
str
basestring_
=
basestring
else
:
def
b
(
s
):
if
isinstance
(
s
,
str
):
return
s
.
encode
(
'latin1'
)
return
bytes
(
s
)
basestring_
=
(
bytes
,
str
)
bytes
=
bytes
text
=
str
if
sys
.
version
<
"3"
:
def
next
(
obj
):
return
obj
.
next
()
else
:
next
=
next
if
sys
.
version
<
"3"
:
def
is_unicode
(
obj
):
return
isinstance
(
obj
,
unicode
)
else
:
def
is_unicode
(
obj
):
return
isinstance
(
obj
,
str
)
def
coerce_text
(
v
):
if
not
isinstance
(
v
,
basestring_
):
if
sys
.
version
<
"3"
:
attr
=
'__unicode__'
else
:
attr
=
'__str__'
if
hasattr
(
v
,
attr
):
return
unicode
(
v
)
else
:
return
bytes
(
v
)
return
v
Cython/Utility/MemoryView_C.c
View file @
3f8fefb0
...
@@ -3,13 +3,13 @@
...
@@ -3,13 +3,13 @@
/* memoryview slice struct */
/* memoryview slice struct */
typedef
struct
{
typedef
struct
{
struct
%
(
memview_struct_name
)
s
*
memview
;
struct
{{
memview_struct_name
}}
*
memview
;
/* For convenience and faster access */
/* For convenience and faster access */
char
*
data
;
char
*
data
;
Py_ssize_t
shape
[
%
(
max_dims
)
d
];
Py_ssize_t
shape
[
{{
max_dims
}}
];
Py_ssize_t
strides
[
%
(
max_dims
)
d
];
Py_ssize_t
strides
[
{{
max_dims
}}
];
/* Py_ssize_t suboffsets[%(max_dims)d]; */
Py_ssize_t
suboffsets
[{{
max_dims
}}];
}
%
(
memviewslice_name
)
s
;
}
{{
memviewslice_name
}}
;
// UtilityProto: MemviewSliceInit
// UtilityProto: MemviewSliceInit
...
@@ -194,12 +194,11 @@ static int __Pyx_init_memviewslice(
...
@@ -194,12 +194,11 @@ static int __Pyx_init_memviewslice(
for
(
i
=
0
;
i
<
ndim
;
i
++
)
{
for
(
i
=
0
;
i
<
ndim
;
i
++
)
{
memviewslice
->
strides
[
i
]
=
buf
->
strides
[
i
];
memviewslice
->
strides
[
i
]
=
buf
->
strides
[
i
];
memviewslice
->
shape
[
i
]
=
buf
->
shape
[
i
];
memviewslice
->
shape
[
i
]
=
buf
->
shape
[
i
];
/*
if
(
buf
->
suboffsets
)
{
if
(
buf
->
suboffsets
)
{
memviewslice
->
suboffsets
[
i
]
=
buf
->
suboffsets
[
i
];
memviewslice
->
suboffsets
[
i
]
=
buf
->
suboffsets
[
i
];
}
else
{
}
else
{
memviewslice
->
suboffsets
[
i
]
=
-
1
;
memviewslice
->
suboffsets
[
i
]
=
-
1
;
}
*/
}
}
}
__Pyx_INCREF
((
PyObject
*
)
memview
);
__Pyx_INCREF
((
PyObject
*
)
memview
);
...
@@ -221,7 +220,7 @@ no_fail:
...
@@ -221,7 +220,7 @@ no_fail:
// UtilityCode: MemviewSliceCopyTemplate
// UtilityCode: MemviewSliceCopyTemplate
static
__Pyx_memviewslice
%
(
copy_name
)
s
(
const
__Pyx_memviewslice
from_mvs
)
{
static
__Pyx_memviewslice
{{
copy_name
}}
(
const
__Pyx_memviewslice
from_mvs
)
{
__Pyx_RefNannyDeclarations
__Pyx_RefNannyDeclarations
int
i
;
int
i
;
...
@@ -232,9 +231,9 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
...
@@ -232,9 +231,9 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
PyObject
*
temp_int
=
0
;
PyObject
*
temp_int
=
0
;
struct
__pyx_array_obj
*
array_obj
=
0
;
struct
__pyx_array_obj
*
array_obj
=
0
;
struct
__pyx_memoryview_obj
*
memview_obj
=
0
;
struct
__pyx_memoryview_obj
*
memview_obj
=
0
;
char
*
mode
=
"
%(mode)s
"
;
char
*
mode
=
"
{{mode}}
"
;
__Pyx_RefNannySetupContext
(
"
%(copy_name)s
"
);
__Pyx_RefNannySetupContext
(
"
{{copy_name}}
"
);
shape_tuple
=
PyTuple_New
((
Py_ssize_t
)(
buf
->
ndim
));
shape_tuple
=
PyTuple_New
((
Py_ssize_t
)(
buf
->
ndim
));
if
(
unlikely
(
!
shape_tuple
))
{
if
(
unlikely
(
!
shape_tuple
))
{
...
@@ -252,13 +251,13 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
...
@@ -252,13 +251,13 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
}
}
}
}
array_obj
=
__pyx_array_new
(
shape_tuple
,
%
(
sizeof_dtype
)
s
,
buf
->
format
,
mode
);
array_obj
=
__pyx_array_new
(
shape_tuple
,
{{
sizeof_dtype
}}
,
buf
->
format
,
mode
);
if
(
unlikely
(
!
array_obj
))
{
if
(
unlikely
(
!
array_obj
))
{
goto
fail
;
goto
fail
;
}
}
__Pyx_GOTREF
(
array_obj
);
__Pyx_GOTREF
(
array_obj
);
memview_obj
=
__pyx_memoryview_new
((
PyObject
*
)
array_obj
,
%
(
contig_flag
)
s
);
memview_obj
=
__pyx_memoryview_new
((
PyObject
*
)
array_obj
,
{{
contig_flag
}}
);
if
(
unlikely
(
!
memview_obj
))
{
if
(
unlikely
(
!
memview_obj
))
{
goto
fail
;
goto
fail
;
}
}
...
@@ -270,7 +269,7 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
...
@@ -270,7 +269,7 @@ static __Pyx_memviewslice %(copy_name)s(const __Pyx_memviewslice from_mvs) {
goto
fail
;
goto
fail
;
}
}
if
(
unlikely
(
-
1
==
%
(
copy_contents_name
)
s
(
&
from_mvs
,
&
new_mvs
)))
{
if
(
unlikely
(
-
1
==
{{
copy_contents_name
}}
(
&
from_mvs
,
&
new_mvs
)))
{
/* PyErr_SetString(PyExc_RuntimeError,
/* PyErr_SetString(PyExc_RuntimeError,
"Could not copy contents of memoryview slice."); */
"Could not copy contents of memoryview slice."); */
goto
fail
;
goto
fail
;
...
...
setup.py
View file @
3f8fefb0
...
@@ -274,6 +274,7 @@ packages = [
...
@@ -274,6 +274,7 @@ packages = [
'Cython.Build.Tests'
,
'Cython.Build.Tests'
,
'Cython.Compiler.Tests'
,
'Cython.Compiler.Tests'
,
'Cython.Utility'
,
'Cython.Utility'
,
'Cython.Tempita'
,
]
]
if
include_debugger
:
if
include_debugger
:
...
...
tests/run/memslice_indexing.pyx
View file @
3f8fefb0
...
@@ -20,7 +20,10 @@ def create_array(shape, mode='c'):
...
@@ -20,7 +20,10 @@ def create_array(shape, mode='c'):
def
slice_contig_indexing
():
def
slice_contig_indexing
():
"""
"""
>>> slice_contig_indexing()
>>> print "disabled"
disabled
slice_contig_indexing()
98
98
61
61
98
98
...
...
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