Commit 08643650 authored by Mark Florisson's avatar Mark Florisson

merge with cython-devel

parents 0aca01f5 54031cb0
......@@ -6,6 +6,7 @@ syntax: glob
Cython/Compiler/Lexicon.pickle
BUILD/
build/
dist/
.coverage
*~
*.orig
......
print "Warning: Using prototype cython.inline code..."
import tempfile
import sys, os, re, inspect
try:
import hashlib
except ImportError:
import md5 as hashlib
from distutils.dist import Distribution
from Cython.Distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Compiler.Main import Context, CompilationOptions, default_options
from Cython.Compiler.ParseTreeTransforms import CythonTransform, SkipDeclarations, AnalyseDeclarationsTransform
from Cython.Compiler.TreeFragment import parse_from_strings
_code_cache = {}
class AllSymbols(CythonTransform, SkipDeclarations):
def __init__(self):
CythonTransform.__init__(self, None)
self.names = set()
def visit_NameNode(self, node):
self.names.add(node.name)
def unbound_symbols(code, context=None):
if context is None:
context = Context([], default_options)
from Cython.Compiler.ParseTreeTransforms import AnalyseDeclarationsTransform
if isinstance(code, str):
code = code.decode('ascii')
tree = parse_from_strings('(tree fragment)', code)
for phase in context.create_pipeline(pxd=False):
if phase is None:
continue
tree = phase(tree)
if isinstance(phase, AnalyseDeclarationsTransform):
break
symbol_collector = AllSymbols()
symbol_collector(tree)
unbound = []
import __builtin__
for name in symbol_collector.names:
if not tree.scope.lookup(name) and not hasattr(__builtin__, name):
unbound.append(name)
return unbound
def get_type(arg, context=None):
py_type = type(arg)
if py_type in [list, tuple, dict, str]:
return py_type.__name__
elif py_type is float:
return 'double'
elif py_type is bool:
return 'bint'
elif py_type is int:
return 'long'
elif 'numpy' in sys.modules and isinstance(arg, sys.modules['numpy'].ndarray):
return 'numpy.ndarray[numpy.%s_t, ndim=%s]' % (arg.dtype.name, arg.ndim)
else:
for base_type in py_type.mro():
if base_type.__module__ == '__builtin__':
return 'object'
module = context.find_module(base_type.__module__, need_pxd=False)
if module:
entry = module.lookup(base_type.__name__)
if entry.is_type:
return '%s.%s' % (base_type.__module__, base_type.__name__)
return 'object'
# TODO: use locals/globals for unbound variables
def cython_inline(code,
types='aggressive',
lib_dir=os.path.expanduser('~/.cython/inline'),
include_dirs=['.'],
locals=None,
globals=None,
**kwds):
code = strip_common_indent(code)
ctx = Context(include_dirs, default_options)
if locals is None:
locals = inspect.currentframe().f_back.f_back.f_locals
if globals is None:
globals = inspect.currentframe().f_back.f_back.f_globals
try:
for symbol in unbound_symbols(code):
if symbol in kwds:
continue
elif symbol in locals:
kwds[symbol] = locals[symbol]
elif symbol in globals:
kwds[symbol] = globals[symbol]
else:
print "Couldn't find ", symbol
except AssertionError:
# Parsing from strings not fully supported (e.g. cimports).
print "Could not parse code as a string (to extract unbound symbols)."
arg_names = kwds.keys()
arg_names.sort()
arg_sigs = tuple([(get_type(kwds[arg], ctx), arg) for arg in arg_names])
key = code, arg_sigs
module = _code_cache.get(key)
if not module:
cimports = []
qualified = re.compile(r'([.\w]+)[.]')
for type, _ in arg_sigs:
m = qualified.match(type)
if m:
cimports.append('\ncimport %s' % m.groups()[0])
module_body, func_body = extract_func_code(code)
params = ', '.join(['%s %s' % a for a in arg_sigs])
module_code = """
%(cimports)s
%(module_body)s
def __invoke(%(params)s):
%(func_body)s
""" % {'cimports': '\n'.join(cimports), 'module_body': module_body, 'params': params, 'func_body': func_body }
# print module_code
_, pyx_file = tempfile.mkstemp('.pyx')
open(pyx_file, 'w').write(module_code)
module = "_" + hashlib.md5(code + str(arg_sigs)).hexdigest()
extension = Extension(
name = module,
sources = [pyx_file],
pyrex_include_dirs = include_dirs)
build_extension = build_ext(Distribution())
build_extension.finalize_options()
build_extension.extensions = [extension]
build_extension.build_temp = os.path.dirname(pyx_file)
if lib_dir not in sys.path:
sys.path.append(lib_dir)
build_extension.build_lib = lib_dir
build_extension.run()
_code_cache[key] = module
arg_list = [kwds[arg] for arg in arg_names]
return __import__(module).__invoke(*arg_list)
non_space = re.compile('[^ ]')
def strip_common_indent(code):
min_indent = None
lines = code.split('\n')
for line in lines:
match = non_space.search(line)
if not match:
continue # blank
indent = match.start()
if line[indent] == '#':
continue # comment
elif min_indent is None or min_indent > indent:
min_indent = indent
for ix, line in enumerate(lines):
match = non_space.search(line)
if not match or line[indent] == '#':
continue
else:
lines[ix] = line[min_indent:]
return '\n'.join(lines)
module_statement = re.compile(r'^((cdef +(extern|class))|cimport|(from .+ cimport)|(from .+ import +[*]))')
def extract_func_code(code):
module = []
function = []
# TODO: string literals, backslash
current = function
code = code.replace('\t', ' ')
lines = code.split('\n')
for line in lines:
if not line.startswith(' '):
if module_statement.match(line):
current = module
else:
current = function
current.append(line)
return '\n'.join(module), ' ' + '\n '.join(function)
......@@ -20,89 +20,76 @@ class AutoTestDictTransform(ScopeTrackingTransform):
return node
self.scope_type = 'module'
self.scope_node = node
if self.current_directives['autotestdict']:
assert isinstance(node.body, StatListNode)
# First see if __test__ is already created
if u'__test__' in node.scope.entries:
# Do nothing
return node
pos = node.pos
if not self.current_directives['autotestdict']:
return node
self.all_docstrings = self.current_directives['autotestdict.all']
self.cdef_docstrings = self.all_docstrings or self.current_directives['autotestdict.cdef']
assert isinstance(node.body, StatListNode)
# First see if __test__ is already created
if u'__test__' in node.scope.entries:
# Do nothing
return node
self.tests = []
self.testspos = node.pos
pos = node.pos
test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'),
py_object_type,
pos,
visibility='public')
create_test_dict_assignment = SingleAssignmentNode(pos,
lhs=NameNode(pos, name=EncodedString(u'__test__'),
entry=test_dict_entry),
rhs=DictNode(pos, key_value_pairs=self.tests))
self.visitchildren(node)
node.body.stats.append(create_test_dict_assignment)
self.tests = []
self.testspos = node.pos
test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'),
py_object_type,
pos,
visibility='public')
create_test_dict_assignment = SingleAssignmentNode(pos,
lhs=NameNode(pos, name=EncodedString(u'__test__'),
entry=test_dict_entry),
rhs=DictNode(pos, key_value_pairs=self.tests))
self.visitchildren(node)
node.body.stats.append(create_test_dict_assignment)
return node
def add_test(self, testpos, name, func_ref_node):
# func_ref_node must evaluate to the function object containing
# the docstring, BUT it should not be the function itself (which
# would lead to a new *definition* of the function)
def add_test(self, testpos, path, doctest):
pos = self.testspos
keystr = u'%s (line %d)' % (name, testpos[1])
keystr = u'%s (line %d)' % (path, testpos[1])
key = UnicodeNode(pos, value=EncodedString(keystr))
value = DocstringRefNode(pos, func_ref_node)
value = UnicodeNode(pos, value=doctest)
self.tests.append(DictItemNode(pos, key=key, value=value))
def visit_FuncDefNode(self, node):
if node.doc:
if not node.doc:
return node
if not self.cdef_docstrings:
if isinstance(node, CFuncDefNode) and not node.py_func:
# skip non-cpdef cdef functions
return node
pos = self.testspos
if self.scope_type == 'module':
parent = ModuleRefNode(pos)
name = node.entry.name
elif self.scope_type in ('pyclass', 'cclass'):
if isinstance(node, CFuncDefNode):
if not self.all_docstrings and '>>>' not in node.doc:
return node
pos = self.testspos
if self.scope_type == 'module':
path = node.entry.name
elif self.scope_type in ('pyclass', 'cclass'):
if isinstance(node, CFuncDefNode):
if node.py_func is not None:
name = node.py_func.name
else:
name = node.name
if self.scope_type == 'cclass' and name in self.blacklist:
return node
mod = ModuleRefNode(pos)
if self.scope_type == 'pyclass':
clsname = self.scope_node.name
else:
clsname = self.scope_node.class_name
parent = AttributeNode(pos, obj=mod,
attribute=clsname,
type=py_object_type,
is_py_attr=True,
is_temp=True)
if isinstance(node.entry.scope, Symtab.PropertyScope):
new_node = AttributeNode(pos, obj=parent,
attribute=node.entry.scope.name,
type=py_object_type,
is_py_attr=True,
is_temp=True)
parent = new_node
name = "%s.%s.%s" % (clsname, node.entry.scope.name,
node.entry.name)
else:
name = "%s.%s" % (clsname, node.entry.name)
name = node.entry.name
else:
assert False
getfunc = AttributeNode(pos, obj=parent,
attribute=node.entry.name,
type=py_object_type,
is_py_attr=True,
is_temp=True)
self.add_test(node.pos, name, getfunc)
name = node.name
if self.scope_type == 'cclass' and name in self.blacklist:
return node
if self.scope_type == 'pyclass':
class_name = self.scope_node.name
else:
class_name = self.scope_node.class_name
if isinstance(node.entry.scope, Symtab.PropertyScope):
property_method_name = node.entry.scope.name
path = "%s.%s.%s" % (class_name, node.entry.scope.name,
node.entry.name)
else:
path = "%s.%s" % (class_name, node.entry.name)
else:
assert False
self.add_test(node.pos, path, node.doc)
return node
......@@ -115,7 +115,7 @@ builtin_types_table = [
("copy", "O", "O", "PyDict_Copy")]),
("slice", "PySlice_Type", []),
("file", "PyFile_Type", []),
# ("file", "PyFile_Type", []), # not in Py3
("set", "PySet_Type", [("clear", "O", "i", "PySet_Clear"),
("discard", "OO", "i", "PySet_Discard"),
......@@ -128,8 +128,9 @@ types_that_construct_their_instance = (
# some builtin types do not always return an instance of
# themselves - these do:
'type', 'bool', 'long', 'float', 'bytes', 'unicode', 'tuple', 'list',
'dict', 'file', 'set', 'frozenset'
'dict', 'set', 'frozenset'
# 'str', # only in Py3.x
# 'file', # only in Py2.x
)
......
......@@ -274,7 +274,7 @@ class DependencyTree(object):
def find_pxd(self, module, filename=None):
if module[0] == '.':
raise NotImplementedError, "New relative imports."
raise NotImplementedError("New relative imports.")
if filename is not None:
relative = '.'.join(self.package(filename) + tuple(module.split('.')))
pxd = self.context.find_pxd_file(relative, None)
......@@ -291,9 +291,9 @@ class DependencyTree(object):
a = self.cimports(filename)
b = filter(None, [self.find_pxd(m, filename) for m in self.cimports(filename)])
if len(a) != len(b):
print (filename)
print ("\n\t".join(a))
print ("\n\t".join(b))
print(filename)
print("\n\t".join(a))
print("\n\t".join(b))
return tuple(self_pxd + filter(None, [self.find_pxd(m, filename) for m in self.cimports(filename)]))
cimported_files = cached_method(cimported_files)
......@@ -392,7 +392,7 @@ def create_extension_list(patterns, ctx=None, aliases=None):
base = DistutilsInfo(template)
exn_type = type(template)
else:
raise TypeError, pattern
raise TypeError(pattern)
for file in glob(filepattern):
pkg = deps.package(file)
if name == '*':
......@@ -428,7 +428,7 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None):
dep_timestamp, dep = deps.newest_dependency(source)
priority = 2 - (dep in deps.immediate_dependencies(source))
if c_timestamp < dep_timestamp:
print "Compiling", source, "because it depends on", dep
print("Compiling %s because it depends on %s" % (source, dep))
to_compile.append((priority, source, c_file))
new_sources.append(c_file)
else:
......@@ -441,22 +441,33 @@ def cythonize(module_list, ctx=None, nthreads=0, aliases=None):
try:
import multiprocessing
except ImportError:
print "multiprocessing required for parallel cythonization"
print("multiprocessing required for parallel cythonization")
nthreads = 0
pool = multiprocessing.Pool(nthreads)
pool.map(cythonoize_one_helper, to_compile)
pool.map(cythonize_one_helper, to_compile)
if not nthreads:
for priority, pyx_file, c_file in to_compile:
cythonoize_one(pyx_file, c_file)
cythonize_one(pyx_file, c_file)
return module_list
cython_py = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../cython.py'))
def cythonize_one(pyx_file, c_file, options=None):
from Cython.Compiler.Main import compile, CompilationOptions, default_options
from Cython.Compiler.Errors import CompileError, PyrexError
def cythonoize_one(pyx_file, c_file):
cmd = "%s %s %s -o %s" % (sys.executable, cython_py, pyx_file, c_file)
print cmd
if os.system(cmd) != 0:
raise CompilerError, pyx_file
if options is None:
options = CompilationOptions(default_options)
options.output_file = c_file
def cythonoize_one_helper(m):
return cythonoize_one(*m[1:])
any_failures = 0
try:
result = compile([pyx_file], options)
if result.num_errors > 0:
any_failures = 1
except (EnvironmentError, PyrexError), e:
sys.stderr.write(str(e) + '\n')
any_failures = 1
if any_failures:
raise CompileError(None, pyx_file)
def cythonize_one_helper(m):
return cythonize_one(*m[1:])
......@@ -39,7 +39,7 @@ def format_error(message, position):
if position:
pos_str = format_position(position)
cont = context(position)
message = u'\nError converting Pyrex file to C:\n%s\n%s%s' % (cont, pos_str, message or u'')
message = u'\nError compiling Cython file:\n%s\n%s%s' % (cont, pos_str, message or u'')
return message
class CompileError(PyrexError):
......
This diff is collapsed.
......@@ -37,7 +37,10 @@ def interpret_compiletime_options(optlist, optdict, type_env=None, type_args=())
def interpret(node, ix):
if ix in type_args:
if type_env:
return (node.analyse_as_type(type_env), node.pos)
type = node.analyse_as_type(type_env)
if not type:
raise CompileError(node.pos, "Invalid type.")
return (type, node.pos)
else:
raise CompileError(node.pos, "Type not allowed here.")
else:
......
......@@ -615,6 +615,25 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#endif")
code.put("""
#if (PY_MAJOR_VERSION < 3) || (PY_VERSION_HEX >= 0x03010300)
#define __Pyx_PySequence_GetSlice(obj, a, b) PySequence_GetSlice(obj, a, b)
#define __Pyx_PySequence_SetSlice(obj, a, b, value) PySequence_SetSlice(obj, a, b, value)
#define __Pyx_PySequence_DelSlice(obj, a, b) PySequence_DelSlice(obj, a, b)
#else
#define __Pyx_PySequence_GetSlice(obj, a, b) (unlikely(!(obj)) ? \\
(PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), (PyObject*)0) : \\
(likely((obj)->ob_type->tp_as_mapping) ? (PySequence_GetSlice(obj, a, b)) : \\
(PyErr_Format(PyExc_TypeError, "'%.200s' object is unsliceable", (obj)->ob_type->tp_name), (PyObject*)0)))
#define __Pyx_PySequence_SetSlice(obj, a, b, value) (unlikely(!(obj)) ? \\
(PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \\
(likely((obj)->ob_type->tp_as_mapping) ? (PySequence_SetSlice(obj, a, b, value)) : \\
(PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice assignment", (obj)->ob_type->tp_name), -1)))
#define __Pyx_PySequence_DelSlice(obj, a, b) (unlikely(!(obj)) ? \\
(PyErr_SetString(PyExc_SystemError, "null argument to internal routine"), -1) : \\
(likely((obj)->ob_type->tp_as_mapping) ? (PySequence_DelSlice(obj, a, b)) : \\
(PyErr_Format(PyExc_TypeError, "'%.200s' object doesn't support slice deletion", (obj)->ob_type->tp_name), -1)))
#endif
#if PY_MAJOR_VERSION >= 3
#define PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func))
#endif
......@@ -2097,12 +2116,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
type.vtabptr_cname,
code.error_goto(entry.pos)))
env.use_utility_code(Nodes.set_vtable_utility_code)
code.putln(
'if (__Pyx_SetAttrString(%s, "%s", (PyObject *)&%s) < 0) %s' % (
Naming.module_cname,
scope.class_name,
typeobj_cname,
code.error_goto(entry.pos)))
if not type.scope.is_internal and not type.scope.directives['internal']:
# scope.is_internal is set for types defined by
# Cython (such as closures), the 'internal'
# directive is set by users
code.putln(
'if (__Pyx_SetAttrString(%s, "%s", (PyObject *)&%s) < 0) %s' % (
Naming.module_cname,
scope.class_name,
typeobj_cname,
code.error_goto(entry.pos)))
weakref_entry = scope.lookup_here("__weakref__")
if weakref_entry:
if weakref_entry.type is py_object_type:
......
......@@ -899,13 +899,11 @@ class CVarDefNode(StatNode):
# declarators [CDeclaratorNode]
# in_pxd boolean
# api boolean
# properties [entry]
# decorators [cython.locals(...)] or None
# directive_locals { string : NameNode } locals defined by cython.locals(...)
child_attrs = ["base_type", "declarators"]
properties = ()
decorators = None
directive_locals = {}
......@@ -921,7 +919,6 @@ class CVarDefNode(StatNode):
# a property; made in AnalyseDeclarationsTransform).
if (dest_scope.is_c_class_scope
and self.visibility in ('public', 'readonly')):
self.properties = []
need_property = True
else:
need_property = False
......@@ -955,8 +952,7 @@ class CVarDefNode(StatNode):
"Only 'extern' C variable declaration allowed in .pxd file")
entry = dest_scope.declare_var(name, type, declarator.pos,
cname = cname, visibility = visibility, is_cdef = 1)
if need_property:
self.properties.append(entry)
entry.needs_property = need_property
class CStructOrUnionDefNode(StatNode):
......@@ -1284,7 +1280,9 @@ class FuncDefNode(StatNode, BlockNode):
acquire_gil = self.acquire_gil
if acquire_gil:
env.use_utility_code(force_init_threads_utility_code)
code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
code.putln("#endif")
# ----- set up refnanny
if not lenv.nogil:
code.put_setup_refcount_context(self.entry.name)
......@@ -1469,7 +1467,9 @@ class FuncDefNode(StatNode, BlockNode):
code.put_finish_refcount_context()
if acquire_gil:
code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_Release(_save);")
code.putln("#endif")
if not self.return_type.is_void:
code.putln("return %s;" % Naming.retval_cname)
......@@ -1959,6 +1959,9 @@ class DefNode(FuncDefNode):
# staticmethod() was overridden - not much we can do here ...
self.is_staticmethod = False
if self.name == '__new__':
self.is_staticmethod = 1
self.analyse_argument_types(env)
if self.name == '<lambda>':
self.declare_lambda_function(env)
......@@ -2203,9 +2206,11 @@ class DefNode(FuncDefNode):
def synthesize_assignment_node(self, env):
import ExprNodes
if env.is_py_class_scope:
rhs = ExprNodes.UnboundMethodNode(self.pos,
function = ExprNodes.PyCFunctionNode(self.pos,
pymethdef_cname = self.entry.pymethdef_cname))
rhs = ExprNodes.PyCFunctionNode(self.pos,
pymethdef_cname = self.entry.pymethdef_cname)
if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
elif env.is_closure_scope:
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
......@@ -3016,9 +3021,10 @@ class PyClassDefNode(ClassDefNode):
code.pyclass_stack.append(self)
cenv = self.scope
self.dict.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
self.body.generate_execution_code(code)
self.classobj.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
self.body.generate_execution_code(code)
self.target.generate_assignment_code(self.classobj, code)
self.dict.generate_disposal_code(code)
self.dict.free_temps(code)
......@@ -3104,7 +3110,12 @@ class CClassDefNode(ClassDefNode):
elif not base_class_entry.type.is_extension_type:
error(self.pos, "'%s' is not an extension type" % self.base_class_name)
elif not base_class_entry.type.is_complete():
error(self.pos, "Base class '%s' is incomplete" % self.base_class_name)
error(self.pos, "Base class '%s' of type '%s' is incomplete" % (
self.base_class_name, self.class_name))
elif base_class_entry.type.scope and base_class_entry.type.scope.directives and \
base_class_entry.type.scope.directives['final']:
error(self.pos, "Base class '%s' of type '%s' is final" % (
self.base_class_name, self.class_name))
else:
self.base_type = base_class_entry.type
has_body = self.body is not None
......@@ -5084,10 +5095,15 @@ class GILStatNode(TryFinallyStatNode):
def generate_execution_code(self, code):
code.mark_pos(self.pos)
code.putln("{")
if self.state == 'gil':
code.putln("{ PyGILState_STATE _save = PyGILState_Ensure();")
code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
code.putln("#endif")
else:
code.putln("{ PyThreadState *_save;")
code.putln("#ifdef WITH_THREAD")
code.putln("PyThreadState *_save;")
code.putln("#endif")
code.putln("Py_UNBLOCK_THREADS")
TryFinallyStatNode.generate_execution_code(self, code)
code.putln("}")
......@@ -5105,7 +5121,9 @@ class GILExitNode(StatNode):
def generate_execution_code(self, code):
if self.state == 'gil':
code.putln("PyGILState_Release();")
code.putln("#ifdef WITH_THREAD")
code.putln("PyGILState_Release(_save);")
code.putln("#endif")
else:
code.putln("Py_BLOCK_THREADS")
......
......@@ -62,10 +62,14 @@ directive_defaults = {
'wraparound' : True,
'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "",
'final' : False,
'internal' : False,
'profile': False,
'infer_types': None,
'infer_types.verbose': False,
'autotestdict': True,
'autotestdict.cdef': False,
'autotestdict.all': False,
'language_level': 2,
'warn': None,
......@@ -81,6 +85,8 @@ directive_defaults = {
# Override types possibilities above, if needed
directive_types = {
'final' : bool, # final cdef classes and methods
'internal' : bool, # cdef class visibility in the module dict
'infer_types' : bool, # values can be True/None/False
}
......@@ -90,7 +96,11 @@ for key, val in directive_defaults.items():
directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement'
'final' : ('cclass',), # add 'method' in the future
'internal' : ('cclass',),
'autotestdict' : ('module',),
'autotestdict.all' : ('module',),
'autotestdict.cdef' : ('module',),
'test_assert_path_exists' : ('function',),
'test_fail_if_path_exists' : ('function',),
}
......
......@@ -730,7 +730,18 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
return directives
directives.append(self.try_to_parse_directive(optname, args, kwds, node.function.pos))
return directives
elif isinstance(node, (AttributeNode, NameNode)):
self.visit(node)
optname = node.as_cython_attribute()
if optname:
directivetype = Options.directive_types.get(optname)
if directivetype is bool:
return [(optname, True)]
elif directivetype is None:
return [(optname, None)]
else:
raise PostParseError(
node.pos, "The '%s' directive should be used as a function call." % optname)
return None
def try_to_parse_directive(self, optname, args, kwds, pos):
......@@ -774,57 +785,68 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
# Handle decorators
def visit_FuncDefNode(self, node):
directives = []
if node.decorators:
# Split the decorators into two lists -- real decorators and directives
realdecs = []
for dec in node.decorators:
new_directives = self.try_to_parse_directives(dec.decorator)
if new_directives is not None:
directives.extend(new_directives)
directives = self._extract_directives(node, 'function')
if not directives:
return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives)
def visit_CVarDefNode(self, node):
if not node.decorators:
return node
for dec in node.decorators:
for directive in self.try_to_parse_directives(dec.decorator) or ():
if directive is not None and directive[0] == u'locals':
node.directive_locals = directive[1]
else:
realdecs.append(dec)
if realdecs and isinstance(node, CFuncDefNode):
raise PostParseError(realdecs[0].pos, "Cdef functions cannot take arbitrary decorators.")
self.context.nonfatal_error(PostParseError(dec.pos,
"Cdef functions can only take cython.locals() decorator."))
return node
def visit_CClassDefNode(self, node):
directives = self._extract_directives(node, 'cclass')
if not directives:
return self.visit_Node(node)
body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, directives)
def _extract_directives(self, node, scope_name):
if not node.decorators:
return {}
# Split the decorators into two lists -- real decorators and directives
directives = []
realdecs = []
for dec in node.decorators:
new_directives = self.try_to_parse_directives(dec.decorator)
if new_directives is not None:
for directive in new_directives:
if self.check_directive_scope(node.pos, directive[0], scope_name):
directives.append(directive)
else:
node.decorators = realdecs
if directives:
optdict = {}
directives.reverse() # Decorators coming first take precedence
for directive in directives:
name, value = directive
legal_scopes = Options.directive_scopes.get(name, None)
if not self.check_directive_scope(node.pos, name, 'function'):
continue
if name in optdict:
old_value = optdict[name]
# keywords and arg lists can be merged, everything
# else overrides completely
if isinstance(old_value, dict):
old_value.update(value)
elif isinstance(old_value, list):
old_value.extend(value)
else:
optdict[name] = value
realdecs.append(dec)
if realdecs and isinstance(node, (CFuncDefNode, CClassDefNode)):
raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.")
else:
node.decorators = realdecs
# merge or override repeated directives
optdict = {}
directives.reverse() # Decorators coming first take precedence
for directive in directives:
name, value = directive
if name in optdict:
old_value = optdict[name]
# keywords and arg lists can be merged, everything
# else overrides completely
if isinstance(old_value, dict):
old_value.update(value)
elif isinstance(old_value, list):
old_value.extend(value)
else:
optdict[name] = value
body = StatListNode(node.pos, stats=[node])
return self.visit_with_directives(body, optdict)
else:
return self.visit_Node(node)
def visit_CVarDefNode(self, node):
if node.decorators:
for dec in node.decorators:
for directive in self.try_to_parse_directives(dec.decorator) or []:
if directive is not None and directive[0] == u'locals':
node.directive_locals = directive[1]
else:
self.context.nonfatal_error(PostParseError(dec.pos,
"Cdef functions can only take cython.locals() decorator."))
return node
else:
optdict[name] = value
return optdict
# Handle with statements
def visit_WithStatNode(self, node):
directive_dict = {}
......@@ -835,6 +857,10 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
PostParseError(node.pos, "Compiler directive with statements cannot contain 'as'"))
else:
name, value = directive
if name == 'nogil':
# special case: in pure mode, "with nogil" spells "with cython.nogil"
node = GILStatNode(node.pos, state = "nogil", body = node.body)
return self.visit_Node(node)
if self.check_directive_scope(node.pos, name, 'with statement'):
directive_dict[name] = value
if directive_dict:
......@@ -932,9 +958,8 @@ class DecoratorTransform(CythonTransform, SkipDeclarations):
return self._handle_decorators(
func_node, func_node.name)
def _visit_CClassDefNode(self, class_node):
# This doesn't currently work, so it's disabled (also in the
# parser).
def visit_CClassDefNode(self, class_node):
# This doesn't currently work, so it's disabled.
#
# Problem: assignments to cdef class names do not work. They
# would require an additional check anyway, as the extension
......@@ -944,8 +969,11 @@ class DecoratorTransform(CythonTransform, SkipDeclarations):
self.visitchildren(class_node)
if not class_node.decorators:
return class_node
return self._handle_decorators(
class_node, class_node.class_name)
error(class_node.pos,
"Decorators not allowed on cdef classes (used on type '%s')" % class_node.class_name)
return class_node
#return self._handle_decorators(
# class_node, class_node.class_name)
def visit_ClassDefNode(self, class_node):
self.visitchildren(class_node)
......@@ -1021,6 +1049,20 @@ property NAME:
self.visitchildren(node)
self.env_stack.pop()
return node
def visit_CClassDefNode(self, node):
node = self.visit_ClassDefNode(node)
if node.scope and node.scope.implemented:
stats = []
for entry in node.scope.var_entries:
if entry.needs_property:
property = self.create_Property(entry)
property.analyse_declarations(node.scope)
self.visit(property)
stats.append(property)
if stats:
node.body.stats += stats
return node
def visit_FuncDefNode(self, node):
self.seen_vars_stack.append(set())
......@@ -1096,20 +1138,9 @@ property NAME:
return node
def visit_CVarDefNode(self, node):
# to ensure all CNameDeclaratorNodes are visited.
self.visitchildren(node)
if node.properties:
stats = []
for entry in node.properties:
property = self.create_Property(entry)
property.analyse_declarations(node.dest_scope)
self.visit(property)
stats.append(property)
return StatListNode(pos=node.pos, stats=stats)
else:
return None
return None
def create_Property(self, entry):
if entry.visibility == 'public':
......@@ -1269,6 +1300,7 @@ class CreateClosureClasses(CythonTransform):
func_scope.scope_class = entry
class_scope = entry.type.scope
class_scope.is_internal = True
class_scope.directives = {'final': True}
if node.entry.scope.is_closure_scope:
class_scope.declare_var(pos=node.pos,
name=Naming.outer_scope_cname, # this could conflict?
......
......@@ -149,7 +149,7 @@ cpdef p_ctypedef_statement(PyrexScanner s, ctx)
cpdef p_decorators(PyrexScanner s)
cpdef p_def_statement(PyrexScanner s, list decorators = *)
cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
cpdef p_py_arg_decl(PyrexScanner s)
cpdef p_py_arg_decl(PyrexScanner s, bint annotated = *)
cpdef p_class_statement(PyrexScanner s, decorators)
cpdef p_c_class_definition(PyrexScanner s, pos, ctx)
cpdef p_c_class_options(PyrexScanner s)
......
......@@ -497,20 +497,16 @@ def p_subscript(s):
# 1, 2 or 3 ExprNodes, depending on how
# many slice elements were encountered.
pos = s.position()
if s.sy == '.':
expect_ellipsis(s)
return [ExprNodes.EllipsisNode(pos)]
else:
start = p_slice_element(s, (':',))
if s.sy != ':':
return [start]
s.next()
stop = p_slice_element(s, (':', ',', ']'))
if s.sy != ':':
return [start, stop]
s.next()
step = p_slice_element(s, (':', ',', ']'))
return [start, stop, step]
start = p_slice_element(s, (':',))
if s.sy != ':':
return [start]
s.next()
stop = p_slice_element(s, (':', ',', ']'))
if s.sy != ':':
return [start, stop]
s.next()
step = p_slice_element(s, (':', ',', ']'))
return [start, stop, step]
def p_slice_element(s, follow_set):
# Simple expression which may be missing iff
......@@ -569,6 +565,9 @@ def p_atom(s):
return p_dict_or_set_maker(s)
elif sy == '`':
return p_backquote_expr(s)
elif sy == '.':
expect_ellipsis(s)
return ExprNodes.EllipsisNode(pos)
elif sy == 'INT':
value = s.systring
s.next()
......@@ -1504,50 +1503,62 @@ def p_include_statement(s, ctx):
return Nodes.PassStatNode(pos)
def p_with_statement(s):
pos = s.position()
s.next() # 'with'
# if s.sy == 'IDENT' and s.systring in ('gil', 'nogil'):
if s.sy == 'IDENT' and s.systring == 'nogil':
if s.systring == 'template' and not s.in_python_file:
node = p_with_template(s)
else:
node = p_with_items(s)
return node
def p_with_items(s):
pos = s.position()
if not s.in_python_file and s.sy == 'IDENT' and s.systring == 'nogil':
state = s.systring
s.next()
body = p_suite(s)
return Nodes.GILStatNode(pos, state = state, body = body)
elif s.systring == 'template':
templates = []
s.next()
s.expect('[')
#s.next()
templates.append(s.systring)
s.next()
while s.systring == ',':
s.next()
templates.append(s.systring)
s.next()
s.expect(']')
if s.sy == ':':
if s.sy == ',':
s.next()
s.expect_newline("Syntax error in template function declaration")
s.expect_indent()
body_ctx = Ctx()
body_ctx.templates = templates
func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
s.expect_dedent()
return func_or_var
body = p_with_items(s)
else:
error(pos, "Syntax error in template function declaration")
body = p_suite(s)
return Nodes.GILStatNode(pos, state = state, body = body)
else:
manager = p_test(s)
target = None
if s.sy == 'IDENT' and s.systring == 'as':
s.next()
allow_multi = (s.sy == '(')
target = p_target(s, ':')
if not allow_multi and isinstance(target, ExprNodes.TupleNode):
s.error("Multiple with statement target values not allowed without paranthesis")
body = p_suite(s)
target = p_starred_expr(s)
if s.sy == ',':
s.next()
body = p_with_items(s)
else:
body = p_suite(s)
return Nodes.WithStatNode(pos, manager = manager,
target = target, body = body)
def p_with_template(s):
pos = s.position()
templates = []
s.next()
s.expect('[')
templates.append(s.systring)
s.next()
while s.systring == ',':
s.next()
templates.append(s.systring)
s.next()
s.expect(']')
if s.sy == ':':
s.next()
s.expect_newline("Syntax error in template function declaration")
s.expect_indent()
body_ctx = Ctx()
body_ctx.templates = templates
func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
s.expect_dedent()
return func_or_var
else:
error(pos, "Syntax error in template function declaration")
def p_simple_statement(s, first_statement = 0):
#print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global':
......@@ -1682,8 +1693,8 @@ def p_statement(s, ctx, first_statement = 0):
s.level = ctx.level
node = p_cdef_statement(s, ctx(overridable = overridable))
if decorators is not None:
if not isinstance(node, (Nodes.CFuncDefNode, Nodes.CVarDefNode)):
s.error("Decorators can only be followed by functions or Python classes")
if not isinstance(node, (Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode)):
s.error("Decorators can only be followed by functions or classes")
node.decorators = decorators
return node
else:
......@@ -2569,23 +2580,23 @@ def p_varargslist(s, terminator=')', annotated=1):
if s.sy == '*':
s.next()
if s.sy == 'IDENT':
star_arg = p_py_arg_decl(s)
star_arg = p_py_arg_decl(s, annotated=annotated)
if s.sy == ',':
s.next()
args.extend(p_c_arg_list(s, in_pyfunc = 1,
nonempty_declarators = 1, kw_only = 1))
nonempty_declarators = 1, kw_only = 1, annotated = annotated))
elif s.sy != terminator:
s.error("Syntax error in Python function argument list")
if s.sy == '**':
s.next()
starstar_arg = p_py_arg_decl(s)
starstar_arg = p_py_arg_decl(s, annotated=annotated)
return (args, star_arg, starstar_arg)
def p_py_arg_decl(s):
def p_py_arg_decl(s, annotated = 1):
pos = s.position()
name = p_ident(s)
annotation = None
if s.sy == ':':
if annotated and s.sy == ':':
s.next()
annotation = p_test(s)
return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
......
......@@ -1072,6 +1072,7 @@ class CComplexType(CNumericType):
None,
visibility="extern")
scope.parent_type = self
scope.directives = {}
scope.declare_var("real", self.real_type, None, "real", is_cdef=True)
scope.declare_var("imag", self.real_type, None, "imag", is_cdef=True)
entry = scope.declare_cfunction(
......@@ -1095,7 +1096,8 @@ class CComplexType(CNumericType):
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix))
m = self.funcsuffix,
is_float = self.real_type.is_float))
return True
def create_to_py_utility_code(self, env):
......@@ -1112,7 +1114,8 @@ class CComplexType(CNumericType):
utility_code.specialize(
self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix))
m = self.funcsuffix,
is_float = self.real_type.is_float))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name()
return True
......@@ -1271,11 +1274,17 @@ proto="""
#ifdef __cplusplus
#define __Pyx_c_is_zero%(m)s(z) ((z)==(%(real_type)s)0)
#define __Pyx_c_conj%(m)s(z) (::std::conj(z))
/*#define __Pyx_c_abs%(m)s(z) (::std::abs(z))*/
#if %(is_float)s
#define __Pyx_c_abs%(m)s(z) (::std::abs(z))
#define __Pyx_c_pow%(m)s(a, b) (::std::pow(a, b))
#endif
#else
#define __Pyx_c_is_zero%(m)s(z) ((z)==0)
#define __Pyx_c_conj%(m)s(z) (conj%(m)s(z))
/*#define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))*/
#if %(is_float)s
#define __Pyx_c_abs%(m)s(z) (cabs%(m)s(z))
#define __Pyx_c_pow%(m)s(a, b) (cpow%(m)s(a, b))
#endif
#endif
#else
static CYTHON_INLINE int __Pyx_c_eq%(m)s(%(type)s, %(type)s);
......@@ -1286,7 +1295,10 @@ proto="""
static CYTHON_INLINE %(type)s __Pyx_c_neg%(m)s(%(type)s);
static CYTHON_INLINE int __Pyx_c_is_zero%(m)s(%(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_conj%(m)s(%(type)s);
/*static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);*/
#if %(is_float)s
static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s);
static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s, %(type)s);
#endif
#endif
""",
impl="""
......@@ -1335,15 +1347,60 @@ impl="""
z.imag = -a.imag;
return z;
}
/*
static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
#if HAVE_HYPOT
return hypot%(m)s(z.real, z.imag);
#else
return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
#endif
}
*/
#if %(is_float)s
static CYTHON_INLINE %(real_type)s __Pyx_c_abs%(m)s(%(type)s z) {
#if HAVE_HYPOT
return hypot%(m)s(z.real, z.imag);
#else
return sqrt%(m)s(z.real*z.real + z.imag*z.imag);
#endif
}
static CYTHON_INLINE %(type)s __Pyx_c_pow%(m)s(%(type)s a, %(type)s b) {
%(type)s z;
%(real_type)s r, lnr, theta, z_r, z_theta;
if (b.imag == 0 && b.real == (int)b.real) {
if (b.real < 0) {
%(real_type)s denom = a.real * a.real + a.imag * a.imag;
a.real = a.real / denom;
a.imag = -a.imag / denom;
b.real = -b.real;
}
switch ((int)b.real) {
case 0:
z.real = 1;
z.imag = 0;
return z;
case 1:
return a;
case 2:
z = __Pyx_c_prod%(m)s(a, a);
return __Pyx_c_prod%(m)s(a, a);
case 3:
z = __Pyx_c_prod%(m)s(a, a);
return __Pyx_c_prod%(m)s(z, a);
case 4:
z = __Pyx_c_prod%(m)s(a, a);
return __Pyx_c_prod%(m)s(z, z);
}
}
if (a.imag == 0) {
if (a.real == 0) {
return a;
}
r = a.real;
theta = 0;
} else {
r = __Pyx_c_abs%(m)s(a);
theta = atan2%(m)s(a.imag, a.real);
}
lnr = log%(m)s(r);
z_r = exp%(m)s(lnr * b.real - theta * b.imag);
z_theta = theta * b.real + lnr * b.imag;
z.real = z_r * cos%(m)s(z_theta);
z.imag = z_r * sin%(m)s(z_theta);
return z;
}
#endif
#endif
""")
......
......@@ -70,6 +70,7 @@ class Entry(object):
# or class attribute during
# class construction
# is_member boolean Is an assigned class member
# is_real_dict boolean Is a real dict, PyClass attributes dict
# is_variable boolean Is a variable
# is_cfunction boolean Is a C function
# is_cmethod boolean Is a C method of an extension type
......@@ -131,6 +132,7 @@ class Entry(object):
is_cglobal = 0
is_pyglobal = 0
is_member = 0
is_real_dict = 0
is_variable = 0
is_cfunction = 0
is_cmethod = 0
......@@ -246,7 +248,7 @@ class Scope(object):
self.qualified_name = qual_scope.qualify_name(name)
self.scope_prefix = qual_scope.scope_prefix + mangled_name
else:
self.qualified_name = name
self.qualified_name = EncodedString(name)
self.scope_prefix = mangled_name
self.entries = {}
self.const_entries = []
......@@ -348,7 +350,7 @@ class Scope(object):
return entry
def qualify_name(self, name):
return "%s.%s" % (self.qualified_name, name)
return EncodedString("%s.%s" % (self.qualified_name, name))
def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
# Add an entry for a named constant.
......@@ -726,7 +728,11 @@ class BuiltinScope(Scope):
def declare_builtin_type(self, name, cname, utility_code = None):
name = EncodedString(name)
type = PyrexTypes.BuiltinObjectType(name, cname)
type.set_scope(CClassScope(name, outer_scope=None, visibility='extern'))
scope = CClassScope(name, outer_scope=None, visibility='extern')
scope.directives = {}
if name == 'bool':
scope.directives['final'] = True
type.set_scope(scope)
self.type_names[name] = 1
entry = self.declare_type(name, type, None, visibility='extern')
entry.utility_code = utility_code
......@@ -768,7 +774,7 @@ class BuiltinScope(Scope):
"frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
"slice": ["((PyObject*)&PySlice_Type)", py_object_type],
"file": ["((PyObject*)&PyFile_Type)", py_object_type],
# "file": ["((PyObject*)&PyFile_Type)", py_object_type], # not in Py3
"None": ["Py_None", py_object_type],
"False": ["Py_False", py_object_type],
......@@ -813,6 +819,7 @@ class ModuleScope(Scope):
# Treat Spam/__init__.pyx specially, so that when Python loads
# Spam/__init__.so, initSpam() is defined.
self.module_name = parent_module.module_name
self.module_name = EncodedString(self.module_name)
self.context = context
self.module_cname = Naming.module_cname
self.module_dict_cname = Naming.moddict_cname
......@@ -1400,6 +1407,7 @@ class PyClassScope(ClassScope):
entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef)
entry.is_pyglobal = 1
entry.is_real_dict = 1
return entry
def add_default_value(self, type):
......@@ -1763,8 +1771,13 @@ static PyObject* __Pyx_Method_ClassMethod(PyObject *method) {
else if (PyCFunction_Check(method)) {
return PyClassMethod_New(method);
}
#ifdef __pyx_binding_PyCFunctionType_USED
else if (PyObject_TypeCheck(method, __pyx_binding_PyCFunctionType)) { /* binded CFunction */
return PyClassMethod_New(method);
}
#endif
PyErr_Format(PyExc_TypeError,
"Class-level classmethod() can only be called on"
"Class-level classmethod() can only be called on "
"a method_descriptor or instance method.");
return NULL;
}
......
......@@ -60,6 +60,7 @@ def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None):
scope = scope, context = context, initial_pos = initial_pos)
if level is None:
tree = Parsing.p_module(scanner, 0, module_name)
tree.scope = scope
else:
tree = Parsing.p_code(scanner, level=level)
return tree
......@@ -201,6 +202,8 @@ class TreeFragment(object):
if not isinstance(t, StatListNode):
t = StatListNode(pos=mod.pos, stats=[t])
for transform in pipeline:
if transform is None:
continue
t = transform(t)
self.root = t
elif isinstance(code, Node):
......
......@@ -323,7 +323,9 @@ class TypeFlagsSlot(SlotDescriptor):
# Descriptor for the type flags slot.
def slot_code(self, scope):
value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER"
value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER"
if not scope.directives['final']:
value += "|Py_TPFLAGS_BASETYPE"
if scope.needs_gc():
value += "|Py_TPFLAGS_HAVE_GC"
return value
......
version = '0.13'
# for backwards compatibility
from Cython import __version__ as version
......@@ -3,14 +3,15 @@
Implements a version of the Distutils 'build_ext' command, for
building Cython extension modules."""
# This module should be kept compatible with Python 2.1.
# This module should be kept compatible with Python 2.3.
__revision__ = "$Id:$"
import sys, os, re
from types import *
import sys
import os
import re
from distutils.core import Command
from distutils.errors import *
from distutils.errors import DistutilsPlatformError
from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer, newer_group
from distutils import log
......@@ -70,7 +71,7 @@ class build_ext(_build_ext.build_ext):
_build_ext.build_ext.finalize_options(self)
if self.pyrex_include_dirs is None:
self.pyrex_include_dirs = []
elif type(self.pyrex_include_dirs) is StringType:
elif isinstance(self.pyrex_include_dirs, basestring):
self.pyrex_include_dirs = \
self.pyrex_include_dirs.split(os.pathsep)
if self.pyrex_directives is None:
......
cdef extern from "Python.h":
ctypedef long long PY_LONG_LONG
ctypedef unsigned long long uPY_LONG_LONG
ctypedef unsigned long long uPY_LONG_LONG "unsigned PY_LONG_LONG"
############################################################################
# 7.2.3 Long Integer Objects
......
......@@ -12,8 +12,8 @@ cdef extern from "<deque>" namespace "std":
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
......
......@@ -10,8 +10,8 @@ cdef extern from "<list>" namespace "std":
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
......@@ -30,6 +30,7 @@ cdef extern from "<list>" namespace "std":
T& back()
iterator begin()
#const_iterator begin()
void clear()
bint empty()
iterator end()
#const_iterator end()
......
from pair cimport pair
from utility cimport pair
cdef extern from "<map>" namespace "std":
cdef cppclass map[T, U]:
......@@ -9,11 +9,11 @@ cdef extern from "<map>" namespace "std":
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
pair[T,U] operator*()
pair[T,U]& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
......
cdef extern from "<utility>" namespace "std":
cdef cppclass pair[T, U]:
T first
U second
pair()
pair(pair&)
pair(T&, U&)
from utility cimport pair
......@@ -3,17 +3,17 @@ from pair cimport pair
cdef extern from "<set>" namespace "std":
cdef cppclass set[T]:
cppclass iterator:
T operator*()
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
T operator*()
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
......
cdef extern from "<utility>" namespace "std":
cdef cppclass pair[T, U]:
T first
U second
pair()
pair(pair&)
pair(T&, U&)
bint operator==(pair&, pair&)
bint operator!=(pair&, pair&)
bint operator<(pair&, pair&)
bint operator>(pair&, pair&)
bint operator<=(pair&, pair&)
bint operator>=(pair&, pair&)
......@@ -6,12 +6,20 @@ cdef extern from "<vector>" namespace "std":
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator<(iterator)
bint operator>(iterator)
bint operator<=(iterator)
bint operator>=(iterator)
cppclass reverse_iterator:
T& operator*()
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
bint operator<(reverse_iterator)
bint operator>(reverse_iterator)
bint operator<=(reverse_iterator)
bint operator>=(reverse_iterator)
#cppclass const_iterator(iterator):
# pass
#cppclass const_reverse_iterator(reverse_iterator):
......
# cython.* namespace for pure mode.
compiled = False
def empty_decorator(x):
return x
# Function decorators
def locals(**arg_types):
return empty_decorator
def inline(f, *args, **kwds):
if isinstance(f, basestring):
from Cython.Build.Inline import cython_inline
return cython_inline(f, *args, **kwds)
else:
assert len(args) == len(kwds) == 0
return f
# Special functions
def cdiv(a, b):
......@@ -46,6 +58,17 @@ def declare(type=None, value=None, **kwds):
else:
return value
class _nogil(object):
"""Support for 'with nogil' statement
"""
def __enter__(self):
pass
def __exit__(self, exc_class, exc, tb):
return exc_class is None
nogil = _nogil()
del _nogil
# Emulated types
class CythonType(object):
......
......@@ -115,7 +115,7 @@ class NormalisedNewlineStream(object):
self.close = stream.close
self.encoding = getattr(stream, 'encoding', 'UTF-8')
def read(self, count):
def read(self, count=-1):
data = self._read(count)
if u'\r' not in data:
return data
......
__version__ = "0.13"
# Void cython.* directives (for case insensitive operating systems).
from Cython.Shadow import *
......@@ -117,7 +117,7 @@ class ErrorWriter(object):
class TestBuilder(object):
def __init__(self, rootdir, workdir, selectors, exclude_selectors, annotate,
cleanup_workdir, cleanup_sharedlibs, with_pyregr, cython_only,
languages, test_bugs, fork):
languages, test_bugs, fork, language_level):
self.rootdir = rootdir
self.workdir = workdir
self.selectors = selectors
......@@ -130,6 +130,7 @@ class TestBuilder(object):
self.languages = languages
self.test_bugs = test_bugs
self.fork = fork
self.language_level = language_level
def build_suite(self):
suite = unittest.TestSuite()
......@@ -190,6 +191,9 @@ class TestBuilder(object):
for test in self.build_tests(test_class, path, workdir,
module, expect_errors):
suite.addTest(test)
if context == 'run' and filename.endswith('.py'):
# additionally test file in real Python
suite.addTest(PureDoctestTestCase(module, os.path.join(path, filename)))
return suite
def build_tests(self, test_class, path, workdir, module, expect_errors):
......@@ -220,12 +224,14 @@ class TestBuilder(object):
cleanup_workdir=self.cleanup_workdir,
cleanup_sharedlibs=self.cleanup_sharedlibs,
cython_only=self.cython_only,
fork=self.fork)
fork=self.fork,
language_level=self.language_level)
class CythonCompileTestCase(unittest.TestCase):
def __init__(self, test_directory, workdir, module, language='c',
expect_errors=False, annotate=False, cleanup_workdir=True,
cleanup_sharedlibs=True, cython_only=False, fork=True):
cleanup_sharedlibs=True, cython_only=False, fork=True,
language_level=2):
self.test_directory = test_directory
self.workdir = workdir
self.module = module
......@@ -236,6 +242,7 @@ class CythonCompileTestCase(unittest.TestCase):
self.cleanup_sharedlibs = cleanup_sharedlibs
self.cython_only = cython_only
self.fork = fork
self.language_level = language_level
unittest.TestCase.__init__(self)
def shortDescription(self):
......@@ -339,6 +346,7 @@ class CythonCompileTestCase(unittest.TestCase):
annotate = annotate,
use_listing_file = False,
cplus = self.language == 'cpp',
language_level = self.language_level,
generate_pxi = False,
evaluate_tree_assertions = True,
)
......@@ -494,6 +502,38 @@ class CythonRunTestCase(CythonCompileTestCase):
try: os.unlink(result_file)
except: pass
class PureDoctestTestCase(unittest.TestCase):
def __init__(self, module_name, module_path):
self.module_name = module_name
self.module_path = module_path
unittest.TestCase.__init__(self, 'run')
def shortDescription(self):
return "running pure doctests in %s" % self.module_name
def run(self, result=None):
if result is None:
result = self.defaultTestResult()
loaded_module_name = 'pure_doctest__' + self.module_name
result.startTest(self)
try:
self.setUp()
import imp
m = imp.load_source(loaded_module_name, self.module_path)
try:
doctest.DocTestSuite(m).run(result)
finally:
del m
if loaded_module_name in sys.modules:
del sys.modules[loaded_module_name]
except Exception:
result.addError(self, sys.exc_info())
result.stopTest(self)
try:
self.tearDown()
except Exception:
pass
is_private_field = re.compile('^_[^_]').match
......@@ -645,6 +685,14 @@ class EndToEndTest(unittest.TestCase):
self.treefile = treefile
self.workdir = os.path.join(workdir, os.path.splitext(treefile)[0])
self.cleanup_workdir = cleanup_workdir
cython_syspath = self.cython_root
for path in sys.path[::-1]:
if path.startswith(self.cython_root):
# Py3 installation and refnanny build prepend their
# fixed paths to sys.path => prefer that over the
# generic one
cython_syspath = path + os.pathsep + cython_syspath
self.cython_syspath = cython_syspath
unittest.TestCase.__init__(self)
def shortDescription(self):
......@@ -667,11 +715,16 @@ class EndToEndTest(unittest.TestCase):
commands = (self.commands
.replace("CYTHON", "PYTHON %s" % os.path.join(self.cython_root, 'cython.py'))
.replace("PYTHON", sys.executable))
commands = """
PYTHONPATH="%s%s$PYTHONPATH"
%s
""" % (self.cython_root, os.pathsep, commands)
self.assertEqual(0, os.system(commands))
old_path = os.environ.get('PYTHONPATH')
try:
os.environ['PYTHONPATH'] = self.cython_syspath + os.pathsep + (old_path or '')
print(os.environ['PYTHONPATH'])
self.assertEqual(0, os.system(commands))
finally:
if old_path:
os.environ['PYTHONPATH'] = old_path
else:
del os.environ['PYTHONPATH']
# TODO: Support cython_freeze needed here as well.
......@@ -750,10 +803,14 @@ class FileListExcluder:
def __init__(self, list_file):
self.excludes = {}
for line in open(list_file).readlines():
line = line.strip()
if line and line[0] != '#':
self.excludes[line.split()[0]] = True
f = open(list_file)
try:
for line in f.readlines():
line = line.strip()
if line and line[0] != '#':
self.excludes[line.split()[0]] = True
finally:
f.close()
def __call__(self, testname):
return testname in self.excludes or testname.split('.')[-1] in self.excludes
......@@ -842,6 +899,9 @@ if __name__ == '__main__':
parser.add_option("-T", "--ticket", dest="tickets",
action="append",
help="a bug ticket number to run the respective test in 'tests/*'")
parser.add_option("-3", dest="language_level",
action="store_const", const=3, default=2,
help="set language level to Python 3 (useful for running the CPython regression tests)'")
parser.add_option("--xml-output", dest="xml_output_dir", metavar="DIR",
help="write test results in XML to directory DIR")
parser.add_option("--exit-ok", dest="exit_ok", default=False,
......@@ -861,6 +921,8 @@ if __name__ == '__main__':
# try if Cython is installed in a Py3 version
import Cython.Compiler.Main
except Exception:
# back out anything the import process loaded, then
# 2to3 the Cython sources to make them re-importable
cy_modules = [ name for name in sys.modules
if name == 'Cython' or name.startswith('Cython.') ]
for name in cy_modules:
......@@ -908,13 +970,13 @@ if __name__ == '__main__':
if not os.path.exists(WORKDIR):
os.makedirs(WORKDIR)
sys.stderr.write("Python %s\n" % sys.version)
sys.stderr.write("\n")
if WITH_CYTHON:
from Cython.Compiler.Version import version
sys.stderr.write("Running tests against Cython %s\n" % version)
else:
sys.stderr.write("Running tests without Cython.\n")
sys.stderr.write("Python %s\n" % sys.version)
sys.stderr.write("\n")
if options.with_refnanny:
from pyximport.pyxbuild import pyx_to_dll
......@@ -929,6 +991,11 @@ if __name__ == '__main__':
sys.stderr.write("Disabling forked testing to support XML test output\n")
options.fork = False
if WITH_CYTHON and options.language_level == 3:
sys.stderr.write("Using Cython language level 3.\n")
sys.stderr.write("\n")
test_bugs = False
if options.tickets:
for ticket_number in options.tickets:
......@@ -979,7 +1046,7 @@ if __name__ == '__main__':
options.annotate_source, options.cleanup_workdir,
options.cleanup_sharedlibs, options.pyregr,
options.cython_only, languages, test_bugs,
options.fork)
options.fork, options.language_level)
test_suite.addTest(filetests.build_suite())
if options.system_pyregr and languages:
......@@ -987,7 +1054,7 @@ if __name__ == '__main__':
options.annotate_source, options.cleanup_workdir,
options.cleanup_sharedlibs, True,
options.cython_only, languages, test_bugs,
options.fork)
options.fork, options.language_level)
test_suite.addTest(
filetests.handle_directory(
os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
......
......@@ -106,12 +106,19 @@ def compile_cython_modules(profile=False):
)
class build_ext(build_ext_orig):
# we must keep the original modules alive to make sure
# their code keeps working when we remove them from
# sys.modules
dead_modules = []
def build_extensions(self):
# add path where 2to3 installed the transformed sources
# and make sure Python (re-)imports them from there
already_imported = [ module for module in sys.modules
if module == 'Cython' or module.startswith('Cython.') ]
keep_alive = self.dead_modules.append
for module in already_imported:
keep_alive(sys.modules[module])
del sys.modules[module]
sys.path.insert(0, os.path.join(source_root, self.build_lib))
......@@ -190,7 +197,7 @@ except ValueError:
setup_args.update(setuptools_extra_args)
from Cython.Compiler.Version import version
from Cython import __version__ as version
setup(
name = 'Cython',
......
#from ... import foo
print ...
def test():
x = ...
assert x is Ellipsis
......@@ -10,6 +10,7 @@ def f():
cdef object[int,2,3,4,5,6] buf4
cdef object[int, 2, 'foo'] buf5
cdef object[int, 2, well] buf6
cdef object[x, 1] buf0
_ERRORS = u"""
1:17: Buffer types only allowed as function local variables
......@@ -23,5 +24,6 @@ _ERRORS = u"""
#10:15: Too many buffer options
#11:24: Only allowed buffer modes are "full" or "strided" (as a compile-time string)
#12:28: Only allowed buffer modes are "full" or "strided" (as a compile-time string)
#13:17: Invalid type.
#"""
cimport cython
@cython.final
cdef class FinalClass:
pass
cdef class SubType(FinalClass):
pass
_ERRORS = """
8:5: Base class 'FinalClass' of type 'SubType' is final
"""
# Directive defaults to True
"""
Tests doctesthack compiler directive.
Tests autotestdict compiler directive.
The doctests are actually run as part of this test;
which makes the test flow a bit untraditional. Both
module test and individual tests are run; finally,
Both module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print('%s ; %s' % (key, value))
MyCdefClass.cpdef_method (line 78) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 75) ; >>> add_log("cdef class method")
MyClass.method (line 65) ; >>> add_log("class method")
doc_without_test (line 47) ; Some docs
mycpdeffunc (line 53) ; >>> add_log("cpdef")
myfunc (line 44) ; >>> add_log("def")
MyCdefClass.cpdef_method (line 76) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 73) ; >>> add_log("cdef class method")
MyClass.method (line 62) ; >>> add_log("class method")
mycpdeffunc (line 49) ; >>> add_log("cpdef")
myfunc (line 40) ; >>> add_log("def")
"""
......@@ -25,19 +22,18 @@ log = []
cdef cdeffunc():
"""
Please don't include me!
>>> True
False
"""
cdeffunc() # make sure it's being used
def all_tests_run():
log.sort()
assert log == [u'cdef class method', u'class method', u'cpdef', u'def'], log
assert log == [u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s):
log.append(unicode(s))
if len(log) == len(__test__):
if len(log) == len(__test__) + 2:
# Final per-function doctest executed
all_tests_run()
......@@ -58,6 +54,7 @@ class MyClass:
"""
Needs no hack
>>> add_log("class")
>>> True
True
"""
......@@ -68,7 +65,8 @@ class MyClass:
cdef class MyCdefClass:
"""
Needs no hack
>>> add_log("cdef class")
>>> True
True
"""
......@@ -78,6 +76,9 @@ cdef class MyCdefClass:
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
......@@ -141,5 +142,3 @@ cdef class MyOtherCdefClass:
>>> True
False
"""
cdeffunc()
# cython: autotestdict.all=True
"""
Tests autotestdict compiler directive.
Both module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print('%s ; %s' % (key, value))
MyCdefClass.cdef_method (line 79) ; >>> add_log("cdef class method")
MyCdefClass.cpdef_method (line 76) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 73) ; >>> add_log("cdef class method")
MyClass.method (line 62) ; >>> add_log("class method")
cdeffunc (line 26) ; >>> add_log("cdef")
doc_without_test (line 43) ; Some docs
mycpdeffunc (line 49) ; >>> add_log("cpdef")
myfunc (line 40) ; >>> add_log("def")
"""
log = []
cdef cdeffunc():
""">>> add_log("cdef")"""
cdeffunc() # make sure it's being used
def all_tests_run():
log.sort()
assert log == [u'cdef', u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s):
log.append(unicode(s))
if len(log) == len(__test__):
# Final per-function doctest executed
all_tests_run()
def myfunc():
""">>> add_log("def")"""
def doc_without_test():
"""Some docs"""
def nodocstring():
pass
cpdef mycpdeffunc():
""">>> add_log("cpdef")"""
class MyClass:
"""
Needs no hack
>>> add_log("class")
>>> True
True
"""
def method(self):
""">>> add_log("class method")"""
cdef class MyCdefClass:
"""
Needs no hack
>>> add_log("cdef class")
>>> True
True
"""
def method(self):
""">>> add_log("cdef class method")"""
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __dealloc__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __richcmp__(self, other, int op):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
def __nonzero__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __len__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __contains__(self, value):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
cdef class MyOtherCdefClass:
"""
Needs no hack
>>> True
True
"""
def __bool__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
# cython: autotestdict.cdef=True
"""
Tests autotestdict compiler directive.
Both module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print('%s ; %s' % (key, value))
MyCdefClass.cdef_method (line 78) ; >>> add_log("cdef class method")
MyCdefClass.cpdef_method (line 75) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 72) ; >>> add_log("cdef class method")
MyClass.method (line 61) ; >>> add_log("class method")
cdeffunc (line 25) ; >>> add_log("cdef")
mycpdeffunc (line 48) ; >>> add_log("cpdef")
myfunc (line 39) ; >>> add_log("def")
"""
log = []
cdef cdeffunc():
""">>> add_log("cdef")"""
cdeffunc() # make sure it's being used
def all_tests_run():
log.sort()
assert log == [u'cdef', u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s):
log.append(unicode(s))
if len(log) == len(__test__) + 1:
# Final per-function doctest executed
all_tests_run()
def myfunc():
""">>> add_log("def")"""
def doc_without_test():
"""Some docs"""
def nodocstring():
pass
cpdef mycpdeffunc():
""">>> add_log("cpdef")"""
class MyClass:
"""
Needs no hack
>>> add_log("class")
>>> True
True
"""
def method(self):
""">>> add_log("class method")"""
cdef class MyCdefClass:
"""
Needs no hack
>>> add_log("cdef class")
>>> True
True
"""
def method(self):
""">>> add_log("cdef class method")"""
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __dealloc__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __richcmp__(self, other, int op):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
def __nonzero__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __len__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __contains__(self, value):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
cdef class MyOtherCdefClass:
"""
Needs no hack
>>> True
True
"""
def __bool__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
#cython: doctesthack=True
#cython: autotestdict=True
"""
Tests that doctesthack doesn't come into effect when
Tests that autotestdict doesn't come into effect when
a __test__ is defined manually.
If this doesn't work, then the function doctest should fail.
......
cimport cython
################################################################################
## plain char*
@cython.test_assert_path_exists('//SingleAssignmentNode')
#@cython.test_fail_if_path_exists('//SingleAssignmentNode//CoerceFromPyTypeNode')
def charptr_equals_literal(char* s):
"""
>>> charptr_equals_literal('abc'.encode('ASCII'))
True
>>> charptr_equals_literal('aabc'.encode('ASCII'))
False
>>> charptr_equals_literal('abcx'.encode('ASCII'))
False
>>> charptr_equals_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s == b"abc")
return result
def charptr_gt_literal(char* s):
"""
>>> charptr_gt_literal('abc'.encode('ASCII'))
False
>>> charptr_gt_literal('aabc'.encode('ASCII'))
False
>>> charptr_gt_literal('abcx'.encode('ASCII'))
True
>>> charptr_gt_literal('bcx'.encode('ASCII'))
True
"""
cdef bint result = (s > b"abc")
return result
def charptr_lt_literal(char* s):
"""
>>> charptr_lt_literal('abc'.encode('ASCII'))
False
>>> charptr_lt_literal('aabc'.encode('ASCII'))
True
>>> charptr_lt_literal('abcx'.encode('ASCII'))
False
>>> charptr_lt_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s < b"abc")
return result
def charptr_ge_literal(char* s):
"""
>>> charptr_ge_literal('abc'.encode('ASCII'))
True
>>> charptr_ge_literal('aabc'.encode('ASCII'))
False
>>> charptr_ge_literal('abcx'.encode('ASCII'))
True
>>> charptr_ge_literal('bcx'.encode('ASCII'))
True
"""
cdef bint result = (s >= b"abc")
return result
def charptr_le_literal(char* s):
"""
>>> charptr_le_literal('abc'.encode('ASCII'))
True
>>> charptr_le_literal('aabc'.encode('ASCII'))
True
>>> charptr_le_literal('abcx'.encode('ASCII'))
False
>>> charptr_le_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s <= b"abc")
return result
################################################################################
## slices
@cython.test_assert_path_exists('//SingleAssignmentNode')
#FIXME: optimise me!
#@cython.test_fail_if_path_exists('//SingleAssignmentNode//CoerceFromPyTypeNode')
def slice_equals_literal(char* s):
"""
>>> slice_equals_literal('abc'.encode('ASCII'))
True
>>> slice_equals_literal('aabc'.encode('ASCII'))
False
>>> slice_equals_literal('abcx'.encode('ASCII'))
True
>>> slice_equals_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s[:3] == b"abc")
return result
def slice_gt_literal(char* s):
"""
>>> slice_gt_literal('abc'.encode('ASCII'))
False
>>> slice_gt_literal('aabc'.encode('ASCII'))
False
>>> slice_gt_literal('abcx'.encode('ASCII'))
False
>>> slice_gt_literal('bcx'.encode('ASCII'))
True
"""
cdef bint result = (s[:3] > b"abc")
return result
def slice_lt_literal(char* s):
"""
>>> slice_lt_literal('abc'.encode('ASCII'))
False
>>> slice_lt_literal('aabc'.encode('ASCII'))
True
>>> slice_lt_literal('abcx'.encode('ASCII'))
False
>>> slice_lt_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s[:3] < b"abc")
return result
def slice_ge_literal(char* s):
"""
>>> slice_ge_literal('abc'.encode('ASCII'))
True
>>> slice_ge_literal('aabc'.encode('ASCII'))
False
>>> slice_ge_literal('abcx'.encode('ASCII'))
True
>>> slice_ge_literal('bcx'.encode('ASCII'))
True
"""
cdef bint result = (s[:3] >= b"abc")
return result
def slice_le_literal(char* s):
"""
>>> slice_le_literal('abc'.encode('ASCII'))
True
>>> slice_le_literal('aabc'.encode('ASCII'))
True
>>> slice_le_literal('abcx'.encode('ASCII'))
True
>>> slice_le_literal('bcx'.encode('ASCII'))
False
"""
cdef bint result = (s[:3] <= b"abc")
return result
......@@ -11,6 +11,10 @@ class2
class3
>>> class3.plus(1)
8
>>> class4.view()
class4
>>> class5.view()
class5
"""
def f_plus(cls, a):
......@@ -36,3 +40,11 @@ cdef class class3:
def view(cls):
print cls.__name__
view = classmethod(view)
class class4:
@classmethod
def view(cls):
print cls.__name__
class class5(class4):
pass
......@@ -23,6 +23,39 @@ def test_arithmetic(double complex z, double complex w):
"""
return +z, -z+0, z+w, z-w, z*w, z/w
def test_pow(double complex z, double complex w, tol=None):
"""
Various implementations produce slightly different results...
>>> a = complex(3, 1)
>>> test_pow(a, 1)
(3+1j)
>>> test_pow(a, 2, 1e-15)
True
>>> test_pow(a, a, 1e-15)
True
>>> test_pow(complex(0.5, -.25), complex(3, 4), 1e-15)
True
"""
if tol is None:
return z**w
else:
return abs(z**w / <object>z ** <object>w - 1) < tol
def test_int_pow(double complex z, int n, tol=None):
"""
>>> [test_int_pow(complex(0, 1), k, 1e-15) for k in range(-4, 5)]
[True, True, True, True, True, True, True, True, True]
>>> [test_int_pow(complex(0, 2), k, 1e-15) for k in range(-4, 5)]
[True, True, True, True, True, True, True, True, True]
>>> [test_int_pow(complex(2, 0.5), k, 1e-15) for k in range(0, 10)]
[True, True, True, True, True, True, True, True, True, True]
"""
if tol is None:
return z**n + <object>0 # add zero to normalize zero sign
else:
return abs(z**n / <object>z ** <object>n - 1) < tol
@cython.cdivision(False)
def test_div_by_zero(double complex z):
"""
......
cdef int raise_TypeError() except *:
raise TypeError("custom")
cdef extern from "cpp_exceptions_nogil_helper.h" nogil:
cdef void foo "foo"(int i) except +
cdef void bar "foo"(int i) except +ValueError
cdef void spam"foo"(int i) except +raise_TypeError
def test_foo():
"""
>>> test_foo()
"""
#
foo(0)
foo(0)
with nogil:
foo(0)
foo(0)
#
try:
with nogil:
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
with nogil:
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
with nogil:
foo(1)
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
foo(1)
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
try:
with nogil:
foo(1)
except:
with nogil:
foo(1)
finally:
with nogil:
foo(0)
pass
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
try:
with nogil:
foo(1)
except:
with nogil:
foo(1)
finally:
with nogil:
foo(1)
pass
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
def test_bar():
"""
>>> test_bar()
"""
#
bar(0)
bar(0)
with nogil:
bar(0)
bar(0)
#
try:
with nogil:
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
with nogil:
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
with nogil:
bar(1)
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
bar(1)
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
try:
with nogil:
bar(1)
except ValueError:
with nogil:
bar(1)
finally:
with nogil:
bar(0)
pass
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
try:
with nogil:
bar(1)
except ValueError:
with nogil:
bar(1)
finally:
with nogil:
bar(1)
pass
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
def test_spam():
"""
>>> test_spam()
"""
#
spam(0)
spam(0)
with nogil:
spam(0)
spam(0)
#
try:
with nogil:
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
with nogil:
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
with nogil:
spam(1)
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
spam(1)
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
try:
with nogil:
spam(1)
except TypeError:
with nogil:
spam(1)
finally:
with nogil:
spam(0)
pass
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
try:
with nogil:
spam(1)
except TypeError:
with nogil:
spam(1)
finally:
with nogil:
spam(1)
pass
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
void foo(int i) {
if (i==0)
return;
else
throw i;
}
from cython.operator cimport dereference as d
from cython.operator cimport preincrement as incr
cdef extern from "<vector>" namespace "std":
cdef cppclass vector[T]:
void push_back(T)
size_t size()
T& operator[](size_t)
from libcpp.vector cimport vector
def simple_test(double x):
"""
......@@ -71,3 +67,43 @@ def index_set_test(L):
return d(v)[0], d(v)[v.size()-1]
finally:
del v
def iteration_test(L):
"""
>>> iteration_test([1,2,4,8])
1
2
4
8
"""
try:
v = new vector[int]()
for a in L:
v.push_back(a)
it = v.begin()
while it != v.end():
a = d(it)
incr(it)
print(a)
finally:
del v
def reverse_iteration_test(L):
"""
>>> reverse_iteration_test([1,2,4,8])
8
4
2
1
"""
try:
v = new vector[int]()
for a in L:
v.push_back(a)
it = v.rbegin()
while it != v.rend():
a = d(it)
incr(it)
print(a)
finally:
del v
"""
>>> test()
"""
def test():
x = ...
assert x is Ellipsis
d = {}
d[...] = 1
assert d[...] == 1
del d[...]
assert ... not in d
d[..., ...] = 1
assert d[..., ...] == 1
assert d[..., Ellipsis] == 1
assert (Ellipsis, Ellipsis) in d
del d[..., ...]
assert (Ellipsis, Ellipsis) not in d
cdef void foo(int i) except * with gil:
if i != 0: raise ValueError
cdef int bar(int i) except? -1 with gil:
if i != 0: raise ValueError
return 0
cdef int spam(int i) except? -1 with gil:
if i != 0: raise TypeError
return -1
def test_foo():
"""
>>> test_foo()
"""
#
foo(0)
foo(0)
with nogil:
foo(0)
foo(0)
#
try:
with nogil:
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
with nogil:
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
with nogil:
foo(1)
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
foo(0)
finally:
pass
#
try:
with nogil:
foo(0)
foo(1)
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
try:
with nogil:
foo(1)
except:
with nogil:
foo(1)
finally:
with nogil:
foo(0)
pass
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
try:
with nogil:
foo(0)
try:
with nogil:
foo(1)
except:
with nogil:
foo(1)
finally:
with nogil:
foo(1)
pass
except:
with nogil:
foo(0)
finally:
with nogil:
foo(0)
pass
#
def test_bar():
"""
>>> test_bar()
"""
#
bar(0)
bar(0)
with nogil:
bar(0)
bar(0)
#
try:
with nogil:
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
with nogil:
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
with nogil:
bar(1)
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
bar(0)
finally:
pass
#
try:
with nogil:
bar(0)
bar(1)
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
try:
with nogil:
bar(1)
except ValueError:
with nogil:
bar(1)
finally:
with nogil:
bar(0)
pass
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
try:
with nogil:
bar(0)
try:
with nogil:
bar(1)
except ValueError:
with nogil:
bar(1)
finally:
with nogil:
bar(1)
pass
except ValueError:
with nogil:
bar(0)
finally:
with nogil:
bar(0)
pass
#
def test_spam():
"""
>>> test_spam()
"""
#
spam(0)
spam(0)
with nogil:
spam(0)
spam(0)
#
try:
with nogil:
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
with nogil:
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
with nogil:
spam(1)
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
spam(0)
finally:
pass
#
try:
with nogil:
spam(0)
spam(1)
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
try:
with nogil:
spam(1)
except TypeError:
with nogil:
spam(1)
finally:
with nogil:
spam(0)
pass
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
try:
with nogil:
spam(0)
try:
with nogil:
spam(1)
except TypeError:
with nogil:
spam(1)
finally:
with nogil:
spam(1)
pass
except TypeError:
with nogil:
spam(0)
finally:
with nogil:
spam(0)
pass
#
......@@ -5,6 +5,9 @@ cdef class Spam:
def __get__(self):
"""
This is the docstring for Spam.eggs.__get__
>>> True
True
"""
return 42
......@@ -16,9 +19,9 @@ def tomato():
>>> lines = __test__.keys()
>>> len(lines)
3
>>> 'Spam.eggs.__get__ (line 5)' in lines
>>> 'Spam.eggs.__get__ (line 5)' in lines or lines
True
>>> 'tomato (line 11)' in lines
>>> 'tomato (line 14)' in lines or lines
True
"""
cdef Spam spam
......
cimport cython
@cython.final
cdef class FinalClass:
"""
>>> f = FinalClass()
>>> test_final_class(f)
Type tested
>>> try:
... class SubType(FinalClass): pass
... except TypeError:
... print('PASSED!')
PASSED!
"""
cdef class NonFinalClass:
"""
>>> class SubType(NonFinalClass): pass
>>> s = SubType()
"""
@cython.final
cdef class FinalSubClass(NonFinalClass):
"""
>>> f = FinalSubClass()
>>> test_non_final_class(f)
Type tested
>>> try:
... class SubType(FinalSubClass): pass
... except TypeError:
... print('PASSED!')
PASSED!
"""
def test_final_class(FinalClass c):
print u"Type tested"
def test_non_final_class(NonFinalClass c):
print u"Type tested"
......@@ -53,3 +53,56 @@ def c_long_types():
print typeof(1U)
print typeof(1UL)
print typeof(1ULL)
# different ways to write an integer in Python
def c_oct():
"""
>>> c_oct()
(1, 17, 63)
"""
cdef int a = 0o01
cdef int b = 0o21
cdef int c = 0o77
return a,b,c
def py_oct():
"""
>>> py_oct()
(1, 17, 63)
"""
return 0o01, 0o21, 0o77
def c_hex():
"""
>>> c_hex()
(1, 33, 255)
"""
cdef int a = 0x01
cdef int b = 0x21
cdef int c = 0xFF
return a,b,c
def py_hex():
"""
>>> py_hex()
(1, 33, 255)
"""
return 0x01, 0x21, 0xFF
def c_bin():
"""
>>> c_bin()
(1, 2, 15)
"""
cdef int a = 0b01
cdef int b = 0b10
cdef int c = 0b1111
return a,b,c
def py_bin():
"""
>>> py_bin()
(1, 2, 15)
"""
return 0b01, 0b10, 0b1111
cimport cython
@cython.internal
cdef class InternalType:
"""
NOTE: this doesn't fail because it is never tested !
>>> i = InternalType
"""
cdef class PublicType:
"""
>>> p = PublicType
"""
def test():
"""
>>> p,i = test()
>>> p = PublicType
>>> i = InternalType
Traceback (most recent call last):
NameError: name 'InternalType' is not defined
"""
p = PublicType
i = InternalType
return p,i
......@@ -2,67 +2,109 @@ __doc__ = u"""
#>>> py_identity = lambda x:x
#>>> py_identity(1) == cy_identity(1)
#True
>>> idcall = make_identity()
>>> idcall(1)
1
>>> idcall(2)
2
>>> make_const0(1)()
1
>>> make_const1(1)(2)
1
>>> make_const1(1)(2)
1
>>> make_const_calc0()()
11
>>> make_const_calc1()(2)
11
>>> make_const_calc1_xy(8)(2)
27
>>> make_lambda_lambda(1)(2)(4)
7
>>> make_typed_lambda_lambda(1)(2)(4)
7
>>> partial_lambda = make_typed_lambda_lambda(1)(2)
>>> partial_lambda(4)
7
>>> partial_lambda(5)
8
"""
#cy_identity = lambda x:x
def make_identity():
"""
>>> idcall = make_identity()
>>> idcall(1)
1
>>> idcall(2)
2
"""
return lambda x:x
def make_const0(x):
"""
>>> make_const0(1)()
1
"""
return lambda :x
def make_const1(x):
"""
>>> make_const1(1)(2)
1
>>> make_const1(1)(2)
1
"""
return lambda _:x
def make_const_calc0():
"""
>>> make_const_calc0()()
11
"""
return lambda : 1*2*3+5
def make_const_calc1():
"""
>>> make_const_calc1()(2)
11
"""
return lambda _: 1*2*3+5
def make_const_calc1_xy(x):
"""
>>> make_const_calc1_xy(8)(2)
27
"""
return lambda y: x*y+(1*2*3+5)
def make_lambda_lambda(x):
"""
>>> make_lambda_lambda(1)(2)(4)
7
"""
return lambda y : \
lambda z:x+y+z
def make_typed_lambda_lambda(int x):
"""
>>> make_typed_lambda_lambda(1)(2)(4)
7
>>> partial_lambda = make_typed_lambda_lambda(1)(2)
>>> partial_lambda(4)
7
>>> partial_lambda(5)
8
"""
return lambda int y : \
lambda int z:x+y+z
def pass_lambda(f):
"""
>>> def f(a, lfunc): return lfunc(a,2)
>>> pass_lambda(f)
12
"""
return f(1, lambda a, b : a*10+b)
def pass_lambda_with_args(f):
"""
>>> def f(a, lfunc): return lfunc(a,2,3)
>>> pass_lambda_with_args(f)
123
"""
return f(1, lambda a, *args : (a*10 + args[0])*10 + args[1])
def pass_lambda_with_args_kwargs(f):
"""
>>> def f(a, lfunc): return lfunc(a,2,3, b=4)
>>> pass_lambda_with_args_kwargs(f)
1234
"""
return f(1, lambda a, *args, **kwargs : ((a*10 + args[0])*10 + args[1])*10 + kwargs['b'])
def pass_lambda_with_args_kwargs_kwonly_args(f):
"""
>>> def f(a, lfunc): return lfunc(a,2,3, b=4, c=5)
>>> pass_lambda_with_args_kwargs_kwonly_args(f)
12345
"""
return f(1, lambda a, *args, b, **kwargs : (((a*10 + args[0])*10 + args[1])*10 + b)*10 + kwargs['c'])
......@@ -53,3 +53,15 @@ cdef vector[int].iterator iv1 = v1.begin()
cdef vector[int].iterator iv2 = v1.end()
cdef vector[int].reverse_iterator riv1 = v1.rbegin()
cdef vector[int].reverse_iterator riv2 = v1.rend()
def test_vector_coercion(*args):
"""
>>> test_vector_coercion(1.75)
[1.75]
>>> test_vector_coercion(1, 10, 100)
[1.0, 10.0, 100.0]
"""
v = new vector[double]()
for a in args:
v.push_back(a)
return [v[0][i] for i in range(v.size())]
"""
>>> obj = Foo()
>>> obj.metaclass_was_here
True
"""
class Base(type):
def __new__(cls, name, bases, attrs):
attrs['metaclass_was_here'] = True
return type.__new__(cls, name, bases, attrs)
class Foo(object):
__metaclass__ = Base
"""
>>> Foo.incr.__module__ is not None
True
>>> Foo.incr.__module__ == Foo.__module__ == bar.__module__
True
>>> Simpleton.incr.__module__ == Simpleton.__module__ == bar.__module__
True
"""
class Foo(object):
def incr(self,x):
return x+1
def bar():
pass
class Simpleton:
def __str__(self):
return "A simpleton"
def incr(self,x):
"""Increment x by one.
"""
return x+1
......@@ -69,7 +69,6 @@ def test_locals(x):
"""
y = x
return y
MyUnion = cython.union(n=cython.int, x=cython.double)
MyStruct = cython.struct(is_integral=cython.bint, data=MyUnion)
......
import cython
def test_sizeof():
"""
>>> test_sizeof()
True
True
True
True
True
"""
x = cython.declare(cython.bint)
print(cython.sizeof(x) == cython.sizeof(cython.bint))
print(cython.sizeof(cython.char) <= cython.sizeof(cython.short) <= cython.sizeof(cython.int) <= cython.sizeof(cython.long) <= cython.sizeof(cython.longlong))
print(cython.sizeof(cython.uint) == cython.sizeof(cython.int))
print(cython.sizeof(cython.p_int) == cython.sizeof(cython.p_double))
if cython.compiled:
print(cython.sizeof(cython.char) < cython.sizeof(cython.longlong))
else:
print(cython.sizeof(cython.char) == 1)
## CURRENTLY BROKEN - FIXME!!
## def test_declare(n):
## """
## >>> test_declare(100)
## (100, 100)
## >>> test_declare(100.5)
## (100, 100)
## >>> test_declare(None)
## Traceback (most recent call last):
## ...
## TypeError: an integer is required
## """
## x = cython.declare(cython.int)
## y = cython.declare(cython.int, n)
## if cython.compiled:
## cython.declare(xx=cython.int, yy=cython.long)
## i = sizeof(xx)
## ptr = cython.declare(cython.p_int, cython.address(y))
## return y, ptr[0]
@cython.locals(x=cython.double, n=cython.int)
def test_cast(x):
"""
>>> test_cast(1.5)
1
"""
n = cython.cast(cython.int, x)
return n
@cython.locals(x=cython.int, y=cython.p_int)
def test_address(x):
"""
>>> test_address(39)
39
"""
y = cython.address(x)
return y[0]
## CURRENTLY BROKEN - FIXME!!
## @cython.locals(x=cython.int)
## @cython.locals(y=cython.bint)
## def test_locals(x):
## """
## >>> test_locals(5)
## True
## """
## y = x
## return y
def test_with_nogil(nogil):
"""
>>> raised = []
>>> class nogil(object):
... def __enter__(self):
... pass
... def __exit__(self, exc_class, exc, tb):
... raised.append(exc)
... return exc_class is None
>>> test_with_nogil(nogil())
WORKS
True
>>> raised
[None]
"""
result = False
with nogil:
print("WORKS")
with cython.nogil:
result = True
return result
## CURRENTLY BROKEN - FIXME!!
## MyUnion = cython.union(n=cython.int, x=cython.double)
## MyStruct = cython.struct(is_integral=cython.bint, data=MyUnion)
## MyStruct2 = cython.typedef(MyStruct[2])
## def test_struct(n, x):
## """
## >>> test_struct(389, 1.64493)
## (389, 1.64493)
## """
## a = cython.declare(MyStruct2)
## a[0] = MyStruct(True, data=MyUnion(n=n))
## a[1] = MyStruct(is_integral=False, data={'x': x})
## return a[0].data.n, a[1].data.x
import cython as cy
from cython import declare, cast, locals, address, typedef, p_void, compiled
from cython import declare as my_declare, locals as my_locals, p_void as my_void_star, typedef as my_typedef, compiled as my_compiled
@my_locals(a=cython.p_void)
def test_imports():
"""
>>> test_imports() # (True, True)
True
"""
a = cython.NULL
b = declare(p_void, cython.NULL)
c = my_declare(my_void_star, cython.NULL)
d = cy.declare(cy.p_void, cython.NULL)
## CURRENTLY BROKEN - FIXME!!
#return a == d, compiled == my_compiled
return compiled == my_compiled
## CURRENTLY BROKEN - FIXME!!
## MyStruct3 = typedef(MyStruct[3])
## MyStruct4 = my_typedef(MyStruct[4])
## MyStruct5 = cy.typedef(MyStruct[5])
def test_declare_c_types(n):
"""
>>> test_declare_c_types(0)
>>> test_declare_c_types(1)
>>> test_declare_c_types(2)
"""
#
b00 = cython.declare(cython.bint, 0)
b01 = cython.declare(cython.bint, 1)
b02 = cython.declare(cython.bint, 2)
#
i00 = cython.declare(cython.uchar, n)
i01 = cython.declare(cython.char, n)
i02 = cython.declare(cython.schar, n)
i03 = cython.declare(cython.ushort, n)
i04 = cython.declare(cython.short, n)
i05 = cython.declare(cython.sshort, n)
i06 = cython.declare(cython.uint, n)
i07 = cython.declare(cython.int, n)
i08 = cython.declare(cython.sint, n)
i09 = cython.declare(cython.slong, n)
i10 = cython.declare(cython.long, n)
i11 = cython.declare(cython.ulong, n)
i12 = cython.declare(cython.slonglong, n)
i13 = cython.declare(cython.longlong, n)
i14 = cython.declare(cython.ulonglong, n)
i20 = cython.declare(cython.Py_ssize_t, n)
i21 = cython.declare(cython.size_t, n)
#
f00 = cython.declare(cython.float, n)
f01 = cython.declare(cython.double, n)
f02 = cython.declare(cython.longdouble, n)
#
#z00 = cython.declare(cython.complex, n+1j)
#z01 = cython.declare(cython.floatcomplex, n+1j)
#z02 = cython.declare(cython.doublecomplex, n+1j)
#z03 = cython.declare(cython.longdoublecomplex, n+1j)
......@@ -7,6 +7,9 @@ def f(obj1, obj2, obj3, obj4):
True
>>> l is f(1, l, 2, 3)
False
>>> f(1, 42, 2, 3) #doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...unsliceable...
"""
obj1 = obj2[:]
return obj1
......@@ -15,6 +18,9 @@ def g(obj1, obj2, obj3, obj4):
"""
>>> g(1, [1,2,3,4], 2, 3)
[3, 4]
>>> g(1, 42, 2, 3) #doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...unsliceable...
"""
obj1 = obj2[obj3:]
return obj1
......@@ -23,6 +29,9 @@ def h(obj1, obj2, obj3, obj4):
"""
>>> h(1, [1,2,3,4], 2, 3)
[1, 2, 3]
>>> h(1, 42, 2, 3) #doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...unsliceable...
"""
obj1 = obj2[:obj4]
return obj1
......@@ -31,6 +40,9 @@ def j(obj1, obj2, obj3, obj4):
"""
>>> j(1, [1,2,3,4], 2, 3)
[3]
>>> j(1, 42, 2, 3) #doctest: +ELLIPSIS
Traceback (most recent call last):
TypeError: ...unsliceable...
"""
obj1 = obj2[obj3:obj4]
return obj1
......
......@@ -544,10 +544,10 @@ cdef class GetAttrGetItemRedirect:
def __getattr__(self, name):
if name == 'item':
return self.__getitem__(name)
return self[name]
return ('attr', self.obj)
def __getitem__(self, key):
if key == 'attr':
return self.__getattr__(key)
return getattr(self, key)
return ('item', self.obj)
......@@ -5,6 +5,8 @@ __doc__ = u"""
2
>>> class3.plus1(1)
2
>>> class4.plus1(1)
2
"""
def f_plus(a):
......@@ -18,3 +20,8 @@ class class2(object):
cdef class class3:
plus1 = f_plus
class class4:
@staticmethod
def plus1(a):
return a + 1
......@@ -118,3 +118,121 @@ def typed():
with c as i:
i += 11
print i
def multimanager():
"""
>>> multimanager()
enter
enter
enter
enter
enter
enter
2
value
1 2 3 4 5
nested
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
"""
with ContextManager(1), ContextManager(2) as x, ContextManager(u'value') as y,\
ContextManager(3), ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
with ContextManager(u'nested') as nested:
print x
print y
print a, b, c, d, e
print nested
# Tests borrowed from pyregr test_with.py,
# modified to follow the constraints of Cython.
import unittest
class Dummy(object):
def __init__(self, value=None, gobble=False):
if value is None:
value = self
self.value = value
self.gobble = gobble
self.enter_called = False
self.exit_called = False
def __enter__(self):
self.enter_called = True
return self.value
def __exit__(self, *exc_info):
self.exit_called = True
self.exc_info = exc_info
if self.gobble:
return True
class InitRaises(object):
def __init__(self): raise RuntimeError()
class EnterRaises(object):
def __enter__(self): raise RuntimeError()
def __exit__(self, *exc_info): pass
class ExitRaises(object):
def __enter__(self): pass
def __exit__(self, *exc_info): raise RuntimeError()
class NestedWith(unittest.TestCase):
"""
>>> NestedWith().runTest()
"""
def runTest(self):
self.testNoExceptions()
self.testExceptionInExprList()
self.testExceptionInEnter()
self.testExceptionInExit()
self.testEnterReturnsTuple()
def testNoExceptions(self):
with Dummy() as a, Dummy() as b:
self.assertTrue(a.enter_called)
self.assertTrue(b.enter_called)
self.assertTrue(a.exit_called)
self.assertTrue(b.exit_called)
def testExceptionInExprList(self):
try:
with Dummy() as a, InitRaises():
pass
except:
pass
self.assertTrue(a.enter_called)
self.assertTrue(a.exit_called)
def testExceptionInEnter(self):
try:
with Dummy() as a, EnterRaises():
self.fail('body of bad with executed')
except RuntimeError:
pass
else:
self.fail('RuntimeError not reraised')
self.assertTrue(a.enter_called)
self.assertTrue(a.exit_called)
def testExceptionInExit(self):
body_executed = False
with Dummy(gobble=True) as a, ExitRaises():
body_executed = True
self.assertTrue(a.enter_called)
self.assertTrue(a.exit_called)
self.assertTrue(body_executed)
self.assertNotEqual(a.exc_info[0], None)
def testEnterReturnsTuple(self):
with Dummy(value=(1,2)) as (a1, a2), \
Dummy(value=(10, 20)) as (b1, b2):
self.assertEquals(1, a1)
self.assertEquals(2, a2)
self.assertEquals(10, b1)
self.assertEquals(20, b2)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment