--- /dev/null
+"""
+Compile a Python script into an executable that embeds CPython and run it.
+Requires CPython to be built as a shared library ('libpythonX.Y').
+
+Basic usage:
+
+ python cythonrun somefile.py [ARGS]
+"""
+
+DEBUG = True
+
+import sys
+import os
+from distutils import sysconfig
+
+def get_config_var(name):
+ return sysconfig.get_config_var(name) or ''
+
+INCDIR = sysconfig.get_python_inc()
+LIBDIR1 = get_config_var('LIBDIR')
+LIBDIR2 = get_config_var('LIBPL')
+PYLIB = get_config_var('LIBRARY')
+PYLIB_DYN = get_config_var('LDLIBRARY')
+if PYLIB_DYN == PYLIB:
+ # no shared library
+ PYLIB_DYN = ''
+else:
+ PYLIB_DYN = os.path.splitext(PYLIB_DYN[3:])[0] # 'lib(XYZ).so' -> XYZ
+
+CC = get_config_var('CC')
+CFLAGS = get_config_var('CFLAGS') + ' ' + os.environ.get('CFLAGS', '')
+LINKCC = get_config_var('LINKCC')
+LINKFORSHARED = get_config_var('LINKFORSHARED')
+LIBS = get_config_var('LIBS')
+SYSLIBS = get_config_var('SYSLIBS')
+EXE_EXT = sysconfig.get_config_var('EXE')
+
+def _debug(msg, *args):
+ if DEBUG:
+ if args:
+ msg = msg % args
+ sys.stderr.write(msg + '\n')
+
+def dump_config():
+ _debug('INCDIR: %s', INCDIR)
+ _debug('LIBDIR1: %s', LIBDIR1)
+ _debug('LIBDIR2: %s', LIBDIR2)
+ _debug('PYLIB: %s', PYLIB)
+ _debug('PYLIB_DYN: %s', PYLIB_DYN)
+ _debug('CC: %s', CC)
+ _debug('CFLAGS: %s', CFLAGS)
+ _debug('LINKCC: %s', LINKCC)
+ _debug('LINKFORSHARED: %s', LINKFORSHARED)
+ _debug('LIBS: %s', LIBS)
+ _debug('SYSLIBS: %s', SYSLIBS)
+ _debug('EXE_EXT: %s', EXE_EXT)
+
+def runcmd(cmd, shell=True):
+ if shell:
+ cmd = ' '.join(cmd)
+ _debug(cmd)
+ else:
+ _debug(' '.join(cmd))
+
+ try:
+ import subprocess
+ except ImportError: # Python 2.3 ...
+ returncode = os.system(cmd)
+ else:
+ returncode = subprocess.call(cmd, shell=shell)
+
+ if returncode:
+ sys.exit(returncode)
+
+def clink(basename):
+ runcmd([LINKCC, '-o', basename + EXE_EXT, basename+'.o', '-L'+LIBDIR1, '-L'+LIBDIR2]
+ + [PYLIB_DYN and ('-l'+PYLIB_DYN) or os.path.join(LIBDIR1, PYLIB)]
+ + LIBS.split() + SYSLIBS.split() + LINKFORSHARED.split())
+
+def ccompile(basename):
+ runcmd([CC, '-c', '-o', basename+'.o', basename+'.c', '-I' + INCDIR] + CFLAGS.split())
+
+def cycompile(input_file, options=()):
+ from Cython.Compiler import Version, CmdLine, Main
+ options, sources = CmdLine.parse_command_line(list(options or ()) + ['--embed', input_file])
+ _debug('Using Cython %s to compile %s', Version.version, input_file)
+ result = Main.compile(sources, options)
+ if result.num_errors > 0:
+ sys.exit(1)
+
+def exec_file(program_name, args=()):
+ runcmd([os.path.abspath(program_name)] + list(args), shell=False)
+
+def build(input_file, compiler_args=()):
+ """
+ Build an executable program from a Cython module.
+
+ Returns the name of the executable file.
+ """
+ basename = os.path.splitext(input_file)[0]
+ cycompile(input_file, compiler_args)
+ ccompile(basename)
+ clink(basename)
+ return basename + EXE_EXT
+
+def build_and_run(args):
+ """
+ Build an executable program from a Cython module and runs it.
+
+ Arguments after the module name will be passed verbatimely to the
+ program.
+ """
+ cy_args = []
+ last_arg = None
+ for i, arg in enumerate(args):
+ if arg.startswith('-'):
+ cy_args.append(arg)
+ elif last_arg in ('-X', '--directive'):
+ cy_args.append(arg)
+ else:
+ input_file = arg
+ args = args[i+1:]
+ break
+ last_arg = arg
+ else:
+ raise ValueError('no input file provided')
+
+ program_name = build(input_file, cy_args)
+ exec_file(program_name, args)
+
+if __name__ == '__main__':
+ build_and_run(sys.argv[1:])
int new_count, enc_count;
int is_complex;
char enc_type;
- char packmode;
+ char new_packmode;
+ char enc_packmode;
} __Pyx_BufFmt_Context;
static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
ctx->head->field = &ctx->root;
ctx->fmt_offset = 0;
ctx->head->parent_offset = 0;
- ctx->packmode = '@';
+ ctx->new_packmode = '@';
+ ctx->enc_packmode = '@';
ctx->new_count = 1;
ctx->enc_count = 0;
ctx->enc_type = 0;
__Pyx_StructField* field = ctx->head->field;
__Pyx_TypeInfo* type = field->type;
- if (ctx->packmode == '@' || ctx->packmode == '^') {
+ if (ctx->enc_packmode == '@' || ctx->enc_packmode == '^') {
size = __Pyx_BufFmt_TypeCharToNativeSize(ctx->enc_type, ctx->is_complex);
} else {
size = __Pyx_BufFmt_TypeCharToStandardSize(ctx->enc_type, ctx->is_complex);
}
- if (ctx->packmode == '@') {
+ if (ctx->enc_packmode == '@') {
int align_at = __Pyx_BufFmt_TypeCharToAlignment(ctx->enc_type, ctx->is_complex);
int align_mod_offset;
if (align_at == 0) return -1;
if (ctx->fmt_offset != offset) {
PyErr_Format(PyExc_ValueError,
"Buffer dtype mismatch; next field is at offset %"PY_FORMAT_SIZE_T"d "
- "but %"PY_FORMAT_SIZE_T"d expected", ctx->fmt_offset, offset);
+ "but %"PY_FORMAT_SIZE_T"d expected", (Py_ssize_t)ctx->fmt_offset, (Py_ssize_t)offset);
return -1;
}
return 0;
}
-static int __Pyx_BufFmt_FirstPack(__Pyx_BufFmt_Context* ctx) {
- if (ctx->enc_type != 0 || ctx->packmode != '@') {
- PyErr_SetString(PyExc_ValueError, "Buffer packing mode currently only allowed at beginning of format string (this is a defect)");
- return -1;
- }
- return 0;
-}
-
static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts) {
int got_Z = 0;
while (1) {
PyErr_SetString(PyExc_ValueError, "Little-endian buffer not supported on big-endian compiler");
return NULL;
}
- if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
- ctx->packmode = '=';
+ ctx->new_packmode = '=';
++ts;
break;
case '>':
PyErr_SetString(PyExc_ValueError, "Big-endian buffer not supported on little-endian compiler");
return NULL;
}
- if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
- ctx->packmode = '=';
+ ctx->new_packmode = '=';
++ts;
break;
case '=':
case '@':
case '^':
- if (__Pyx_BufFmt_FirstPack(ctx) == -1) return NULL;
- ctx->packmode = *ts++;
+ ctx->new_packmode = *ts++;
break;
case 'T': /* substruct */
{
ctx->new_count = 1;
ctx->enc_count = 0;
ctx->enc_type = 0;
+ ctx->enc_packmode = ctx->new_packmode;
++ts;
break;
case 'Z':
case 'l': case 'L': case 'q': case 'Q':
case 'f': case 'd': case 'g':
case 'O':
- if (ctx->enc_type == *ts && got_Z == ctx->is_complex) {
+ if (ctx->enc_type == *ts && got_Z == ctx->is_complex &&
+ ctx->enc_packmode == ctx->new_packmode) {
/* Continue pooling same type */
ctx->enc_count += ctx->new_count;
} else {
/* New type */
if (__Pyx_BufFmt_ProcessTypeChunk(ctx) == -1) return NULL;
ctx->enc_count = ctx->new_count;
+ ctx->enc_packmode = ctx->new_packmode;
ctx->enc_type = *ts;
ctx->is_complex = got_Z;
}
ctx->new_count = 1;
got_Z = 0;
break;
- case ':':
+ case ':':
++ts;
while(*ts != ':') ++ts;
++ts;
"Item size of buffer (%"PY_FORMAT_SIZE_T"d byte%s) does not match size of '%s' (%"PY_FORMAT_SIZE_T"d byte%s)",
buf->itemsize, (buf->itemsize > 1) ? "s" : "",
dtype->name,
- dtype->size, (dtype->size > 1) ? "s" : "");
+ (Py_ssize_t)dtype->size, (dtype->size > 1) ? "s" : "");
goto fail;
}
if (buf->suboffsets == NULL) buf->suboffsets = __Pyx_minusones;
("tuple", "PyTuple_Type", []),
- ("list", "PyList_Type", [BuiltinMethod("insert", "TzO", "i", "PyList_Insert"),
- BuiltinMethod("reverse", "T", "i", "PyList_Reverse"),
- BuiltinMethod("append", "TO", "i", "PyList_Append"),
+ ("list", "PyList_Type", [BuiltinMethod("insert", "TzO", "r", "PyList_Insert"),
+ BuiltinMethod("reverse", "T", "r", "PyList_Reverse"),
+ BuiltinMethod("append", "TO", "r", "PyList_Append"),
]),
("dict", "PyDict_Type", [BuiltinMethod("items", "T", "O", "PyDict_Items"), # FIXME: Py3 mode?
]),
# ("file", "PyFile_Type", []), # not in Py3
- ("set", "PySet_Type", [BuiltinMethod("clear", "T", "i", "PySet_Clear"),
- BuiltinMethod("discard", "TO", "i", "PySet_Discard"),
- BuiltinMethod("add", "TO", "i", "PySet_Add"),
+ ("set", "PySet_Type", [BuiltinMethod("clear", "T", "r", "PySet_Clear"),
+ BuiltinMethod("discard", "TO", "r", "PySet_Discard"),
+ BuiltinMethod("add", "TO", "r", "PySet_Add"),
BuiltinMethod("pop", "T", "O", "PySet_Pop")]),
("frozenset", "PyFrozenSet_Type", []),
]
-2 Compile based on Python-2 syntax and code semantics.
-3 Compile based on Python-3 syntax and code semantics.
--fast-fail Abort the compilation on the first error
+ --warning-error, -Werror Make all warnings into errors
-X, --directive <name>=<value>[,<name=value,...] Overrides a compiler directive
"""
options.language_level = 3
elif option == "--fast-fail":
Options.fast_fail = True
+ elif option in ('-Werror', '--warning-errors'):
+ Options.warning_errors = True
elif option == "--disable-function-redefinition":
Options.disable_function_redefinition = True
- elif option in ("-X", "--directive"):
+ elif option == "--directive" or option.startswith('-X'):
+ if option.startswith('-X') and option[2:].strip():
+ x_args = option[2:]
+ else:
+ x_args = pop_arg()
try:
options.compiler_directives = Options.parse_directive_list(
- pop_arg(), relaxed_bool=True,
+ x_args, relaxed_bool=True,
current_settings=options.compiler_directives)
except ValueError, e:
sys.stderr.write("Error in compiler directive: %s\n" % e.args[0])
cdef public dict temps_used_type
cdef public size_t temp_counter
+ cdef public object closure_temps
+
@cython.locals(n=size_t)
cpdef new_label(self, name=*)
cpdef tuple get_loop_labels(self)
cdef public object text
cdef public object escaped_value
cdef public dict py_strings
+ cdef public list py_versions
@cython.locals(intern=bint, is_str=bint, is_unicode=bint)
- cpdef get_py_string_const(self, encoding, identifier=*, is_str=*)
+ cpdef get_py_string_const(self, encoding, identifier=*, is_str=*, py3str_cstring=*)
## cdef class PyStringConst:
## cdef public object cname
-# cython: language_level = 3
+# cython: language_level = 3, py2_import=True
#
# Pyrex - Code output module
#
except ImportError:
from builtins import str as basestring
+
+non_portable_builtins_map = {
+ # builtins that have different names in different Python versions
+ 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'),
+ 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'),
+ 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'),
+ 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'),
+ }
+
+uncachable_builtins = [
+ # builtin names that cannot be cached because they may or may not
+ # be available at import time
+ 'WindowsError',
+ ]
+
class UtilityCode(object):
# Stores utility code to add during code generation.
#
self.temps_free = {} # (type, manage_ref) -> list of free vars with same type/managed status
self.temps_used_type = {} # name -> (type, manage_ref)
self.temp_counter = 0
+ self.closure_temps = None
# labels
if manage_ref
for cname in freelist]
+ def init_closure_temps(self, scope):
+ self.closure_temps = ClosureTempAllocator(scope)
+
class IntConst(object):
"""Global info about a Python integer constant held by GlobalState.
self.text = text
self.escaped_value = StringEncoding.escape_byte_string(byte_string)
self.py_strings = None
+ self.py_versions = []
+
+ def add_py_version(self, version):
+ if not version:
+ self.py_versions = [2,3]
+ elif version not in self.py_versions:
+ self.py_versions.append(version)
- def get_py_string_const(self, encoding, identifier=None, is_str=False):
+ def get_py_string_const(self, encoding, identifier=None,
+ is_str=False, py3str_cstring=None):
py_strings = self.py_strings
text = self.text
else:
encoding_key = ''.join(find_alphanums(encoding))
- key = (is_str, is_unicode, encoding_key)
- if py_strings is not None and key in py_strings:
- py_string = py_strings[key]
+ key = (is_str, is_unicode, encoding_key, py3str_cstring)
+ if py_strings is not None:
+ try:
+ return py_strings[key]
+ except KeyError:
+ pass
else:
- if py_strings is None:
- self.py_strings = {}
- if identifier:
- intern = True
- elif identifier is None:
- if isinstance(text, unicode):
- intern = bool(possible_unicode_identifier(text))
- else:
- intern = bool(possible_bytes_identifier(text))
- else:
- intern = False
- if intern:
- prefix = Naming.interned_str_prefix
- else:
- prefix = Naming.py_const_prefix
- pystring_cname = "%s%s_%s" % (
- prefix,
- (is_str and 's') or (is_unicode and 'u') or 'b',
- self.cname[len(Naming.const_prefix):])
-
- py_string = PyStringConst(
- pystring_cname, encoding, is_unicode, is_str, intern)
- self.py_strings[key] = py_string
+ self.py_strings = {}
+ if identifier:
+ intern = True
+ elif identifier is None:
+ if isinstance(text, unicode):
+ intern = bool(possible_unicode_identifier(text))
+ else:
+ intern = bool(possible_bytes_identifier(text))
+ else:
+ intern = False
+ if intern:
+ prefix = Naming.interned_str_prefix
+ else:
+ prefix = Naming.py_const_prefix
+ pystring_cname = "%s%s_%s" % (
+ prefix,
+ (is_str and 's') or (is_unicode and 'u') or 'b',
+ self.cname[len(Naming.const_prefix):])
+
+ py_string = PyStringConst(
+ pystring_cname, encoding, is_unicode, is_str, py3str_cstring, intern)
+ self.py_strings[key] = py_string
return py_string
class PyStringConst(object):
"""Global info about a Python string constant held by GlobalState.
"""
# cname string
+ # py3str_cstring string
# encoding string
# intern boolean
# is_unicode boolean
# is_str boolean
- def __init__(self, cname, encoding, is_unicode, is_str=False, intern=False):
+ def __init__(self, cname, encoding, is_unicode, is_str=False,
+ py3str_cstring=None, intern=False):
self.cname = cname
+ self.py3str_cstring = py3str_cstring
self.encoding = encoding
self.is_str = is_str
self.is_unicode = is_unicode
w.enter_cfunc_scope()
w.putln("")
w.putln("static int __Pyx_InitCachedConstants(void) {")
+ w.put_declare_refcount_context()
w.put_setup_refcount_context("__Pyx_InitCachedConstants")
w = self.parts['init_globals']
cleanup_writer.put_xdecref_clear(const.cname, type, nanny=False)
return const
- def get_string_const(self, text):
+ def get_string_const(self, text, py_version=None):
# return a C string constant, creating a new one if necessary
if text.is_unicode:
byte_string = text.utf8encode()
c = self.string_const_index[byte_string]
except KeyError:
c = self.new_string_const(text, byte_string)
+ c.add_py_version(py_version)
return c
- def get_py_string_const(self, text, identifier=None, is_str=False):
+ def get_py_string_const(self, text, identifier=None,
+ is_str=False, unicode_value=None):
# return a Python string constant, creating a new one if necessary
- c_string = self.get_string_const(text)
- py_string = c_string.get_py_string_const(text.encoding, identifier, is_str)
+ py3str_cstring = None
+ if is_str and unicode_value is not None \
+ and unicode_value.utf8encode() != text.byteencode():
+ py3str_cstring = self.get_string_const(unicode_value, py_version=3)
+ c_string = self.get_string_const(text, py_version=2)
+ else:
+ c_string = self.get_string_const(text)
+ py_string = c_string.get_py_string_const(
+ text.encoding, identifier, is_str, py3str_cstring)
return py_string
def get_interned_identifier(self, text):
return "%s%s%d" % (Naming.const_prefix, prefix, n)
def add_cached_builtin_decl(self, entry):
- if Options.cache_builtins:
+ if entry.is_builtin and entry.is_const:
if self.should_declare(entry.cname, entry):
self.put_pyobject_decl(entry)
w = self.parts['cached_builtins']
- conditional_name = False
- if entry.name == 'xrange':
- # replaced by range() in Py3
- conditional_name = True
- w.putln('#if PY_MAJOR_VERSION >= 3')
+ condition = None
+ if entry.name in non_portable_builtins_map:
+ condition, replacement = non_portable_builtins_map[entry.name]
+ w.putln('#if %s' % condition)
self.put_cached_builtin_init(
- entry.pos, StringEncoding.EncodedString('range'),
+ entry.pos, StringEncoding.EncodedString(replacement),
entry.cname)
- elif entry.name == 'BaseException':
- # replace BaseException by Exception in Py<2.5
- conditional_name = True
- w.putln('#if PY_VERSION_HEX < 0x02050000')
- self.put_cached_builtin_init(
- entry.pos, StringEncoding.EncodedString('Exception'),
- entry.cname)
- if conditional_name:
w.putln('#else')
self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString(entry.name),
entry.cname)
- if conditional_name:
+ if condition:
w.putln('#endif')
def put_cached_builtin_init(self, pos, name, cname):
decls_writer = self.parts['decls']
for _, cname, c in c_consts:
+ conditional = False
+ if c.py_versions and (2 not in c.py_versions or 3 not in c.py_versions):
+ conditional = True
+ decls_writer.putln("#if PY_MAJOR_VERSION %s 3" % (
+ (2 in c.py_versions) and '<' or '>='))
decls_writer.putln('static char %s[] = "%s";' % (
cname, StringEncoding.split_string_literal(c.escaped_value)))
+ if conditional:
+ decls_writer.putln("#endif")
if c.py_strings is not None:
for py_string in c.py_strings.values():
py_strings.append((c.cname, len(py_string.cname), py_string))
decls_writer.putln(
"static PyObject *%s;" % py_string.cname)
+ if py_string.py3str_cstring:
+ w.putln("#if PY_MAJOR_VERSION >= 3")
+ w.putln(
+ "{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
+ py_string.cname,
+ py_string.py3str_cstring.cname,
+ py_string.py3str_cstring.cname,
+ '0', 1, 0,
+ py_string.intern
+ ))
+ w.putln("#else")
w.putln(
"{&%s, %s, sizeof(%s), %s, %d, %d, %d}," % (
py_string.cname,
py_string.is_str,
py_string.intern
))
+ if py_string.py3str_cstring:
+ w.putln("#endif")
w.putln("{0, 0, 0, 0, 0, 0, 0}")
w.putln("};")
def get_string_const(self, text):
return self.globalstate.get_string_const(text).cname
- def get_py_string_const(self, text, identifier=None, is_str=False):
- return self.globalstate.get_py_string_const(text, identifier, is_str).cname
+ def get_py_string_const(self, text, identifier=None,
+ is_str=False, unicode_value=None):
+ return self.globalstate.get_py_string_const(
+ text, identifier, is_str, unicode_value).cname
def get_argument_default_const(self, type):
return self.globalstate.get_py_const(type).cname
#if entry.type.is_extension_type:
# code = "((PyObject*)%s)" % code
self.put_init_to_py_none(code, entry.type, nanny)
+ if entry.in_closure:
+ self.put_giveref('Py_None')
def put_pymethoddef(self, entry, term, allow_skip=True):
if entry.is_special or entry.name == '__getattribute__':
def lookup_filename(self, filename):
return self.globalstate.lookup_filename(filename)
+ def put_declare_refcount_context(self):
+ self.putln('__Pyx_RefNannyDeclarations')
+
def put_setup_refcount_context(self, name):
self.putln('__Pyx_RefNannySetupContext("%s");' % name)
def dedent(self):
self.level -= 1
+
+class ClosureTempAllocator(object):
+ def __init__(self, klass):
+ self.klass = klass
+ self.temps_allocated = {}
+ self.temps_free = {}
+ self.temps_count = 0
+
+ def reset(self):
+ for type, cnames in self.temps_allocated.items():
+ self.temps_free[type] = list(cnames)
+
+ def allocate_temp(self, type):
+ if not type in self.temps_allocated:
+ self.temps_allocated[type] = []
+ self.temps_free[type] = []
+ elif self.temps_free[type]:
+ return self.temps_free[type].pop(0)
+ cname = '%s%d' % (Naming.codewriter_temp_prefix, self.temps_count)
+ self.klass.declare_var(pos=None, name=cname, cname=cname, type=type, is_cdef=True)
+ self.temps_allocated[type].append(cname)
+ self.temps_count += 1
+ return cname
def warning(position, message, level=0):
if level < LEVEL:
return
+ if Options.warning_errors and position:
+ return error(position, message)
warn = CompileWarning(position, message)
line = "warning: %s\n" % warn
if listing_file:
# [ExprNode or [ExprNode or None] or None]
# Cached result of subexpr_nodes()
# use_managed_ref boolean use ref-counted temps/assignments/etc.
+ # result_is_used boolean indicates that the result will be dropped and the
+ # result_code/temp_result can safely be set to None
result_ctype = None
type = None
temp_code = None
old_temp = None # error checker for multiple frees etc.
use_managed_ref = True # can be set by optimisation transforms
+ result_is_used = True
# The Analyse Expressions phase for expressions is split
# into two sub-phases:
def release_temp_result(self, code):
if not self.temp_code:
+ if not self.result_is_used:
+ # not used anyway, so ignore if not set up
+ return
if self.old_temp:
raise RuntimeError("temp %s released multiple times in %s" % (
self.old_temp, self.__class__.__name__))
def generate_disposal_code(self, code):
if self.is_temp:
- if self.type.is_pyobject:
+ if self.type.is_pyobject and self.result():
code.put_decref_clear(self.result(), self.ctype())
else:
# Already done if self.is_temp
if not dst_type.is_pyobject:
return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env)
self.check_for_coercion_error(dst_type, fail=True)
-
- # this will be a unicode string in Py3, so make sure we can decode it
- if self.value.encoding and isinstance(self.value, StringEncoding.BytesLiteral):
- try:
- self.value.decode(self.value.encoding)
- except UnicodeDecodeError:
- error(self.pos, ("Decoding unprefixed string literal from '%s' failed. Consider using"
- "a byte string or unicode string explicitly, "
- "or adjust the source code encoding.") % self.value.encoding)
-
return self
def can_coerce_to_char_literal(self):
def generate_evaluation_code(self, code):
self.result_code = code.get_py_string_const(
- self.value, identifier=self.is_identifier, is_str=True)
+ self.value, identifier=self.is_identifier, is_str=True,
+ unicode_value=self.unicode_value)
def get_constant_c_result_code(self):
return None
if entry and entry.is_cfunction:
var_entry = entry.as_variable
if var_entry:
- if var_entry.is_builtin and Options.cache_builtins:
+ if var_entry.is_builtin and var_entry.is_const:
var_entry = env.declare_builtin(var_entry.name, self.pos)
node = NameNode(self.pos, name = self.name)
node.entry = var_entry
if entry.is_declared_generic:
self.result_ctype = py_object_type
if entry.is_pyglobal or entry.is_builtin:
- if Options.cache_builtins and entry.is_builtin:
+ if entry.is_builtin and entry.is_const:
self.is_temp = 0
else:
self.is_temp = 1
if self.is_used_as_rvalue:
entry = self.entry
if entry.is_builtin:
- if not Options.cache_builtins: # cached builtins are ok
+ if not entry.is_const: # cached builtins are ok
self.gil_error()
elif entry.is_pyglobal:
self.gil_error()
entry = self.entry
if entry is None:
return # There was an error earlier
- if entry.is_builtin and Options.cache_builtins:
+ if entry.is_builtin and entry.is_const:
return # Lookup already cached
elif entry.is_pyclass_attr:
assert entry.type.is_pyobject, "Python global or builtin not a Python object"
#print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
if self.use_managed_ref:
rhs.make_owned_reference(code)
- if entry.is_cglobal:
- code.put_gotref(self.py_result())
+ is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure
if not self.lhs_of_first_assignment:
+ if is_external_ref:
+ code.put_gotref(self.py_result())
if entry.is_local and not Options.init_local_none:
initialized = entry.scope.control_flow.get_state((entry.name, 'initialized'), self.pos)
if initialized is True:
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
- if entry.is_cglobal:
+ if is_external_ref:
code.put_giveref(rhs.py_result())
code.putln('%s = %s;' % (self.result(),
def generate_deletion_code(self, code):
if self.entry is None:
return # There was an error earlier
- elif self.entry.is_pyglobal:
- code.put_error_if_neg(self.pos,
- '__Pyx_DelAttrString(%s, "%s")' % (
- Naming.module_cname,
- self.entry.name))
elif self.entry.is_pyclass_attr:
namespace = self.entry.scope.namespace_cname
code.put_error_if_neg(self.pos,
'PyMapping_DelItemString(%s, "%s")' % (
namespace,
self.entry.name))
+ elif self.entry.is_pyglobal:
+ code.put_error_if_neg(self.pos,
+ '__Pyx_DelAttrString(%s, "%s")' % (
+ Naming.module_cname,
+ self.entry.name))
elif self.entry.type.is_pyobject:
# Fake it until we can do it for real...
self.generate_assignment_code(NoneNode(self.pos), code)
code.put_gotref(self.py_result())
-
class ImportNode(ExprNode):
# Used as part of import statement implementation.
# Implements result =
- # __import__(module_name, globals(), None, name_list)
+ # __import__(module_name, globals(), None, name_list, level)
#
- # module_name StringNode dotted name of module
+ # module_name StringNode dotted name of module. Empty module
+ # name means importing the parent package accourding
+ # to level
# name_list ListNode or None list of names to be imported
+ # level int relative import level:
+ # -1: attempt both relative import and absolute import;
+ # 0: absolute import;
+ # >0: the number of parent directories to search
+ # relative to the current module.
+ # None: decide the level according to language level and
+ # directives
type = py_object_type
subexprs = ['module_name', 'name_list']
def analyse_types(self, env):
+ if self.level is None:
+ if env.directives['language_level'] < 3 or env.directives['py2_import']:
+ self.level = -1
+ else:
+ self.level = 0
self.module_name.analyse_types(env)
self.module_name = self.module_name.coerce_to_pyobject(env)
if self.name_list:
else:
name_list_code = "0"
code.putln(
- "%s = __Pyx_Import(%s, %s); %s" % (
+ "%s = __Pyx_Import(%s, %s, %d); %s" % (
self.result(),
self.module_name.py_result(),
name_list_code,
+ self.level,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
code.putln("}")
+class WithExitCallNode(ExprNode):
+ # The __exit__() call of a 'with' statement. Used in both the
+ # except and finally clauses.
+
+ # with_stat WithStatNode the surrounding 'with' statement
+ # args TupleNode or ResultStatNode the exception info tuple
+
+ subexprs = ['args']
+
+ def analyse_types(self, env):
+ self.args.analyse_types(env)
+ self.type = PyrexTypes.c_bint_type
+ self.is_temp = True
+
+ def generate_result_code(self, code):
+ if isinstance(self.args, TupleNode):
+ # call only if it was not already called (and decref-cleared)
+ code.putln("if (%s) {" % self.with_stat.exit_var)
+ result_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
+ code.putln("%s = PyObject_Call(%s, %s, NULL);" % (
+ result_var,
+ self.with_stat.exit_var,
+ self.args.result()))
+ code.put_decref_clear(self.with_stat.exit_var, type=py_object_type)
+ code.putln(code.error_goto_if_null(result_var, self.pos))
+ code.put_gotref(result_var)
+ code.putln("%s = __Pyx_PyObject_IsTrue(%s);" % (self.result(), result_var))
+ code.put_decref_clear(result_var, type=py_object_type)
+ code.putln(code.error_goto_if_neg(self.result(), self.pos))
+ code.funcstate.release_temp(result_var)
+ if isinstance(self.args, TupleNode):
+ code.putln("}")
+
+
class ExcValueNode(AtomicExprNode):
# Node created during analyse_types phase
# of an ExceptClauseNode to fetch the current
subexprs = []
- def __init__(self, pos, type, env):
+ def __init__(self, pos, type, env=None):
ExprNode.__init__(self, pos)
self.type = type
if type.is_pyobject:
def analyse_types(self, env):
return self.type
+ def analyse_target_declaration(self, env):
+ pass
+
def generate_result_code(self, code):
pass
self.value_expr.annotate(code)
-class GeneratorExpressionNode(ScopedExprNode):
- # A generator expression, e.g. (i for i in range(10))
- #
- # Result is a generator.
+class InlinedGeneratorExpressionNode(ScopedExprNode):
+ # An inlined generator expression for which the result is
+ # calculated inside of the loop. This will only be created by
+ # transforms when replacing builtin calls on generator
+ # expressions.
#
- # loop ForStatNode the for-loop, containing a YieldExprNode
+ # loop ForStatNode the for-loop, not containing any YieldExprNodes
+ # result_node ResultRefNode the reference to the result value temp
+ # orig_func String the name of the builtin function this node replaces
child_attrs = ["loop"]
-
+ loop_analysed = False
type = py_object_type
def analyse_scoped_declarations(self, env):
self.loop.analyse_expressions(env)
self.is_temp = True
- def analyse_scoped_expressions(self, env):
- if self.has_local_scope:
- self.loop.analyse_expressions(env)
-
def may_be_none(self):
return False
def annotate(self, code):
self.loop.annotate(code)
-
-class InlinedGeneratorExpressionNode(GeneratorExpressionNode):
- # An inlined generator expression for which the result is
- # calculated inside of the loop. This will only be created by
- # transforms when replacing builtin calls on generator
- # expressions.
- #
- # loop ForStatNode the for-loop, not containing any YieldExprNodes
- # result_node ResultRefNode the reference to the result value temp
- # orig_func String the name of the builtin function this node replaces
-
- child_attrs = ["loop"]
- loop_analysed = False
-
def infer_type(self, env):
return self.result_node.infer_type(env)
def analyse_scoped_expressions(self, env):
self.loop_analysed = True
- GeneratorExpressionNode.analyse_scoped_expressions(self, env)
+ if self.has_local_scope:
+ self.loop.analyse_expressions(env)
def coerce_to(self, dst_type, env):
if self.orig_func == 'sum' and dst_type.is_numeric and not self.loop_analysed:
# assignments.
self.result_node.type = self.type = dst_type
return self
- return GeneratorExpressionNode.coerce_to(self, dst_type, env)
+ return super(InlinedGeneratorExpressionNode, self).coerce_to(dst_type, env)
def generate_result_code(self, code):
self.result_node.result_code = self.result()
self.pymethdef_cname = self.def_node.entry.pymethdef_cname
env.add_lambda_def(self.def_node)
+
+class GeneratorExpressionNode(LambdaNode):
+ # A generator expression, e.g. (i for i in range(10))
+ #
+ # Result is a generator.
+ #
+ # loop ForStatNode the for-loop, containing a YieldExprNode
+ # def_node DefNode the underlying generator 'def' node
+
+ name = StringEncoding.EncodedString('genexpr')
+ binding = False
+
+ def analyse_declarations(self, env):
+ self.def_node.no_assignment_synthesis = True
+ self.def_node.analyse_declarations(env)
+ env.add_lambda_def(self.def_node)
+
+ def generate_result_code(self, code):
+ code.putln(
+ '%s = %s(%s, NULL); %s' % (
+ self.result(),
+ self.def_node.entry.func_cname,
+ self.self_result_code(),
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_gotref(self.py_result())
+
+
class YieldExprNode(ExprNode):
# Yield expression node
#
# arg ExprNode the value to return from the generator
# label_name string name of the C label used for this yield
+ # label_num integer yield label number
subexprs = ['arg']
type = py_object_type
+ label_num = 0
def analyse_types(self, env):
+ if not self.label_num:
+ error(self.pos, "'yield' not supported here")
self.is_temp = 1
if self.arg is not None:
self.arg.analyse_types(env)
if not self.arg.type.is_pyobject:
self.arg = self.arg.coerce_to_pyobject(env)
- error(self.pos, "Generators are not supported")
+ env.use_utility_code(generator_utility_code)
- def generate_result_code(self, code):
+ def generate_evaluation_code(self, code):
self.label_name = code.new_label('resume_from_yield')
code.use_label(self.label_name)
- code.putln("/* FIXME: save temporary variables */")
- code.putln("/* FIXME: return from function, yielding value */")
+ if self.arg:
+ self.arg.generate_evaluation_code(code)
+ self.arg.make_owned_reference(code)
+ code.putln(
+ "%s = %s;" % (
+ Naming.retval_cname,
+ self.arg.result_as(py_object_type)))
+ self.arg.generate_post_assignment_code(code)
+ #self.arg.generate_disposal_code(code)
+ self.arg.free_temps(code)
+ else:
+ code.put_init_to_py_none(Naming.retval_cname, py_object_type)
+ saved = []
+ code.funcstate.closure_temps.reset()
+ for cname, type, manage_ref in code.funcstate.temps_in_use():
+ save_cname = code.funcstate.closure_temps.allocate_temp(type)
+ saved.append((cname, save_cname, type))
+ if type.is_pyobject:
+ code.put_xgiveref(cname)
+ code.putln('%s->%s = %s;' % (Naming.cur_scope_cname, save_cname, cname))
+
+ code.put_xgiveref(Naming.retval_cname)
+ code.put_finish_refcount_context()
+ code.putln("/* return from generator, yielding value */")
+ code.putln("%s->%s.resume_label = %d;" % (Naming.cur_scope_cname, Naming.obj_base_cname, self.label_num))
+ code.putln("return %s;" % Naming.retval_cname);
code.put_label(self.label_name)
- code.putln("/* FIXME: restore temporary variables and */")
- code.putln("/* FIXME: extract sent value from closure */")
-
+ for cname, save_cname, type in saved:
+ code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
+ if type.is_pyobject:
+ code.putln('%s->%s = 0;' % (Naming.cur_scope_cname, save_cname))
+ if type.is_pyobject:
+ code.put_xgotref(cname)
+ if self.result_is_used:
+ self.allocate_temp_result(code)
+ code.putln('%s = %s; %s' %
+ (self.result(), Naming.sent_value_cname,
+ code.error_goto_if_null(self.result(), self.pos)))
+ code.put_incref(self.result(), py_object_type)
+ else:
+ code.putln(code.error_goto_if_null(Naming.sent_value_cname, self.pos))
#-------------------------------------------------------------------
#
operator = '+'
def analyse_c_operation(self, env):
- self.type = self.operand.type
+ self.type = PyrexTypes.widest_numeric_type(
+ self.operand.type, PyrexTypes.c_int_type)
def py_operation_function(self):
return "PyNumber_Positive"
def analyse_c_operation(self, env):
if self.operand.type.is_numeric:
- self.type = self.operand.type
+ self.type = PyrexTypes.widest_numeric_type(
+ self.operand.type, PyrexTypes.c_int_type)
else:
self.type_error()
if self.type.is_complex:
def analyse_c_operation(self, env):
if self.operand.type.is_int:
- self.type = self.operand.type
+ self.type = PyrexTypes.widest_numeric_type(
+ self.operand.type, PyrexTypes.c_int_type)
else:
self.type_error()
# unary ++/-- operator
def analyse_c_operation(self, env):
- if self.operand.type.is_ptr or self.operand.type.is_numeric:
+ if self.operand.type.is_numeric:
+ self.type = PyrexTypes.widest_numeric_type(
+ self.operand.type, PyrexTypes.c_int_type)
+ elif self.operand.type.is_ptr:
self.type = self.operand.type
else:
self.type_error()
if self.operator not in '|^&':
# False + False == 0 # not False!
widest_type = PyrexTypes.c_int_type
+ else:
+ widest_type = PyrexTypes.widest_numeric_type(
+ widest_type, PyrexTypes.c_int_type)
return widest_type
else:
return None
import_utility_code = UtilityCode(
proto = """
-static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level); /*proto*/
""",
impl = """
-static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, long level) {
PyObject *py_import = 0;
PyObject *empty_list = 0;
PyObject *module = 0;
empty_dict = PyDict_New();
if (!empty_dict)
goto bad;
+ #if PY_VERSION_HEX >= 0x02050000
+ {
+ PyObject *py_level = PyInt_FromLong(level);
+ if (!py_level)
+ goto bad;
+ module = PyObject_CallFunctionObjArgs(py_import,
+ name, global_dict, empty_dict, list, py_level, NULL);
+ Py_DECREF(py_level);
+ }
+ #else
+ if (level>0) {
+ PyErr_SetString(PyExc_RuntimeError, "Relative import is not supported for Python <=2.4.");
+ goto bad;
+ }
module = PyObject_CallFunctionObjArgs(py_import,
name, global_dict, empty_dict, list, NULL);
+ #endif
bad:
Py_XDECREF(empty_list);
Py_XDECREF(py_import);
#if PY_MAJOR_VERSION < 3
if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
PyObject *base = PyTuple_GET_ITEM(bases, 0);
- metaclass = PyObject_GetAttrString(base, "__class__");
+ metaclass = PyObject_GetAttrString(base, (char *)"__class__");
if (!metaclass) {
PyErr_Clear();
metaclass = (PyObject*) Py_TYPE(base);
PyObject *ns;
PyObject *str;
- prep = PyObject_GetAttrString(metaclass, "__prepare__");
+ prep = PyObject_GetAttrString(metaclass, (char *)"__prepare__");
if (!prep) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
}
""" % Naming.__dict__)
+
+generator_utility_code = UtilityCode(
+proto="""
+static PyObject *__Pyx_Generator_Next(PyObject *self);
+static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value);
+static PyObject *__Pyx_Generator_Close(PyObject *self);
+static PyObject *__Pyx_Generator_Throw(PyObject *gen, PyObject *args, CYTHON_UNUSED PyObject *kwds);
+
+typedef PyObject *(*__pyx_generator_body_t)(PyObject *, PyObject *);
+""",
+impl="""
+static CYTHON_INLINE void __Pyx_Generator_ExceptionClear(struct __pyx_Generator_object *self)
+{
+ Py_XDECREF(self->exc_type);
+ Py_XDECREF(self->exc_value);
+ Py_XDECREF(self->exc_traceback);
+
+ self->exc_type = NULL;
+ self->exc_value = NULL;
+ self->exc_traceback = NULL;
+}
+
+static CYTHON_INLINE PyObject *__Pyx_Generator_SendEx(struct __pyx_Generator_object *self, PyObject *value)
+{
+ PyObject *retval;
+
+ if (self->is_running) {
+ PyErr_SetString(PyExc_ValueError,
+ "generator already executing");
+ return NULL;
+ }
+
+ if (self->resume_label == 0) {
+ if (value && value != Py_None) {
+ PyErr_SetString(PyExc_TypeError,
+ "can't send non-None value to a "
+ "just-started generator");
+ return NULL;
+ }
+ }
+
+ if (self->resume_label == -1) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+
+
+ if (value)
+ __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback);
+ else
+ __Pyx_Generator_ExceptionClear(self);
+
+ self->is_running = 1;
+ retval = self->body((PyObject *) self, value);
+ self->is_running = 0;
+
+ if (retval)
+ __Pyx_ExceptionSwap(&self->exc_type, &self->exc_value, &self->exc_traceback);
+ else
+ __Pyx_Generator_ExceptionClear(self);
+
+ return retval;
+}
+
+static PyObject *__Pyx_Generator_Next(PyObject *self)
+{
+ return __Pyx_Generator_SendEx((struct __pyx_Generator_object *) self, Py_None);
+}
+
+static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value)
+{
+ return __Pyx_Generator_SendEx((struct __pyx_Generator_object *) self, value);
+}
+
+static PyObject *__Pyx_Generator_Close(PyObject *self)
+{
+ struct __pyx_Generator_object *generator = (struct __pyx_Generator_object *) self;
+ PyObject *retval;
+#if PY_VERSION_HEX < 0x02050000
+ PyErr_SetNone(PyExc_StopIteration);
+#else
+ PyErr_SetNone(PyExc_GeneratorExit);
+#endif
+ retval = __Pyx_Generator_SendEx(generator, NULL);
+ if (retval) {
+ Py_DECREF(retval);
+ PyErr_SetString(PyExc_RuntimeError,
+ "generator ignored GeneratorExit");
+ return NULL;
+ }
+#if PY_VERSION_HEX < 0x02050000
+ if (PyErr_ExceptionMatches(PyExc_StopIteration))
+#else
+ if (PyErr_ExceptionMatches(PyExc_StopIteration)
+ || PyErr_ExceptionMatches(PyExc_GeneratorExit))
+#endif
+ {
+ PyErr_Clear(); /* ignore these errors */
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return NULL;
+}
+
+static PyObject *__Pyx_Generator_Throw(PyObject *self, PyObject *args, CYTHON_UNUSED PyObject *kwds)
+{
+ struct __pyx_Generator_object *generator = (struct __pyx_Generator_object *) self;
+ PyObject *typ;
+ PyObject *tb = NULL;
+ PyObject *val = NULL;
+
+ if (!PyArg_UnpackTuple(args, (char *)"throw", 1, 3, &typ, &val, &tb))
+ return NULL;
+ __Pyx_Raise(typ, val, tb);
+ return __Pyx_Generator_SendEx(generator, NULL);
+}
+""",
+proto_block='utility_code_proto_before_types',
+requires=[Nodes.raise_utility_code, Nodes.swap_exception_utility_code],
+)
try:
return getattr(__future__, name)
except AttributeError:
- # unique fake object for earlier Python versions
+ # unique fake object for earlier Python versions or Python 3
return object()
unicode_literals = _get_feature("unicode_literals")
division = _get_feature("division")
print_function = _get_feature("print_function")
nested_scopes = _get_feature("nested_scopes") # dummy
+generators = _get_feature("generators") # dummy
del _get_feature
-# cython: language_level=3
+# cython: language_level=3, py2_import=True
#
# Cython Scanner - Lexical Definitions
#
PostParse(self),
_specific_post_parse,
InterpretCompilerDirectives(self, self.compiler_directives),
- _align_function_definitions,
MarkClosureVisitor(self),
+ _align_function_definitions,
ConstantFolding(),
FlattenInListTransform(),
WithTransform(self),
if os.path.exists(html_filename):
line = codecs.open(html_filename, "r", encoding="UTF-8").readline()
if line.startswith(u'<!-- Generated by Cython'):
- options.annotate = True
+ options.annotate = True
# Get pipeline
if source_ext.lower() == '.py':
f.close()
def generate_h_code(self, env, options, result):
- def h_entries(entries, pxd = 0):
+ def h_entries(entries, api=0, pxd=0):
return [entry for entry in entries
- if entry.visibility == 'public' or pxd and entry.defined_in_pxd]
- h_types = h_entries(env.type_entries)
+ if ((entry.visibility == 'public') or
+ (api and entry.api) or
+ (pxd and entry.defined_in_pxd))]
+ h_types = h_entries(env.type_entries, api=1)
h_vars = h_entries(env.var_entries)
h_funcs = h_entries(env.cfunc_entries)
h_extension_types = h_entries(env.c_class_entries)
- if h_types or h_vars or h_funcs or h_extension_types:
+ if (h_types or h_vars or h_funcs or h_extension_types):
result.h_file = replace_suffix(result.c_file, ".h")
h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
i_code = Code.PyrexCodeWriter(result.i_file)
else:
i_code = None
- guard = Naming.h_guard_prefix + env.qualified_name.replace(".", "__")
- h_code.put_h_guard(guard)
- self.generate_extern_c_macro_definition(h_code)
+
+ h_guard = Naming.h_guard_prefix + self.api_name(env)
+ h_code.put_h_guard(h_guard)
+ h_code.putln("")
self.generate_type_header_code(h_types, h_code)
h_code.putln("")
- h_code.putln("#ifndef %s" % Naming.api_guard_prefix + self.api_name(env))
- if h_vars:
- h_code.putln("")
- for entry in h_vars:
- self.generate_public_declaration(entry, h_code, i_code)
- if h_funcs:
- h_code.putln("")
- for entry in h_funcs:
- self.generate_public_declaration(entry, h_code, i_code)
+ api_guard = Naming.api_guard_prefix + self.api_name(env)
+ h_code.putln("#ifndef %s" % api_guard)
+ h_code.putln("")
+ self.generate_extern_c_macro_definition(h_code)
if h_extension_types:
h_code.putln("")
for entry in h_extension_types:
self.generate_cclass_header_code(entry.type, h_code)
if i_code:
self.generate_cclass_include_code(entry.type, i_code)
+ if h_funcs:
+ h_code.putln("")
+ for entry in h_funcs:
+ self.generate_public_declaration(entry, h_code, i_code)
+ if h_vars:
+ h_code.putln("")
+ for entry in h_vars:
+ self.generate_public_declaration(entry, h_code, i_code)
h_code.putln("")
- h_code.putln("#endif")
+ h_code.putln("#endif /* !%s */" % api_guard)
h_code.putln("")
+ h_code.putln("#if PY_MAJOR_VERSION < 3")
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
- h_code.putln("")
+ h_code.putln("#else")
+ h_code.putln("PyMODINIT_FUNC PyInit_%s(void);" % env.module_name)
h_code.putln("#endif")
+ h_code.putln("")
+ h_code.putln("#endif /* !%s */" % h_guard)
f = open_new_file(result.h_file)
try:
return env.qualified_name.replace(".", "__")
def generate_api_code(self, env, result):
- api_funcs = []
- public_extension_types = []
- has_api_extension_types = 0
- for entry in env.cfunc_entries:
- if entry.api:
- api_funcs.append(entry)
- for entry in env.c_class_entries:
- if entry.visibility == 'public':
- public_extension_types.append(entry)
- if entry.api:
- has_api_extension_types = 1
- if api_funcs or has_api_extension_types:
+ def api_entries(entries, pxd=0):
+ return [entry for entry in entries
+ if entry.api or (pxd and entry.defined_in_pxd)]
+ api_vars = api_entries(env.var_entries)
+ api_funcs = api_entries(env.cfunc_entries)
+ api_extension_types = api_entries(env.c_class_entries)
+ if api_vars or api_funcs or api_extension_types:
result.api_file = replace_suffix(result.c_file, "_api.h")
h_code = Code.CCodeWriter()
Code.GlobalState(h_code)
- name = self.api_name(env)
- guard = Naming.api_guard_prefix + name
- h_code.put_h_guard(guard)
+ api_guard = Naming.api_guard_prefix + self.api_name(env)
+ h_code.put_h_guard(api_guard)
h_code.putln('#include "Python.h"')
if result.h_file:
h_code.putln('#include "%s"' % os.path.basename(result.h_file))
- for entry in public_extension_types:
- type = entry.type
+ if api_extension_types:
h_code.putln("")
- h_code.putln("static PyTypeObject *%s;" % type.typeptr_cname)
- h_code.putln("#define %s (*%s)" % (
- type.typeobj_cname, type.typeptr_cname))
+ for entry in api_extension_types:
+ type = entry.type
+ h_code.putln("static PyTypeObject *%s = 0;" % type.typeptr_cname)
+ h_code.putln("#define %s (*%s)" % (
+ type.typeobj_cname, type.typeptr_cname))
if api_funcs:
h_code.putln("")
for entry in api_funcs:
type = CPtrType(entry.type)
- h_code.putln("static %s;" % type.declaration_code(entry.cname))
- h_code.putln("")
- h_code.put_h_guard(Naming.api_func_guard + "import_module")
+ cname = env.mangle(Naming.func_prefix, entry.name)
+ h_code.putln("static %s = 0;" % type.declaration_code(cname))
+ h_code.putln("#define %s %s" % (entry.name, cname))
+ if api_vars:
+ h_code.putln("")
+ for entry in api_vars:
+ type = CPtrType(entry.type)
+ cname = env.mangle(Naming.var_prefix, entry.name)
+ h_code.putln("static %s = 0;" % type.declaration_code(cname))
+ h_code.putln("#define %s (*%s)" % (entry.name, cname))
h_code.put(import_module_utility_code.impl)
- h_code.putln("")
- h_code.putln("#endif")
+ if api_vars:
+ h_code.put(voidptr_import_utility_code.impl)
if api_funcs:
- h_code.putln("")
h_code.put(function_import_utility_code.impl)
- if public_extension_types:
- h_code.putln("")
+ if api_extension_types:
h_code.put(type_import_utility_code.impl)
h_code.putln("")
- h_code.putln("static int import_%s(void) {" % name)
+ h_code.putln("static int import_%s(void) {" % self.api_name(env))
h_code.putln("PyObject *module = 0;")
h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name)
h_code.putln("if (!module) goto bad;")
for entry in api_funcs:
+ cname = env.mangle(Naming.func_prefix, entry.name)
sig = entry.type.signature_string()
h_code.putln(
- 'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' % (
- entry.name,
- entry.cname,
- sig))
+ 'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;'
+ % (entry.name, cname, sig))
+ for entry in api_vars:
+ cname = env.mangle(Naming.var_prefix, entry.name)
+ sig = entry.type.declaration_code("")
+ h_code.putln(
+ 'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
+ % (entry.name, cname, sig))
h_code.putln("Py_DECREF(module); module = 0;")
- for entry in public_extension_types:
+ for entry in api_extension_types:
self.generate_type_import_call(
entry.type, h_code,
"if (!%s) goto bad;" % entry.type.typeptr_cname)
h_code.putln("return -1;")
h_code.putln("}")
h_code.putln("")
- h_code.putln("#endif")
+ h_code.putln("#endif /* !%s */" % api_guard)
f = open_new_file(result.api_file)
try:
f.close()
def generate_cclass_header_code(self, type, h_code):
- h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
+ h_code.putln("%s %s %s;" % (
Naming.extern_c_macro,
+ PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
type.typeobj_cname))
def generate_cclass_include_code(self, type, i_code):
self.generate_objstruct_definition(type, code)
for entry in vtabslot_list:
self.generate_objstruct_definition(entry.type, code)
+ self.generate_typeobj_predeclaration(entry, code)
for entry in vtab_list:
- self.generate_typeobject_predeclaration(entry, code)
+ self.generate_typeobj_predeclaration(entry, code)
self.generate_exttype_vtable_struct(entry, code)
self.generate_exttype_vtabptr_declaration(entry, code)
code.putln("#define _USE_MATH_DEFINES")
code.putln("#endif")
code.putln("#include <math.h>")
+ code.putln("#define %s" % Naming.h_guard_prefix + self.api_name(env))
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code)
code.putln("")
def generate_extern_c_macro_definition(self, code):
name = Naming.extern_c_macro
- code.putln("#ifdef __cplusplus")
- code.putln('#define %s extern "C"' % name)
- code.putln("#else")
- code.putln("#define %s extern" % name)
+ code.putln("#ifndef %s" % name)
+ code.putln(" #ifdef __cplusplus")
+ code.putln(' #define %s extern "C"' % name)
+ code.putln(" #else")
+ code.putln(" #define %s extern" % name)
+ code.putln(" #endif")
code.putln("#endif")
def generate_includes(self, env, cimported_modules, code):
def generate_typedef(self, entry, code):
base_type = entry.type.typedef_base_type
if base_type.is_numeric:
- writer = code.globalstate['numeric_typedefs']
+ try:
+ writer = code.globalstate['numeric_typedefs']
+ except KeyError:
+ writer = code
else:
writer = code
- writer.putln("")
+ writer.mark_pos(entry.pos)
writer.putln("typedef %s;" % base_type.declaration_code(entry.cname))
def sue_header_footer(self, type, kind, name):
code.globalstate.use_utility_code(packed_struct_utility_code)
header, footer = \
self.sue_header_footer(type, kind, type.cname)
- code.putln("")
if packed:
code.putln("#if defined(__SUNPRO_C)")
code.putln(" #pragma pack(1)")
name = entry.cname or entry.name or ""
header, footer = \
self.sue_header_footer(type, "enum", name)
- code.putln("")
code.putln(header)
enum_values = entry.enum_values
if not enum_values:
code.putln(value_code)
code.putln(footer)
- def generate_typeobject_predeclaration(self, entry, code):
+ def generate_typeobj_predeclaration(self, entry, code):
code.putln("")
name = entry.type.typeobj_cname
if name:
if entry.visibility == 'extern' and not entry.in_cinclude:
- code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
+ code.putln("%s %s %s;" % (
Naming.extern_c_macro,
+ PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
name))
elif entry.visibility == 'public':
- code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
+ code.putln("%s %s %s;" % (
Naming.extern_c_macro,
+ PyrexTypes.public_decl("PyTypeObject", "DL_EXPORT"),
name))
# ??? Do we really need the rest of this? ???
#else:
- # code.putln("staticforward PyTypeObject %s;" % name)
+ # code.putln("static PyTypeObject %s;" % name)
def generate_exttype_vtable_struct(self, entry, code):
code.mark_pos(entry.pos)
return # Forward declared but never defined
header, footer = \
self.sue_header_footer(type, "struct", type.objstruct_cname)
- code.putln("")
code.putln(header)
base_type = type.base_type
if base_type:
type.vtabstruct_cname,
type.vtabslot_cname))
for attr in type.scope.var_entries:
+ if attr.is_declared_generic:
+ attr_type = py_object_type
+ else:
+ attr_type = attr.type
code.putln(
"%s;" %
- attr.type.declaration_code(attr.cname))
+ attr_type.declaration_code(attr.cname))
code.putln(footer)
if type.objtypedef_cname is not None:
# Only for exposing public typedef name.
for entry in env.cfunc_entries:
if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
or entry.defined_in_pxd or entry.visibility == 'extern')):
- if entry.visibility in ('public', 'extern'):
+ if entry.visibility == 'public':
+ storage_class = "%s " % Naming.extern_c_macro
dll_linkage = "DL_EXPORT"
+ elif entry.visibility == 'extern':
+ storage_class = "%s " % Naming.extern_c_macro
+ dll_linkage = "DL_IMPORT"
+ elif entry.visibility == 'private':
+ storage_class = "static "
+ dll_linkage = None
else:
+ storage_class = "static "
dll_linkage = None
type = entry.type
+
if not definition and entry.defined_in_pxd:
type = CPtrType(type)
header = type.declaration_code(entry.cname,
- dll_linkage = dll_linkage)
- if entry.visibility == 'private':
- storage_class = "static "
- elif entry.visibility == 'public':
- storage_class = ""
- else:
- storage_class = "%s " % Naming.extern_c_macro
+ dll_linkage = dll_linkage)
if entry.func_modifiers:
- modifiers = '%s ' % ' '.join([
- modifier.upper() for modifier in entry.func_modifiers])
+ modifiers = "%s " % ' '.join(entry.func_modifiers).upper()
else:
modifiers = ''
code.putln("%s%s%s; /*proto*/" % (
for entry in py_attrs:
name = "p->%s" % entry.cname
code.putln("tmp = ((PyObject*)%s);" % name)
- code.put_init_to_py_none(name, entry.type, nanny=False)
+ if entry.is_declared_generic:
+ code.put_init_to_py_none(name, py_object_type, nanny=False)
+ else:
+ code.put_init_to_py_none(name, entry.type, nanny=False)
code.putln("Py_XDECREF(tmp);")
code.putln(
"return 0;")
code.putln("#endif")
code.putln("{")
tempdecl_code = code.insertion_point()
-
+
+ code.put_declare_refcount_context()
code.putln("#if CYTHON_REFNANNY")
- code.putln("void* __pyx_refnanny = NULL;")
code.putln("__Pyx_RefNanny = __Pyx_RefNannyImportAPI(\"refnanny\");")
code.putln("if (!__Pyx_RefNanny) {")
code.putln(" PyErr_Clear();")
code.putln(" if (!__Pyx_RefNanny)")
code.putln(" Py_FatalError(\"failed to import 'refnanny' module\");")
code.putln("}")
- code.putln("__pyx_refnanny = __Pyx_RefNanny->SetupContext(\"%s\", __LINE__, __FILE__);"% header3)
code.putln("#endif")
+ code.put_setup_refcount_context(header3)
env.use_utility_code(check_binary_version_utility_code)
code.putln("if ( __Pyx_check_binary_version() < 0) %s" % code.error_goto(self.pos))
code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code)
+ code.putln("/*--- Variable export code ---*/")
+ self.generate_c_variable_export_code(env, code)
+
code.putln("/*--- Function export code ---*/")
self.generate_c_function_export_code(env, code)
if entry.type.is_pyobject and entry.used:
code.put_init_var_to_py_none(entry, nanny=False)
+ def generate_c_variable_export_code(self, env, code):
+ # Generate code to create PyCFunction wrappers for exported C functions.
+ for entry in env.var_entries:
+ if entry.api or entry.defined_in_pxd:
+ env.use_utility_code(voidptr_export_utility_code)
+ signature = entry.type.declaration_code("")
+ code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % (
+ entry.name,
+ entry.cname,
+ signature,
+ code.error_goto(self.pos)))
+
def generate_c_function_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions.
for entry in env.cfunc_entries:
else:
objstruct = "struct %s" % type.objstruct_cname
module_name = type.module_name
+ condition = None
if module_name not in ('__builtin__', 'builtins'):
module_name = '"%s"' % module_name
else:
module_name = '__Pyx_BUILTIN_MODULE_NAME'
- if type.name in self.py3_type_name_map:
- code.putln("#if PY_MAJOR_VERSION >= 3")
- code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % (
- type.typeptr_cname,
- module_name,
- self.py3_type_name_map[type.name],
- objstruct,
- error_code))
- code.putln("#else")
+ if type.name in Code.non_portable_builtins_map:
+ condition, replacement = Code.non_portable_builtins_map[entry.name]
+ code.putln("#if %s" % condition)
+ code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % (
+ type.typeptr_cname,
+ module_name,
+ replacement,
+ objstruct,
+ error_code))
+ code.putln("#else")
code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), %i); %s' % (
type.typeptr_cname,
module_name,
objstruct,
not type.is_external or type.is_subclassed,
error_code))
- if type.name in self.py3_type_name_map:
+ if condition:
code.putln("#endif")
def generate_type_ready_code(self, env, entry, code):
#------------------------------------------------------------------------------------
+voidptr_export_utility_code = UtilityCode(
+proto = """
+static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig); /*proto*/
+""",
+impl = r"""
+static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig) {
+ PyObject *d = 0;
+ PyObject *cobj = 0;
+
+ d = PyObject_GetAttrString(%(MODULE)s, (char *)"%(API)s");
+ if (!d) {
+ PyErr_Clear();
+ d = PyDict_New();
+ if (!d)
+ goto bad;
+ Py_INCREF(d);
+ if (PyModule_AddObject(%(MODULE)s, (char *)"%(API)s", d) < 0)
+ goto bad;
+ }
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
+ cobj = PyCapsule_New(p, sig, 0);
+#else
+ cobj = PyCObject_FromVoidPtrAndDesc(p, (void *)sig, 0);
+#endif
+ if (!cobj)
+ goto bad;
+ if (PyDict_SetItemString(d, name, cobj) < 0)
+ goto bad;
+ Py_DECREF(cobj);
+ Py_DECREF(d);
+ return 0;
+bad:
+ Py_XDECREF(cobj);
+ Py_XDECREF(d);
+ return -1;
+}
+""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
+)
+
function_export_utility_code = UtilityCode(
proto = """
static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/
""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
)
+voidptr_import_utility_code = UtilityCode(
+proto = """
+static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig); /*proto*/
+""",
+impl = """
+#ifndef __PYX_HAVE_RT_ImportVoidPtr
+#define __PYX_HAVE_RT_ImportVoidPtr
+static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig) {
+ PyObject *d = 0;
+ PyObject *cobj = 0;
+
+ d = PyObject_GetAttrString(module, (char *)"%(API)s");
+ if (!d)
+ goto bad;
+ cobj = PyDict_GetItemString(d, name);
+ if (!cobj) {
+ PyErr_Format(PyExc_ImportError,
+ "%%s does not export expected C variable %%s",
+ PyModule_GetName(module), name);
+ goto bad;
+ }
+#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
+ if (!PyCapsule_IsValid(cobj, sig)) {
+ PyErr_Format(PyExc_TypeError,
+ "C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
+ PyModule_GetName(module), name, sig, PyCapsule_GetName(cobj));
+ goto bad;
+ }
+ *p = PyCapsule_GetPointer(cobj, sig);
+#else
+ {const char *desc, *s1, *s2;
+ desc = (const char *)PyCObject_GetDesc(cobj);
+ if (!desc)
+ goto bad;
+ s1 = desc; s2 = sig;
+ while (*s1 != '\\0' && *s1 == *s2) { s1++; s2++; }
+ if (*s1 != *s2) {
+ PyErr_Format(PyExc_TypeError,
+ "C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
+ PyModule_GetName(module), name, sig, desc);
+ goto bad;
+ }
+ *p = PyCObject_AsVoidPtr(cobj);}
+#endif
+ if (!(*p))
+ goto bad;
+ Py_DECREF(d);
+ return 0;
+bad:
+ Py_XDECREF(d);
+ return -1;
+}
+#endif
+""" % dict(API = Naming.api_name)
+)
+
function_import_utility_code = UtilityCode(
proto = """
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/
""" % {'IMPORT_STAR' : Naming.import_star,
'IMPORT_STAR_SET' : Naming.import_star_set }
-refnanny_utility_code = UtilityCode(proto="""
+refnanny_utility_code = UtilityCode(
+proto="""
#ifndef CYTHON_REFNANNY
#define CYTHON_REFNANNY 0
#endif
void (*FinishContext)(void**);
} __Pyx_RefNannyAPIStruct;
static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
- static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) {
- PyObject *m = NULL, *p = NULL;
- void *r = NULL;
- m = PyImport_ImportModule((char *)modname);
- if (!m) goto end;
- p = PyObject_GetAttrString(m, (char *)\"RefNannyAPI\");
- if (!p) goto end;
- r = PyLong_AsVoidPtr(p);
- end:
- Py_XDECREF(p);
- Py_XDECREF(m);
- return (__Pyx_RefNannyAPIStruct *)r;
- }
+ static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); /*proto*/
+ #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL;
#define __Pyx_RefNannySetupContext(name) \
- void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
+ __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
#define __Pyx_RefNannyFinishContext() \
__Pyx_RefNanny->FinishContext(&__pyx_refnanny)
- #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+ #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+ #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
+ #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0)
+ #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0)
+ #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0)
+ #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0)
+ #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0)
#else
+ #define __Pyx_RefNannyDeclarations
#define __Pyx_RefNannySetupContext(name)
#define __Pyx_RefNannyFinishContext()
#define __Pyx_INCREF(r) Py_INCREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_GOTREF(r)
#define __Pyx_GIVEREF(r)
+ #define __Pyx_XINCREF(r) Py_XINCREF(r)
#define __Pyx_XDECREF(r) Py_XDECREF(r)
+ #define __Pyx_XGOTREF(r)
+ #define __Pyx_XGIVEREF(r)
#endif /* CYTHON_REFNANNY */
-#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0)
-#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0)
-""")
-
+""",
+impl="""
+#if CYTHON_REFNANNY
+static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) {
+ PyObject *m = NULL, *p = NULL;
+ void *r = NULL;
+ m = PyImport_ImportModule((char *)modname);
+ if (!m) goto end;
+ p = PyObject_GetAttrString(m, (char *)\"RefNannyAPI\");
+ if (!p) goto end;
+ r = PyLong_AsVoidPtr(p);
+end:
+ Py_XDECREF(p);
+ Py_XDECREF(m);
+ return (__Pyx_RefNannyAPIStruct *)r;
+}
+#endif /* CYTHON_REFNANNY */
+""",
+)
main_method = UtilityCode(
impl = """
enum_prefix = pyrex_prefix + "e_"
func_prefix = pyrex_prefix + "f_"
pyfunc_prefix = pyrex_prefix + "pf_"
+genbody_prefix = pyrex_prefix + "gb_"
gstab_prefix = pyrex_prefix + "getsets_"
prop_get_prefix = pyrex_prefix + "getprop_"
const_prefix = pyrex_prefix + "k_"
module_is_main = pyrex_prefix + "module_is_main_"
args_cname = pyrex_prefix + "args"
+sent_value_cname = pyrex_prefix + "sent_value"
pykwdlist_cname = pyrex_prefix + "pyargnames"
obj_base_cname = pyrex_prefix + "base"
builtins_cname = pyrex_prefix + "b"
exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
-exc_save_vars = (pyrex_prefix + 'save_exc_type',
- pyrex_prefix + 'save_exc_value',
- pyrex_prefix + 'save_exc_tb')
-
api_name = pyrex_prefix + "capi__"
h_guard_prefix = "__PYX_HAVE__"
from Symtab import ModuleScope, LocalScope, ClosureScope, \
StructOrUnionScope, PyClassScope, CClassScope, CppClassScope
from Cython.Utils import open_new_file, replace_suffix
-from Code import UtilityCode
+from Code import UtilityCode, ClosureTempAllocator
from StringEncoding import EncodedString, escape_byte_string, split_string_literal
import Options
import ControlFlow
overridable = 0
optional_arg_count = 0
- def analyse(self, return_type, env, nonempty = 0):
+ def analyse(self, return_type, env, nonempty = 0, directive_locals = {}):
if nonempty:
nonempty -= 1
func_type_args = []
name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
is_self_arg = (i == 0 and env.is_c_class_scope))
name = name_declarator.name
+ if name in directive_locals:
+ type_node = directive_locals[name]
+ other_type = type_node.analyse_as_type(env)
+ if other_type is None:
+ error(type_node.pos, "Not a type")
+ elif (type is not PyrexTypes.py_object_type
+ and not type.same_as(other_type)):
+ error(self.base.pos, "Signature does not agree with previous declaration")
+ error(type_node.pos, "Previous declaration here")
+ else:
+ type = other_type
if name_declarator.cname:
error(self.pos,
"Function argument cannot have C name specification")
child_attrs = ["base_type", "declarators"]
decorators = None
- directive_locals = {}
+ directive_locals = None
def analyse_declarations(self, env, dest_scope = None):
+ if self.directive_locals is None:
+ self.directive_locals = {}
if not dest_scope:
dest_scope = env
self.dest_scope = dest_scope
visibility = self.visibility
for declarator in self.declarators:
- name_declarator, type = declarator.analyse(base_type, env)
+ if isinstance(declarator, CFuncDeclaratorNode):
+ name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
+ else:
+ name_declarator, type = declarator.analyse(base_type, env)
if not type.is_complete():
if not (self.visibility == 'extern' and type.is_array):
error(declarator.pos,
cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
api = self.api)
if entry is not None:
- entry.directive_locals = self.directive_locals
+ entry.directive_locals = copy.copy(self.directive_locals)
else:
if self.directive_locals:
error(self.pos, "Decorators can only be followed by functions")
error(self.pos,
"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)
+ cname=cname, visibility=visibility, api=self.api, is_cdef=1)
entry.needs_property = need_property
# kind "struct" or "union"
# typedef_flag boolean
# visibility "public" or "private"
+ # api boolean
# in_pxd boolean
# attributes [CVarDefNode] or None
# entry Entry
scope = StructOrUnionScope(self.name)
self.entry = env.declare_struct_or_union(
self.name, self.kind, scope, self.typedef_flag, self.pos,
- self.cname, visibility = self.visibility, packed = self.packed)
+ self.cname, visibility = self.visibility, api = self.api,
+ packed = self.packed)
if self.attributes is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
# items [CEnumDefItemNode]
# typedef_flag boolean
# visibility "public" or "private"
+ # api boolean
# in_pxd boolean
# entry Entry
def analyse_declarations(self, env):
self.entry = env.declare_enum(self.name, self.pos,
cname = self.cname, typedef_flag = self.typedef_flag,
- visibility = self.visibility)
+ visibility = self.visibility, api = self.api)
if self.items is not None:
if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1
pass
def generate_execution_code(self, code):
- if self.visibility == 'public':
+ if self.visibility == 'public' or self.api:
temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
for item in self.entry.enum_values:
code.putln("%s = PyInt_FromLong(%s); %s" % (
self.value.analyse_const_expression(env)
entry = env.declare_const(self.name, enum_entry.type,
self.value, self.pos, cname = self.cname,
- visibility = enum_entry.visibility)
+ visibility = enum_entry.visibility, api = enum_entry.api)
enum_entry.enum_values.append(entry)
# base_type CBaseTypeNode
# declarator CDeclaratorNode
# visibility "public" or "private"
+ # api boolean
# in_pxd boolean
child_attrs = ["base_type", "declarator"]
name = name_declarator.name
cname = name_declarator.cname
entry = env.declare_typedef(name, type, self.pos,
- cname = cname, visibility = self.visibility)
+ cname = cname, visibility = self.visibility, api = self.api)
if self.in_pxd and not env.in_cinclude:
entry.defined_in_pxd = 1
assmt = None
needs_closure = False
needs_outer_scope = False
+ is_generator = False
+ is_generator_body = False
modifiers = []
def analyse_default_values(self, env):
elif default_seen:
error(arg.pos, "Non-default argument following default argument")
+ def align_argument_type(self, env, arg):
+ directive_locals = self.directive_locals
+ type = arg.type
+ if arg.name in directive_locals:
+ type_node = directive_locals[arg.name]
+ other_type = type_node.analyse_as_type(env)
+ if other_type is None:
+ error(type_node.pos, "Not a type")
+ elif (type is not PyrexTypes.py_object_type
+ and not type.same_as(other_type)):
+ error(arg.base_type.pos, "Signature does not agree with previous declaration")
+ error(type_node.pos, "Previous declaration here")
+ else:
+ arg.type = other_type
+ return arg
+
def need_gil_acquisition(self, lenv):
return 0
lenv.directives = env.directives
return lenv
+ def generate_function_body(self, env, code):
+ self.body.generate_execution_code(code)
+
def generate_function_definitions(self, env, code):
import Buffer
preprocessor_guard = None
profile = code.globalstate.directives['profile']
+ if profile and lenv.nogil:
+ warning(self.pos, "Cannot profile nogil function.", 1)
+ profile = False
if profile:
- if lenv.nogil:
- error(self.pos, "Cannot profile nogil function.")
code.globalstate.use_utility_code(profile_utility_code)
# Generate C code for header and body of function
(self.return_type.declaration_code(Naming.retval_cname),
init))
tempvardecl_code = code.insertion_point()
+ if not lenv.nogil:
+ code.put_declare_refcount_context()
self.generate_keyword_list(code)
if profile:
code.put_trace_declarations()
# -------------------------
# ----- Function body -----
# -------------------------
- self.body.generate_execution_code(code)
+ self.generate_function_body(env, code)
# ----- Default return value
code.putln("")
if entry.type.is_pyobject:
if entry.used and not entry.in_closure:
code.put_var_decref(entry)
- elif entry.in_closure and self.needs_closure:
- code.put_giveref(entry.cname)
# Decref any increfed args
for entry in lenv.arg_entries:
if entry.type.is_pyobject:
- if entry.in_closure:
- code.put_var_giveref(entry)
- elif acquire_gil or entry.assignments:
+ if (acquire_gil or entry.assignments) and not entry.in_closure:
code.put_var_decref(entry)
if self.needs_closure:
code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)
info = self.local_scope.arg_entries[1].cname
# Python 3.0 betas have a bug in memoryview which makes it call
# getbuffer with a NULL parameter. For now we work around this;
- # the following line should be removed when this bug is fixed.
- code.putln("if (%s == NULL) return 0;" % info)
+ # the following block should be removed when this bug is fixed.
+ code.putln("if (%s != NULL) {" % info)
code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
+ code.putln("}")
def getbuffer_error_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
+ code.putln("if (%s != NULL && %s->obj != NULL) {"
+ % (info, info))
code.put_gotref("%s->obj" % info)
- code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" %
- (info, info))
+ code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;"
+ % (info, info))
+ code.putln("}")
def getbuffer_normal_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
- code.putln("if (%s->obj == Py_None) {" % info)
+ code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info))
code.put_gotref("Py_None")
code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
code.putln("}")
inline_in_pxd = False
decorators = None
- directive_locals = {}
+ directive_locals = None
def unqualified_name(self):
return self.entry.name
def analyse_declarations(self, env):
+ if self.directive_locals is None:
+ self.directive_locals = {}
self.directive_locals.update(env.directives['locals'])
base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names.
- name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
+ if isinstance(self.declarator, CFuncDeclaratorNode):
+ name_declarator, type = self.declarator.analyse(base_type, env,
+ nonempty = 2 * (self.body is not None),
+ directive_locals = self.directive_locals)
+ else:
+ name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
if not type.is_cfunction:
error(self.pos,
"Suite attached to non-function declaration")
declarator = declarator.base
self.args = declarator.args
for formal_arg, type_arg in zip(self.args, type.args):
+ self.align_argument_type(env, type_arg)
formal_arg.type = type_arg.type
formal_arg.name = type_arg.name
formal_arg.cname = type_arg.cname
def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
arg_decls = []
type = self.type
- visibility = self.entry.visibility
for arg in type.args[:len(type.args)-type.optional_arg_count]:
arg_decls.append(arg.declaration_code())
if with_dispatch and self.overridable:
if cname is None:
cname = self.entry.func_cname
entity = type.function_header_code(cname, ', '.join(arg_decls))
- if visibility == 'public':
- dll_linkage = "DL_EXPORT"
+ if self.entry.visibility == 'private':
+ storage_class = "static "
else:
- dll_linkage = None
- header = self.return_type.declaration_code(entity,
- dll_linkage = dll_linkage)
- if visibility == 'extern':
- storage_class = "%s " % Naming.extern_c_macro
- elif visibility == 'public':
storage_class = ""
- else:
- storage_class = "static "
+ dll_linkage = None
+ modifiers = ""
if 'inline' in self.modifiers:
self.modifiers[self.modifiers.index('inline')] = 'cython_inline'
- code.putln("%s%s %s {" % (
- storage_class,
- ' '.join(self.modifiers).upper(), # macro forms
- header))
+ if self.modifiers:
+ modifiers = "%s " % ' '.join(self.modifiers).upper()
+
+ header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
+ #print (storage_class, modifiers, header)
+ code.putln("%s%s%s {" % (storage_class, modifiers, header))
def generate_argument_declarations(self, env, code):
for arg in self.args:
num_required_kw_args = 0
reqd_kw_flags_cname = "0"
is_wrapper = 0
+ no_assignment_synthesis = 0
decorators = None
return_type_annotation = None
entry = None
api = False,
directive_locals = getattr(cfunc, 'directive_locals', {}))
+ def is_cdef_func_compatible(self):
+ """Determines if the function's signature is compatible with a
+ cdef function. This can be used before calling
+ .as_cfunction() to see if that will be successful.
+ """
+ if self.needs_closure:
+ return False
+ if self.star_arg or self.starstar_arg:
+ return False
+ return True
+
def analyse_declarations(self, env):
self.is_classmethod = self.is_staticmethod = False
if self.decorators:
allow_none_for_extension_args = env.directives['allow_none_for_extension_args']
for arg in self.args:
if hasattr(arg, 'name'):
- type = arg.type
name_declarator = None
else:
base_type = arg.base_type.analyse(env)
name_declarator, type = \
arg.declarator.analyse(base_type, env)
arg.name = name_declarator.name
- if arg.name in directive_locals:
- type_node = directive_locals[arg.name]
- other_type = type_node.analyse_as_type(env)
- if other_type is None:
- error(type_node.pos, "Not a type")
- elif (type is not PyrexTypes.py_object_type
- and not type.same_as(other_type)):
- error(arg.base_type.pos, "Signature does not agree with previous declaration")
- error(type_node.pos, "Previous declaration here")
- else:
- type = other_type
+ arg.type = type
+ self.align_argument_type(env, arg)
if name_declarator and name_declarator.cname:
error(self.pos,
"Python function argument cannot have C name specification")
- arg.type = type.as_argument_type()
+ arg.type = arg.type.as_argument_type()
arg.hdr_type = None
arg.needs_conversion = 0
arg.needs_type_test = 0
entry.doc = None
def declare_lambda_function(self, env):
- name = self.name
- prefix = env.scope_prefix
- func_cname = \
- Naming.lambda_func_prefix + u'funcdef' + prefix + self.lambda_name
- entry = env.declare_lambda_function(func_cname, self.pos)
- entry.pymethdef_cname = \
- Naming.lambda_func_prefix + u'methdef' + prefix + self.lambda_name
- entry.qualified_name = env.qualify_name(self.lambda_name)
+ entry = env.declare_lambda_function(self.lambda_name, self.pos)
entry.doc = None
self.entry = entry
self.synthesize_assignment_node(env)
def needs_assignment_synthesis(self, env, code=None):
+ if self.no_assignment_synthesis:
+ return False
# Should enable for module level as well, that will require more testing...
if self.entry.is_anonymous:
return True
code.putln("0};")
def generate_argument_parsing_code(self, env, code):
- # Generate PyArg_ParseTuple call for generic
- # arguments, if any.
+ # Generate fast equivalent of PyArg_ParseTuple call for
+ # generic arguments, if any, including args/kwargs
if self.entry.signature.has_dummy_arg and not self.self_in_stararg:
# get rid of unused argument warning
code.putln("%s = %s;" % (Naming.self_cname, Naming.self_cname))
if code.label_used(end_label):
code.put_label(end_label)
+ # fix refnanny view on closure variables here, instead of
+ # doing it separately for each arg parsing special case
+ if self.star_arg and self.star_arg.entry.in_closure:
+ code.put_var_giveref(self.star_arg.entry)
+ if self.starstar_arg and self.starstar_arg.entry.in_closure:
+ code.put_var_giveref(self.starstar_arg.entry)
+ for arg in self.args:
+ if arg.type.is_pyobject and arg.entry.in_closure:
+ code.put_var_giveref(arg.entry)
+
def generate_arg_assignment(self, arg, item, code):
if arg.type.is_pyobject:
if arg.is_generic:
item = PyrexTypes.typecast(arg.type, PyrexTypes.py_object_type, item)
entry = arg.entry
- code.putln("%s = %s;" % (entry.cname, item))
if entry.in_closure:
- code.put_var_incref(entry)
+ code.put_incref(item, PyrexTypes.py_object_type)
+ code.putln("%s = %s;" % (entry.cname, item))
else:
func = arg.type.from_py_function
if func:
code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
Naming.args_cname,
max_positional_args))
- code.put('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s)); ' % (
+ code.putln('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s));' % (
self.star_arg.entry.cname, Naming.args_cname,
max_positional_args, Naming.args_cname))
- code.put_gotref(self.star_arg.entry.cname)
+ code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
if self.starstar_arg:
- code.putln("")
- code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
code.put_decref_clear(self.starstar_arg.entry.cname, py_object_type)
- code.putln('return %s;' % self.error_value())
- code.putln('}')
- else:
- code.putln("if (unlikely(!%s)) return %s;" % (
- self.star_arg.entry.cname, self.error_value()))
+ if self.needs_closure:
+ code.put_decref(Naming.cur_scope_cname, self.local_scope.scope_class.type)
+ code.put_finish_refcount_context()
+ code.putln('return %s;' % self.error_value())
+ code.putln('}')
+ code.put_gotref(self.star_arg.entry.cname)
code.putln('} else {')
code.put("%s = %s; " % (self.star_arg.entry.cname, Naming.empty_tuple))
code.put_incref(Naming.empty_tuple, py_object_type)
if arg.needs_conversion:
self.generate_arg_conversion(arg, code)
elif arg.entry.in_closure:
- code.putln('%s = %s;' % (arg.entry.cname, arg.hdr_cname))
if arg.type.is_pyobject:
- code.put_var_incref(arg.entry)
+ code.put_incref(arg.hdr_cname, py_object_type)
+ code.putln('%s = %s;' % (arg.entry.cname, arg.hdr_cname))
def generate_arg_conversion(self, arg, code):
# Generate conversion code for one argument.
def caller_will_check_exceptions(self):
return 1
+
+class GeneratorDefNode(DefNode):
+ # Generator DefNode.
+ #
+ # gbody GeneratorBodyDefNode
+ #
+
+ is_generator = True
+ needs_closure = True
+
+ child_attrs = DefNode.child_attrs + ["gbody"]
+
+ def __init__(self, **kwargs):
+ # XXX: don't actually needs a body
+ kwargs['body'] = StatListNode(kwargs['pos'], stats=[])
+ super(GeneratorDefNode, self).__init__(**kwargs)
+
+ def analyse_declarations(self, env):
+ super(GeneratorDefNode, self).analyse_declarations(env)
+ self.gbody.local_scope = self.local_scope
+ self.gbody.analyse_declarations(env)
+
+ def generate_function_body(self, env, code):
+ body_cname = self.gbody.entry.func_cname
+ generator_cname = '%s->%s' % (Naming.cur_scope_cname, Naming.obj_base_cname)
+
+ code.putln('%s.resume_label = 0;' % generator_cname)
+ code.putln('%s.body = (__pyx_generator_body_t) %s;' % (generator_cname, body_cname))
+ code.put_giveref(Naming.cur_scope_cname)
+ code.put_finish_refcount_context()
+ code.putln("return (PyObject *) %s;" % Naming.cur_scope_cname);
+
+ def generate_function_definitions(self, env, code):
+ self.gbody.generate_function_header(code, proto=True)
+ super(GeneratorDefNode, self).generate_function_definitions(env, code)
+ self.gbody.generate_function_definitions(env, code)
+
+
+class GeneratorBodyDefNode(DefNode):
+ # Generator body DefNode.
+ #
+
+ is_generator_body = True
+
+ def __init__(self, pos=None, name=None, body=None):
+ super(GeneratorBodyDefNode, self).__init__(pos=pos, body=body, name=name, doc=None,
+ args=[],
+ star_arg=None, starstar_arg=None)
+
+ def declare_generator_body(self, env):
+ prefix = env.next_id(env.scope_prefix)
+ name = env.next_id('generator')
+ entry = env.declare_var(prefix + name, py_object_type, self.pos, visibility='private')
+ entry.func_cname = Naming.genbody_prefix + prefix + name
+ entry.qualified_name = EncodedString(self.name)
+ self.entry = entry
+
+ def analyse_declarations(self, env):
+ self.analyse_argument_types(env)
+ self.declare_generator_body(env)
+
+ def generate_function_header(self, code, proto=False):
+ header = "static PyObject *%s(%s, PyObject *%s)" % (
+ self.entry.func_cname,
+ self.local_scope.scope_class.type.declaration_code(Naming.cur_scope_cname),
+ Naming.sent_value_cname)
+ if proto:
+ code.putln('%s; /* proto */' % header)
+ else:
+ code.putln('%s /* generator body */\n{' % header);
+
+ def generate_function_definitions(self, env, code):
+ lenv = self.local_scope
+
+ # Generate closure function definitions
+ self.body.generate_function_definitions(lenv, code)
+
+ # Generate C code for header and body of function
+ code.enter_cfunc_scope()
+ code.return_from_error_cleanup_label = code.new_label()
+
+ # ----- Top-level constants used by this function
+ code.mark_pos(self.pos)
+ self.generate_cached_builtins_decls(lenv, code)
+ # ----- Function header
+ code.putln("")
+ self.generate_function_header(code)
+ # ----- Local variables
+ code.putln("PyObject *%s = NULL;" % Naming.retval_cname)
+ tempvardecl_code = code.insertion_point()
+ code.put_declare_refcount_context()
+ code.put_setup_refcount_context(self.entry.name)
+
+ # ----- Resume switch point.
+ code.funcstate.init_closure_temps(lenv.scope_class.type.scope)
+ resume_code = code.insertion_point()
+ first_run_label = code.new_label('first_run')
+ code.use_label(first_run_label)
+ code.put_label(first_run_label)
+ code.putln('%s' %
+ (code.error_goto_if_null(Naming.sent_value_cname, self.pos)))
+
+ # ----- Function body
+ self.generate_function_body(env, code)
+ code.putln('PyErr_SetNone(PyExc_StopIteration); %s' % code.error_goto(self.pos))
+ # ----- Error cleanup
+ if code.error_label in code.labels_used:
+ code.put_goto(code.return_label)
+ code.put_label(code.error_label)
+ for cname, type in code.funcstate.all_managed_temps():
+ code.put_xdecref(cname, type)
+ code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
+
+ # ----- Non-error return cleanup
+ code.put_label(code.return_label)
+ code.put_xdecref(Naming.retval_cname, py_object_type)
+ code.putln('%s->%s.resume_label = -1;' % (Naming.cur_scope_cname, Naming.obj_base_cname))
+ code.put_finish_refcount_context()
+ code.putln('return NULL;');
+ code.putln("}")
+
+ # ----- Go back and insert temp variable declarations
+ tempvardecl_code.put_temp_declarations(code.funcstate)
+ # ----- Generator resume code
+ resume_code.putln("switch (%s->%s.resume_label) {" % (Naming.cur_scope_cname, Naming.obj_base_cname));
+ resume_code.putln("case 0: goto %s;" % first_run_label)
+
+ from ParseTreeTransforms import YieldNodeCollector
+ collector = YieldNodeCollector()
+ collector.visitchildren(self)
+ for yield_expr in collector.yields:
+ resume_code.putln("case %d: goto %s;" % (yield_expr.label_num, yield_expr.label_name));
+ resume_code.putln("default: /* CPython raises the right error here */");
+ resume_code.put_finish_refcount_context()
+ resume_code.putln("return NULL;");
+ resume_code.putln("}");
+
+ code.exit_cfunc_scope()
+
+
class OverrideCheckNode(StatNode):
# A Node for dispatching to the def method if it
# is overriden.
visibility = self.visibility,
typedef_flag = self.typedef_flag,
api = self.api,
- buffer_defaults = buffer_defaults,
+ buffer_defaults = buffer_defaults,
shadow = self.shadow)
if self.shadow:
home_scope.lookup(self.class_name).as_variable = self.entry
pass
+class NonlocalNode(StatNode):
+ # Nonlocal variable declaration via the 'nonlocal' keyword.
+ #
+ # names [string]
+
+ child_attrs = []
+
+ def analyse_declarations(self, env):
+ for name in self.names:
+ env.declare_nonlocal(name, self.pos)
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
class ExprStatNode(StatNode):
# Expression used as a statement.
#
self.__class__ = PassStatNode
def analyse_expressions(self, env):
+ self.expr.result_is_used = False # hint that .result() may safely be left empty
self.expr.analyse_expressions(env)
def nogil_check(self, env):
if self.exc_type and not self.exc_value and not self.exc_tb:
exc = self.exc_type
import ExprNodes
- if isinstance(exc, ExprNodes.SimpleCallNode) and not exc.args:
+ if (isinstance(exc, ExprNodes.SimpleCallNode) and
+ not (exc.args or (exc.arg_tuple is not None and
+ exc.arg_tuple.args))):
exc = exc.function # extract the exception type
if exc.is_name and exc.entry.is_builtin:
self.builtin_exc_name = exc.name
"""
Represents a Python with statement.
- This is only used at parse tree level; and is not present in
- analysis or generation phases.
+ Implemented by the WithTransform as follows:
+
+ MGR = EXPR
+ EXIT = MGR.__exit__
+ VALUE = MGR.__enter__()
+ EXC = True
+ try:
+ try:
+ TARGET = VALUE # optional
+ BODY
+ except:
+ EXC = False
+ if not EXIT(*EXCINFO):
+ raise
+ finally:
+ if EXC:
+ EXIT(None, None, None)
+ MGR = EXIT = VALUE = None
"""
# manager The with statement manager object
- # target Node (lhs expression)
+ # target ExprNode the target lhs of the __enter__() call
# body StatNode
+
child_attrs = ["manager", "target", "body"]
+ has_target = False
+
+ def analyse_declarations(self, env):
+ self.manager.analyse_declarations(env)
+ self.body.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.manager.analyse_types(env)
+ self.body.analyse_expressions(env)
+
+ def generate_function_definitions(self, env, code):
+ self.manager.generate_function_definitions(env, code)
+ self.body.generate_function_definitions(env, code)
+
+ def generate_execution_code(self, code):
+ code.putln("/*with:*/ {")
+ self.manager.generate_evaluation_code(code)
+ self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
+ code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
+ self.exit_var,
+ self.manager.py_result(),
+ code.get_py_string_const(EncodedString('__exit__'), identifier=True),
+ code.error_goto_if_null(self.exit_var, self.pos),
+ ))
+ code.put_gotref(self.exit_var)
+
+ # need to free exit_var in the face of exceptions during setup
+ old_error_label = code.new_error_label()
+ intermediate_error_label = code.error_label
+
+ enter_func = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
+ code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
+ enter_func,
+ self.manager.py_result(),
+ code.get_py_string_const(EncodedString('__enter__'), identifier=True),
+ code.error_goto_if_null(enter_func, self.pos),
+ ))
+ code.put_gotref(enter_func)
+ self.manager.generate_disposal_code(code)
+ self.manager.free_temps(code)
+ self.target_temp.allocate(code)
+ code.putln('%s = PyObject_Call(%s, ((PyObject *)%s), NULL); %s' % (
+ self.target_temp.result(),
+ enter_func,
+ Naming.empty_tuple,
+ code.error_goto_if_null(self.target_temp.result(), self.pos),
+ ))
+ code.put_gotref(self.target_temp.result())
+ code.put_decref_clear(enter_func, py_object_type)
+ code.funcstate.release_temp(enter_func)
+ if not self.has_target:
+ code.put_decref_clear(self.target_temp.result(), type=py_object_type)
+ self.target_temp.release(code)
+ # otherwise, WithTargetAssignmentStatNode will do it for us
+
+ code.error_label = old_error_label
+ self.body.generate_execution_code(code)
+
+ step_over_label = code.new_label()
+ code.put_goto(step_over_label)
+ code.put_label(intermediate_error_label)
+ code.put_decref_clear(self.exit_var, py_object_type)
+ code.put_goto(old_error_label)
+ code.put_label(step_over_label)
+
+ code.funcstate.release_temp(self.exit_var)
+ code.putln('}')
+
+class WithTargetAssignmentStatNode(AssignmentNode):
+ # The target assignment of the 'with' statement value (return
+ # value of the __enter__() call).
+ #
+ # This is a special cased assignment that steals the RHS reference
+ # and frees its temp.
+ #
+ # lhs ExprNode the assignment target
+ # rhs TempNode the return value of the __enter__() call
+
+ child_attrs = ["lhs", "rhs"]
+
+ def analyse_declarations(self, env):
+ self.lhs.analyse_target_declaration(env)
+
+ def analyse_types(self, env):
+ self.rhs.analyse_types(env)
+ self.lhs.analyse_target_types(env)
+ self.lhs.gil_assignment_check(env)
+ self.orig_rhs = self.rhs
+ self.rhs = self.rhs.coerce_to(self.lhs.type, env)
+
+ def generate_execution_code(self, code):
+ self.rhs.generate_evaluation_code(code)
+ self.lhs.generate_assignment_code(self.rhs, code)
+ self.orig_rhs.release(code)
+
+ def generate_function_definitions(self, env, code):
+ self.rhs.generate_function_definitions(env, code)
+
+ def annotate(self, code):
+ self.lhs.annotate(code)
+ self.rhs.annotate(code)
+
+
class TryExceptStatNode(StatNode):
# try .. except statement
#
try_continue_label = code.new_label('try_continue')
try_end_label = code.new_label('try_end')
+ exc_save_vars = [code.funcstate.allocate_temp(py_object_type, False)
+ for i in xrange(3)]
code.putln("{")
- code.putln("PyObject %s;" %
- ', '.join(['*%s' % var for var in Naming.exc_save_vars]))
code.putln("__Pyx_ExceptionSave(%s);" %
- ', '.join(['&%s' % var for var in Naming.exc_save_vars]))
- for var in Naming.exc_save_vars:
+ ', '.join(['&%s' % var for var in exc_save_vars]))
+ for var in exc_save_vars:
code.put_xgotref(var)
code.putln(
"/*try:*/ {")
self.else_clause.generate_execution_code(code)
code.putln(
"}")
- for var in Naming.exc_save_vars:
+ for var in exc_save_vars:
code.put_xdecref_clear(var, py_object_type)
code.put_goto(try_end_label)
if code.label_used(try_return_label):
code.put_label(try_return_label)
- for var in Naming.exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
- ', '.join(Naming.exc_save_vars))
+ ', '.join(exc_save_vars))
code.put_goto(old_return_label)
code.put_label(our_error_label)
for temp_name, type in temps_to_clean_up:
if error_label_used or not self.has_default_clause:
if error_label_used:
code.put_label(except_error_label)
- for var in Naming.exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
- ', '.join(Naming.exc_save_vars))
+ ', '.join(exc_save_vars))
code.put_goto(old_error_label)
for exit_label, old_label in zip(
if code.label_used(exit_label):
code.put_label(exit_label)
- for var in Naming.exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
- ', '.join(Naming.exc_save_vars))
+ ', '.join(exc_save_vars))
code.put_goto(old_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
- for var in Naming.exc_save_vars: code.put_xgiveref(var)
+ for var in exc_save_vars:
+ code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
- ', '.join(Naming.exc_save_vars))
+ ', '.join(exc_save_vars))
code.put_label(try_end_label)
code.putln("}")
+ for cname in exc_save_vars:
+ code.funcstate.release_temp(cname)
+
code.return_label = old_return_label
code.break_label = old_break_label
code.continue_label = old_continue_label
# pattern [ExprNode]
# target ExprNode or None
# body StatNode
- # excinfo_target NameNode or None optional target for exception info
+ # excinfo_target ResultRefNode or None optional target for exception info
# match_flag string result of exception match
# exc_value ExcValueNode used internally
# function_name string qualified name of enclosing function
def analyse_declarations(self, env):
if self.target:
self.target.analyse_target_declaration(env)
- if self.excinfo_target is not None:
- self.excinfo_target.analyse_target_declaration(env)
self.body.analyse_declarations(env)
def analyse_expressions(self, env):
self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
ExprNodes.ExcValueNode(pos=self.pos, env=env) for x in range(3)])
self.excinfo_tuple.analyse_expressions(env)
- self.excinfo_target.analyse_target_expression(env, self.excinfo_tuple)
self.body.analyse_expressions(env)
for tempvar, node in zip(exc_vars, self.excinfo_tuple.args):
node.set_var(tempvar)
self.excinfo_tuple.generate_evaluation_code(code)
- self.excinfo_target.generate_assignment_code(self.excinfo_tuple, code)
+ self.excinfo_target.result_code = self.excinfo_tuple.result()
old_break_label, old_continue_label = code.break_label, code.continue_label
code.break_label = code.new_label('except_break')
code.funcstate.exc_vars = exc_vars
self.body.generate_execution_code(code)
code.funcstate.exc_vars = old_exc_vars
+ if self.excinfo_target is not None:
+ self.excinfo_tuple.generate_disposal_code(code)
for var in exc_vars:
- code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
+ code.put_decref_clear(var, py_object_type)
code.put_goto(end_label)
if code.label_used(code.break_label):
code.put_label(code.break_label)
+ if self.excinfo_target is not None:
+ self.excinfo_tuple.generate_disposal_code(code)
for var in exc_vars:
- code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
+ code.put_decref_clear(var, py_object_type)
code.put_goto(old_break_label)
code.break_label = old_break_label
if code.label_used(code.continue_label):
code.put_label(code.continue_label)
+ if self.excinfo_target is not None:
+ self.excinfo_tuple.generate_disposal_code(code)
for var in exc_vars:
- code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
+ code.put_decref_clear(var, py_object_type)
code.put_goto(old_continue_label)
code.continue_label = old_continue_label
+ if self.excinfo_target is not None:
+ self.excinfo_tuple.free_temps(code)
for temp in exc_vars:
code.funcstate.release_temp(temp)
preserve_exception = 1
+ # handle exception case, in addition to return/break/continue
+ handle_error_case = True
+
disallow_continue_in_try_finally = 0
# There doesn't seem to be any point in disallowing
# continue in the try block, since we have no problem
old_labels = code.all_new_labels()
new_labels = code.get_all_labels()
new_error_label = code.error_label
+ if not self.handle_error_case:
+ code.error_label = old_error_label
catch_label = code.new_label()
code.putln(
"/*try:*/ {")
#------------------------------------------------------------------------------------
+swap_exception_utility_code = UtilityCode(
+proto = """
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+""",
+impl = """
+static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb) {
+ PyObject *tmp_type, *tmp_value, *tmp_tb;
+ PyThreadState *tstate = PyThreadState_GET();
+
+ tmp_type = tstate->exc_type;
+ tmp_value = tstate->exc_value;
+ tmp_tb = tstate->exc_traceback;
+
+ tstate->exc_type = *type;
+ tstate->exc_value = *value;
+ tstate->exc_traceback = *tb;
+
+ *type = tmp_type;
+ *value = tmp_value;
+ *tb = tmp_tb;
+}
+""")
+
+#------------------------------------------------------------------------------------
+
arg_type_test_utility_code = UtilityCode(
proto = """
static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed,
self.yield_nodes = []
visit_Node = Visitor.TreeVisitor.visitchildren
- def visit_YieldExprNode(self, node):
+ # XXX: disable inlining while it's not back supported
+ def __visit_YieldExprNode(self, node):
self.yield_nodes.append(node)
self.visitchildren(node)
- def visit_ExprStatNode(self, node):
+ def __visit_ExprStatNode(self, node):
self.visitchildren(node)
if node.expr in self.yield_nodes:
self.yield_stat_nodes[node.expr] = node
return node.operand
return node
+ def visit_ExprStatNode(self, node):
+ """
+ Drop useless coercions.
+ """
+ self.visitchildren(node)
+ if isinstance(node.expr, ExprNodes.CoerceToPyTypeNode):
+ node.expr = node.expr.arg
+ return node
+
def visit_CoerceToBooleanNode(self, node):
"""Drop redundant conversion nodes after tree changes.
"""
_handle_simple_method_list_pop = _handle_simple_method_object_pop
single_param_func_type = PyrexTypes.CFuncType(
- PyrexTypes.c_int_type, [
+ PyrexTypes.c_returncode_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None),
],
exception_value = "-1")
return node
return self._substitute_method_call(
node, "PyList_Sort", self.single_param_func_type,
- 'sort', is_unbound_method, args)
+ 'sort', is_unbound_method, args).coerce_to(node.type, self.current_env)
Pyx_PyDict_GetItem_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
# Cython - Compilation-wide options and pragma declarations
#
-cache_builtins = True # Perform lookups on builtin names only once
+# Perform lookups on builtin names only once, at module initialisation
+# time. This will prevent the module from getting imported if a
+# builtin name that it uses cannot be found during initialisation.
+cache_builtins = True
embed_pos_in_docstring = False
gcc_branch_hints = True
# to keep going and printing further error messages.
fast_fail = False
+# Make all warnings into errors.
+warning_errors = False
+
+# Make unknown names an error. Python raises a NameError when
+# encountering unknown names at runtime, whereas this option makes
+# them a compile time error. If you want full Python compatibility,
+# you should disable this option and also 'cache_builtins'.
+error_on_unknown_names = True
+
# This will convert statements of the form "for i in range(...)"
# to "for i from ..." when i is a cdef'd integer type, and the direction
# (i.e. sign of step) can be determined.
'autotestdict.all': False,
'language_level': 2,
'fast_getattr': False, # Undocumented until we come up with a better way to handle this everywhere.
+ 'py2_import': False, # For backward compatibility of Cython's source code
'warn': None,
'warn.undeclared': False,
cdef class PostParse(ScopeTrackingTransform):
cdef dict specialattribute_handlers
cdef size_t lambda_counter
+ cdef size_t genexpr_counter
cdef _visit_assignment_node(self, node, list expr_list)
cdef dict directives
cdef scope
+cdef class YieldNodeCollector(TreeVisitor):
+ cdef public list yields
+ cdef public list returns
+ cdef public bint has_return_value
+
cdef class MarkClosureVisitor(CythonTransform):
cdef bint needs_closure
cdef list path
cdef bint in_lambda
cdef module_scope
+ cdef generator_class
cdef class GilCheck(VisitorTransform):
cdef list env_stack
import ExprNodes
import Nodes
import Options
+import Builtin
from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
from Cython.Compiler.ModuleNode import ModuleNode
-from Cython.Compiler.UtilNodes import LetNode, LetRefNode
+from Cython.Compiler.UtilNodes import LetNode, LetRefNode, ResultRefNode
from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import error, warning, CompileError, InternalError
def visit_ModuleNode(self, node):
self.lambda_counter = 1
+ self.genexpr_counter = 1
return super(PostParse, self).visit_ModuleNode(node)
def visit_LambdaNode(self, node):
lambda_id = self.lambda_counter
self.lambda_counter += 1
node.lambda_name = EncodedString(u'lambda%d' % lambda_id)
-
- body = Nodes.ReturnStatNode(
- node.result_expr.pos, value = node.result_expr)
+ collector = YieldNodeCollector()
+ collector.visitchildren(node.result_expr)
+ if collector.yields or isinstance(node.result_expr, ExprNodes.YieldExprNode):
+ body = Nodes.ExprStatNode(
+ node.result_expr.pos, expr=node.result_expr)
+ else:
+ body = Nodes.ReturnStatNode(
+ node.result_expr.pos, value=node.result_expr)
node.def_node = Nodes.DefNode(
node.pos, name=node.name, lambda_name=node.lambda_name,
args=node.args, star_arg=node.star_arg,
starstar_arg=node.starstar_arg,
- body=body)
+ body=body, doc=None)
+ self.visitchildren(node)
+ return node
+
+ def visit_GeneratorExpressionNode(self, node):
+ # unpack a generator expression into the corresponding DefNode
+ genexpr_id = self.genexpr_counter
+ self.genexpr_counter += 1
+ node.genexpr_name = EncodedString(u'genexpr%d' % genexpr_id)
+
+ node.def_node = Nodes.DefNode(node.pos, name=node.name,
+ doc=None,
+ args=[], star_arg=None,
+ starstar_arg=None,
+ body=node.loop)
self.visitchildren(node)
return node
return assign_node
+ def _flatten_sequence(self, seq, result):
+ for arg in seq.args:
+ if arg.is_sequence_constructor:
+ self._flatten_sequence(arg, result)
+ else:
+ result.append(arg)
+ return result
+
+ def visit_DelStatNode(self, node):
+ self.visitchildren(node)
+ node.args = self._flatten_sequence(node, [])
+ return node
+
+
def eliminate_rhs_duplicates(expr_list_list, ref_node_sequence):
"""Replace rhs items by LetRefNodes if they appear more than once.
Creates a sequence of LetRefNodes that set up the required temps
super(InterpretCompilerDirectives, self).__init__(context)
self.compilation_directive_defaults = {}
for key, value in compilation_directive_defaults.items():
- self.compilation_directive_defaults[unicode(key)] = value
+ self.compilation_directive_defaults[unicode(key)] = copy.deepcopy(value)
self.cython_module_names = cython.set()
self.directive_names = {}
self.wrong_scope_error(node.pos, key, 'module')
del node.directive_comments[key]
- directives = copy.copy(Options.directive_defaults)
- directives.update(self.compilation_directive_defaults)
+ directives = copy.deepcopy(Options.directive_defaults)
+ directives.update(copy.deepcopy(self.compilation_directive_defaults))
directives.update(node.directive_comments)
self.directives = directives
node.directives = directives
return self.visit_Node(node)
class WithTransform(CythonTransform, SkipDeclarations):
-
- # EXCINFO is manually set to a variable that contains
- # the exc_info() tuple that can be generated by the enclosing except
- # statement.
- template_without_target = TreeFragment(u"""
- MGR = EXPR
- EXIT = MGR.__exit__
- MGR.__enter__()
- EXC = True
- try:
- try:
- EXCINFO = None
- BODY
- except:
- EXC = False
- if not EXIT(*EXCINFO):
- raise
- finally:
- if EXC:
- EXIT(None, None, None)
- """, temps=[u'MGR', u'EXC', u"EXIT"],
- pipeline=[NormalizeTree(None)])
-
- template_with_target = TreeFragment(u"""
- MGR = EXPR
- EXIT = MGR.__exit__
- VALUE = MGR.__enter__()
- EXC = True
- try:
- try:
- EXCINFO = None
- TARGET = VALUE
- BODY
- except:
- EXC = False
- if not EXIT(*EXCINFO):
- raise
- finally:
- if EXC:
- EXIT(None, None, None)
- MGR = EXIT = VALUE = EXC = None
-
- """, temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
- pipeline=[NormalizeTree(None)])
-
def visit_WithStatNode(self, node):
- # TODO: Cleanup badly needed
- TemplateTransform.temp_name_counter += 1
- handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
-
- self.visitchildren(node, ['body'])
- excinfo_temp = ExprNodes.NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
- if node.target is not None:
- result = self.template_with_target.substitute({
- u'EXPR' : node.manager,
- u'BODY' : node.body,
- u'TARGET' : node.target,
- u'EXCINFO' : excinfo_temp
- }, pos=node.pos)
- else:
- result = self.template_without_target.substitute({
- u'EXPR' : node.manager,
- u'BODY' : node.body,
- u'EXCINFO' : excinfo_temp
- }, pos=node.pos)
-
- # Set except excinfo target to EXCINFO
- try_except = result.stats[-1].body.stats[-1]
- try_except.except_clauses[0].excinfo_target = ExprNodes.NameNode(node.pos, name=handle)
-# excinfo_temp.ref(node.pos))
-
-# result.stats[-1].body.stats[-1] = TempsBlockNode(
-# node.pos, temps=[excinfo_temp], body=try_except)
-
- return result
+ self.visitchildren(node, 'body')
+ pos = node.pos
+ body, target, manager = node.body, node.target, node.manager
+ node.target_temp = ExprNodes.TempNode(pos, type=PyrexTypes.py_object_type)
+ if target is not None:
+ node.has_target = True
+ body = Nodes.StatListNode(
+ pos, stats = [
+ Nodes.WithTargetAssignmentStatNode(
+ pos, lhs = target, rhs = node.target_temp),
+ body
+ ])
+ node.target = None
+
+ excinfo_target = ResultRefNode(
+ pos=pos, type=Builtin.tuple_type, may_hold_none=False)
+ except_clause = Nodes.ExceptClauseNode(
+ pos, body = Nodes.IfStatNode(
+ pos, if_clauses = [
+ Nodes.IfClauseNode(
+ pos, condition = ExprNodes.NotNode(
+ pos, operand = ExprNodes.WithExitCallNode(
+ pos, with_stat = node,
+ args = excinfo_target)),
+ body = Nodes.ReraiseStatNode(pos),
+ ),
+ ],
+ else_clause = None),
+ pattern = None,
+ target = None,
+ excinfo_target = excinfo_target,
+ )
+
+ node.body = Nodes.TryFinallyStatNode(
+ pos, body = Nodes.TryExceptStatNode(
+ pos, body = body,
+ except_clauses = [except_clause],
+ else_clause = None,
+ ),
+ finally_clause = Nodes.ExprStatNode(
+ pos, expr = ExprNodes.WithExitCallNode(
+ pos, with_stat = node,
+ args = ExprNodes.TupleNode(
+ pos, args = [ExprNodes.NoneNode(pos) for _ in range(3)]
+ ))),
+ handle_error_case = False,
+ )
+ return node
def visit_ExprNode(self, node):
# With statements are never inside expressions.
arg = copy.deepcopy(arg_template)
arg.declarator.name = entry.name
init_method.args.append(arg)
-
+
# setters/getters
for entry, attr in zip(var_entries, attributes):
# TODO: branch on visibility
}, pos = entry.pos).stats[0]
property.name = entry.name
wrapper_class.body.stats.append(property)
-
+
wrapper_class.analyse_declarations(self.env_stack[-1])
return self.visit_CClassDefNode(wrapper_class)
def visit_CNameDeclaratorNode(self, node):
if node.name in self.seen_vars_stack[-1]:
entry = self.env_stack[-1].lookup(node.name)
- if entry is None or entry.visibility != 'extern':
+ if (entry is None or entry.visibility != 'extern'
+ and not entry.scope.is_c_class_scope):
warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
self.visitchildren(node)
return node
return self.visit_CClassDefNode(node.as_cclass(), pxd_def)
else:
error(node.pos, "'%s' redeclared" % node.name)
- error(pxd_def.pos, "previous declaration here")
+ if pxd_def.pos:
+ error(pxd_def.pos, "previous declaration here")
return None
else:
return node
def visit_DefNode(self, node):
pxd_def = self.scope.lookup(node.name)
- if pxd_def:
+ if pxd_def and (not pxd_def.scope or not pxd_def.scope.is_builtin_scope):
if not pxd_def.is_cfunction:
error(node.pos, "'%s' redeclared" % node.name)
- error(pxd_def.pos, "previous declaration here")
+ if pxd_def.pos:
+ error(pxd_def.pos, "previous declaration here")
return None
node = node.as_cfunction(pxd_def)
- elif self.scope.is_module_scope and self.directives['auto_cpdef']:
+ elif (self.scope.is_module_scope and self.directives['auto_cpdef']
+ and node.is_cdef_func_compatible()):
node = node.as_cfunction(scope=self.scope)
- # Enable this when internal def functions are allowed.
+ # Enable this when nested cdef functions are allowed.
# self.visitchildren(node)
return node
+class YieldNodeCollector(TreeVisitor):
+
+ def __init__(self):
+ super(YieldNodeCollector, self).__init__()
+ self.yields = []
+ self.returns = []
+ self.has_return_value = False
+
+ def visit_Node(self, node):
+ return self.visitchildren(node)
+
+ def visit_YieldExprNode(self, node):
+ if self.has_return_value:
+ error(node.pos, "'yield' outside function")
+ self.yields.append(node)
+ self.visitchildren(node)
+
+ def visit_ReturnStatNode(self, node):
+ if node.value:
+ self.has_return_value = True
+ if self.yields:
+ error(node.pos, "'return' with argument inside generator")
+ self.returns.append(node)
+
+ def visit_ClassDefNode(self, node):
+ pass
+
+ def visit_FuncDefNode(self, node):
+ pass
+
+ def visit_LambdaNode(self, node):
+ pass
+
+ def visit_GeneratorExpressionNode(self, node):
+ pass
+
class MarkClosureVisitor(CythonTransform):
def visit_ModuleNode(self, node):
self.visitchildren(node)
node.needs_closure = self.needs_closure
self.needs_closure = True
+
+ collector = YieldNodeCollector()
+ collector.visitchildren(node)
+
+ if collector.yields:
+ for i, yield_expr in enumerate(collector.yields):
+ yield_expr.label_num = i + 1
+
+ gbody = Nodes.GeneratorBodyDefNode(pos=node.pos,
+ name=node.name,
+ body=node.body)
+ generator = Nodes.GeneratorDefNode(pos=node.pos,
+ name=node.name,
+ args=node.args,
+ star_arg=node.star_arg,
+ starstar_arg=node.starstar_arg,
+ doc=node.doc,
+ decorators=node.decorators,
+ gbody=gbody,
+ lambda_name=node.lambda_name)
+ return generator
return node
def visit_CFuncDefNode(self, node):
self.needs_closure = True
return node
-
class CreateClosureClasses(CythonTransform):
# Output closure classes in module scope for all functions
# that really need it.
super(CreateClosureClasses, self).__init__(context)
self.path = []
self.in_lambda = False
+ self.generator_class = None
def visit_ModuleNode(self, node):
self.module_scope = node.scope
self.visitchildren(node)
return node
- def get_scope_use(self, node):
+ def create_generator_class(self, target_module_scope, pos):
+ if self.generator_class:
+ return self.generator_class
+ # XXX: make generator class creation cleaner
+ entry = target_module_scope.declare_c_class(name='__pyx_Generator',
+ objstruct_cname='__pyx_Generator_object',
+ typeobj_cname='__pyx_Generator_type',
+ pos=pos, defining=True, implementing=True)
+ klass = entry.type.scope
+ klass.is_internal = True
+ klass.directives = {'final': True}
+
+ body_type = PyrexTypes.create_typedef_type('generator_body',
+ PyrexTypes.c_void_ptr_type,
+ '__pyx_generator_body_t')
+ klass.declare_var(pos=pos, name='body', cname='body',
+ type=body_type, is_cdef=True)
+ klass.declare_var(pos=pos, name='is_running', cname='is_running', type=PyrexTypes.c_int_type,
+ is_cdef=True)
+ klass.declare_var(pos=pos, name='resume_label', cname='resume_label', type=PyrexTypes.c_int_type,
+ is_cdef=True)
+ klass.declare_var(pos=pos, name='exc_type', cname='exc_type',
+ type=PyrexTypes.py_object_type, is_cdef=True)
+ klass.declare_var(pos=pos, name='exc_value', cname='exc_value',
+ type=PyrexTypes.py_object_type, is_cdef=True)
+ klass.declare_var(pos=pos, name='exc_traceback', cname='exc_traceback',
+ type=PyrexTypes.py_object_type, is_cdef=True)
+
+ import TypeSlots
+ e = klass.declare_pyfunction('send', pos)
+ e.func_cname = '__Pyx_Generator_Send'
+ e.signature = TypeSlots.binaryfunc
+
+ e = klass.declare_pyfunction('close', pos)
+ e.func_cname = '__Pyx_Generator_Close'
+ e.signature = TypeSlots.unaryfunc
+
+ e = klass.declare_pyfunction('throw', pos)
+ e.func_cname = '__Pyx_Generator_Throw'
+ e.signature = TypeSlots.pyfunction_signature
+
+ e = klass.declare_var('__iter__', PyrexTypes.py_object_type, pos, visibility='public')
+ e.func_cname = 'PyObject_SelfIter'
+
+ e = klass.declare_var('__next__', PyrexTypes.py_object_type, pos, visibility='public')
+ e.func_cname = '__Pyx_Generator_Next'
+
+ self.generator_class = entry.type
+ return self.generator_class
+
+ def find_entries_used_in_closures(self, node):
from_closure = []
in_closure = []
for name, entry in node.local_scope.entries.items():
if entry.from_closure:
from_closure.append((name, entry))
- elif entry.in_closure and not entry.from_closure:
+ elif entry.in_closure:
in_closure.append((name, entry))
return from_closure, in_closure
def create_class_from_scope(self, node, target_module_scope, inner_node=None):
- from_closure, in_closure = self.get_scope_use(node)
+ # skip generator body
+ if node.is_generator_body:
+ return
+ # move local variables into closure
+ if node.is_generator:
+ for entry in node.local_scope.entries.values():
+ if not entry.from_closure:
+ entry.in_closure = True
+
+ from_closure, in_closure = self.find_entries_used_in_closures(node)
in_closure.sort()
# Now from the begining
inner_node = node.assmt.rhs
inner_node.needs_self_code = False
node.needs_outer_scope = False
- # Simple cases
- if not in_closure and not from_closure:
+
+ base_type = None
+ if node.is_generator:
+ base_type = self.create_generator_class(target_module_scope, node.pos)
+ elif not in_closure and not from_closure:
return
elif not in_closure:
func_scope.is_passthrough = True
as_name = '%s_%s' % (target_module_scope.next_id(Naming.closure_class_prefix), node.entry.cname)
- entry = target_module_scope.declare_c_class(name = as_name,
- pos = node.pos, defining = True, implementing = True)
+ entry = target_module_scope.declare_c_class(
+ name=as_name, pos=node.pos, defining=True,
+ implementing=True, base_type=base_type)
+
func_scope.scope_class = entry
class_scope = entry.type.scope
class_scope.is_internal = True
is_cdef=True)
node.needs_outer_scope = True
for name, entry in in_closure:
- class_scope.declare_var(pos=entry.pos,
+ closure_entry = class_scope.declare_var(pos=entry.pos,
name=entry.name,
cname=entry.cname,
type=entry.type,
is_cdef=True)
+ if entry.is_declared_generic:
+ closure_entry.is_declared_generic = 1
node.needs_closure = True
# Do it here because other classes are already checked
target_module_scope.check_c_class(func_scope.scope_class)
error(node.pos, u"'%s' not a valid cython attribute or is being used incorrectly" % attribute)
return node
- def visit_SimpleCallNode(self, node):
+ def _inject_locals(self, node, func_name):
+ # locals()/dir() builtins
+ lenv = self.current_env()
+ entry = lenv.lookup_here(func_name)
+ if entry:
+ # not the builtin
+ return node
+ pos = node.pos
+ if func_name == 'locals':
+ if len(node.args) > 0:
+ error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d"
+ % len(node.args))
+ return node
+ items = [ ExprNodes.DictItemNode(pos,
+ key=ExprNodes.StringNode(pos, value=var),
+ value=ExprNodes.NameNode(pos, name=var))
+ for var in lenv.entries ]
+ return ExprNodes.DictNode(pos, key_value_pairs=items)
+ else:
+ if len(node.args) > 1:
+ error(self.pos, "Builtin 'dir()' called with wrong number of args, expected 0-1, got %d"
+ % len(node.args))
+ return node
+ elif len(node.args) == 1:
+ # optimised in Builtin.py
+ return node
+ items = [ ExprNodes.StringNode(pos, value=var) for var in lenv.entries ]
+ return ExprNodes.ListNode(pos, args=items)
- # locals builtin
+ def visit_SimpleCallNode(self, node):
if isinstance(node.function, ExprNodes.NameNode):
- if node.function.name == 'locals':
- lenv = self.current_env()
- entry = lenv.lookup_here('locals')
- if entry:
- # not the builtin 'locals'
- return node
- if len(node.args) > 0:
- error(self.pos, "Builtin 'locals()' called with wrong number of args, expected 0, got %d" % len(node.args))
- return node
- pos = node.pos
- items = [ ExprNodes.DictItemNode(pos,
- key=ExprNodes.StringNode(pos, value=var),
- value=ExprNodes.NameNode(pos, name=var))
- for var in lenv.entries ]
- return ExprNodes.DictNode(pos, key_value_pairs=items)
+ func_name = node.function.name
+ if func_name in ('dir', 'locals'):
+ return self._inject_locals(node, func_name)
# cython.foo
function = node.function.as_cython_attribute()
#-------------------------------------------------------
cdef p_global_statement(PyrexScanner s)
+cdef p_nonlocal_statement(PyrexScanner s)
cdef p_expression_or_assignment(PyrexScanner s)
cdef p_print_statement(PyrexScanner s)
cdef p_exec_statement(PyrexScanner s)
-# cython: auto_cpdef=True, infer_types=True, language_level=3
+# cython: auto_cpdef=True, infer_types=True, language_level=3, py2_import=True
#
# Pyrex Parser
#
return ExprNodes.BoolNode(pos, value=True)
elif name == "False":
return ExprNodes.BoolNode(pos, value=False)
- elif name == "NULL":
+ elif name == "NULL" and not s.in_python_file:
return ExprNodes.NullNode(pos)
else:
return p_name(s, name)
names = p_ident_list(s)
return Nodes.GlobalNode(pos, names = names)
+def p_nonlocal_statement(s):
+ pos = s.position()
+ s.next()
+ names = p_ident_list(s)
+ return Nodes.NonlocalNode(pos, names = names)
+
def p_expression_or_assignment(s):
expr_list = [p_testlist_star_expr(s)]
while s.sy == '=':
rhs = ExprNodes.ImportNode(pos,
module_name = ExprNodes.IdentifierStringNode(
pos, value = dotted_name),
+ level = None,
name_list = name_list))
stats.append(stat)
return Nodes.StatListNode(pos, stats = stats)
# s.sy == 'from'
pos = s.position()
s.next()
- (dotted_name_pos, _, dotted_name, _) = \
- p_dotted_name(s, as_allowed = 0)
+ if s.sy == '.':
+ # count relative import level
+ level = 0
+ while s.sy == '.':
+ level += 1
+ s.next()
+ if s.sy == 'cimport':
+ s.error("Relative cimport is not supported yet")
+ else:
+ level = None
+ if level is not None and s.sy == 'import':
+ # we are dealing with "from .. import foo, bar"
+ dotted_name_pos, dotted_name = s.position(), ''
+ elif level is not None and s.sy == 'cimport':
+ # "from .. cimport"
+ s.error("Relative cimport is not supported yet")
+ else:
+ (dotted_name_pos, _, dotted_name, _) = \
+ p_dotted_name(s, as_allowed = 0)
if s.sy in ('import', 'cimport'):
kind = s.sy
s.next()
else:
s.error("Expected 'import' or 'cimport'")
+
is_cimport = kind == 'cimport'
is_parenthesized = False
if s.sy == '*':
if dotted_name == '__future__':
if not first_statement:
s.error("from __future__ imports must occur at the beginning of the file")
+ elif level is not None:
+ s.error("invalid syntax")
else:
for (name_pos, name, as_name, kind) in imported_names:
if name == "braces":
return Nodes.FromImportStatNode(pos,
module = ExprNodes.ImportNode(dotted_name_pos,
module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
+ level = level,
name_list = import_list),
items = items)
s.error("Expected one of '<', '<=', '>' '>='")
def p_for_from_step(s):
- if s.sy == 'by':
+ if s.sy == 'IDENT' and s.systring == 'by':
s.next()
step = p_bit_expr(s)
return step
#print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global':
node = p_global_statement(s)
+ elif s.sy == 'nonlocal':
+ node = p_nonlocal_statement(s)
elif s.sy == 'print':
node = p_print_statement(s)
elif s.sy == 'exec':
# Parse a series of simple statements on one line
# separated by semicolons.
stat = p_simple_statement(s, first_statement = first_statement)
- if s.sy == ';':
- stats = [stat]
- while s.sy == ';':
- #print "p_simple_statement_list: maybe more to follow" ###
- s.next()
- if s.sy in ('NEWLINE', 'EOF'):
- break
- stats.append(p_simple_statement(s))
- stat = Nodes.StatListNode(stats[0].pos, stats = stats)
+ pos = stat.pos
+ stats = []
+ if not isinstance(stat, Nodes.PassStatNode):
+ stats.append(stat)
+ while s.sy == ';':
+ #print "p_simple_statement_list: maybe more to follow" ###
+ s.next()
+ if s.sy in ('NEWLINE', 'EOF'):
+ break
+ stat = p_simple_statement(s, first_statement = first_statement)
+ if isinstance(stat, Nodes.PassStatNode):
+ continue
+ stats.append(stat)
+ first_statement = False
+
+ if not stats:
+ stat = Nodes.PassStatNode(pos)
+ elif len(stats) == 1:
+ stat = stats[0]
+ else:
+ stat = Nodes.StatListNode(pos, stats = stats)
s.expect_newline("Syntax error in simple statement list")
return stat
pos = s.position()
stats = []
while s.sy not in ('DEDENT', 'EOF'):
- stats.append(p_statement(s, ctx, first_statement = first_statement))
- first_statement = 0
- if len(stats) == 1:
+ stat = p_statement(s, ctx, first_statement = first_statement)
+ if isinstance(stat, Nodes.PassStatNode):
+ continue
+ stats.append(stat)
+ first_statement = False
+ if not stats:
+ return Nodes.PassStatNode(pos)
+ elif len(stats) == 1:
return stats[0]
else:
return Nodes.StatListNode(pos, stats = stats)
return Nodes.CEnumDefNode(
pos, name = name, cname = cname, items = items,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
- in_pxd = ctx.level == 'module_pxd')
+ api = ctx.api, in_pxd = ctx.level == 'module_pxd')
def p_c_enum_line(s, ctx, items):
if s.sy != 'pass':
return Nodes.CStructOrUnionDefNode(pos,
name = name, cname = cname, kind = kind, attributes = attributes,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
- in_pxd = ctx.level == 'module_pxd', packed = packed)
+ api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
def p_visibility(s, prev_visibility):
pos = s.position()
s.expect_newline("Syntax error in ctypedef statement")
return Nodes.CTypeDefNode(
pos, base_type = base_type,
- declarator = declarator, visibility = visibility,
+ declarator = declarator,
+ visibility = visibility, api = api,
in_pxd = ctx.level == 'module_pxd')
def p_decorators(s):
base_class_module = ".".join(base_class_path[:-1])
base_class_name = base_class_path[-1]
if s.sy == '[':
- if ctx.visibility not in ('public', 'extern'):
- error(s.position(), "Name options only allowed for 'public' or 'extern' C class")
+ if ctx.visibility not in ('public', 'extern') and not ctx.api:
+ error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
objstruct_name, typeobj_name = p_c_class_options(s)
if s.sy == ':':
if ctx.level == 'module_pxd':
error(pos, "Type object name specification required for 'public' C class")
elif ctx.visibility == 'private':
if ctx.api:
- error(pos, "Only 'public' C class can be declared 'api'")
+ if not objstruct_name:
+ error(pos, "Object struct name specification required for 'api' C class")
+ if not typeobj_name:
+ error(pos, "Type object name specification required for 'api' C class")
else:
error(pos, "Invalid class visibility '%s'" % ctx.visibility)
return Nodes.CClassDefNode(pos,
repr(s.sy), repr(s.systring)))
return body
-COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*cython:\s*((\w|[.])+\s*=.*)$")
+COMPILER_DIRECTIVE_COMMENT_RE = re.compile(r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$")
def p_compiler_directive_comments(s):
result = {}
def cast_code(self, expr_code):
return "((%s)%s)" % (self.declaration_code(""), expr_code)
-
+
def specialization_name(self):
return self.declaration_code("").replace(" ", "__")
-
+
def base_declaration_code(self, base_code, entity_code):
if entity_code:
return "%s %s" % (base_code, entity_code)
# has_attributes boolean Has C dot-selectable attributes
# default_value string Initial value
#
- # declaration_code(entity_code,
+ # declaration_code(entity_code,
# for_display = 0, dll_linkage = None, pyrex = 0)
# Returns a code fragment for the declaration of an entity
# of this type, given a code fragment for the entity.
# Coerces array type into pointer type for use as
# a formal argument type.
#
-
+
is_pyobject = 0
is_unspecified = 0
is_extension_type = 0
is_buffer = 0
has_attributes = 0
default_value = ""
-
+
def resolve(self):
# If a typedef, returns the base type.
return self
-
+
def specialize(self, values):
# TODO(danilo): Override wherever it makes sense.
return self
-
+
def literal_code(self, value):
# Returns a C code fragment representing a literal
# value of this type.
return str(value)
-
+
def __str__(self):
return self.declaration_code("", for_display = 1).strip()
-
+
def same_as(self, other_type, **kwds):
return self.same_as_resolved_type(other_type.resolve(), **kwds)
-
+
def same_as_resolved_type(self, other_type):
return self == other_type or other_type is error_type
-
+
def subtype_of(self, other_type):
return self.subtype_of_resolved_type(other_type.resolve())
-
+
def subtype_of_resolved_type(self, other_type):
return self.same_as(other_type)
-
+
def assignable_from(self, src_type):
return self.assignable_from_resolved_type(src_type.resolve())
-
+
def assignable_from_resolved_type(self, src_type):
return self.same_as(src_type)
-
+
def as_argument_type(self):
return self
-
+
def is_complete(self):
# A type is incomplete if it is an unsized array,
# a struct whose attributes are not defined, etc.
return "%s(%s)" % (dll_linkage, base_code)
else:
return base_code
-
+
def create_typedef_type(name, base_type, cname, is_external=0):
if base_type.is_complex:
if is_external:
# typedef_cname string
# typedef_base_type PyrexType
# typedef_is_external bool
-
+
is_typedef = 1
typedef_is_external = 0
to_py_utility_code = None
from_py_utility_code = None
-
-
+
+
def __init__(self, name, base_type, cname, is_external=0):
assert not base_type.is_complex
self.typedef_name = name
self.typedef_cname = cname
self.typedef_base_type = base_type
self.typedef_is_external = is_external
-
+
def resolve(self):
return self.typedef_base_type.resolve()
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.typedef_name
else:
base_code = public_decl(self.typedef_cname, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
-
+
def as_argument_type(self):
return self
def cast_code(self, expr_code):
# If self is really an array (rather than pointer), we can't cast.
- # For example, the gmp mpz_t.
+ # For example, the gmp mpz_t.
if self.typedef_base_type.is_array:
base_type = self.typedef_base_type.base_type
return CPtrType(base_type).cast_code(expr_code)
def __repr__(self):
return "<CTypedefType %s>" % self.typedef_cname
-
+
def __str__(self):
return self.typedef_name
# Delegates most attribute
# lookups to the base type. ANYTHING NOT DEFINED
# HERE IS DELEGATED!
-
+
# dtype PyrexType
# ndim int
# mode str
self.mode = mode
self.negative_indices = negative_indices
self.cast = cast
-
+
def as_argument_type(self):
return self
buffer_defaults = None
is_extern = False
is_subclassed = False
-
+
def __str__(self):
return "Python object"
-
+
def __repr__(self):
return "<PyObjectType>"
def assignable_from(self, src_type):
# except for pointers, conversion will be attempted
return not src_type.is_ptr or src_type.is_string
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = "object"
self.cname = cname
self.typeptr_cname = "(&%s)" % cname
self.objstruct_cname = objstruct_cname
-
+
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
-
+
def __str__(self):
return "%s object" % self.name
-
+
def __repr__(self):
return "<%s>"% self.cname
src_type.name == self.name)
else:
return True
-
+
def typeobj_is_available(self):
return True
-
+
def attributes_known(self):
return True
-
+
def subtype_of(self, type):
return type.is_pyobject and self.assignable_from(type)
error = '(PyErr_Format(PyExc_TypeError, "Expected %s, got %%.200s", Py_TYPE(%s)->tp_name), 0)' % (self.name, arg)
return check + '||' + error
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
# vtabstruct_cname string Name of C method table struct
# vtabptr_cname string Name of pointer to C method table
# vtable_cname string Name of C method table definition
-
+
is_extension_type = 1
has_attributes = 1
-
+
objtypedef_cname = None
-
+
def __init__(self, name, typedef_flag, base_type, is_external=0):
self.name = name
self.scope = None
self.vtabptr_cname = None
self.vtable_cname = None
self.is_external = is_external
-
+
def set_scope(self, scope):
self.scope = scope
if scope:
scope.parent_type = self
-
+
def subtype_of_resolved_type(self, other_type):
if other_type.is_extension_type:
return self is other_type or (
self.base_type and self.base_type.subtype_of(other_type))
else:
return other_type is py_object_type
-
+
def typeobj_is_available(self):
# Do we have a pointer to the type object?
return self.typeptr_cname
-
+
def typeobj_is_imported(self):
# If we don't know the C name of the type object but we do
# know which module it's defined in, it will be imported.
return self.typeobj_cname is None and self.module_name is not None
-
+
def assignable_from(self, src_type):
if self == src_type:
return True
return self.assignable_from(src_type.base_type)
return False
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0, deref = 0):
if pyrex or for_display:
base_code = self.name
def attributes_known(self):
return self.scope is not None
-
+
def __str__(self):
return self.name
-
+
def __repr__(self):
return "<PyExtensionType %s%s>" % (self.scope.class_name,
("", " typedef")[self.typedef_flag])
-
+
class CType(PyrexType):
#
# to_py_function string C function for converting to Python object
# from_py_function string C function for constructing from Python object
#
-
+
to_py_function = None
from_py_function = None
exception_value = None
def create_to_py_utility_code(self, env):
return self.to_py_function is not None
-
+
def create_from_py_utility_code(self, env):
return self.from_py_function is not None
#
is_void = 1
-
+
def __repr__(self):
return "<CVoidType>"
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = "void"
else:
base_code = public_decl("void", dll_linkage)
return self.base_declaration_code(base_code, entity_code)
-
+
def is_complete(self):
return 0
# rank integer Relative size
# signed integer 0 = unsigned, 1 = unspecified, 2 = explicitly signed
#
-
+
is_numeric = 1
default_value = "0"
has_attributes = True
scope = None
-
+
sign_words = ("unsigned ", "", "signed ")
-
+
def __init__(self, rank, signed = 1):
self.rank = rank
self.signed = signed
-
+
def sign_and_name(self):
s = self.sign_words[self.signed]
n = rank_to_type_name[self.rank]
return s + n
-
+
def __repr__(self):
return "<CNumericType %s>" % self.sign_and_name()
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
type_name = self.sign_and_name()
if pyrex or for_display:
else:
base_code = public_decl(type_name, dll_linkage)
return self.base_declaration_code(base_code, entity_code)
-
+
def attributes_known(self):
if self.scope is None:
import Symtab
} else {
int one = 1; int little = (int)*(unsigned char *)&one;
unsigned char *bytes = (unsigned char *)&val;
- return _PyLong_FromByteArray(bytes, sizeof(%(type)s),
+ return _PyLong_FromByteArray(bytes, sizeof(%(type)s),
little, !is_unsigned);
}
}
class CReturnCodeType(CIntType):
+ to_py_function = "__Pyx_Owned_Py_None"
+
is_returncode = 1
def __repr__(self):
return "<CNumericType bint>"
+ def __str__(self):
+ return 'bint'
+
class CPyUCS4IntType(CIntType):
# Py_UCS4
from_py_function = "__pyx_PyFloat_AsDouble"
exception_value = -1
-
+
def __init__(self, rank, math_h_modifier = ''):
CNumericType.__init__(self, rank, 1)
self.math_h_modifier = math_h_modifier
-
+
def assignable_from_resolved_type(self, src_type):
return (src_type.is_numeric and not src_type.is_complex) or src_type is error_type
class CComplexType(CNumericType):
-
+
is_complex = 1
to_py_function = "__pyx_PyComplex_FromComplex"
has_attributes = 1
scope = None
-
+
def __init__(self, real_type):
while real_type.is_typedef and not real_type.typedef_is_external:
real_type = real_type.typedef_base_type
self.funcsuffix = real_type.math_h_modifier
else:
self.funcsuffix = "_%s" % real_type.specialization_name()
-
+
self.real_type = real_type
CNumericType.__init__(self, real_type.rank + 0.5, real_type.signed)
self.binops = {}
return self.real_type == other.real_type
else:
return False
-
+
def __ne__(self, other):
if isinstance(self, CComplexType) and isinstance(other, CComplexType):
return self.real_type != other.real_type
def __hash__(self):
return ~hash(self.real_type)
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
real_code = self.real_type.declaration_code("", for_display, dll_linkage, pyrex)
real_type_name = real_type_name.replace('long__double','long_double')
real_type_name = real_type_name.replace('PY_LONG_LONG','long_long')
return Naming.type_prefix + real_type_name + "_complex"
-
+
def assignable_from(self, src_type):
# Temporary hack/feature disabling, see #441
if (not src_type.is_complex and src_type.is_numeric and src_type.is_typedef
return False
else:
return super(CComplexType, self).assignable_from(src_type)
-
+
def assignable_from_resolved_type(self, src_type):
return (src_type.is_complex and self.real_type.assignable_from_resolved_type(src_type.real_type)
- or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type)
+ or src_type.is_numeric and self.real_type.assignable_from_resolved_type(src_type)
or src_type is error_type)
-
+
def attributes_known(self):
if self.scope is None:
import Symtab
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)
+ scope.declare_var("real", self.real_type, None, cname="real", is_cdef=True)
+ scope.declare_var("imag", self.real_type, None, cname="imag", is_cdef=True)
entry = scope.declare_cfunction(
"conjugate",
CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True),
complex_arithmetic_utility_code):
env.use_utility_code(
utility_code.specialize(
- self,
+ self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix,
is_float = self.real_type.is_float))
complex_from_py_utility_code):
env.use_utility_code(
utility_code.specialize(
- self,
+ self,
real_type = self.real_type.declaration_code(''),
m = self.funcsuffix,
is_float = self.real_type.is_float))
self.from_py_function = "__Pyx_PyComplex_As_" + self.specialization_name()
return True
-
+
def lookup_op(self, nargs, op):
try:
return self.binops[nargs, op]
def unary_op(self, op):
return self.lookup_op(1, op)
-
+
def binary_op(self, op):
return self.lookup_op(2, op)
-
+
complex_ops = {
(1, '-'): 'neg',
(1, 'zero'): 'is_zero',
class CArrayType(CType):
# base_type CType Element type
# size integer or None Number of elements
-
+
is_array = 1
-
+
def __init__(self, base_type, size):
self.base_type = base_type
self.size = size
if base_type in (c_char_type, c_uchar_type, c_schar_type):
self.is_string = 1
-
+
def __repr__(self):
return "<CArrayType %s %s>" % (self.size, repr(self.base_type))
-
+
def same_as_resolved_type(self, other_type):
return ((other_type.is_array and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
-
+
def assignable_from_resolved_type(self, src_type):
# Can't assign to a variable of an array type
return 0
-
+
def element_ptr_type(self):
return c_ptr_type(self.base_type)
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if self.size is not None:
dimension_code = self.size
return self.base_type.declaration_code(
"%s[%s]" % (entity_code, dimension_code),
for_display, dll_linkage, pyrex)
-
+
def as_argument_type(self):
return c_ptr_type(self.base_type)
-
+
def is_complete(self):
return self.size is not None
class CPtrType(CType):
# base_type CType Referenced type
-
+
is_ptr = 1
default_value = "0"
-
+
def __init__(self, base_type):
self.base_type = base_type
-
+
def __repr__(self):
return "<CPtrType %s>" % repr(self.base_type)
-
+
def same_as_resolved_type(self, other_type):
return ((other_type.is_ptr and
self.base_type.same_as(other_type.base_type))
or other_type is error_type)
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CPtrType.declaration_code: pointer to", self.base_type ###
return self.base_type.declaration_code(
"*%s" % entity_code,
for_display, dll_linkage, pyrex)
-
+
def assignable_from_resolved_type(self, other_type):
if other_type is error_type:
return 1
return self.base_type.pointer_assignable_from_resolved_type(other_type)
else:
return 0
- if (self.base_type.is_cpp_class and other_type.is_ptr
+ if (self.base_type.is_cpp_class and other_type.is_ptr
and other_type.base_type.is_cpp_class and other_type.base_type.is_subclass(self.base_type)):
return 1
if other_type.is_array or other_type.is_ptr:
return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
return 0
-
+
def specialize(self, values):
base_type = self.base_type.specialize(values)
if base_type == self.base_type:
class CNullPtrType(CPtrType):
is_null_ptr = 1
-
+
class CReferenceType(BaseType):
def __repr__(self):
return "<CReferenceType %s>" % repr(self.ref_base_type)
-
+
def __str__(self):
return "%s &" % self.ref_base_type
def as_argument_type(self):
return self
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
return self.ref_base_type.declaration_code(
"&%s" % entity_code,
for_display, dll_linkage, pyrex)
-
+
def specialize(self, values):
base_type = self.ref_base_type.specialize(values)
if base_type == self.ref_base_type:
# nogil boolean Can be called without gil
# with_gil boolean Acquire gil around function body
# templates [string] or None
-
+
is_cfunction = 1
original_sig = None
-
+
def __init__(self, return_type, args, has_varargs = 0,
exception_value = None, exception_check = 0, calling_convention = "",
nogil = 0, with_gil = 0, is_overridable = 0, optional_arg_count = 0,
self.with_gil = with_gil
self.is_overridable = is_overridable
self.templates = templates
-
+
def __repr__(self):
arg_reprs = map(repr, self.args)
if self.has_varargs:
self.calling_convention_prefix(),
",".join(arg_reprs),
except_clause)
-
+
def calling_convention_prefix(self):
cc = self.calling_convention
if cc:
return cc + " "
else:
return ""
-
+
def same_c_signature_as(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(
other_type.resolve(), as_cmethod)
def compatible_signature_with(self, other_type, as_cmethod = 0):
return self.compatible_signature_with_resolved_type(other_type.resolve(), as_cmethod)
-
+
def compatible_signature_with_resolved_type(self, other_type, as_cmethod):
#print "CFuncType.same_c_signature_as_resolved_type:", \
# self, other_type, "as_cmethod =", as_cmethod ###
if as_cmethod:
self.args[0] = other_type.args[0]
return 1
-
-
+
+
def narrower_c_signature_than(self, other_type, as_cmethod = 0):
return self.narrower_c_signature_than_resolved_type(other_type.resolve(), as_cmethod)
-
+
def narrower_c_signature_than_resolved_type(self, other_type, as_cmethod):
if other_type is error_type:
return 1
sc1 = self.calling_convention == '__stdcall'
sc2 = other.calling_convention == '__stdcall'
return sc1 == sc2
-
+
def same_exception_signature_as(self, other_type):
return self.same_exception_signature_as_resolved_type(
other_type.resolve())
def same_exception_signature_as_resolved_type(self, other_type):
return self.exception_value == other_type.exception_value \
and self.exception_check == other_type.exception_check
-
+
def same_as_resolved_type(self, other_type, as_cmethod = 0):
return self.same_c_signature_as_resolved_type(other_type, as_cmethod) \
and self.same_exception_signature_as_resolved_type(other_type) \
and self.nogil == other_type.nogil
-
+
def pointer_assignable_from_resolved_type(self, other_type):
return self.same_c_signature_as_resolved_type(other_type) \
and self.same_exception_signature_as_resolved_type(other_type) \
and not (self.nogil and not other_type.nogil)
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0,
with_calling_convention = 1):
arg_decl_list = []
return self.return_type.declaration_code(
"%s%s(%s)%s" % (cc, entity_code, arg_decl_code, trailer),
for_display, dll_linkage, pyrex)
-
+
def function_header_code(self, func_name, arg_code):
return "%s%s(%s)" % (self.calling_convention_prefix(),
func_name, arg_code)
def signature_cast_string(self):
s = self.declaration_code("(*)", with_calling_convention=False)
return '(%s)' % s
-
+
def specialize(self, values):
if self.templates is None:
new_templates = None
is_overridable = self.is_overridable,
optional_arg_count = self.optional_arg_count,
templates = new_templates)
-
+
def opt_arg_cname(self, arg_name):
return self.op_arg_struct.base_type.scope.lookup(arg_name).cname
self.type = type
self.pos = pos
self.needs_type_test = False # TODO: should these defaults be set in analyse_types()?
-
+
def __repr__(self):
return "%s:%s" % (self.name, repr(self.type))
-
+
def declaration_code(self, for_display = 0):
return self.type.declaration_code(self.cname, for_display)
-
+
def specialize(self, values):
return CFuncTypeArg(self.name, self.type.specialize(values), self.pos, self.cname)
return isinstance(other, StructUtilityCode) and self.header == other.header
def __hash__(self):
return hash(self.header)
-
+
def put_code(self, output):
code = output['utility_code_def']
proto = output['utility_code_proto']
-
+
code.putln("%s {" % self.header)
code.putln("PyObject* res;")
code.putln("PyObject* member;")
if self.forward_decl:
proto.putln(self.type.declaration_code('') + ';')
proto.putln(self.header + ";")
-
+
class CStructOrUnionType(CType):
# name string
# scope StructOrUnionScope, or None if incomplete
# typedef_flag boolean
# packed boolean
-
+
# entry Entry
-
+
is_struct_or_union = 1
has_attributes = 1
-
+
def __init__(self, name, kind, scope, typedef_flag, cname, packed=False):
self.name = name
self.cname = cname
self.exception_check = True
self._convert_code = None
self.packed = packed
-
+
def create_to_py_utility_code(self, env):
if env.outer_scope is None:
return False
return False
forward_decl = (self.entry.visibility != 'extern')
self._convert_code = StructUtilityCode(self, forward_decl)
-
+
env.use_utility_code(self._convert_code)
return True
-
+
def __repr__(self):
return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
- def declaration_code(self, entity_code,
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
def is_complete(self):
return self.scope is not None
-
+
def attributes_known(self):
return self.is_complete()
# cname string
# scope CppClassScope
# templates [string] or None
-
+
is_cpp_class = 1
has_attributes = 1
exception_check = True
namespace = None
-
+
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None):
self.name = name
self.cname = cname
error(pos, "'%s' type is not a template" % self);
return PyrexTypes.error_type
if len(self.templates) != len(template_values):
- error(pos, "%s templated type receives %d arguments, got %d" %
+ error(pos, "%s templated type receives %d arguments, got %d" %
(self.name, len(self.templates), len(template_values)))
return error_type
return self.specialize(dict(zip(self.templates, template_values)))
-
+
def specialize(self, values):
if not self.templates and not self.namespace:
return self
if base_class.is_subclass(other_type):
return 1
return 0
-
+
def same_as_resolved_type(self, other_type):
if other_type.is_cpp_class:
if self == other_type:
if other_type is error_type:
return True
return other_type.is_cpp_class and other_type.is_subclass(self)
-
+
def attributes_known(self):
return self.scope is not None
class TemplatePlaceholderType(CType):
-
+
def __init__(self, name):
self.name = name
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if entity_code:
return self.name + " " + entity_code
else:
return self.name
-
+
def specialize(self, values):
if self in values:
return values[self]
return self.name == other_type.name
else:
return 0
-
+
def __hash__(self):
return hash(self.name)
-
+
def __cmp__(self, other):
if isinstance(other, TemplatePlaceholderType):
return cmp(self.name, other.name)
self.cname = cname
self.values = []
self.typedef_flag = typedef_flag
-
+
def __str__(self):
return self.name
-
+
def __repr__(self):
return "<CEnumType %s %s%s>" % (self.name, self.cname,
("", " typedef")[self.typedef_flag])
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
if pyrex or for_display:
base_code = self.name
is_string = 1
is_unicode = 0
-
+
to_py_function = "PyBytes_FromString"
from_py_function = "PyBytes_AsString"
exception_value = "NULL"
class CUTF8CharArrayType(CStringType, CArrayType):
# C 'char []' type.
-
+
is_unicode = 1
-
+
to_py_function = "PyUnicode_DecodeUTF8"
exception_value = "NULL"
-
+
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
class CCharArrayType(CStringType, CArrayType):
# C 'char []' type.
-
+
def __init__(self, size):
CArrayType.__init__(self, c_char_type, size)
-
+
class CCharPtrType(CStringType, CPtrType):
# C 'char *' type.
-
+
def __init__(self):
CPtrType.__init__(self, c_char_type)
class CUCharPtrType(CStringType, CPtrType):
# C 'unsigned char *' type.
-
+
to_py_function = "__Pyx_PyBytes_FromUString"
from_py_function = "__Pyx_PyBytes_AsUString"
class UnspecifiedType(PyrexType):
# Used as a placeholder until the type can be determined.
-
+
is_unspecified = 1
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<unspecified>"
-
+
def same_as_resolved_type(self, other_type):
return False
-
+
class ErrorType(PyrexType):
# Used to prevent propagation of error messages.
-
+
is_error = 1
exception_value = "0"
exception_check = 0
to_py_function = "dummy"
from_py_function = "dummy"
-
+
def create_to_py_utility_code(self, env):
return True
-
+
def create_from_py_utility_code(self, env):
return True
-
- def declaration_code(self, entity_code,
+
+ def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
return "<error>"
-
+
def same_as_resolved_type(self, other_type):
return 1
-
+
def error_condition(self, result_code):
return "dummy"
def is_promotion(src_type, dst_type):
# It's hard to find a hard definition of promotion, but empirical
- # evidence suggests that the below is all that's allowed.
+ # evidence suggests that the below is all that's allowed.
if src_type.is_numeric:
if dst_type.same_as(c_int_type):
unsigned = (not src_type.signed)
functions based on how much work must be done to convert the
arguments, with the following priorities:
* identical types or pointers to identical types
- * promotions
+ * promotions
* non-Python types
That is, we prefer functions where no arguments need converted,
and failing that, functions where only promotions are required, and
the same weight, we return None (as there is no best match). If pos
is not None, we also generate an error.
"""
- # TODO: args should be a list of types, not a list of Nodes.
+ # TODO: args should be a list of types, not a list of Nodes.
actual_nargs = len(args)
candidates = []
errors.append((func, error_mesg))
continue
candidates.append((func, func_type))
-
+
# Optimize the most common case of no overloading...
if len(candidates) == 1:
return candidates[0][0]
else:
error(pos, "no suitable method found")
return None
-
+
possibilities = []
bad_types = []
- for func, func_type in candidates:
+ for index, (func, func_type) in enumerate(candidates):
score = [0,0,0]
for i in range(min(len(args), len(func_type.args))):
src_type = args[i].type
bad_types.append((func, error_mesg))
break
else:
- possibilities.append((score, func)) # so we can sort it
+ possibilities.append((score, index, func)) # so we can sort it
if possibilities:
possibilities.sort()
if len(possibilities) > 1 and possibilities[0][0] == possibilities[1][0]:
if pos is not None:
error(pos, "ambiguous overloaded method")
return None
- return possibilities[0][1]
+ return possibilities[0][-1]
if pos is not None:
if len(bad_types) == 1:
error(pos, bad_types[0][1])
return ntype
widest_type = CComplexType(
widest_numeric_type(
- real_type(type1),
+ real_type(type1),
real_type(type2)))
elif type1.is_enum and type2.is_enum:
widest_type = c_int_type
# Find type descriptor for simple type given name and modifiers.
# Returns None if arguments don't make sense.
return modifiers_and_name_to_type.get((signed, longness, name))
-
+
def parse_basic_type(name):
base = None
if name.startswith('p_'):
if name.startswith('u'):
name = name[1:]
signed = 0
- elif (name.startswith('s') and
+ elif (name.startswith('s') and
not name.startswith('short')):
name = name[1:]
signed = 2
def same_type(type1, type2):
return type1.same_as(type2)
-
+
def assignable_from(type1, type2):
return type1.assignable_from(type2)
#define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s)
#define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s))
+#define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None)
#define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x);
-# cython: infer_types=True, language_level=3
+# cython: infer_types=True, language_level=3, py2_import=True
#
# Cython Scanner
#
#------------------------------------------------------------------
py_reserved_words = [
- "global", "def", "class", "print", "del", "pass", "break",
+ "global", "nonlocal", "def", "class", "print", "del", "pass", "break",
"continue", "return", "raise", "import", "exec", "try",
"except", "finally", "while", "if", "elif", "else", "for",
"in", "assert", "and", "or", "not", "is", "in", "lambda",
pyx_reserved_words = py_reserved_words + [
"include", "ctypedef", "cdef", "cpdef",
- "cimport", "by", "DEF", "IF", "ELIF", "ELSE"
+ "cimport", "DEF", "IF", "ELIF", "ELSE"
]
class Method(object):
# cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping
# return_type PyrexType or None Return type of function owning scope
+ # is_builtin_scope boolean Is the builtin scope of Python/Cython
# is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope
# is_closure_scope boolean Is a closure scope
# analysis, contains directive values.
# is_internal boolean Is only used internally (simpler setup)
+ is_builtin_scope = 0
is_py_class_scope = 0
is_c_class_scope = 0
is_closure_scope = 0
def qualify_name(self, name):
return EncodedString("%s.%s" % (self.qualified_name, name))
- def declare_const(self, name, type, value, pos, cname = None, visibility = 'private'):
+ def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0):
# Add an entry for a named constant.
if not cname:
- if self.in_cinclude or visibility == 'public':
+ if self.in_cinclude or (visibility == 'public' or api):
cname = name
else:
cname = self.mangle(Naming.enum_prefix, name)
return entry
def declare_type(self, name, type, pos,
- cname = None, visibility = 'private', defining = 1, shadow = 0):
+ cname = None, visibility = 'private', api = 0, defining = 1, shadow = 0):
# Add an entry for a type definition.
if not cname:
cname = name
entry = self.declare(name, cname, type, pos, visibility, shadow)
entry.is_type = 1
+ entry.api = api
if defining:
self.type_entries.append(entry)
# here we would set as_variable to an object representing this type
return entry
def declare_typedef(self, name, base_type, pos, cname = None,
- visibility = 'private'):
+ visibility = 'private', api = 0):
if not cname:
- if self.in_cinclude or visibility == 'public':
+ if self.in_cinclude or (visibility == 'public' or api):
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
except ValueError, e:
error(pos, e.args[0])
type = PyrexTypes.error_type
- entry = self.declare_type(name, type, pos, cname, visibility)
+ entry = self.declare_type(name, type, pos, cname,
+ visibility = visibility, api = api)
type.qualified_name = entry.qualified_name
return entry
def declare_struct_or_union(self, name, kind, scope,
- typedef_flag, pos, cname = None, visibility = 'private',
- packed = False):
+ typedef_flag, pos, cname = None,
+ visibility = 'private', api = 0,
+ packed = False):
# Add an entry for a struct or union definition.
if not cname:
- if self.in_cinclude or visibility == 'public':
+ if self.in_cinclude or (visibility == 'public' or api):
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
type = PyrexTypes.CStructOrUnionType(
name, kind, scope, typedef_flag, cname, packed)
entry = self.declare_type(name, type, pos, cname,
- visibility = visibility, defining = scope is not None)
+ visibility = visibility, api = api,
+ defining = scope is not None)
self.sue_entries.append(entry)
type.entry = entry
else:
entry.name, entry.visibility))
def declare_enum(self, name, pos, cname, typedef_flag,
- visibility = 'private'):
+ visibility = 'private', api = 0):
if name:
if not cname:
- if self.in_cinclude or visibility == 'public':
+ if self.in_cinclude or (visibility == 'public' or api):
cname = name
else:
cname = self.mangle(Naming.type_prefix, name)
else:
type = PyrexTypes.c_anon_enum_type
entry = self.declare_type(name, type, pos, cname = cname,
- visibility = visibility)
+ visibility = visibility, api = api)
entry.enum_values = []
self.sue_entries.append(entry)
return entry
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a variable.
if not cname:
if visibility != 'private':
error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1
+ entry.api = api
self.control_flow.set_state((), (name, 'initialized'), False)
return entry
entry.is_anonymous = True
return entry
- def declare_lambda_function(self, func_cname, pos):
+ def declare_lambda_function(self, lambda_name, pos):
# Add an entry for an anonymous Python function.
- entry = self.declare_var(None, py_object_type, pos,
- cname=func_cname, visibility='private')
- entry.name = EncodedString(func_cname)
+ func_cname = self.mangle(Naming.lambda_func_prefix + u'funcdef_', lambda_name)
+ pymethdef_cname = self.mangle(Naming.lambda_func_prefix + u'methdef_', lambda_name)
+ qualified_name = self.qualify_name(lambda_name)
+
+ entry = self.declare(None, func_cname, py_object_type, pos, 'private')
+ entry.name = lambda_name
+ entry.qualified_name = qualified_name
+ entry.pymethdef_cname = pymethdef_cname
entry.func_cname = func_cname
entry.signature = pyfunction_signature
entry.is_anonymous = True
class BuiltinScope(Scope):
# The builtin namespace.
+ is_builtin_scope = True
+
def __init__(self):
if Options.pre_import is None:
Scope.__init__(self, "__builtin__", None, None)
if self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos)
else:
- error(pos, "undeclared name not builtin: %s"%name)
+ if Options.error_on_unknown_names:
+ error(pos, "undeclared name not builtin: %s" % name)
+ else:
+ warning(pos, "undeclared name not builtin: %s" % name, 2)
def declare_builtin_cfunction(self, name, type, cname, python_equiv = None,
utility_code = None):
var_entry.is_readonly = 1
var_entry.is_builtin = 1
var_entry.utility_code = utility_code
+ if Options.cache_builtins:
+ var_entry.is_const = True
entry.as_variable = var_entry
return type
return self.outer_scope.lookup(name, language_level = self.context.language_level)
def declare_builtin(self, name, pos):
- if not hasattr(builtins, name) and name not in ('xrange', 'BaseException'):
- # 'xrange' and 'BaseException' are special cased in Code.py
+ if not hasattr(builtins, name) \
+ and name not in Code.non_portable_builtins_map \
+ and name not in Code.uncachable_builtins:
if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos)
return entry
- elif self.outer_scope is not None:
- return self.outer_scope.declare_builtin(name, pos)
else:
- error(pos, "undeclared name not builtin: %s"%name)
+ if Options.error_on_unknown_names:
+ error(pos, "undeclared name not builtin: %s" % name)
+ else:
+ warning(pos, "undeclared name not builtin: %s" % name, 2)
+ # unknown - assume it's builtin and look it up at runtime
+ entry = self.declare(name, None, py_object_type, pos, 'private')
+ entry.is_builtin = 1
+ return entry
if Options.cache_builtins:
for entry in self.cached_builtins:
if entry.name == name:
return entry
entry = self.declare(None, None, py_object_type, pos, 'private')
- if Options.cache_builtins:
+ if Options.cache_builtins and name not in Code.uncachable_builtins:
entry.is_builtin = 1
- entry.is_const = 1
+ entry.is_const = 1 # cached
entry.name = name
entry.cname = Naming.builtin_prefix + name
self.cached_builtins.append(entry)
self.undeclared_cached_builtins.append(entry)
else:
entry.is_builtin = 1
+ entry.name = name
return entry
def find_module(self, module_name, pos):
return entry
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a global variable. If it is a Python
# object type, and not declared with cdef, it will live
# in the module dictionary, otherwise it will be a C
# global variable.
entry = Scope.declare_var(self, name, type, pos,
- cname, visibility, is_cdef)
+ cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
if not visibility in ('private', 'public', 'extern'):
error(pos, "Module-level variable cannot be declared %s" % visibility)
if not is_cdef:
# the non-typedef struct internally to avoid needing forward
# declarations for anonymous structs.
if typedef_flag and visibility != 'extern':
- if visibility != 'public':
- warning(pos, "ctypedef only valid for public and extern classes", 2)
+ if not (visibility == 'public' or api):
+ warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 2)
objtypedef_cname = objstruct_cname
typedef_flag = 0
else:
return entry
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a local variable.
if visibility in ('public', 'readonly'):
error(pos, "Local variable cannot be declared %s" % visibility)
entry = Scope.declare_var(self, name, type, pos,
- cname, visibility, is_cdef)
+ cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
if type.is_pyobject and not Options.init_local_none:
entry.init = "0"
entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
entry = self.global_scope().lookup_target(name)
self.entries[name] = entry
+ def declare_nonlocal(self, name, pos):
+ # Pull entry from outer scope into local scope
+ orig_entry = self.lookup_here(name)
+ if orig_entry and orig_entry.scope is self and not orig_entry.from_closure:
+ error(pos, "'%s' redeclared as nonlocal" % name)
+ else:
+ entry = self.lookup(name)
+ if entry is None or not entry.from_closure:
+ error(pos, "no binding for nonlocal '%s' found" % name)
+
def lookup(self, name):
# Look up name in this scope or an enclosing one.
# Return None if not found.
inner_entry.is_variable = True
inner_entry.outer_entry = entry
inner_entry.from_closure = True
+ inner_entry.is_declared_generic = entry.is_declared_generic
self.entries[name] = inner_entry
return inner_entry
return entry
return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = True):
+ cname = None, visibility = 'private', api = 0, is_cdef = True):
if type is unspecified_type:
# if the outer scope defines a type for this variable, inherit it
outer_entry = self.outer_scope.lookup(name)
self.entries[name] = entry
return entry
+ def declare_lambda_function(self, func_cname, pos):
+ return self.outer_scope.declare_lambda_function(func_cname, pos)
+
+ def add_lambda_def(self, def_node):
+ return self.outer_scope.add_lambda_def(def_node)
+
class ClosureScope(LocalScope):
Scope.__init__(self, name, None, None)
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute.
if not cname:
cname = name
def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()): # currently no utility code ...
- return self.declare_var(name, type, pos, cname, visibility)
+ return self.declare_var(name, type, pos,
+ cname=cname, visibility=visibility)
class ClassScope(Scope):
# Abstract base class for namespace of
is_py_class_scope = 1
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0):
if type is unspecified_type:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
- cname, visibility, is_cdef)
- entry.is_pyglobal = 1
+ cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
+ entry.is_pyglobal = 1 # FIXME: WTF?
entry.is_pyclass_attr = 1
return entry
+ def declare_nonlocal(self, name, pos):
+ # Pull entry from outer scope into local scope
+ orig_entry = self.lookup_here(name)
+ if orig_entry and orig_entry.scope is self and not orig_entry.from_closure:
+ error(pos, "'%s' redeclared as nonlocal" % name)
+ else:
+ entry = self.lookup(name)
+ if entry is None:
+ error(pos, "no binding for nonlocal '%s' found" % name)
+ else:
+ # FIXME: this works, but it's unclear if it's the
+ # right thing to do
+ self.entries[name] = entry
+
def add_default_value(self, type):
return self.outer_scope.add_default_value(type)
self.parent_type.base_type.scope.needs_gc())
def declare_var(self, name, type, pos,
- cname = None, visibility = 'private', is_cdef = 0):
+ cname = None, visibility = 'private', api = 0, is_cdef = 0):
if is_cdef:
# Add an entry for an attribute.
if self.defined:
type = py_object_type
# Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos,
- cname, visibility, is_cdef)
+ cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
entry.is_member = 1
entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
# I keep it in for now. is_member should be enough
if name == "__new__":
error(pos, "__new__ method of extension type will change semantics "
"in a future version of Pyrex and Cython. Use __cinit__ instead.")
- entry = self.declare_var(name, py_object_type, pos, visibility='extern')
+ entry = self.declare_var(name, py_object_type, pos,
+ visibility='extern')
special_sig = get_special_method_signature(name)
if special_sig:
# Special methods get put in the method table with a particular
self.inherited_var_entries = []
def declare_var(self, name, type, pos,
- cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0):
+ cname = None, visibility = 'extern', api = 0,
+ is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute.
if not cname:
cname = name
error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor))
- def declare_cfunction(self, name, type, pos,
- cname = None, visibility = 'extern', defining = 0,
- api = 0, in_pxd = 0, modifiers = (), utility_code = None):
+ def declare_cfunction(self, name, type, pos, cname = None,
+ visibility = 'extern', api = 0, defining = 0,
+ in_pxd = 0, modifiers = (), utility_code = None):
if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos)
name = '<init>'
type.return_type = self.lookup(self.name).type
prev_entry = self.lookup_here(name)
- entry = self.declare_var(name, type, pos, cname, visibility)
+ entry = self.declare_var(name, type, pos,
+ cname=cname, visibility=visibility)
if prev_entry:
entry.overloaded_alternatives = prev_entry.all_alternatives()
entry.utility_code = utility_code
self.inherited_var_entries.append(entry)
for base_entry in base_scope.cfunc_entries:
entry = self.declare_cfunction(base_entry.name, base_entry.type,
- base_entry.pos, base_entry.cname,
- base_entry.visibility, base_entry.func_modifiers,
+ base_entry.pos, base_entry.cname,
+ base_entry.visibility, 0,
+ modifiers = base_entry.func_modifiers,
utility_code = base_entry.utility_code)
entry.is_inherited = 1
x = TMP
""")
T = F.substitute(temps=[u"TMP"])
- s = T.stats
- self.assert_(s[0].expr.name == "__tmpvar_1")
-# self.assert_(isinstance(s[0].expr, TempRefNode))
-# self.assert_(isinstance(s[1].rhs, TempRefNode))
-# self.assert_(s[0].expr.handle is s[1].rhs.handle)
+ s = T.body.stats
+ self.assert_(isinstance(s[0].expr, TempRefNode))
+ self.assert_(isinstance(s[1].rhs, TempRefNode))
+ self.assert_(s[0].expr.handle is s[1].rhs.handle)
if __name__ == "__main__":
import unittest
temphandles = []
for temp in temps:
TemplateTransform.temp_name_counter += 1
- handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
-# handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
+ handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
tempmap[temp] = handle
-# temphandles.append(handle)
+ temphandles.append(handle)
self.tempmap = tempmap
result = super(TemplateTransform, self).__call__(node)
-# if temps:
-# result = UtilNodes.TempsBlockNode(self.get_pos(node),
-# temps=temphandles,
-# body=result)
+ if temps:
+ result = UtilNodes.TempsBlockNode(self.get_pos(node),
+ temps=temphandles,
+ body=result)
return result
def get_pos(self, node):
def visit_NameNode(self, node):
temphandle = self.tempmap.get(node.name)
if temphandle:
- return NameNode(pos=node.pos, name=temphandle)
# Replace name with temporary
- #return temphandle.ref(self.get_pos(node))
+ return temphandle.ref(self.get_pos(node))
else:
return self.try_substitution(node, node.name)
# TODO: Implement a real type inference algorithm.
# (Something more powerful than just extending this one...)
def infer_types(self, scope):
- enabled = not scope.is_closure_scope and scope.directives['infer_types']
+ enabled = scope.directives['infer_types']
verbose = scope.directives['infer_types.verbose']
+
if enabled == True:
spanning_type = aggressive_spanning_type
elif enabled is None: # safe mode
ready_to_infer = []
for name, entry in scope.entries.items():
if entry.type is unspecified_type:
+ if entry.in_closure or entry.from_closure:
+ # cross-closure type inference is not currently supported
+ entry.type = py_object_type
+ continue
all = set()
for expr in entry.assignments:
all.update(expr.type_dependencies(scope))
entries_by_dependancy[dep].add(entry)
else:
ready_to_infer.append(entry)
+
def resolve_dependancy(dep):
if dep in entries_by_dependancy:
for entry in entries_by_dependancy[dep]:
if not entry_deps and entry != dep:
del dependancies_by_entry[entry]
ready_to_infer.append(entry)
+
# Try to infer things in order...
while True:
while ready_to_infer:
self.type = type
assert self.pos is not None
+ def clone_node(self):
+ # nothing to do here
+ return self
+
def analyse_types(self, env):
if self.expression is not None:
self.type = self.expression.type
-# July 2002, Graham Fawcett
-#
-# this hack was inspired by the way Thomas Heller got py2exe
-# to appear as a distutil command
-#
-# we replace distutils.command.build_ext with our own version
-# and keep the old one under the module name _build_ext,
-# so that *our* build_ext can make use of it.
-
from Cython.Distutils.build_ext import build_ext
-
-# from extension import Extension
+from Cython.Distutils.extension import Extension
# cdef extern from "Python.h":
# PyObject* PyNumber_Add(PyObject *o1, PyObject *o2)
#
-# in your file after any .pxi includes. Cython will use the latest
-# declaration.
+# in your .pyx file or into a cimported .pxd file. You just have to
+# use the one from the right (pxd-)namespace then.
+#
+# Cython automatically takes care of reference counting for anything
+# of type object.
#
-# Cython takes care of this automatically for anything of type object.
## More precisely, I think the correct convention for
-## using the Python/C API from Pyrex is as follows.
+## using the Python/C API from Cython is as follows.
##
## (1) Declare all input arguments as type "object". This way no explicit
-## <PyObject*> casting is needed, and moreover Pyrex doesn't generate
+## <PyObject*> casting is needed, and moreover Cython doesn't generate
## any funny reference counting.
## (2) Declare output as object if a new reference is returned.
## (3) Declare output as PyObject* if a borrowed reference is returned.
## This way when you call objects, no cast is needed, and if the api
## calls returns a new reference (which is about 95% of them), then
## you can just assign to a variable of type object. With borrowed
-## references if you do an explicit typecast to <object>, Pyrex generates an
+## references if you do an explicit typecast to <object>, Cython generates an
## INCREF and DECREF so you have to be careful. However, you got a
## borrowed reference in this case, so there's got to be another reference
## to your object, so you're OK, as long as you relealize this
--- /dev/null
+
+cdef extern from "<string>" namespace "std":
+
+ size_t npos = -1
+
+ cdef cppclass string:
+ string()
+ string(char *)
+ string(char *, size_t)
+ string(string&)
+ # as a string formed by a repetition of character c, n times.
+ string(size_t, char)
+
+ char* c_str()
+ size_t size()
+ size_t max_size()
+ size_t length()
+ void resize(size_t)
+ void resize(size_t, char c)
+ size_t capacity()
+ void reserve(size_t)
+ void clear()
+ bint empty()
+
+ char at(size_t)
+ char operator[](size_t)
+ int compare(string&)
+
+ string& append(string&)
+ string& append(string&, size_t, size_t)
+ string& append(char *)
+ string& append(char *, size_t)
+ string& append(size_t, char)
+
+ void push_back(char c)
+
+ string& assign (string&)
+ string& assign (string&, size_t, size_t)
+ string& assign (char *, size_t)
+ string& assign (char *)
+ string& assign (size_t n, char c)
+
+ string& insert(size_t, string&)
+ string& insert(size_t, string&, size_t, size_t)
+ string& insert(size_t, char* s, size_t)
+
+
+ string& insert(size_t, char* s)
+ string& insert(size_t, size_t, char c)
+
+ size_t copy(char *, size_t, size_t)
+
+ size_t find(string&)
+ size_t find(string&, size_t)
+ size_t find(char*, size_t pos, size_t)
+ size_t find(char*, size_t pos)
+ size_t find(char, size_t pos)
+
+ size_t rfind(string&, size_t)
+ size_t rfind(char* s, size_t, size_t)
+ size_t rfind(char*, size_t pos)
+ size_t rfind(char c, size_t)
+ size_t rfind(char c)
+
+ size_t find_first_of(string&, size_t)
+ size_t find_first_of(char* s, size_t, size_t)
+ size_t find_first_of(char*, size_t pos)
+ size_t find_first_of(char c, size_t)
+ size_t find_first_of(char c)
+
+ size_t find_first_not_of(string&, size_t)
+ size_t find_first_not_of(char* s, size_t, size_t)
+ size_t find_first_not_of(char*, size_t pos)
+ size_t find_first_not_of(char c, size_t)
+ size_t find_first_not_of(char c)
+
+ size_t find_last_of(string&, size_t)
+ size_t find_last_of(char* s, size_t, size_t)
+ size_t find_last_of(char*, size_t pos)
+ size_t find_last_of(char c, size_t)
+ size_t find_last_of(char c)
+
+ size_t find_last_not_of(string&, size_t)
+ size_t find_last_not_of(char* s, size_t, size_t)
+ size_t find_last_not_of(char*, size_t pos)
+
+ string substr(size_t, size_t)
+ string substr()
+ string substr(size_t)
+
+ size_t find_last_not_of(char c, size_t)
+ size_t find_last_not_of(char c)
+
+ #string& operator= (string&)
+ #string& operator= (char*)
+ #string& operator= (char)
+
+ bint operator==(string&)
+ bint operator==(char*)
+
+ bint operator!= (string& rhs )
+ bint operator!= (char* )
+
+ bint operator< (string&)
+ bint operator< (char*)
+
+ bint operator> (string&)
+ bint operator> (char*)
+
+ bint operator<= (string&)
+ bint operator<= (char*)
+
+ bint operator>= (string&)
+ bint operator>= (char*)
# requirements, and does not yet fullfill the PEP.
# In particular strided access is always provided regardless
# of flags
+
+ if info == NULL: return
+
cdef int copy_shape, i, ndim
cdef int endian_detector = 1
cdef bint little_endian = ((<char*>&endian_detector)[0] != 0)
def __init__(self, scanner, state_name):
self.scanner = scanner
- self.position = scanner.position()
+ self.position = scanner.get_position()
self.state_name = state_name
def __str__(self):
"""
return (self.name, self.start_line, self.start_col)
+ def get_position(self):
+ """Python accessible wrapper around position(), only for error reporting.
+ """
+ return self.position()
+
def begin(self, state_name):
"""Set the current state of the scanner to the named state."""
self.initial_state = (
compiled = False
-def empty_decorator(x):
- return x
+_Unspecified = object()
# Function decorators
+def _empty_decorator(x):
+ return x
+
def locals(**arg_types):
- return empty_decorator
+ return _empty_decorator
+
+def test_assert_path_exists(path):
+ return _empty_decorator
+
+def test_fail_if_path_exists(path):
+ return _empty_decorator
+
+class _EmptyDecoratorAndManager(object):
+ def __call__(self, x):
+ return x
+ def __enter__(self):
+ pass
+ def __exit__(self, exc_type, exc_value, traceback):
+ pass
def inline(f, *args, **kwds):
if isinstance(f, basestring):
# Emulated language constructs
-def cast(type, arg):
+def cast(type, *args):
if hasattr(type, '__call__'):
- return type(arg)
+ return type(*args)
else:
- return arg
+ return args[0]
def sizeof(arg):
return 1
def address(arg):
return pointer(type(arg))([arg])
-def declare(type=None, value=None, **kwds):
+def declare(type=None, value=_Unspecified, **kwds):
if type is not None and hasattr(type, '__call__'):
- if value:
+ if value is not _Unspecified:
return type(value)
else:
return type()
# Emulated types
-class CythonType(object):
+class CythonMetaType(type):
+
+ def __getitem__(type, ix):
+ return array(type, ix)
+
+CythonTypeObject = CythonMetaType('CythonTypeObject', (object,), {})
+
+class CythonType(CythonTypeObject):
def _pointer(self, n=1):
for i in range(n):
self = pointer(self)
return self
- def __getitem__(self, ix):
- return array(self, ix)
-
-
class PointerType(CythonType):
def __init__(self, value=None):
- if isinstance(value, ArrayType):
+ if isinstance(value, (ArrayType, PointerType)):
self._items = [cast(self._basetype, a) for a in value._items]
elif isinstance(value, list):
self._items = [cast(self._basetype, a) for a in value]
- elif value is None:
+ elif value is None or value is 0:
self._items = []
else:
raise ValueError
raise IndexError("negative indexing not allowed in C")
self._items[ix] = cast(self._basetype, value)
+ def __eq__(self, value):
+ if value is None and not self._items:
+ return True
+ elif type(self) != type(value):
+ return False
+ else:
+ return not self._items and not value._items
+
class ArrayType(PointerType):
def __init__(self):
class StructType(CythonType):
- def __init__(self, **data):
- for key, value in data.iteritems():
- setattr(self, key, value)
+ def __init__(self, cast_from=_Unspecified, **data):
+ if cast_from is not _Unspecified:
+ # do cast
+ if len(data) > 0:
+ raise ValueError('Cannot accept keyword arguments when casting.')
+ if type(cast_from) is not type(self):
+ raise ValueError('Cannot cast from %s'%cast_from)
+ for key, value in cast_from.__dict__.items():
+ setattr(self, key, value)
+ else:
+ for key, value in data.iteritems():
+ setattr(self, key, value)
def __setattr__(self, key, value):
if key in self._members:
class UnionType(CythonType):
- def __init__(self, **data):
- if len(data) > 0:
+ def __init__(self, cast_from=_Unspecified, **data):
+ if cast_from is not _Unspecified:
+ # do type cast
+ if len(data) > 0:
+ raise ValueError('Cannot accept keyword arguments when casting.')
+ if isinstance(cast_from, dict):
+ datadict = cast_from
+ elif type(cast_from) is type(self):
+ datadict = cast_from.__dict__
+ else:
+ raise ValueError('Cannot cast from %s'%cast_from)
+ else:
+ datadict = data
+ if len(datadict) > 1:
raise AttributeError("Union can only store one field at a time.")
- for key, value in data.iteritems():
+ for key, value in datadict.iteritems():
setattr(self, key, value)
def __setattr__(self, key, value):
def __init__(self, type):
self._basetype = type
- def __call__(self, value=None):
- if value is not None:
- value = cast(self._basetype, value)
+ def __call__(self, *arg):
+ value = cast(self._basetype, *arg)
return value
gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i)
void = typedef(None)
-NULL = None
+NULL = p_void(0)
include Demos/freeze/*
include Demos/libraries/*
include Demos/Makefile*
-recursive-include Cython/Debugger/Tests/*
+recursive-include Cython/Debugger/Tests *
recursive-include Tools *
recursive-include tests *.pyx *.pxd *.pxi *.py *.h *.BROKEN bugs.txt
recursive-include tests *_lib.cpp *.srctree
;; Cython mode
-(require 'python-mode)
+;; Load python-mode if available, otherwise use builtin emacs python package
+(when (not(require 'python-mode nil t))
+ (require 'python))
(add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode))
(add-to-list 'auto-mode-alist '("\\.pxd\\'" . cython-mode))
--- /dev/null
+#!/usr/bin/env python
+
+"""
+Compile a Python script into an executable that embeds CPython and run it.
+Requires CPython to be built as a shared library ('libpythonX.Y').
+
+Basic usage:
+
+ python cythonrun somefile.py [ARGS]
+"""
+
+from Cython.Build.BuildExecutable import build, build_and_run
+
+if __name__ == '__main__':
+ import sys
+ build_and_run(sys.argv[1:])
+#!/usr/bin/env python
+
#
# Cython -- Main Program, generic
#
if __name__ == '__main__':
+ import os
+ import sys
+
+ # Make sure we import the right Cython
+ cythonpath, _ = os.path.split(os.path.realpath(__file__))
+ sys.path.insert(0, cythonpath)
+
from Cython.Compiler.Main import main
main(command_line = 1)
--- /dev/null
+syntax: glob
+
+*.pyc
+*~
+.*.swp
+
+syntax: regexp
+^build/
+^_build/
--- /dev/null
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html web htmlhelp latex changes linkcheck
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " web to make files usable by Sphinx.web"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview over all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+
+clean:
+ -rm -rf build/*
+
+html:
+ mkdir -p build/html build/doctrees
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
+ @echo
+ @echo "Build finished. The HTML pages are in build/html."
+
+web:
+ mkdir -p build/web build/doctrees
+ $(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web
+ @echo
+ @echo "Build finished; now you can run"
+ @echo " python -m sphinx.web build/web"
+ @echo "to start the server."
+
+htmlhelp:
+ mkdir -p build/htmlhelp build/doctrees
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in build/htmlhelp."
+
+latex:
+ mkdir -p build/latex build/doctrees
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in build/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ mkdir -p build/changes build/doctrees
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
+ @echo
+ @echo "The overview file is in build/changes."
+
+linkcheck:
+ mkdir -p build/linkcheck build/doctrees
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in build/linkcheck/output.txt."
--- /dev/null
+Cython's entire documentation suite is currently being overhauled.
+
+For the time being, I'll use this page to post notes.
+
+The previous Cython documentation files are hosted at http://hg.cython.org/cython-docs
+
+
+Notes
+=======
+
+1) Some css work should definately be done.
+2) Use local 'top-of-page' contents rather than the sidebar, imo.
+3) Provide a link from each (sub)section to the TOC of the page.
+4) Fix cython highlighter for cdef blocks
--- /dev/null
+{% extends "!layout.html" %}
+
+{% block footer %}
+{{ super() }}
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+try {
+var pageTracker = _gat._getTracker("UA-6139100-3");
+pageTracker._trackPageview();
+} catch(err) {}</script>
+{% endblock %}
--- /dev/null
+# -*- coding: utf-8 -*-
+#
+# Cython documentation build configuration file, created by
+# sphinx-quickstart on Fri Apr 25 12:49:32 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys
+
+# If your extensions are in another directory, add it here.
+sys.path.append('sphinxext')
+
+# Import support for ipython console session syntax highlighting (lives
+# in the sphinxext directory defined above)
+import ipython_console_highlighting
+
+# General configuration
+# ---------------------
+
+# Use cython as the default syntax highlighting language, as python is a subset
+# this does the right thing
+highlight_language = 'cython'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['ipython_console_highlighting', 'cython_highlighting', 'sphinx.ext.pngmath', 'sphinx.ext.todo']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+exclude_patterns = ['py*', 'build']
+
+# General substitutions.
+project = 'Cython'
+copyright = '2011, Stefan Behnel, Robert Bradshaw, Dag Sverre Seljebotn, Greg Ewing, William Stein, Gabriel Gellner, et al.'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '0.15'
+# The full version, including alpha/beta/rc tags.
+release = '0.15pre'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# Options for HTML output
+# -----------------------
+
+# suffix for generated files
+html_file_suffix = '.html'
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# Include the Cython logo in the sidebar
+html_logo = '_static/cython-logo-light.png'
+
+# used a favicon!
+html_favicon = '_static/favicon.ico'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Content template for the index page.
+#html_index = ''
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# Don't generate and index
+html_use_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Cythondoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+#_stdauthor = r'Greg Ewig\\ Gabriel Gellner, editor'
+_stdauthor = r'Stefan Behnel, Robert Bradshaw, William Stein\\ Gary Furnish, Dag Seljebotn, Greg Ewing\\ Gabriel Gellner, editor'
+latex_documents = [
+ ('src/reference/index', 'reference.tex',
+ 'Cython Reference Guide', _stdauthor, 'manual'),
+ ('src/tutorial/index', 'tutorial.tex',
+ 'Cython Tutorial', _stdauthor, 'manual')
+]
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
+
+# todo
+todo_include_todos = True
--- /dev/null
+def fib(n):
+ """Print the Fibonacci series up to n."""
+ a, b = 0, 1
+ while b < n:
+ print b,
+ a, b = b, a + b
--- /dev/null
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+
+setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("fib", ["fib.pyx"])]
+)
+
--- /dev/null
+import math
+
+def great_circle(lon1, lat1, lon2, lat2):
+ radius = 3956 # miles
+ x = math.pi/180.0
+
+ a = (90.0 - lat1)*x
+ b = (90.0 - lat2)*x
+ theta = (lon2 - lon1)*x
+ c = math.acos(math.cos(a)*math.cos(b) + math.sin(a)*math.sin(b)*math.cos(theta))
+
+ return radius*c
--- /dev/null
+import math
+
+def great_circle(double lon1, double lat1, double lon2, double lat2):
+ cdef double radius = 3956 # miles
+ cdef double x = math.pi/180.0
+ cdef double a, b, theta, c
+
+ a = (90.0 - lat1)*x
+ b = (90.0 - lat2)*x
+ theta = (lon2 - lon1)*x
+ c = math.acos(math.cos(a)*math.cos(b) + math.sin(a)*math.sin(b)*math.cos(theta))
+
+ return radius*c
--- /dev/null
+import math
+
+def great_circle(lon1, lat1, lon2, lat2):
+ radius = 3956 # miles
+ x = math.pi/180.0
+
+ a = (90.0 - lat1)*x
+ b = (90.0 - lat2)*x
+ theta = (lon2 - lon1)*x
+ c = math.acos(math.cos(a)*math.cos(b) + math.sin(a)*math.sin(b)*math.cos(theta))
+
+ return radius*c
--- /dev/null
+def primes(kmax):
+ result = []
+ if kmax > 1000:
+ kmax = 1000
+ while k < kmax:
+ i = 0
+ while i < k and n % p[i] != 0:
+ i = i + 1
+ if i == k:
+ p[k] = n
+ k = k + 1
+ result.append(n)
+ n = n + 1
+ return result
+
--- /dev/null
+def primes(int kmax):
+ cdef int n, k, i
+ cdef int p[1000]
+ result = []
+ if kmax > 1000:
+ kmax = 1000
+ k = 0
+ n = 2
+ while k < kmax:
+ i = 0
+ while i < k and n % p[i] != 0:
+ i = i + 1
+ if i == k:
+ p[k] = n
+ k = k + 1
+ result.append(n)
+ n = n + 1
+ return result
+
--- /dev/null
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+
+setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("primes", ["primes.pyx"])]
+)
+
--- /dev/null
+
+Welcome to Cython's Documentation
+=================================
+
+.. toctree::
+ :maxdepth: 2
+
+ src/quickstart/index
+ src/tutorial/index
+ src/userguide/index
+ src/reference/index
--- /dev/null
+import re
+
+from pygments.lexer import Lexer, RegexLexer, ExtendedRegexLexer, \
+ LexerContext, include, combined, do_insertions, bygroups, using
+from pygments.token import Error, Text, \
+ Comment, Operator, Keyword, Name, String, Number, Generic, Punctuation
+from pygments.util import get_bool_opt, get_list_opt, shebang_matches
+from pygments import unistring as uni
+
+from sphinx import highlighting
+
+
+line_re = re.compile('.*?\n')
+
+class CythonLexer(RegexLexer):
+ """
+ For `Cython <http://cython.org>`_ source code.
+ """
+
+ name = 'Cython'
+ aliases = ['cython', 'pyx']
+ filenames = ['*.pyx', '*.pxd', '*.pxi']
+ mimetypes = ['text/x-cython', 'application/x-cython']
+
+ tokens = {
+ 'root': [
+ (r'\n', Text),
+ (r'^(\s*)("""(?:.|\n)*?""")', bygroups(Text, String.Doc)),
+ (r"^(\s*)('''(?:.|\n)*?''')", bygroups(Text, String.Doc)),
+ (r'[^\S\n]+', Text),
+ (r'#.*$', Comment),
+ (r'[]{}:(),;[]', Punctuation),
+ (r'\\\n', Text),
+ (r'\\', Text),
+ (r'(in|is|and|or|not)\b', Operator.Word),
+ (r'(<)([a-zA-Z0-9.?]+)(>)',
+ bygroups(Punctuation, Keyword.Type, Punctuation)),
+ (r'!=|==|<<|>>|[-~+/*%=<>&^|.?]', Operator),
+ (r'(from)(\d+)(<=)(\s+)(<)(\d+)(:)',
+ bygroups(Keyword, Number.Integer, Operator, Name, Operator,
+ Name, Punctuation)),
+ include('keywords'),
+ (r'(def|property)(\s+)', bygroups(Keyword, Text), 'funcname'),
+ (r'(cp?def)(\s+)', bygroups(Keyword, Text), 'cdef'),
+ (r'(class|struct)(\s+)', bygroups(Keyword, Text), 'classname'),
+ (r'(from)(\s+)', bygroups(Keyword, Text), 'fromimport'),
+ (r'(c?import)(\s+)', bygroups(Keyword, Text), 'import'),
+ include('builtins'),
+ include('backtick'),
+ ('(?:[rR]|[uU][rR]|[rR][uU])"""', String, 'tdqs'),
+ ("(?:[rR]|[uU][rR]|[rR][uU])'''", String, 'tsqs'),
+ ('(?:[rR]|[uU][rR]|[rR][uU])"', String, 'dqs'),
+ ("(?:[rR]|[uU][rR]|[rR][uU])'", String, 'sqs'),
+ ('[uU]?"""', String, combined('stringescape', 'tdqs')),
+ ("[uU]?'''", String, combined('stringescape', 'tsqs')),
+ ('[uU]?"', String, combined('stringescape', 'dqs')),
+ ("[uU]?'", String, combined('stringescape', 'sqs')),
+ include('name'),
+ include('numbers'),
+ ],
+ 'keywords': [
+ (r'(assert|break|by|continue|ctypedef|del|elif|else|except\??|exec|'
+ r'finally|for|gil|global|if|include|lambda|nogil|pass|print|raise|'
+ r'return|try|while|yield|as|with)\b', Keyword),
+ (r'(DEF|IF|ELIF|ELSE)\b', Comment.Preproc),
+ ],
+ 'builtins': [
+ (r'(?<!\.)(__import__|abs|all|any|apply|basestring|bin|bool|buffer|'
+ r'bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|'
+ r'complex|delattr|dict|dir|divmod|enumerate|eval|execfile|exit|'
+ r'file|filter|float|frozenset|getattr|globals|hasattr|hash|hex|id|'
+ r'input|int|intern|isinstance|issubclass|iter|len|list|locals|'
+ r'long|map|max|min|next|object|oct|open|ord|pow|property|range|'
+ r'raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|'
+ r'sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|'
+ r'vars|xrange|zip)\b', Name.Builtin),
+ (r'(?<!\.)(self|None|Ellipsis|NotImplemented|False|True|NULL'
+ r')\b', Name.Builtin.Pseudo),
+ (r'(?<!\.)(ArithmeticError|AssertionError|AttributeError|'
+ r'BaseException|DeprecationWarning|EOFError|EnvironmentError|'
+ r'Exception|FloatingPointError|FutureWarning|GeneratorExit|IOError|'
+ r'ImportError|ImportWarning|IndentationError|IndexError|KeyError|'
+ r'KeyboardInterrupt|LookupError|MemoryError|NameError|'
+ r'NotImplemented|NotImplementedError|OSError|OverflowError|'
+ r'OverflowWarning|PendingDeprecationWarning|ReferenceError|'
+ r'RuntimeError|RuntimeWarning|StandardError|StopIteration|'
+ r'SyntaxError|SyntaxWarning|SystemError|SystemExit|TabError|'
+ r'TypeError|UnboundLocalError|UnicodeDecodeError|'
+ r'UnicodeEncodeError|UnicodeError|UnicodeTranslateError|'
+ r'UnicodeWarning|UserWarning|ValueError|Warning|ZeroDivisionError'
+ r')\b', Name.Exception),
+ ],
+ 'numbers': [
+ (r'(\d+\.?\d*|\d*\.\d+)([eE][+-]?[0-9]+)?', Number.Float),
+ (r'0\d+', Number.Oct),
+ (r'0[xX][a-fA-F0-9]+', Number.Hex),
+ (r'\d+L', Number.Integer.Long),
+ (r'\d+', Number.Integer)
+ ],
+ 'backtick': [
+ ('`.*?`', String.Backtick),
+ ],
+ 'name': [
+ (r'@[a-zA-Z0-9_]+', Name.Decorator),
+ ('[a-zA-Z_][a-zA-Z0-9_]*', Name),
+ ],
+ 'funcname': [
+ ('[a-zA-Z_][a-zA-Z0-9_]*', Name.Function, '#pop')
+ ],
+ 'cdef': [
+ (r'(public|readonly|extern|api|inline)\b', Keyword.Reserved),
+ (r'(struct|enum|union|class)\b', Keyword),
+ (r'([a-zA-Z_][a-zA-Z0-9_]*)(\s*)(?=[(:#=]|$)',
+ bygroups(Name.Function, Text), '#pop'),
+ (r'([a-zA-Z_][a-zA-Z0-9_]*)(\s*)(,)',
+ bygroups(Name.Function, Text, Punctuation)),
+ (r'from\b', Keyword, '#pop'),
+ (r'as\b', Keyword),
+ (r':', Punctuation, '#pop'),
+ (r'(?=["\'])', Text, '#pop'),
+ (r'[a-zA-Z_][a-zA-Z0-9_]*', Keyword.Type),
+ (r'.', Text),
+ ],
+ 'classname': [
+ ('[a-zA-Z_][a-zA-Z0-9_]*', Name.Class, '#pop')
+ ],
+ 'import': [
+ (r'(\s+)(as)(\s+)', bygroups(Text, Keyword, Text)),
+ (r'[a-zA-Z_][a-zA-Z0-9_.]*', Name.Namespace),
+ (r'(\s*)(,)(\s*)', bygroups(Text, Operator, Text)),
+ (r'', Text, '#pop') # all else: go back
+ ],
+ 'fromimport': [
+ (r'(\s+)(c?import)\b', bygroups(Text, Keyword), '#pop'),
+ (r'[a-zA-Z_.][a-zA-Z0-9_.]*', Name.Namespace),
+ # ``cdef foo from "header"``, or ``for foo from 0 < i < 10``
+ (r'', Text, '#pop'),
+ ],
+ 'stringescape': [
+ (r'\\([\\abfnrtv"\']|\n|N{.*?}|u[a-fA-F0-9]{4}|'
+ r'U[a-fA-F0-9]{8}|x[a-fA-F0-9]{2}|[0-7]{1,3})', String.Escape)
+ ],
+ 'strings': [
+ (r'%(\([a-zA-Z0-9]+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?'
+ '[hlL]?[diouxXeEfFgGcrs%]', String.Interpol),
+ (r'[^\\\'"%\n]+', String),
+ # quotes, percents and backslashes must be parsed one at a time
+ (r'[\'"\\]', String),
+ # unhandled string formatting sign
+ (r'%', String)
+ # newlines are an error (use "nl" state)
+ ],
+ 'nl': [
+ (r'\n', String)
+ ],
+ 'dqs': [
+ (r'"', String, '#pop'),
+ (r'\\\\|\\"|\\\n', String.Escape), # included here again for raw strings
+ include('strings')
+ ],
+ 'sqs': [
+ (r"'", String, '#pop'),
+ (r"\\\\|\\'|\\\n", String.Escape), # included here again for raw strings
+ include('strings')
+ ],
+ 'tdqs': [
+ (r'"""', String, '#pop'),
+ include('strings'),
+ include('nl')
+ ],
+ 'tsqs': [
+ (r"'''", String, '#pop'),
+ include('strings'),
+ include('nl')
+ ],
+ }
+
+ ##TODO: fix this, as shebang lines don't make sense for cython.
+ def analyse_text(text):
+ return shebang_matches(text, r'pythonw?(2\.\d)?')
+
+highlighting.lexers['cython'] = CythonLexer()
--- /dev/null
+from pygments.lexer import Lexer, do_insertions
+from pygments.lexers.agile import PythonConsoleLexer, PythonLexer, \
+ PythonTracebackLexer
+from pygments.token import Comment, Generic
+from sphinx import highlighting
+import re
+
+line_re = re.compile('.*?\n')
+
+class IPythonConsoleLexer(Lexer):
+ """
+ For IPython console output or doctests, such as:
+
+ Tracebacks are not currently supported.
+
+ .. sourcecode:: ipython
+
+ In [1]: a = 'foo'
+
+ In [2]: a
+ Out[2]: 'foo'
+
+ In [3]: print a
+ foo
+
+ In [4]: 1 / 0
+ """
+ name = 'IPython console session'
+ aliases = ['ipython']
+ mimetypes = ['text/x-ipython-console']
+ input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)")
+ output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)")
+ continue_prompt = re.compile(" \.\.\.+:")
+ tb_start = re.compile("\-+")
+
+ def get_tokens_unprocessed(self, text):
+ pylexer = PythonLexer(**self.options)
+ tblexer = PythonTracebackLexer(**self.options)
+
+ curcode = ''
+ insertions = []
+ for match in line_re.finditer(text):
+ line = match.group()
+ input_prompt = self.input_prompt.match(line)
+ continue_prompt = self.continue_prompt.match(line.rstrip())
+ output_prompt = self.output_prompt.match(line)
+ if line.startswith("#"):
+ insertions.append((len(curcode),
+ [(0, Comment, line)]))
+ elif input_prompt is not None:
+ insertions.append((len(curcode),
+ [(0, Generic.Prompt, input_prompt.group())]))
+ curcode += line[input_prompt.end():]
+ elif continue_prompt is not None:
+ insertions.append((len(curcode),
+ [(0, Generic.Prompt, continue_prompt.group())]))
+ curcode += line[continue_prompt.end():]
+ elif output_prompt is not None:
+ insertions.append((len(curcode),
+ [(0, Generic.Output, output_prompt.group())]))
+ curcode += line[output_prompt.end():]
+ else:
+ if curcode:
+ for item in do_insertions(insertions,
+ pylexer.get_tokens_unprocessed(curcode)):
+ yield item
+ curcode = ''
+ insertions = []
+ yield match.start(), Generic.Output, line
+ if curcode:
+ for item in do_insertions(insertions,
+ pylexer.get_tokens_unprocessed(curcode)):
+ yield item
+
+highlighting.lexers['ipython'] = IPythonConsoleLexer()
--- /dev/null
+Building Cython code
+====================
+
+Cython code must, unlike Python, be compiled. This happens in two stages:
+
+ - A ``.pyx`` file is compiled by Cython to a ``.c`` file, containing
+ the code of a Python extension module
+ - The ``.c`` file is compiled by a C compiler to
+ a ``.so`` file (or ``.pyd`` on Windows) which can be
+ ``import``-ed directly into a Python session.
+
+There are several ways to build Cython code:
+
+ - Write a distutils ``setup.py``.
+ - Use ``pyximport``, importing Cython ``.pyx`` files as if they
+ were ``.py`` files (using distutils to compile and build the background).
+ - Run the ``cython`` command-line utility manually to produce the ``.c`` file
+ from the ``.pyx`` file, then manually compiling the ``.c`` file into a shared
+ object library or ``.dll`` suitable for import from Python.
+ (This is mostly for debugging and experimentation.)
+ - Use the [Sage]_ notebook which allows Cython code inline.
+
+Currently, distutils is the most common way Cython files are built and distributed. The other methods are described in more detail in the :ref:`compilation` section of the reference manual.
+
+Building a Cython module using distutils
+----------------------------------------
+
+Imagine a simple "hello world" script in a file ``hello.pyx``::
+
+ def say_hello_to(name):
+ print("Hello %s!" % name)
+
+The following could be a corresponding ``setup.py`` script::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ ext_modules = [Extension("hello", ["hello.pyx"])]
+
+ setup(
+ name = 'Hello world app',
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = ext_modules
+ )
+
+To build, run ``python setup.py build_ext --inplace``. Then simply
+start a Python session and do ``from hello import say_hello_to`` and
+use the imported function as you see fit.
+
+
+
+.. figure:: sage.png
+
+ The Sage notebook allows transparently editing and compiling Cython
+ code simply by typing ``%cython`` at the top of a cell and evaluate
+ it. Variables and functions defined in a Cython cell imported into
+ the running session.
+
+.. [Sage] W. Stein et al., Sage Mathematics Software, http://sagemath.org
--- /dev/null
+Faster code via static typing
+=============================
+
+Cython is a Python compiler. This means that it can compile normal
+Python code without changes (with a few obvious exceptions of some as-yet
+unsupported language features). However, for performance critical
+code, it is often helpful to add static type declarations, as they
+will allow Cython to step out of the dynamic nature of the Python code
+and generate simpler and faster C code - sometimes faster by orders of
+magnitude.
+
+It must be noted, however, that type declarations can make the source
+code more verbose and thus less readable. It is therefore discouraged
+to use them without good reason, such as where benchmarks prove
+that they really make the code substantially faster in a performance
+critical section. Typically a few types in the right spots go a long way.
+
+All C types are available for type declarations: integer and floating
+point types, complex numbers, structs, unions and pointer types.
+Cython can automatically and correctly convert between the types on
+assignment. This also includes Python's arbitrary size integer types,
+where value overflows on conversion to a C type will raise a Python
+``OverflowError`` at runtime. (It does not, however, check for overflow
+when doing arithmetic.) The generated C code will handle the
+platform dependent sizes of C types correctly and safely in this case.
+
+Types are declared via the cdef keyword.
+
+
+Typing Variables
+----------------
+
+Consider the following pure Python code::
+
+ def f(x):
+ return x**2-x
+
+ def integrate_f(a, b, N):
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f(a+i*dx)
+ return s * dx
+
+Simply compiling this in Cython merely gives a 35% speedup. This is
+better than nothing, but adding some static types can make a much larger
+difference.
+
+With additional type declarations, this might look like::
+
+ def f(double x):
+ return x**2-x
+
+ def integrate_f(double a, double b, int N):
+ cdef int i
+ cdef double s, dx
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f(a+i*dx)
+ return s * dx
+
+Since the iterator variable ``i`` is typed with C semantics, the for-loop will be compiled
+to pure C code. Typing ``a``, ``s`` and ``dx`` is important as they are involved
+in arithmetic withing the for-loop; typing ``b`` and ``N`` makes less of a
+difference, but in this case it is not much extra work to be
+consistent and type the entire function.
+
+This results in a 4 times speedup over the pure Python version.
+
+Typing Functions
+----------------
+
+Python function calls can be expensive -- in Cython doubly so because
+one might need to convert to and from Python objects to do the call.
+In our example above, the argument is assumed to be a C double both inside f()
+and in the call to it, yet a Python ``float`` object must be constructed around the
+argument in order to pass it.
+
+Therefore Cython provides a syntax for declaring a C-style function,
+the cdef keyword::
+
+ cdef double f(double) except? -2:
+ return x**2-x
+
+Some form of except-modifier should usually be added, otherwise Cython
+will not be able to propagate exceptions raised in the function (or a
+function it calls). The ``except? -2`` means that an error will be checked
+for if ``-2`` is returned (though the ``?`` indicates that ``-2`` may also
+be used as a valid return value).
+Alternatively, the slower ``except *`` is always
+safe. An except clause can be left out if the function returns a Python
+object or if it is guaranteed that an exception will not be raised
+within the function call.
+
+A side-effect of cdef is that the function is no longer available from
+Python-space, as Python wouldn't know how to call it. Using the
+``cpdef`` keyword instead of cdef, a Python wrapper is also created,
+so that the function is available both from Cython (fast, passing
+typed values directly) and from Python (wrapping values in Python
+objects).
+
+Note also that it is no longer possible to change ``f`` at runtime.
+
+Speedup: 150 times over pure Python.
+
+Determining where to add types
+------------------------------
+
+Because static typing is often the key to large speed gains, beginners
+often have a tendency to type everything in sight. This cuts down on both
+readability and flexibility. On the other hand, it is easy to kill
+performance by forgetting to type a critical loop variable. Two essential
+tools to help with this task are profiling and annotation.
+Profiling should be the first step of any optimization effort, and can
+tell you where you are spending your time. Cython's annotation can then
+tell you why your code is taking time.
+
+Using the ``-a`` switch to the ``cython`` command line program (or
+following a link from the Sage notebook) results in an HTML report
+of Cython code interleaved with the generated C code. Lines are
+colored according to the level of "typedness" -- white lines
+translates to pure C without any Python API calls. This report
+is invaluable when optimizing a function for speed.
+
+.. figure:: htmlreport.png
--- /dev/null
+from time import time
+from math import sin
+
+cdef double first_time = 0
+
+def timeit(f, label):
+ global first_time
+ t = time()
+ f(1.0, 2.0, 10**7)
+ cdef double elapsed = time() - t
+ if first_time == 0:
+ first_time = elapsed
+ print label, elapsed, (100*elapsed/first_time), '% or', first_time/elapsed, 'x'
+
+# Pure Python
+
+py_funcs = {'sin': sin}
+py_funcs.update(__builtins__.__dict__)
+exec """
+def f(x):
+ return x**2-x
+
+def integrate_f(a, b, N):
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f(a+i*dx)
+ return s * dx
+
+""" in py_funcs
+timeit(py_funcs['integrate_f'], "Python")
+
+# Just compiled
+
+def f0(x):
+ return x**2-x
+
+def integrate_f0(a, b, N):
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f0(a+i*dx)
+ return s * dx
+
+timeit(integrate_f0, "Cython")
+
+
+
+# Typed vars
+
+def f1(double x):
+ return x**2-x
+
+def integrate_f1(double a, double b, int N):
+ cdef int i
+ cdef double s, dx
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f1(a+i*dx)
+ return s * dx
+
+timeit(integrate_f1, "Typed vars")
+
+
+
+# Typed func
+
+cdef double f2(double x) except? -2:
+ return x**2-x
+
+def integrate_f2(double a, double b, int N):
+ cdef int i
+ cdef double s, dx
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f2(a+i*dx)
+ return s * dx
+
+timeit(integrate_f2, "Typed func")
--- /dev/null
+Getting Started
+===============
+
+.. toctree::
+ :maxdepth: 2
+
+ overview
+ install
+ build
+ cythonize
--- /dev/null
+Installing Cython
+=================
+
+Many scientific Python distributions, such as the Enthought Python
+Distribution [EPD]_, Python(x,y) [Pythonxy]_, and Sage [Sage]_, bundle
+Cython and no setup is needed. Note however that if your distribution
+ships a version of Cython which is too old you can still use the
+instructions below to update Cython. Everything in this tutorial
+should work with Cython 0.11.2 and newer, unless a footnote says
+otherwise.
+
+Unlike most Python software, Cython requires a C compiler to be
+present on the system. The details of getting a C compiler varies
+according to the system used:
+
+ - **Linux** The GNU C Compiler (gcc) is usually present, or easily
+ available through the package system. On Ubuntu or Debian, for
+ instance, the command ``sudo apt-get install build-essential`` will
+ fetch everything you need.
+
+ - **Mac OS X** To retrieve gcc, one option is to install Apple's
+ XCode, which can be retrieved from the Mac OS X's install DVDs or
+ from http://developer.apple.com.
+
+ - **Windows** A popular option is to use the open source MinGW (a
+ Windows distribution of gcc). See the appendix for instructions for
+ setting up MinGW manually. EPD and Python(x,y) bundle MinGW, but
+ some of the configuration steps in the appendix might still be
+ necessary. Another option is to use Microsoft's Visual C. One must
+ then use the same version which the installed Python was compiled
+ with.
+
+.. dagss tried other forms of ReST lists and they didn't look nice
+.. with rst2latex.
+
+The newest Cython release can always be downloaded from
+http://cython.org. Unpack the tarball or zip file, enter the
+directory, and then run::
+
+ python setup.py install
+
+If you have Python setuptools set up on your system, you should be
+able to fetch Cython from PyPI and install it using::
+
+ easy_install cython
+
+For Windows there is also an executable installer available for
+download.
+
+.. [EPD] http://www.enthought.com/products/epd.php
+.. [Pythonxy] http://www.pythonxy.com/
+.. [Sage] W. Stein et al., Sage Mathematics Software, http://sagemath.org
--- /dev/null
+Cython - an overview
+====================
+
+[Cython]_ is a programming language based on Python, with extra syntax
+allowing for optional static type declarations. It aims to become a superset
+of the [Python]_ language which gives it high-level, object-oriented,
+functional, and dynamic programming. The source code gets translated
+into optimized C/C++ code and compiled as Python extension modules.
+This allows for both very fast program execution and tight integration
+with external C libraries, while keeping up the high programmer
+productivity for which the Python language is well known.
+
+The primary Python execution environment is commonly referred to as
+CPython, as it is written in C. Other major implementations use Java
+(Jython [Jython]_), C# (IronPython [IronPython]_) and Python itself
+(PyPy [PyPy]_). Written in C, CPython has been conducive to wrapping
+many external libraries that interface through the C language. It
+has, however, remained non trivial to write the necessary glue code in
+C, especially for programmers who are more fluent in a high-level
+language like Python than in a close-to-the-metal language like C.
+
+Originally based on the well-known Pyrex [Pyrex]_, the Cython project has
+approached this problem by means of a source code compiler that
+translates Python code to equivalent C code. This code is executed
+within the CPython runtime environment, but at the speed of compiled C
+and with the ability to call directly into C libraries.
+At the same time, it keeps the original interface of the Python
+source code, which makes it directly usable from Python code. These
+two-fold characteristics enable Cython's two major use cases:
+extending the CPython interpreter with fast binary modules, and
+interfacing Python code with external C libraries.
+
+While Cython can compile (most) regular Python code, the generated C
+code usually gains major (and sometime impressive) speed improvements
+from optional static type declarations for both Python and C types.
+These allow Cython to assign C semantics to parts of the code, and to
+translate them into very efficient C code. Type declarations can
+therefore be used for two purposes: for moving code sections from
+dynamic Python semantics into static-and-fast C semantics, but also
+for directly manipulating types defined in external libraries. Cython
+thus merges the two worlds into a very broadly applicable programming
+language.
+
+.. [Cython] G. Ewing, R. W. Bradshaw, S. Behnel, D. S. Seljebotn et al.,
+ The Cython compiler, http://cython.org.
+.. [IronPython] Jim Hugunin et al., http://www.codeplex.com/IronPython.
+.. [Jython] J. Huginin, B. Warsaw, F. Bock, et al.,
+ Jython: Python for the Java platform, http://www.jython.org/
+.. [PyPy] The PyPy Group, PyPy: a Python implementation written in Python,
+ http://codespeak.net/pypy.
+.. [Pyrex] G. Ewing, Pyrex: C-Extensions for Python,
+ http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
+.. [Python] G. van Rossum et al., The Python programming language,
+ http://python.org.
--- /dev/null
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html web htmlhelp latex changes linkcheck
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " web to make files usable by Sphinx.web"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview over all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+
+clean:
+ -rm -rf build/*
+
+html:
+ mkdir -p build/html build/doctrees
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
+ @echo
+ @echo "Build finished. The HTML pages are in build/html."
+
+web:
+ mkdir -p build/web build/doctrees
+ $(SPHINXBUILD) -b web $(ALLSPHINXOPTS) build/web
+ @echo
+ @echo "Build finished; now you can run"
+ @echo " python -m sphinx.web build/web"
+ @echo "to start the server."
+
+htmlhelp:
+ mkdir -p build/htmlhelp build/doctrees
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in build/htmlhelp."
+
+latex:
+ mkdir -p build/latex build/doctrees
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in build/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ mkdir -p build/changes build/doctrees
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
+ @echo
+ @echo "The overview file is in build/changes."
+
+linkcheck:
+ mkdir -p build/linkcheck build/doctrees
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in build/linkcheck/output.txt."
--- /dev/null
+.. highlight:: cython
+
+.. _compilation:
+
+=============
+Compilation
+=============
+
+Cython code, unlike Python, must be compiled. This happens in two stages:
+
+ * A ``.pyx`` file is compiles by Cython to a ``.c`` file.
+
+ * The ``.c`` file is compiled by a C compiler to a ``.so`` file (or a
+ ``.pyd`` file on Windows)
+
+
+The following sub-sections describe several ways to build your
+extension modules, and how to pass directives to the Cython compiler.
+
+Compiling from the command line
+===============================
+
+Run the Cython compiler command with your options and list of ``.pyx``
+files to generate. For example::
+
+ $ cython -a yourmod.pyx
+
+This creates a ``yourmod.c`` file, and the -a switch produces a
+generated html file. Pass the ``-h`` flag for a complete list of
+supported flags.
+
+Compiling your ``.c`` files will vary depending on your operating
+system. Python documentation for writing extension modules should
+have some details for your system. Here we give an example on a Linux
+system::
+
+ $ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.5 -o yourmod.so yourmod.c
+
+[``gcc`` will need to have paths to your included header files and
+paths to libraries you need to link with]
+
+A ``yourmod.so`` file is now in the same directory and your module,
+``yourmod``, is available for you to import as you normally would.
+
+Compiling with ``distutils``
+============================
+
+First, make sure that ``distutils`` package is installed in your
+system. The following assumes a Cython file to be compiled called
+*hello.pyx*. Now, create a ``setup.py`` script::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ ext_modules = [Extension("spam", ["spam.pyx"]),
+ Extension("ham", ["ham.pyx"])]
+ # You can add directives for each extension too
+ # by attaching the `pyrex_directives`
+ for e in ext modules:
+ e.pyrex_directives = {"boundscheck": False}
+ setup(
+ name = "My hello app",
+ cmdclass = {"build_ext": build_ext},
+ ext_modules = ext_modules
+ )
+
+Run the command ``python setup.py build_ext --inplace`` in your
+system's command shell and you are done. Import your new extension
+module into your python shell or script as normal.
+
+Cython provides utility code to automatically generate lists of
+Extension objects from ```.pyx`` files, so one can write::
+
+ from distutils.core import setup
+ from Cython.Build import cythonize
+
+ setup(
+ name = "My hello app",
+ ext_modules = cythonize("*.pyx"),
+ )
+
+to compile all ``.pyx`` files in a given directory.
+The ``cythonize`` command also allows for multi-threaded compilation and
+dependency resolution.
+
+Compiling with ``pyximport``
+=============================
+
+For generating Cython code right in your pure python module just type::
+
+ >>> import pyximport; pyximport.install()
+ >>> import helloworld
+ Hello World
+
+This allows you to automatically run Cython on every ``.pyx`` that
+Python is trying to import. You should use this for simple Cython
+builds only where no extra C libraries and no special building setup
+is needed.
+
+In the case that Cython fails to compile a Python module, *pyximport*
+will fall back to loading the source modules instead.
+
+It is also possible to compile new ``.py`` modules that are being
+imported (including the standard library and installed packages). For
+using this feature, just tell that to ``pyximport``::
+
+ >>> pyximport.install(pyimport = True)
+
+Compiling with ``cython.inline``
+=============================
+
+One can also compile Cython in a fashion similar to SciPy's ``weave.inline``.
+For example::
+
+ >>> import cython
+ >>> def f(a):
+ ... ret = cython.inline("return a+b", b=3)
+ ...
+
+Unbound variables are automatically pulled from the surrounding local
+and global scopes, and the result of the compilation is cached for
+efficient re-use.
+
+Compiling with Sage
+===================
+
+The Sage notebook allows transparently editing and compiling Cython
+code simply by typing ``%cython`` at the top of a cell and evaluate
+it. Variables and functions defined in a Cython cell are imported into the
+running session. Please check `Sage documentation
+<http://www.sagemath.org/doc/>`_ for details.
+
+You can tailor the behavior of the Cython compiler by specifying the
+directives below.
+
+====================
+Compiler directives
+====================
+
+Compiler directives are instructions which affect the behavior of
+Cython code. Here is the list of currently supported directives:
+
+``boundscheck`` (True / False)
+ If set to False, Cython is free to assume that indexing operations
+ ([]-operator) in the code will not cause any IndexErrors to be
+ raised. Currently this is only made use of for buffers, lists and
+ tuples, but could be affected other types in the future. Conditions
+ which would normally trigger an IndexError may instead cause
+ segfaults or data corruption if this is set to False.
+ Default is True.
+
+``wraparound`` (True / False)
+ In Python arrays can be indexed relative to the end. For example
+ A[-1] indexes the last value of a list. In C negative indexing is
+ not supported. If set to False, Cython will neither check for nor
+ correctly handle negative indices, possibly causing segfaults or
+ data corruption.
+ Default is True.
+
+``nonecheck`` (True / False)
+ If set to False, Cython is free to assume that native field
+ accesses on variables typed as an extension type, or buffer
+ accesses on a buffer variable, never occurs when the variable is
+ set to ``None``. Otherwise a check is inserted and the
+ appropriate exception is raised. This is off by default for
+ performance reasons. Default is False.
+
+``embedsignature`` (True / False)
+ If set to True, Cython will embed a textual copy of the call
+ signature in the docstring of all Python visible functions and
+ classes. Tools like IPython and epydoc can thus display the
+ signature, which cannot otherwise be retrieved after
+ compilation. Default is False.
+
+``cdivision`` (True / False)
+ If set to False, Cython will adjust the remainder and quotient
+ operators C types to match those of Python ints (which differ when
+ the operands have opposite signs) and raise a
+ ``ZeroDivisionError`` when the right operand is 0. This has up to
+ a 35% speed penalty. If set to True, no checks are performed. See
+ `CEP 516 <http://wiki.cython.org/enhancements/division>`_. Default
+ is False.
+
+``cdivision_warnings`` (True / False)
+ If set to True, Cython will emit a runtime warning whenever
+ division is performed with negative operands. See `CEP 516
+ <http://wiki.cython.org/enhancements/division>`_. Default is
+ False.
+
+``always_allow_keywords`` (True / False)
+ Avoid the ``METH_NOARGS`` and ``METH_O`` when constructing
+ functions/methods which take zero or one arguments. Has no effect
+ on special methods and functions with more than one argument. The
+ ``METH_NOARGS`` and ``METH_O`` signatures provide faster
+ calling conventions but disallow the use of keywords.
+
+``profile`` (True / False)
+ Add hooks for Python profilers into the compiled C code. Default
+ is False.
+
+``infer_types`` (True / False)
+ Infer types of untyped variables in function bodies. Default is
+ None, indicating that on safe (semantically-unchanging) inferences
+ are allowed.
+
+How to set directives
+---------------------
+
+Globally
+:::::::::
+
+One can set compiler directives through a special header comment at the top of the file, like this::
+
+ #!python
+ #cython: boundscheck=False
+
+The comment must appear before any code (but can appear after other
+comments or whitespace).
+
+One can also pass a directive on the command line by using the -X switch::
+
+ $ cython -X boundscheck=True ...
+
+Directives passed on the command line will override directives set in
+header comments.
+
+Locally
+::::::::
+
+For local blocks, you need to cimport the special builtin ``cython``
+module::
+
+ #!python
+ cimport cython
+
+Then you can use the directives either as decorators or in a with
+statement, like this::
+
+ #!python
+ @cython.boundscheck(False) # turn off boundscheck for this function
+ def f():
+ ...
+ with cython.boundscheck(True): # turn it temporarily on again for this block
+ ...
+
+.. Warning:: These two methods of setting directives are **not**
+ affected by overriding the directive on the command-line using the
+ -X option.
--- /dev/null
+Compiler Directives
+===================
+
+TODO. See http://wiki.cython.org/enhancements/compilerdirectives
\ No newline at end of file
--- /dev/null
+.. highlight:: cython
+
+.. _extension_types:
+
+***************
+Extension Types
+***************
+
+* Normal Python as well as extension type classes can be defined.
+* Extension types:
+
+ * Are considered by Python as "built-in" types.
+ * Can be used to wrap arbitrary C-data structures, and provide a Python-like interface to them from Python.
+ * Attributes and methods can be called from Python or Cython code
+ * Are defined by the ``cdef class`` statement.
+
+::
+
+ cdef class Shrubbery:
+
+ cdef int width, height
+
+ def __init__(self, w, h):
+ self.width = w
+ self.height = h
+
+ def describe(self):
+ print "This shrubbery is", self.width, \
+ "by", self.height, "cubits."
+
+==========
+Attributes
+==========
+
+* Are stored directly in the object's C struct.
+* Are fixed at compile time.
+
+ * You can't add attributes to an extension type instance at run time like in normal Python.
+ * You can sub-class the extenstion type in Python to add attributes at run-time.
+
+* There are two ways to access extension type attributes:
+
+ * By Python look-up.
+
+ * Python code's only method of access.
+
+ * By direct access to the C struct from Cython code.
+
+ * Cython code can use either method of access, though.
+
+* By default, extension type attributes are:
+
+ * Only accessible by direct access.
+ * Not accessible from Python code.
+
+* To make attributes accessible to Python, they must be declared ``public`` or ``readonly``::
+
+ cdef class Shrubbery:
+ cdef public int width, height
+ cdef readonly float depth
+
+ * The ``width`` and ``height`` attributes are readable and writable from Python code.
+ * The ``depth`` attribute is readable but not writable.
+
+.. note::
+ .. note::
+ You can only expose simple C types, such as ints, floats, and strings, for Python access. You can also expose Python-valued attributes.
+
+ .. note::
+ The ``public`` and ``readonly`` options apply only to Python access, not direct access. All the attributes of an extension type are always readable and writable by C-level access.
+
+
+=======
+Methods
+=======
+
+* ``self`` is used in extension type methods just like it normally is in Python.
+* See **Functions and Methods**; all of which applies here.
+
+==========
+Properties
+==========
+
+* Cython provides a special syntax::
+
+ cdef class Spam:
+
+ property cheese:
+
+ "A doc string can go here."
+
+ def __get__(self):
+ # This is called when the property is read.
+ ...
+
+ def __set__(self, value):
+ # This is called when the property is written.
+ ...
+
+ def __del__(self):
+ # This is called when the property is deleted.
+
+* The ``__get__()``, ``__set__()``, and ``__del__()`` methods are all optional.
+
+ * If they are ommitted, An exception is raised when an access attempt is made.
+
+* Below, is a full example that defines a property which can..
+
+ * Add to a list each time it is written to (``"__set__"``).
+ * Return the list when it is read (``"__get__"``).
+ * Empty the list when it is deleted (``"__del__"``).
+
+::
+
+ # cheesy.pyx
+ cdef class CheeseShop:
+
+ cdef object cheeses
+
+ def __cinit__(self):
+ self.cheeses = []
+
+ property cheese:
+
+ def __get__(self):
+ return "We don't have: %s" % self.cheeses
+
+ def __set__(self, value):
+ self.cheeses.append(value)
+
+ def __del__(self):
+ del self.cheeses[:]
+
+ # Test input
+ from cheesy import CheeseShop
+
+ shop = CheeseShop()
+ print shop.cheese
+
+ shop.cheese = "camembert"
+ print shop.cheese
+
+ shop.cheese = "cheddar"
+ print shop.cheese
+
+ del shop.cheese
+ print shop.cheese
+
+::
+
+ # Test output
+ We don't have: []
+ We don't have: ['camembert']
+ We don't have: ['camembert', 'cheddar']
+ We don't have: []
+
+
+===============
+Special Methods
+===============
+
+.. note::
+
+ #. The semantics of Cython's special methods are similar in principle to that of Python's.
+ #. There are substantial differences in some behavior.
+ #. Some Cython special methods have no Python counter-part.
+
+* See the :ref:`special_methods_table` for the many that are available.
+
+
+Declaration
+===========
+
+* Must be declared with ``def`` and cannot be declared with ``cdef``.
+* Performance is not affected by the ``def`` declaration because of special calling conventions
+
+Docstrings
+==========
+
+* Docstrings are not supported yet for some special method types.
+* They can be included in the source, but may not appear in the corresponding ``__doc__`` attribute at run-time.
+
+ * This a Python library limitation because the ``PyTypeObject`` data structure is limited
+
+Initialization: ``__cinit__()`` and ``__init__()``
+==================================================
+
+* Any arguments passed to the extension type's constructor, will be passed to both initialization methods.
+* ``__cinit__()`` is where you should perform C-level initialization of the object
+
+ * This includes any allocation of C data structures.
+ * **Caution** is warranted as to what you do in this method.
+
+ * The object may not be fully valid Python object when it is called.
+ * Calling Python objects, including the extensions own methods, may be hazardous.
+
+ * By the time ``__cinit__()`` is called...
+
+ * Memory has been allocated for the object.
+ * All C-level attributes have been initialized to 0 or null.
+ * Python have been initialized to ``None``, but you can not rely on that for each occasion.
+ * This initialization method is guaranteed to be called exactly once.
+
+ * For Extensions types that inherit a base type:
+
+ * The ``__cinit__()`` method of the base type is automatically called before this one.
+ * The inherited ``__cinit__()`` method can not be called explicitly.
+ * Passing modified argument lists to the base type must be done through ``__init__()``.
+ * It may be wise to give the ``__cinit__()`` method both ``"*"`` and ``"**"`` arguments.
+
+ * Allows the method to accept or ignore additional arguments.
+ * Eliminates the need for a Python level sub-class, that changes the ``__init__()`` method's signature, to have to override both the ``__new__()`` and ``__init__()`` methods.
+
+ * If ``__cinit__()`` is declared to take no arguments except ``self``, it will ignore any extra arguments passed to the constructor without complaining about a signature mis-match
+
+
+* ``__init__()`` is for higher-level initialization and is safer for Python access.
+
+ * By the time this method is called, the extension type is a fully valid Python object.
+ * All operations are safe.
+ * This method may sometimes be called more than once, or possibly not at all.
+
+ * Take this into consideration to make sure the design of your other methods are robust of this fact.
+
+Finalization: ``__dealloc__()``
+===============================
+
+* This method is the counter-part to ``__cinit__()``.
+* Any C-data that was explicitly allocated in the ``__cinit__()`` method should be freed here.
+* Use caution in this method:
+
+ * The Python object to which this method belongs may not be completely intact at this point.
+ * Avoid invoking any Python operations that may touch the object.
+ * Don't call any of this object's methods.
+ * It's best to just deallocate C-data structures here.
+
+* All Python attributes of your extension type object are deallocated by Cython after the ``__dealloc__()`` method returns.
+
+Arithmetic Methods
+==================
+
+.. note:: Most of these methods behave differently than in Python
+
+* There are not "reversed" versions of these methods... there is no __radd__() for instance.
+* If the first operand cannot perform the operation, the same method of the second operand is called, with the operands in the same order.
+* Do not rely on the first parameter of these methods, being ``"self"`` or the right type.
+* The types of both operands should be tested before deciding what to do.
+* Return ``NotImplemented`` for unhandled, mis-matched operand types.
+* The previously mentioned points..
+
+ * Also apply to 'in-place' method ``__ipow__()``.
+ * Do not apply to other 'in-place' methods like ``__iadd__()``, in that these always take ``self`` as the first argument.
+
+
+Rich Comparisons
+================
+
+.. note:: There are no separate methods for individual rich comparison operations.
+
+* A single special method called ``__richcmp__()`` replaces all the individual rich compare, special method types.
+* ``__richcmp__()`` takes an integer argument, indicating which operation is to be performed as shown in the table below.
+
+ +-----+-----+
+ | < | 0 |
+ +-----+-----+
+ | == | 2 |
+ +-----+-----+
+ | > | 4 |
+ +-----+-----+
+ | <= | 1 |
+ +-----+-----+
+ | != | 3 |
+ +-----+-----+
+ | >= | 5 |
+ +-----+-----+
+
+
+
+
+The ``__next__()`` Method
+=========================
+
+* Extension types used to expose an iterator interface should define a ``__next__()`` method.
+* **Do not** explicitly supply a ``next()`` method, because Python does that for you automatically.
+
+
+===========
+Subclassing
+===========
+
+* An extension type may inherit from a built-in type or another extension type::
+
+ cdef class Parrot:
+ ...
+
+ cdef class Norwegian(Parrot):
+ ...
+
+* A complete definition of the base type must be available to Cython
+
+ * If the base type is a built-in type, it must have been previously declared as an ``extern`` extension type.
+ * ``cimport`` can be used to import the base type, if the extern declared base type is in a ``.pxd`` definition file.
+
+ * In Cython, multiple inheritance is not permitted.. singlular inheritance only
+
+* Cython extenstion types can also be sub-classed in Python.
+
+ * Here multiple inhertance is permissible as is normal for Python.
+ * Even multiple extension types may be inherited, but C-layout of all the base classes must be compatible.
+
+
+====================
+Forward Declarations
+====================
+
+* Extension types can be "forward-declared".
+* This is necessary when two extension types refer to each other::
+
+ cdef class Shrubbery # forward declaration
+
+ cdef class Shrubber:
+ cdef Shrubbery work_in_progress
+
+ cdef class Shrubbery:
+ cdef Shrubber creator
+
+* An extension type that has a base-class, requires that both forward-declarations be specified::
+
+ cdef class A(B)
+
+ ...
+
+ cdef class A(B):
+ # attributes and methods
+
+
+========================
+Extension Types and None
+========================
+
+* Parameters and C-variables declared as an Extension type, may take the value of ``None``.
+* This is analogous to the way a C-pointer can take the value of ``NULL``.
+
+.. note::
+ #. Exercise caution when using ``None``
+ #. Read this section carefully.
+
+* There is no problem as long as you are performing Python operations on it.
+
+ * This is because full dynamic type checking is applied
+
+* When accessing an extension type's C-attributes, **make sure** it is not ``None``.
+
+ * Cython does not check this for reasons of efficency.
+
+* Be very aware of exposing Python functions that take extension types as arguments::
+
+ def widen_shrubbery(Shrubbery sh, extra_width): # This is
+ sh.width = sh.width + extra_width
+
+ * Users could **crash** the program by passing ``None`` for the ``sh`` parameter.
+ * This could be avoided by::
+
+ def widen_shrubbery(Shrubbery sh, extra_width):
+ if sh is None:
+ raise TypeError
+ sh.width = sh.width + extra_width
+
+ * Cython provides a more convenient way with a ``not None`` clause::
+
+ def widen_shrubbery(Shrubbery sh not None, extra_width):
+ sh.width = sh.width + extra_width
+
+ * Now this function automatically checks that ``sh`` is not ``None``, as well as that is the right type.
+
+* ``not None`` can only be used in Python functions (declared with ``def`` **not** ``cdef``).
+* For ``cdef`` functions, you will have to provide the check yourself.
+* The ``self`` parameter of an extension type is guaranteed to **never** be ``None``.
+* When comparing a value ``x`` with ``None``, and ``x`` is a Python object, note the following:
+
+ * ``x is None`` and ``x is not None`` are very efficient.
+
+ * They translate directly to C-pointer comparisons.
+
+ * ``x == None`` and ``x != None`` or ``if x: ...`` (a boolean condition), will invoke Python operations and will therefore be much slower.
+
+================
+Weak Referencing
+================
+
+* By default, weak references are not supported.
+* It can be enabled by declaring a C attribute of the ``object`` type called ``__weakref__()``::
+
+ cdef class ExplodingAnimal:
+ """This animal will self-destruct when it is
+ no longer strongly referenced."""
+
+ cdef object __weakref__
+
+=========================
+External and Public Types
+=========================
+
+
+Public
+======
+
+* When an extention type is declared ``public``, Cython will generate a C-header (".h") file.
+* The header file will contain the declarations for it's **object-struct** and it's **type-object**.
+* External C-code can now access the attributes of the extension type.
+
+
+External
+========
+
+* An ``extern`` extension type allows you to gain access to the internals of:
+
+ * Python objects defined in the Python core.
+ * Non-Cython extension modules
+
+* The following example lets you get at the C-level members of Python's built-in "complex" object::
+
+ cdef extern from "complexobject.h":
+
+ struct Py_complex:
+ double real
+ double imag
+
+ ctypedef class __builtin__.complex [object PyComplexObject]:
+ cdef Py_complex cval
+
+ # A function which uses the above type
+ def spam(complex c):
+ print "Real:", c.cval.real
+ print "Imag:", c.cval.imag
+
+.. note:: Some important things in the example:
+ #. ``ctypedef`` has been used because because Python's header file has the struct decalared with::
+
+ ctypedef struct {
+ ...
+ } PyComplexObject;
+
+ #. The module of where this type object can be found is specified along side the name of the extension type. See **Implicit Importing**.
+
+ #. When declaring an external extension type...
+
+ * Don't declare any methods, because they are Python method class the are not needed.
+ * Similiar to **structs** and **unions**, extension classes declared inside a ``cdef extern from`` block only need to declare the C members which you will actually need to access in your module.
+
+
+Name Specification Clause
+=========================
+
+.. note:: Only available to **public** and **extern** extension types.
+
+* Example::
+
+ [object object_struct_name, type type_object_name ]
+
+* ``object_struct_name`` is the name to assume for the type's C-struct.
+* ``type_object_name`` is the name to assume for the type's statically declared type-object.
+* The object and type clauses can be written in any order.
+* For ``cdef extern from`` declarations, This clause **is required**.
+
+ * The object clause is required because Cython must generate code that is compatible with the declarations in the header file.
+ * Otherwise the object clause is optional.
+
+* For public extension types, both the object and type clauses **are required** for Cython to generate code that is compatible with external C-code.
+
+================================
+Type Names vs. Constructor Names
+================================
+
+* In a Cython module, the name of an extension type serves two distinct purposes:
+
+ #. When used in an expression, it refers to a "module-level" global variable holding the type's constructor (i.e. it's type-object)
+ #. It can also be used as a C-type name to declare a "type" for variables, arguments, and return values.
+
+* Example::
+
+ cdef extern class MyModule.Spam:
+ ...
+
+ * The name "Spam" serves both of these roles.
+ * Only "Spam" can be used as the type-name.
+ * The constructor can be referred to by other names.
+ * Upon an explicit import of "MyModule"...
+
+ * ``MyModule.Spam()`` could be used as the constructor call.
+ * ``MyModule.Spam`` could not be used as a type-name
+
+* When an "as" clause is used, the name specified takes over both roles::
+
+ cdef extern class MyModule.Spam as Yummy:
+ ...
+
+ * ``Yummy`` becomes both type-name and a name for the constructor.
+ * There other ways of course, to get hold of the constructor, but ``Yummy`` is the only usable type-name.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+Reference Guide
+===============
+
+.. note::
+ .. todo::
+ Most of the **boldface** is to be changed to refs or other markup later.
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ compilation
+ language_basics
+ extension_types
+ interfacing_with_other_code
+ special_mention
+ limitations
+ directives
+
+Indices and tables
+------------------
+
+.. toctree::
+ :maxdepth: 2
+
+ special_methods_table
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
--- /dev/null
+.. highlight:: cython
+
+.. _interfacing_with_other_code:
+
+***************************
+Interfacing with Other Code
+***************************
+
+==
+C
+==
+
+===
+C++
+===
+
+=======
+Fortran
+=======
+
+=====
+Numpy
+=====
+
+
+
--- /dev/null
+.. highlight:: cython
+
+
+
+.. _language_basics:
+
+***************
+Language Basics
+***************
+
+=================
+Cython File Types
+=================
+
+There are three file types in Cython:
+
+* Implementation files carry a ``.pyx`` suffix
+* Definition files carry a ``.pxd`` suffix
+* Include files which carry a ``.pxi`` suffix
+
+
+Implementation File
+===================
+
+What can it contain?
+--------------------
+
+* Basically anything Cythonic, but see below.
+
+What can't it contain?
+----------------------
+
+* There are some restrictions when it comes to **extension types**, if the extension type is
+ already defined else where... **more on this later**
+
+
+Definition File
+===============
+
+What can it contain?
+--------------------
+
+* Any kind of C type declaration.
+* ``extern`` C function or variable declarations.
+* Declarations for module implementations.
+* The definition parts of **extension types**.
+* All declarations of functions, etc., for an **external library**
+
+What can't it contain?
+----------------------
+
+* Any non-extern C variable declaration.
+* Implementations of C or Python functions.
+* Python class definitions
+* Python executable statements.
+* Any declaration that is defined as **public** to make it accessible to other Cython modules.
+
+ * This is not necessary, as it is automatic.
+ * a **public** declaration is only needed to make it accessible to **external C code**.
+
+What else?
+----------
+
+cimport
+```````
+
+* Use the **cimport** statement, as you would Python's import statement, to access these files
+ from other definition or implementation files.
+* **cimport** does not need to be called in ``.pyx`` file for for ``.pxd`` file that has the
+ same name, as they are already in the same namespace.
+* For cimport to find the stated definition file, the path to the file must be appended to the
+ ``-I`` option of the **Cython compile command**.
+
+compilation order
+`````````````````
+
+* When a ``.pyx`` file is to be compiled, Cython first checks to see if a corresponding ``.pxd`` file
+ exits and processes it first.
+
+
+
+Include File
+============
+
+What can it contain?
+--------------------
+
+* Any Cythonic code really, because the entire file is textually embedded at the location
+ you prescribe.
+
+How do I use it?
+----------------
+
+* Include the ``.pxi`` file with an ``include`` statement like: ``include "spamstuff.pxi``
+* The ``include`` statement can appear anywhere in your Cython file and at any indentation level
+* The code in the ``.pxi`` file needs to be rooted at the "zero" indentation level.
+* The included code can itself contain other ``include`` statements.
+
+
+====================
+Declaring Data Types
+====================
+
+
+As a dynamic language, Python encourages a programming style of considering classes and objects in terms of their methods and attributes, more than where they fit into the class hierarchy.
+
+This can make Python a very relaxed and comfortable language for rapid development, but with a price - the 'red tape' of managing data types is dumped onto the interpreter. At run time, the interpreter does a lot of work searching namespaces, fetching attributes and parsing argument and keyword tuples. This run-time ‘late binding’ is a major cause of Python’s relative slowness compared to ‘early binding’ languages such as C++.
+
+However with Cython it is possible to gain significant speed-ups through the use of ‘early binding’ programming techniques.
+
+.. note:: Typing is not a necessity
+
+ Providing static typing to parameters and variables is convenience to speed up your code, but it is not a necessity. Optimize where and when needed.
+
+The cdef Statement
+==================
+
+The ``cdef`` statement is used to make C level declarations for:
+
+:Variables:
+
+::
+
+ cdef int i, j, k
+ cdef float f, g[42], *h
+
+:Structs:
+
+::
+
+ cdef struct Grail:
+ int age
+ float volume
+
+:Unions:
+
+::
+
+ cdef union Food:
+ char *spam
+ float *eggs
+
+
+:Enums:
+
+::
+
+ cdef enum CheeseType:
+ cheddar, edam,
+ camembert
+
+ cdef enum CheeseState:
+ hard = 1
+ soft = 2
+ runny = 3
+
+:Functions:
+
+::
+
+ cdef int eggs(unsigned long l, float f):
+ ...
+
+:Extension Types:
+
+::
+
+ cdef class Spam:
+ ...
+
+
+.. note:: Constants
+
+ Constants can be defined by using an anonymous enum::
+
+ cdef enum:
+ tons_of_spam = 3
+
+
+Grouping cdef Declarations
+==========================
+
+A series of declarations can grouped into a ``cdef`` block::
+
+ cdef:
+ struct Spam:
+ int tons
+
+ int i
+ float f
+ Spam *p
+
+ void f(Spam *s):
+ print s.tons, "Tons of spam"
+
+
+.. note:: ctypedef statement
+
+ The ``ctypedef`` statement is provided for naming types::
+
+ ctypedef unsigned long ULong
+
+ ctypedef int *IntPtr
+
+
+Parameters
+==========
+
+* Both C and Python **function** types can be declared to have parameters C data types.
+* Use normal C declaration syntax::
+
+ def spam(int i, char *s):
+ ...
+
+ cdef int eggs(unsigned long l, float f):
+ ...
+
+* As these parameters are passed into a Python declared function, they are magically **converted** to the specified C type value.
+
+ * This holds true for only numeric and string types
+
+* If no type is specified for a parameter or a return value, it is assumed to be a Python object
+
+ * The following takes two Python objects as parameters and returns a Python object::
+
+ cdef spamobjs(x, y):
+ ...
+
+ .. note:: --
+
+ This is different then C language behavior, where it is an int by default.
+
+
+
+* Python object types have reference counting performed according to the standard Python C-API rules:
+
+ * Borrowed references are taken as parameters
+ * New references are returned
+
+.. todo::
+ link or label here the one ref count caveat for numpy.
+
+* The name ``object`` can be used to explicitly declare something as a Python Object.
+
+ * For sake of code clarity, it recommended to always use ``object`` explicitly in your code.
+
+ * This is also useful for cases where the name being declared would otherwise be taken for a type::
+
+ cdef foo(object int):
+ ...
+
+ * As a return type::
+
+ cdef object foo(object int):
+ ...
+
+.. todo::
+ Do a see also here ..??
+
+Optional Arguments
+------------------
+
+* Are supported for ``cdef`` and ``cpdef`` functions
+* There differences though whether you declare them in a ``.pyx`` file or a ``.pxd`` file
+
+ * When in a ``.pyx`` file, the signature is the same as it is in Python itself::
+
+ cdef class A:
+ cdef foo(self):
+ print "A"
+ cdef class B(A)
+ cdef foo(self, x=None)
+ print "B", x
+ cdef class C(B):
+ cpdef foo(self, x=True, int k=3)
+ print "C", x, k
+
+
+ * When in a ``.pxd`` file, the signature is different like this example: ``cdef foo(x=*)``::
+
+ cdef class A:
+ cdef foo(self)
+ cdef class B(A)
+ cdef foo(self, x=*)
+ cdef class C(B):
+ cpdef foo(self, x=*, int k=*)
+
+
+ * The number of arguments may increase when subclassing, but the arg types and order must be the same.
+
+* There may be a slight performance penalty when the optional arg is overridden with one that does not have default values.
+
+Keyword-only Arguments
+=======================
+
+* As in Python 3, ``def`` functions can have keyword-only argurments listed after a ``"*"`` parameter and before a ``"**"`` parameter if any::
+
+ def f(a, b, *args, c, d = 42, e, **kwds):
+ ...
+
+ * Shown above, the ``c``, ``d`` and ``e`` arguments can not be passed as positional arguments and must be passed as keyword arguments.
+ * Furthermore, ``c`` and ``e`` are required keyword arguments since they do not have a default value.
+
+* If the parameter name after the ``"*"`` is omitted, the function will not accept any extra positional arguments::
+
+ def g(a, b, *, c, d):
+ ...
+
+ * Shown above, the signature takes exactly two positional parameters and has two required keyword parameters
+
+
+
+Automatic Type Conversion
+=========================
+
+* For basic numeric and string types, in most situations, when a Python object is used in the context of a C value and vice versa.
+
+* The following table summarizes the conversion possibilities, assuming ``sizeof(int) == sizeof(long)``:
+
+ +----------------------------+--------------------+------------------+
+ | C types | From Python types | To Python types |
+ +============================+====================+==================+
+ | [unsigned] char | int, long | int |
+ +----------------------------+ | |
+ | [unsigned] short | | |
+ +----------------------------+ | |
+ | int, long | | |
+ +----------------------------+--------------------+------------------+
+ | unsigned int | int, long | long |
+ +----------------------------+ | |
+ | unsigned long | | |
+ +----------------------------+ | |
+ | [unsigned] long long | | |
+ +----------------------------+--------------------+------------------+
+ | float, double, long double | int, long, float | float |
+ +----------------------------+--------------------+------------------+
+ | char * | str/bytes | str/bytes [#]_ |
+ +----------------------------+--------------------+------------------+
+ | struct | | dict |
+ +----------------------------+--------------------+------------------+
+
+.. note::
+ **Python String in a C Context**
+
+ * A Python string, passed to C context expecting a ``char*``, is only valid as long as the Python string exists.
+ * A reference to the Python string must be kept around for as long as the C string is needed.
+ * If this can't be guaranteed, then make a copy of the C string.
+ * Cython may produce an error message: ``Obtaining char* from a temporary Python value`` and will not resume compiling in situations like this::
+
+ cdef char *s
+ s = pystring1 + pystring2
+
+ * The reason is that concatenating to strings in Python produces a temporary variable.
+
+ * The variable is decrefed, and the Python string deallocated as soon as the statement has finished,
+
+ * Therefore the lvalue **``s``** is left dangling.
+
+ * The solution is to assign the result of the concatenation to a Python variable, and then obtain the ``char*`` from that::
+
+ cdef char *s
+ p = pystring1 + pystring2
+ s = p
+
+ .. note::
+ **It is up to you to be aware of this, and not to depend on Cython's error message, as it is not guaranteed to be generated for every situation.**
+
+
+Type Casting
+=============
+
+* The syntax used in type casting are ``"<"`` and ``">"``
+
+ .. note::
+ The syntax is different from C convention
+
+ ::
+
+ cdef char *p, float *q
+ p = <char*>q
+
+* If one of the types is a python object for ``<type>x``, Cython will try and do a coercion.
+
+ .. note:: Cython will not stop a casting where there is no conversion, but it will emit a warning.
+
+* If the address is what is wanted, cast to a ``void*`` first.
+
+
+Type Checking
+-------------
+
+* A cast like ``<MyExtensionType>x`` will cast x to type ``MyExtensionType`` without type checking at all.
+
+* To have a cast type checked, use the syntax like: ``<MyExtensionType?>x``.
+
+ * In this case, Cython will throw an error if ``"x"`` is not a (subclass) of ``MyExtensionType``
+
+* Automatic type checking for extension types can be obtained whenever ``isinstance()`` is used as the second parameter
+
+
+Python Objects
+==============
+
+==========================
+Statements and Expressions
+==========================
+
+* For the most part, control structures and expressions follow Python syntax.
+* When applied to Python objects, the semantics are the same unless otherwise noted.
+* Most Python operators can be applied to C values with the obvious semantics.
+* An expression with mixed Python and C values will have **conversions** performed automatically.
+* Python operations are automatically checked for errors, with the appropriate action taken.
+
+Differences Between Cython and C
+================================
+
+* Most notable are C constructs which have no direct equivalent in Python.
+
+ * An integer literal is treated as a C constant
+
+ * It will be truncated to whatever size your C compiler thinks appropriate.
+ * Cast to a Python object like this::
+
+ <object>10000000000000000000
+
+ * The ``"L"``, ``"LL"`` and the ``"U"`` suffixes have the same meaning as in C
+
+* There is no ``->`` operator in Cython.. instead of ``p->x``, use ``p.x``.
+* There is no ``*`` operator in Cython.. instead of ``*p``, use ``p[0]``.
+* ``&`` is permissible and has the same semantics as in C.
+* ``NULL`` is the null C pointer.
+
+ * Do NOT use 0.
+ * ``NULL`` is a reserved word in Cython
+
+* Syntax for **Type casts** are ``<type>value``.
+
+Scope Rules
+===========
+
+* All determination of scoping (local, module, built-in) in Cython is determined statically.
+* As with Python, a variable assignment which is not declared explicitly is implicitly declared to be a Python variable residing in the scope where it was assigned.
+
+.. note::
+ * Module-level scope behaves the same way as a Python local scope if you refer to the variable before assigning to it.
+
+ * Tricks, like the following will NOT work in Cython::
+
+ try:
+ x = True
+ except NameError:
+ True = 1
+
+ * The above example will not work because ``True`` will always be looked up in the module-level scope. Do the following instead::
+
+ import __builtin__
+ try:
+ True = __builtin__.True
+ except AttributeError:
+ True = 1
+
+
+Built-in Constants
+==================
+
+Predefined Python built-in constants:
+
+* None
+* True
+* False
+
+
+Operator Precedence
+===================
+
+* Cython uses Python precedence order, not C
+
+
+For-loops
+==========
+
+* ``range()`` is C optimized when the index value has been declared by ``cdef``::
+
+ cdef i
+ for i in range(n):
+ ...
+
+* The other form available in C is the for-from style
+
+ * The target expression must be a variable name.
+ * The name between the lower and upper bounds must be the same as the target name.
+
+ for i from 0 <= i < n:
+ ...
+
+ * Or when using a step size::
+
+ for i from 0 <= i < n by s:
+ ...
+
+ * To reverse the direction, reverse the conditional operation::
+
+ for i from 0 >= i > n:
+ ...
+
+* The ``break`` and ``continue`` are permissible.
+* Can contain an else clause.
+
+=====================
+Functions and Methods
+=====================
+
+* There are three types of function declarations in Cython as the sub-sections show below.
+* Only "Python" functions can be called outside a Cython module from *Python interpreted code*.
+
+
+Callable from Python
+=====================
+
+* Are declared with the ``def`` statement
+* Are called with Python objects
+* Return Python objects
+* See **Parameters** for special consideration
+
+Callable from C
+================
+
+* Are declared with the ``cdef`` statement.
+* Are called with either Python objects or C values.
+* Can return either Python objects or C values.
+
+Callable from both Python and C
+================================
+
+* Are declared with the ``cpdef`` statement.
+* Can be called from anywhere, because it uses a little Cython magic.
+* Uses the faster C calling conventions when being called from other Cython code.
+
+Overriding
+==========
+
+``cpdef`` functions can override ``cdef`` functions::
+
+ cdef class A:
+ cdef foo(self):
+ print "A"
+ cdef class B(A)
+ cdef foo(self, x=None)
+ print "B", x
+ cdef class C(B):
+ cpdef foo(self, x=True, int k=3)
+ print "C", x, k
+
+
+Function Pointers
+=================
+
+* Functions declared in a ``struct`` are automatically converted to function pointers.
+* see **using exceptions with function pointers**
+
+Python Built-ins
+================
+
+The following are provided:
+
+.. todo:: incomplete
+
++------------------------------+-------------+----------------------------+
+| Function and arguments | Return type | Python/C API Equivalent |
++==============================+=============+============================+
+| abs(obj) | object | PyNumber_Absolute |
++------------------------------+-------------+----------------------------+
+| bool(obj) | object | Py_True, Py_False |
++------------------------------+-------------+----------------------------+
+| chr(obj) | object | char |
++------------------------------+-------------+----------------------------+
+| delattr(obj, name) | int | PyObject_DelAttr |
++------------------------------+-------------+----------------------------+
+| dir(obj) | object | PyObject_Dir |
+| getattr(obj, name) (Note 1) | | |
+| getattr3(obj, name, default) | | |
++------------------------------+-------------+----------------------------+
+| hasattr(obj, name) | int | PyObject_HasAttr |
++------------------------------+-------------+----------------------------+
+| hash(obj) | int | PyObject_Hash |
++------------------------------+-------------+----------------------------+
+| intern(obj) | object | PyObject_InternFromString |
++------------------------------+-------------+----------------------------+
+| isinstance(obj, type) | int | PyObject_IsInstance |
++------------------------------+-------------+----------------------------+
+| issubclass(obj, type) | int | PyObject_IsSubclass |
++------------------------------+-------------+----------------------------+
+| iter(obj) | object | PyObject_GetIter |
++------------------------------+-------------+----------------------------+
+| len(obj) | Py_ssize_t | PyObject_Length |
++------------------------------+-------------+----------------------------+
+| pow(x, y, z) (Note 2) | object | PyNumber_Power |
++------------------------------+-------------+----------------------------+
+| reload(obj) | object | PyImport_ReloadModule |
++------------------------------+-------------+----------------------------+
+| repr(obj) | object | PyObject_Repr |
++------------------------------+-------------+----------------------------+
+| setattr(obj, name) | void | PyObject_SetAttr |
++------------------------------+-------------+----------------------------+
+
+
+============================
+Error and Exception Handling
+============================
+
+* A plain ``cdef`` declared function, that does not return a Python object...
+
+ * Has no way of reporting a Python exception to it's caller.
+ * Will only print a warning message and the exception is ignored.
+
+* In order to propagate exceptions like this to it's caller, you need to declare an exception value for it.
+* There are three forms of declaring an exception for a C compiled program.
+
+ * First::
+
+ cdef int spam() except -1:
+ ...
+
+ * In the example above, if an error occurs inside spam, it will immediately return with the value of ``-1``, causing an exception to be propagated to it's caller.
+ * Functions declared with an exception value, should explicitly prevent a return of that value.
+
+ * Second::
+
+ cdef int spam() except? -1:
+ ...
+
+ * Used when a ``-1`` may possibly be returned and is not to be considered an error.
+ * The ``"?"`` tells Cython that ``-1`` only indicates a *possible* error.
+ * Now, each time ``-1`` is returned, Cython generates a call to ``PyErr_Occurred`` to verify it is an actual error.
+
+ * Third::
+
+ cdef int spam() except *
+
+ * A call to ``PyErr_Occurred`` happens *every* time the function gets called.
+
+ .. note:: Returning ``void``
+
+ A need to propagate errors when returning ``void`` must use this version.
+
+* Exception values can only be declared for functions returning an..
+
+ * integer
+ * enum
+ * float
+ * pointer type
+ * Must be a constant expression
+
+.. note::
+
+ .. note:: Function pointers
+
+ * Require the same exception value specification as it's user has declared.
+ * Use cases here are when used as parameters and when assigned to a variable::
+
+ int (*grail)(int, char *) except -1
+
+ .. note:: Python Objects
+
+ * Declared exception values are **not** need.
+ * Remember that Cython assumes that a function function without a declared return value, returns a Python object.
+ * Exceptions on such functions are implicitly propagated by returning ``NULL``
+
+ .. note:: C++
+
+ * For exceptions from C++ compiled programs, see **Wrapping C++ Classes**
+
+Checking return values for non-Cython functions..
+=================================================
+
+* Do not try to raise exceptions by returning the specified value.. Example::
+
+ cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
+
+ * The except clause does not work that way.
+ * It's only purpose is to propagate Python exceptions that have already been raised by either...
+
+ * A Cython function
+ * A C function that calls Python/C API routines.
+
+* To propagate an exception for these circumstances you need to raise it yourself::
+
+ cdef FILE *p
+ p = fopen("spam.txt", "r")
+ if p == NULL:
+ raise SpamError("Couldn't open the spam file")
+
+=======================
+Conditional Compilation
+=======================
+
+* The expressions in the following sub-sections must be valid compile-time expressions.
+* They can evaluate to any Python value.
+* The *truth* of the result is determined in the usual Python way.
+
+Compile-Time Definitions
+=========================
+
+* Defined using the ``DEF`` statement::
+
+ DEF FavouriteFood = "spam"
+ DEF ArraySize = 42
+ DEF OtherArraySize = 2 * ArraySize + 17
+
+* The right hand side must be a valid compile-time expression made up of either:
+
+ * Literal values
+ * Names defined by other ``DEF`` statements
+
+* They can be combined using any of the Python expression syntax
+* Cython provides the following predefined names
+
+ * Corresponding to the values returned by ``os.uname()``
+
+ * UNAME_SYSNAME
+ * UNAME_NODENAME
+ * UNAME_RELEASE
+ * UNAME_VERSION
+ * UNAME_MACHINE
+
+* A name defined by ``DEF`` can appear anywhere an identifier can appear.
+* Cython replaces the name with the literal value before compilation.
+
+ * The compile-time expression, in this case, must evaluate to a Python value of ``int``, ``long``, ``float``, or ``str``::
+
+ cdef int a1[ArraySize]
+ cdef int a2[OtherArraySize]
+ print "I like", FavouriteFood
+
+
+Conditional Statements
+=======================
+
+* Similar semantics of the C pre-processor
+* The following statements can be used to conditionally include or exclude sections of code to compile.
+
+ * ``IF``
+ * ``ELIF``
+ * ``ELSE``
+
+::
+
+ IF UNAME_SYSNAME == "Windows":
+ include "icky_definitions.pxi"
+ ELIF UNAME_SYSNAME == "Darwin":
+ include "nice_definitions.pxi"
+ ELIF UNAME_SYSNAME == "Linux":
+ include "penguin_definitions.pxi"
+ ELSE:
+ include "other_definitions.pxi"
+
+* ``ELIF`` and ``ELSE`` are optional.
+* ``IF`` can appear anywhere that a normal statement or declaration can appear
+* It can contain any statements or declarations that would be valid in that context.
+
+ * This includes other ``IF`` and ``DEF`` statements
+
+
+
+.. [#] The conversion is to/from str for Python 2.x, and bytes for Python 3.x.
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+.. highlight:: cython
+
+.. _limitations:
+
+***********
+Limitations
+***********
+
--- /dev/null
+.. highlight:: cython
+
+.. _special_mention:
+
+
+***************
+Special Mention
+***************
--- /dev/null
+.. _special_methods_table:
+
+Special Methods Table
+---------------------
+
+This table lists all of the special methods together with their parameter and
+return types. In the table below, a parameter name of self is used to indicate
+that the parameter has the type that the method belongs to. Other parameters
+with no type specified in the table are generic Python objects.
+
+You don't have to declare your method as taking these parameter types. If you
+declare different types, conversions will be performed as necessary.
+
+General
+^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __cinit__ |self, ... | | Basic initialisation (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __init__ |self, ... | | Further initialisation |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __dealloc__ |self | | Basic deallocation (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __cmp__ |x, y | int | 3-way comparison |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __richcmp__ |x, y, int op | object | Rich comparison (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __str__ |self | object | str(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __repr__ |self | object | repr(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __hash__ |self | int | Hash function |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __call__ |self, ... | object | self(...) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __iter__ |self | object | Return iterator for sequence |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getattr__ |self, name | object | Get attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setattr__ |self, name, val | | Set attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delattr__ |self, name | | Delete attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Arithmetic operators
+^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __add__ | x, y | object | binary `+` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __sub__ | x, y | object | binary `-` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __mul__ | x, y | object | `*` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __div__ | x, y | object | `/` operator for old-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __floordiv__ | x, y | object | `//` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __truediv__ | x, y | object | `/` operator for new-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __mod__ | x, y | object | `%` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __divmod__ | x, y | object | combined div and mod |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __pow__ | x, y, z | object | `**` operator or pow(x, y, z) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __neg__ | self | object | unary `-` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __pos__ | self | object | unary `+` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __abs__ | self | object | absolute value |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __nonzero__ | self | int | convert to boolean |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __invert__ | self | object | `~` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __lshift__ | x, y | object | `<<` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __rshift__ | x, y | object | `>>` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __and__ | x, y | object | `&` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __or__ | x, y | object | `|` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __xor__ | x, y | object | `^` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Numeric conversions
+^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __int__ | self | object | Convert to integer |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __long__ | self | object | Convert to long integer |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __float__ | self | object | Convert to float |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __oct__ | self | object | Convert to octal |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __hex__ | self | object | Convert to hexadecimal |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __index__ (2.5+ only) | self | object | Convert to sequence index |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+In-place arithmetic operators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __iadd__ | self, x | object | `+=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __isub__ | self, x | object | `-=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __imul__ | self, x | object | `*=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __idiv__ | self, x | object | `/=` operator for old-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ifloordiv__ | self, x | object | `//=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __itruediv__ | self, x | object | `/=` operator for new-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __imod__ | self, x | object | `%=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ipow__ | x, y, z | object | `**=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ilshift__ | self, x | object | `<<=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __irshift__ | self, x | object | `>>=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __iand__ | self, x | object | `&=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ior__ | self, x | object | `|=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ixor__ | self, x | object | `^=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Sequences and mappings
+^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __len__ | self int | | len(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getitem__ | self, x | object | self[x] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setitem__ | self, x, y | | self[x] = y |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delitem__ | self, x | | del self[x] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getslice__ | self, Py_ssize_t i, Py_ssize_t j | object | self[i:j] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setslice__ | self, Py_ssize_t i, Py_ssize_t j, x | | self[i:j] = x |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delslice__ | self, Py_ssize_t i, Py_ssize_t j | | del self[i:j] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __contains__ | self, x | int | x in self |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Iterators
+^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __next__ | self | object | Get next item (called next in Python) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Buffer interface
+^^^^^^^^^^^^^^^^
+
+.. note::
+ The buffer interface is intended for use by C code and is not directly
+ accessible from Python. It is described in the Python/C API Reference Manual
+ under sections 6.6 and 10.6.
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __getreadbuffer__ | self, int i, void `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getwritebuffer__ | self, int i, void `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getsegcount__ | self, int `*p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getcharbuffer__ | self, int i, char `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Descriptor objects
+^^^^^^^^^^^^^^^^^^
+
+.. note::
+ Descriptor objects are part of the support mechanism for new-style
+ Python classes. See the discussion of descriptors in the Python documentation.
+ See also PEP 252, "Making Types Look More Like Classes", and PEP 253,
+ "Subtyping Built-In Types".
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __get__ | self, instance, class | object | Get value of attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __set__ | self, instance, value | | Set value of attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delete__ | self, instance | | Delete attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+
+
+
+
--- /dev/null
+Appendix: Installing MinGW on Windows
+=====================================
+
+ 1. Download the MinGW installer from
+ http://www.mingw.org/wiki/HOWTO_Install_the_MinGW_GCC_Compiler_Suite.
+ (As of this
+ writing, the download link is a bit difficult to find; it's under
+ "About" in the menu on the left-hand side). You want the file
+ entitled "Automated MinGW Installer" (currently version 5.1.4).
+ 2. Run it and install MinGW. Only the basic package is strictly
+ needed for Cython, although you might want to grab at least the
+ C++ compiler as well.
+ 3. You need to set up Windows' "PATH" environment variable so that
+ includes e.g. "c:\\mingw\\bin" (if you installed MinGW to
+ "c:\\mingw"). The following web-page describes the procedure
+ in Windows XP (the Vista procedure is similar):
+ http://support.microsoft.com/kb/310519
+ 4. Finally, tell Python to use MinGW as the default compiler
+ (otherwise it will try for Visual C). If Python is installed to
+ "c:\\Python26", create a file named
+ "c:\\Python26\\Lib\\distutils\\distutils.cfg" containing::
+
+ [build]
+ compiler = mingw32
+
+The [WinInst]_ wiki page contains updated information about this
+procedure. Any contributions towards making the Windows install
+process smoother is welcomed; it is an unfortunate fact that none of
+the regular Cython developers have convenient access to Windows.
+
+.. [WinInst] http://wiki.cython.org/InstallingOnWindows
--- /dev/null
+Caveats
+=======
+
+Since Cython mixes C and Python semantics, some things may be a bit
+surprising or unintuitive. Work always goes on to make Cython more natural
+for Python users, so this list may change in the future.
+
+ - ``10**-2 == 0``, instead of ``0.01`` like in Python.
+ - Given two typed ``int`` variables ``a`` and ``b``, ``a % b`` has the
+ same sign as the second argument (following Python semantics) rather then
+ having the same sign as the first (as in C). The C behavior can be
+ obtained, at some speed gain, by enabling the division directive.
+ (Versions prior to Cython 0.12. always followed C semantics.)
+ - Care is needed with unsigned types. ``cdef unsigned n = 10;
+ print(range(-n, n))`` will print an empty list, since ``-n`` wraps
+ around to a large positive integer prior to being passed to the
+ ``range`` function.
+ - Python's ``float`` type actually wraps C ``double`` values, and
+ Python's ``int`` type wraps C ``long`` values.
--- /dev/null
+Extension types (aka. cdef classes)
+===================================
+
+To support object-oriented programming, Cython supports writing normal
+Python classes exactly as in Python::
+
+ class MathFunction(object):
+ def __init__(self, name, operator):
+ self.name = name
+ self.operator = operator
+
+ def __call__(self, *operands):
+ return self.operator(*operands)
+
+Based on what Python calls a "built-in type", however, Cython supports
+a second kind of class: *extension types*, sometimes referred to as
+"cdef classes" due to the keywords used for their declaration. They
+are somewhat restricted compared to Python classes, but are generally
+more memory efficient and faster than generic Python classes. The
+main difference is that they use a C struct to store their fields and methods
+instead of a Python dict. This allows them to store arbitrary C types
+in their fields without requiring a Python wrapper for them, and to
+access fields and methods directly at the C level without passing
+through a Python dictionary lookup.
+
+Normal Python classes can inherit from cdef classes, but not the other
+way around. Cython requires to know the complete inheritance
+hierarchy in order to lay out their C structs, and restricts it to
+single inheritance. Normal Python classes, on the other hand, can
+inherit from any number of Python classes and extension types, both in
+Cython code and pure Python code.
+
+So far our integration example has not been very useful as it only
+integrates a single hard-coded function. In order to remedy this,
+without sacrificing speed, we will use a cdef class to represent a
+function on floating point numbers::
+
+ cdef class Function:
+ cpdef double evaluate(self, double x) except *:
+ return 0
+
+Like before, cpdef makes two versions of the method available; one
+fast for use from Cython and one slower for use from Python. Then::
+
+ cdef class SinOfSquareFunction(Function):
+ cpdef double evaluate(self, double x) except *:
+ return sin(x**2)
+
+Using this, we can now change our integration example::
+
+ def integrate(Function f, double a, double b, int N):
+ cdef int i
+ cdef double s, dx
+ if f is None:
+ raise ValueError("f cannot be None")
+ s = 0
+ dx = (b-a)/N
+ for i in range(N):
+ s += f.evaluate(a+i*dx)
+ return s * dx
+
+ print(integrate(SinOfSquareFunction(), 0, 1, 10000))
+
+This is almost as fast as the previous code, however it is much more flexible
+as the function to integrate can be changed. It is even possible to pass
+in a new function defined in Python-space::
+
+ >>> import integrate
+ >>> class MyPolynomial(integrate.Function):
+ ... def evaluate(self, x):
+ ... return 2*x*x + 3*x - 10
+ ...
+ >>> integrate(MyPolynomial(), 0, 1, 10000)
+ -7.8335833300000077
+
+This is about 20 times slower, but still about 10 times faster than
+the original Python-only integration code. This shows how large the
+speed-ups can easily be when whole loops are moved from Python code
+into a Cython module.
+
+Some notes on our new implementation of ``evaluate``:
+
+ - The fast method dispatch here only works because ``evaluate`` was
+ declared in ``Function``. Had ``evaluate`` been introduced in
+ ``SinOfSquareFunction``, the code would still work, but Cython
+ would have used the slower Python method dispatch mechanism
+ instead.
+
+ - In the same way, had the argument ``f`` not been typed, but only
+ been passed as a Python object, the slower Python dispatch would
+ be used.
+
+ - Since the argument is typed, we need to check whether it is
+ ``None``. In Python, this would have resulted in an ``AttributeError``
+ when the ``evaluate`` method was looked up, but Cython would instead
+ try to access the (incompatible) internal structure of ``None`` as if
+ it were a ``Function``, leading to a crash or data corruption.
+
+There is a *compiler directive* ``nonecheck`` which turns on checks
+for this, at the cost of decreased speed. Here's how compiler directives
+are used to dynamically switch on or off ``nonecheck``::
+
+ #cython: nonecheck=True
+ # ^^^ Turns on nonecheck globally
+
+ import cython
+
+ # Turn off nonecheck locally for the function
+ @cython.nonecheck(False)
+ def func():
+ cdef MyClass obj = None
+ try:
+ # Turn nonecheck on again for a block
+ with cython.nonecheck(True):
+ print obj.myfunc() # Raises exception
+ except AttributeError:
+ pass
+ print obj.myfunc() # Hope for a crash!
+
+
+
+Attributes in cdef classes behave differently from attributes in regular classes:
+
+ - All attributes must be pre-declared at compile-time
+ - Attributes are by default only accessible from Cython (typed access)
+ - Properties can be declared to expose dynamic attributes to Python-space
+
+::
+
+ cdef class WaveFunction(Function):
+ # Not available in Python-space:
+ cdef double offset
+ # Available in Python-space:
+ cdef public double freq
+ # Available in Python-space:
+ property period:
+ def __get__(self):
+ return 1.0 / self. freq
+ def __set__(self, value):
+ self. freq = 1.0 / value
+ <...>
--- /dev/null
+Using C libraries
+=================
+
+Apart from writing fast code, one of the main use cases of Cython is
+to call external C libraries from Python code. As Cython code
+compiles down to C code itself, it is actually trivial to call C
+functions directly in the code. The following gives a complete
+example for using (and wrapping) an external C library in Cython code,
+including appropriate error handling and considerations about
+designing a suitable API for Python and Cython code.
+
+Imagine you need an efficient way to store integer values in a FIFO
+queue. Since memory really matters, and the values are actually
+coming from C code, you cannot afford to create and store Python
+``int`` objects in a list or deque. So you look out for a queue
+implementation in C.
+
+After some web search, you find the C-algorithms library [CAlg]_ and
+decide to use its double ended queue implementation. To make the
+handling easier, however, you decide to wrap it in a Python extension
+type that can encapsulate all memory management.
+
+The C API of the queue implementation, which is defined in the header
+file ``libcalg/queue.h``, essentially looks like this::
+
+ /* file: queue.h */
+
+ typedef struct _Queue Queue;
+ typedef void *QueueValue;
+
+ Queue *queue_new(void);
+ void queue_free(Queue *queue);
+
+ int queue_push_head(Queue *queue, QueueValue data);
+ QueueValue queue_pop_head(Queue *queue);
+ QueueValue queue_peek_head(Queue *queue);
+
+ int queue_push_tail(Queue *queue, QueueValue data);
+ QueueValue queue_pop_tail(Queue *queue);
+ QueueValue queue_peek_tail(Queue *queue);
+
+ int queue_is_empty(Queue *queue);
+
+To get started, the first step is to redefine the C API in a ``.pxd``
+file, say, ``cqueue.pxd``::
+
+ # file: cqueue.pxd
+
+ cdef extern from "libcalg/queue.h":
+ ctypedef struct Queue:
+ pass
+ ctypedef void* QueueValue
+
+ Queue* queue_new()
+ void queue_free(Queue* queue)
+
+ int queue_push_head(Queue* queue, QueueValue data)
+ QueueValue queue_pop_head(Queue* queue)
+ QueueValue queue_peek_head(Queue* queue)
+
+ int queue_push_tail(Queue* queue, QueueValue data)
+ QueueValue queue_pop_tail(Queue* queue)
+ QueueValue queue_peek_tail(Queue* queue)
+
+ bint queue_is_empty(Queue* queue)
+
+Note how these declarations are almost identical to the header file
+declarations, so you can often just copy them over. However, you do
+not need to provide *all* declarations as above, just those that you
+use in your code or in other declarations, so that Cython gets to see
+a sufficient and consistent subset of them. Then, consider adapting
+them somewhat to make them more comfortable to work with in Cython.
+
+One noteworthy difference to the header file that we use above is the
+declaration of the ``Queue`` struct in the first line. ``Queue`` is
+in this case used as an *opaque handle*; only the library that is
+called knows what is really inside. Since no Cython code needs to
+know the contents of the struct, we do not need to declare its
+contents, so we simply provide an empty definition (as we do not want
+to declare the ``_Queue`` type which is referenced in the C header)
+[#]_.
+
+.. [#] There's a subtle difference between ``cdef struct Queue: pass``
+ and ``ctypedef struct Queue: pass``. The former declares a
+ type which is referenced in C code as ``struct Queue``, while
+ the latter is referenced in C as ``Queue``. This is a C
+ language quirk that Cython is not able to hide. Most modern C
+ libraries use the ``ctypedef`` kind of struct.
+
+Another exception is the last line. The integer return value of the
+``queue_is_empty()`` function is actually a C boolean value, i.e. the
+only interesting thing about it is whether it is non-zero or zero,
+indicating if the queue is empty or not. This is best expressed by
+Cython's ``bint`` type, which is a normal ``int`` type when used in C
+but maps to Python's boolean values ``True`` and ``False`` when
+converted to a Python object. This way of tightening declarations in
+a ``.pxd`` file can often simplify the code that uses them.
+
+It is good practice to define one ``.pxd`` file for each library that
+you use, and sometimes even for each header file (or functional group)
+if the API is large. That simplifies their reuse in other projects.
+Sometimes, you may need to use C functions from the standard C
+library, or want to call C-API functions from CPython directly. For
+common needs like this, Cython ships with a set of standard ``.pxd``
+files that provide these declarations in a readily usable way that is
+adapted to their use in Cython. The main packages are ``cpython``,
+``libc`` and ``libcpp``. The NumPy library also has a standard
+``.pxd`` file ``numpy``, as it is often used in Cython code. See
+Cython's ``Cython/Includes/`` source package for a complete list of
+provided ``.pxd`` files.
+
+After declaring our C library's API, we can start to design the Queue
+class that should wrap the C queue. It will live in a file called
+``queue.pyx``. [#]_
+
+.. [#] Note that the name of the ``.pyx`` file must be different from
+ the ``cqueue.pxd`` file with declarations from the C library,
+ as both do not describe the same code. A ``.pxd`` file next to
+ a ``.pyx`` file with the same name defines exported
+ declarations for code in the ``.pyx`` file. As the
+ ``cqueue.pxd`` file contains declarations of a regular C
+ library, there must not be a ``.pyx`` file with the same name
+ that Cython associates with it.
+
+Here is a first start for the Queue class::
+
+ # file: queue.pyx
+
+ cimport cqueue
+
+ cdef class Queue:
+ cdef cqueue.Queue *_c_queue
+ def __cinit__(self):
+ self._c_queue = cqueue.queue_new()
+
+Note that it says ``__cinit__`` rather than ``__init__``. While
+``__init__`` is available as well, it is not guaranteed to be run (for
+instance, one could create a subclass and forget to call the
+ancestor's constructor). Because not initializing C pointers often
+leads to hard crashes of the Python interpreter, Cython provides
+``__cinit__`` which is *always* called immediately on construction,
+before CPython even considers calling ``__init__``, and which
+therefore is the right place to initialise ``cdef`` fields of the new
+instance. However, as ``__cinit__`` is called during object
+construction, ``self`` is not fully constructed yet, and one must
+avoid doing anything with ``self`` but assigning to ``cdef`` fields.
+
+Note also that the above method takes no parameters, although subtypes
+may want to accept some. A no-arguments ``__cinit__()`` method is a
+special case here that simply does not receive any parameters that
+were passed to a constructor, so it does not prevent subclasses from
+adding parameters. If parameters are used in the signature of
+``__cinit__()``, they must match those of any declared ``__init__``
+method of classes in the class hierarchy that are used to instantiate
+the type.
+
+Before we continue implementing the other methods, it is important to
+understand that the above implementation is not safe. In case
+anything goes wrong in the call to ``queue_new()``, this code will
+simply swallow the error, so we will likely run into a crash later on.
+According to the documentation of the ``queue_new()`` function, the
+only reason why the above can fail is due to insufficient memory. In
+that case, it will return ``NULL``, whereas it would normally return a
+pointer to the new queue.
+
+The Python way to get out of this is to raise a ``MemoryError`` [#]_.
+We can thus change the init function as follows::
+
+ cimport cqueue
+
+ cdef class Queue:
+ cdef cqueue.Queue *_c_queue
+ def __cinit__(self):
+ self._c_queue = cqueue.queue_new()
+ if self._c_queue is NULL:
+ raise MemoryError()
+
+.. [#] In the specific case of a ``MemoryError``, creating a new
+ exception instance in order to raise it may actually fail because
+ we are running out of memory. Luckily, CPython provides a C-API
+ function ``PyErr_NoMemory()`` that safely raises the right
+ exception for us. Since version 0.14.1, Cython automatically
+ substitutes this C-API call whenever you write ``raise
+ MemoryError`` or ``raise MemoryError()``. If you use an older
+ version, you have to cimport the C-API function from the standard
+ package ``cpython.exc`` and call it directly.
+
+The next thing to do is to clean up when the Queue instance is no
+longer used (i.e. all references to it have been deleted). To this
+end, CPython provides a callback that Cython makes available as a
+special method ``__dealloc__()``. In our case, all we have to do is
+to free the C Queue, but only if we succeeded in initialising it in
+the init method::
+
+ def __dealloc__(self):
+ if self._c_queue is not NULL:
+ cqueue.queue_free(self._c_queue)
+
+At this point, we have a working Cython module that we can test. To
+compile it, we need to configure a ``setup.py`` script for distutils.
+Here is the most basic script for compiling a Cython module::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("queue", ["queue.pyx"])]
+ )
+
+To build against the external C library, we must extend this script to
+include the necessary setup. Assuming the library is installed in the
+usual places (e.g. under ``/usr/lib`` and ``/usr/include`` on a
+Unix-like system), we could simply change the extension setup from
+
+::
+
+ ext_modules = [Extension("queue", ["queue.pyx"])]
+
+to
+
+::
+
+ ext_modules = [
+ Extension("queue", ["queue.pyx"],
+ libraries=["calg"])
+ ]
+
+If it is not installed in a 'normal' location, users can provide the
+required parameters externally by passing appropriate C compiler
+flags, such as::
+
+ CFLAGS="-I/usr/local/otherdir/calg/include" \
+ LDFLAGS="-L/usr/local/otherdir/calg/lib" \
+ python setup.py build_ext -i
+
+Once we have compiled the module for the first time, we can now import
+it and instantiate a new Queue::
+
+ $ export PYTHONPATH=.
+ $ python -c 'import queue.Queue as Q ; Q()'
+
+However, this is all our Queue class can do so far, so let's make it
+more usable.
+
+Before implementing the public interface of this class, it is good
+practice to look at what interfaces Python offers, e.g. in its
+``list`` or ``collections.deque`` classes. Since we only need a FIFO
+queue, it's enough to provide the methods ``append()``, ``peek()`` and
+``pop()``, and additionally an ``extend()`` method to add multiple
+values at once. Also, since we already know that all values will be
+coming from C, it's best to provide only ``cdef`` methods for now, and
+to give them a straight C interface.
+
+In C, it is common for data structures to store data as a ``void*`` to
+whatever data item type. Since we only want to store ``int`` values,
+which usually fit into the size of a pointer type, we can avoid
+additional memory allocations through a trick: we cast our ``int`` values
+to ``void*`` and vice versa, and store the value directly as the
+pointer value.
+
+Here is a simple implementation for the ``append()`` method::
+
+ cdef append(self, int value):
+ cqueue.queue_push_tail(self._c_queue, <void*>value)
+
+Again, the same error handling considerations as for the
+``__cinit__()`` method apply, so that we end up with this
+implementation instead::
+
+ cdef append(self, int value):
+ if not cqueue.queue_push_tail(self._c_queue,
+ <void*>value):
+ raise MemoryError()
+
+Adding an ``extend()`` method should now be straight forward::
+
+ cdef extend(self, int* values, size_t count):
+ """Append all ints to the queue.
+ """
+ cdef size_t i
+ for i in range(count):
+ if not cqueue.queue_push_tail(
+ self._c_queue, <void*>values[i]):
+ raise MemoryError()
+
+This becomes handy when reading values from a NumPy array, for
+example.
+
+So far, we can only add data to the queue. The next step is to write
+the two methods to get the first element: ``peek()`` and ``pop()``,
+which provide read-only and destructive read access respectively::
+
+ cdef int peek(self):
+ return <int>cqueue.queue_peek_head(self._c_queue)
+
+ cdef int pop(self):
+ return <int>cqueue.queue_pop_head(self._c_queue)
+
+Simple enough. Now, what happens when the queue is empty? According
+to the documentation, the functions return a ``NULL`` pointer, which
+is typically not a valid value. Since we are simply casting to and
+from ints, we cannot distinguish anymore if the return value was
+``NULL`` because the queue was empty or because the value stored in
+the queue was ``0``. However, in Cython code, we would expect the
+first case to raise an exception, whereas the second case should
+simply return ``0``. To deal with this, we need to special case this
+value, and check if the queue really is empty or not::
+
+ cdef int peek(self) except? -1:
+ cdef int value = \
+ <int>cqueue.queue_peek_head(self._c_queue)
+ if value == 0:
+ # this may mean that the queue is empty, or
+ # that it happens to contain a 0 value
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return value
+
+Note how we have effectively created a fast path through the method in
+the hopefully common cases that the return value is not ``0``. Only
+that specific case needs an additional check if the queue is empty.
+
+The ``except? -1`` declaration in the method signature falls into the
+same category. If the function was a Python function returning a
+Python object value, CPython would simply return ``NULL`` internally
+instead of a Python object to indicate an exception, which would
+immediately be propagated by the surrounding code. The problem is
+that the return type is ``int`` and any ``int`` value is a valid queue
+item value, so there is no way to explicitly signal an error to the
+calling code. In fact, without such a declaration, there is no
+obvious way for Cython to know what to return on exceptions and for
+calling code to even know that this method *may* exit with an
+exception.
+
+The only way calling code can deal with this situation is to call
+``PyErr_Occurred()`` when returning from a function to check if an
+exception was raised, and if so, propagate the exception. This
+obviously has a performance penalty. Cython therefore allows you to
+declare which value it should implicitly return in the case of an
+exception, so that the surrounding code only needs to check for an
+exception when receiving this exact value.
+
+We chose to use ``-1`` as the exception return value as we expect it
+to be an unlikely value to be put into the queue. The question mark
+in the ``except? -1`` declaration indicates that the return value is
+ambiguous (there *may* be a ``-1`` value in the queue, after all) and
+that an additional exception check using ``PyErr_Occurred()`` is
+needed in calling code. Without it, Cython code that calls this
+method and receives the exception return value would silently (and
+sometimes incorrectly) assume that an exception has been raised. In
+any case, all other return values will be passed through almost
+without a penalty, thus again creating a fast path for 'normal'
+values.
+
+Now that the ``peek()`` method is implemented, the ``pop()`` method
+also needs adaptation. Since it removes a value from the queue,
+however, it is not enough to test if the queue is empty *after* the
+removal. Instead, we must test it on entry::
+
+ cdef int pop(self) except? -1:
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return <int>cqueue.queue_pop_head(self._c_queue)
+
+The return value for exception propagation is declared exactly as for
+``peek()``.
+
+Lastly, we can provide the Queue with an emptiness indicator in the
+normal Python way by implementing the ``__bool__()`` special method
+(note that Python 2 calls this method ``__nonzero__``, whereas Cython
+code can use either name)::
+
+ def __bool__(self):
+ return not cqueue.queue_is_empty(self._c_queue)
+
+Note that this method returns either ``True`` or ``False`` as we
+declared the return type of the ``queue_is_empty`` function as
+``bint`` in ``cqueue.pxd``.
+
+Now that the implementation is complete, you may want to write some
+tests for it to make sure it works correctly. Especially doctests are
+very nice for this purpose, as they provide some documentation at the
+same time. To enable doctests, however, you need a Python API that
+you can call. C methods are not visible from Python code, and thus
+not callable from doctests.
+
+A quick way to provide a Python API for the class is to change the
+methods from ``cdef`` to ``cpdef``. This will let Cython generate two
+entry points, one that is callable from normal Python code using the
+Python call semantics and Python objects as arguments, and one that is
+callable from C code with fast C semantics and without requiring
+intermediate argument conversion from or to Python types.
+
+The following listing shows the complete implementation that uses
+``cpdef`` methods where possible::
+
+ cimport cqueue
+
+ cdef class Queue:
+ """A queue class for C integer values.
+
+ >>> q = Queue()
+ >>> q.append(5)
+ >>> q.peek()
+ 5
+ >>> q.pop()
+ 5
+ """
+ cdef cqueue.Queue *_c_queue
+ def __cinit__(self):
+ self._c_queue = cqueue.queue_new()
+ if self._c_queue is NULL:
+ raise MemoryError()
+
+ def __dealloc__(self):
+ if self._c_queue is not NULL:
+ cqueue.queue_free(self._c_queue)
+
+ cpdef append(self, int value):
+ if not cqueue.queue_push_tail(self._c_queue,
+ <void*>value):
+ raise MemoryError()
+
+ cdef extend(self, int* values, size_t count):
+ cdef size_t i
+ for i in xrange(count):
+ if not cqueue.queue_push_tail(
+ self._c_queue, <void*>values[i]):
+ raise MemoryError()
+
+ cpdef int peek(self) except? -1:
+ cdef int value = \
+ <int>cqueue.queue_peek_head(self._c_queue)
+ if value == 0:
+ # this may mean that the queue is empty,
+ # or that it happens to contain a 0 value
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return value
+
+ cdef int pop(self) except? -1:
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return <int>cqueue.queue_pop_head(self._c_queue)
+
+ def __bool__(self):
+ return not cqueue.queue_is_empty(self._c_queue)
+
+The ``cpdef`` feature is obviously not available for the ``extend()``
+method, as the method signature is incompatible with Python argument
+types. However, if wanted, we can rename the C-ish ``extend()``
+method to e.g. ``c_extend()``, and write a new ``extend()`` method
+instead that accepts an arbitrary Python iterable::
+
+ cdef c_extend(self, int* values, size_t count):
+ cdef size_t i
+ for i in range(count):
+ if not cqueue.queue_push_tail(
+ self._c_queue, <void*>values[i]):
+ raise MemoryError()
+
+ cpdef extend(self, values):
+ for value in values:
+ self.append(value)
+
+As a quick test with 10000 numbers on the author's machine indicates,
+using this Queue from Cython code with C ``int`` values is about five
+times as fast as using it from Cython code with Python object values,
+almost eight times faster than using it from Python code in a Python
+loop, and still more than twice as fast as using Python's highly
+optimised ``collections.deque`` type from Cython code with Python
+integers.
+
+.. [CAlg] Simon Howard, C Algorithms library, http://c-algorithms.sourceforge.net/
--- /dev/null
+{
+ 'title': 'Cython Tutorial',
+ 'paper_abstract': '''
+Cython is a programming language based on Python with extra
+syntax to provide static type declarations. This takes advantage of the
+benefits of Python while allowing one to achieve the speed of C.
+In this paper we describe the Cython language and show how it can
+be used both to write optimized code and to interface with external
+C libraries.
+''',
+ 'authors': [
+ {'first_names': 'Stefan',
+ 'surname': 'Behnel',
+ 'address': '',
+ 'country': 'Germany',
+ 'email_address': 'stefan\_ml@behnel.de',
+ 'institution': ''},
+ {'first_names': 'Robert W.',
+ 'surname': 'Bradshaw',
+ 'address': '',
+ 'country': 'USA',
+ 'email_address': 'robertwb@math.washington.edu',
+ 'institution': '''University of Washington\\footnote{
+ Department of Mathematics, University of Washington, Seattle, WA, USA
+ }'''},
+ {'first_names': 'Dag Sverre',
+ 'surname': 'Seljebotn',
+ 'address': '',
+ 'country': 'Norway',
+ 'email_address': 'dagss@student.matnat.uio.no',
+ # I need three institutions w/ full address... leave it
+ # all here until we get to editing stage
+ 'institution': '''University of Oslo\\footnote{Institute of Theoretical Astrophysics,
+ University of Oslo, P.O. Box 1029 Blindern, N-0315 Oslo, Norway}\\footnote{Department
+ of Mathematics, University of Oslo, P.O. Box 1053 Blindern,
+ N-0316 Oslo, Norway}\\footnote{Centre of Mathematics for
+ Applications, University of Oslo, P.O. Box 1053 Blindern, N-0316
+ Oslo, Norway}'''}
+ ],
+}
--- /dev/null
+Calling C functions
+====================
+
+This tutorial describes shortly what you need to know in order to call
+C library functions from Cython code. For a longer and more
+comprehensive tutorial about using external C libraries, wrapping them
+and handling errors, see :doc:`clibraries`.
+
+For simplicity, let's start with a function from the standard C
+library. This does not add any dependencies to your code, and it has
+the additional advantage that Cython already defines many such
+functions for you. So you can just cimport and use them.
+
+For example, let's say you need a low-level way to parse a number from
+a ``char*`` value. You could use the ``atoi()`` function, as defined
+by the ``stdlib.h`` header file. This can be done as follows::
+
+ from libc.stdlib cimport atoi
+
+ cdef parse_charptr_to_py_int(char* s):
+ assert s is not NULL, "byte string value is NULL"
+ return atoi(s) # note: atoi() has no error detection!
+
+You can find a complete list of these standard cimport files in
+Cython's source package ``Cython/Includes/``. It also has a complete
+set of declarations for CPython's C-API. For example, to test at C
+compilation time which CPython version your code is being compiled
+with, you can do this::
+
+ from cpython.version cimport PY_VERSION_HEX
+
+ print PY_VERSION_HEX >= 0x030200F0 # Python version >= 3.2 final
+
+Cython also provides declarations for the C math library::
+
+ from libc.math cimport sin
+
+ cdef double f(double x):
+ return sin(x*x)
+
+However, this is a library that is not linked by default on some Unix-like
+systems, such as Linux. In addition to cimporting the
+declarations, you must configure your build system to link against the
+shared library ``m``. For distutils, it is enough to add it to the
+``libraries`` parameter of the ``Extension()`` setup::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ ext_modules=[
+ Extension("demo",
+ ["demo.pyx"],
+ libraries=["m"]) # Unix-like specific
+ ]
+
+ setup(
+ name = "Demos",
+ cmdclass = {"build_ext": build_ext},
+ ext_modules = ext_modules
+ )
+
+If you want to access C code for which Cython does not provide a ready
+to use declaration, you must declare them yourself. For example, the
+above ``sin()`` function is defined as follows::
+
+ cdef extern from "math.h":
+ double sin(double)
+
+This declares the ``sin()`` function in a way that makes it available
+to Cython code and instructs Cython to generate C code that includes
+the ``math.h`` header file. The C compiler will see the original
+declaration in ``math.h`` at compile time, but Cython does not parse
+"math.h" and requires a separate definition.
+
+Just like the ``sin()`` function from the math library, it is possible
+to declare and call into any C library as long as the module that
+Cython generates is properly linked against the shared or static
+library.
--- /dev/null
+Tutorials
+=========
+
+.. toctree::
+ :maxdepth: 2
+
+ external
+ clibraries
+ cdef_classes
+ pxd_files
+ caveats
+ profiling_tutorial
+ strings
+ pure
+ numpy
+ readings
+ related_work
+ appendix
+
--- /dev/null
+=======================
+Working with NumPy
+=======================
+
+You can use NumPy from Cython exactly the same as in regular Python, but by
+doing so you are loosing potentially high speedups because Cython has support
+for fast access to NumPy arrays. Let's see how this works with a simple
+example.
+
+The code below does 2D discrete convolution of an image with a filter (and I'm
+sure you can do better!, let it serve for demonstration purposes). It is both
+valid Python and valid Cython code. I'll refer to it as both
+:file:`convolve_py.py` for the Python version and :file:`convolve1.pyx` for
+the Cython version -- Cython uses ".pyx" as its file suffix.
+
+.. code-block:: python
+
+ from __future__ import division
+ import numpy as np
+ def naive_convolve(f, g):
+ # f is an image and is indexed by (v, w)
+ # g is a filter kernel and is indexed by (s, t),
+ # it needs odd dimensions
+ # h is the output image and is indexed by (x, y),
+ # it is not cropped
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ # smid and tmid are number of pixels between the center pixel
+ # and the edge, ie for a 5x5 filter they will be 2.
+ #
+ # The output size is calculated by adding smid, tmid to each
+ # side of the dimensions of the input image.
+ vmax = f.shape[0]
+ wmax = f.shape[1]
+ smax = g.shape[0]
+ tmax = g.shape[1]
+ smid = smax // 2
+ tmid = tmax // 2
+ xmax = vmax + 2*smid
+ ymax = wmax + 2*tmid
+ # Allocate result image.
+ h = np.zeros([xmax, ymax], dtype=f.dtype)
+ # Do convolution
+ for x in range(xmax):
+ for y in range(ymax):
+ # Calculate pixel value for h at (x,y). Sum one component
+ # for each pixel (s, t) of the filter g.
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h
+
+This should be compiled to produce :file:`yourmod.so` (for Linux systems). We
+run a Python session to test both the Python version (imported from
+``.py``-file) and the compiled Cython module.
+
+.. sourcecode:: ipython
+
+ In [1]: import numpy as np
+ In [2]: import convolve_py
+ In [3]: convolve_py.naive_convolve(np.array([[1, 1, 1]], dtype=np.int),
+ ... np.array([[1],[2],[1]], dtype=np.int))
+ Out [3]:
+ array([[1, 1, 1],
+ [2, 2, 2],
+ [1, 1, 1]])
+ In [4]: import convolve1
+ In [4]: convolve1.naive_convolve(np.array([[1, 1, 1]], dtype=np.int),
+ ... np.array([[1],[2],[1]], dtype=np.int))
+ Out [4]:
+ array([[1, 1, 1],
+ [2, 2, 2],
+ [1, 1, 1]])
+ In [11]: N = 100
+ In [12]: f = np.arange(N*N, dtype=np.int).reshape((N,N))
+ In [13]: g = np.arange(81, dtype=np.int).reshape((9, 9))
+ In [19]: %timeit -n2 -r3 convolve_py.naive_convolve(f, g)
+ 2 loops, best of 3: 1.86 s per loop
+ In [20]: %timeit -n2 -r3 convolve1.naive_convolve(f, g)
+ 2 loops, best of 3: 1.41 s per loop
+
+There's not such a huge difference yet; because the C code still does exactly
+what the Python interpreter does (meaning, for instance, that a new object is
+allocated for each number used). Look at the generated html file and see what
+is needed for even the simplest statements you get the point quickly. We need
+to give Cython more information; we need to add types.
+
+Adding types
+=============
+
+To add types we use custom Cython syntax, so we are now breaking Python source
+compatibility. Consider this code (*read the comments!*) ::
+
+ from __future__ import division
+ import numpy as np
+ # "cimport" is used to import special compile-time information
+ # about the numpy module (this is stored in a file numpy.pxd which is
+ # currently part of the Cython distribution).
+ cimport numpy as np
+ # We now need to fix a datatype for our arrays. I've used the variable
+ # DTYPE for this, which is assigned to the usual NumPy runtime
+ # type info object.
+ DTYPE = np.int
+ # "ctypedef" assigns a corresponding compile-time type to DTYPE_t. For
+ # every type in the numpy module there's a corresponding compile-time
+ # type with a _t-suffix.
+ ctypedef np.int_t DTYPE_t
+ # "def" can type its arguments but not have a return type. The type of the
+ # arguments for a "def" function is checked at run-time when entering the
+ # function.
+ #
+ # The arrays f, g and h is typed as "np.ndarray" instances. The only effect
+ # this has is to a) insert checks that the function arguments really are
+ # NumPy arrays, and b) make some attribute access like f.shape[0] much
+ # more efficient. (In this example this doesn't matter though.)
+ def naive_convolve(np.ndarray f, np.ndarray g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ assert f.dtype == DTYPE and g.dtype == DTYPE
+ # The "cdef" keyword is also used within functions to type variables. It
+ # can only be used at the top indendation level (there are non-trivial
+ # problems with allowing them in other places, though we'd love to see
+ # good and thought out proposals for it).
+ #
+ # For the indices, the "int" type is used. This corresponds to a C int,
+ # other C types (like "unsigned int") could have been used instead.
+ # Purists could use "Py_ssize_t" which is the proper Python type for
+ # array indices.
+ cdef int vmax = f.shape[0]
+ cdef int wmax = f.shape[1]
+ cdef int smax = g.shape[0]
+ cdef int tmax = g.shape[1]
+ cdef int smid = smax // 2
+ cdef int tmid = tmax // 2
+ cdef int xmax = vmax + 2*smid
+ cdef int ymax = wmax + 2*tmid
+ cdef np.ndarray h = np.zeros([xmax, ymax], dtype=DTYPE)
+ cdef int x, y, s, t, v, w
+ # It is very important to type ALL your variables. You do not get any
+ # warnings if not, only much slower code (they are implicitly typed as
+ # Python objects).
+ cdef int s_from, s_to, t_from, t_to
+ # For the value variable, we want to use the same data type as is
+ # stored in the array, so we use "DTYPE_t" as defined above.
+ # NB! An important side-effect of this is that if "value" overflows its
+ # datatype size, it will simply wrap around like in C, rather than raise
+ # an error like in Python.
+ cdef DTYPE_t value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h
+
+After building this and continuing my (very informal) benchmarks, I get:
+
+.. sourcecode:: ipython
+
+ In [21]: import convolve2
+ In [22]: %timeit -n2 -r3 convolve2.naive_convolve(f, g)
+ 2 loops, best of 3: 828 ms per loop
+
+Efficient indexing
+====================
+
+There's still a bottleneck killing performance, and that is the array lookups
+and assignments. The ``[]``-operator still uses full Python operations --
+what we would like to do instead is to access the data buffer directly at C
+speed.
+
+What we need to do then is to type the contents of the :obj:`ndarray` objects.
+We do this with a special "buffer" syntax which must be told the datatype
+(first argument) and number of dimensions ("ndim" keyword-only argument, if
+not provided then one-dimensional is assumed).
+
+These are the needed changes::
+
+ ...
+ def naive_convolve(np.ndarray[DTYPE_t, ndim=2] f, np.ndarray[DTYPE_t, ndim=2] g):
+ ...
+ cdef np.ndarray[DTYPE_t, ndim=2] h = ...
+
+Usage:
+
+.. sourcecode:: ipython
+
+ In [18]: import convolve3
+ In [19]: %timeit -n3 -r100 convolve3.naive_convolve(f, g)
+ 3 loops, best of 100: 11.6 ms per loop
+
+Note the importance of this change.
+
+*Gotcha*: This efficient indexing only affects certain index operations,
+namely those with exactly ``ndim`` number of typed integer indices. So if
+``v`` for instance isn't typed, then the lookup ``f[v, w]`` isn't
+optimized. On the other hand this means that you can continue using Python
+objects for sophisticated dynamic slicing etc. just as when the array is not
+typed.
+
+Tuning indexing further
+========================
+
+The array lookups are still slowed down by two factors:
+
+1. Bounds checking is performed.
+2. Negative indices are checked for and handled correctly. The code above is
+ explicitly coded so that it doesn't use negative indices, and it
+ (hopefully) always access within bounds. We can add a decorator to disable
+ bounds checking::
+
+ ...
+ cimport cython
+ @cython.boundscheck(False) # turn of bounds-checking for entire function
+ def naive_convolve(np.ndarray[DTYPE_t, ndim=2] f, np.ndarray[DTYPE_t, ndim=2] g):
+ ...
+
+Now bounds checking is not performed (and, as a side-effect, if you ''do''
+happen to access out of bounds you will in the best case crash your program
+and in the worst case corrupt data). It is possible to switch bounds-checking
+mode in many ways, see [:docs/compilerdirectives:compiler directives] for more
+information.
+
+Negative indices are dealt with by ensuring Cython that the indices will be
+positive, by casting the variables to unsigned integer types (if you do have
+negative values, then this casting will create a very large positive value
+instead and you will attempt to access out-of-bounds values). Casting is done
+with a special ``<>``-syntax. The code below is changed to use either
+unsigned ints or casting as appropriate::
+
+ ...
+ cdef int s, t # changed
+ cdef unsigned int x, y, v, w # changed
+ cdef int s_from, s_to, t_from, t_to
+ cdef DTYPE_t value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = <unsigned int>(x - smid + s) # changed
+ w = <unsigned int>(y - tmid + t) # changed
+ value += g[<unsigned int>(smid - s), <unsigned int>(tmid - t)] * f[v, w] # changed
+ h[x, y] = value
+ ...
+
+The function call overhead now starts to play a role, so we compare the latter
+two examples with larger N:
+
+.. sourcecode:: ipython
+
+ In [11]: %timeit -n3 -r100 convolve4.naive_convolve(f, g)
+ 3 loops, best of 100: 5.97 ms per loop
+ In [12]: N = 1000
+ In [13]: f = np.arange(N*N, dtype=np.int).reshape((N,N))
+ In [14]: g = np.arange(81, dtype=np.int).reshape((9, 9))
+ In [17]: %timeit -n1 -r10 convolve3.naive_convolve(f, g)
+ 1 loops, best of 10: 1.16 s per loop
+ In [18]: %timeit -n1 -r10 convolve4.naive_convolve(f, g)
+ 1 loops, best of 10: 597 ms per loop
+
+(Also this is a mixed benchmark as the result array is allocated within the
+function call.)
+
+.. Warning::
+
+ Speed comes with some cost. Especially it can be dangerous to set typed
+ objects (like ``f``, ``g`` and ``h`` in our sample code) to
+ :keyword:`None`. Setting such objects to :keyword:`None` is entirely
+ legal, but all you can do with them is check whether they are None. All
+ other use (attribute lookup or indexing) can potentially segfault or
+ corrupt data (rather than raising exceptions as they would in Python).
+
+ The actual rules are a bit more complicated but the main message is clear:
+ Do not use typed objects without knowing that they are not set to None.
+
+More generic code
+==================
+
+It would be possible to do::
+
+ def naive_convolve(object[DTYPE_t, ndim=2] f, ...):
+
+i.e. use :obj:`object` rather than :obj:`np.ndarray`. Under Python 3.0 this
+can allow your algorithm to work with any libraries supporting the buffer
+interface; and support for e.g. the Python Imaging Library may easily be added
+if someone is interested also under Python 2.x.
+
+There is some speed penalty to this though (as one makes more assumptions
+compile-time if the type is set to :obj:`np.ndarray`, specifically it is
+assumed that the data is stored in pure strided more and not in indirect
+mode).
+
--- /dev/null
+.. highlight:: cython
+
+.. _profiling:
+
+*********
+Profiling
+*********
+
+This part describes the profiling abilities of Cython. If you are familiar
+with profiling pure Python code, you can only read the first section
+(:ref:`profiling_basics`). If you are not familiar with python profiling you
+should also read the tutorial (:ref:`profiling_tutorial`) which takes you
+through a complete example step by step.
+
+.. _profiling_basics:
+
+Cython Profiling Basics
+=======================
+
+Profiling in Cython is controlled by a compiler directive.
+It can either be set either for an entire file or on a per function
+via a Cython decorator.
+
+Enable profiling for a complete source file
+-------------------------------------------
+
+Profiling is enable for a complete source file via a global directive to the
+Cython compiler at the top of a file::
+
+ # cython: profile=True
+
+Note that profiling gives a slight overhead to each function call therefore making
+your program a little slower (or a lot, if you call some small functions very
+often).
+
+Once enabled, your Cython code will behave just like Python code when called
+from the cProfile module. This means you can just profile your Cython code
+together with your Python code using the same tools as for Python code alone.
+
+Disabling profiling function wise
+------------------------------------------
+
+If your profiling is messed up because of the call overhead to some small
+functions that you rather do not want to see in your profile - either because
+you plan to inline them anyway or because you are sure that you can't make them
+any faster - you can use a special decorator to disable profiling for one
+function only::
+
+ cimport cython
+
+ @cython.profile(False)
+ def my_often_called_function():
+ pass
+
+
+.. _profiling_tutorial:
+
+Profiling Tutorial
+==================
+
+This will be a complete tutorial, start to finish, of profiling python code,
+turning it into Cython code and keep profiling until it is fast enough.
+
+As a toy example, we would like to evaluate the summation of the reciprocals of
+squares up to a certain integer :math:`n` for evaluating :math:`\pi`. The
+relation we want to use has been proven by Euler in 1735 and is known as the
+`Basel problem <http://en.wikipedia.org/wiki/Basel_problem>`_.
+
+
+.. math::
+ \pi^2 = 6 \sum_{k=1}^{\infty} \frac{1}{k^2} =
+ 6 \lim_{k \to \infty} \big( \frac{1}{1^2} +
+ \frac{1}{2^2} + \dots + \frac{1}{k^2} \big) \approx
+ 6 \big( \frac{1}{1^2} + \frac{1}{2^2} + \dots + \frac{1}{n^2} \big)
+
+A simple python code for evaluating the truncated sum looks like this::
+
+ #!/usr/bin/env python
+ # encoding: utf-8
+ # filename: calc_pi.py
+
+ def recip_square(i):
+ return 1./i**2
+
+ def approx_pi(n=10000000):
+ val = 0.
+ for k in range(1,n+1):
+ val += recip_square(k)
+ return (6 * val)**.5
+
+On my box, this needs approximately 4 seconds to run the function with the
+default n. The higher we choose n, the better will be the approximation for
+:math:`\pi`. An experienced python programmer will already see plenty of
+places to optimize this code. But remember the golden rule of optimization:
+Never optimize without having profiled. Let me repeat this: **Never** optimize
+without having profiled your code. Your thoughts about which part of your
+code takes too much time are wrong. At least, mine are always wrong. So let's
+write a short script to profile our code::
+
+ #!/usr/bin/env python
+ # encoding: utf-8
+ # filename: profile.py
+
+ import pstats, cProfile
+
+ import calc_pi
+
+ cProfile.runctx("calc_pi.approx_pi()", globals(), locals(), "Profile.prof")
+
+ s = pstats.Stats("Profile.prof")
+ s.strip_dirs().sort_stats("time").print_stats()
+
+Running this on my box gives the following output::
+
+ TODO: how to display this not as code but verbatimly?
+
+ Sat Nov 7 17:40:54 2009 Profile.prof
+
+ 10000004 function calls in 6.211 CPU seconds
+
+ Ordered by: internal time
+
+ ncalls tottime percall cumtime percall filename:lineno(function)
+ 1 3.243 3.243 6.211 6.211 calc_pi.py:7(approx_pi)
+ 10000000 2.526 0.000 2.526 0.000 calc_pi.py:4(recip_square)
+ 1 0.442 0.442 0.442 0.442 {range}
+ 1 0.000 0.000 6.211 6.211 <string>:1(<module>)
+ 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
+
+This contains the information that the code runs in 6.2 CPU seconds. Note that
+the code got slower by 2 seconds because it ran inside the cProfile module. The
+table contains the real valuable information. You might want to check the
+python `profiling documentation <http://docs.python.org/library/profile.html>`_
+for the nitty gritty details. The most important columns here are totime (total
+time spent in this function **not** counting functions that were called by this
+function) and cumtime (total time spent in this function **also** counting the
+functions called by this function). Looking at the tottime column, we see that
+approximately half the time is spent in approx_pi and the other half is spent
+in recip_square. Also half a second is spent in range ... of course we should
+have used xrange for such a big iteration. And in fact, just changing range to
+xrange makes the code run in 5.8 seconds.
+
+We could optimize a lot in the pure python version, but since we are interested
+in Cython, let's move forward and bring this module to Cython. We would do this
+anyway at some time to get the loop run faster. Here is our first Cython version::
+
+ # encoding: utf-8
+ # cython: profile=True
+ # filename: calc_pi.pyx
+
+ def recip_square(int i):
+ return 1./i**2
+
+ def approx_pi(int n=10000000):
+ cdef double val = 0.
+ cdef int k
+ for k in xrange(1,n+1):
+ val += recip_square(k)
+ return (6 * val)**.5
+
+Note the second line: We have to tell Cython that profiling should be enabled.
+This makes the Cython code slightly slower, but without this we would not get
+meaningful output from the cProfile module. The rest of the code is mostly
+unchanged, I only typed some variables which will likely speed things up a bit.
+
+We also need to modify our profiling script to import the Cython module directly.
+Here is the complete version adding the import of the pyximport module::
+
+ #!/usr/bin/env python
+ # encoding: utf-8
+ # filename: profile.py
+
+ import pstats, cProfile
+
+ import pyximport
+ pyximport.install()
+
+ import calc_pi
+
+ cProfile.runctx("calc_pi.approx_pi()", globals(), locals(), "Profile.prof")
+
+ s = pstats.Stats("Profile.prof")
+ s.strip_dirs().sort_stats("time").print_stats()
+
+We only added two lines, the rest stays completely the same. Alternatively, we could also
+manually compile our code into an extension; we wouldn't need to change the
+profile script then at all. The script now outputs the following::
+
+ Sat Nov 7 18:02:33 2009 Profile.prof
+
+ 10000004 function calls in 4.406 CPU seconds
+
+ Ordered by: internal time
+
+ ncalls tottime percall cumtime percall filename:lineno(function)
+ 1 3.305 3.305 4.406 4.406 calc_pi.pyx:7(approx_pi)
+ 10000000 1.101 0.000 1.101 0.000 calc_pi.pyx:4(recip_square)
+ 1 0.000 0.000 4.406 4.406 {calc_pi.approx_pi}
+ 1 0.000 0.000 4.406 4.406 <string>:1(<module>)
+ 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
+
+We gained 1.8 seconds. Not too shabby. Comparing the output to the previous, we
+see that recip_square function got faster while the approx_pi function has not
+changed a lot. Let's concentrate on the recip_square function a bit more. First
+note, that this function is not to be called from code outside of our module;
+so it would be wise to turn it into a cdef to reduce call overhead. We should
+also get rid of the power operator: it is turned into a pow(i,2) function call by
+Cython, but we could instead just write i*i which could be faster. The
+whole function is also a good candidate for inlining. Let's look at the
+necessary changes for these ideas::
+
+ # encoding: utf-8
+ # cython: profile=True
+ # filename: calc_pi.pyx
+
+ cdef inline double recip_square(int i):
+ return 1./(i*i)
+
+ def approx_pi(int n=10000000):
+ cdef double val = 0.
+ cdef int k
+ for k in xrange(1,n+1):
+ val += recip_square(k)
+ return (6 * val)**.5
+
+Now running the profile script yields::
+
+ Sat Nov 7 18:10:11 2009 Profile.prof
+
+ 10000004 function calls in 2.622 CPU seconds
+
+ Ordered by: internal time
+
+ ncalls tottime percall cumtime percall filename:lineno(function)
+ 1 1.782 1.782 2.622 2.622 calc_pi.pyx:7(approx_pi)
+ 10000000 0.840 0.000 0.840 0.000 calc_pi.pyx:4(recip_square)
+ 1 0.000 0.000 2.622 2.622 {calc_pi.approx_pi}
+ 1 0.000 0.000 2.622 2.622 <string>:1(<module>)
+ 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
+
+That bought us another 1.8 seconds. Not the dramatic change we could have
+expected. And why is recip_square still in this table; it is supposed to be
+inlined, isn't it? The reason for this is that Cython still generates profiling code
+even if the function call is eliminated. Let's tell it to not
+profile recip_square any more; we couldn't get the function to be much faster anyway::
+
+ # encoding: utf-8
+ # cython: profile=True
+ # filename: calc_pi.pyx
+
+ cimport cython
+
+ @cython.profile(False)
+ cdef inline double recip_square(int i):
+ return 1./(i*i)
+
+ def approx_pi(int n=10000000):
+ cdef double val = 0.
+ cdef int k
+ for k in xrange(1,n+1):
+ val += recip_square(k)
+ return (6 * val)**.5
+
+Running this shows an interesting result::
+
+ Sat Nov 7 18:15:02 2009 Profile.prof
+
+ 4 function calls in 0.089 CPU seconds
+
+ Ordered by: internal time
+
+ ncalls tottime percall cumtime percall filename:lineno(function)
+ 1 0.089 0.089 0.089 0.089 calc_pi.pyx:10(approx_pi)
+ 1 0.000 0.000 0.089 0.089 {calc_pi.approx_pi}
+ 1 0.000 0.000 0.089 0.089 <string>:1(<module>)
+ 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
+
+First note the tremendous speed gain: this version only takes 1/50 of the time
+of our first Cython version. Also note that recip_square has vanished from the
+table like we wanted. But the most peculiar and import change is that
+approx_pi also got much faster. This is a problem with all profiling: calling a
+function in a profile run adds a certain overhead to the function call. This
+overhead is **not** added to the time spent in the called function, but to the
+time spent in the **calling** function. In this example, approx_pi didn't need 2.622
+seconds in the last run; but it called recip_square 10000000 times, each time taking a
+little to set up profiling for it. This adds up to the massive time loss of
+around 2.6 seconds. Having disabled profiling for the often called function now
+reveals realistic timings for approx_pi; we could continue optimizing it now if
+needed.
+
+This concludes this profiling tutorial. There is still some room for
+improvement in this code. We could try to replace the power operator in
+approx_pi with a call to sqrt from the C stdlib; but this is not necessarily
+faster than calling pow(x,0.5).
+
+Even so, the result we achieved here is quite satisfactory: we came up with a
+solution that is much faster then our original python version while retaining
+functionality and readability.
+
+
--- /dev/null
+Pure Python Mode
+================
+
+Cython provides language constructs to let the same file be either interpreted
+or compiled. This is accomplished by the same "magic" module ``cython`` that
+directives use and which must be imported. This is available for both :file:`.py` and
+:file:`.pyx` files.
+
+This is accomplished via special functions and decorators and an (optional)
+augmenting :file:`.pxd` file.
+
+Magic Attributes
+----------------
+
+The currently supported attributes of the ``cython`` module are:
+
+* ``declare`` declares a typed variable in the current scope, which can be used in
+ place of the :samp:`cdef type var [= value]` construct. This has two forms, the
+ first as an assignment (useful as it creates a declaration in
+ interpreted mode as well)::
+
+ x = cython.declare(cython.int) # cdef int x
+ y = cython.declare(cython.double, 0.57721) # cdef double y = 0.57721
+
+ and the second mode as a simple function call::
+
+ cython.declare(x=cython.int, y=cython.double) # cdef int x; cdef double y
+
+* ``locals`` is a decorator that is used to specify the types of local variables
+ in the function body (including any or all of the argument types)::
+
+ @cython.locals(a=cython.double, b=cython.double, n=cython.p_double)
+ def foo(a, b, x, y):
+ ...
+
+* ``address`` is used in place of the ``&`` operator::
+
+ cython.declare(x=cython.int, x_ptr=cython.p_int)
+ x_ptr = cython.address(x)
+
+* ``sizeof`` emulates the `sizeof` operator. It can take both types and
+ expressions.::
+
+ cython.declare(n=cython.longlong)
+ print cython.sizeof(cython.longlong), cython.sizeof(n)
+
+* ``struct`` can be used to create struct types.::
+
+ MyStruct = cython.struct(x=cython.int, y=cython.int, data=cython.double)
+ a = cython.declare(MyStruct)
+
+ is equivalent to the code::
+
+ cdef struct MyStruct:
+ int x
+ int y
+ double data
+
+ cdef MyStruct a
+
+* ``union`` creates union types with exactly the same syntax as ``struct``
+
+* ``typedef`` creates a new type::
+
+ T = cython.typedef(cython.p_int) # ctypedef int* T
+
+* ``compiled`` is a special variable which is set to ``True`` when the compiler
+ runs, and ``False`` in the interpreter. Thus the code::
+
+ if cython.compiled:
+ print "Yep, I'm compiled."
+ else:
+ print "Just a lowly interpreted script."
+
+ will behave differently depending on whether or not the code is loaded as a
+ compiled :file:`.so` file or a plain :file:`.py` file.
+
+Augmenting .pxd
+---------------
+
+If a :file:`.pxd` file is found with the same name as a :file:`.py` file, it will be
+searched for :keyword:`cdef` classes and :keyword:`cdef`/:keyword:`cpdef`
+functions and methods. It will then convert the corresponding
+classes/functions/methods in the :file:`.py` file to be of the correct type. Thus if
+one had :file:`a.pxd`::
+
+ cdef class A:
+ cpdef foo(self, int i)
+
+the file :file:`a.py`::
+
+ class A:
+ def foo(self, i):
+ print "Big" if i > 1000 else "Small"
+
+would be interpreted as::
+
+ cdef class A:
+ cpdef foo(self, int i):
+ print "Big" if i > 1000 else "Small"
+
+The special cython module can also be imported and used within the augmenting
+:file:`.pxd` file. This makes it possible to add types to a pure python file without
+changing the file itself. For example, the following python file
+:file:`dostuff.py`::
+
+ def dostuff(n):
+ t = 0
+ for i in range(n):
+ t += i
+ return t
+
+could be augmented with the following :file:`.pxd` file :file:`dostuff.pxd`::
+
+ import cython
+
+ @cython.locals(t = cython.int, i = cython.int)
+ cpdef int dostuff(int n)
+
+Besides the ``cython.locals`` decorator, the :func:`cython.declare` function can also be
+used to add types to global variables in the augmenting :file:`.pxd` file.
+
+Note that normal Python (:keyword:`def`) functions cannot be declared in
+:file:`.pxd` files, so it is currently impossible to override the types of
+Python functions in :file:`.pxd` files if they use ``*args`` or ``**kwargs`` in their
+signature, for instance.
+
+Types
+-----
+
+There are numerous types built in to the cython module. One has all the
+standard C types, namely ``char``, ``short``, ``int``, ``long``, ``longlong``
+as well as their unsigned versions ``uchar``, ``ushort``, ``uint``, ``ulong``,
+``ulonglong``. One also has ``bint`` and ``Py_ssize_t``. For each type, one
+has pointer types ``p_int``, ``pp_int``, . . ., up to three levels deep in
+interpreted mode, and infinitely deep in compiled mode. The Python types int,
+long and bool are interpreted as C ``int``, ``long`` and ``bint``
+respectively. Also, the python types ``list``, ``dict``, ``tuple``, . . . may
+be used, as well as any user defined types.
+
+Pointer types may be constructed with ``cython.pointer(cython.int)``, and
+arrays as ``cython.int[10]``. A limited attempt is made to emulate these more
+complex types, but only so much can be done from the Python language.
+
+Decorators (not yet implemented)
+--------------------------------
+
+We have settled on ``@cython.cclass`` for the ``cdef class``
+decorators, and ``@cython.cfunc`` and ``@cython.ccall`` for :keyword:`cdef` and
+:keyword:`cpdef` functions (respectively).
+http://codespeak.net/pipermail/cython-dev/2008-November/002925.html
+
--- /dev/null
+pxd files
+=========
+
+In addition to the ``.pyx`` source files, Cython uses ``.pxd`` files
+which work like C header files -- they contain Cython declarations
+(and sometimes code sections) which are only meant for inclusion by
+Cython modules. A ``pxd`` file is imported into a ``pyx`` module by
+using the ``cimport`` keyword.
+
+``pxd`` files have many use-cases:
+
+ 1. They can be used for sharing external C declarations.
+ 2. They can contain functions which are well suited for inlining by
+ the C compiler. Such functions should be marked ``inline``, example:
+ ::
+
+ cdef inline int int_min(int a, int b):
+ return b if b < a else a
+
+ 3. When accompanying an equally named ``pyx`` file, they
+ provide a Cython interface to the Cython module so that other
+ Cython modules can communicate with it using a more efficient
+ protocol than the Python one.
+
+In our integration example, we might break it up into ``pxd`` files like this:
+
+ 1. Add a ``cmath.pxd`` function which defines the C functions available from
+ the C ``math.h`` header file, like ``sin``. Then one would simply do
+ ``from cmath cimport sin`` in ``integrate.pyx``.
+ 2. Add a ``integrate.pxd`` so that other modules written in Cython
+ can define fast custom functions to integrate.
+ ::
+
+ cdef class Function:
+ cpdef evaluate(self, double x)
+ cpdef integrate(Function f, double a,
+ double b, int N)
+
+ Note that if you have a cdef class with attributes, the attributes must
+ be declared in the class declaration ``pxd`` file (if you use one), not
+ the ``pyx`` file. The compiler will tell you about this.
--- /dev/null
+cdef extern from "libcalg/queue.h":
+ ctypedef struct Queue:
+ pass
+ ctypedef void* QueueValue
+
+ Queue* queue_new()
+ void queue_free(Queue* queue)
+
+ int queue_push_head(Queue* queue, QueueValue data)
+ QueueValue queue_pop_head(Queue* queue)
+ QueueValue queue_peek_head(Queue* queue)
+
+ int queue_push_tail(Queue* queue, QueueValue data)
+ QueueValue queue_pop_tail(Queue* queue)
+ QueueValue queue_peek_tail(Queue* queue)
+
+ int queue_is_empty(Queue* queue)
--- /dev/null
+cimport cqueue
+cimport python_exc
+
+cdef class Queue:
+ cdef cqueue.Queue* _c_queue
+ def __cinit__(self):
+ self._c_queue = cqueue.queue_new()
+ if self._c_queue is NULL:
+ python_exc.PyErr_NoMemory()
+
+ def __dealloc__(self):
+ if self._c_queue is not NULL:
+ cqueue.queue_free(self._c_queue)
+
+ cpdef int append(self, int value) except -1:
+ if not cqueue.queue_push_tail(self._c_queue, <void*>value):
+ python_exc.PyErr_NoMemory()
+ return 0
+
+ cdef int extend(self, int* values, Py_ssize_t count) except -1:
+ cdef Py_ssize_t i
+ for i in xrange(count):
+ if not cqueue.queue_push_tail(self._c_queue, <void*>values[i]):
+ python_exc.PyErr_NoMemory()
+ return 0
+
+ cpdef int peek(self) except? 0:
+ cdef int value = <int>cqueue.queue_peek_head(self._c_queue)
+ if value == 0:
+ # this may mean that the queue is empty, or that it
+ # happens to contain a 0 value
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return value
+
+ cpdef int pop(self) except? 0:
+ cdef int value = <int>cqueue.queue_pop_head(self._c_queue)
+ if value == 0:
+ # this may mean that the queue is empty, or that it
+ # happens to contain a 0 value
+ if cqueue.queue_is_empty(self._c_queue):
+ raise IndexError("Queue is empty")
+ return value
+
+ def __nonzero__(self):
+ return not cqueue.queue_is_empty(self._c_queue)
+
+DEF repeat_count=10000
+
+def test_cy():
+ cdef int i
+ cdef Queue q = Queue()
+ for i in xrange(repeat_count):
+ q.append(i)
+ for i in xrange(repeat_count):
+ q.peek()
+ while q:
+ q.pop()
+
+def test_py():
+ cdef int i
+ q = Queue()
+ for i in xrange(repeat_count):
+ q.append(i)
+ for i in xrange(repeat_count):
+ q.peek()
+ while q:
+ q.pop()
+
+from collections import deque
+
+def test_deque():
+ cdef int i
+ q = deque()
+ for i in xrange(repeat_count):
+ q.appendleft(i)
+ for i in xrange(repeat_count):
+ q[-1]
+ while q:
+ q.pop()
+
+repeat = range(repeat_count)
+
+def test_py_exec():
+ q = Queue()
+ d = dict(q=q, repeat=repeat)
+
+ exec u"""\
+for i in repeat:
+ q.append(9)
+for i in repeat:
+ q.peek()
+while q:
+ q.pop()
+""" in d
--- /dev/null
+Further reading
+===============
+
+The main documentation is located at http://docs.cython.org/. Some
+recent features might not have documentation written yet, in such
+cases some notes can usually be found in the form of a Cython
+Enhancement Proposal (CEP) on http://wiki.cython.org/enhancements.
+
+[Seljebotn09]_ contains more information about Cython and NumPy
+arrays. If you intend to use Cython code in a multi-threaded setting,
+it is essential to read up on Cython's features for managing the
+Global Interpreter Lock (the GIL). The same paper contains an
+explanation of the GIL, and the main documentation explains the Cython
+features for managing it.
+
+Finally, don't hesitate to ask questions (or post reports on
+successes!) on the Cython users mailing list [UserList]_. The Cython
+developer mailing list, [DevList]_, is also open to everybody, but
+focusses on core development issues. Feel free to use it to report a
+clear bug, to ask for guidance if you have time to spare to develop
+Cython, or if you have suggestions for future development.
+
+.. [DevList] Cython developer mailing list: http://mail.python.org/mailman/listinfo/cython-devel
+.. [Seljebotn09] D. S. Seljebotn, Fast numerical computations with Cython,
+ Proceedings of the 8th Python in Science Conference, 2009.
+.. [UserList] Cython users mailing list: http://groups.google.com/group/cython-users
--- /dev/null
+Related work
+============
+
+Pyrex [Pyrex]_ is the compiler project that Cython was originally
+based on. Many features and the major design decisions of the Cython
+language were developed by Greg Ewing as part of that project. Today,
+Cython supersedes the capabilities of Pyrex by providing a
+substantially higher compatibility with Python code and Python
+semantics, as well as superior optimisations and better integration
+with scientific Python extensions like NumPy.
+
+ctypes [ctypes]_ is a foreign function interface (FFI) for Python. It
+provides C compatible data types, and allows calling functions in DLLs
+or shared libraries. It can be used to wrap these libraries in pure
+Python code. Compared to Cython, it has the major advantage of being
+in the standard library and being usable directly from Python code,
+without any additional dependencies. The major drawback is its
+performance, which suffers from the Python call overhead as all
+operations must pass through Python code first. Cython, being a
+compiled language, can avoid much of this overhead by moving more
+functionality and long-running loops into fast C code.
+
+SWIG [SWIG]_ is a wrapper code generator. It makes it very easy to
+parse large API definitions in C/C++ header files, and to generate
+straight forward wrapper code for a large set of programming
+languages. As opposed to Cython, however, it is not a programming
+language itself. Thin wrappers are easy to generate, but the more
+functionality a wrapper needs to provide, the harder it gets to
+implement it with SWIG. Cython, on the other hand, makes it very easy
+to write very elaborate wrapper code specifically for the Python
+language, and to make it as thin or thick as needed at any given
+place. Also, there exists third party code for parsing C header files
+and using it to generate Cython definitions and module skeletons.
+
+ShedSkin [ShedSkin]_ is an experimental Python-to-C++ compiler. It
+uses a very powerful whole-module type inference engine to generate a
+C++ program from (restricted) Python source code. The main drawback
+is that it has no support for calling the Python/C API for operations
+it does not support natively, and supports very few of the standard
+Python modules.
+
+.. [ctypes] http://docs.python.org/library/ctypes.html.
+.. there's also the original ctypes home page: http://python.net/crew/theller/ctypes/
+.. [Pyrex] G. Ewing, Pyrex: C-Extensions for Python,
+ http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
+.. [ShedSkin] M. Dufour, J. Coughlan, ShedSkin,
+ http://code.google.com/p/shedskin/
+.. [SWIG] David M. Beazley et al.,
+ SWIG: An Easy to Use Tool for Integrating Scripting Languages with C and C++,
+ http://www.swig.org.
--- /dev/null
+.. highlight:: cython
+
+Unicode and passing strings
+===========================
+
+Similar to the string semantics in Python 3, Cython also strictly
+separates byte strings and unicode strings. Above all, this means
+that there is no automatic conversion between byte strings and unicode
+strings (except for what Python 2 does in string operations). All
+encoding and decoding must pass through an explicit encoding/decoding
+step.
+
+It is, however, very easy to pass byte strings between C code and Python.
+When receiving a byte string from a C library, you can let Cython
+convert it into a Python byte string by simply assigning it to a
+Python variable::
+
+ cdef char* c_string = c_call_returning_a_c_string()
+ cdef bytes py_string = c_string
+
+This creates a Python byte string object that holds a copy of the
+original C string. It can be safely passed around in Python code, and
+will be garbage collected when the last reference to it goes out of
+scope. It is important to remember that null bytes in the string act
+as terminator character, as generally known from C. The above will
+therefore only work correctly for C strings that do not contain null
+bytes.
+
+Note that the creation of the Python bytes string can fail with an
+exception, e.g. due to insufficient memory. If you need to ``free()``
+the string after the conversion, you should wrap the assignment in a
+try-finally construct::
+
+ cimport stdlib
+ cdef bytes py_string
+ cdef char* c_string = c_call_returning_a_c_string()
+ try:
+ py_string = c_string
+ finally:
+ stdlib.free(c_string)
+
+To convert the byte string back into a C ``char*``, use the opposite
+assignment::
+
+ cdef char* other_c_string = py_string
+
+This is a very fast operation after which ``other_c_string`` points to
+the byte string buffer of the Python string itself. It is tied to the
+life time of the Python string. When the Python string is garbage
+collected, the pointer becomes invalid. It is therefore important to
+keep a reference to the Python string as long as the ``char*`` is in
+use. Often enough, this only spans the call to a C function that
+receives the pointer as parameter. Special care must be taken,
+however, when the C function stores the pointer for later use. Apart
+from keeping a Python reference to the string, no manual memory
+management is required.
+
+Decoding bytes to text
+----------------------
+
+The initially presented way of passing and receiving C strings is
+sufficient if your code only deals with binary data in the strings.
+When we deal with encoded text, however, it is best practice to decode
+the C byte strings to Python Unicode strings on reception, and to
+encode Python Unicode strings to C byte strings on the way out.
+
+With a Python byte string object, you would normally just call the
+``.decode()`` method to decode it into a Unicode string::
+
+ ustring = byte_string.decode('UTF-8')
+
+Cython allows you to do the same for a C string, as long as it
+contains no null bytes::
+
+ cdef char* some_c_string = c_call_returning_a_c_string()
+ ustring = some_c_string.decode('UTF-8')
+
+However, this will not work for strings that contain null bytes, and
+it is very inefficient for long strings, since Cython has to call
+``strlen()`` on the C string first to find out the length by counting
+the bytes up to the terminating null byte. In many cases, the user
+code will know the length already, e.g. because a C function returned
+it. In this case, it is much more efficient to tell Cython the exact
+number of bytes by slicing the C string::
+
+ cdef char* c_string = NULL
+ cdef Py_ssize_t length = 0
+
+ # get pointer and length from a C function
+ get_a_c_string(&c_string, &length)
+
+ ustring = c_string[:length].decode('UTF-8')
+
+The same can be used when the string contains null bytes, e.g. when it
+uses an encoding like UCS-4, where each character is encoded in four
+bytes.
+
+It is common practice to wrap string conversions (and non-trivial type
+conversions in general) in dedicated functions, as this needs to be
+done in exactly the same way whenever receiving text from C. This
+could look as follows::
+
+ cimport python_unicode
+ cimport stdlib
+
+ cdef unicode tounicode(char* s):
+ return s.decode('UTF-8', 'strict')
+
+ cdef unicode tounicode_with_length(
+ char* s, size_t length):
+ return s[:length].decode('UTF-8', 'strict')
+
+ cdef unicode tounicode_with_length_and_free(
+ char* s, size_t length):
+ try:
+ return s[:length].decode('UTF-8', 'strict')
+ finally:
+ stdlib.free(s)
+
+Most likely, you will prefer shorter function names in your code based
+on the kind of string being handled. Different types of content often
+imply different ways of handling them on reception. To make the code
+more readable and to anticipate future changes, it is good practice to
+use separate conversion functions for different types of strings.
+
+Encoding text to bytes
+----------------------
+
+The reverse way, converting a Python unicode string to a C ``char*``,
+is pretty efficient by itself, assuming that what you actually want is
+a memory managed byte string::
+
+ py_byte_string = py_unicode_string.encode('UTF-8')
+ cdef char* c_string = py_byte_string
+
+As noted before, this takes the pointer to the byte buffer of the
+Python byte string. Trying to do the same without keeping a reference
+to the Python byte string will fail with a compile error::
+
+ # this will not compile !
+ cdef char* c_string = py_unicode_string.encode('UTF-8')
+
+Here, the Cython compiler notices that the code takes a pointer to a
+temporary string result that will be garbage collected after the
+assignment. Later access to the invalidated pointer will read invalid
+memory and likely result in a segfault. Cython will therefore refuse
+to compile this code.
+
+Source code encoding
+--------------------
+
+When string literals appear in the code, the source code encoding is
+important. It determines the byte sequence that Cython will store in
+the C code for bytes literals, and the Unicode code points that Cython
+builds for unicode literals when parsing the byte encoded source file.
+Following `PEP 263`_, Cython supports the explicit declaration of
+source file encodings. For example, putting the following comment at
+the top of an ``ISO-8859-15`` (Latin-9) encoded source file (into the
+first or second line) is required to enable ``ISO-8859-15`` decoding
+in the parser::
+
+ # -*- coding: ISO-8859-15 -*-
+
+When no explicit encoding declaration is provided, the source code is
+parsed as UTF-8 encoded text, as specified by `PEP 3120`_. `UTF-8`_
+is a very common encoding that can represent the entire Unicode set of
+characters and is compatible with plain ASCII encoded text that it
+encodes efficiently. This makes it a very good choice for source code
+files which usually consist mostly of ASCII characters.
+
+.. _`PEP 263`: http://www.python.org/dev/peps/pep-0263/
+.. _`PEP 3120`: http://www.python.org/dev/peps/pep-3120/
+.. _`UTF-8`: http://en.wikipedia.org/wiki/UTF-8
+
+As an example, putting the following line into a UTF-8 encoded source
+file will print ``5``, as UTF-8 encodes the letter ``'ö'`` in the two
+byte sequence ``'\xc3\xb6'``::
+
+ print( len(b'abcö') )
+
+whereas the following ``ISO-8859-15`` encoded source file will print
+``4``, as the encoding uses only 1 byte for this letter::
+
+ # -*- coding: ISO-8859-15 -*-
+ print( len(b'abcö') )
+
+Note that the unicode literal ``u'abcö'`` is a correctly decoded four
+character Unicode string in both cases, whereas the unprefixed Python
+``str`` literal ``'abcö'`` will become a byte string in Python 2 (thus
+having length 4 or 5 in the examples above), and a 4 character Unicode
+string in Python 3. If you are not familiar with encodings, this may
+not appear obvious at first read. See `CEP 108`_ for details.
+
+As a rule of thumb, it is best to avoid unprefixed non-ASCII ``str``
+literals and to use unicode string literals for all text. Cython also
+supports the ``__future__`` import ``unicode_literals`` that instructs
+the parser to read all unprefixed ``str`` literals in a source file as
+unicode string literals, just like Python 3.
+
+.. _`CEP 108`: http://wiki.cython.org/enhancements/stringliterals
+
+Single bytes and characters
+---------------------------
+
+The Python C-API uses the normal C ``char`` type to represent a byte
+value, but it has two special integer types for a Unicode code point
+value, i.e. a single Unicode character: ``Py_UNICODE`` and
+``Py_UCS4``. Since version 0.13, Cython supports the first natively,
+support for ``Py_UCS4`` is new in Cython 0.15. ``Py_UNICODE`` is
+either defined as an unsigned 2-byte or 4-byte integer, or as
+``wchar_t``, depending on the platform. The exact type is a compile
+time option in the build of the CPython interpreter and extension
+modules inherit this definition at C compile time. The advantage of
+``Py_UCS4`` is that it is guaranteed to be large enough for any
+Unicode code point value, regardless of the platform. It is defined
+as a 32bit unsigned int or long.
+
+In Cython, the ``char`` type behaves differently from the
+``Py_UNICODE`` and ``Py_UCS4`` types when coercing to Python objects.
+Similar to the behaviour of the bytes type in Python 3, the ``char``
+type coerces to a Python integer value by default, so that the
+following prints 65 and not ``A``::
+
+ # -*- coding: ASCII -*-
+
+ cdef char char_val = 'A'
+ assert char_val == 65 # ASCII encoded byte value of 'A'
+ print( char_val )
+
+If you want a Python bytes string instead, you have to request it
+explicitly, and the following will print ``A`` (or ``b'A'`` in Python
+3)::
+
+ print( <bytes>char_val )
+
+The explicit coercion works for any C integer type. Values outside of
+the range of a ``char`` or ``unsigned char`` will raise an
+``OverflowError`` at runtime. Coercion will also happen automatically
+when assigning to a typed variable, e.g.::
+
+ cdef bytes py_byte_string
+ py_byte_string = char_val
+
+On the other hand, the ``Py_UNICODE`` and ``Py_UCS4`` types are rarely
+used outside of the context of a Python unicode string, so their
+default behaviour is to coerce to a Python unicode object. The
+following will therefore print the character ``A``, as would the same
+code with the ``Py_UNICODE`` type::
+
+ cdef Py_UCS4 uchar_val = u'A'
+ assert uchar_val == 65 # character point value of u'A'
+ print( uchar_val )
+
+Again, explicit casting will allow users to override this behaviour.
+The following will print 65::
+
+ cdef Py_UCS4 uchar_val = u'A'
+ print( <long>uchar_val )
+
+Note that casting to a C ``long`` (or ``unsigned long``) will work
+just fine, as the maximum code point value that a Unicode character
+can have is 1114111 (``0x10FFFF``). On platforms with 32bit or more,
+``int`` is just as good.
+
+
+Narrow Unicode builds
+----------------------
+
+In narrow Unicode builds of CPython, i.e. builds where
+``sys.maxunicode`` is 65535 (such as all Windows builds, as opposed to
+1114111 in wide builds), it is still possible to use Unicode character
+code points that do not fit into the 16 bit wide ``Py_UNICODE`` type.
+For example, such a CPython build will accept the unicode literal
+``u'\U00012345'``. However, the underlying system level encoding
+leaks into Python space in this case, so that the length of this
+literal becomes 2 instead of 1. This also shows when iterating over
+it or when indexing into it. The visible substrings are ``u'\uD808'``
+and ``u'\uDF45'`` in this example. They form a so-called surrogate
+pair that represents the above character.
+
+For more information on this topic, it is worth reading the `Wikipedia
+article about the UTF-16 encoding`_.
+
+.. _`Wikipedia article about the UTF-16 encoding`: http://en.wikipedia.org/wiki/UTF-16/UCS-2
+
+The same properties apply to Cython code that gets compiled for a
+narrow CPython runtime environment. In most cases, e.g. when
+searching for a substring, this difference can be ignored as both the
+text and the substring will contain the surrogates. So most Unicode
+processing code will work correctly also on narrow builds. Encoding,
+decoding and printing will work as expected, so that the above literal
+turns into exactly the same byte sequence on both narrow and wide
+Unicode platforms.
+
+However, programmers should be aware that a single ``Py_UNICODE``
+value (or single 'character' unicode string in CPython) may not be
+enough to represent a complete Unicode character on narrow platforms.
+For example, if an independent search for ``u'\uD808'`` and
+``u'\uDF45'`` in a unicode string succeeds, this does not necessarily
+mean that the character ``u'\U00012345`` is part of that string. It
+may well be that two different characters are in the string that just
+happen to share a code unit with the surrogate pair of the character
+in question. Looking for substrings works correctly because the two
+code units in the surrogate pair use distinct value ranges, so the
+pair is always identifiable in a sequence of code points.
+
+As of version 0.15, Cython has extended support for surrogate pairs so
+that you can safely use an ``in`` test to search character values from
+the full ``Py_UCS4`` range even on narrow platforms::
+
+ cdef Py_UCS4 uchar = 0x12345
+ print( uchar in some_unicode_string )
+
+Similarly, it can coerce a one character string with a high Unicode
+code point value to a Py_UCS4 value on both narrow and wide Unicode
+platforms::
+
+ cdef Py_UCS4 uchar = u'\U00012345'
+ assert uchar == 0x12345
+
+
+Iteration
+---------
+
+Cython 0.13 supports efficient iteration over ``char*``, bytes and
+unicode strings, as long as the loop variable is appropriately typed.
+So the following will generate the expected C code::
+
+ cdef char* c_string = ...
+
+ cdef char c
+ for c in c_string[:100]:
+ if c == 'A': ...
+
+The same applies to bytes objects::
+
+ cdef bytes bytes_string = ...
+
+ cdef char c
+ for c in bytes_string:
+ if c == 'A': ...
+
+For unicode objects, Cython will automatically infer the type of the
+loop variable as ``Py_UCS4``::
+
+ cdef unicode ustring = ...
+
+ # NOTE: no typing required for 'uchar' !
+ for uchar in ustring:
+ if uchar == u'A': ...
+
+The automatic type inference usually leads to much more efficient code
+here. However, note that some unicode operations still require the
+value to be a Python object, so Cython may end up generating redundant
+conversion code for the loop variable value inside of the loop. If
+this leads to a performance degradation for a specific piece of code,
+you can either type the loop variable as a Python object explicitly,
+or assign its value to a Python typed variable somewhere inside of the
+loop to enforce one-time coercion before running Python operations on
+it.
+
+There are also optimisations for ``in`` tests, so that the following
+code will run in plain C code, (actually using a switch statement)::
+
+ cdef Py_UCS4 uchar_val = get_a_unicode_character()
+ if uchar_val in u'abcABCxY':
+ ...
+
+Combined with the looping optimisation above, this can result in very
+efficient character switching code, e.g. in unicode parsers.
--- /dev/null
+.. highlight:: cython
+
+.. _debugging:
+
+**********************************
+Debugging your Cython program
+**********************************
+
+Cython comes with an extension for the GNU Debugger that helps users debug
+Cython code. To use this functionality, you will need to install gdb 7.2 or
+higher, built with Python support (linked to Python 2.5 or higher).
+The debugger supports debuggees with versions 2.6 and higher. For Python 3,
+code should be built with Python 3 and the debugger should be run with
+Python 2 (or at least it should be able to find the Python 2 Cython
+installation).
+
+The debugger will need debug information that the Cython compiler can export.
+This can be achieved from within the setup
+script by passing ``pyrex_gdb=True`` to your Cython Extenion class::
+
+ from Cython.Distutils import extension
+
+ ext = extension.Extension('source', 'source.pyx', pyrex_gdb=True)
+ setup(..., ext_modules=[ext)]
+
+With this approach debug information can be enabled on a per-module basis.
+Another (easier) way is to simply pass the ``--pyrex-gdb`` flag as a command
+line argument::
+
+ python setup.py build_ext --pyrex-gdb
+
+For development it's often easy to use the ``--inplace`` flag also, which makes
+distutils build your project "in place", i.e., not in a separate `build`
+directory.
+
+When invoking Cython from the command line directly you can have it write
+debug information using the ``--gdb`` flag::
+
+ cython --gdb myfile.pyx
+
+.. note:: The debugger is newly part of Cython 0.14 and as such is still
+ experimental. CC markflorisson88@gmail.com in your TRAC tickets or
+ mailing list complaints.
+
+Running the Debugger
+=====================
+.. highlight:: bash
+
+To run the Cython debugger and have it import the debug information exported
+by Cython, run ``cygdb`` in the build directory::
+
+ $ python setup.py build_ext --pyrex-gdb --inplace
+ $ cygdb
+ GNU gdb (GDB) 7.2
+ ...
+ (gdb)
+
+When using the Cython debugger, it's preferable that you build and run your code
+with an interpreter that is compiled with debugging symbols (i.e. configured
+with ``--with-pydebug`` or compiled with the ``-g`` CFLAG). If your Python is
+installed and managed by your package manager you probably need to install debug
+support separately, e.g. for ubuntu::
+
+ $ sudo apt-get install python-dbg
+ $ python-dbg setup.py build_ext --pyrex-gdb --inplace
+
+Then you need to run your script with ``python-dbg`` also.
+
+You can also pass additional arguments to gdb::
+
+ $ cygdb /path/to/build/directory/ GDBARGS
+
+i.e.::
+
+ $ cygdb . --args python-dbg mainscript.py
+
+To tell cygdb not to import any debug information, supply ``--`` as the first
+argument::
+
+ $ cygdb --
+
+
+Using the Debugger
+===================
+The Cython debugger comes with a set of commands that support breakpoints,
+stack inspection, source code listing, stepping, stepping over, etc. Most
+of these commands are analogous to their respective gdb command.
+
+.. function:: cy break breakpoints...
+
+ Break in a Python, Cython or C function. First it will look for a Cython
+ function with that name, if cygdb doesn't know about a function (or method)
+ with that name, it will set a (pending) C breakpoint. The ``-p`` option can
+ be used to specify a Python breakpoint.
+
+ Breakpoints can be set for either the function or method name, or they can
+ be fully "qualified", which means that the entire "path" to a function is
+ given::
+
+ (gdb) cy break cython_function_or_method
+ (gdb) cy break packagename.modulename.cythonfunction
+ (gdb) cy break packagename.modulename.ClassName.cythonmethod
+ (gdb) cy break c_function
+
+ You can also break on Cython line numbers::
+
+ (gdb) cy break packagename.modulename:14
+ (gdb) cy break :14
+
+ Python breakpoints currently support names of the module (not the entire
+ package path) and the function or method::
+
+ (gdb) cy break -p pythonmodule.python_function_or_method
+ (gdb) cy break -p python_function_or_method
+
+.. note:: Python breakpoints only work in Python builds where the Python frame
+ information can be read from the debugger. To ensure this, use a
+ Python debug build or a non-stripped build compiled with debug
+ support.
+
+.. function:: cy step
+
+ Step through Python, Cython or C code. Python, Cython and C functions
+ called directly from Cython code are considered relevant and will be
+ stepped into.
+
+.. function:: cy next
+
+ Step over Python, Cython or C code.
+
+.. function:: cy run
+
+ Run the program. The default interpreter is the interpreter that was used
+ to build your extensions with, or the interpreter ``cygdb`` is run with
+ in case the "don't import debug information" option was in effect.
+ The interpreter can be overridden using gdb's ``file`` command.
+
+.. function:: cy cont
+
+ Continue the program.
+
+.. function:: cy up
+ cy down
+
+ Go up and down the stack to what is considered a relevant frame.
+
+.. function:: cy finish
+
+ Execute until an upward relevant frame is met or something halts
+ execution.
+
+.. function:: cy bt
+ cy backtrace
+
+ Print a traceback of all frames considered relevant. The ``-a`` option
+ makes it print the full traceback (all C frames).
+
+.. function:: cy select
+
+ Select a stack frame by number as listed by ``cy backtrace``. This
+ command is introduced because ``cy backtrace`` prints a reversed stack
+ trace, so frame numbers differ from gdb's ``bt``.
+
+.. function:: cy print varname
+
+ Print a local or global Cython, Python or C variable (depending on the
+ context). Variables may also be dereferenced::
+
+ (gdb) cy print x
+ x = 1
+ (gdb) cy print *x
+ *x = (PyObject) {
+ _ob_next = 0x93efd8,
+ _ob_prev = 0x93ef88,
+ ob_refcnt = 65,
+ ob_type = 0x83a3e0
+ }
+
+.. function:: cy set cython_variable = value
+
+ Set a Cython variable on the Cython stack to value.
+
+.. function:: cy list
+
+ List the source code surrounding the current line.
+
+.. function:: cy locals
+ cy globals
+
+ Print all the local and global variables and their values.
+
+.. function:: cy import FILE...
+
+ Import debug information from files given as arguments. The easiest way to
+ import debug information is to use the cygdb command line tool.
+
+.. function:: cy exec code
+
+ Execute code in the current Python or Cython frame. This works like
+ Python's interactive interpreter.
+
+ For Python frames it uses the globals and locals from the Python frame,
+ for Cython frames it uses the dict of globals used on the Cython module
+ and a new dict filled with the local Cython variables.
+
+.. note:: ``cy exec`` modifies state and executes code in the debuggee and is
+ therefore potentially dangerous.
+
+Example::
+
+ (gdb) cy exec x + 1
+ 2
+ (gdb) cy exec import sys; print sys.version_info
+ (2, 6, 5, 'final', 0)
+ (gdb) cy exec
+ >global foo
+ >
+ >foo = 'something'
+ >end
+
+Convenience functions
+=====================
+The following functions are gdb functions, which means they can be used in a
+gdb expression.
+
+.. function:: cy_cname(varname)
+
+ Returns the C variable name of a Cython variable. For global
+ variables this may not be actually valid.
+
+.. function:: cy_cvalue(varname)
+
+ Returns the value of a Cython variable.
+
+.. function:: cy_eval(expression)
+
+ Evaluates Python code in the nearest Python or Cython frame and returns
+ the result of the expression as a gdb value. This gives a new reference
+ if successful, NULL on error.
+
+.. function:: cy_lineno()
+
+ Returns the current line number in the selected Cython frame.
+
+Example::
+
+ (gdb) print $cy_cname("x")
+ $1 = "__pyx_v_x"
+ (gdb) watch $cy_cvalue("x")
+ Hardware watchpoint 13: $cy_cvalue("x")
+ (gdb) cy set my_cython_variable = $cy_eval("{'spam': 'ham'}")
+ (gdb) print $cy_lineno()
+ $2 = 12
+
+
+Configuring the Debugger
+========================
+A few aspects of the debugger are configurable with gdb parameters. For
+instance, colors can be disabled, the terminal background color
+and breakpoint autocompletion can be configured.
+
+.. c:macro:: cy_complete_unqualified
+
+ Tells the Cython debugger whether ``cy break`` should also complete
+ plain function names, i.e. not prefixed by their module name.
+ E.g. if you have a function named ``spam``,
+ in module ``M``, it tells whether to only complete ``M.spam`` or also just
+ ``spam``.
+
+ The default is true.
+
+.. c:macro:: cy_colorize_code
+
+ Tells the debugger whether to colorize source code. The default is true.
+
+.. c:macro:: cy_terminal_background_color
+
+ Tells the debugger about the terminal background color, which affects
+ source code coloring. The default is "dark", another valid option is
+ "light".
+
+This is how these parameters can be used::
+
+ (gdb) set cy_complete_unqualified off
+ (gdb) set cy_terminal_background_color light
+ (gdb) show cy_colorize_code
--- /dev/null
+.. highlight:: cython
+
+.. _early-binding-for-speed:
+
+**************************
+Early Binding for Speed
+**************************
+
+As a dynamic language, Python encourages a programming style of considering
+classes and objects in terms of their methods and attributes, more than where
+they fit into the class hierarchy.
+
+This can make Python a very relaxed and comfortable language for rapid
+development, but with a price - the 'red tape' of managing data types is
+dumped onto the interpreter. At run time, the interpreter does a lot of work
+searching namespaces, fetching attributes and parsing argument and keyword
+tuples. This run-time 'late binding' is a major cause of Python's relative
+slowness compared to 'early binding' languages such as C++.
+
+However with Cython it is possible to gain significant speed-ups through the
+use of 'early binding' programming techniques.
+
+For example, consider the following (silly) code example:
+
+.. sourcecode:: cython
+
+ cdef class Rectangle:
+ cdef int x0, y0
+ cdef int x1, y1
+ def __init__(self, int x0, int y0, int x1, int y1):
+ self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
+ def area(self):
+ area = (self.x1 - self.x0) * (self.y1 - self.y0)
+ if area < 0:
+ area = -area
+ return area
+
+ def rectArea(x0, y0, x1, y1):
+ rect = Rectangle(x0, y0, x1, y1)
+ return rect.area()
+
+In the :func:`rectArea` method, the call to :meth:`rect.area` and the
+:meth:`.area` method contain a lot of Python overhead.
+
+However, in Cython, it is possible to eliminate a lot of this overhead in cases
+where calls occur within Cython code. For example:
+
+.. sourcecode:: cython
+
+ cdef class Rectangle:
+ cdef int x0, y0
+ cdef int x1, y1
+ def __init__(self, int x0, int y0, int x1, int y1):
+ self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
+ cdef int _area(self):
+ cdef int area
+ area = (self.x1 - self.x0) * (self.y1 - self.y0)
+ if area < 0:
+ area = -area
+ return area
+ def area(self):
+ return self._area()
+
+ def rectArea(x0, y0, x1, y1):
+ cdef Rectangle rect
+ rect = Rectangle(x0, y0, x1, y1)
+ return rect._area()
+
+Here, in the Rectangle extension class, we have defined two different area
+calculation methods, the efficient :meth:`_area` C method, and the
+Python-callable :meth:`area` method which serves as a thin wrapper around
+:meth:`_area`. Note also in the function :func:`rectArea` how we 'early bind'
+by declaring the local variable ``rect`` which is explicitly given the type
+Rectangle. By using this declaration, instead of just dynamically assigning to
+``rect``, we gain the ability to access the much more efficient C-callable
+:meth:`_rect` method.
+
+But Cython offers us more simplicity again, by allowing us to declare
+dual-access methods - methods that can be efficiently called at C level, but
+can also be accessed from pure Python code at the cost of the Python access
+overheads. Consider this code:
+
+.. sourcecode:: cython
+
+ cdef class Rectangle:
+ cdef int x0, y0
+ cdef int x1, y1
+ def __init__(self, int x0, int y0, int x1, int y1):
+ self.x0 = x0; self.y0 = y0; self.x1 = x1; self.y1 = y1
+ cpdef int area(self):
+ cdef int area
+ area = (self.x1 - self.x0) * (self.y1 - self.y0)
+ if area < 0:
+ area = -area
+ return area
+
+ def rectArea(x0, y0, x1, y1):
+ cdef Rectangle rect
+ rect = Rectangle(x0, y0, x1, y1)
+ return rect.area()
+
+.. note::
+
+ in earlier versions of Cython, the :keyword:`cpdef` keyword is
+ :keyword:`rdef` - but has the same effect).
+
+Here, we just have a single area method, declared as :keyword:`cpdef` to make it
+efficiently callable as a C function, but still accessible from pure Python
+(or late-binding Cython) code.
+
+If within Cython code, we have a variable already 'early-bound' (ie, declared
+explicitly as type Rectangle, (or cast to type Rectangle), then invoking its
+area method will use the efficient C code path and skip the Python overhead.
+But if in Pyrex or regular Python code we have a regular object variable
+storing a Rectangle object, then invoking the area method will require:
+
+* an attribute lookup for the area method
+* packing a tuple for arguments and a dict for keywords (both empty in this case)
+* using the Python API to call the method
+
+and within the area method itself:
+
+* parsing the tuple and keywords
+* executing the calculation code
+* converting the result to a python object and returning it
+
+So within Cython, it is possible to achieve massive optimisations by
+using strong typing in declaration and casting of variables. For tight loops
+which use method calls, and where these methods are pure C, the difference can
+be huge.
+
--- /dev/null
+.. highlight:: cython
+
+.. _extension-types:
+
+******************
+Extension Types
+******************
+
+Introduction
+==============
+
+As well as creating normal user-defined classes with the Python class
+statement, Cython also lets you create new built-in Python types, known as
+extension types. You define an extension type using the :keyword:`cdef` class
+statement. Here's an example::
+
+ cdef class Shrubbery:
+
+ cdef int width, height
+
+ def __init__(self, w, h):
+ self.width = w
+ self.height = h
+
+ def describe(self):
+ print "This shrubbery is", self.width, \
+ "by", self.height, "cubits."
+
+As you can see, a Cython extension type definition looks a lot like a Python
+class definition. Within it, you use the def statement to define methods that
+can be called from Python code. You can even define many of the special
+methods such as :meth:`__init__` as you would in Python.
+
+The main difference is that you can use the :keyword:`cdef` statement to define
+attributes. The attributes may be Python objects (either generic or of a
+particular extension type), or they may be of any C data type. So you can use
+extension types to wrap arbitrary C data structures and provide a Python-like
+interface to them.
+
+Attributes
+============
+
+Attributes of an extension type are stored directly in the object's C struct.
+The set of attributes is fixed at compile time; you can't add attributes to an
+extension type instance at run time simply by assigning to them, as you could
+with a Python class instance. (You can subclass the extension type in Python
+and add attributes to instances of the subclass, however.)
+
+There are two ways that attributes of an extension type can be accessed: by
+Python attribute lookup, or by direct access to the C struct from Cython code.
+Python code is only able to access attributes of an extension type by the
+first method, but Cython code can use either method.
+
+By default, extension type attributes are only accessible by direct access,
+not Python access, which means that they are not accessible from Python code.
+To make them accessible from Python code, you need to declare them as
+:keyword:`public` or :keyword:`readonly`. For example,::
+
+ cdef class Shrubbery:
+ cdef public int width, height
+ cdef readonly float depth
+
+makes the width and height attributes readable and writable from Python code,
+and the depth attribute readable but not writable.
+
+.. note::
+
+ You can only expose simple C types, such as ints, floats, and
+ strings, for Python access. You can also expose Python-valued attributes.
+
+.. note::
+
+ Also the :keyword:`public` and :keyword:`readonly` options apply only to
+ Python access, not direct access. All the attributes of an extension type
+ are always readable and writable by C-level access.
+
+Type declarations
+===================
+
+Before you can directly access the attributes of an extension type, the Cython
+compiler must know that you have an instance of that type, and not just a
+generic Python object. It knows this already in the case of the ``self``
+parameter of the methods of that type, but in other cases you will have to use
+a type declaration.
+
+For example, in the following function,::
+
+ cdef widen_shrubbery(sh, extra_width): # BAD
+ sh.width = sh.width + extra_width
+
+because the ``sh`` parameter hasn't been given a type, the width attribute
+will be accessed by a Python attribute lookup. If the attribute has been
+declared :keyword:`public` or :keyword:`readonly` then this will work, but it
+will be very inefficient. If the attribute is private, it will not work at all
+-- the code will compile, but an attribute error will be raised at run time.
+
+The solution is to declare ``sh`` as being of type :class:`Shrubbery`, as
+follows::
+
+ cdef widen_shrubbery(Shrubbery sh, extra_width):
+ sh.width = sh.width + extra_width
+
+Now the Cython compiler knows that ``sh`` has a C attribute called
+:attr:`width` and will generate code to access it directly and efficiently.
+The same consideration applies to local variables, for example,::
+
+ cdef Shrubbery another_shrubbery(Shrubbery sh1):
+ cdef Shrubbery sh2
+ sh2 = Shrubbery()
+ sh2.width = sh1.width
+ sh2.height = sh1.height
+ return sh2
+
+
+Type Testing and Casting
+------------------------
+
+Suppose I have a method :meth:`quest` which returns an object of type :class:`Shrubbery`.
+To access it's width I could write::
+
+ cdef Shrubbery sh = quest()
+ print sh.width
+
+which requires the use of a local variable and performs a type test on assignment.
+If you *know* the return value of :meth:`quest` will be of type :class:`Shrubbery`
+you can use a cast to write::
+
+ print (<Shrubbery>quest()).width
+
+This may be dangerous if :meth:`quest()` is not actually a :class:`Shrubbery`, as it
+will try to access width as a C struct member which may not exist. At the C level,
+rather than raising an :class:`AttributeError`, either an nonsensical result will be
+returned (interpreting whatever data is at at that address as an int) or a segfault
+may result from trying to access invalid memory. Instead, one can write::
+
+ print (<Shrubbery?>quest()).width
+
+which performs a type check (possibly raising a :class:`TypeError`) before making the
+cast and allowing the code to proceed.
+
+To explicitly test the type of an object, use the :meth:`isinstance` method. By default,
+in Python, the :meth:`isinstance` method checks the :class:`__class__` attribute of the
+first argument to determine if it is of the required type. However, this is potentially
+unsafe as the :class:`__class__` attribute can be spoofed or changed, but the C structure
+of an extension type must be correct to access its :keyword:`cdef` attributes and call its :keyword:`cdef` methods. Cython detects if the second argument is a known extension
+type and does a type check instead, analogous to Pyrex's :meth:`typecheck`.
+The old behavior is always available by passing a tuple as the second parameter::
+
+ print isinstance(sh, Shrubbery) # Check the type of sh
+ print isinstance(sh, (Shrubbery,)) # Check sh.__class__
+
+
+Extension types and None
+=========================
+
+When you declare a parameter or C variable as being of an extension type,
+Cython will allow it to take on the value ``None`` as well as values of its
+declared type. This is analogous to the way a C pointer can take on the value
+``NULL``, and you need to exercise the same caution because of it. There is no
+problem as long as you are performing Python operations on it, because full
+dynamic type checking will be applied. However, when you access C attributes
+of an extension type (as in the widen_shrubbery function above), it's up to
+you to make sure the reference you're using is not ``None`` -- in the
+interests of efficiency, Cython does not check this.
+
+You need to be particularly careful when exposing Python functions which take
+extension types as arguments. If we wanted to make :func:`widen_shrubbery` a
+Python function, for example, if we simply wrote::
+
+ def widen_shrubbery(Shrubbery sh, extra_width): # This is
+ sh.width = sh.width + extra_width # dangerous!
+
+then users of our module could crash it by passing ``None`` for the ``sh``
+parameter.
+
+One way to fix this would be::
+
+ def widen_shrubbery(Shrubbery sh, extra_width):
+ if sh is None:
+ raise TypeError
+ sh.width = sh.width + extra_width
+
+but since this is anticipated to be such a frequent requirement, Cython
+provides a more convenient way. Parameters of a Python function declared as an
+extension type can have a ``not None`` clause::
+
+ def widen_shrubbery(Shrubbery sh not None, extra_width):
+ sh.width = sh.width + extra_width
+
+Now the function will automatically check that ``sh`` is ``not None`` along
+with checking that it has the right type.
+
+.. note::
+
+ ``not None`` clause can only be used in Python functions (defined with
+ :keyword:`def`) and not C functions (defined with :keyword:`cdef`). If
+ you need to check whether a parameter to a C function is None, you will
+ need to do it yourself.
+
+.. note::
+
+ Some more things:
+
+ * The self parameter of a method of an extension type is guaranteed never to
+ be ``None``.
+ * When comparing a value with ``None``, keep in mind that, if ``x`` is a Python
+ object, ``x is None`` and ``x is not None`` are very efficient because they
+ translate directly to C pointer comparisons, whereas ``x == None`` and
+ ``x != None``, or simply using ``x`` as a boolean value (as in ``if x: ...``)
+ will invoke Python operations and therefore be much slower.
+
+Special methods
+================
+
+Although the principles are similar, there are substantial differences between
+many of the :meth:`__xxx__` special methods of extension types and their Python
+counterparts. There is a :ref:`separate page <special-methods>` devoted to this subject, and you should
+read it carefully before attempting to use any special methods in your
+extension types.
+
+Properties
+============
+
+There is a special syntax for defining properties in an extension class::
+
+ cdef class Spam:
+
+ property cheese:
+
+ "A doc string can go here."
+
+ def __get__(self):
+ # This is called when the property is read.
+ ...
+
+ def __set__(self, value):
+ # This is called when the property is written.
+ ...
+
+ def __del__(self):
+ # This is called when the property is deleted.
+
+
+The :meth:`__get__`, :meth:`__set__` and :meth:`__del__` methods are all
+optional; if they are omitted, an exception will be raised when the
+corresponding operation is attempted.
+
+Here's a complete example. It defines a property which adds to a list each
+time it is written to, returns the list when it is read, and empties the list
+when it is deleted.::
+
+ # cheesy.pyx
+ cdef class CheeseShop:
+
+ cdef object cheeses
+
+ def __cinit__(self):
+ self.cheeses = []
+
+ property cheese:
+
+ def __get__(self):
+ return "We don't have: %s" % self.cheeses
+
+ def __set__(self, value):
+ self.cheeses.append(value)
+
+ def __del__(self):
+ del self.cheeses[:]
+
+ # Test input
+ from cheesy import CheeseShop
+
+ shop = CheeseShop()
+ print shop.cheese
+
+ shop.cheese = "camembert"
+ print shop.cheese
+
+ shop.cheese = "cheddar"
+ print shop.cheese
+
+ del shop.cheese
+ print shop.cheese
+
+.. sourcecode:: text
+
+ # Test output
+ We don't have: []
+ We don't have: ['camembert']
+ We don't have: ['camembert', 'cheddar']
+ We don't have: []
+
+Subclassing
+=============
+
+An extension type may inherit from a built-in type or another extension type::
+
+ cdef class Parrot:
+ ...
+
+ cdef class Norwegian(Parrot):
+ ...
+
+
+A complete definition of the base type must be available to Cython, so if the
+base type is a built-in type, it must have been previously declared as an
+extern extension type. If the base type is defined in another Cython module, it
+must either be declared as an extern extension type or imported using the
+:keyword:`cimport` statement.
+
+An extension type can only have one base class (no multiple inheritance).
+
+Cython extension types can also be subclassed in Python. A Python class can
+inherit from multiple extension types provided that the usual Python rules for
+multiple inheritance are followed (i.e. the C layouts of all the base classes
+must be compatible).
+
+Since Cython 0.13.1, there is a way to prevent extension types from
+being subtyped in Python. This is done via the ``final`` directive,
+usually set on an extension type using a decorator::
+
+ cimport cython
+
+ @cython.final
+ cdef class Parrot:
+ def done(self): pass
+
+Trying to create a Python subclass from this type will raise a
+:class:`TypeError` at runtime. Cython will also prevent subtyping a
+final type inside of the same module, i.e. creating an extension type
+that uses a final type as its base type will fail at compile time.
+Note, however, that this restriction does not currently propagate to
+other extension modules, so even final extension types can still be
+subtyped at the C level by foreign code.
+
+
+C methods
+=========
+Extension types can have C methods as well as Python methods. Like C
+functions, C methods are declared using :keyword:`cdef` or :keyword:`cpdef` instead of
+:keyword:`def`. C methods are "virtual", and may be overridden in derived
+extension types.::
+
+ # pets.pyx
+ cdef class Parrot:
+
+ cdef void describe(self):
+ print "This parrot is resting."
+
+ cdef class Norwegian(Parrot):
+
+ cdef void describe(self):
+ Parrot.describe(self)
+ print "Lovely plumage!"
+
+
+ cdef Parrot p1, p2
+ p1 = Parrot()
+ p2 = Norwegian()
+ print "p1:"
+ p1.describe()
+ print "p2:"
+ p2.describe()
+
+.. sourcecode:: text
+
+ # Output
+ p1:
+ This parrot is resting.
+ p2:
+ This parrot is resting.
+ Lovely plumage!
+
+The above example also illustrates that a C method can call an inherited C
+method using the usual Python technique, i.e.::
+
+ Parrot.describe(self)
+
+Forward-declaring extension types
+===================================
+
+Extension types can be forward-declared, like :keyword:`struct` and
+:keyword:`union` types. This will be necessary if you have two extension types
+that need to refer to each other, e.g.::
+
+ cdef class Shrubbery # forward declaration
+
+ cdef class Shrubber:
+ cdef Shrubbery work_in_progress
+
+ cdef class Shrubbery:
+ cdef Shrubber creator
+
+If you are forward-declaring an extension type that has a base class, you must
+specify the base class in both the forward declaration and its subsequent
+definition, for example,::
+
+ cdef class A(B)
+
+ ...
+
+ cdef class A(B):
+ # attributes and methods
+
+Making extension types weak-referenceable
+==========================================
+
+By default, extension types do not support having weak references made to
+them. You can enable weak referencing by declaring a C attribute of type
+object called :attr:`__weakref__`. For example,::
+
+ cdef class ExplodingAnimal:
+ """This animal will self-destruct when it is
+ no longer strongly referenced."""
+
+ cdef object __weakref__
+
+Public and external extension types
+====================================
+
+Extension types can be declared extern or public. An extern extension type
+declaration makes an extension type defined in external C code available to a
+Cython module. A public extension type declaration makes an extension type
+defined in a Cython module available to external C code.
+
+External extension types
+------------------------
+
+An extern extension type allows you to gain access to the internals of Python
+objects defined in the Python core or in a non-Cython extension module.
+
+.. note::
+
+ In previous versions of Pyrex, extern extension types were also used to
+ reference extension types defined in another Pyrex module. While you can still
+ do that, Cython provides a better mechanism for this. See
+ :ref:`sharing-declarations`.
+
+Here is an example which will let you get at the C-level members of the
+built-in complex object.::
+
+ cdef extern from "complexobject.h":
+
+ struct Py_complex:
+ double real
+ double imag
+
+ ctypedef class __builtin__.complex [object PyComplexObject]:
+ cdef Py_complex cval
+
+ # A function which uses the above type
+ def spam(complex c):
+ print "Real:", c.cval.real
+ print "Imag:", c.cval.imag
+
+.. note::
+
+ Some important things:
+
+ 1. In this example, :keyword:`ctypedef` class has been used. This is
+ because, in the Python header files, the ``PyComplexObject`` struct is
+ declared with:
+
+ .. sourcecode:: c
+
+ ctypedef struct {
+ ...
+ } PyComplexObject;
+
+ 2. As well as the name of the extension type, the module in which its type
+ object can be found is also specified. See the implicit importing section
+ below.
+
+ 3. When declaring an external extension type, you don't declare any
+ methods. Declaration of methods is not required in order to call them,
+ because the calls are Python method calls. Also, as with
+ :keyword:`structs` and :keyword:`unions`, if your extension class
+ declaration is inside a :keyword:`cdef` extern from block, you only need to
+ declare those C members which you wish to access.
+
+Name specification clause
+-------------------------
+
+The part of the class declaration in square brackets is a special feature only
+available for extern or public extension types. The full form of this clause
+is::
+
+ [object object_struct_name, type type_object_name ]
+
+where ``object_struct_name`` is the name to assume for the type's C struct,
+and type_object_name is the name to assume for the type's statically declared
+type object. (The object and type clauses can be written in either order.)
+
+If the extension type declaration is inside a :keyword:`cdef` extern from
+block, the object clause is required, because Cython must be able to generate
+code that is compatible with the declarations in the header file. Otherwise,
+for extern extension types, the object clause is optional.
+
+For public extension types, the object and type clauses are both required,
+because Cython must be able to generate code that is compatible with external C
+code.
+
+Implicit importing
+------------------
+
+Cython requires you to include a module name in an extern extension class
+declaration, for example,::
+
+ cdef extern class MyModule.Spam:
+ ...
+
+The type object will be implicitly imported from the specified module and
+bound to the corresponding name in this module. In other words, in this
+example an implicit::
+
+ from MyModule import Spam
+
+statement will be executed at module load time.
+
+The module name can be a dotted name to refer to a module inside a package
+hierarchy, for example,::
+
+ cdef extern class My.Nested.Package.Spam:
+ ...
+
+You can also specify an alternative name under which to import the type using
+an as clause, for example,::
+
+ cdef extern class My.Nested.Package.Spam as Yummy:
+ ...
+
+which corresponds to the implicit import statement::
+
+ from My.Nested.Package import Spam as Yummy
+
+Type names vs. constructor names
+--------------------------------
+
+Inside a Cython module, the name of an extension type serves two distinct
+purposes. When used in an expression, it refers to a module-level global
+variable holding the type's constructor (i.e. its type-object). However, it
+can also be used as a C type name to declare variables, arguments and return
+values of that type.
+
+When you declare::
+
+ cdef extern class MyModule.Spam:
+ ...
+
+the name Spam serves both these roles. There may be other names by which you
+can refer to the constructor, but only Spam can be used as a type name. For
+example, if you were to explicity import MyModule, you could use
+``MyModule.Spam()`` to create a Spam instance, but you wouldn't be able to use
+:class:`MyModule.Spam` as a type name.
+
+When an as clause is used, the name specified in the as clause also takes over
+both roles. So if you declare::
+
+ cdef extern class MyModule.Spam as Yummy:
+ ...
+
+then Yummy becomes both the type name and a name for the constructor. Again,
+there are other ways that you could get hold of the constructor, but only
+Yummy is usable as a type name.
+
+Public extension types
+======================
+
+An extension type can be declared public, in which case a ``.h`` file is
+generated containing declarations for its object struct and type object. By
+including the ``.h`` file in external C code that you write, that code can
+access the attributes of the extension type.
+
+
+
--- /dev/null
+.. highlight:: cython
+
+.. _external-C-code:
+
+**********************************
+Interfacing with External C Code
+**********************************
+
+One of the main uses of Cython is wrapping existing libraries of C code. This
+is achieved by using external declarations to declare the C functions and
+variables from the library that you want to use.
+
+You can also use public declarations to make C functions and variables defined
+in a Cython module available to external C code. The need for this is expected
+to be less frequent, but you might want to do it, for example, if you are
+`embedding Python`_ in another application as a scripting language. Just as a
+Cython module can be used as a bridge to allow Python code to call C code, it
+can also be used to allow C code to call Python code.
+
+.. _embedding Python: http://www.freenet.org.nz/python/embeddingpyrex/
+
+External declarations
+=======================
+
+By default, C functions and variables declared at the module level are local
+to the module (i.e. they have the C static storage class). They can also be
+declared extern to specify that they are defined elsewhere, for example::
+
+ cdef extern int spam_counter
+
+ cdef extern void order_spam(int tons)
+
+Referencing C header files
+---------------------------
+
+When you use an extern definition on its own as in the examples above, Cython
+includes a declaration for it in the generated C file. This can cause problems
+if the declaration doesn't exactly match the declaration that will be seen by
+other C code. If you're wrapping an existing C library, for example, it's
+important that the generated C code is compiled with exactly the same
+declarations as the rest of the library.
+
+To achieve this, you can tell Cython that the declarations are to be found in a
+C header file, like this::
+
+ cdef extern from "spam.h":
+
+ int spam_counter
+
+ void order_spam(int tons)
+
+The ``cdef extern`` from clause does three things:
+
+1. It directs Cython to place a ``#include`` statement for the named header file in
+ the generated C code.
+2. It prevents Cython from generating any C code
+ for the declarations found in the associated block.
+3. It treats all declarations within the block as though they started with
+ ``cdef extern``.
+
+It's important to understand that Cython does not itself read the C header
+file, so you still need to provide Cython versions of any declarations from it
+that you use. However, the Cython declarations don't always have to exactly
+match the C ones, and in some cases they shouldn't or can't. In particular:
+
+1. Don't use ``const``. Cython doesn't know anything about ``const``, so just
+ leave it out. Most of the time this shouldn't cause any problem, although
+ on rare occasions you might have to use a cast. You can also explicitly
+ declare something like::
+
+ ctypedef char* const_char_ptr "const char*"
+
+ though in most cases this will not be needed.
+
+ .. warning::
+
+ A problem with const could arise if you have something like::
+
+ cdef extern from "grail.h":
+ char *nun
+
+ where grail.h actually contains::
+
+ extern const char *nun;
+
+ and you do::
+
+ cdef void languissement(char *s):
+ #something that doesn't change s
+
+ ...
+
+ languissement(nun)
+
+ which will cause the C compiler to complain. You can work around it by
+ casting away the constness::
+
+ languissement(<char *>nun)
+
+2. Leave out any platform-specific extensions to C declarations such as
+ ``__declspec()``.
+
+3. If the header file declares a big struct and you only want to use a few
+ members, you only need to declare the members you're interested in. Leaving
+ the rest out doesn't do any harm, because the C compiler will use the full
+ definition from the header file.
+
+ In some cases, you might not need any of the struct's members, in which
+ case you can just put pass in the body of the struct declaration, e.g.::
+
+ cdef extern from "foo.h":
+ struct spam:
+ pass
+
+ .. note::
+
+ you can only do this inside a ``cdef extern from`` block; struct
+ declarations anywhere else must be non-empty.
+
+
+
+4. If the header file uses ``typedef`` names such as :ctype:`word` to refer
+ to platform-dependent flavours of numeric types, you will need a
+ corresponding :keyword:`ctypedef` statement, but you don't need to match
+ the type exactly, just use something of the right general kind (int, float,
+ etc). For example,::
+
+ ctypedef int word
+
+ will work okay whatever the actual size of a :ctype:`word ` is (provided the header
+ file defines it correctly). Conversion to and from Python types, if any, will also
+ be used for this new type.
+
+5. If the header file uses macros to define constants, translate them into a
+ dummy ``enum`` declaration.
+
+6. If the header file defines a function using a macro, declare it as though
+ it were an ordinary function, with appropriate argument and result types.
+
+7. For archaic reasons C uses the keyword :keyword:`void` to declare a function
+ taking no parameters. In Cython as in Python, simply declare such functions
+ as :meth:`foo()`.
+
+A few more tricks and tips:
+
+* If you want to include a C header because it's needed by another header, but
+ don't want to use any declarations from it, put pass in the extern-from
+ block::
+
+ cdef extern from "spam.h":
+ pass
+
+* If you want to include some external declarations, but don't want to specify
+ a header file (because it's included by some other header that you've
+ already included) you can put ``*`` in place of the header file name::
+
+ cdef extern from *:
+ ...
+
+Styles of struct, union and enum declaration
+----------------------------------------------
+
+There are two main ways that structs, unions and enums can be declared in C
+header files: using a tag name, or using a typedef. There are also some
+variations based on various combinations of these.
+
+It's important to make the Cython declarations match the style used in the
+header file, so that Cython can emit the right sort of references to the type
+in the code it generates. To make this possible, Cython provides two different
+syntaxes for declaring a struct, union or enum type. The style introduced
+above corresponds to the use of a tag name. To get the other style, you prefix
+the declaration with :keyword:`ctypedef`, as illustrated below.
+
+The following table shows the various possible styles that can be found in a
+header file, and the corresponding Cython declaration that you should put in
+the ``cdef extern`` from block. Struct declarations are used as an example; the
+same applies equally to union and enum declarations.
+
++-------------------------+---------------------------------------------+-----------------------------------------------------------------------+
+| C code | Possibilities for corresponding Cython Code | Comments |
++=========================+=============================================+=======================================================================+
+| .. sourcecode:: c | :: | Cython will refer to the as ``struct Foo`` in the generated C code. |
+| | | |
+| struct Foo { | cdef struct Foo: | |
+| ... | ... | |
+| }; | | |
++-------------------------+---------------------------------------------+-----------------------------------------------------------------------+
+| .. sourcecode:: c | :: | Cython will refer to the type simply as ``Foo`` in |
+| | | the generated C code. |
+| typedef struct { | ctypedef struct Foo: | |
+| ... | ... | |
+| } Foo; | | |
++-------------------------+---------------------------------------------+-----------------------------------------------------------------------+
+| .. sourcecode:: c | :: | If the C header uses both a tag and a typedef with *different* |
+| | | names, you can use either form of declaration in Cython |
+| typedef struct foo { | cdef struct foo: | (although if you need to forward reference the type, |
+| ... | ... | you'll have to use the first form). |
+| } Foo; | ctypedef foo Foo #optional | |
+| | | |
+| | or:: | |
+| | | |
+| | ctypedef struct Foo: | |
+| | ... | |
++-------------------------+---------------------------------------------+-----------------------------------------------------------------------+
+| .. sourcecode:: c | :: | If the header uses the *same* name for the tag and typedef, you |
+| | | won't be able to include a :keyword:`ctypedef` for it -- but then, |
+| typedef struct Foo { | cdef struct Foo: | it's not necessary. |
+| ... | ... | |
+| } Foo; | | |
++-------------------------+---------------------------------------------+-----------------------------------------------------------------------+
+
+Note that in all the cases below, you refer to the type in Cython code simply
+as :ctype:`Foo`, not ``struct Foo``.
+
+Accessing Python/C API routines
+---------------------------------
+
+One particular use of the ``cdef extern from`` statement is for gaining access to
+routines in the Python/C API. For example,::
+
+ cdef extern from "Python.h":
+
+ object PyString_FromStringAndSize(char *s, Py_ssize_t len)
+
+will allow you to create Python strings containing null bytes.
+
+Special Types
+--------------
+
+Cython predefines the name ``Py_ssize_t`` for use with Python/C API routines. To
+make your extensions compatible with 64-bit systems, you should always use
+this type where it is specified in the documentation of Python/C API routines.
+
+Windows Calling Conventions
+----------------------------
+
+The ``__stdcall`` and ``__cdecl`` calling convention specifiers can be used in
+Cython, with the same syntax as used by C compilers on Windows, for example,::
+
+ cdef extern int __stdcall FrobnicateWindow(long handle)
+
+ cdef void (__stdcall *callback)(void *)
+
+If ``__stdcall`` is used, the function is only considered compatible with
+other ``__stdcall`` functions of the same signature.
+
+Resolving naming conflicts - C name specifications
+----------------------------------------------------
+
+Each Cython module has a single module-level namespace for both Python and C
+names. This can be inconvenient if you want to wrap some external C functions
+and provide the Python user with Python functions of the same names.
+
+Cython provides a couple of different ways of solving this problem. The
+best way, especially if you have many C functions to wrap, is probably to put
+the extern C function declarations into a different namespace using the
+facilities described in the section on sharing declarations between Cython
+modules.
+
+The other way is to use a C name specification to give different Cython and C
+names to the C function. Suppose, for example, that you want to wrap an
+external function called :func:`eject_tomato`. If you declare it as::
+
+ cdef extern void c_eject_tomato "eject_tomato" (float speed)
+
+then its name inside the Cython module will be ``c_eject_tomato``, whereas its name
+in C will be ``eject_tomato``. You can then wrap it with::
+
+ def eject_tomato(speed):
+ c_eject_tomato(speed)
+
+so that users of your module can refer to it as ``eject_tomato``.
+
+Another use for this feature is referring to external names that happen to be
+Cython keywords. For example, if you want to call an external function called
+print, you can rename it to something else in your Cython module.
+
+As well as functions, C names can be specified for variables, structs, unions,
+enums, struct and union members, and enum values. For example,::
+
+ cdef extern int one "ein", two "zwei"
+ cdef extern float three "drei"
+
+ cdef struct spam "SPAM":
+ int i "eye"
+
+ cdef enum surprise "inquisition":
+ first "alpha"
+ second "beta" = 3
+
+Using Cython Declarations from C
+==================================
+
+Cython provides two methods for making C declarations from a Cython module
+available for use by external C code---public declarations and C API
+declarations.
+
+.. note::
+
+ You do not need to use either of these to make declarations from one
+ Cython module available to another Cython module – you should use the
+ :keyword:`cimport` statement for that. Sharing Declarations Between Cython Modules.
+
+Public Declarations
+---------------------
+
+You can make C types, variables and functions defined in a Cython module
+accessible to C code that is linked with the module, by declaring them with
+the public keyword::
+
+ cdef public struct Bunny: # public type declaration
+ int vorpalness
+
+ cdef public int spam # public variable declaration
+
+ cdef public void grail(Bunny *): # public function declaration
+ ...
+
+If there are any public declarations in a Cython module, a header file called
+:file:`modulename.h` file is generated containing equivalent C declarations for
+inclusion in other C code.
+
+Any C code wanting to make use of these declarations will need to be linked,
+either statically or dynamically, with the extension module.
+
+If the Cython module resides within a package, then the name of the ``.h``
+file consists of the full dotted name of the module, e.g. a module called
+:mod:`foo.spam` would have a header file called :file:`foo.spam.h`.
+
+C API Declarations
+-------------------
+
+The other way of making declarations available to C code is to declare them
+with the :keyword:`api` keyword. You can use this keyword with C functions and
+extension types. A header file called :file:`modulename_api.h` is produced
+containing declarations of the functions and extension types, and a function
+called :func:`import_modulename`.
+
+C code wanting to use these functions or extension types needs to include the
+header and call the :func:`import_modulename` function. The other functions
+can then be called and the extension types used as usual.
+
+Any public C type or extension type declarations in the Cython module are also
+made available when you include :file:`modulename_api.h`.::
+
+ # delorean.pyx
+ cdef public struct Vehicle:
+ int speed
+ float power
+
+ cdef api void activate(Vehicle *v):
+ if v.speed >= 88 and v.power >= 1.21:
+ print "Time travel achieved"
+
+.. sourcecode:: c
+
+ # marty.c
+ #include "delorean_api.h"
+
+ Vehicle car;
+
+ int main(int argc, char *argv[]) {
+ import_delorean();
+ car.speed = atoi(argv[1]);
+ car.power = atof(argv[2]);
+ activate(&car);
+ }
+
+.. note::
+
+ Any types defined in the Cython module that are used as argument or
+ return types of the exported functions will need to be declared public,
+ otherwise they won't be included in the generated header file, and you will
+ get errors when you try to compile a C file that uses the header.
+
+Using the :keyword:`api` method does not require the C code using the
+declarations to be linked with the extension module in any way, as the Python
+import machinery is used to make the connection dynamically. However, only
+functions can be accessed this way, not variables.
+
+You can use both :keyword:`public` and :keyword:`api` on the same function to
+make it available by both methods, e.g.::
+
+ cdef public api void belt_and_braces():
+ ...
+
+However, note that you should include either :file:`modulename.h` or
+:file:`modulename_api.h` in a given C file, not both, otherwise you may get
+conflicting dual definitions.
+
+If the Cython module resides within a package, then:
+
+* The name of the header file contains of the full dotted name of the module.
+* The name of the importing function contains the full name with dots replaced
+ by double underscores.
+
+E.g. a module called :mod:`foo.spam` would have an API header file called
+:file:`foo.spam_api.h` and an importing function called
+:func:`import_foo__spam`.
+
+Multiple public and API declarations
+--------------------------------------
+
+You can declare a whole group of items as :keyword:`public` and/or
+:keyword:`api` all at once by enclosing them in a :keyword:`cdef` block, for
+example,::
+
+ cdef public api:
+ void order_spam(int tons)
+ char *get_lunch(float tomato_size)
+
+This can be a useful thing to do in a ``.pxd`` file (see
+:ref:`sharing-declarations`) to make the module's public interface
+available by all three methods.
+
+Acquiring and Releasing the GIL
+---------------------------------
+
+Cython provides facilities for releasing the Global Interpreter Lock (GIL)
+before calling C code, and for acquiring the GIL in functions that are to be
+called back from C code that is executed without the GIL.
+
+Releasing the GIL
+^^^^^^^^^^^^^^^^^
+
+You can release the GIL around a section of code using the
+:keyword:`with nogil` statement::
+
+ with nogil:
+ <code to be executed with the GIL released>
+
+Code in the body of the statement must not manipulate Python objects in any
+way, and must not call anything that manipulates Python objects without first
+re-acquiring the GIL. Cython currently does not check this.
+
+Acquiring the GIL
+^^^^^^^^^^^^^^^^^
+
+A C function that is to be used as a callback from C code that is executed
+without the GIL needs to acquire the GIL before it can manipulate Python
+objects. This can be done by specifying with :keyword:`gil` in the function
+header::
+
+ cdef void my_callback(void *data) with gil:
+ ...
+
+Declaring a function as callable without the GIL
+--------------------------------------------------
+
+You can specify :keyword:`nogil` in a C function header or function type to
+declare that it is safe to call without the GIL.::
+
+ cdef void my_gil_free_func(int spam) nogil:
+ ...
+
+If you are implementing such a function in Cython, it cannot have any Python
+arguments, Python local variables, or Python return type, and cannot
+manipulate Python objects in any way or call any function that does so without
+acquiring the GIL first. Some of these restrictions are currently checked by
+Cython, but not all. It is possible that more stringent checking will be
+performed in the future.
+
+Declaring a function with :keyword:`gil` also implicitly makes its signature
+:keyword:`nogil`.
+
--- /dev/null
+Users Guide
+===========
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ overview
+ tutorial
+ language_basics
+ extension_types
+ special_methods
+ sharing_declarations
+ external_C_code
+ source_files_and_compilation
+ wrapping_CPlusPlus
+ limitations
+ pyrex_differences
+ early_binding_for_speed
+ debugging
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. toctree::
+
--- /dev/null
+.. highlight:: cython
+
+.. _language-basics:
+
+*****************
+Language Basics
+*****************
+
+C variable and type definitions
+===============================
+
+The :keyword:`cdef` statement is used to declare C variables, either local or
+module-level::
+
+ cdef int i, j, k
+ cdef float f, g[42], *h
+
+and C :keyword:`struct`, :keyword:`union` or :keyword:`enum` types::
+
+ cdef struct Grail:
+ int age
+ float volume
+
+ cdef union Food:
+ char *spam
+ float *eggs
+
+ cdef enum CheeseType:
+ cheddar, edam,
+ camembert
+
+ cdef enum CheeseState:
+ hard = 1
+ soft = 2
+ runny = 3
+
+There is currently no special syntax for defining a constant, but you can use
+an anonymous :keyword:`enum` declaration for this purpose, for example,::
+
+ cdef enum:
+ tons_of_spam = 3
+
+.. note::
+ the words ``struct``, ``union`` and ``enum`` are used only when
+ defining a type, not when referring to it. For example, to declare a variable
+ pointing to a ``Grail`` you would write::
+
+ cdef Grail *gp
+
+ and not::
+
+ cdef struct Grail *gp # WRONG
+
+ There is also a ``ctypedef`` statement for giving names to types, e.g.::
+
+ ctypedef unsigned long ULong
+
+ ctypedef int *IntPtr
+
+Grouping multiple C declarations
+--------------------------------
+
+If you have a series of declarations that all begin with :keyword:`cdef`, you
+can group them into a :keyword:`cdef` block like this::
+
+ cdef:
+ struct Spam:
+ int tons
+
+ int i
+ float f
+ Spam *p
+
+ void f(Spam *s):
+ print s.tons, "Tons of spam"
+
+
+Python functions vs. C functions
+==================================
+
+There are two kinds of function definition in Cython:
+
+Python functions are defined using the def statement, as in Python. They take
+Python objects as parameters and return Python objects.
+
+C functions are defined using the new :keyword:`cdef` statement. They take
+either Python objects or C values as parameters, and can return either Python
+objects or C values.
+
+Within a Cython module, Python functions and C functions can call each other
+freely, but only Python functions can be called from outside the module by
+interpreted Python code. So, any functions that you want to "export" from your
+Cython module must be declared as Python functions using def.
+There is also a hybrid function, called :keyword:`cpdef`. A :keyword:`cpdef`
+can be called from anywhere, but uses the faster C calling conventions
+when being called from other Cython code.
+
+Parameters of either type of function can be declared to have C data types,
+using normal C declaration syntax. For example,::
+
+ def spam(int i, char *s):
+ ...
+
+ cdef int eggs(unsigned long l, float f):
+ ...
+
+When a parameter of a Python function is declared to have a C data type, it is
+passed in as a Python object and automatically converted to a C value, if
+possible. Automatic conversion is currently only possible for numeric types
+and string types; attempting to use any other type for the parameter of a
+Python function will result in a compile-time error.
+
+C functions, on the other hand, can have parameters of any type, since they're
+passed in directly using a normal C function call.
+
+A more complete comparison of the pros and cons of these different method
+types can be found at :ref:`early-binding-for-speed`.
+
+Python objects as parameters and return values
+----------------------------------------------
+
+If no type is specified for a parameter or return value, it is assumed to be a
+Python object. (Note that this is different from the C convention, where it
+would default to int.) For example, the following defines a C function that
+takes two Python objects as parameters and returns a Python object::
+
+ cdef spamobjs(x, y):
+ ...
+
+Reference counting for these objects is performed automatically according to
+the standard Python/C API rules (i.e. borrowed references are taken as
+parameters and a new reference is returned).
+
+The name object can also be used to explicitly declare something as a Python
+object. This can be useful if the name being declared would otherwise be taken
+as the name of a type, for example,::
+
+ cdef ftang(object int):
+ ...
+
+declares a parameter called int which is a Python object. You can also use
+object as the explicit return type of a function, e.g.::
+
+ cdef object ftang(object int):
+ ...
+
+In the interests of clarity, it is probably a good idea to always be explicit
+about object parameters in C functions.
+
+
+Error return values
+-------------------
+
+If you don't do anything special, a function declared with :keyword:`cdef` that
+does not return a Python object has no way of reporting Python exceptions to
+its caller. If an exception is detected in such a function, a warning message
+is printed and the exception is ignored.
+
+If you want a C function that does not return a Python object to be able to
+propagate exceptions to its caller, you need to declare an exception value for
+it. Here is an example::
+
+ cdef int spam() except -1:
+ ...
+
+With this declaration, whenever an exception occurs inside spam, it will
+immediately return with the value ``-1``. Furthermore, whenever a call to spam
+returns ``-1``, an exception will be assumed to have occurred and will be
+propagated.
+
+When you declare an exception value for a function, you should never
+explicitly return that value. If all possible return values are legal and you
+can't reserve one entirely for signalling errors, you can use an alternative
+form of exception value declaration::
+
+ cdef int spam() except? -1:
+ ...
+
+The "?" indicates that the value ``-1`` only indicates a possible error. In this
+case, Cython generates a call to :cfunc:`PyErr_Occurred` if the exception value is
+returned, to make sure it really is an error.
+
+There is also a third form of exception value declaration::
+
+ cdef int spam() except *:
+ ...
+
+This form causes Cython to generate a call to :cfunc:`PyErr_Occurred` after
+every call to spam, regardless of what value it returns. If you have a
+function returning void that needs to propagate errors, you will have to use
+this form, since there isn't any return value to test.
+Otherwise there is little use for this form.
+
+An external C++ function that may raise an exception can be declared with::
+
+ cdef int spam() except +
+
+See :ref:`wrapping-cplusplus` for more details.
+
+Some things to note:
+
+* Exception values can only declared for functions returning an integer, enum,
+ float or pointer type, and the value must be a constant expression.
+ Void functions can only use the ``except *`` form.
+* The exception value specification is part of the signature of the function.
+ If you're passing a pointer to a function as a parameter or assigning it
+ to a variable, the declared type of the parameter or variable must have
+ the same exception value specification (or lack thereof). Here is an
+ example of a pointer-to-function declaration with an exception
+ value::
+
+ int (*grail)(int, char *) except -1
+
+* You don't need to (and shouldn't) declare exception values for functions
+ which return Python objects. Remember that a function with no declared
+ return type implicitly returns a Python object. (Exceptions on such functions
+ are implicitly propagated by returning NULL.)
+
+Checking return values of non-Cython functions
+----------------------------------------------
+
+It's important to understand that the except clause does not cause an error to
+be raised when the specified value is returned. For example, you can't write
+something like::
+
+ cdef extern FILE *fopen(char *filename, char *mode) except NULL # WRONG!
+
+and expect an exception to be automatically raised if a call to :func:`fopen`
+returns ``NULL``. The except clause doesn't work that way; its only purpose is
+for propagating Python exceptions that have already been raised, either by a Cython
+function or a C function that calls Python/C API routines. To get an exception
+from a non-Python-aware function such as :func:`fopen`, you will have to check the
+return value and raise it yourself, for example,::
+
+ cdef FILE *p
+ p = fopen("spam.txt", "r")
+ if p == NULL:
+ raise SpamError("Couldn't open the spam file")
+
+
+Automatic type conversions
+==========================
+
+In most situations, automatic conversions will be performed for the basic
+numeric and string types when a Python object is used in a context requiring a
+C value, or vice versa. The following table summarises the conversion
+possibilities.
+
++----------------------------+--------------------+------------------+
+| C types | From Python types | To Python types |
++============================+====================+==================+
+| [unsigned] char | int, long | int |
+| [unsigned] short | | |
+| int, long | | |
++----------------------------+--------------------+------------------+
+| unsigned int | int, long | long |
+| unsigned long | | |
+| [unsigned] long long | | |
++----------------------------+--------------------+------------------+
+| float, double, long double | int, long, float | float |
++----------------------------+--------------------+------------------+
+| char * | str/bytes | str/bytes [#]_ |
++----------------------------+--------------------+------------------+
+| struct | | dict |
++----------------------------+--------------------+------------------+
+
+.. [#] The conversion is to/from str for Python 2.x, and bytes for Python 3.x.
+
+Caveats when using a Python string in a C context
+-------------------------------------------------
+
+You need to be careful when using a Python string in a context expecting a
+``char *``. In this situation, a pointer to the contents of the Python string is
+used, which is only valid as long as the Python string exists. So you need to
+make sure that a reference to the original Python string is held for as long
+as the C string is needed. If you can't guarantee that the Python string will
+live long enough, you will need to copy the C string.
+
+Cython detects and prevents some mistakes of this kind. For instance, if you
+attempt something like::
+
+ cdef char *s
+ s = pystring1 + pystring2
+
+then Cython will produce the error message ``Obtaining char * from temporary
+Python value``. The reason is that concatenating the two Python strings
+produces a new Python string object that is referenced only by a temporary
+internal variable that Cython generates. As soon as the statement has finished,
+the temporary variable will be decrefed and the Python string deallocated,
+leaving ``s`` dangling. Since this code could not possibly work, Cython refuses to
+compile it.
+
+The solution is to assign the result of the concatenation to a Python
+variable, and then obtain the ``char *`` from that, i.e.::
+
+ cdef char *s
+ p = pystring1 + pystring2
+ s = p
+
+It is then your responsibility to hold the reference p for as long as
+necessary.
+
+Keep in mind that the rules used to detect such errors are only heuristics.
+Sometimes Cython will complain unnecessarily, and sometimes it will fail to
+detect a problem that exists. Ultimately, you need to understand the issue and
+be careful what you do.
+
+Statements and expressions
+==========================
+
+Control structures and expressions follow Python syntax for the most part.
+When applied to Python objects, they have the same semantics as in Python
+(unless otherwise noted). Most of the Python operators can also be applied to
+C values, with the obvious semantics.
+
+If Python objects and C values are mixed in an expression, conversions are
+performed automatically between Python objects and C numeric or string types.
+
+Reference counts are maintained automatically for all Python objects, and all
+Python operations are automatically checked for errors, with appropriate
+action taken.
+
+Differences between C and Cython expressions
+--------------------------------------------
+
+There are some differences in syntax and semantics between C expressions and
+Cython expressions, particularly in the area of C constructs which have no
+direct equivalent in Python.
+
+* An integer literal is treated as a C constant, and will
+ be truncated to whatever size your C compiler thinks appropriate.
+ To get a Python integer (of arbitrary precision) cast immediately to
+ an object (e.g. ``<object>100000000000000000000``). The ``L``, ``LL``,
+ and ``U`` suffixes have the same meaning as in C.
+* There is no ``->`` operator in Cython. Instead of ``p->x``, use ``p.x``
+* There is no unary ``*`` operator in Cython. Instead of ``*p``, use ``p[0]``
+* There is an ``&`` operator, with the same semantics as in C.
+* The null C pointer is called ``NULL``, not ``0`` (and ``NULL`` is a reserved word).
+* Type casts are written ``<type>value`` , for example::
+
+ cdef char *p, float *q
+ p = <char*>q
+
+Scope rules
+-----------
+
+Cython determines whether a variable belongs to a local scope, the module
+scope, or the built-in scope completely statically. As with Python, assigning
+to a variable which is not otherwise declared implicitly declares it to be a
+Python variable residing in the scope where it is assigned.
+
+.. note::
+ A consequence of these rules is that the module-level scope behaves the
+ same way as a Python local scope if you refer to a variable before assigning
+ to it. In particular, tricks such as the following will not work in Cython::
+
+ try:
+ x = True
+ except NameError:
+ True = 1
+
+ because, due to the assignment, the True will always be looked up in the
+ module-level scope. You would have to do something like this instead::
+
+ import __builtin__
+ try:
+ True = __builtin__.True
+ except AttributeError:
+ True = 1
+
+
+Built-in Functions
+------------------
+
+Cython compiles calls to the following built-in functions into direct calls to
+the corresponding Python/C API routines, making them particularly fast.
+
++------------------------------+-------------+----------------------------+
+| Function and arguments | Return type | Python/C API Equivalent |
++==============================+=============+============================+
+| abs(obj) | object | PyNumber_Absolute |
++------------------------------+-------------+----------------------------+
+| delattr(obj, name) | int | PyObject_DelAttr |
++------------------------------+-------------+----------------------------+
+| dir(obj) | object | PyObject_Dir |
+| getattr(obj, name) (Note 1) | | |
+| getattr3(obj, name, default) | | |
++------------------------------+-------------+----------------------------+
+| hasattr(obj, name) | int | PyObject_HasAttr |
++------------------------------+-------------+----------------------------+
+| hash(obj) | int | PyObject_Hash |
++------------------------------+-------------+----------------------------+
+| intern(obj) | object | PyObject_InternFromString |
++------------------------------+-------------+----------------------------+
+| isinstance(obj, type) | int | PyObject_IsInstance |
++------------------------------+-------------+----------------------------+
+| issubclass(obj, type) | int | PyObject_IsSubclass |
++------------------------------+-------------+----------------------------+
+| iter(obj) | object | PyObject_GetIter |
++------------------------------+-------------+----------------------------+
+| len(obj) | Py_ssize_t | PyObject_Length |
++------------------------------+-------------+----------------------------+
+| pow(x, y, z) (Note 2) | object | PyNumber_Power |
++------------------------------+-------------+----------------------------+
+| reload(obj) | object | PyImport_ReloadModule |
++------------------------------+-------------+----------------------------+
+| repr(obj) | object | PyObject_Repr |
++------------------------------+-------------+----------------------------+
+| setattr(obj, name) | void | PyObject_SetAttr |
++------------------------------+-------------+----------------------------+
+
+Note 1: There are two different functions corresponding to the Python
+:func:`getattr` depending on whether a third argument is used. In a Python
+context, they both evaluate to the Python :func:`getattr` function.
+
+Note 2: Only the three-argument form of :func:`pow` is supported. Use the
+``**`` operator otherwise.
+
+Only direct function calls using these names are optimised. If you do
+something else with one of these names that assumes it's a Python object, such
+as assign it to a Python variable, and later call it, the call will be made as
+a Python function call.
+
+
+Operator Precedence
+-------------------
+
+Keep in mind that there are some differences in operator precedence between
+Python and C, and that Cython uses the Python precedences, not the C ones.
+
+Integer for-loops
+------------------
+
+Cython recognises the usual Python for-in-range integer loop pattern::
+
+ for i in range(n):
+ ...
+
+If ``i`` is declared as a :keyword:`cdef` integer type, it will
+optimise this into a pure C loop. This restriction is required as
+otherwise the generated code wouldn't be correct due to potential
+integer overflows on the target architecture. If you are worried that
+the loop is not being converted correctly, use the annotate feature of
+the cython commandline (``-a``) to easily see the generated C code.
+See :ref:`automatic-range-conversion`
+
+For backwards compatibility to Pyrex, Cython also supports another
+form of for-loop::
+
+ for i from 0 <= i < n:
+ ...
+
+or::
+
+ for i from 0 <= i < n by s:
+ ...
+
+where ``s`` is some integer step size.
+
+Some things to note about the for-from loop:
+
+* The target expression must be a variable name.
+* The name between the lower and upper bounds must be the same as the target
+ name.
+* The direction of iteration is determined by the relations. If they are both
+ from the set {``<``, ``<=``} then it is upwards; if they are both from the set
+ {``>``, ``>=``} then it is downwards. (Any other combination is disallowed.)
+
+Like other Python looping statements, break and continue may be used in the
+body, and the loop may have an else clause.
+
+
+The include statement
+=====================
+
+.. warning::
+ Historically the ``include`` statement was used for sharing declarations.
+ Use :ref:`sharing-declarations` instead.
+
+A Cython source file can include material from other files using the include
+statement, for example::
+
+ include "spamstuff.pxi"
+
+The contents of the named file are textually included at that point. The
+included file can contain any complete statements or declarations that are
+valid in the context where the include statement appears, including other
+include statements. The contents of the included file should begin at an
+indentation level of zero, and will be treated as though they were indented to
+the level of the include statement that is including the file.
+
+.. note::
+
+ There are other mechanisms available for splitting Cython code into
+ separate parts that may be more appropriate in many cases. See
+ :ref:`sharing-declarations`.
+
+
+Conditional Compilation
+=======================
+
+Some features are available for conditional compilation and compile-time
+constants within a Cython source file.
+
+Compile-Time Definitions
+------------------------
+
+A compile-time constant can be defined using the DEF statement::
+
+ DEF FavouriteFood = "spam"
+ DEF ArraySize = 42
+ DEF OtherArraySize = 2 * ArraySize + 17
+
+The right-hand side of the ``DEF`` must be a valid compile-time expression.
+Such expressions are made up of literal values and names defined using ``DEF``
+statements, combined using any of the Python expression syntax.
+
+The following compile-time names are predefined, corresponding to the values
+returned by :func:`os.uname`.
+
+ UNAME_SYSNAME, UNAME_NODENAME, UNAME_RELEASE,
+ UNAME_VERSION, UNAME_MACHINE
+
+The following selection of builtin constants and functions are also available:
+
+ None, True, False,
+ abs, bool, chr, cmp, complex, dict, divmod, enumerate,
+ float, hash, hex, int, len, list, long, map, max, min,
+ oct, ord, pow, range, reduce, repr, round, slice, str,
+ sum, tuple, xrange, zip
+
+A name defined using ``DEF`` can be used anywhere an identifier can appear,
+and it is replaced with its compile-time value as though it were written into
+the source at that point as a literal. For this to work, the compile-time
+expression must evaluate to a Python value of type ``int``, ``long``,
+``float`` or ``str``.::
+
+ cdef int a1[ArraySize]
+ cdef int a2[OtherArraySize]
+ print "I like", FavouriteFood
+
+Conditional Statements
+----------------------
+
+The ``IF`` statement can be used to conditionally include or exclude sections
+of code at compile time. It works in a similar way to the ``#if`` preprocessor
+directive in C.::
+
+ IF UNAME_SYSNAME == "Windows":
+ include "icky_definitions.pxi"
+ ELIF UNAME_SYSNAME == "Darwin":
+ include "nice_definitions.pxi"
+ ELIF UNAME_SYSNAME == "Linux":
+ include "penguin_definitions.pxi"
+ ELSE:
+ include "other_definitions.pxi"
+
+The ``ELIF`` and ``ELSE`` clauses are optional. An ``IF`` statement can appear
+anywhere that a normal statement or declaration can appear, and it can contain
+any statements or declarations that would be valid in that context, including
+``DEF`` statements and other ``IF`` statements.
+
+The expressions in the ``IF`` and ``ELIF`` clauses must be valid compile-time
+expressions as for the ``DEF`` statement, although they can evaluate to any
+Python value, and the truth of the result is determined in the usual Python
+way.
+
--- /dev/null
+.. highlight:: cython
+
+.. _cython-limitations:
+
+*************
+Limitations
+*************
+
+Unsupported Python Features
+============================
+
+One of our goals is to make Cython as compatible as possible with standard
+Python. This page lists the things that work in Python but not in Cython.
+As Cython matures, the items in this list should go away.
+
+
+Generators and generator expressions
+-------------------------------------
+
+The yield keyword is not yet supported. This is work in progress.
+
+Since Cython 0.13, some generator expressions are supported when they
+can be transformed into inlined loops in combination with builtins,
+e.g. ``sum(x*2 for x in seq)``. As of 0.14, the supported builtins
+are ``list()``, ``set()``, ``dict()``, ``sum()``, ``any()``,
+``all()``, ``sorted()``.
+
+
+Other Current Limitations
+==========================
+
+* The :func:`globals` builtin returns the last Python callers globals, not the current function's locals. This behavior should not be relied upon, as it will probably change in the future.
+* The :func:`locals` builtin can only be used if all local variables can be converted to Python objects, and returns a dict.
+* Class and function definitions cannot be placed inside control structures.
+
+Semantic differences between Python and Cython
+----------------------------------------------
+
+Behaviour of class scopes
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In Python, referring to a method of a class inside the class definition, i.e.
+while the class is being defined, yields a plain function object, but in
+Cython it yields an unbound method [#]_. A consequence of this is that the
+usual idiom for using the :func:`classmethod` and :func:`staticmethod` functions,
+e.g.::
+
+ class Spam:
+
+ def method(cls):
+ ...
+
+ method = classmethod(method)
+
+will not work in Cython. This can be worked around by defining the function
+outside the class, and then assigning the result of ``classmethod`` or
+``staticmethod`` inside the class, i.e.::
+
+ def Spam_method(cls):
+ ...
+
+ class Spam:
+
+ method = classmethod(Spam_method)
+
+This will change in the near future.
+
+.. rubric:: Footnotes
+
+.. [#] The reason for the different behaviour of class scopes is that
+ Cython-defined Python functions are ``PyCFunction`` objects, not
+ ``PyFunction`` objects, and are not recognised by the machinery that creates a
+ bound or unbound method when a function is extracted from a class. To get
+ around this, Cython wraps each method in an unbound method object itself
+ before storing it in the class's dictionary.
--- /dev/null
+.. highlight:: cython
+
+.. _numpy_tutorial:
+
+**************************
+Cython for NumPy users
+**************************
+
+This tutorial is aimed at NumPy users who have no experience with Cython at
+all. If you have some knowledge of Cython you may want to skip to the
+''Efficient indexing'' section which explains the new improvements made in
+summer 2008.
+
+The main scenario considered is NumPy end-use rather than NumPy/SciPy
+development. The reason is that Cython is not (yet) able to support functions
+that are generic with respect to datatype and the number of dimensions in a
+high-level fashion. This restriction is much more severe for SciPy development
+than more specific, "end-user" functions. See the last section for more
+information on this.
+
+The style of this tutorial will not fit everybody, so you can also consider:
+
+* Robert Bradshaw's `slides on cython for SciPy2008
+ <http://wiki.sagemath.org/scipy08?action=AttachFile&do=get&target=scipy-cython.tgz>`_
+ (a higher-level and quicker introduction)
+* Basic Cython documentation (see `Cython front page <http://cython.org>`_).
+* ``[:enhancements/buffer:Spec for the efficient indexing]``
+
+.. Note::
+ The fast array access documented below is a completely new feature, and
+ there may be bugs waiting to be discovered. It might be a good idea to do
+ a manual sanity check on the C code Cython generates before using this for
+ serious purposes, at least until some months have passed.
+
+Cython at a glance
+====================
+
+Cython is a compiler which compiles Python-like code files to C code. Still,
+''Cython is not a Python to C translator''. That is, it doesn't take your full
+program and "turns it into C" -- rather, the result makes full use of the
+Python runtime environment. A way of looking at it may be that your code is
+still Python in that it runs within the Python runtime environment, but rather
+than compiling to interpreted Python bytecode one compiles to native machine
+code (but with the addition of extra syntax for easy embedding of faster
+C-like code).
+
+This has two important consequences:
+
+* Speed. How much depends very much on the program involved though. Typical Python numerical programs would tend to gain very little as most time is spent in lower-level C that is used in a high-level fashion. However for-loop-style programs can gain many orders of magnitude, when typing information is added (and is so made possible as a realistic alternative).
+* Easy calling into C code. One of Cython's purposes is to allow easy wrapping
+ of C libraries. When writing code in Cython you can call into C code as
+ easily as into Python code.
+
+Some Python constructs are not yet supported, though making Cython compile all
+Python code is a stated goal (among the more important omissions are inner
+functions and generator functions).
+
+Your Cython environment
+========================
+
+Using Cython consists of these steps:
+
+1. Write a :file:`.pyx` source file
+2. Run the Cython compiler to generate a C file
+3. Run a C compiler to generate a compiled library
+4. Run the Python interpreter and ask it to import the module
+
+However there are several options to automate these steps:
+
+1. The `SAGE <http://sagemath.org>`_ mathematics software system provides
+ excellent support for using Cython and NumPy from an interactive command
+ line (like IPython) or through a notebook interface (like
+ Maple/Mathematica). See `this documentation
+ <http://www.sagemath.org/doc/prog/node40.html>`_.
+2. A version of `pyximport <http://www.prescod.net/pyximport/>`_ is shipped
+ with Cython, so that you can import pyx-files dynamically into Python and
+ have them compiled automatically (See :ref:`pyximport`).
+3. Cython supports distutils so that you can very easily create build scripts
+ which automate the process, this is the preferred method for full programs.
+4. Manual compilation (see below)
+
+.. Note::
+ If using another interactive command line environment than SAGE, like
+ IPython or Python itself, it is important that you restart the process
+ when you recompile the module. It is not enough to issue an "import"
+ statement again.
+
+Installation
+=============
+
+Unless you are used to some other automatic method:
+`download Cython <http://cython.org/#download>`_ (0.9.8.1.1 or later), unpack it,
+and run the usual ```python setup.py install``. This will install a
+``cython`` executable on your system. It is also possible to use Cython from
+the source directory without installing (simply launch :file:`cython.py` in the
+root directory).
+
+As of this writing SAGE comes with an older release of Cython than required
+for this tutorial. So if using SAGE you should download the newest Cython and
+then execute ::
+
+ $ cd path/to/cython-distro
+ $ path-to-sage/sage -python setup.py install
+
+This will install the newest Cython into SAGE.
+
+Manual compilation
+====================
+
+As it is always important to know what is going on, I'll describe the manual
+method here. First Cython is run::
+
+ $ cython yourmod.pyx
+
+This creates :file:`yourmod.c` which is the C source for a Python extension
+module. A useful additional switch is ``-a`` which will generate a document
+:file:`yourmod.html`) that shows which Cython code translates to which C code
+line by line.
+
+Then we compile the C file. This may vary according to your system, but the C
+file should be built like Python was built. Python documentation for writing
+extensions should have some details. On Linux this often means something
+like::
+
+ $ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing -I/usr/include/python2.5 -o yourmod.so yourmod.c
+
+``gcc`` should have access to the NumPy C header files so if they are not
+installed at :file:`/usr/include/numpy` or similar you may need to pass another
+option for those.
+
+This creates :file:`yourmod.so` in the same directory, which is importable by
+Python by using a normal ``import yourmod`` statement.
+
+The first Cython program
+==========================
+
+The code below does 2D discrete convolution of an image with a filter (and I'm
+sure you can do better!, let it serve for demonstration purposes). It is both
+valid Python and valid Cython code. I'll refer to it as both
+:file:`convolve_py.py` for the Python version and :file:`convolve1.pyx` for the
+Cython version -- Cython uses ".pyx" as its file suffix.
+
+.. code-block:: python
+
+ from __future__ import division
+ import numpy as np
+ def naive_convolve(f, g):
+ # f is an image and is indexed by (v, w)
+ # g is a filter kernel and is indexed by (s, t),
+ # it needs odd dimensions
+ # h is the output image and is indexed by (x, y),
+ # it is not cropped
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ # smid and tmid are number of pixels between the center pixel
+ # and the edge, ie for a 5x5 filter they will be 2.
+ #
+ # The output size is calculated by adding smid, tmid to each
+ # side of the dimensions of the input image.
+ vmax = f.shape[0]
+ wmax = f.shape[1]
+ smax = g.shape[0]
+ tmax = g.shape[1]
+ smid = smax // 2
+ tmid = tmax // 2
+ xmax = vmax + 2*smid
+ ymax = wmax + 2*tmid
+ # Allocate result image.
+ h = np.zeros([xmax, ymax], dtype=f.dtype)
+ # Do convolution
+ for x in range(xmax):
+ for y in range(ymax):
+ # Calculate pixel value for h at (x,y). Sum one component
+ # for each pixel (s, t) of the filter g.
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h
+
+This should be compiled to produce :file:`yourmod.so` (for Linux systems). We
+run a Python session to test both the Python version (imported from
+``.py``-file) and the compiled Cython module.
+
+.. sourcecode:: ipython
+
+ In [1]: import numpy as np
+ In [2]: import convolve_py
+ In [3]: convolve_py.naive_convolve(np.array([[1, 1, 1]], dtype=np.int),
+ ... np.array([[1],[2],[1]], dtype=np.int))
+ Out [3]:
+ array([[1, 1, 1],
+ [2, 2, 2],
+ [1, 1, 1]])
+ In [4]: import convolve1
+ In [4]: convolve1.naive_convolve(np.array([[1, 1, 1]], dtype=np.int),
+ ... np.array([[1],[2],[1]], dtype=np.int))
+ Out [4]:
+ array([[1, 1, 1],
+ [2, 2, 2],
+ [1, 1, 1]])
+ In [11]: N = 100
+ In [12]: f = np.arange(N*N, dtype=np.int).reshape((N,N))
+ In [13]: g = np.arange(81, dtype=np.int).reshape((9, 9))
+ In [19]: %timeit -n2 -r3 convolve_py.naive_convolve(f, g)
+ 2 loops, best of 3: 1.86 s per loop
+ In [20]: %timeit -n2 -r3 convolve1.naive_convolve(f, g)
+ 2 loops, best of 3: 1.41 s per loop
+
+There's not such a huge difference yet; because the C code still does exactly
+what the Python interpreter does (meaning, for instance, that a new object is
+allocated for each number used). Look at the generated html file and see what
+is needed for even the simplest statements you get the point quickly. We need
+to give Cython more information; we need to add types.
+
+Adding types
+=============
+
+To add types we use custom Cython syntax, so we are now breaking Python source
+compatibility. Here's :file:`convolve2.pyx`. *Read the comments!* ::
+
+ from __future__ import division
+ import numpy as np
+ # "cimport" is used to import special compile-time information
+ # about the numpy module (this is stored in a file numpy.pxd which is
+ # currently part of the Cython distribution).
+ cimport numpy as np
+ # We now need to fix a datatype for our arrays. I've used the variable
+ # DTYPE for this, which is assigned to the usual NumPy runtime
+ # type info object.
+ DTYPE = np.int
+ # "ctypedef" assigns a corresponding compile-time type to DTYPE_t. For
+ # every type in the numpy module there's a corresponding compile-time
+ # type with a _t-suffix.
+ ctypedef np.int_t DTYPE_t
+ # The builtin min and max functions works with Python objects, and are
+ # so very slow. So we create our own.
+ # - "cdef" declares a function which has much less overhead than a normal
+ # def function (but it is not Python-callable)
+ # - "inline" is passed on to the C compiler which may inline the functions
+ # - The C type "int" is chosen as return type and argument types
+ # - Cython allows some newer Python constructs like "a if x else b", but
+ # the resulting C file compiles with Python 2.3 through to Python 3.0 beta.
+ cdef inline int int_max(int a, int b): return a if a >= b else b
+ cdef inline int int_min(int a, int b): return a if a <= b else b
+ # "def" can type its arguments but not have a return type. The type of the
+ # arguments for a "def" function is checked at run-time when entering the
+ # function.
+ #
+ # The arrays f, g and h is typed as "np.ndarray" instances. The only effect
+ # this has is to a) insert checks that the function arguments really are
+ # NumPy arrays, and b) make some attribute access like f.shape[0] much
+ # more efficient. (In this example this doesn't matter though.)
+ def naive_convolve(np.ndarray f, np.ndarray g):
+ if g.shape[0] % 2 != 1 or g.shape[1] % 2 != 1:
+ raise ValueError("Only odd dimensions on filter supported")
+ assert f.dtype == DTYPE and g.dtype == DTYPE
+ # The "cdef" keyword is also used within functions to type variables. It
+ # can only be used at the top indendation level (there are non-trivial
+ # problems with allowing them in other places, though we'd love to see
+ # good and thought out proposals for it).
+ #
+ # For the indices, the "int" type is used. This corresponds to a C int,
+ # other C types (like "unsigned int") could have been used instead.
+ # Purists could use "Py_ssize_t" which is the proper Python type for
+ # array indices.
+ cdef int vmax = f.shape[0]
+ cdef int wmax = f.shape[1]
+ cdef int smax = g.shape[0]
+ cdef int tmax = g.shape[1]
+ cdef int smid = smax // 2
+ cdef int tmid = tmax // 2
+ cdef int xmax = vmax + 2*smid
+ cdef int ymax = wmax + 2*tmid
+ cdef np.ndarray h = np.zeros([xmax, ymax], dtype=DTYPE)
+ cdef int x, y, s, t, v, w
+ # It is very important to type ALL your variables. You do not get any
+ # warnings if not, only much slower code (they are implicitly typed as
+ # Python objects).
+ cdef int s_from, s_to, t_from, t_to
+ # For the value variable, we want to use the same data type as is
+ # stored in the array, so we use "DTYPE_t" as defined above.
+ # NB! An important side-effect of this is that if "value" overflows its
+ # datatype size, it will simply wrap around like in C, rather than raise
+ # an error like in Python.
+ cdef DTYPE_t value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = int_max(smid - x, -smid)
+ s_to = int_min((xmax - x) - smid, smid + 1)
+ t_from = int_max(tmid - y, -tmid)
+ t_to = int_min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = x - smid + s
+ w = y - tmid + t
+ value += g[smid - s, tmid - t] * f[v, w]
+ h[x, y] = value
+ return h
+
+At this point, have a look at the generated C code for :file:`convolve1.pyx` and
+:file:`convolve2.pyx`. Click on the lines to expand them and see corresponding C.
+(Note that this code annotation is currently experimental and especially
+"trailing" cleanup code for a block may stick to the last expression in the
+block and make it look worse than it is -- use some common sense).
+
+* .. literalinclude: convolve1.html
+* .. literalinclude: convolve2.html
+
+Especially have a look at the for loops: In :file:`convolve1.c`, these are ~20 lines
+of C code to set up while in :file:`convolve2.c` a normal C for loop is used.
+
+After building this and continuing my (very informal) benchmarks, I get:
+
+.. sourcecode:: ipython
+
+ In [21]: import convolve2
+ In [22]: %timeit -n2 -r3 convolve2.naive_convolve(f, g)
+ 2 loops, best of 3: 828 ms per loop
+
+Efficient indexing
+====================
+
+There's still a bottleneck killing performance, and that is the array lookups
+and assignments. The ``[]``-operator still uses full Python operations --
+what we would like to do instead is to access the data buffer directly at C
+speed.
+
+What we need to do then is to type the contents of the :obj:`ndarray` objects.
+We do this with a special "buffer" syntax which must be told the datatype
+(first argument) and number of dimensions ("ndim" keyword-only argument, if
+not provided then one-dimensional is assumed).
+
+More information on this syntax [:enhancements/buffer:can be found here].
+
+Showing the changes needed to produce :file:`convolve3.pyx` only::
+
+ ...
+ def naive_convolve(np.ndarray[DTYPE_t, ndim=2] f, np.ndarray[DTYPE_t, ndim=2] g):
+ ...
+ cdef np.ndarray[DTYPE_t, ndim=2] h = ...
+
+Usage:
+
+.. sourcecode:: ipython
+
+ In [18]: import convolve3
+ In [19]: %timeit -n3 -r100 convolve3.naive_convolve(f, g)
+ 3 loops, best of 100: 11.6 ms per loop
+
+Note the importance of this change.
+
+*Gotcha*: This efficient indexing only affects certain index operations,
+namely those with exactly ``ndim`` number of typed integer indices. So if
+``v`` for instance isn't typed, then the lookup ``f[v, w]`` isn't
+optimized. On the other hand this means that you can continue using Python
+objects for sophisticated dynamic slicing etc. just as when the array is not
+typed.
+
+Tuning indexing further
+========================
+
+The array lookups are still slowed down by two factors:
+
+1. Bounds checking is performed.
+2. Negative indices are checked for and handled correctly. The code above is
+ explicitly coded so that it doesn't use negative indices, and it
+ (hopefully) always access within bounds. We can add a decorator to disable
+ bounds checking::
+
+ ...
+ cimport cython
+ @cython.boundscheck(False) # turn of bounds-checking for entire function
+ def naive_convolve(np.ndarray[DTYPE_t, ndim=2] f, np.ndarray[DTYPE_t, ndim=2] g):
+ ...
+
+Now bounds checking is not performed (and, as a side-effect, if you ''do''
+happen to access out of bounds you will in the best case crash your program
+and in the worst case corrupt data). It is possible to switch bounds-checking
+mode in many ways, see [:docs/compilerdirectives:compiler directives] for more
+information.
+
+Negative indices are dealt with by ensuring Cython that the indices will be
+positive, by casting the variables to unsigned integer types (if you do have
+negative values, then this casting will create a very large positive value
+instead and you will attempt to access out-of-bounds values). Casting is done
+with a special ``<>``-syntax. The code below is changed to use either
+unsigned ints or casting as appropriate::
+
+ ...
+ cdef int s, t # changed
+ cdef unsigned int x, y, v, w # changed
+ cdef int s_from, s_to, t_from, t_to
+ cdef DTYPE_t value
+ for x in range(xmax):
+ for y in range(ymax):
+ s_from = max(smid - x, -smid)
+ s_to = min((xmax - x) - smid, smid + 1)
+ t_from = max(tmid - y, -tmid)
+ t_to = min((ymax - y) - tmid, tmid + 1)
+ value = 0
+ for s in range(s_from, s_to):
+ for t in range(t_from, t_to):
+ v = <unsigned int>(x - smid + s) # changed
+ w = <unsigned int>(y - tmid + t) # changed
+ value += g[<unsigned int>(smid - s), <unsigned int>(tmid - t)] * f[v, w] # changed
+ h[x, y] = value
+ ...
+
+(In the next Cython release we will likely add a compiler directive or
+argument to the ``np.ndarray[]``-type specifier to disable negative indexing
+so that casting so much isn't necessary; feedback on this is welcome.)
+
+The function call overhead now starts to play a role, so we compare the latter
+two examples with larger N:
+
+.. sourcecode:: ipython
+
+ In [11]: %timeit -n3 -r100 convolve4.naive_convolve(f, g)
+ 3 loops, best of 100: 5.97 ms per loop
+ In [12]: N = 1000
+ In [13]: f = np.arange(N*N, dtype=np.int).reshape((N,N))
+ In [14]: g = np.arange(81, dtype=np.int).reshape((9, 9))
+ In [17]: %timeit -n1 -r10 convolve3.naive_convolve(f, g)
+ 1 loops, best of 10: 1.16 s per loop
+ In [18]: %timeit -n1 -r10 convolve4.naive_convolve(f, g)
+ 1 loops, best of 10: 597 ms per loop
+
+(Also this is a mixed benchmark as the result array is allocated within the
+function call.)
+
+.. Warning::
+
+ Speed comes with some cost. Especially it can be dangerous to set typed
+ objects (like ``f``, ``g`` and ``h`` in our sample code) to :keyword:`None`.
+ Setting such objects to :keyword:`None` is entirely legal, but all you can do with them
+ is check whether they are None. All other use (attribute lookup or indexing)
+ can potentially segfault or corrupt data (rather than raising exceptions as
+ they would in Python).
+
+ The actual rules are a bit more complicated but the main message is clear: Do
+ not use typed objects without knowing that they are not set to None.
+
+More generic code
+==================
+
+It would be possible to do::
+
+ def naive_convolve(object[DTYPE_t, ndim=2] f, ...):
+
+i.e. use :obj:`object` rather than :obj:`np.ndarray`. Under Python 3.0 this
+can allow your algorithm to work with any libraries supporting the buffer
+interface; and support for e.g. the Python Imaging Library may easily be added
+if someone is interested also under Python 2.x.
+
+There is some speed penalty to this though (as one makes more assumptions
+compile-time if the type is set to :obj:`np.ndarray`, specifically it is
+assumed that the data is stored in pure strided more and not in indirect
+mode).
+
+[:enhancements/buffer:More information]
+
+The future
+============
+
+These are some points to consider for further development. All points listed
+here has gone through a lot of thinking and planning already; still they may
+or may not happen depending on available developer time and resources for
+Cython.
+
+1. Support for efficient access to structs/records stored in arrays; currently
+ only primitive types are allowed.
+2. Support for efficient access to complex floating point types in arrays. The
+ main obstacle here is getting support for efficient complex datatypes in
+ Cython.
+3. Calling NumPy/SciPy functions currently has a Python call overhead; it
+ would be possible to take a short-cut from Cython directly to C. (This does
+ however require some isolated and incremental changes to those libraries;
+ mail the Cython mailing list for details).
+4. Efficient code that is generic with respect to the number of dimensions.
+ This can probably be done today by calling the NumPy C multi-dimensional
+ iterator API directly; however it would be nice to have for-loops over
+ :func:`enumerate` and :func:`ndenumerate` on NumPy arrays create efficient
+ code.
+5. A high-level construct for writing type-generic code, so that one can write
+ functions that work simultaneously with many datatypes. Note however that a
+ macro preprocessor language can help with doing this for now.
+
--- /dev/null
+.. highlight:: cython
+
+.. _overview:
+
+********
+Overview
+********
+
+About Cython
+==============
+
+Cython is a language that makes writing C extensions for the Python language
+as easy as Python itself. Cython is based on the well-known `Pyrex
+<http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/>`_ language by Greg Ewing,
+but supports more cutting edge functionality and optimizations [#]_.
+The Cython language is very close to the Python language, but Cython
+additionally supports calling C functions and declaring C types on variables
+and class attributes. This allows the compiler to generate very efficient C
+code from Cython code.
+
+This makes Cython the ideal language for wrapping external C libraries,
+and for fast C modules that speed up the execution of Python code.
+
+Future Plans
+============
+Cython is not finished. Substantial tasks remaining. See
+:ref:`cython-limitations` for a current list.
+
+.. rubric:: Footnotes
+
+.. [#] For differences with Pyrex see :ref:`pyrex-differences`.
+
--- /dev/null
+I think this is a result of a recent change to Pyrex that
+has been merged into Cython.
+
+If a directory contains an :file:`__init__.py` or :file:`__init__.pyx` file,
+it's now assumed to be a package directory. So, for example,
+if you have a directory structure::
+
+ foo/
+ __init__.py
+ shrubbing.pxd
+ shrubbing.pyx
+
+then the shrubbing module is assumed to belong to a package
+called 'foo', and its fully qualified module name is
+'foo.shrubbing'.
+
+So when Pyrex wants to find out whether there is a `.pxd` file for shrubbing,
+it looks for one corresponding to a module called `foo.shrubbing`. It
+does this by searching the include path for a top-level package directory
+called 'foo' containing a file called 'shrubbing.pxd'.
+
+However, if foo is the current directory you're running
+the compiler from, and you haven't added foo to the
+include path using a -I option, then it won't be on
+the include path, and the `.pxd` won't be found.
+
+What to do about this depends on whether you really
+intend the module to reside in a package.
+
+If you intend shrubbing to be a top-level module, you
+will have to move it somewhere else where there is
+no :file:`__init__.*` file.
+
+If you do intend it to reside in a package, then there
+are two alternatives:
+
+1. cd to the directory containing foo and compile
+ from there::
+
+ cd ..; cython foo/shrubbing.pyx
+
+2. arrange for the directory containing foo to be
+ passed as a -I option, e.g.::
+
+ cython -I .. shrubbing.pyx
+
+Arguably this behaviour is not very desirable, and I'll
+see if I can do something about it.
+
--- /dev/null
+.. highlight:: cython
+
+.. _pyrex-differences:
+
+**************************************
+Differences between Cython and Pyrex
+**************************************
+
+.. warning::
+ Both Cython and Pyrex are moving targets. It has come to the point
+ that an explicit list of all the differences between the two
+ projects would be laborious to list and track, but hopefully
+ this high-level list gives an idea of the differences that
+ are present. It should be noted that both projects make an effort
+ at mutual compatibility, but Cython's goal is to be as close to
+ and complete as Python as reasonable.
+
+
+Python 3.0 Support
+==================
+
+Cython creates ``.c`` files that can be built and used with both
+Python 2.x and Python 3.x. In fact, compiling your module with
+Cython may very well be the easiest way to port code to Python 3.0.
+We are also working to make the compiler run in both Python 2.x and 3.0.
+
+Many Python 3 constructs are already supported by Cython.
+
+List/Set/Dict Comprehensions
+----------------------------
+
+Cython supports the different comprehensions defined by Python 3.0 for
+lists, sets and dicts::
+
+ [expr(x) for x in A] # list
+ {expr(x) for x in A} # set
+ {key(x) : value(x) for x in A} # dict
+
+Looping is optimized if ``A`` is a list, tuple or dict. You can use
+the :keyword:`for` ... :keyword:`from` syntax, too, but it is
+generally preferred to use the usual :keyword:`for` ... :keyword:`in`
+``range(...)`` syntax with a C run variable (e.g. ``cdef int i``).
+
+.. note:: see :ref:`automatic-range-conversion`
+
+Note that Cython also supports set literals starting from Python 2.3.
+
+Keyword-only arguments
+----------------------
+
+Python functions can have keyword-only arguments listed after the ``*``
+parameter and before the ``**`` parameter if any, e.g.::
+
+ def f(a, b, *args, c, d = 42, e, **kwds):
+ ...
+
+Here ``c``, ``d`` and ``e`` cannot be passed as position arguments and must be
+passed as keyword arguments. Furthermore, ``c`` and ``e`` are required keyword
+arguments, since they do not have a default value.
+
+If the parameter name after the ``*`` is omitted, the function will not accept any
+extra positional arguments, e.g.::
+
+ def g(a, b, *, c, d):
+ ...
+
+takes exactly two positional parameters and has two required keyword parameters.
+
+
+
+Conditional expressions "x if b else y" (python 2.5)
+=====================================================
+
+Conditional expressions as described in
+http://www.python.org/dev/peps/pep-0308/::
+
+ X if C else Y
+
+Only one of ``X`` and ``Y`` is evaluated, (depending on the value of C).
+
+cdef inline
+=============
+
+Module level functions can now be declared inline, with the :keyword:`inline`
+keyword passed on to the C compiler. These can be as fast as macros.::
+
+ cdef inline int something_fast(int a, int b):
+ return a*a + b
+
+Note that class-level :keyword:`cdef` functions are handled via a virtual
+function table, so the compiler won't be able to inline them in almost all
+cases.
+
+Assignment on declaration (e.g. "cdef int spam = 5")
+======================================================
+
+In Pyrex, one must write::
+
+ cdef int i, j, k
+ i = 2
+ j = 5
+ k = 7
+
+Now, with cython, one can write::
+
+ cdef int i = 2, j = 5, k = 7
+
+The expression on the right hand side can be arbitrarily complicated, e.g.::
+
+ cdef int n = python_call(foo(x,y), a + b + c) - 32
+
+
+'by' expression in for loop (e.g. "for i from 0 <= i < 10 by 2")
+==================================================================
+
+::
+
+ for i from 0 <= i < 10 by 2:
+ print i
+
+
+yields::
+
+ 0
+ 2
+ 4
+ 6
+ 8
+
+.. note:: see :ref:`automatic-range-conversion`
+
+
+Boolean int type (e.g. it acts like a c int, but coerces to/from python as a boolean)
+======================================================================================
+
+In C, ints are used for truth values. In python, any object can be used as a
+truth value (using the :meth:`__nonzero__` method, but the canonical choices
+are the two boolean objects ``True`` and ``False``. The :keyword:`bint` of
+"boolean int" object is compiled to a C int, but get coerced to and from
+Cython as booleans. The return type of comparisons and several builtins is a
+:ctype:`bint` as well. This allows one to avoid having to wrap things in
+:func:`bool()`. For example, one can write::
+
+ def is_equal(x):
+ return x == y
+
+which would return ``1`` or ``0`` in Pyrex, but returns ``True`` or ``False`` in
+python. One can declare variables and return values for functions to be of the
+:ctype:`bint` type. For example::
+
+ cdef int i = x
+ cdef bint b = x
+
+The first conversion would happen via ``x.__int__()`` whereas the second would
+happen via ``x.__nonzero__()``. (Actually, if ``x`` is the python object
+``True`` or ``False`` then no method call is made.)
+
+Executable class bodies
+=======================
+
+Including a working :func:`classmethod`::
+
+ cdef class Blah:
+ def some_method(self):
+ print self
+ some_method = classmethod(some_method)
+ a = 2*3
+ print "hi", a
+
+cpdef functions
+=================
+
+Cython adds a third function type on top of the usual :keyword:`def` and
+:keyword:`cdef`. If a function is declared :keyword:`cpdef` it can be called
+from and overridden by both extension and normal python subclasses. You can
+essentially think of a :keyword:`cpdef` method as a :keyword:`cdef` method +
+some extras. (That's how it's implemented at least.) First, it creates a
+:keyword:`def` method that does nothing but call the underlying
+:keyword:`cdef` method (and does argument unpacking/coercion if needed). At
+the top of the :keyword:`cdef` method a little bit of code is added to check
+to see if it's overridden. Specifically, in pseudocode::
+
+ if type(self) has a __dict__:
+ foo = self.getattr('foo')
+ if foo is not wrapper_foo:
+ return foo(args)
+ [cdef method body]
+
+To detect whether or not a type has a dictionary, it just checks the
+tp_dictoffset slot, which is ``NULL`` (by default) for extension types, but
+non- null for instance classes. If the dictionary exists, it does a single
+attribute lookup and can tell (by comparing pointers) whether or not the
+returned result is actually a new function. If, and only if, it is a new
+function, then the arguments packed into a tuple and the method called. This
+is all very fast. A flag is set so this lookup does not occur if one calls the
+method on the class directly, e.g.::
+
+ cdef class A:
+ cpdef foo(self):
+ pass
+
+ x = A()
+ x.foo() # will check to see if overridden
+ A.foo(x) # will call A's implementation whether overridden or not
+
+See :ref:`early-binding-for-speed` for explanation and usage tips.
+
+.. _automatic-range-conversion:
+
+Automatic range conversion
+============================
+
+This will convert statements of the form ``for i in range(...)`` to ``for i
+from ...`` when ``i`` is any cdef'd integer type, and the direction (i.e. sign
+of step) can be determined.
+
+.. warning::
+
+ This may change the semantics if the range causes
+ assignment to ``i`` to overflow. Specifically, if this option is set, an error
+ will be raised before the loop is entered, whereas without this option the loop
+ will execute until a overflowing value is encountered. If this effects you
+ change ``Cython/Compiler/Options.py`` (eventually there will be a better
+ way to set this).
+
+More friendly type casting
+===========================
+
+In Pyrex, if one types ``<int>x`` where ``x`` is a Python object, one will get
+the memory address of ``x``. Likewise, if one types ``<object>i`` where ``i``
+is a C int, one will get an "object" at location ``i`` in memory. This leads
+to confusing results and segfaults.
+
+In Cython ``<type>x`` will try and do a coercion (as would happen on assignment of
+``x`` to a variable of type type) if exactly one of the types is a python object.
+It does not stop one from casting where there is no conversion (though it will
+emit a warning). If one really wants the address, cast to a ``void *`` first.
+
+As in Pyrex ``<MyExtensionType>x`` will cast ``x`` to type :ctype:`MyExtensionType` without any
+type checking. Cython supports the syntax ``<MyExtensionType?>`` to do the cast
+with type checking (i.e. it will throw an error if ``x`` is not a (subclass of)
+:ctype:`MyExtensionType`.
+
+Optional arguments in cdef/cpdef functions
+============================================
+
+Cython now supports optional arguments for :keyword:`cdef` and
+:keyword:`cpdef` functions.
+
+The syntax in the ``.pyx`` file remains as in Python, but one declares such
+functions in the ``.pxd`` file by writing ``cdef foo(x=*)``. The number of
+arguments may increase on subclassing, but the argument types and order must
+remain the same. There is a slight performance penalty in some cases when a
+cdef/cpdef function without any optional is overridden with one that does have
+default argument values.
+
+For example, one can have the ``.pxd`` file::
+
+ cdef class A:
+ cdef foo(self)
+ cdef class B(A)
+ cdef foo(self, x=*)
+ cdef class C(B):
+ cpdef foo(self, x=*, int k=*)
+
+with corresponding ``.pyx`` file::
+
+ cdef class A:
+ cdef foo(self):
+ print "A"
+ cdef class B(A)
+ cdef foo(self, x=None)
+ print "B", x
+ cdef class C(B):
+ cpdef foo(self, x=True, int k=3)
+ print "C", x, k
+
+.. note::
+
+ this also demonstrates how :keyword:`cpdef` functions can override
+ :keyword:`cdef` functions.
+
+Function pointers in structs
+=============================
+
+Functions declared in :keyword:`structs` are automatically converted to
+function pointers for convenience.
+
+C++ Exception handling
+=========================
+
+:keyword:`cdef` functions can now be declared as::
+
+ cdef int foo(...) except +
+ cdef int foo(...) except +TypeError
+ cdef int foo(...) except +python_error_raising_function
+
+in which case a Python exception will be raised when a C++ error is caught.
+See :ref:`wrapping-cplusplus` for more details.
+
+Synonyms
+=========
+
+``cdef import from`` means the same thing as ``cdef extern from``
+
+Source code encoding
+======================
+
+.. TODO: add the links to the relevent PEPs
+
+Cython supports PEP 3120 and PEP 263, i.e. you can start your Cython source
+file with an encoding comment and generally write your source code in UTF-8.
+This impacts the encoding of byte strings and the conversion of unicode string
+literals like ``u'abcd'`` to unicode objects.
+
+Automatic ``typecheck``
+========================
+
+Rather than introducing a new keyword :keyword:`typecheck` as explained in the
+`Pyrex docs
+<http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/version/Doc/Manual/special_methods.html>`_,
+Cython emits a (non-spoofable and faster) typecheck whenever
+:func:`isinstance` is used with an extension type as the second parameter.
+
+From __future__ directives
+==========================
+
+Cython supports several from __future__ directives, namely ``unicode_literals`` and ``division``.
+
+With statements are always enabled.
+
+Pure Python mode
+================
+
+Cython has support for compiling ``.py`` files, and
+accepting type annotations using decorators and other
+valid Python syntax. This allows the same source to
+be interpreted as straight Python, or compiled for
+optimized results.
+See http://wiki.cython.org/pure
+for more details.
+
--- /dev/null
+.. highlight:: cython
+
+.. _sharing-declarations:
+
+********************************************
+Sharing Declarations Between Cython Modules
+********************************************
+
+This section describes a new set of facilities for making C declarations,
+functions and extension types in one Cython module available for use in
+another Cython module. These facilities are closely modelled on the Python
+import mechanism, and can be thought of as a compile-time version of it.
+
+Definition and Implementation files
+====================================
+
+A Cython module can be split into two parts: a definition file with a ``.pxd``
+suffix, containing C declarations that are to be available to other Cython
+modules, and an implementation file with a ``.pyx`` suffix, containing
+everything else. When a module wants to use something declared in another
+module's definition file, it imports it using the :keyword:`cimport`
+statement.
+
+A ``.pxd`` file that consists solely of extern declarations does not need
+to correspond to an actual ``.pyx`` file or Python module. This can make it a
+convenient place to put common declarations, for example declarations of
+functions from an :ref:`external library <external-C-code>` that one wants to use in several modules.
+
+What a Definition File contains
+================================
+
+A definition file can contain:
+
+* Any kind of C type declaration.
+* extern C function or variable declarations.
+* Declarations of C functions defined in the module.
+* The definition part of an extension type (see below).
+
+It cannot contain any non-extern C variable declarations.
+
+It cannot contain the implementations of any C or Python functions, or any
+Python class definitions, or any executable statements. It is needed when one
+wants to access :keyword:`cdef` attributes and methods, or to inherit from
+:keyword:`cdef` classes defined in this module.
+
+.. note::
+
+ You don't need to (and shouldn't) declare anything in a declaration file
+ public in order to make it available to other Cython modules; its mere
+ presence in a definition file does that. You only need a public
+ declaration if you want to make something available to external C code.
+
+What an Implementation File contains
+======================================
+
+An implementation file can contain any kind of Cython statement, although there
+are some restrictions on the implementation part of an extension type if the
+corresponding definition file also defines that type (see below).
+If one doesn't need to :keyword:`cimport` anything from this module, then this
+is the only file one needs.
+
+The cimport statement
+=======================
+
+The :keyword:`cimport` statement is used in a definition or
+implementation file to gain access to names declared in another definition
+file. Its syntax exactly parallels that of the normal Python import
+statement::
+
+ cimport module [, module...]
+
+ from module cimport name [as name] [, name [as name] ...]
+
+Here is an example. The file on the left is a definition file which exports a
+C data type. The file on the right is an implementation file which imports and
+uses it.
+
+:file:`dishes.pxd`::
+
+ cdef enum otherstuff:
+ sausage, eggs, lettuce
+
+ cdef struct spamdish:
+ int oz_of_spam
+ otherstuff filler
+
+:file:`restaurant.pyx`::
+
+ cimport dishes
+ from dishes cimport spamdish
+
+ cdef void prepare(spamdish *d):
+ d.oz_of_spam = 42
+ d.filler = dishes.sausage
+
+ def serve():
+ cdef spamdish d
+ prepare(&d)
+ print "%d oz spam, filler no. %d" % (d.oz_of_spam, d.otherstuff)
+
+It is important to understand that the :keyword:`cimport` statement can only
+be used to import C data types, C functions and variables, and extension
+types. It cannot be used to import any Python objects, and (with one
+exception) it doesn't imply any Python import at run time. If you want to
+refer to any Python names from a module that you have cimported, you will have
+to include a regular import statement for it as well.
+
+The exception is that when you use :keyword:`cimport` to import an extension type, its
+type object is imported at run time and made available by the name under which
+you imported it. Using :keyword:`cimport` to import extension types is covered in more
+detail below.
+
+If a ``.pxd`` file changes, any modules that :keyword:`cimport` from it may need to be
+recompiled.
+
+Search paths for definition files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When you :keyword:`cimport` a module called ``modulename``, the Cython
+compiler searches for a file called :file:`modulename.pxd` along the search
+path for include files, as specified by ``-I`` command line options.
+
+Also, whenever you compile a file :file:`modulename.pyx`, the corresponding
+definition file :file:`modulename.pxd` is first searched for along the same
+path, and if found, it is processed before processing the ``.pyx`` file.
+
+Using cimport to resolve naming conflicts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The :keyword:`cimport` mechanism provides a clean and simple way to solve the
+problem of wrapping external C functions with Python functions of the same
+name. All you need to do is put the extern C declarations into a ``.pxd`` file
+for an imaginary module, and :keyword:`cimport` that module. You can then
+refer to the C functions by qualifying them with the name of the module.
+Here's an example:
+
+:file:`c_lunch.pxd` ::
+
+ cdef extern from "lunch.h":
+ void eject_tomato(float)
+
+:file:`lunch.pyx` ::
+
+ cimport c_lunch
+
+ def eject_tomato(float speed):
+ c_lunch.eject_tomato(speed)
+
+You don't need any :file:`c_lunch.pyx` file, because the only things defined
+in :file:`c_lunch.pxd` are extern C entities. There won't be any actual
+``c_lunch`` module at run time, but that doesn't matter; the
+:file:`c_lunch.pxd` file has done its job of providing an additional namespace
+at compile time.
+
+Sharing C Functions
+===================
+
+C functions defined at the top level of a module can be made available via
+:keyword:`cimport` by putting headers for them in the ``.pxd`` file, for
+example,:
+
+:file:`volume.pxd`::
+
+ cdef float cube(float)
+
+:file:`spammery.pyx`::
+
+ from volume cimport cube
+
+ def menu(description, size):
+ print description, ":", cube(size), \
+ "cubic metres of spam"
+
+ menu("Entree", 1)
+ menu("Main course", 3)
+ menu("Dessert", 2)
+
+:file:`volume.pyx`::
+
+ cdef float cube(float x):
+ return x * x * x
+
+.. note::
+
+ When a module exports a C function in this way, an object appears in the
+ module dictionary under the function's name. However, you can't make use of
+ this object from Python, nor can you use it from Cython using a normal import
+ statement; you have to use :keyword:`cimport`.
+
+Sharing Extension Types
+=======================
+
+An extension type can be made available via :keyword:`cimport` by splitting
+its definition into two parts, one in a definition file and the other in the
+corresponding implementation file.
+
+The definition part of the extension type can only declare C attributes and C
+methods, not Python methods, and it must declare all of that type's C
+attributes and C methods.
+
+The implementation part must implement all of the C methods declared in the
+definition part, and may not add any further C attributes. It may also define
+Python methods.
+
+Here is an example of a module which defines and exports an extension type,
+and another module which uses it.::
+
+ # Shrubbing.pxd
+ cdef class Shrubbery:
+ cdef int width
+ cdef int length
+
+ # Shrubbing.pyx
+ cdef class Shrubbery:
+ def __cinit__(self, int w, int l):
+ self.width = w
+ self.length = l
+
+ def standard_shrubbery():
+ return Shrubbery(3, 7)
+
+
+ # Landscaping.pyx
+ cimport Shrubbing
+ import Shrubbing
+
+ cdef Shrubbing.Shrubbery sh
+ sh = Shrubbing.standard_shrubbery()
+ print "Shrubbery size is %d x %d" % (sh.width, sh.height)
+
+Some things to note about this example:
+
+* There is a :keyword:`cdef` class Shrubbery declaration in both
+ :file:`Shrubbing.pxd` and :file:`Shrubbing.pyx`. When the Shrubbing module
+ is compiled, these two declarations are combined into one.
+* In Landscaping.pyx, the :keyword:`cimport` Shrubbing declaration allows us
+ to refer to the Shrubbery type as :class:`Shrubbing.Shrubbery`. But it
+ doesn't bind the name Shrubbing in Landscaping's module namespace at run
+ time, so to access :func:`Shrubbing.standard_shrubbery` we also need to
+ ``import Shrubbing``.
+
--- /dev/null
+.. highlight:: cython
+
+.. _compilation:
+
+****************************
+Source Files and Compilation
+****************************
+
+Cython source file names consist of the name of the module followed by a
+``.pyx`` extension, for example a module called primes would have a source
+file named :file:`primes.pyx`.
+
+Once you have written your ``.pyx`` file, there are a couple of ways of turning it
+into an extension module. One way is to compile it manually with the Cython
+compiler, e.g.:
+
+.. sourcecode:: text
+
+ $ cython primes.pyx
+
+This will produce a file called :file:`primes.c`, which then needs to be
+compiled with the C compiler using whatever options are appropriate on your
+platform for generating an extension module. For these options look at the
+official Python documentation.
+
+The other, and probably better, way is to use the :mod:`distutils` extension
+provided with Cython. The benifit of this method is that it will give the
+platform specific compilation options, acting like a stripped down autotools.
+
+Basic setup.py
+===============
+The distutils extension provided with Cython allows you to pass ``.pyx`` files
+directly to the ``Extension`` constructor in your setup file.
+
+If you have a single Cython file that you want to turn into a compiled
+extension, say with filename :file:`example.pyx` the associated :file:`setup.py`
+would be::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("example", ["example.pyx"])]
+ )
+
+To understand the :file:`setup.py` more fully look at the official
+:mod:`distutils` documentation. To compile the extension for use in the
+current directory use:
+
+.. sourcecode:: text
+
+ $ python setup.py build_ext --inplace
+
+Cython Files Depending on C Files
+===================================
+
+When you have come C files that have been wrapped with cython and you want to
+compile them into your extension the basic :file:`setup.py` file to do this
+would be::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ sourcefiles = ['example.pyx', 'helper.c', 'another_helper.c']
+
+ setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("example", sourcefiles)]
+ )
+
+Notice that the files have been given a name, this is not necessary, but it
+makes the file easier to format if the list gets long.
+
+The :class:`Extension` class takes many options, and a fuller explanation can
+be found in the `distutils documentation`_. Some useful options to know about
+are ``include_dirs``, ``libraries``, and ``library_dirs`` which specify where
+to find the ``.h`` and library files when linking to external libraries.
+
+.. _distutils documentation: http://docs.python.org/extending/building.html
+
+
+
+Multiple Cython Files in a Package
+===================================
+
+TODO
+
+Distributing Cython modules
+============================
+It is strongly recommended that you distribute the generated ``.c`` files as well
+as your Cython sources, so that users can install your module without needing
+to have Cython available.
+
+It is also recommended that Cython compilation not be enabled by default in the
+version you distribute. Even if the user has Cython installed, he probably
+doesn't want to use it just to install your module. Also, the version he has
+may not be the same one you used, and may not compile your sources correctly.
+
+This simply means that the :file:`setup.py` file that you ship with will just
+be a normal distutils file on the generated `.c` files, for the basic example
+we would have instead::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+
+ setup(
+ ext_modules = [Extension("example", ["example.c"])]
+ )
+
+
+.. _pyximport:
+
+Pyximport
+===========
+
+.. TODO add some text about how this is Paul Prescods code. Also change the
+ tone to be more universal (i.e. remove all the I statements)
+
+Cython is a compiler. Therefore it is natural that people tend to go
+through an edit/compile/test cycle with Cython modules. But my personal
+opinion is that one of the deep insights in Python's implementation is
+that a language can be compiled (Python modules are compiled to ``.pyc``)
+files and hide that compilation process from the end-user so that they
+do not have to worry about it. Pyximport does this for Cython modules.
+For instance if you write a Cython module called :file:`foo.pyx`, with
+Pyximport you can import it in a regular Python module like this::
+
+
+ import pyximport; pyximport.install()
+ import foo
+
+Doing so will result in the compilation of :file:`foo.pyx` (with appropriate
+exceptions if it has an error in it).
+
+If you would always like to import Cython files without building them
+specially, you can also the first line above to your :file:`sitecustomize.py`.
+That will install the hook every time you run Python. Then you can use
+Cython modules just with simple import statements. I like to test my
+Cython modules like this:
+
+.. sourcecode:: text
+
+ $ python -c "import foo"
+
+Dependency Handling
+--------------------
+
+In Pyximport 1.1 it is possible to declare that your module depends on
+multiple files, (likely ``.h`` and ``.pxd`` files). If your Cython module is
+named ``foo`` and thus has the filename :file:`foo.pyx` then you should make
+another file in the same directory called :file:`foo.pyxdep`. The
+:file:`modname.pyxdep` file can be a list of filenames or "globs" (like
+``*.pxd`` or ``include/*.h``). Each filename or glob must be on a separate
+line. Pyximport will check the file date for each of those files before
+deciding whether to rebuild the module. In order to keep track of the
+fact that the dependency has been handled, Pyximport updates the
+modification time of your ".pyx" source file. Future versions may do
+something more sophisticated like informing distutils of the
+dependencies directly.
+
+Limitations
+------------
+
+Pyximport does not give you any control over how your Cython file is
+compiled. Usually the defaults are fine. You might run into problems if
+you wanted to write your program in half-C, half-Cython and build them
+into a single library. Pyximport 1.2 will probably do this.
+
+Pyximport does not hide the Distutils/GCC warnings and errors generated
+by the import process. Arguably this will give you better feedback if
+something went wrong and why. And if nothing went wrong it will give you
+the warm fuzzy that pyximport really did rebuild your module as it was
+supposed to.
+
+For further thought and discussion
+------------------------------------
+
+I don't think that Python's :func:`reload` will do anything for changed
+``.so``'s on some (all?) platforms. It would require some (easy)
+experimentation that I haven't gotten around to. But reload is rarely used in
+applications outside of the Python interactive interpreter and certainly not
+used much for C extension modules. Info about Windows
+`<http://mail.python.org/pipermail/python-list/2001-July/053798.html>`_
+
+``setup.py install`` does not modify :file:`sitecustomize.py` for you. Should it?
+Modifying Python's "standard interpreter" behaviour may be more than
+most people expect of a package they install..
+
+Pyximport puts your ``.c`` file beside your ``.pyx`` file (analogous to
+``.pyc`` beside ``.py``). But it puts the platform-specific binary in a
+build directory as per normal for Distutils. If I could wave a magic
+wand and get Cython or distutils or whoever to put the build directory I
+might do it but not necessarily: having it at the top level is *VERY*
+*HELPFUL* for debugging Cython problems.
+
--- /dev/null
+.. _special-methods:
+
+Special Methods of Extension Types
+===================================
+
+This page describes the special methods currently supported by Cython extension
+types. A complete list of all the special methods appears in the table at the
+bottom. Some of these methods behave differently from their Python
+counterparts or have no direct Python counterparts, and require special
+mention.
+
+.. Note: Everything said on this page applies only to extension types, defined
+ with the :keyword:`cdef class` statement. It doesn't apply to classes defined with the
+ Python :keyword:`class` statement, where the normal Python rules apply.
+
+Declaration
+------------
+Special methods of extension types must be declared with :keyword:`def`, not
+:keyword:`cdef`. This does not impact their performance--Python uses different
+calling conventions to invoke these special methods.
+
+Docstrings
+-----------
+
+Currently, docstrings are not fully supported in some special methods of extension
+types. You can place a docstring in the source to serve as a comment, but it
+won't show up in the corresponding :attr:`__doc__` attribute at run time. (This
+seems to be is a Python limitation -- there's nowhere in the `PyTypeObject`
+data structure to put such docstrings.)
+
+Initialisation methods: :meth:`__cinit__` and :meth:`__init__`
+---------------------------------------------------------------
+There are two methods concerned with initialising the object.
+
+The :meth:`__cinit__` method is where you should perform basic C-level
+initialisation of the object, including allocation of any C data structures
+that your object will own. You need to be careful what you do in the
+:meth:`__cinit__` method, because the object may not yet be fully valid Python
+object when it is called. Therefore, you should be careful invoking any Python
+operations which might touch the object; in particular, its methods.
+
+By the time your :meth:`__cinit__` method is called, memory has been allocated for the
+object and any C attributes it has have been initialised to 0 or null. (Any
+Python attributes have also been initialised to None, but you probably
+shouldn't rely on that.) Your :meth:`__cinit__` method is guaranteed to be called
+exactly once.
+
+If your extension type has a base type, the :meth:`__cinit__` method of the base type
+is automatically called before your :meth:`__cinit__` method is called; you cannot
+explicitly call the inherited :meth:`__cinit__` method. If you need to pass a modified
+argument list to the base type, you will have to do the relevant part of the
+initialisation in the :meth:`__init__` method instead (where the normal rules for
+calling inherited methods apply).
+
+Any initialisation which cannot safely be done in the :meth:`__cinit__` method should
+be done in the :meth:`__init__` method. By the time :meth:`__init__` is called, the object is
+a fully valid Python object and all operations are safe. Under some
+circumstances it is possible for :meth:`__init__` to be called more than once or not
+to be called at all, so your other methods should be designed to be robust in
+such situations.
+
+Any arguments passed to the constructor will be passed to both the
+:meth:`__cinit__` method and the :meth:`__init__` method. If you anticipate
+subclassing your extension type in Python, you may find it useful to give the
+:meth:`__cinit__` method `*` and `**` arguments so that it can accept and
+ignore extra arguments. Otherwise, any Python subclass which has an
+:meth:`__init__` with a different signature will have to override
+:meth:`__new__`[#] as well as :meth:`__init__`, which the writer of a Python
+class wouldn't expect to have to do. Alternatively, as a convenience, if you declare
+your :meth:`__cinit__`` method to take no arguments (other than self) it
+will simply ignore any extra arguments passed to the constructor without
+complaining about the signature mismatch.
+
+.. Note: Older Cython files may use :meth:`__new__` rather than :meth:`__cinit__`. The two are synonyms.
+ The name change from :meth:`__new__` to :meth:`__cinit__` was to avoid
+ confusion with Python :meth:`__new__` (which is an entirely different
+ concept) and eventually the use of :meth:`__new__` in Cython will be
+ disallowed to pave the way for supporting Python-style :meth:`__new__`
+
+.. [#] http://docs.python.org/reference/datamodel.html#object.__new__
+
+Finalization method: :meth:`__dealloc__`
+----------------------------------------
+
+The counterpart to the :meth:`__cinit__` method is the :meth:`__dealloc__`
+method, which should perform the inverse of the :meth:`__cinit__` method. Any
+C data that you explicitly allocated (e.g. via malloc) in your
+:meth:`__cinit__` method should be freed in your :meth:`__dealloc__` method.
+
+You need to be careful what you do in a :meth:`__dealloc__` method. By the time your
+:meth:`__dealloc__` method is called, the object may already have been partially
+destroyed and may not be in a valid state as far as Python is concerned, so
+you should avoid invoking any Python operations which might touch the object.
+In particular, don't call any other methods of the object or do anything which
+might cause the object to be resurrected. It's best if you stick to just
+deallocating C data.
+
+You don't need to worry about deallocating Python attributes of your object,
+because that will be done for you by Cython after your :meth:`__dealloc__` method
+returns.
+
+.. Note: There is no :meth:`__del__` method for extension types.
+
+Arithmetic methods
+-------------------
+
+Arithmetic operator methods, such as :meth:`__add__`, behave differently from their
+Python counterparts. There are no separate "reversed" versions of these
+methods (:meth:`__radd__`, etc.) Instead, if the first operand cannot perform the
+operation, the same method of the second operand is called, with the operands
+in the same order.
+
+This means that you can't rely on the first parameter of these methods being
+"self" or being the right type, and you should test the types of both operands
+before deciding what to do. If you can't handle the combination of types you've
+been given, you should return `NotImplemented`.
+
+This also applies to the in-place arithmetic method :meth:`__ipow__`. It doesn't apply
+to any of the other in-place methods (:meth:`__iadd__`, etc.) which always
+take `self` as the first argument.
+
+Rich comparisons
+-----------------
+
+There are no separate methods for the individual rich comparison operations
+(:meth:`__eq__`, :meth:`__le__`, etc.) Instead there is a single method
+:meth:`__richcmp__` which takes an integer indicating which operation is to be
+performed, as follows:
+
++-----+-----+
+| < | 0 |
++-----+-----+
+| == | 2 |
++-----+-----+
+| > | 4 |
++-----+-----+
+| <= | 1 |
++-----+-----+
+| != | 3 |
++-----+-----+
+| >= | 5 |
++-----+-----+
+
+The :meth:`__next__` method
+----------------------------
+
+Extension types wishing to implement the iterator interface should define a
+method called :meth:`__next__`, not next. The Python system will automatically
+supply a next method which calls your :meth:`__next__`. Do *NOT* explicitly
+give your type a :meth:`next` method, or bad things could happen.
+
+Special Method Table
+---------------------
+
+This table lists all of the special methods together with their parameter and
+return types. In the table below, a parameter name of self is used to indicate
+that the parameter has the type that the method belongs to. Other parameters
+with no type specified in the table are generic Python objects.
+
+You don't have to declare your method as taking these parameter types. If you
+declare different types, conversions will be performed as necessary.
+
+General
+^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __cinit__ |self, ... | | Basic initialisation (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __init__ |self, ... | | Further initialisation |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __dealloc__ |self | | Basic deallocation (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __cmp__ |x, y | int | 3-way comparison |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __richcmp__ |x, y, int op | object | Rich comparison (no direct Python equivalent) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __str__ |self | object | str(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __repr__ |self | object | repr(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __hash__ |self | int | Hash function |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __call__ |self, ... | object | self(...) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __iter__ |self | object | Return iterator for sequence |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getattr__ |self, name | object | Get attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setattr__ |self, name, val | | Set attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delattr__ |self, name | | Delete attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Arithmetic operators
+^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __add__ | x, y | object | binary `+` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __sub__ | x, y | object | binary `-` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __mul__ | x, y | object | `*` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __div__ | x, y | object | `/` operator for old-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __floordiv__ | x, y | object | `//` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __truediv__ | x, y | object | `/` operator for new-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __mod__ | x, y | object | `%` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __divmod__ | x, y | object | combined div and mod |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __pow__ | x, y, z | object | `**` operator or pow(x, y, z) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __neg__ | self | object | unary `-` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __pos__ | self | object | unary `+` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __abs__ | self | object | absolute value |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __nonzero__ | self | int | convert to boolean |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __invert__ | self | object | `~` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __lshift__ | x, y | object | `<<` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __rshift__ | x, y | object | `>>` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __and__ | x, y | object | `&` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __or__ | x, y | object | `|` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __xor__ | x, y | object | `^` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Numeric conversions
+^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __int__ | self | object | Convert to integer |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __long__ | self | object | Convert to long integer |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __float__ | self | object | Convert to float |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __oct__ | self | object | Convert to octal |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __hex__ | self | object | Convert to hexadecimal |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __index__ (2.5+ only) | self | object | Convert to sequence index |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+In-place arithmetic operators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __iadd__ | self, x | object | `+=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __isub__ | self, x | object | `-=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __imul__ | self, x | object | `*=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __idiv__ | self, x | object | `/=` operator for old-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ifloordiv__ | self, x | object | `//=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __itruediv__ | self, x | object | `/=` operator for new-style division |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __imod__ | self, x | object | `%=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ipow__ | x, y, z | object | `**=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ilshift__ | self, x | object | `<<=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __irshift__ | self, x | object | `>>=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __iand__ | self, x | object | `&=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ior__ | self, x | object | `|=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __ixor__ | self, x | object | `^=` operator |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Sequences and mappings
+^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __len__ | self int | | len(self) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getitem__ | self, x | object | self[x] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setitem__ | self, x, y | | self[x] = y |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delitem__ | self, x | | del self[x] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getslice__ | self, Py_ssize_t i, Py_ssize_t j | object | self[i:j] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __setslice__ | self, Py_ssize_t i, Py_ssize_t j, x | | self[i:j] = x |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delslice__ | self, Py_ssize_t i, Py_ssize_t j | | del self[i:j] |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __contains__ | self, x | int | x in self |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Iterators
+^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __next__ | self | object | Get next item (called next in Python) |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Buffer interface [PEP 3118] (no Python equivalents - see note 1)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __getbuffer__ | self, Py_buffer `*view`, int flags | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __releasebuffer__ | self, Py_buffer `*view` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Buffer interface [legacy] (no Python equivalents - see note 1)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __getreadbuffer__ | self, Py_ssize_t i, void `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getwritebuffer__ | self, Py_ssize_t i, void `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getsegcount__ | self, Py_ssize_t `*p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __getcharbuffer__ | self, Py_ssize_t i, char `**p` | | |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+Descriptor objects (see note 2)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| Name | Parameters | Return type | Description |
++=======================+=======================================+=============+=====================================================+
+| __get__ | self, instance, class | object | Get value of attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __set__ | self, instance, value | | Set value of attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+| __delete__ | self, instance | | Delete attribute |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+.. note:: (1) The buffer interface was intended for use by C code and is not directly
+ accessible from Python. It is described in the Python/C API Reference Manual
+ of Python 2.x under sections 6.6 and 10.6. It was superseded by the new
+ PEP 3118 buffer protocol in Python 2.6 and is no longer available in Python 3.
+
+.. note:: (2) Descriptor objects are part of the support mechanism for new-style
+ Python classes. See the discussion of descriptors in the Python documentation.
+ See also PEP 252, "Making Types Look More Like Classes", and PEP 253,
+ "Subtyping Built-In Types".
+
--- /dev/null
+.. highlight:: cython
+
+.. _tutorial:
+
+**************
+Basic Tutorial
+**************
+
+The Basics of Cython
+====================
+
+The fundamental nature of Cython can be summed up as follows: Cython is Python
+with C data types.
+
+Cython is Python: Almost any piece of Python code is also valid Cython code.
+(There are a few :ref:`cython-limitations`, but this approximation will
+serve for now.) The Cython compiler will convert it into C code which makes
+equivalent calls to the Python/C API.
+
+But Cython is much more than that, because parameters and variables can be
+declared to have C data types. Code which manipulates Python values and C
+values can be freely intermixed, with conversions occurring automatically
+wherever possible. Reference count maintenance and error checking of Python
+operations is also automatic, and the full power of Python's exception
+handling facilities, including the try-except and try-finally statements, is
+available to you -- even in the midst of manipulating C data.
+
+
+
+Cython Hello World
+===================
+
+As Cython can accept almost any valid python source file, one of the hardest
+things in getting started is just figuring out how to compile your extension.
+
+So lets start with the canonical python hello world::
+
+ print "Hello World"
+
+So the first thing to do is rename the file to :file:`helloworld.pyx`. Now we
+need to make the :file:`setup.py`, which is like a python Makefile (for more
+information see :ref:`compilation`). Your :file:`setup.py` should look like::
+
+ from distutils.core import setup
+ from distutils.extension import Extension
+ from Cython.Distutils import build_ext
+
+ setup(
+ cmdclass = {'build_ext': build_ext},
+ ext_modules = [Extension("helloworld", ["helloworld.pyx"])]
+ )
+
+To use this to build your Cython file use the commandline options:
+
+.. sourcecode:: text
+
+ $ python setup.py build_ext --inplace
+
+Which will leave a file in your local directory called :file:`helloworld.so` in unix
+or :file:`helloworld.dll` in Windows. Now to use this file: start the python
+interpreter and simply import it as if it was a regular python module::
+
+ >>> import helloworld
+ Hello World
+
+Congratulations! You now know how to build a Cython extension. But So Far
+this example doesn't really give a feeling why one would ever want to use Cython, so
+lets create a more realistic example.
+
+:mod:`pyximport`: Cython Compilation the Easy Way
+==================================================
+
+If your module doesn't require any extra C libraries or a special
+build setup, then you can use the pyximport module by Paul Prescod and
+Stefan Behnel to load .pyx files directly on import, without having to
+write a :file:`setup.py` file. It is shipped and installed with
+Cython and can be used like this::
+
+ >>> import pyximport; pyximport.install()
+ >>> import helloworld
+ Hello World
+
+Since Cython 0.11, the :mod:`pyximport` module also has experimental
+compilation support for normal Python modules. This allows you to
+automatically run Cython on every .pyx and .py module that Python
+imports, including the standard library and installed packages.
+Cython will still fail to compile a lot of Python modules, in which
+case the import mechanism will fall back to loading the Python source
+modules instead. The .py import mechanism is installed like this::
+
+ >>> pyximport.install(pyimport = True)
+
+Fibonacci Fun
+==============
+
+From the official Python tutorial a simple fibonacci function is defined as:
+
+.. literalinclude:: ../../examples/tutorial/fib1/fib.pyx
+
+Now following the steps for the Hello World example we first rename the file
+to have a `.pyx` extension, lets say :file:`fib.pyx`, then we create the
+:file:`setup.py` file. Using the file created for the Hello World example, all
+that you need to change is the name of the Cython filename, and the resulting
+module name, doing this we have:
+
+.. literalinclude:: ../../examples/tutorial/fib1/setup.py
+
+Build the extension with the same command used for the helloworld.pyx:
+
+.. sourcecode:: text
+
+ $ python setup.py build_ext --inplace
+
+And use the new extension with::
+
+ >>> import fib
+ >>> fib.fib(2000)
+ 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
+
+Primes
+=======
+
+Here's a small example showing some of what can be done. It's a routine for
+finding prime numbers. You tell it how many primes you want, and it returns
+them as a Python list.
+
+:file:`primes.pyx`:
+
+.. literalinclude:: ../../examples/tutorial/primes/primes.pyx
+ :linenos:
+
+You'll see that it starts out just like a normal Python function definition,
+except that the parameter ``kmax`` is declared to be of type ``int`` . This
+means that the object passed will be converted to a C integer (or a
+``TypeError.`` will be raised if it can't be).
+
+Lines 2 and 3 use the ``cdef`` statement to define some local C variables.
+Line 4 creates a Python list which will be used to return the result. You'll
+notice that this is done exactly the same way it would be in Python. Because
+the variable result hasn't been given a type, it is assumed to hold a Python
+object.
+
+Lines 7-9 set up for a loop which will test candidate numbers for primeness
+until the required number of primes has been found. Lines 11-12, which try
+dividing a candidate by all the primes found so far, are of particular
+interest. Because no Python objects are referred to, the loop is translated
+entirely into C code, and thus runs very fast.
+
+When a prime is found, lines 14-15 add it to the p array for fast access by
+the testing loop, and line 16 adds it to the result list. Again, you'll notice
+that line 16 looks very much like a Python statement, and in fact it is, with
+the twist that the C parameter ``n`` is automatically converted to a Python
+object before being passed to the append method. Finally, at line 18, a normal
+Python return statement returns the result list.
+
+Compiling primes.pyx with the Cython compiler produces an extension module
+which we can try out in the interactive interpreter as follows::
+
+ >>> import primes
+ >>> primes.primes(10)
+ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
+
+See, it works! And if you're curious about how much work Cython has saved you,
+take a look at the C code generated for this module.
+
+Language Details
+================
+
+For more about the Cython language, see :ref:`language-basics`.
+To dive right in to using Cython in a numerical computation context, see :ref:`numpy_tutorial`.
+
--- /dev/null
+.. highlight:: cython
+
+.. _wrapping-cplusplus:
+
+********************************
+Using C++ in Cython
+********************************
+
+Overview
+=========
+
+Cython v0.13 introduces native support for most of the C++ language. This means that the previous tricks that were used to wrap C++ classes (as described in http://wiki.cython.org/WrappingCPlusPlus_ForCython012AndLower) are no longer needed.
+
+Wrapping C++ classes with Cython is now much more straightforward. This document describe in details the new way of wrapping C++ code.
+
+What's new in Cython v0.13 about C++
+---------------------------------------------------
+
+For users of previous Cython versions, here is a brief overview of the main new features of Cython v0.13 regarding C++ support:
+
+* C++ objects can now be dynamically allocated with ``new`` and ``del`` keywords.
+* C++ objects can now be stack-allocated.
+* C++ classes can be declared with the new keyword ``cppclass``.
+* Templated classes are supported.
+* Overloaded functions are supported.
+* Overloading of C++ operators (such as operator+, operator[],...) is supported.
+
+Procedure Overview
+-------------------
+The general procedure for wrapping a C++ file can now be described as follow:
+
+* Specify C++ language in :file:`setup.py` script
+* Create ``cdef extern from`` blocks with the optional namespace (if exists) and the namespace name as string
+* Declare classes as ``cdef cppclass`` blocks
+* Declare public attributes (variables, methods and constructors)
+
+A simple Tutorial
+==================
+
+An example C++ API
+-------------------
+
+Here is a tiny C++ API which we will use as an example throughout this
+document. Let's assume it will be in a header file called
+:file:`Rectangle.h`:
+
+.. sourcecode:: c++
+
+ namespace shapes {
+ class Rectangle {
+ public:
+ int x0, y0, x1, y1;
+ Rectangle(int x0, int y0, int x1, int y1);
+ ~Rectangle();
+ int getLength();
+ int getHeight();
+ int getArea();
+ void move(int dx, int dy);
+ };
+ }
+
+and the implementation in the file called :file:`Rectangle.cpp`:
+
+.. sourcecode:: c++
+
+ #include "Rectangle.h"
+
+ Rectangle::Rectangle(int X0, int Y0, int X1, int Y1)
+ {
+ x0 = X0;
+ y0 = Y0;
+ x1 = X1;
+ y1 = Y1;
+ }
+
+ Rectangle::~Rectangle()
+ {
+ }
+
+ int Rectangle::getLength()
+ {
+ return (x1 - x0);
+ }
+
+ int Rectangle::getHeight()
+ {
+ return (y1 - y0);
+ }
+
+ int Rectangle::getArea()
+ {
+ return (x1 - x0) * (y1 - y0);
+ }
+
+ void Rectangle::move(int dx, int dy)
+ {
+ x0 += dx;
+ y0 += dy;
+ x1 += dx;
+ y1 += dy;
+ }
+
+This is pretty dumb, but should suffice to demonstrate the steps involved.
+
+Specify C++ language in setup.py
+---------------------------------
+
+In Cython :file:`setup.py` scripts, one normally instantiates an Extension
+object. To make Cython generate and compile a C++ source, you just need
+to add the keyword ``language="c++"`` to your Extension construction statement, as in::
+
+ ext = Extension(
+ "rectangle", # name of extension
+ ["rectangle.pyx", "Rectangle.cpp"], # filename of our Cython source
+ language="c++", # this causes Cython to create C++ source
+ include_dirs=[...], # usual stuff
+ libraries=["stdc++", ...], # ditto
+ extra_link_args=[...], # if needed
+ cmdclass = {'build_ext': build_ext}
+ )
+
+Cython will generate and compile the :file:`rectangle.cpp` file (from the
+:file:`rectangle.pyx`), then it will compile :file:`Rectangle.cpp`
+(implementation of the ``Rectangle`` class) and link both objects files
+together into :file:`rectangle.so`, which you can then import in Python using
+``import rectangle`` (if you forget to link the :file:`Rectangle.o`, you will
+get missing symbols while importing the library in Python).
+
+
+Alternatively, one can also use the ``cython`` command-line utility to generate a C++ ``.cpp`` file, and then compile it into a python extension. C++ mode for the ``cython`` command is turned on with the ``--cplus`` option.
+
+Declaring a C++ class interface
+--------------------------------
+
+The procedure for wrapping a C++ class is quite similar to that for wrapping
+normal C structs, with a couple of additions. Let's start here by creating the
+basic ``cdef extern from`` block::
+
+ cdef extern from "Rectangle.h" namespace "shapes":
+
+This will make the C++ class def for Rectangle available. Note the namespace declaration.
+
+Declare class with cdef cppclass
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now, let's add the Rectangle class to this extern from block - just copy the class name from Rectangle.h and adjust for Cython syntax, so now it becomes::
+
+ cdef extern from "Rectangle.h" namespace "shapes":
+ cdef cppclass Rectangle:
+
+Add public attributes
+^^^^^^^^^^^^^^^^^^^^^^
+
+We now need to declare the attributes for use on Cython::
+
+ cdef extern from "Rectangle.h" namespace "shapes":
+ cdef cppclass Rectangle:
+ Rectangle(int, int, int, int)
+ int x0, y0, x1, y1
+ int getLength()
+ int getHeight()
+ int getArea()
+ void move(int, int)
+
+Declare a var with the wrapped C++ class
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now, we use cdef to declare a var of the class with the C++ ``new`` statement::
+
+ cdef Rectangle *rec = new Rectangle(1, 2, 3, 4)
+ cdef int recLength = rec.getLength()
+ ...
+ del rec #delete heap allocated object
+
+It's also possible to declare a stack allocated object, but it's necessary to have a "default" constructor::
+
+ cdef extern from "Foo.h":
+ cdef cppclass Foo:
+ Foo()
+
+ cdef Foo foo
+
+Note that, like C++, if the class has only one constructor and it is a default one, it's not necessary to declare it.
+
+Create Cython wrapper class
+----------------------------
+
+At this point, we have exposed into our pyx file's namespace the interface of the C++ Rectangle type. Now, we need to make
+this accessible from external Python code (which is our whole point).
+
+Common programming practice is to create a Cython extension type which
+holds a C++ instance pointer as an attribute ``thisptr``, and create a bunch of
+forwarding methods. So we can implement the Python extension type as::
+
+ cdef class PyRectangle:
+ cdef Rectangle *thisptr # hold a C++ instance which we're wrapping
+ def __cinit__(self, int x0, int y0, int x1, int y1):
+ self.thisptr = new Rectangle(x0, y0, x1, y1)
+ def __dealloc__(self):
+ del self.thisptr
+ def getLength(self):
+ return self.thisptr.getLength()
+ def getHeight(self):
+ return self.thisptr.getHeight()
+ def getArea(self):
+ return self.thisptr.getArea()
+ def move(self, dx, dy):
+ self.thisptr.move(dx, dy)
+
+And there we have it. From a Python perspective, this extension type will look
+and feel just like a natively defined Rectangle class. If you want to give
+attribute access, you could just implement some properties::
+
+ property x0:
+ def __get__(self): return self.thisptr.x0
+ def __set__(self, x0): self.thisptr.x0 = x0
+ ...
+
+
+Advanced C++ features
+======================
+
+We describe here all the C++ features that were not discussed in the above tutorial.
+
+Overloading
+------------
+
+Overloading is very simple. Just declare the method with different parameters and use any of them::
+
+ cdef extern from "Foo.h":
+ cdef cppclass Foo:
+ Foo(int)
+ Foo(bool)
+ Foo(int, bool)
+ Foo(int, int)
+
+Overloading operators
+----------------------
+
+Cython uses C++ for overloading operators::
+
+ cdef extern from "foo.h":
+ cdef cppclass Foo:
+ Foo()
+ Foo* operator+(Foo*)
+ Foo* operator-(Foo)
+ int operator*(Foo*)
+ int operator/(int)
+
+ cdef Foo* foo = new Foo()
+ cdef int x
+
+ cdef Foo* foo2 = foo[0] + foo
+ foo2 = foo[0] - foo[0]
+
+ x = foo[0] * foo2
+ x = foo[0] / 1
+
+ cdef Foo f
+ foo = f + &f
+ foo2 = f - f
+
+ del foo, foo2
+
+Nested class declarations
+--------------------------
+C++ allows nested class declaration. Class declarations can also be nested in Cython::
+
+
+ cdef extern from "<vector>" namespace "std":
+ cdef cppclass vector[T]:
+ cppclass iterator:
+ T operator*()
+ iterator operator++()
+ bint operator==(iterator)
+ bint operator!=(iterator)
+ vector()
+ void push_back(T&)
+ T& operator[](int)
+ T& at(int)
+ iterator begin()
+ iterator end()
+
+ cdef vector[int].iterator iter #iter is declared as being of type vector<int>::iterator
+
+Note that the nested class is declared with a ``cppclass`` but without a ``cdef``.
+
+C++ operators not compatible with Python syntax
+------------------------------------------------
+
+Cython try to keep a syntax as close as possible to standard Python. Because of this, certain C++ operators, like the preincrement ``++foo`` or the dereferencing operator ``*foo`` cannot be used with the same syntax as C++. Cython provides functions replacing these operators in a special module ``cython.operator``. The functions provided are:
+
+* ``cython.operator.dereference`` for dereferencing. ``dereference(foo)`` will produce the C++ code ``*foo``
+* ``cython.operator.preincrement`` for pre-incrementation. ``preincrement(foo)`` will produce the C++ code ``++foo``
+* ...
+
+These functions need to be cimported. Of course, one can use a ``from ... cimport ... as`` to have shorter and more readable functions. For example: ``from cython.operator cimport dereference as deref``.
+
+Templates
+----------
+
+Cython uses a bracket syntax for templating. A simple example for wrapping C++ vector::
+
+ from cython.operator cimport dereference as deref, preincrement as inc #dereference and increment operators
+
+ cdef extern from "<vector>" namespace "std":
+ cdef cppclass vector[T]:
+ cppclass iterator:
+ T operator*()
+ iterator operator++()
+ bint operator==(iterator)
+ bint operator!=(iterator)
+ vector()
+ void push_back(T&)
+ T& operator[](int)
+ T& at(int)
+ iterator begin()
+ iterator end()
+
+ cdef vector[int] *v = new vector[int]()
+ cdef int i
+ for i in range(10):
+ v.push_back(i)
+
+ cdef vector[int].iterator it = v.begin()
+ while it != v.end():
+ print deref(it)
+ inc(it)
+
+ del v
+
+Multiple template parameters can be defined as a list, such as [T, U, V] or [int, bool, char].
+
+Standard library
+-----------------
+
+Most of the containers of the C++ Standard Library have been declared in pxd files located in ``/Cython/Includes/libcpp``. These containers are: deque, list, map, pair, queue, set, stack, vector.
+
+For example::
+
+ from libcpp.vector cimport vector
+
+ cdef vector[int] vect
+ cdef int i
+ for i in range(10):
+ vect.push_back(i)
+ for i in range(10):
+ print vect[i]
+
+The pxd files in ``/Cython/Includes/libcpp`` also work as good examples on how to declare C++ classes.
+
+Exceptions
+-----------
+
+Cython cannot throw C++ exceptions, or catch them with a try-except statement,
+but it is possible to declare a function as potentially raising an C++
+exception and converting it into a Python exception. For example, ::
+
+ cdef extern from "some_file.h":
+ cdef int foo() except +
+
+This will translate try and the C++ error into an appropriate Python exception
+(currently an IndexError on std::out_of_range and a RuntimeError otherwise
+(preserving the what() message). ::
+
+ cdef int bar() except +MemoryError
+
+This will catch any C++ error and raise a Python MemoryError in its place.
+(Any Python exception is valid here.) ::
+
+ cdef int raise_py_error()
+ cdef int something_dangerous() except +raise_py_error
+
+If something_dangerous raises a C++ exception then raise_py_error will be
+called, which allows one to do custom C++ to Python error "translations." If
+raise_py_error does not actually raise an exception a RuntimeError will be
+raised.
+
+
+Caveats and Limitations
+========================
+
+Access to C-only functions
+---------------------------
+
+Whenever generating C++ code, Cython generates declarations of and calls
+to functions assuming these functions are C++ (ie, not declared as extern "C"
+{...} . This is ok if the C functions have C++ entry points, but if they're C
+only, you will hit a roadblock. If you have a C++ Cython module needing
+to make calls to pure-C functions, you will need to write a small C++ shim
+module which:
+
+* includes the needed C headers in an extern "C" block
+* contains minimal forwarding functions in C++, each of which calls the
+ respective pure-C function
+
+Inherited C++ methods
+----------------------
+
+If you have a class ``Foo`` with a child class ``Bar``, and ``Foo`` has a
+method :meth:`fred`, then you'll have to cast to access this method from
+``Bar`` objects.
+For example::
+
+ cdef class MyClass:
+ Bar *b
+ ...
+ def myfunc(self):
+ ...
+ b.fred() # wrong, won't work
+ (<Foo *>(self.b)).fred() # should work, Cython now thinks it's a 'Foo'
+
+It might take some experimenting by others (you?) to find the most elegant
+ways of handling this issue.
+
+Declaring/Using References
+---------------------------
+
+Question: How do you declare and call a function that takes a reference as an argument?
+
+C++ left-values
+----------------
+
+C++ allows functions returning a reference to be left-values. This is currently not supported in Cython. ``cython.operator.dereference(foo)`` is also not considered a left-value.
+
+
--- /dev/null
+Background
+----------
+
+[brain dump]
+
+The "Old Cython Users Guide" is a derivative of the old Pyrex documentation. It underwent substantial editing by Peter Alexandar
+to become the Reference Guide, which is oriented around bullet points
+and lists rather than prose. This transition was incomplete.
+
+At nearly the same time, Robert, Dag, and Stefan wrote a tutorial as
+part of the SciPy proceedings. It was felt that the content there was
+cleaner and more up to date than anything else, and this became the
+basis for the "Getting Started" and "Tutorials" sections. However,
+it simply doesn't have as much content as the old documentation used to.
+Eventually, it seems all of the old users manual could be whittled
+down into independent tutorial topics. Much discussion of what we'd
+like to see is at
+
+http://www.mail-archive.com/cython-dev@codespeak.net/msg06945.html
+
+There is currently a huge amount of redundancy, but no one section has
+it all.
+
+Also, we should go through the wiki enhancement proposal list and make sure to transfer the (done) ones into the user manual.
--- /dev/null
+.. highlight:: cython
+
+.. _overview:
+
+********
+Welcome!
+********
+
+===============
+What is Cython?
+===============
+
+Cython is a programming language based on Python
+with extra syntax to provide static type declarations.
+
+================
+What Does It Do?
+================
+
+It takes advantage of the benefits of Python while allowing one to achieve the speed of C.
+
+============================
+How Exactly Does It Do That?
+============================
+
+The source code gets translated into optimized C/C++
+code and compiled as Python extension modules.
+
+This allows for both very fast program execution and tight
+integration with external C libraries, while keeping
+up the high *programmer productivity* for which the
+Python language is well known.
+
+=============
+Tell Me More!
+=============
+
+The Python language is well known.
+
+The primary Python execution environment is commonly referred to as CPython, as it is written in
+C. Other major implementations use:
+
+:Java: Jython [#Jython]_
+:C#: IronPython [#IronPython]_)
+:Python itself: PyPy [#PyPy]_
+
+Written in C, CPython has been
+conducive to wrapping many external libraries that interface through the C language. It has, however, remained non trivial to write the necessary glue code in
+C, especially for programmers who are more fluent in a
+high-level language like Python than in a do-it-yourself
+language like C.
+
+Originally based on the well-known Pyrex [#Pyrex]_, the
+Cython project has approached this problem by means
+of a source code compiler that translates Python code
+to equivalent C code. This code is executed within the
+CPython runtime environment, but at the speed of
+compiled C and with the ability to call directly into C
+libraries.
+
+At the same time, it keeps the original interface of the Python source code, which makes it directly
+usable from Python code. These two-fold characteristics enable Cython’s two major use cases:
+
+#. Extending the CPython interpreter with fast binary modules, and
+#. Interfacing Python code with external C libraries.
+
+While Cython can compile (most) regular Python
+code, the generated C code usually gains major (and
+sometime impressive) speed improvements from optional static type declarations for both Python and
+C types. These allow Cython to assign C semantics to
+parts of the code, and to translate them into very efficient C code.
+
+Type declarations can therefore be used
+for two purposes:
+
+#. For moving code sections from dynamic Python semantics into static-and-fast C semantics, but also for..
+#. Directly manipulating types defined in external libraries. Cython thus merges the two worlds into a very broadly applicable programming language.
+
+==================
+Where Do I Get It?
+==================
+
+Well.. at `cython.org <http://cython.org>`_.. of course!
+
+======================
+How Do I Report a Bug?
+======================
+
+=================================
+I Want To Make A Feature Request!
+=================================
+
+============================================
+Is There a Mail List? How Do I Contact You?
+============================================
+
+
+
+.. rubric:: Footnotes
+
+.. [#Jython] **Jython:** \J. Huginin, B. Warsaw, F. Bock, et al., Jython: Python for the Java platform, http://www.jython.org/
+
+.. [#IronPython] **IronPython:** Jim Hugunin et al., http://www.codeplex.com/IronPython.
+
+
+.. [#PyPy] **PyPy:** The PyPy Group, PyPy: a Python implementation written in Python, http://codespeak.net/pypy.
+
+.. [#Pyrex] **Pyrex:** G. Ewing, Pyrex: C-Extensions for Python, http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
+
+
+
+
+
+
+
+
+
+
+
+
+
try:
fp, pathname, (ext,mode,ty) = imp.find_module(fullname,package_path)
if fp: fp.close() # Python should offer a Default-Loader to avoid this double find/open!
- if ty!=imp.C_EXTENSION: # only when an extension, check if we have a .pyx next!
+ if pathname.endswith(self.extension):
+ return PyxLoader(fullname, pathname,
+ pyxbuild_dir=self.pyxbuild_dir)
+ if ty != imp.C_EXTENSION: # only when an extension, check if we have a .pyx next!
return None
# find .pyx fast, when .so/.pyd exist --inplace
self.super = super(PyImporter, self)
self.super.__init__(extension='.py', pyxbuild_dir=pyxbuild_dir)
self.uncompilable_modules = {}
- self.blocked_modules = ['Cython']
+ self.blocked_modules = ['Cython', 'distutils.extension',
+ 'distutils.sysconfig']
def find_module(self, fullname, package_path=None):
if fullname in sys.modules:
# prevent infinite recursion
return None
if DEBUG_IMPORT:
- print("trying import of module", fullname)
+ print("trying import of module '%s'" % fullname)
if fullname in self.uncompilable_modules:
path, last_modified = self.uncompilable_modules[fullname]
try:
try:
importer = self.super.find_module(fullname, package_path)
if importer is not None:
- if DEBUG_IMPORT:
- print("importer found")
try:
if importer.init_path:
path = importer.init_path
else:
path = importer.path
+ if DEBUG_IMPORT:
+ print("importer found path %s" % path)
build_module(fullname, path,
pyxbuild_dir=self.pyxbuild_dir)
except Exception, e:
except ImportError:
import pickle
+try:
+ from io import open as io_open
+except ImportError:
+ from codecs import open as io_open
+
try:
import threading
except ImportError: # No threads, no problems
threading = None
+try:
+ from collections import defaultdict
+except ImportError:
+ class defaultdict(object):
+ def __init__(self, default_factory=lambda : None):
+ self._dict = {}
+ self.default_factory = default_factory
+ def __getitem__(self, key):
+ if key not in self._dict:
+ self._dict[key] = self.default_factory()
+ return self._dict[key]
+ def __setitem__(self, key, value):
+ self._dict[key] = value
+ def __repr__(self):
+ return repr(self._dict)
+
WITH_CYTHON = True
CY3_DIR = None
except ValueError: pass
distutils_distro.parse_config_files(cfgfiles)
-TEST_DIRS = ['compile', 'errors', 'run', 'wrappers', 'pyregr', 'build']
-TEST_RUN_DIRS = ['run', 'wrappers', 'pyregr']
-
-# Lists external modules, and a matcher matching tests
-# which should be excluded if the module is not present.
EXT_DEP_MODULES = {
- 'numpy' : re.compile('.*\.numpy_.*').match,
- 'pstats' : re.compile('.*\.pstats_.*').match,
- 'posix' : re.compile('.*\.posix_.*').match,
+ 'numpy' : 'tag:numpy',
+ 'pstats' : 'tag:pstats',
+ 'posix' : 'tag:posix',
}
def get_numpy_include_dirs():
import numpy
return [numpy.get_include()]
+# TODO: use tags
EXT_DEP_INCLUDES = [
# test name matcher , callable returning list
(re.compile('numpy_.*').match, get_numpy_include_dirs),
]
+# TODO: use tags
VER_DEP_MODULES = {
# tests are excluded if 'CurrentPythonVersion OP VersionTuple', i.e.
# (2,4) : (operator.lt, ...) excludes ... when PyVer < 2.4.x
]),
(2,5) : (operator.lt, lambda x: x in ['run.any',
'run.all',
+ 'run.relativeimport_T542',
+ 'run.relativeimport_star_T542',
]),
(2,6) : (operator.lt, lambda x: x in ['run.print_function',
'run.cython3',
+ 'run.generators_py', # generators, with statement
'run.pure_py', # decorators, with statement
]),
+ (2,7) : (operator.lt, lambda x: x in ['run.withstat_py', # multi context with statement
+ ]),
# The next line should start (3,); but this is a dictionary, so
# we can only have one (3,) key. Since 2.7 is supposed to be the
# last 2.x release, things would have to change drastically for this
INCLUDE_DIRS = [ d for d in os.getenv('INCLUDE', '').split(os.pathsep) if d ]
CFLAGS = os.getenv('CFLAGS', '').split()
+def memoize(f):
+ uncomputed = object()
+ f._cache = {}
+ def func(*args):
+ res = f._cache.get(args, uncomputed)
+ if res is uncomputed:
+ res = f._cache[args] = f(*args)
+ return res
+ return func
+
+def parse_tags(filepath):
+ tags = defaultdict(list)
+ f = io_open(filepath, encoding='ISO-8859-1', errors='replace')
+ try:
+ for line in f:
+ line = line.strip()
+ if not line:
+ continue
+ if line[0] != '#':
+ break
+ ix = line.find(':')
+ if ix != -1:
+ tag = line[1:ix].strip()
+ values = line[ix+1:].split(',')
+ tags[tag].extend([value.strip() for value in values])
+ finally:
+ f.close()
+ return tags
+
+parse_tags = memoize(parse_tags)
+
+
class build_ext(_build_ext):
def build_extension(self, ext):
if ext.language == 'c++':
def build_suite(self):
suite = unittest.TestSuite()
- test_dirs = TEST_DIRS
filenames = os.listdir(self.rootdir)
filenames.sort()
for filename in filenames:
- if not WITH_CYTHON and filename == "errors":
- # we won't get any errors without running Cython
- continue
path = os.path.join(self.rootdir, filename)
- if os.path.isdir(path) and filename in test_dirs:
+ if os.path.isdir(path):
if filename == 'pyregr' and not self.with_pyregr:
continue
+ if filename == 'broken' and not self.test_bugs:
+ continue
suite.addTest(
self.handle_directory(path, filename))
if sys.platform not in ['win32']:
if not os.path.exists(workdir):
os.makedirs(workdir)
- expect_errors = (context == 'errors')
suite = unittest.TestSuite()
filenames = os.listdir(path)
filenames.sort()
for filename in filenames:
- if filename.endswith(".srctree"):
- if not [ 1 for match in self.selectors if match(filename) ]:
- continue
- if self.exclude_selectors:
- if [1 for match in self.exclude_selectors if match(filename)]:
- continue
- suite.addTest(EndToEndTest(os.path.join(path, filename), workdir, self.cleanup_workdir))
- continue
- if not (filename.endswith(".pyx") or filename.endswith(".py")):
+ filepath = os.path.join(path, filename)
+ module, ext = os.path.splitext(filename)
+ if ext not in ('.py', '.pyx', '.srctree'):
continue
- if filename.startswith('.'): continue # certain emacs backup files
- if context == 'pyregr' and not filename.startswith('test_'):
- continue
- module = os.path.splitext(filename)[0]
+ if filename.startswith('.'):
+ continue # certain emacs backup files
+ tags = parse_tags(filepath)
fqmodule = "%s.%s" % (context, module)
if not [ 1 for match in self.selectors
- if match(fqmodule) ]:
+ if match(fqmodule, tags) ]:
continue
if self.exclude_selectors:
- if [1 for match in self.exclude_selectors if match(fqmodule)]:
+ if [1 for match in self.exclude_selectors
+ if match(fqmodule, tags)]:
+ continue
+
+ mode = 'run' # default
+ if tags['mode']:
+ mode = tags['mode'][0]
+ elif context == 'pyregr':
+ mode = 'pyregr'
+
+ if ext == '.srctree':
+ suite.addTest(EndToEndTest(filepath, workdir, self.cleanup_workdir))
+ continue
+
+ # Choose the test suite.
+ if mode == 'pyregr':
+ if not filename.startswith('test_'):
continue
- if context == 'pyregr':
test_class = CythonPyregrTestCase
- elif context in TEST_RUN_DIRS:
+ elif mode == 'run':
if module.startswith("test_"):
test_class = CythonUnitTestCase
else:
test_class = CythonRunTestCase
else:
test_class = CythonCompileTestCase
+
for test in self.build_tests(test_class, path, workdir,
- module, expect_errors):
+ module, mode == 'error', tags):
suite.addTest(test)
- if context == 'run' and filename.endswith('.py'):
+ if mode == 'run' and ext == '.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):
+ def build_tests(self, test_class, path, workdir, module, expect_errors, tags):
+ if 'werror' in tags['tags']:
+ warning_errors = True
+ else:
+ warning_errors = False
+
if expect_errors:
- if 'cpp' in module and 'cpp' in self.languages:
+ if 'cpp' in tags['tag'] and 'cpp' in self.languages:
languages = ['cpp']
else:
languages = self.languages[:1]
else:
languages = self.languages
- if 'cpp' in module and 'c' in languages:
+ if 'cpp' in tags['tag'] and 'c' in languages:
languages = list(languages)
languages.remove('c')
tests = [ self.build_test(test_class, path, workdir, module,
- language, expect_errors)
+ language, expect_errors, warning_errors)
for language in languages ]
return tests
def build_test(self, test_class, path, workdir, module,
- language, expect_errors):
+ language, expect_errors, warning_errors):
workdir = os.path.join(workdir, language)
if not os.path.exists(workdir):
os.makedirs(workdir)
cleanup_sharedlibs=self.cleanup_sharedlibs,
cython_only=self.cython_only,
fork=self.fork,
- language_level=self.language_level)
+ language_level=self.language_level,
+ warning_errors=warning_errors)
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,
- language_level=2):
+ language_level=2, warning_errors=False):
self.test_directory = test_directory
self.workdir = workdir
self.module = module
self.cython_only = cython_only
self.fork = fork
self.language_level = language_level
+ self.warning_errors = warning_errors
unittest.TestCase.__init__(self)
def shortDescription(self):
return "compiling (%s) %s" % (self.language, self.module)
def setUp(self):
+ from Cython.Compiler import Options
+ self._saved_options = [ (name, getattr(Options, name))
+ for name in ('warning_errors', 'error_on_unknown_names') ]
+ Options.warning_errors = self.warning_errors
+
if self.workdir not in sys.path:
sys.path.insert(0, self.workdir)
def tearDown(self):
+ from Cython.Compiler import Options
+ for name, value in self._saved_options:
+ setattr(Options, name, value)
+
try:
sys.path.remove(self.workdir)
except ValueError:
def split_source_and_output(self, test_directory, module, workdir):
source_file = self.find_module_source_file(os.path.join(test_directory, module) + '.pyx')
- source_and_output = codecs.open(source_file, 'rU', 'ISO-8859-1')
+ source_and_output = io_open(source_file, 'rU', encoding='ISO-8859-1')
try:
- out = codecs.open(os.path.join(workdir, module + os.path.splitext(source_file)[1]),
- 'w', 'ISO-8859-1')
+ out = io_open(os.path.join(workdir, module + os.path.splitext(source_file)[1]),
+ 'w', encoding='ISO-8859-1')
for line in source_and_output:
last_line = line
if line.startswith("_ERRORS"):
self.run_doctests(self.module, result)
def run_doctests(self, module_name, result):
- if sys.version_info[0] >= 3 or not hasattr(os, 'fork') or not self.fork:
- doctest.DocTestSuite(module_name).run(result)
- gc.collect()
- return
-
- # fork to make sure we do not keep the tested module loaded
- result_handle, result_file = tempfile.mkstemp()
- os.close(result_handle)
- child_id = os.fork()
- if not child_id:
- result_code = 0
- try:
- try:
- tests = None
- try:
- partial_result = PartialTestResult(result)
- tests = doctest.DocTestSuite(module_name)
- tests.run(partial_result)
- gc.collect()
- except Exception:
- if tests is None:
- # importing failed, try to fake a test class
- tests = _FakeClass(
- failureException=sys.exc_info()[1],
- _shortDescription=self.shortDescription(),
- module_name=None)
- partial_result.addError(tests, sys.exc_info())
- result_code = 1
- output = open(result_file, 'wb')
- pickle.dump(partial_result.data(), output)
- except:
- traceback.print_exc()
- finally:
- try: output.close()
- except: pass
- os._exit(result_code)
+ def run_test(result):
+ tests = doctest.DocTestSuite(module_name)
+ tests.run(result)
+ run_forked_test(result, run_test, self.shortDescription(), self.fork)
+
+def run_forked_test(result, run_func, test_name, fork=True):
+ if not fork or sys.version_info[0] >= 3 or not hasattr(os, 'fork'):
+ run_func(result)
+ gc.collect()
+ return
+
+ # fork to make sure we do not keep the tested module loaded
+ result_handle, result_file = tempfile.mkstemp()
+ os.close(result_handle)
+ child_id = os.fork()
+ if not child_id:
+ result_code = 0
try:
- cid, result_code = os.waitpid(child_id, 0)
- # os.waitpid returns the child's result code in the
- # upper byte of result_code, and the signal it was
- # killed by in the lower byte
- if result_code & 255:
- raise Exception("Tests in module '%s' were unexpectedly killed by signal %d"%
- (module_name, result_code & 255))
- result_code = result_code >> 8
- if result_code in (0,1):
- input = open(result_file, 'rb')
+ try:
+ tests = None
try:
- PartialTestResult.join_results(result, pickle.load(input))
- finally:
- input.close()
- if result_code:
- raise Exception("Tests in module '%s' exited with status %d" %
- (module_name, result_code))
+ partial_result = PartialTestResult(result)
+ run_func(partial_result)
+ gc.collect()
+ except Exception:
+ if tests is None:
+ # importing failed, try to fake a test class
+ tests = _FakeClass(
+ failureException=sys.exc_info()[1],
+ _shortDescription=test_name,
+ module_name=None)
+ partial_result.addError(tests, sys.exc_info())
+ result_code = 1
+ output = open(result_file, 'wb')
+ pickle.dump(partial_result.data(), output)
+ except:
+ traceback.print_exc()
finally:
- try: os.unlink(result_file)
+ try: output.close()
except: pass
+ os._exit(result_code)
+
+ try:
+ cid, result_code = os.waitpid(child_id, 0)
+ # os.waitpid returns the child's result code in the
+ # upper byte of result_code, and the signal it was
+ # killed by in the lower byte
+ if result_code & 255:
+ raise Exception("Tests in module '%s' were unexpectedly killed by signal %d"%
+ (module_name, result_code & 255))
+ result_code = result_code >> 8
+ if result_code in (0,1):
+ input = open(result_file, 'rb')
+ try:
+ PartialTestResult.join_results(result, pickle.load(input))
+ finally:
+ input.close()
+ if result_code:
+ raise Exception("Tests in module '%s' exited with status %d" %
+ (module_name, result_code))
+ finally:
+ try: os.unlink(result_file)
+ except: pass
class PureDoctestTestCase(unittest.TestCase):
def __init__(self, module_name, module_path):
class CythonPyregrTestCase(CythonRunTestCase):
+ def setUp(self):
+ CythonRunTestCase.setUp(self)
+ from Cython.Compiler import Options
+ Options.error_on_unknown_names = False
+
def _run_unittest(self, result, *classes):
"""Run tests from unittest.TestCase-derived classes."""
valid_types = (unittest.TestSuite, unittest.TestCase)
except ImportError: # Py3k
from test import support
- def run_unittest(*classes):
- return self._run_unittest(result, *classes)
- def run_doctest(module, verbosity=None):
- return self._run_doctest(result, module)
+ def run_test(result):
+ def run_unittest(*classes):
+ return self._run_unittest(result, *classes)
+ def run_doctest(module, verbosity=None):
+ return self._run_doctest(result, module)
- support.run_unittest = run_unittest
- support.run_doctest = run_doctest
+ support.run_unittest = run_unittest
+ support.run_doctest = run_doctest
- try:
- module = __import__(self.module)
- if hasattr(module, 'test_main'):
- module.test_main()
- except (unittest.SkipTest, support.ResourceDenied):
- result.addSkip(self, 'ok')
+ try:
+ module = __import__(self.module)
+ if hasattr(module, 'test_main'):
+ module.test_main()
+ except (unittest.SkipTest, support.ResourceDenied):
+ result.addSkip(self, 'ok')
+
+ run_forked_test(result, run_test, self.shortDescription(), self.fork)
include_debugger = sys.version_info[:2] > (2, 5)
try:
__import__(mod)
except ImportError:
- self.exclude_matchers.append(matcher)
+ self.exclude_matchers.append(string_selector(matcher))
self.tests_missing_deps = []
- def __call__(self, testname):
+ def __call__(self, testname, tags=None):
for matcher in self.exclude_matchers:
- if matcher(testname):
+ if matcher(testname, tags):
self.tests_missing_deps.append(testname)
return True
return False
if compare(version_info, ver):
self.exclude_matchers.append(matcher)
self.tests_missing_deps = []
- def __call__(self, testname):
+ def __call__(self, testname, tags=None):
for matcher in self.exclude_matchers:
if matcher(testname):
self.tests_missing_deps.append(testname)
finally:
f.close()
- def __call__(self, testname):
+ def __call__(self, testname, tags=None):
return testname in self.excludes or testname.split('.')[-1] in self.excludes
+class TagsSelector:
+
+ def __init__(self, tag, value):
+ self.tag = tag
+ self.value = value
+
+ def __call__(self, testname, tags=None):
+ if tags is None:
+ return False
+ else:
+ return self.value in tags[self.tag]
+
+class RegExSelector:
+
+ def __init__(self, pattern_string):
+ self.pattern = re.compile(pattern_string, re.I|re.U)
+
+ def __call__(self, testname, tags=None):
+ return self.pattern.search(testname)
+
+def string_selector(s):
+ ix = s.find(':')
+ if ix == -1:
+ return RegExSelector(s)
+ else:
+ return TagsSelector(s[:ix], s[ix+1:])
+
+
def refactor_for_py3(distdir, cy3_dir):
# need to convert Cython sources first
import lib2to3.refactor
if options.tickets:
for ticket_number in options.tickets:
test_bugs = True
- cmd_args.append('.*T%s$' % ticket_number)
+ cmd_args.append('ticket:%s' % ticket_number)
if not test_bugs:
for selector in cmd_args:
if selector.startswith('bugs'):
test_bugs = True
import re
- selectors = [ re.compile(r, re.I|re.U).search for r in cmd_args ]
+ selectors = [ string_selector(r) for r in cmd_args ]
if not selectors:
- selectors = [ lambda x:True ]
+ selectors = [ lambda x, tags=None: True ]
# Chech which external modules are not present and exclude tests
# which depends on them (by prefix)
exclude_selectors = [missing_dep_excluder, version_dep_excluder] # want to pring msg at exit
if options.exclude:
- exclude_selectors += [ re.compile(r, re.I|re.U).search for r in options.exclude ]
+ exclude_selectors += [ string_selector(r) for r in options.exclude ]
if not test_bugs:
exclude_selectors += [ FileListExcluder(os.path.join(ROOTDIR, "bugs.txt")) ]
test_suite.addTest(filetests.build_suite())
if options.system_pyregr and languages:
- filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
- options.annotate_source, options.cleanup_workdir,
- options.cleanup_sharedlibs, True,
- options.cython_only, languages, test_bugs,
- options.fork, options.language_level)
- test_suite.addTest(
- filetests.handle_directory(
- os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test'),
- 'pyregr'))
+ sys_pyregr_dir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3], 'test')
+ if os.path.isdir(sys_pyregr_dir):
+ filetests = TestBuilder(ROOTDIR, WORKDIR, selectors, exclude_selectors,
+ options.annotate_source, options.cleanup_workdir,
+ options.cleanup_sharedlibs, True,
+ options.cython_only, languages, test_bugs,
+ options.fork, sys.version_info[0])
+ sys.stderr.write("Including CPython regression tests in %s\n" % sys_pyregr_dir)
+ test_suite.addTest(filetests.handle_directory(sys_pyregr_dir, 'pyregr'))
if options.xml_output_dir:
from Cython.Tests.xmlrunner import XMLTestRunner
from distutils.command.sdist import sdist as sdist_orig
class sdist(sdist_orig):
def run(self):
+ self.force_manifest = 1
if (sys.platform != "win32" and
os.path.isdir('.git')):
assert os.system("git show-ref -s HEAD > .gitrev") == 0
compile.cpp_operators
cpp_templated_ctypedef
cpp_structs
-genexpr_T491
-with_statement_module_level_T536
function_as_method_T494
closure_inside_cdef_T554
pure_mode_cmethod_inheritance_T583
for_from_pyvar_loop_T601
decorators_T593
temp_sideeffects_T654
+class_scope_T671
# CPython regression tests that don't current work:
pyregr.test_threadsignals
-pyregr.test_module
pyregr.test_capi
pyregr.test_socket
pyregr.test_threading
pyregr.test_sys
+pyregr.test_pep3131
# CPython regression tests that don't make sense
pyregr.test_gdb
+# mode: compile
+
cdef public struct Foo:
int a, b
cdef public Zax *blarg
+cdef public C c_pub = C()
+cdef api C c_api = C()
+
+cdef public dict o_pub = C()
+cdef api list o_api = C()
+
cdef api float f(Foo *x):
pass
cdef public api void h(Zax *x):
pass
+
+cdef extern from "a_capi.h":
+ pass
+# mode: compile
+
cdef swallow
def spam(w, int x = 42, y = "grail", z = swallow):
+# mode: compile
cdef extern from *:
+# mode: compile
+
cdef enum E:
z
+# mode: compile
+
cdef void f1(char *argv[]):
f2(argv)
+# mode: compile
+
cdef void spam():
cdef long long L
cdef unsigned long long U
+# mode: compile
+
def f(a, b):
assert a, a+b
+# mode: compile
+
cdef enum E:
spam, eggs
+# mode: compile
+
cdef extern from *:
ctypedef int intptr_t
+# ticket: 444
+# mode: compile
def test():
cdef object[int] not_assigned_to
+# mode: compile
+
def f():
x = open("foo")
+# mode: compile
+
cdef int f() except -1:
cdef object x, y, z, w
cdef int i
+# mode: compile
# cython: boundscheck = False
# cython: ignoreme = OK
# cython: warn.undeclared = False
+# mode: compile
+
cdef extern from "callingconvention.h":
pass
+# mode: compile
+
def f(obj, int i, float f, char *s1, char s2[]):
pass
+# mode: compile
+
cdef extern:
cdef func(int[])
+# mode: compile
+
cdef void foo():
cdef int bool, int1=0, int2=0, int3=0, int4=0
cdef object obj1, obj2, obj3, obj4
+# mode: compile
+
cdef void foo():
cdef int i1, i2=0
cdef char c1=0, c2
+# ticket: 518
+# mode: compile
+
cdef extern from "cast_ctypedef_array_T518_helper.h":
cdef struct __foo_struct:
int i, j
+# mode: compile
+
cdef extern class external.Spam:
pass
+# mode: compile
+
cdef extern from "cheese.h":
pass
+# mode: compile
+
cdef extern from *:
int spam
+# mode: compile
+
cdef enum Spam:
a
b, c,
+# mode: compile
+
cdef int i, j, k
cdef object a, b, x
+# ticket: 4
+# mode: compile
+
from a cimport b
cdef int **t = b.foo(NULL)
+# ticket: 248
+# mode: compile
+
from ewing8 cimport (Foo,
+# mode: compile
+
__doc__ = u"""
>>> s = Swallow()
>>> s.spam(1)
+# mode: compile
+
cdef extern from "cnamespec.h":
int a "c_a", b "c_b"
+# mode: compile
+
def f():
cdef int int1, int2=0, int3=1
cdef char char1=0
+# mode: compile
+
cdef void f():
cdef void *p
cdef char *q=NULL
+# mode: compile
+
cdef extern (int *[42]) spam, grail, swallow
cdef (int (*)()) brian():
+# mode: compile
+
cdef enum Grail:
k = 42
+# mode: compile
+
cdef class Tst:
cdef foo,
+# mode: compile
+
cdef class A:
cpdef a(self):
ma(self)
+# tag: cpp
+# mode: compile
+
cdef extern from "cpp_enums.h":
cdef enum Enum1:
Item1
+# tag: cpp
+# mode: compile
+
cdef extern from "operators.h":
cdef cppclass Operators:
Operators(int)
+# tag: cpp
+# mode: compile
+
cdef extern from "point.h" namespace "geometry":
cdef struct Point:
+# tag: cpp
+# mode: compile
+
cdef extern from *:
cdef cppclass Foo[T]:
pass
+# tag: cpp
+# mode: compile
+
cdef extern from "templates.h":
cdef cppclass TemplateTest1[T]:
TemplateTest1()
+# mode: compile
+
ctypedef struct Foo:
int blarg
+# mode: compile
+
ctypedef int *IntPtr
ctypedef unsigned long ULong
cdef extern IntPtr spam
+# ticket: 355
+# mode: compile
+
ctypedef public class Time [type MyTime_Type, object MyTimeObject]:
def __init__(self, seconds):
self.seconds = seconds
+# mode: compile
+
ctypedef class spam:
pass
+# mode: compile
+
ctypedef enum parrot_state:
alive = 1
dead = 2
+# mode: compile
+
ctypedef public api class Foo [type PyFoo_Type, object PyFooObject]:
pass
+# mode: compile
+
ctypedef struct order:
int spam
int eggs
+# mode: compile
+
ctypedef union pet:
int cat
float dog
+# mode: compile
+
cdef void f():
cdef unsigned long x
cdef object y=0
+# mode: compile
+
cdef extern short int s
cdef extern long int l
cdef extern long long ll
+# mode: compile
+
cdef class Tomato:
def eject(self):
+# mode: compile
+
cdef extern from "declarations.h":
pass
+# mode: compile
+
def f(a, b):
global g
del g
+# mode: compile
+
cdef void spam():
cdef object x
del x[17:42]
+# mode: compile
+
"Welcome to the parrot module. It is currently resting."
def zap(polly, volts):
+# mode: compile
+
cdef class Spam:
pass
+# mode: compile
+
cimport dotted_cimport_submodule.a
import dotted_cimport_submodule.b
+# mode: compile
+
cdef char *s
s = r'\"HT\"'
+# ticket: 488
+# mode: compile
#from ... import foo
print ...
+# mode: compile
+
cdef void f():
try:
pass
+# mode: compile
+
cdef enum E:
a
+# mode: compile
+
cdef void foo():
cdef int bool, int1=0, int2=0
cdef float float1=0, float2=0
+# mode: compile
+
cdef int blarg(int i):
pass
+# mode: compile
+
cdef class C:
cdef f(self):
pass
+# mode: compile
+
cdef void f():
"This is a pseudo doc string."
+# mode: compile
+
cdef char *f():
raise Exception
+# mode: compile
# Spurious gcc3.3 warnings about incompatible pointer
# types passed to C method
+# mode: compile
+
cdef class A:
cdef void f(self, x):
pass
+# mode: compile
+
cdef class Blarg:
pass
+# mode: compile
+
cdef struct xmlDoc:
int i
+# mode: compile
+
cdef extern from "excvalcheck.h":
pass
+# mode: compile
+
cdef int spam() except 42:
pass
+# mode: compile
+
cdef int spam() except -1:
eggs = 42
+# mode: compile
+
cdef extern class somewhere.Swallow:
pass
+# mode: compile
+
cdef class Spam:
cdef int tons
+# mode: compile
+
cdef class Grail:
def __add__(int x, float y):
+# mode: compile
+
cdef class Spam:
def __delattr__(self, n):
+# mode: compile
+
cdef class Spam:
def __delitem__(self, i):
+# mode: compile
+
cdef class Spam:
def __delslice__(self, Py_ssize_t i, Py_ssize_t j):
+# mode: compile
+
cdef class Foo:
def __delete__(self, i):
+# mode: compile
+
cdef class Foo:
def __get__(self, i, c):
+# mode: compile
+
cdef class Foo:
def __set__(self, i, v):
+# mode: compile
+
cdef extern int i
cdef extern char *s[]
cdef extern void spam(char c)
+# mode: compile
+
cdef extern class external.Spam [object SpamObject]:
pass
+# mode: compile
+
cdef class Spam
cdef class Grail:
+# mode: compile
+
cdef class Spam:
def __getattr__(self, x):
+# mode: compile
+
cdef class Spam:
def __getitem__(self, x):
+# mode: compile
+
cdef class Spam:
def __hash__(self):
+# mode: compile
+
cdef extern class Spam.Eggs.Ham:
pass
+# mode: compile
+
from crunchytype cimport Crunchy
cdef class Sub2(Crunchy):
+# mode: compile
+
cdef class Spam:
def __index__(self):
+# mode: compile
+
cdef class Parrot:
pass
+# mode: compile
+
cdef class Parrot:
pass
+# mode: compile
+
cdef class Spam:
property eggs:
+# mode: compile
+
cdef class Spam:
property eggs:
+# mode: compile
+
cdef class Spam:
property eggs:
+# mode: compile
+
cdef class Spam:
property eggs:
+# mode: compile
+
cdef class Spam:
property eggs:
+# mode: compile
+
cdef class Spam:
cdef public char c
cdef public int i
+# mode: compile
+
cdef class Spam:
def __setattr__(self, n, x):
+# mode: compile
+
cdef class Spam:
def __setitem__(self, i, x):
+# mode: compile
+
cdef class Spam:
def __setslice__(self, Py_ssize_t i, Py_ssize_t j, x):
+# mode: compile
cimport cython
+# mode: compile
+
def f(a, b, c):
cdef int i
for a in b:
+# mode: compile
+
cdef void spam():
cdef int i, j=0, k=0
for i from 0 <= i < 10:
+# mode: compile
+
cdef int x
x = 42
+# mode: compile
+
def f():
from spam import eggs
from spam.morespam import bacon, eggs, ham
from spam import eggs as ova
-
+ from . import spam
+ from ... import spam
+ from .. import spam, foo
+ from ... import spam, foobar
+ from .spam import foo
+ from ...spam import foo, bar
+ from ...spam.foo import bar
+ from ...spam.foo import foo, bar
+ from ...spam.foo import (foo, bar)
--- /dev/null
+# mode: compile
+
+from spam import *
+from ...spam.foo import *
+from . import *
+from ... import *
+# mode: compile
+
cdef int grail():
cdef int (*spam)()
spam = &grail
--- /dev/null
+# mode: compile
+
+from __future__ import nested_scopes
+
+from __future__ import with_statement
+
+pass
+
+from __future__ import nested_scopes ; from __future__ import nested_scopes
+# mode: compile
+
def f(x, y):
x = y
+# mode: compile
+
global __name__
print __name__
+# mode: compile
+
def f():
global a,b,c,d
a = b
+# mode: compile
+
cdef int a_global_int
cdef a_global_pyobject
+# mode: compile
+
ctypedef enum someenum_t:
ENUMVALUE_1
ENUMVALUE_2
+# mode: compile
+
cdef class vector:
def __div__(vector self, double factor):
cdef object result = vector()
+# mode: compile
+
cdef enum Color:
red
white
+# mode: compile
+
cdef:
struct PrivFoo:
+# mode: compile
+
def f():
import spam
import spam.eggs
+# mode: compile
+
def f(obj1, obj2, obj3):
cdef int int1, int2=0, int3=0
cdef float flt1, *ptr1=NULL
+# mode: compile
+
cdef int* a
cdef object x
+# mode: compile
+
cdef class A:
def __getitem__(self, x):
+# mode: compile
+
cdef void __stdcall f():
pass
+# mode: compile
+
cdef class Position
cdef class Point(Position)
cdef class Vector(Point)
+# mode: compile
+
cdef class A:
cdef object x
+# mode: compile
+
def f():
cdef int i=0
global mylist
+# mode: compile
+
cdef extern from "string.h":
void memcpy(void* des, void* src, int size)
+# mode: compile
+
ctypedef enum foo:
FOO
+# mode: compile
+
cdef class C:
cdef object foo
+# mode: compile
+
cdef class T:
cdef int a[1]
+# mode: compile
+
def f(x,):
pass
+# mode: compile
+
ctypedef struct BB:
void (*f) (void* state)
+# mode: compile
+
cimport libc
cimport libc.stdio
+# mode: compile
+
from libc.errno cimport *
if errno == EDOM : pass
+# mode: compile
+
from libc.math cimport (M_E, M_LOG2E, M_LOG10E, M_LN2, M_LN10, M_PI, M_PI_2,
M_PI_4, M_1_PI, M_2_PI, M_2_SQRTPI, M_SQRT2, M_SQRT1_2)
from libc.math cimport (acos, asin, atan, atan2, cos, sin, tan, cosh, sinh,
+# mode: compile
+
from libc.signal cimport *
cdef void sighdl(int signum) nogil:
+# mode: compile
+
cdef extern unsigned long x
cdef extern long unsigned y
+# mode: compile
+
cdef void foo():
cdef int bool, int1=0, int2=0
bool = int1 < int2
+# mode: compile
+
"""A long module docstring.\r
\r
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sit amet\r
+# mode: compile
+
cdef extern object g(object x) nogil
cdef extern void g2(object x) nogil
+# mode: compile
+
cdef class spam:
pass
+# mode: compile
+
cdef void spam():
eggs = None
+# mode: compile
+
cdef extern class external.Spam [object Spam]: pass
cdef extern class external.Eggs [object Eggs]: pass
+# mode: compile
+
cdef char *p1
cdef int *p2
cdef int x
+# mode: compile
+
cdef extern void spam(int, char *)
+# mode: compile
+
__doc__ = u"""
>>> fiches_CP
[]
+# tag: posix
+# mode: compile
+
cimport posix
cimport posix.unistd
--- /dev/null
+# mode: compile
+# --
+
+ctypedef int Int0
+ctypedef api int Int1
+
+ctypedef enum EnumA0: EA0
+ctypedef api enum EnumA1: EA1
+
+cdef enum EnumB0: EB0=0
+cdef api enum EnumB1: EB1=1
+
+cdef Int0 i0 = 0
+cdef EnumA0 ea0 = EA0
+cdef EnumB0 eb0 = EB0
+
+cdef api Int1 i1 = 0
+cdef api EnumA1 ea1 = EA1
+cdef api EnumB1 eb1 = EB1
+
+# --
+
+ctypedef struct StructA0:
+ int SA0
+ctypedef api struct StructA1:
+ int SA1
+
+cdef struct StructB0:
+ int SB0
+cdef api struct StructB1:
+ int SB1
+
+cdef StructA0 sa0 = {'SA0':0}
+cdef StructB0 sb0 = {'SB0':2}
+
+cdef api StructA1 sa1 = {'SA1':1}
+cdef api StructB1 sb1 = {'SB1':3}
+
+# --
+
+ctypedef class Foo0: pass
+ctypedef api class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+
+cdef class Bar0: pass
+cdef api class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+
+cdef Foo0 f0 = None
+cdef Bar0 b0 = None
+
+cdef api Foo1 f1 = None
+cdef api Bar1 b1 = None
+
+# --
+
+cdef void bar0(): pass
+cdef api void bar1(): pass
+
+cdef void* spam0(object o) except NULL: return NULL
+cdef api void* spam1(object o) except NULL: return NULL
+
+bar0()
+bar1()
+spam0(None)
+spam1(None)
+
+# --
--- /dev/null
+# mode: compile
+# --
+
+ctypedef int Int0
+ctypedef public int Int1
+ctypedef api int Int2
+ctypedef public api int Int3
+
+ctypedef enum EnumA0: EA0
+ctypedef public enum EnumA1: EA1
+ctypedef api enum EnumA2: EA2
+ctypedef public api enum EnumA3: EA3
+
+cdef enum EnumB0: EB0=0
+cdef public enum EnumB1: EB1=1
+cdef api enum EnumB2: EB2=2
+cdef public api enum EnumB3: EB3=3
+
+# --
+
+ctypedef struct StructA0:
+ int SA0
+ctypedef public struct StructA1:
+ int SA1
+ctypedef api struct StructA2:
+ int SA2
+ctypedef public api struct StructA3:
+ int SA3
+
+cdef struct StructB0:
+ int SB0
+cdef public struct StructB1:
+ int SB1
+cdef api struct StructB2:
+ int SB2
+cdef public api struct StructB3:
+ int SB3
+
+# --
+
+ctypedef class Foo0: pass
+ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+ctypedef api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
+ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
+
+cdef class Bar0: pass
+cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+cdef api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
+cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
+
+# --
+
+cdef void bar0(): pass
+cdef public void bar1(): pass
+cdef api void bar2(): pass
+cdef public api void bar3(): pass
+
+cdef void* spam0(object o) except NULL: return NULL
+cdef public void* spam1(object o) except NULL: return NULL
+cdef api void* spam2(object o) except NULL: return NULL
+cdef public api void* spam3(object o) except NULL: return NULL
+
+bar0()
+spam0(None)
+
+# --
+
+cdef double d0 = 0
+cdef public double d1 = 1
+cdef api double d2 = 2
+cdef public api double d3 = 3
+
+cdef object o0 = None
+cdef public object o1 = None
+cdef api object o2 = None
+cdef public api object o3 = None
+
+# --
--- /dev/null
+# mode: compile
+# --
+
+ctypedef int Int0
+ctypedef public int Int1
+
+ctypedef enum EnumA0: EA0
+ctypedef public enum EnumA1: EA1
+
+cdef enum EnumB0: EB0=0
+cdef public enum EnumB1: EB1=1
+
+cdef Int0 i0 = 0
+cdef EnumA0 ea0 = EA0
+cdef EnumB0 eb0 = EB0
+
+cdef public Int1 i1 = 0
+cdef public EnumA1 ea1 = EA1
+cdef public EnumB1 eb1 = EB1
+
+# --
+
+ctypedef struct StructA0:
+ int SA0
+ctypedef public struct StructA1:
+ int SA1
+
+cdef struct StructB0:
+ int SB0
+cdef public struct StructB1:
+ int SB1
+
+cdef StructA0 sa0 = {'SA0':0}
+cdef StructB0 sb0 = {'SB0':2}
+
+cdef public StructA1 sa1 = {'SA1':1}
+cdef public StructB1 sb1 = {'SB1':3}
+
+# --
+
+ctypedef class Foo0: pass
+ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+
+cdef class Bar0: pass
+cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+
+cdef Foo0 f0 = None
+cdef Bar0 b0 = None
+
+cdef public Foo1 f1 = None
+cdef public Bar1 b1 = None
+
+# --
+
+cdef void bar0(): pass
+cdef public void bar1(): pass
+
+cdef void* spam0(object o) except NULL: return NULL
+cdef public void* spam1(object o) except NULL: return NULL
+
+bar0()
+bar1()
+spam0(None)
+spam1(None)
+
+# --
--- /dev/null
+# --
+
+ctypedef int Int0
+ctypedef public int Int1
+ctypedef api int Int2
+ctypedef public api int Int3
+
+ctypedef enum EnumA0: EA0
+ctypedef public enum EnumA1: EA1
+ctypedef api enum EnumA2: EA2
+ctypedef public api enum EnumA3: EA3
+
+cdef enum EnumB0: EB0=0
+cdef public enum EnumB1: EB1=1
+cdef api enum EnumB2: EB2=2
+cdef public api enum EnumB3: EB3=3
+
+# --
+
+ctypedef struct StructA0:
+ int SA0
+ctypedef public struct StructA1:
+ int SA1
+ctypedef api struct StructA2:
+ int SA2
+ctypedef public api struct StructA3:
+ int SA3
+
+cdef struct StructB0:
+ int SB0
+cdef public struct StructB1:
+ int SB1
+cdef api struct StructB2:
+ int SB2
+cdef public api struct StructB3:
+ int SB3
+
+# --
+
+ctypedef class Foo0: pass
+ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
+ctypedef api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
+ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
+
+cdef class Bar0: pass
+cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
+cdef api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
+cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
+
+# --
+
+cdef inline void bar0(): pass
+cdef public void bar1()
+cdef api void bar2()
+cdef public api void bar3()
+
+cdef inline void* spam0(object o) except NULL: return NULL
+cdef public void* spam1(object o) except NULL
+cdef api void* spam2(object o) nogil except NULL
+cdef public api void* spam3(object o) except NULL with gil
+
+# --
+
+#cdef public int i1
+#cdef api int i2
+#cdef public api int i3
+
+# --
--- /dev/null
+# mode: compile
+
+cdef class Foo1: pass
+cdef class Foo2: pass
+cdef class Foo3: pass
+
+cdef class Bar1: pass
+cdef class Bar2: pass
+cdef class Bar3: pass
+
+cdef public void bar1(): pass
+cdef api void bar2(): pass
+cdef public api void bar3(): pass
+
+cdef public void* spam1(object o) except NULL: return NULL
+cdef api void* spam2(object o) nogil except NULL: return NULL
+cdef public api void* spam3(object o) except NULL with gil: return NULL
+# mode: compile
+
class A:
def foo(self):
return "A"
+# mode: compile
+
class Spam:
def eggs(self):
+# mode: compile
+
cdef extern from "Python.h":
ctypedef struct PyTypeObject:
pass
+# mode: compile
+
__doc__ = u"""
>>> main()
3.14159265358979323846
+# mode: compile
+
cdef struct S:
char c
unsigned char uc
+# mode: compile
+
def f(a, b, c, d, e, f, g, h, i):
a = b[c:d, e:f:g, ..., h, :i:]
+# mode: compile
+
DEF nan = float('nan')
DEF inf = float('inf')
DEF minf = -float('inf')
+# mode: compile
+
cdef class Grail:
def __cinit__(self, spam = None):
+# mode: compile
+
cdef class C:
def __cinit__(self):
"This is an unusable docstring."
+# mode: compile
+
cdef class Spam:
cdef int eggs
+# mode: compile
+
def spam():
raise Exception
+# mode: compile
+
def f(a, b, c, x):
cdef int i
a = b + c
+# mode: compile
+
def f(a, b, c, x):
cdef int i
a = b + c
+# mode: compile
+
cdef void f(obj):
cdef size_t i=0
cdef char *p
+# mode: compile
+
print sizeof(point*)
cdef foo(int i0, int i, list L0, list L, point p0, point p, point* ps):
+# mode: compile
+
cdef int x
x = 0xFFFFFFFF
+# ticket: 276
+# mode: compile
+
__doc__ = u"""
"""
+# mode: compile
+
def f(a, b):
cdef int i = 5
+# mode: compile
+
cdef void f() with gil:
x = 42
+# mode: error
break
_ERRORS = u'''
-2:0: break statement not inside loop
-5:4: break statement not inside loop
-8:4: break statement not inside loop
-11:4: break statement not inside loop
-16:5: break statement not inside loop
-20:4: break statement not inside loop
-22:4: break statement not inside loop
+3:0: break statement not inside loop
+6:4: break statement not inside loop
+9:4: break statement not inside loop
+12:4: break statement not inside loop
+17:5: break statement not inside loop
+21:4: break statement not inside loop
+23:4: break statement not inside loop
'''
+# ticket: 117
+# mode: error
+
ctypedef object[float] mybuffer
_ERRORS = u"""
-1:23: Syntax error in ctypedef statement
+4:23: Syntax error in ctypedef statement
"""
+# mode: error
# current restriction: cannot inherit from PyVarObject (see ticket #152)
pass
_ERRORS = """
-4:5: inheritance from PyVarObject types like 'tuple' is not currently supported
-7:5: inheritance from PyVarObject types like 'bytes' is not currently supported
-10:5: inheritance from PyVarObject types like 'str' is not currently supported
+5:5: inheritance from PyVarObject types like 'tuple' is not currently supported
+8:5: inheritance from PyVarObject types like 'bytes' is not currently supported
+11:5: inheritance from PyVarObject types like 'str' is not currently supported
"""
+# mode: error
+
def f(*args, **kwargs):
pass
# too bad we don't get more errors here ...
_ERRORS = u"""
-8:13: Non-keyword arg following star-arg
+10:13: Non-keyword arg following star-arg
"""
+# ticket: 307
+# mode: error
+
nonexisting(3, with_kw_arg=4)
_ERRORS = u"""
-1:11: undeclared name not builtin: nonexisting
+4:11: undeclared name not builtin: nonexisting
"""
+# ticket: 517
+# mode: error
+
ctypedef void* VoidP
cdef class Spam:
pass
_ERRORS = u"""
-5:24: C attribute of type 'VoidP' cannot be accessed from Python
-5:24: Cannot convert 'VoidP' to Python object
-6:24: C attribute of type 'VoidP' cannot be accessed from Python
-6:24: Cannot convert 'VoidP' to Python object
-6:24: Cannot convert Python object to 'VoidP'
-14:22: C attribute of type 'Foo' cannot be accessed from Python
-14:22: Cannot convert Python object to 'Foo'
+8:24: C attribute of type 'VoidP' cannot be accessed from Python
+8:24: Cannot convert 'VoidP' to Python object
+9:24: C attribute of type 'VoidP' cannot be accessed from Python
+9:24: Cannot convert 'VoidP' to Python object
+9:24: Cannot convert Python object to 'VoidP'
+17:22: C attribute of type 'Foo' cannot be accessed from Python
+17:22: Cannot convert Python object to 'Foo'
"""
+# mode: error
cdef pass
cdef void
cdef nogil class test: pass
_ERRORS = u"""
- 2: 5: Expected an identifier, found 'pass'
- 3: 9: Empty declarator
- 4:11: Expected ':', found 'class'
+3: 5: Expected an identifier, found 'pass'
+4: 9: Empty declarator
+5:11: Expected ':', found 'class'
"""
+# mode: error
+
__doc__ = u"""
>>> call2()
>>> call3()
+# mode: error
+
def call5():
b(1,2,3,4,5)
pass
_ERRORS = u"""
-2:5:Call with wrong number of arguments (expected at most 4, got 5)
+4:5:Call with wrong number of arguments (expected at most 4, got 5)
"""
+# mode: error
cdef class Test:
cdef __cinit__(self):
pass
_ERRORS = u"""
-3:9: Special methods must be declared with 'def', not 'cdef'
-6:9: Special methods must be declared with 'def', not 'cdef'
+4:9: Special methods must be declared with 'def', not 'cdef'
+7:9: Special methods must be declared with 'def', not 'cdef'
"""
+# mode: error
+
cdef class C:
cdef void f(self):
pass
pass
_ERRORS = u"""
-6: 9: Signature not compatible with previous declaration
-2: 9: Previous declaration is here
+8: 9: Signature not compatible with previous declaration
+4: 9: Previous declaration is here
"""
+# ticket: 370
+# mode: error
cdef int raiseit():
raise IndexError
+# mode: error
continue
return True
_ERRORS = u'''
-2:0: continue statement not inside loop
-5:4: continue statement not inside loop
-8:4: continue statement not inside loop
-11:4: continue statement not inside loop
-16:5: continue statement not inside loop
-20:4: continue statement not inside loop
-22:4: continue statement not inside loop
+3:0: continue statement not inside loop
+6:4: continue statement not inside loop
+9:4: continue statement not inside loop
+12:4: continue statement not inside loop
+17:5: continue statement not inside loop
+21:4: continue statement not inside loop
+23:4: continue statement not inside loop
'''
+# mode: error
cpdef nogil: pass
cpdef nogil class test: pass
_ERRORS = u"""
- 2: 6: cdef blocks cannot be declared cpdef
- 3: 6: cdef blocks cannot be declared cpdef
- 3:12: Expected ':', found 'class'
+3: 6: cdef blocks cannot be declared cpdef
+4: 6: cdef blocks cannot be declared cpdef
+4:12: Expected ':', found 'class'
"""
+# tag: cpp
+# mode: error
+
cdef extern from *:
cdef cppclass Foo:
Foo()
new Foo(1, 2)
_ERRORS = u"""
-6:7: no suitable method found
+9:7: no suitable method found
"""
+# mode: error
# -*- coding: utf-8 -*-
# cython: language_level=3
invalid = b'abcüöä'
_ERRORS = """
-5:10: bytes can only contain ASCII literal characters.
+6:10: bytes can only contain ASCII literal characters.
"""
+# ticket: 158
+# mode: error
+
def mult_decl_test():
print "%s" % vv
print "%s" % s
# in 0.11.1 these are warnings
FUTURE_ERRORS = u"""
-4:13: cdef variable 's' declared after it is used
-4:16: cdef variable 'vv' declared after it is used
-9:14: cdef variable 'i' declared after it is used
-15:14: cdef variable 'i' declared after it is used
-21:14: cdef variable 'i' declared after it is used
-24:9: cdef variable 's' declared after it is used
-30:17: cdef variable 't' declared after it is used
-34:13: cdef variable 'r' declared after it is used
-40:17: cdef variable 't' declared after it is used
-47:10: cdef variable 'baz' declared after it is used
-50:24: cdef variable 'var' declared after it is used
+6:13: cdef variable 's' declared after it is used
+6:16: cdef variable 'vv' declared after it is used
+11:14: cdef variable 'i' declared after it is used
+17:14: cdef variable 'i' declared after it is used
+23:14: cdef variable 'i' declared after it is used
+26:9: cdef variable 's' declared after it is used
+32:17: cdef variable 't' declared after it is used
+36:13: cdef variable 'r' declared after it is used
+42:17: cdef variable 't' declared after it is used
+49:10: cdef variable 'baz' declared after it is used
+52:24: cdef variable 'var' declared after it is used
"""
syntax error
_ERRORS = u"""
-40:17: cdef variable 't' declared after it is used
-47:10: cdef variable 'baz' declared after it is used
-50:24: cdef variable 'var' declared after it is used
-67:7: Syntax error in simple statement list
+42:17: cdef variable 't' declared after it is used
+49:10: cdef variable 'baz' declared after it is used
+52:24: cdef variable 'var' declared after it is used
+70:7: Syntax error in simple statement list
"""
+# mode: error
def test() nogil:
pass
_ERRORS = """
-2:0: Python function cannot be declared nogil
+3:0: Python function cannot be declared nogil
"""
+# ticket: 290
+# mode: error
+
cdef packed foo:
pass
_ERRORS = u"""
-1:12: Expected 'struct', found 'foo'
+4:12: Expected 'struct', found 'foo'
"""
+# mode: error
+
def f():
cdef int int1, int3
cdef int *ptr1, *ptr2, *ptr3
ptr1 = ptr2 + ptr3 # error
_ERRORS = u"""
-4:13: Invalid operand types for '+' (int *; int *)
+6:13: Invalid operand types for '+' (int *; int *)
"""
+# mode: error
+
cdef spam(int i, char *s = "blarg", float f): # can't have default value
pass
pass
_ERRORS = u"""
-1:10: Non-default argument follows default argument
-1:36: Non-default argument following default argument
-4:23: Non-default argument following default argument
-9:16: This argument cannot have a default value
+3:10: Non-default argument follows default argument
+3:36: Non-default argument following default argument
+6:23: Non-default argument following default argument
+11:16: This argument cannot have a default value
"""
+# mode: error
+
cdef void foo(obj):
cdef int i1
cdef char *p1
obj = p2 # error
_ERRORS = u"""
-5:16: Cannot assign type 'char *' to 'int'
-6:17: Cannot convert Python object to 'int *'
-8:17: Cannot convert 'int *' to Python object
+7:16: Cannot assign type 'char *' to 'int'
+8:17: Cannot convert Python object to 'int *'
+10:17: Cannot convert 'int *' to Python object
"""
+# mode: error
+
cdef void spam():
None = 42
_ERRORS = u"""
-2:1: Cannot assign to or delete this
+4:1: Cannot assign to or delete this
"""
+# mode: error
+
cimport cython
@cython.autotestdict(False)
pass
_ERRORS = u"""
-4:0: The autotestdict compiler directive is not allowed in function scope
+6:0: The autotestdict compiler directive is not allowed in function scope
"""
+# mode: error
+
cdef char *spam() except -1:
pass
_ERRORS = u"""
-1:26: Cannot assign type 'long' to 'char *'
-1:26: Exception value incompatible with function return type
+3:26: Cannot assign type 'long' to 'char *'
+3:26: Exception value incompatible with function return type
"""
+# mode: error
+
cdef struct Spam
cdef extern int spam(void) # function argument cannot be void
pass
_ERRORS = u"""
-3:21: Use spam() rather than spam(void) to declare a function with no arguments.
-4:29: Use spam() rather than spam(void) to declare a function with no arguments.
-5:16: Argument type 'Spam' is incomplete
+5:21: Use spam() rather than spam(void) to declare a function with no arguments.
+6:29: Use spam() rather than spam(void) to declare a function with no arguments.
+7:16: Argument type 'Spam' is incomplete
"""
+# mode: error
+
cdef struct Foo
def f(Foo *p):
pass
_ERRORS = u"""
-3:6: Cannot convert Python object argument to type 'Foo *'
+5:6: Cannot convert Python object argument to type 'Foo *'
"""
+# mode: error
+
cdef struct Grail
cdef extern object xobj # Python object cannot be extern
ptr = None # This should not produce another error
_ERRORS = u"""
-3:19: Python object cannot be declared extern
-4:16: Array element cannot be a Python object
-5:12: Pointer base type cannot be a Python object
-7:13: Variable type 'int []' is incomplete
-8:11: Variable type 'Grail' is incomplete
-9:10: Variable type 'void' is incomplete
-11:15: Array element type 'int []' is incomplete
-12:14: Array element type 'Grail' is incomplete
-13:16: Array element type 'void' is incomplete
-16:9: Variable type 'int []' is incomplete
+5:19: Python object cannot be declared extern
+6:16: Array element cannot be a Python object
+7:12: Pointer base type cannot be a Python object
+9:13: Variable type 'int []' is incomplete
+10:11: Variable type 'Grail' is incomplete
+11:10: Variable type 'void' is incomplete
+13:15: Array element type 'int []' is incomplete
+14:14: Array element type 'Grail' is incomplete
+15:16: Array element type 'void' is incomplete
+18:9: Variable type 'int []' is incomplete
#19:1: Function argument cannot be void
-19:1: Use spam() rather than spam(void) to declare a function with no arguments.
-18:7: Argument type 'Grail' is incomplete
-19:1: Invalid use of 'void'
-23:5: 'NoSuchType' is not a type identifier
+21:1: Use spam() rather than spam(void) to declare a function with no arguments.
+20:7: Argument type 'Grail' is incomplete
+21:1: Invalid use of 'void'
+25:5: 'NoSuchType' is not a type identifier
"""
+# mode: error
+
def f():
cdef int int1, int2
cdef char *ptr
int1 = int2 | ptr # error
_ERRORS = u"""
-4:13: Invalid operand types for '|' (int; char *)
+6:13: Invalid operand types for '|' (int; char *)
"""
+# mode: error
+
ctypedef struct struct_type_not_boolean:
int i
float f
_ERRORS = u"""
-5:26: 'struct_type_not_boolean' is not a constant, variable or function identifier
-5:26: Type 'struct_type_not_boolean' not acceptable as a boolean
+7:26: 'struct_type_not_boolean' is not a constant, variable or function identifier
+7:26: Type 'struct_type_not_boolean' not acceptable as a boolean
-12:21: 'struct_not_boolean' is not a constant, variable or function identifier
-12:21: Type 'struct_not_boolean' not acceptable as a boolean
+14:21: 'struct_not_boolean' is not a constant, variable or function identifier
+14:21: Type 'struct_not_boolean' not acceptable as a boolean
-19:25: 'union_type_not_boolean' is not a constant, variable or function identifier
-19:25: Type 'union_type_not_boolean' not acceptable as a boolean
+21:25: 'union_type_not_boolean' is not a constant, variable or function identifier
+21:25: Type 'union_type_not_boolean' not acceptable as a boolean
-26:20: 'union_not_boolean' is not a constant, variable or function identifier
-26:20: Type 'union_not_boolean' not acceptable as a boolean
+28:20: 'union_not_boolean' is not a constant, variable or function identifier
+28:20: Type 'union_not_boolean' not acceptable as a boolean
"""
+# mode: error
+
cdef object[int] buf
cdef class A:
cdef object[int] buf
cdef object[x, 1] buf0
_ERRORS = u"""
-1:17: Buffer types only allowed as function local variables
-3:21: Buffer types only allowed as function local variables
-6:31: "fakeoption" is not a buffer option
+3:17: Buffer types only allowed as function local variables
+5:21: Buffer types only allowed as function local variables
+8:31: "fakeoption" is not a buffer option
"""
#TODO:
#7:22: "ndim" must be non-negative
+# mode: error
+
cimport e_bufaccess_pxd # was needed to provoke a bug involving ErrorType
import cython
buf = x
_ERRORS = u"""
-3:9: 'nothing' is not a type identifier
-10:11: Cannot check buffer index bounds without gil; use boundscheck(False) directive
-22:11: Cannot access buffer with object dtype without gil
-22:11: Assignment of Python object not allowed without gil
-27:12: Assignment of Python object not allowed without gil
+ 3: 9: 'nothing' is not a type identifier
+12:11: Cannot check buffer index bounds without gil; use boundscheck(False) directive
+24:11: Cannot access buffer with object dtype without gil
+24:11: Assignment of Python object not allowed without gil
+29:12: Assignment of Python object not allowed without gil
"""
+# mode: error
+
cdef int i
i()
x()()
_ERRORS = u"""
-2:1: Calling non-function type 'int'
-5:1: Calling non-function type 'float'
-14:3: Calling non-function type 'int'
+4:1: Calling non-function type 'int'
+7:1: Calling non-function type 'float'
+16:3: Calling non-function type 'int'
"""
+# mode: error
+
cimport cython
@cython.callspec("")
#p2 = h4 # fail
_ERRORS = u"""
-16:22: cannot have both '__stdcall' and '__cdecl' calling conventions
-19:23: cannot have both '__fastcall' and '__cdecl' calling conventions
+18:22: cannot have both '__stdcall' and '__cdecl' calling conventions
+21:23: cannot have both '__fastcall' and '__cdecl' calling conventions
"""
#31:14: Cannot assign type 'void (__cdecl )(void)' to 'void (*)(void)'
#32:14: Cannot assign type 'void (__stdcall )(void)' to 'void (*)(void)'
+# ticket: 241
+# mode: error
+
cdef some_function(x, y):
pass
a.some_method(1, y=2)
_ERRORS = u"""
-9:13: Keyword and starred arguments not allowed in cdef functions.
-14:13: Keyword and starred arguments not allowed in cdef functions.
+12:13: Keyword and starred arguments not allowed in cdef functions.
+17:13: Keyword and starred arguments not allowed in cdef functions.
"""
+# mode: error
+
cdef int
cdef extern from *:
void f(int)
_ERRORS = u"""
-1:8: Empty declarator
+3:8: Empty declarator
"""
+# mode: error
+
cdef class A:
cdef int value = 3
int value = 3
_ERRORS = u"""
-2:13: Cannot assign default value to fields in cdef classes, structs or unions
-6:12: Cannot assign default value to fields in cdef classes, structs or unions
+4:13: Cannot assign default value to fields in cdef classes, structs or unions
+8:12: Cannot assign default value to fields in cdef classes, structs or unions
"""
+# mode: error
+
cdef struct spam:
pass
cdef enum ham:
pass
_ERRORS = u"""
-1:5: Empty struct or union definition not allowed outside a 'cdef extern from' block
-4:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
-7:5: Empty enum definition not allowed outside a 'cdef extern from' block
+3:5: Empty struct or union definition not allowed outside a 'cdef extern from' block
+6:0: Empty struct or union definition not allowed outside a 'cdef extern from' block
+9:5: Empty enum definition not allowed outside a 'cdef extern from' block
"""
+# mode: error
+
cdef enum Spam:
a, b, c
a = 42 # assignment to non-lvalue
_ERRORS = u"""
-6:3: Assignment to non-lvalue 'a'
+8:3: Assignment to non-lvalue 'a'
"""
+# mode: error
+
cdef class C:
cdef void f(self):
pass
cdef void f(self, int x):
pass
_ERRORS = u"""
-6:6: Signature not compatible with previous declaration
-2:6: Previous declaration is here
+8:6: Signature not compatible with previous declaration
+4:6: Previous declaration is here
"""
+# mode: error
+
cdef void foo():
cdef int bool, int1
cdef char *ptr2
bool = 1 in 2 in 3
_ERRORS = u"""
- 8:13: Invalid types for '==' (int *, Python object)
- 9:13: Invalid types for '==' (int, char *)
-10:13: Invalid types for '==' (char *, int *)
+10:13: Invalid types for '==' (int *, Python object)
+11:13: Invalid types for '==' (int, char *)
+12:13: Invalid types for '==' (char *, int *)
"""
+# mode: error
+
cdef struct Spam:
int i
char c
_ERRORS = u"""
-5:36: C struct/union member cannot be a Python object
-15:6: Object of type 'Spam' has no attribute 'k'
-16:6: Cannot assign type 'float *[42]' to 'int'
-17:21: Cannot assign type 'int' to 'float *[42]'
-20:7: Cannot select attribute of incomplete type 'Grail'
-21:3: Cannot select attribute of incomplete type 'Grail'
+7:36: C struct/union member cannot be a Python object
+17:6: Object of type 'Spam' has no attribute 'k'
+18:6: Cannot assign type 'float *[42]' to 'int'
+19:21: Cannot assign type 'int' to 'float *[42]'
+22:7: Cannot select attribute of incomplete type 'Grail'
+23:3: Cannot select attribute of incomplete type 'Grail'
"""
+# mode: error
+
ctypedef struct Spam
cdef extern from *:
ctypedef struct Spam
_ERRORS = u"""
-1:0: Forward-referenced type must use 'cdef', not 'ctypedef'
+3:0: Forward-referenced type must use 'cdef', not 'ctypedef'
"""
+# mode: error
+
cdef struct Foo
ctypedef struct Foo:
cdef Blarg b
_ERRORS = u"""
-3:0: 'Foo' previously declared using 'cdef'
-9:5: 'Blarg' previously declared using 'ctypedef'
+5:0: 'Foo' previously declared using 'cdef'
+11:5: 'Blarg' previously declared using 'ctypedef'
"""
+# mode: error
+
cdef extern void fa[5]()
cdef extern int af()[5]
cdef extern int ff()()
_ERRORS = u"""
-1:19: Array element cannot be a function
-3:18: Function cannot return a function
-8:10: Function cannot return a function
-8:5: Cannot cast to a function type
+3:19: Array element cannot be a function
+5:18: Function cannot return a function
+10:10: Function cannot return a function
+10:5: Cannot cast to a function type
"""
+# mode: error
_ERRORS = u"""
4:4 Expected a newline after decorator
+# mode: error
+
cdef struct S:
int m
del x[i] # error: deletion of non-Python object
del s.m # error: deletion of non-Python object
_ERRORS = u"""
-8:6: Cannot assign to or delete this
-9:45: Deletion of non-Python, non-C++ object
-11:6: Deletion of non-Python, non-C++ object
-12:6: Deletion of non-Python, non-C++ object
+10:6: Cannot assign to or delete this
+11:45: Deletion of non-Python, non-C++ object
+13:6: Deletion of non-Python, non-C++ object
+14:6: Deletion of non-Python, non-C++ object
"""
+# mode: error
# cython: nonexistant = True
# cython: boundscheck = true
# cython: boundscheck = true
_ERRORS = u"""
-3:0: boundscheck directive must be set to True or False, got 'true'
-4:0: boundscheck directive must be set to True or False, got '9'
+4:0: boundscheck directive must be set to True or False, got 'true'
+5:0: boundscheck directive must be set to True or False, got '9'
"""
+# mode: error
try:
raise KeyError
pass
_ERRORS = u"""
-8:0: default 'except:' must be last
-10:0: default 'except:' must be last
+9:0: default 'except:' must be last
+11:0: default 'except:' must be last
"""
+# mode: error
+
ctypedef int (*spamfunc)(int, char *) except 42
ctypedef int (*grailfunc)(int, char *)
grail = spam # type mismatch
spam = grail # type mismatch
_ERRORS = u"""
-7:28: Cannot assign type 'spamfunc' to 'grailfunc'
-8:28: Cannot assign type 'grailfunc' to 'spamfunc'
+9:28: Cannot assign type 'spamfunc' to 'grailfunc'
+10:28: Cannot assign type 'grailfunc' to 'spamfunc'
"""
+# mode: error
+
cdef class C:
cdef object __weakref__
x = c.__weakref__
c.__weakref__ = x
_ERRORS = u"""
-5:20: Illegal use of special attribute __weakref__
-5:20: Illegal use of special attribute __weakref__
-5:20: Illegal use of special attribute __weakref__
-5:20: Special attribute __weakref__ cannot be exposed to Python
-8:22: Illegal use of special attribute __weakref__
-8:22: Special attribute __weakref__ cannot be exposed to Python
-13:6: Illegal use of special attribute __weakref__
-14:2: Illegal use of special attribute __weakref__
+7:20: Illegal use of special attribute __weakref__
+7:20: Illegal use of special attribute __weakref__
+7:20: Illegal use of special attribute __weakref__
+7:20: Special attribute __weakref__ cannot be exposed to Python
+10:22: Illegal use of special attribute __weakref__
+10:22: Special attribute __weakref__ cannot be exposed to Python
+15:6: Illegal use of special attribute __weakref__
+16:2: Illegal use of special attribute __weakref__
"""
+# mode: error
+
cimport e_func_in_pxd_support
_ERRORS = u"""
--- /dev/null
+# mode: error
+
+def foo():
+ yield
+ return 0
+
+def bar(a):
+ return 0
+ yield
+
+yield
+
+class Foo:
+ yield
+
+_ERRORS = u"""
+5:4: 'return' with argument inside generator
+9:4: 'yield' outside function
+11:0: 'yield' not supported here
+14:4: 'yield' not supported here
+"""
+# mode: error
+
def f(obj1, obj2):
cdef int int1, int2, int3
cdef float flt1, *ptr1
int1 = int2[int3] # error
obj1 = obj2[ptr1] # error
_ERRORS = u"""
-5:14: Invalid index type 'float'
-6:14: Invalid index type 'float *'
-7:12: Attempting to index non-array type 'int'
-8:17: Cannot convert 'float *' to Python object
+7:14: Invalid index type 'float'
+8:14: Invalid index type 'float *'
+9:12: Attempting to index non-array type 'int'
+10:17: Cannot convert 'float *' to Python object
"""
+# mode: error
# cython: language_level=2
def int_literals():
_ERRORS = """
-6:8: illegal integer literal syntax in Python source file
7:8: illegal integer literal syntax in Python source file
8:8: illegal integer literal syntax in Python source file
+9:8: illegal integer literal syntax in Python source file
"""
+# mode: error
# cython: language_level=3
def int_literals():
_ERRORS = """
-4:8: illegal integer literal syntax in Python source file
5:8: illegal integer literal syntax in Python source file
6:8: illegal integer literal syntax in Python source file
7:8: illegal integer literal syntax in Python source file
8:8: illegal integer literal syntax in Python source file
+9:8: illegal integer literal syntax in Python source file
"""
+# mode: error
+
def f(obj1a, obj1b):
cdef int int1, int2, int3
cdef int *ptr2
int1, int3, obj1a = int2, ptr2, obj1b # error
_ERRORS = u"""
-4:31: Cannot assign type 'int *' to 'int'
+6:31: Cannot assign type 'int *' to 'int'
"""
+# mode: error
+
cdef extern grail(char *s, int i)
cdef extern spam(char *s, int i,...)
spam() # too few args
spam("blarg") # too few args
_ERRORS = u"""
-5:6: Call with wrong number of arguments (expected 2, got 0)
-6:6: Call with wrong number of arguments (expected 2, got 1)
-7:6: Call with wrong number of arguments (expected 2, got 3)
-8:5: Call with wrong number of arguments (expected at least 2, got 0)
-9:5: Call with wrong number of arguments (expected at least 2, got 1)
+7:6: Call with wrong number of arguments (expected 2, got 0)
+8:6: Call with wrong number of arguments (expected 2, got 1)
+9:6: Call with wrong number of arguments (expected 2, got 3)
+10:5: Call with wrong number of arguments (expected at least 2, got 0)
+11:5: Call with wrong number of arguments (expected at least 2, got 1)
"""
+# mode: error
+
cdef class C:
cdef void f(self) nogil:
pass
_ERRORS = u"""
-2:6: Signature not compatible with previous declaration
2:12: Previous declaration is here
+4: 6: Signature not compatible with previous declaration
"""
+# mode: error
+
cdef extern from *:
cdef void f()
cdef void (*fp)() nogil
fp = f
_ERRORS = u"""
-5:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil'
+7:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil'
"""
--- /dev/null
+# mode: error
+
+def test_non_existant():
+ nonlocal no_such_name
+ no_such_name = 1
+
+def redef():
+ x = 1
+ def f():
+ x = 2
+ nonlocal x
+
+global_name = 5
+
+def ref_to_global():
+ nonlocal global_name
+ global_name = 6
+
+def global_in_class_scope():
+ class Test():
+ nonlocal global_name
+ global_name = 6
+
+def redef_in_class_scope():
+ x = 1
+ class Test():
+ x = 2
+ nonlocal x
+
+
+_ERRORS = u"""
+ 4:4: no binding for nonlocal 'no_such_name' found
+11:8: 'x' redeclared as nonlocal
+16:4: no binding for nonlocal 'global_name' found
+28:8: 'x' redeclared as nonlocal
+"""
+# mode: error
+
cdef signed float e
cdef unsigned float f
cdef signed double g
_ERRORS = u"""
-1:5: Unrecognised type modifier combination
-2:5: Unrecognised type modifier combination
3:5: Unrecognised type modifier combination
4:5: Unrecognised type modifier combination
5:5: Unrecognised type modifier combination
6:5: Unrecognised type modifier combination
+7:5: Unrecognised type modifier combination
+8:5: Unrecognised type modifier combination
"""
+# mode: error
+
cdef extern class Grail.Shrubbery
cdef void spam(Shrubbery sh not None):
pass
_ERRORS = u"""
-3:15: 'not None' only allowed in Python functions
+5:15: 'not None' only allowed in Python functions
"""
+# mode: error
+
def eggs(int x not None, char* y not None):
pass
_ERRORS = u"""
-1: 9: Only Python type arguments can have 'not None'
-1:25: Only Python type arguments can have 'not None'
+3: 9: Only Python type arguments can have 'not None'
+3:25: Only Python type arguments can have 'not None'
"""
+# mode: error
+
def f():
cdef int int1, int2
cdef int *ptr
int1 = int2 * ptr # error
_ERRORS = u"""
-4:13: Invalid operand types for '*' (int; int *)
+6:13: Invalid operand types for '*' (int; int *)
"""
+# ticket: 290
+# mode: error
+
cdef extern:
cdef packed struct MyStruct:
char a
_ERRORS = u"""
-2:9: Cannot declare extern struct as 'packed'
+5:9: Cannot declare extern struct as 'packed'
"""
+# mode: error
+
def f():
cdef char *str1
cdef float flt1, flt2, flt3
flt1 = flt2 ** str1 # error
_ERRORS = u"""
-4:13: Invalid operand types for '**' (char *; float)
-5:13: Invalid operand types for '**' (float; char *)
+6:13: Invalid operand types for '**' (char *; float)
+7:13: Invalid operand types for '**' (float; char *)
"""
+# mode: error
+
cimport e_pxdimpl_imported
_ERRORS = u"""
-6:4: function definition in pxd file must be declared 'cdef inline'
+ 6:4: function definition in pxd file must be declared 'cdef inline'
18:4: function definition in pxd file must be declared 'cdef inline'
23:8: function definition in pxd file must be declared 'cdef inline'
"""
+# mode: error
+
cdef object x
cdef struct spam:
cdef spam s
s.parrot = x
_ERRORS = u"""
-4:8: C struct/union member cannot be a Python object
+6:8: C struct/union member cannot be a Python object
"""
+# mode: error
+
cdef void g():
cdef int i
return i # error
return # error
return p # error
_ERRORS = u"""
-3:17: Return with value in void function
-7:1: Return value required
-8:17: Cannot assign type 'int *' to 'int'
+5:17: Return with value in void function
+9:1: Return value required
+10:17: Cannot assign type 'int *' to 'int'
"""
+# mode: error
+
cdef struct unbekannt
cdef int n
n = sizeof(unbekannt)
_ERRORS = u"""
-3:4: Cannot take sizeof incomplete type 'unbekannt'
+5:4: Cannot take sizeof incomplete type 'unbekannt'
"""
+# mode: error
+
def f(obj2):
cdef int *ptr1
obj1 = obj2[ptr1::] # error
pass
_ERRORS = u"""
-3:20: Cannot convert 'int *' to Python object
-4:21: Cannot convert 'int *' to Python object
-5:22: Cannot convert 'int *' to Python object
-10:16: C array iteration requires known end index
+5:20: Cannot convert 'int *' to Python object
+6:21: Cannot convert 'int *' to Python object
+7:22: Cannot convert 'int *' to Python object
12:16: C array iteration requires known end index
-14:22: C array iteration requires known step size and end index
+14:16: C array iteration requires known end index
+16:22: C array iteration requires known step size and end index
"""
+# mode: error
+
cdef int c1 = "t" # works
cdef int c2 = "te" # fails
cdef int cx = "test" # fails
_ERRORS = """
-2:14: Only single-character string literals can be coerced into ints.
-3:14: Only single-character string literals can be coerced into ints.
-6:15: Only single-character string literals can be coerced into ints.
-9:14: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
+4:14: Only single-character string literals can be coerced into ints.
+5:14: Only single-character string literals can be coerced into ints.
+8:15: Only single-character string literals can be coerced into ints.
+11:14: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
"""
+# mode: error
+
def f():
cdef int int2
cdef char *ptr1, *ptr2, *ptr3
ptr1 = int2 - ptr3 # error
ptr1 = ptr2 - ptr3 # error
_ERRORS = u"""
-4:13: Invalid operand types for '-' (int; char *)
-5:13: Cannot assign type 'int' to 'char *'
+6:13: Invalid operand types for '-' (int; char *)
+7:13: Cannot assign type 'int' to 'char *'
"""
+# mode: error
+
cdef int x = 3
if x == NONEXISTING:
print 34
_ERRORS = u"""
-3:19: undeclared name not builtin: NONEXISTING
+5:19: undeclared name not builtin: NONEXISTING
"""
+# mode: error
+
cdef object blarg
def foo(obj):
p = <void *>(obj + blarg) # error - temporary
_ERRORS = u"""
-6:5: Casting temporary Python object to non-numeric non-Python type
+8:5: Casting temporary Python object to non-numeric non-Python type
"""
+# mode: error
+
cdef class Spam
cdef extern class external.Eggs
_ERRORS = u"""
-1:5: C class 'Spam' is declared but not defined
-2:5: C class 'Eggs' is declared but not defined
+3:5: C class 'Spam' is declared but not defined
+4:5: C class 'Eggs' is declared but not defined
"""
+# mode: error
+
def f():
cdef int int1
cdef char *str2
int1 = -str2 # error
int1 = ~str2 # error
_ERRORS = u"""
-4:8: Invalid operand type for '-' (char *)
-5:8: Invalid operand type for '~' (char *)
+6:8: Invalid operand type for '-' (char *)
+7:8: Invalid operand type for '~' (char *)
"""
+# mode: error
+
def f(a, b):
cdef int i
break # error
continue # error
_ERRORS = u"""
-3:1: break statement not inside loop
-4:1: continue statement not inside loop
+5:1: break statement not inside loop
+6:1: continue statement not inside loop
"""
# coding=ASCII
+# mode: error
"""
Tr\8fs bien.
"""
_ERRORS = u"""
-0:0:Decoding error, missing or incorrect coding=<encoding-name> at top of source ('ascii' codec can't decode byte 0x8f in position 22: ordinal not in range(128))
+0:0:Decoding error, missing or incorrect coding=<encoding-name> at top of source ('ascii' codec can't decode byte 0x8f in position 36: ordinal not in range(128))
"""
+# mode: error
+
__doc__ = u"""
>>> e = ExtClass()
>>> e.get()
_attribute = 5 # FIXME: this is not currently handled!!!
_ERRORS = u"""
-8:13: Cannot assign default value to fields in cdef classes, structs or unions
+10:13: Cannot assign default value to fields in cdef classes, structs or unions
"""
+# mode: error
# invalid syntax (not handled by the parser)
_ERRORS = u"""
# syntax1()
- 7: 4: can use starred expression only as assignment target
- 9: 4: can use starred expression only as assignment target
-11: 4: can use starred expression only as assignment target
-13: 4: can use starred expression only as assignment target
-15: 5: can use starred expression only as assignment target
-15: 9: can use starred expression only as assignment target
-17:11: can use starred expression only as assignment target
-17:24: can use starred expression only as assignment target
+ 8: 4: can use starred expression only as assignment target
+10: 4: can use starred expression only as assignment target
+12: 4: can use starred expression only as assignment target
+14: 4: can use starred expression only as assignment target
+16: 5: can use starred expression only as assignment target
+16: 9: can use starred expression only as assignment target
+18:11: can use starred expression only as assignment target
+18:24: can use starred expression only as assignment target
# syntax2()
-23:11: more than 1 starred expression in assignment
+24:11: more than 1 starred expression in assignment
# types()
-29:15: Cannot coerce list to type 'int'
-30:10: starred target must have Python object (list) type
+30:15: Cannot coerce list to type 'int'
+31:10: starred target must have Python object (list) type
"""
+# mode: error
# wrong size RHS (as handled by the parser)
_ERRORS = u"""
- 5:4: too many values to unpack (expected 2, got 3)
- 8:4: need more than 1 value to unpack
-11:4: need more than 0 values to unpack
-14:4: need more than 0 values to unpack
-17:4: need more than 0 values to unpack
-18:4: need more than 1 value to unpack
-21:6: need more than 1 value to unpack
+6:4: too many values to unpack (expected 2, got 3)
+9:4: need more than 1 value to unpack
+12:4: need more than 0 values to unpack
+15:4: need more than 0 values to unpack
+18:4: need more than 0 values to unpack
+19:4: need more than 1 value to unpack
+22:6: need more than 1 value to unpack
"""
+# mode: error
# invalid syntax (as handled by the parser)
_ERRORS = u"""
-5:4: more than 1 starred expression in assignment
-5:8: more than 1 starred expression in assignment
+6:4: more than 1 starred expression in assignment
+6:8: more than 1 starred expression in assignment
"""
+# mode: error
+
from __future__ import braces
_ERRORS = u"""
-1:23: not a chance
+3:23: not a chance
"""
+# mode: error
+
def f():
a = <foao>True
_ERRORS = u"""
-2:9: 'foao' is not a type identifier
+4:9: 'foao' is not a type identifier
"""
+# mode: error
'\x'
_ERRORS = '''
-2:1: Invalid hex escape '\x'
+3:1: Invalid hex escape '\x'
'''
+# mode: error
'\x1'
_ERRORS = '''
-2:1: Invalid hex escape '\x'
+3:1: Invalid hex escape '\x'
'''
+# mode: error
u'\uXYZ'
_ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
'''
+# mode: error
u'\u'
_ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
'''
+# mode: error
u'\u12'
_ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
'''
+# mode: error
+
def f():
cdef int* p
if false():
return False
_ERRORS = u"""
-4:10: Literal list must be assigned to pointer at time of declaration
+6:10: Literal list must be assigned to pointer at time of declaration
"""
+# ticket: 262
+# mode: error
+
cdef class Album
cdef class SessionStruct:
+# ticket: 156
+# mode: error
cdef class B:
cpdef b():
pass
_ERRORS = u"""
-3:10: C method has no self argument
+5:10: C method has no self argument
"""
+# ticket: 165
+# mode: error
cdef class A:
cpdef a(int not_self):
pass
_ERRORS = u"""
-3:10: Self argument (int) of C method 'a' does not match parent type (A)
+5:10: Self argument (int) of C method 'a' does not match parent type (A)
"""
+# mode: error
+
cdef object f(object x) nogil:
pass
# except these: 29, 34, 44, 56, 58, 60, 62-64
_ERRORS = u"""
-1:5: Function with Python return type cannot be declared nogil
-4:5: Function declared nogil has Python locals or temporaries
-6:6: Assignment of Python object not allowed without gil
-9:5: Discarding owned Python object not allowed without gil
-11:5: Function with Python return type cannot be declared nogil
-15:5: Calling gil-requiring function not allowed without gil
-24:9: Calling gil-requiring function not allowed without gil
-26:12: Assignment of Python object not allowed without gil
-28:8: Discarding owned Python object not allowed without gil
-28:16: Constructing complex number not allowed without gil
-30:8: Backquote expression not allowed without gil
+3:5: Function with Python return type cannot be declared nogil
+6:5: Function declared nogil has Python locals or temporaries
+8:6: Assignment of Python object not allowed without gil
+11:5: Discarding owned Python object not allowed without gil
+13:5: Function with Python return type cannot be declared nogil
+17:5: Calling gil-requiring function not allowed without gil
+26:9: Calling gil-requiring function not allowed without gil
+28:12: Assignment of Python object not allowed without gil
30:8: Discarding owned Python object not allowed without gil
-30:9: Operation not allowed without gil
-31:15: Assignment of Python object not allowed without gil
-31:15: Operation not allowed without gil
-31:15: Python import not allowed without gil
-32:8: Operation not allowed without gil
-32:13: Python import not allowed without gil
-32:25: Constructing Python list not allowed without gil
-32:25: Operation not allowed without gil
-33:17: Iterating over Python object not allowed without gil
-35:11: Discarding owned Python object not allowed without gil
-35:11: Indexing Python object not allowed without gil
-36:11: Discarding owned Python object not allowed without gil
-36:11: Slicing Python object not allowed without gil
-37:11: Constructing Python slice object not allowed without gil
+30:16: Constructing complex number not allowed without gil
+32:8: Backquote expression not allowed without gil
+32:8: Discarding owned Python object not allowed without gil
+32:9: Operation not allowed without gil
+33:15: Assignment of Python object not allowed without gil
+33:15: Operation not allowed without gil
+33:15: Python import not allowed without gil
+34:8: Operation not allowed without gil
+34:13: Python import not allowed without gil
+34:25: Constructing Python list not allowed without gil
+34:25: Operation not allowed without gil
+35:17: Iterating over Python object not allowed without gil
37:11: Discarding owned Python object not allowed without gil
37:11: Indexing Python object not allowed without gil
-37:13: Converting to Python object not allowed without gil
-37:15: Converting to Python object not allowed without gil
-37:17: Converting to Python object not allowed without gil
-38:11: Accessing Python attribute not allowed without gil
38:11: Discarding owned Python object not allowed without gil
-39:9: Constructing Python tuple not allowed without gil
-39:9: Discarding owned Python object not allowed without gil
-40:8: Constructing Python list not allowed without gil
-40:8: Discarding owned Python object not allowed without gil
-41:8: Constructing Python dict not allowed without gil
-41:8: Discarding owned Python object not allowed without gil
-42:12: Discarding owned Python object not allowed without gil
-42:12: Truth-testing Python object not allowed without gil
-43:13: Python type test not allowed without gil
-45:10: Discarding owned Python object not allowed without gil
-45:10: Operation not allowed without gil
-46:8: Discarding owned Python object not allowed without gil
-46:8: Operation not allowed without gil
-47:10: Assignment of Python object not allowed without gil
-47:14: Assignment of Python object not allowed without gil
-48:9: Assignment of Python object not allowed without gil
-48:13: Assignment of Python object not allowed without gil
-48:16: Creating temporary Python reference not allowed without gil
-48:19: Creating temporary Python reference not allowed without gil
-49:11: Assignment of Python object not allowed without gil
-49:11: Indexing Python object not allowed without gil
-50:11: Accessing Python attribute not allowed without gil
-50:11: Assignment of Python object not allowed without gil
-51:8: Constructing Python tuple not allowed without gil
-51:8: Python print statement not allowed without gil
-52:8: Deleting Python object not allowed without gil
-53:8: Returning Python object not allowed without gil
-54:8: Raising exception not allowed without gil
-55:14: Truth-testing Python object not allowed without gil
-57:17: Truth-testing Python object not allowed without gil
-59:8: For-loop using object bounds or target not allowed without gil
-61:8: Try-except statement not allowed without gil
-65:8: Try-finally statement not allowed without gil
-82:8: For-loop using object bounds or target not allowed without gil
+38:11: Slicing Python object not allowed without gil
+39:11: Constructing Python slice object not allowed without gil
+39:11: Discarding owned Python object not allowed without gil
+39:11: Indexing Python object not allowed without gil
+39:13: Converting to Python object not allowed without gil
+39:15: Converting to Python object not allowed without gil
+39:17: Converting to Python object not allowed without gil
+40:11: Accessing Python attribute not allowed without gil
+40:11: Discarding owned Python object not allowed without gil
+41:9: Constructing Python tuple not allowed without gil
+41:9: Discarding owned Python object not allowed without gil
+42:8: Constructing Python list not allowed without gil
+42:8: Discarding owned Python object not allowed without gil
+43:8: Constructing Python dict not allowed without gil
+43:8: Discarding owned Python object not allowed without gil
+44:12: Discarding owned Python object not allowed without gil
+44:12: Truth-testing Python object not allowed without gil
+45:13: Python type test not allowed without gil
+47:10: Discarding owned Python object not allowed without gil
+47:10: Operation not allowed without gil
+48:8: Discarding owned Python object not allowed without gil
+48:8: Operation not allowed without gil
+49:10: Assignment of Python object not allowed without gil
+49:14: Assignment of Python object not allowed without gil
+50:9: Assignment of Python object not allowed without gil
+50:13: Assignment of Python object not allowed without gil
+50:16: Creating temporary Python reference not allowed without gil
+50:19: Creating temporary Python reference not allowed without gil
+51:11: Assignment of Python object not allowed without gil
+51:11: Indexing Python object not allowed without gil
+52:11: Accessing Python attribute not allowed without gil
+52:11: Assignment of Python object not allowed without gil
+53:8: Constructing Python tuple not allowed without gil
+53:8: Python print statement not allowed without gil
+54:8: Deleting Python object not allowed without gil
+55:8: Returning Python object not allowed without gil
+56:8: Raising exception not allowed without gil
+57:14: Truth-testing Python object not allowed without gil
+59:17: Truth-testing Python object not allowed without gil
+61:8: For-loop using object bounds or target not allowed without gil
+63:8: Try-except statement not allowed without gil
+67:8: Try-finally statement not allowed without gil
+84:8: For-loop using object bounds or target not allowed without gil
"""
+# mode: error
+
cdef class C:
cdef void f(self):
pass
_ERRORS = u"""
-2:9: Signature not compatible with previous declaration
2:15: Previous declaration is here
+4:9: Signature not compatible with previous declaration
"""
+# mode: error
+
cdef extern from *:
cdef void f()
cdef void (*fp)() nogil
fp = f
_ERRORS = u"""
-10:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil'
+12:6: Cannot assign type 'void (void)' to 'void (*)(void) nogil'
"""
+# mode: error
+
import os
DEF ospath = os.path
_ERRORS = u"""
-2:15: Compile-time name 'os' not defined
-2:15: Error in compile-time expression: AttributeError: 'NoneType' object has no attribute 'path'
+4:15: Compile-time name 'os' not defined
+4:15: Error in compile-time expression: AttributeError: 'NoneType' object has no attribute 'path'
"""
+# ticket: 418
+# mode: error
+
import somemod.child
cdef somemod.child.something x
_ERRORS = u"""
-3:5: 'somemod.child' is not a cimported module
+6:5: 'somemod.child' is not a cimported module
"""
+# ticket: 286
+# mode: error
+
cdef class A:
pass
+# mode: error
# -*- coding: iso-8859-1 -*-
cdef Py_UCS4 char_ASCII = u'A'
_ERRORS = """
- 7:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
-10:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
-13:21: Only single-character string literals can be coerced into ints.
-16:37: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
+ 8:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
+11:21: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
+14:21: Only single-character string literals can be coerced into ints.
+17:37: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
"""
+# mode: error
# -*- coding: iso-8859-1 -*-
cdef Py_UNICODE char_ASCII = u'A'
_ERRORS = """
- 7:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
-10:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
-13:24: Only single-character string literals can be coerced into ints.
-16:40: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
+ 8:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
+11:24: Only single-character Unicode string literals or surrogate pairs can be coerced into Py_UCS4/Py_UNICODE.
+14:24: Only single-character string literals can be coerced into ints.
+17:40: Bytes literals cannot coerce to Py_UNICODE/Py_UCS4, use a unicode literal instead.
"""
+# ticket: 313
+# mode: error
a = 3
cdef double* disallowed = <double*>a
_ERRORS = u"""
-5:26: Python objects cannot be cast to pointers of primitive types
+7:26: Python objects cannot be cast to pointers of primitive types
"""
+# ticket: 135
+# mode: error
def _runtime_True():
return True
_ERRORS = u'''
- 5:0: Return not inside a function body
- 8:4: Return not inside a function body
-11:4: Return not inside a function body
-13:5: Return not inside a function body
-16:5: Return not inside a function body
-20:4: Return not inside a function body
-23:4: Return not inside a function body
-26:4: Return not inside a function body
+7:0: Return not inside a function body
+10:4: Return not inside a function body
+13:4: Return not inside a function body
+15:5: Return not inside a function body
+18:5: Return not inside a function body
+22:4: Return not inside a function body
+25:4: Return not inside a function body
28:4: Return not inside a function body
+30:4: Return not inside a function body
'''
+# mode: error
+
def f():
a = b # space space
c = d # space tab
_ERRORS = u"""
-3:0: Mixed use of tabs and spaces
+5:0: Mixed use of tabs and spaces
"""
+# mode: error
+
def f():
a = b
c = d
_ERRORS = u"""
-3:0: Possible inconsistent indentation
-3:0: Expected an identifier or literal
+5:0: Possible inconsistent indentation
+5:0: Expected an identifier or literal
"""
+# mode: error
+
def f():
a = b # space space
c = d # tab
_ERRORS = u"""
-3:0: Mixed use of tabs and spaces
+5:0: Mixed use of tabs and spaces
"""
+# mode: error
+
def f(obj1a, obj2a, obj3a, obj1b, obj2b, obj3b, obj4b):
obj1a, (obj2a, obj3a) = obj1b, (obj2b, obj3b, obj4b)
_ERRORS = u"""
-2:9: too many values to unpack (expected 2, got 3)
+4:9: too many values to unpack (expected 2, got 3)
"""
+# mode: error
# coding: ASCII
# ok:
cdef list l_f3 = u1
_ERRORS = u"""
-25:20: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
-26:22: Unicode objects do not support coercion to C types.
-27:22: 'str' objects do not support coercion to C types (use 'bytes'?).
-
-29:20: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
-30:22: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
-31:22: Cannot convert 'str' to 'bytes' implicitly. This is not portable.
-
-33:17: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
-34:19: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
-35:17: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
-36:19: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
-
-38:20: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
-39:22: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
-40:20: Cannot convert 'bytes' object to unicode implicitly, decoding required
-41:22: Cannot convert 'bytes' object to unicode implicitly, decoding required
-42:22: Cannot convert 'char*' to unicode implicitly, decoding required
-
-44:19: Cannot assign type 'str object' to 'tuple object'
-45:18: Cannot assign type 'unicode object' to 'tuple object'
-46:18: Cannot assign type 'bytes object' to 'tuple object'
+26:20: Unicode literals do not support coercion to C types other than Py_UNICODE or Py_UCS4.
+27:22: Unicode objects do not support coercion to C types.
+28:22: 'str' objects do not support coercion to C types (use 'bytes'?).
+
+30:20: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
+31:22: Cannot convert Unicode string to 'bytes' implicitly, encoding required.
+32:22: Cannot convert 'str' to 'bytes' implicitly. This is not portable.
+
+34:17: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
+35:19: Cannot convert 'bytes' object to str implicitly. This is not portable to Py3.
+36:17: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
+37:19: Cannot convert Unicode string to 'str' implicitly. This is not portable and requires explicit encoding.
+
+39:20: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
+40:22: str objects do not support coercion to unicode, use a unicode string literal instead (u'')
+41:20: Cannot convert 'bytes' object to unicode implicitly, decoding required
+42:22: Cannot convert 'bytes' object to unicode implicitly, decoding required
+43:22: Cannot convert 'char*' to unicode implicitly, decoding required
+
+45:19: Cannot assign type 'str object' to 'tuple object'
+46:18: Cannot assign type 'unicode object' to 'tuple object'
+47:18: Cannot assign type 'bytes object' to 'tuple object'
"""
+# mode: error
cimport cython
pass
_ERRORS = """
-8:5: Base class 'FinalClass' of type 'SubType' is final
+9:5: Base class 'FinalClass' of type 'SubType' is final
"""
+# mode: error
cimport cython
_ERRORS = u"""
-8:0: Expected path '//ComprehensionNode' not found in result tree
-8:0: Expected path '//ComprehensionNode//FuncDefNode' not found in result tree
-8:0: Unexpected path '//NameNode' found in result tree
-8:0: Unexpected path '//SimpleCallNode' found in result tree
+9:0: Expected path '//ComprehensionNode' not found in result tree
+9:0: Expected path '//ComprehensionNode//FuncDefNode' not found in result tree
+9:0: Unexpected path '//NameNode' found in result tree
+9:0: Unexpected path '//SimpleCallNode' found in result tree
"""
+# ticket: 304
+# mode: error
def f():
print assert sizeof(int) == sizof(short) == sizeof(long)
_ERRORS = u"""
-3:10: Expected an identifier or literal
+5:10: Expected an identifier or literal
"""
+# mode: error
+
i = _this_global_name_does_not_exist_
def test(i):
return _this_local_name_does_not_exist_
_ERRORS = u"""
-1:37:undeclared name not builtin: _this_global_name_does_not_exist_
-4:43:undeclared name not builtin: _this_local_name_does_not_exist_
+3:37:undeclared name not builtin: _this_global_name_does_not_exist_
+6:43:undeclared name not builtin: _this_local_name_does_not_exist_
"""
+# mode: error
+
cdef extern from *:
void foo(void)
_ERRORS = u"""
-2:13:Use spam() rather than spam(void) to declare a function with no arguments.
+4:13:Use spam() rather than spam(void) to declare a function with no arguments.
"""
--- /dev/null
+# mode: error
+# tags: werror
+
+cdef foo():
+ pass
+
+def foo():
+ pass
+
+_ERRORS = u"""
+7:0: 'foo' redeclared
+7:0: Overriding cdef method with def method.
+"""
+# ticket: 295
+
cimport cython
+# mode: run
+# tag: closures
+# ticket: 658
def outer(int x, *args, **kwargs):
"""
--- /dev/null
+# ticket: 676
+# tag: cpp
+
+from cython cimport typeof
+
+cdef extern from "arithmetic_analyse_types_helper.h":
+ cdef struct short_return:
+ char *msg
+ cdef struct int_return:
+ char *msg
+ cdef struct longlong_return:
+ char *msg
+ cdef short_return f(short)
+ cdef int_return f(int)
+ cdef longlong_return f(long long)
+
+def short_binop(short val):
+ """
+ Arithmetic in C is always done with at least int precision.
+
+ >>> print(short_binop(3))
+ int called
+ """
+ assert typeof(val + val) == "int", typeof(val + val)
+ assert typeof(val - val) == "int", typeof(val - val)
+ assert typeof(val & val) == "int", typeof(val & val)
+ cdef int_return x = f(val + val)
+ return x.msg.decode('ASCII')
+
+def short_unnop(short val):
+ """
+ Arithmetic in C is always done with at least int precision.
+
+ >>> print(short_unnop(3))
+ int called
+ """
+ cdef int_return x = f(-val)
+ return x.msg.decode('ASCII')
+
+def longlong_binop(long long val):
+ """
+ >>> print(longlong_binop(3))
+ long long called
+ """
+ cdef longlong_return x = f(val * val)
+ return x.msg.decode('ASCII')
+
+def longlong_unnop(long long val):
+ """
+ >>> print(longlong_unnop(3))
+ long long called
+ """
+ cdef longlong_return x = f(~val)
+ return x.msg.decode('ASCII')
+
+
+def test_bint(bint a):
+ """
+ >>> test_bint(True)
+ """
+ assert typeof(a + a) == "int", typeof(a + a)
+ assert typeof(a & a) == "bint", typeof(a & a)
--- /dev/null
+/* A set of mutually incompatable return types. */
+
+struct short_return { const char *msg; };
+struct int_return { const char *msg; };
+struct longlong_return { const char *msg; };
+
+/* A set of overloaded methods. */
+
+short_return f(short arg) {
+ short_return val;
+ val.msg = "short called";
+ return val;
+}
+
+int_return f(int arg) {
+ int_return val;
+ val.msg = "int called";
+ return val;
+}
+
+longlong_return f(long long arg) {
+ longlong_return val;
+ val.msg = "long long called";
+ return val;
+}
+
+
--- /dev/null
+# cython: auto_cpdef=True
+# mode:run
+# tag: directive,auto_cpdef
+
+import cython
+
+def str(arg):
+ """
+ This is a bit evil - str gets mapped to a C-API function and is
+ being redefined here.
+
+ >>> print(str('TEST'))
+ STR
+ """
+ return 'STR'
+
+@cython.test_assert_path_exists('//SimpleCallNode[@function.type.is_cfunction = True]')
+@cython.test_fail_if_path_exists('//SimpleCallNode[@function.type.is_builtin_type = True]')
+def call_str(arg):
+ """
+ >>> print(call_str('TEST'))
+ STR
+ """
+ return str(arg)
+
+
+def stararg_func(*args):
+ """
+ >>> stararg_func(1, 2)
+ (1, 2)
+ """
+ return args
+
+def starstararg_func(**kwargs):
+ """
+ >>> starstararg_func(a=1)
+ 1
+ """
+ return kwargs['a']
--- /dev/null
+# cython: auto_cpdef=True
+# mode:run
+# tag: directive,auto_cpdef,closures
+
+def closure_func(x):
+ """
+ >>> c = closure_func(2)
+ >>> c()
+ 2
+ """
+ def c():
+ return x
+ return c
+
+def generator_func():
+ """
+ >>> for i in generator_func(): print(i)
+ 1
+ 2
+ """
+ yield 1
+ yield 2
#cython: autotestdict=True
+
"""
Tests that autotestdict doesn't come into effect when
a __test__ is defined manually.
+# ticket: 252
+
cdef cf(default=None):
return default
-cdef test(bint value):
- print value
+from cython cimport typeof
-def call_test():
+def test(bint value):
"""
- >>> call_test()
- False
+ >>> test(True)
True
+ >>> test(False)
+ False
+ >>> test(None)
+ False
+
+ >>> test(0)
False
+ >>> test(1)
+ True
+ >>> test(-1)
True
+ >>> test(100)
True
+
+ >>> test(0.0)
+ False
+ >>> test(0.1)
True
+
+ >>> test([])
+ False
+ >>> test([1, 2, 3])
True
"""
- test(False)
- test(True)
- test(0)
- test(234)
- test(-1)
- x = True
- test(x)
- x = 3242
- test(x)
+ return value
+
+def test_types(bint a):
+ """
+ >>> test_types(None)
+ """
+ cdef bint b = a
+ assert typeof(a) == 'bint', typeof(a)
+ assert typeof(b) == 'bint', typeof(b)
+ c = b
+ assert typeof(c) == 'bint', typeof(c)
+# ticket: 145
cimport cython
+# ticket: 354
cdef class Test:
"""
+# ticket: 589
cimport cython
SmallStruct y
int z
+cdef packed struct PackedStruct:
+ char a
+ int b
+
+cdef struct NestedPackedStruct:
+ char a
+ int b
+ PackedStruct sub
+ int c
+
cdef class MyStructMockBuffer(MockBuffer):
cdef int write(self, char* buf, object value) except -1:
cdef MyStruct* s
cdef get_itemsize(self): return sizeof(NestedStruct)
cdef get_default_format(self): return b"2T{ii}i"
+cdef class PackedStructMockBuffer(MockBuffer):
+ cdef int write(self, char* buf, object value) except -1:
+ cdef PackedStruct* s
+ s = <PackedStruct*>buf;
+ s.a, s.b = value
+ return 0
+
+ cdef get_itemsize(self): return sizeof(PackedStruct)
+ cdef get_default_format(self): return b"^ci"
+
+cdef class NestedPackedStructMockBuffer(MockBuffer):
+ cdef int write(self, char* buf, object value) except -1:
+ cdef NestedPackedStruct* s
+ s = <NestedPackedStruct*>buf;
+ s.a, s.b, s.sub.a, s.sub.b, s.c = value
+ return 0
+
+ cdef get_itemsize(self): return sizeof(NestedPackedStruct)
+ cdef get_default_format(self): return b"ci^ci@i"
+
@testcase
def basic_struct(object[MyStruct] buf):
"""
"""
print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z
+@testcase
+def packed_struct(object[PackedStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)]))
+ 1 2
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c^i}"))
+ 1 2
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c=i}"))
+ 1 2
+
+ """
+ print buf[0].a, buf[0].b
+
+@testcase
+def nested_packed_struct(object[NestedPackedStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
+ 1 2 3 4 5
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ci^ci@i"))
+ 1 2 3 4 5
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="^c@i^ci@i"))
+ 1 2 3 4 5
+ """
+ print buf[0].a, buf[0].b, buf[0].sub.a, buf[0].sub.b, buf[0].c
+
cdef struct LongComplex:
long double real
long double imag
>>> char3int("c3i")
>>> char3int("ci2i")
- #TODO > char3int("c@i@2i")
+ >>> char3int("c@i@2i")
Extra pad bytes (assuming int size is 4 or more)
>>> char3int("cxiii")
...
ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
- #TODO char3int("=cxxx@iii")
+ >>> char3int("=cxxx@iii")
Error:
>>> char3int("cii")
char x
int y
+cdef struct UnpackedSubStruct:
+ char x
+ int y
+
cdef packed struct PackedStruct:
char a
int b
PackedSubStruct sub
+cdef struct PartiallyPackedStruct:
+ char a
+ int b
+ PackedSubStruct sub
+
+cdef packed struct PartiallyPackedStruct2:
+ char a
+ UnpackedSubStruct sub
+ char b
+ int c
@testcase
def packed_struct(fmt):
>>> packed_struct("^cici")
>>> packed_struct("=cibi")
+ However aligned access won't work:
+
>>> packed_struct("^c@i^ci")
Traceback (most recent call last):
...
- ValueError: Buffer packing mode currently only allowed at beginning of format string (this is a defect)
+ ValueError: Buffer dtype mismatch; next field is at offset 4 but 1 expected
- However aligned access won't work:
>>> packed_struct("@cici")
Traceback (most recent call last):
...
"""
cdef object[PackedStruct] buf = MockBuffer(fmt, sizeof(PackedStruct))
+@testcase
+def partially_packed_struct(fmt):
+ """
+ Assuming int is four bytes:
+
+ >>> partially_packed_struct("^c@i^ci")
+ >>> partially_packed_struct("@ci^ci")
+ >>> partially_packed_struct("^c@i=ci")
+ >>> partially_packed_struct("@ci=ci")
+ >>> partially_packed_struct("ci^ci")
+ >>> partially_packed_struct("ci=ci")
+
+ Incorrectly aligned accesses won't work:
+
+ >>> partially_packed_struct("^cici")
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
+
+ >>> partially_packed_struct("=cibi")
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
+
+ """
+ cdef object[PartiallyPackedStruct] buf = MockBuffer(
+ fmt, sizeof(PartiallyPackedStruct))
+
+@testcase
+def partially_packed_struct_2(fmt):
+ """
+ Assuming int is four bytes:
+
+ >>> partially_packed_struct_2("^ccxxxici")
+ >>> partially_packed_struct_2("^ccxxxi^ci")
+ >>> partially_packed_struct_2("c=cxxxi^ci")
+ >>> partially_packed_struct_2("c^cxxxi^ci")
+ >>> partially_packed_struct_2("c^cxxxi=ci")
+ >>> partially_packed_struct_2("ccxxx^i@c^i")
+
+ Incorrectly aligned accesses won't work:
+
+ >>> partially_packed_struct_2("ccxxxici")
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch; next field is at offset 8 but 5 expected
+
+ >>> partially_packed_struct_2("ccici")
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch; next field is at offset 4 but 5 expected
+
+ """
+ cdef object[PartiallyPackedStruct2] buf = MockBuffer(
+ fmt, sizeof(PartiallyPackedStruct2))
+
+
# TODO: empty struct
# TODO: Incomplete structs
# TODO: mixed structs
--- /dev/null
+# mode: run
+# tag: list, set, builtins
+# ticket: 688
+
+_set = set
+
+class TestObj(object):
+ pass
+
+def _setattr(obj):
+ """
+ >>> t = TestObj()
+ >>> _setattr(t) is None
+ True
+ >>> t.test is None
+ True
+ """
+ setattr(obj, 'test', None)
+ return setattr(obj, 'test', None)
+
+def _delattr(obj):
+ """
+ >>> t = TestObj()
+ >>> t.test1 = t.test2 = True
+ >>> _delattr(t) is None
+ True
+ >>> hasattr(t, 'test1')
+ False
+ >>> hasattr(t, 'test2')
+ False
+ """
+ delattr(obj, 'test1')
+ return delattr(obj, 'test2')
+
+def list_sort(list l):
+ """
+ >>> list_sort([1,2,3]) is None
+ True
+ """
+ l.sort()
+ return l.sort()
+
+def list_reverse(list l):
+ """
+ >>> list_reverse([1,2,3]) is None
+ True
+ """
+ l.reverse()
+ return l.reverse()
+
+def list_insert(list l):
+ """
+ >>> list_insert([1,2,3]) is None
+ True
+ """
+ l.insert(1, 2)
+ return l.insert(1, 2)
+
+def list_append(list l):
+ """
+ >>> list_append([1,2,3]) is None
+ True
+ """
+ l.append(1)
+ return l.append(2)
+
+def set_clear(set s):
+ """
+ >>> set_clear(_set([1,2,3])) is None
+ True
+ """
+ s.clear()
+ return s.clear()
+
+def set_discard(set s):
+ """
+ >>> set_discard(_set([1,2,3])) is None
+ True
+ """
+ s.discard(1)
+ return s.discard(2)
+
+def set_add(set s):
+ """
+ >>> set_add(_set([1,2,3])) is None
+ True
+ """
+ s.add(1)
+ return s.add(2)
+# tag: py3
+
__doc__ = u"""
>>> test_xrange()
0
+# ticket: 608
cdef class MyInt(int):
"""
+# ticket: 166
+
__doc__ = u"""
>>> l = None
>>> l.append(2)
for c in range(arg):
l.append(c)
return l
-
-def raise_and_catch_BaseException():
- """
- >>> raise_and_catch_BaseException()
- 1
- """
- try:
- raise BaseException
- except BaseException:
- return 1
- return 2
+# ticket: 255
+
__doc__ = u""
# -------------------------------------------------------------------
+# ticket: 236
__doc__ = ''
>>> import sys
>>> sys.getrefcount(Foo.__pyx_vtable__)
2
->>> sys.getrefcount(__pyx_capi__['spam'])
+>>> sys.getrefcount(__pyx_capi__['ten'])
2
+>>> sys.getrefcount(__pyx_capi__['pi'])
+2
+>>> sys.getrefcount(__pyx_capi__['obj'])
+2
+>>> sys.getrefcount(__pyx_capi__['dct'])
+2
+>>> sys.getrefcount(__pyx_capi__['one'])
+2
+>>> sys.getrefcount(__pyx_capi__['two'])
+Traceback (most recent call last):
+ ...
+KeyError: 'two'
"""
cdef public api class Foo [type FooType, object FooObject]:
cdef api void spam():
pass
+
+cdef api int ten = 10
+cdef api double pi = 3.14
+cdef api object obj = object()
+cdef api dict dct = {}
+
+cdef public api int one = 1
+cdef public int two = 2
+
+# ticket: 467
def simple_parallel_assignment_from_call():
"""
+# ticket: 466
# extension to T409
def simple_parallel_typed():
+# ticket: 227
+
from cpython.bool cimport bool
def foo(bool a):
--- /dev/null
+# mode: run
+# tag: cdefclass
+# ticket: 677
+"""
+>>> str(Foo(4))
+'4'
+>>> x
+3
+"""
+
+x = 3
+cdef int y
+
+cdef class Foo:
+ cdef int x
+ cdef int y
+ def __init__(self, x):
+ self.x = x
+ def __str__(self):
+ return str(self.x)
+# ticket: 183
+
cimport cython
@cython.cdivision(True)
--- /dev/null
+# ticket: 477
+
+import cython
+@cython.locals(x=double)
+cdef func(x):
+ return x**2
+
+@cython.locals(x=double)
+cdef func_defval(x=0):
+ return x**2
+
+def test():
+ """
+ >>> isinstance(test(), float)
+ True
+ """
+ return func(2)
+
+def test_defval(x=None):
+ """
+ >>> test_defval()
+ 0.0
+ >>> test_defval(1)
+ 1.0
+ >>> test_defval(2.0)
+ 4.0
+ """
+ if x is None:
+ return func_defval()
+ else:
+ return func_defval(x)
+# ticket: 517
#cython: embedsignature=True
+
__doc__ = u"""
>>> a = A()
>>> a.h = 7
+# ticket: 462
cimport cython
+# ticket: 284
+
def no_cdef():
"""
>>> no_cdef()
+# ticket: 408
+
__doc__ = """
>>> call_with_tuple(1, 1.2, 'test', [1,2,3])
(1, 1.2, 'test', [1, 2, 3])
+# ticket: 99
+
cdef char c = 'c'
cdef char* s = 'abcdef'
+# ticket: 412
+
def f():
"""
>>> f()
+# ticket: 582
cimport cython
+# ticket: 505
+
cimport cython
cdef extern from "Python.h":
+# ticket: 18
+
__doc__ = u"""
>>> f = PyFoo()
>>> print(f.bar)
+# ticket: 87
__doc__ = u"""
>>> d = Defined()
--- /dev/null
+# mode:run
+# tag: class, scope
+
+class MethodRedef(object):
+ """
+ >>> MethodRedef().a(5)
+ 7
+ """
+
+ def a(self, i):
+ return i+1
+
+ def a(self, i):
+ return i+2
--- /dev/null
+# mode:run
+# tag: class, scope
+# ticket: 671
+
+MAIN = True
+
+class OuterScopeLookup(object):
+ """
+ >>> OuterScopeLookup.MAIN
+ True
+ """
+ MAIN = MAIN # looked up in parent scope, assigned to class scope
--- /dev/null
+# mode:run
+# tag: class, scope, del
+# ticket: 684
+
+class DelInClass(object):
+ """
+ >>> DelInClass.y
+ 5
+ >>> DelInClass.x
+ Traceback (most recent call last):
+ AttributeError: type object 'DelInClass' has no attribute 'x'
+ """
+ x = 5
+ y = x
+ del x
+# ticket: 336
+
__doc__ = u"""
>>> print('\\n'.join(calls))
Py-Honk PyTestClass
+# mode: run
+# tag: closures
# The arguments in f() are put into the closure one after the other,
# so the reference of 'o' is filled in before the type errors are
+# mode: run
+# tag: closures
+# ticket: 596
+
def simple(a, b):
"""
>>> kls = simple(1, 2)
+# mode: run
+# tag: closures
+# ticket: 478
+
__doc__ = """
>>> Num(13).is_prime()
args (Num(13),) kwds {}
+# mode: run
+# tag: closures
+# ticket: 554
+
def call_f(x):
"""
>>> call_f(2)
+# mode: run
+# tag: closures
+# ticket: 537
__doc__ = u"""
>>> f1 = nested1()
--- /dev/null
+# mode: run
+# tag: closures
+cdef class Test:
+ cdef int x
+
+cdef class SelfInClosure(object):
+ cdef Test _t
+ cdef int x
+
+ def plain(self):
+ """
+ >>> o = SelfInClosure()
+ >>> o.plain()
+ 1
+ """
+ self.x = 1
+ return self.x
+
+ def closure_method(self):
+ """
+ >>> o = SelfInClosure()
+ >>> o.closure_method()() == o
+ True
+ """
+ def nested():
+ return self
+ return nested
+
+ def closure_method_cdef_attr(self, Test t):
+ """
+ >>> o = SelfInClosure()
+ >>> o.closure_method_cdef_attr(Test())()
+ (1, 2)
+ """
+ t.x = 2
+ self._t = t
+ self.x = 1
+ def nested():
+ return self.x, t.x
+ return nested
+# mode: run
+# tag: closures
#
# closure_tests_1.pyx
#
+# mode: run
+# tag: closures
#
# closure_tests_2.pyx
#
+# mode: run
+# tag: closures
#
# closure_tests_3.pyx
#
+# mode: run
+# tag: closures
#
# closure_tests_4.pyx
#
+# mode: run
+# tag: closures
+# ticket: 82
cimport cython
+# ticket: 445
+
def complex_double_cast(double x, double complex z):
"""
>>> complex_double_cast(1, 4-3j)
+# ticket: 446
+
import cython
cdef extern from "complex_int_T446_fix.h":
+# ticket: 305
+
cimport cython
def test_object_conversion(o):
+# ticket: 398
+
cdef extern from "complex_numbers_c89_T398.h": pass
include "complex_numbers_T305.pyx"
+# ticket: 398
+
cdef extern from "complex_numbers_c99_T398.h": pass
include "complex_numbers_T305.pyx"
+# ticket: 398
+
cdef extern from "complex_numbers_cxx_T398.h": pass
include "complex_numbers_T305.pyx"
+# ticket: 455
+
def in_sequence(x, seq):
"""
>>> in_sequence(1, [])
+# ticket: 411
+
cdef class A:
"""
>>> A().is_True()
+# tag: cpp
+
from libcpp cimport bool
def test_bool(bool a):
+# tag: cpp
+
__doc__ = u"""
>>> test_new_del()
(2, 2)
+# tag: cpp
+
cdef int raise_py_error() except *:
raise TypeError("custom")
+# tag: cpp
+
cdef int raise_TypeError() except *:
raise TypeError("custom")
+# tag: cpp
+
cdef extern from "cpp_namespaces_helper.h" namespace "A":
ctypedef int A_t
A_t A_func(A_t first, A_t)
+# tag: cpp
+
from cython.operator cimport dereference as deref
cdef extern from "cpp_templates_helper.h":
+# tag: cpp
+
cdef extern from "cpp_nonstdint.h":
ctypedef int Int24
ctypedef int Int56
+# tag: cpp
+
cimport cython.operator
from cython.operator cimport dereference as deref
+# tag: cpp
+
cdef extern from "vector" namespace "std":
cdef cppclass vector[T]:
--- /dev/null
+# tag: cpp
+
+from libcpp.string cimport string
+
+b_asdf = b'asdf'
+b_asdg = b'asdg'
+b_s = b's'
+
+def test_indexing(char *py_str):
+ """
+ >>> test_indexing(b_asdf)
+ ('s', 's')
+ """
+ cdef string s
+ s = string(py_str)
+ return chr(s[1]), chr(s.at(1))
+
+def test_size(char *py_str):
+ """
+ >>> test_size(b_asdf)
+ (4, 4)
+ """
+ cdef string s
+ s = string(py_str)
+ return s.size(), s.length()
+
+def test_compare(char *a, char *b):
+ """
+ >>> test_compare(b_asdf, b_asdf)
+ 0
+
+ >>> test_compare(b_asdf, b_asdg) < 0
+ True
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ return s.compare(t)
+
+def test_empty():
+ """
+ >>> test_empty()
+ (True, False)
+ """
+ cdef string a = string(<char *>b"")
+ cdef string b = string(<char *>b"aa")
+ return a.empty(), b.empty()
+
+def test_push_back(char *a):
+ """
+ >>> test_push_back(b_asdf) == b_asdf + b_s
+ True
+ """
+ cdef string s = string(a)
+ s.push_back(<char>ord('s'))
+ return s.c_str()
+
+def test_insert(char *a, char *b, int i):
+ """
+ >>> test_insert('AAAA'.encode('ASCII'), 'BBBB'.encode('ASCII'), 2) == 'AABBBBAA'.encode('ASCII')
+ True
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ cdef string u = s.insert(i, t)
+ return u.c_str()
+
+def test_copy(char *a):
+ """
+ >>> test_copy(b_asdf) == b_asdf[1:]
+ True
+ """
+ cdef string t = string(a)
+ cdef char buffer[6]
+ cdef size_t length = t.copy(buffer, 4, 1)
+ buffer[length] = c'\0'
+ return buffer
+
+def test_find(char *a, char *b):
+ """
+ >>> test_find(b_asdf, 'df'.encode('ASCII'))
+ 2
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ cdef size_t i = s.find(t)
+ return i
+
+def test_clear():
+ """
+ >>> test_clear() == ''.encode('ASCII')
+ True
+ """
+ cdef string s = string(<char *>"asdf")
+ s.clear()
+ return s.c_str()
+
+def test_assign(char *a):
+ """
+ >>> test_assign(b_asdf) == 'ggg'.encode('ASCII')
+ True
+ """
+ cdef string s = string(a)
+ s.assign(<char *>"ggg")
+ return s.c_str()
+
+
+def test_substr(char *a):
+ """
+ >>> test_substr('ABCDEFGH'.encode('ASCII')) == ('BCDEFGH'.encode('ASCII'), 'BCDE'.encode('ASCII'), 'ABCDEFGH'.encode('ASCII'))
+ True
+ """
+ cdef string s = string(a)
+ cdef string x, y, z
+ x = s.substr(1)
+ y = s.substr(1, 4)
+ z = s.substr()
+ return x.c_str(), y.c_str(), z.c_str()
+
+def test_append(char *a, char *b):
+ """
+ >>> test_append(b_asdf, '1234'.encode('ASCII')) == b_asdf + '1234'.encode('ASCII')
+ True
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ cdef string j = s.append(t)
+ return j.c_str()
+
+def test_char_compare(py_str):
+ """
+ >>> test_char_compare(b_asdf)
+ True
+ """
+ cdef char *a = py_str
+ cdef string b = string(a)
+ return b.compare(b) == 0
+
+def test_cstr(char *a):
+ """
+ >>> test_cstr(b_asdf) == b_asdf
+ True
+ """
+ cdef string b = string(a)
+ return b.c_str()
+
+def test_equals_operator(char *a, char *b):
+ """
+ >>> test_equals_operator(b_asdf, b_asdf)
+ (True, False)
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ return t == s, t != <char *>"asdf"
+
+def test_less_than(char *a, char *b):
+ """
+ >>> test_less_than(b_asdf[:-1], b_asdf)
+ (True, True, True)
+
+ >>> test_less_than(b_asdf[:-1], b_asdf[:-1])
+ (False, False, True)
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ return (s < t, s < b, s <= b)
+
+def test_greater_than(char *a, char *b):
+ """
+ >>> test_greater_than(b_asdf[:-1], b_asdf)
+ (False, False, False)
+
+ >>> test_greater_than(b_asdf[:-1], b_asdf[:-1])
+ (False, False, True)
+ """
+ cdef string s = string(a)
+ cdef string t = string(b)
+ return (s > t, s > b, s >= b)
+# tag: cpp
+
from cython.operator cimport dereference as d
from cython.operator cimport preincrement as incr
+# tag: cpp
+
from cython.operator import dereference as deref
cdef extern from "cpp_templates_helper.h":
+# ticket: 245
+
cimport crashT245_pxd
def f():
+# ticket: 333
#cython: autotestdict=True
# -------------------------------------------------------------------
# cython: language_level=3
+# mode: run
+# tag: generators, python3
cimport cython
assert x == 'abc' # don't leak in Py3 code
return result
+def list_comp_with_lambda():
+ """
+ >>> list_comp_with_lambda()
+ [0, 4, 8]
+ """
+ x = 'abc'
+ result = [x*2 for x in range(5) if (lambda x:x % 2)(x) == 0]
+ assert x == 'abc' # don't leak in Py3 code
+ return result
+
module_level_lc = [ module_level_loopvar*2 for module_level_loopvar in range(4) ]
def list_comp_module_level():
"""
+# ticket: 593
+
"""
>>> am_i_buggy
False
"""
del a
assert a is None # Until we have unbound locals...
+
+def del_seq(a, b, c):
+ """
+ >>> del_seq(1, 2, 3)
+ """
+ del a, (b, c)
+ assert a is None # Until we have unbound locals...
+ assert b is None # Until we have unbound locals...
+ assert c is None # Until we have unbound locals...
--- /dev/null
+cimport cython
+
+@cython.locals(egg=double)
+cdef foo(egg)
+
+@cython.locals(egg=cython.double)
+cdef foo_defval(egg=*)
+
+@cython.locals(egg=cython.bint, v=cython.int)
+cpdef cpfoo(egg=*)
--- /dev/null
+import cython
+
+def foo(egg):
+ if not cython.compiled:
+ egg = float(egg)
+ return egg
+
+def foo_defval(egg=1):
+ if not cython.compiled:
+ egg = float(egg)
+ return egg**2
+
+def cpfoo(egg=False):
+ if not cython.compiled:
+ egg = bool(egg)
+ v = int(not egg)
+ else:
+ v = not egg
+ return egg, v
+
+def test_pxd_locals():
+ """
+ >>> v1, v2, v3 = test_pxd_locals()
+ >>> isinstance(v1, float)
+ True
+ >>> isinstance(v2, float)
+ True
+ >>> v3
+ (True, 0)
+ """
+ return foo(1), foo_defval(), cpfoo(1)
+# ticket: 384
+
"""
>>> test(3)
(3+1j)
+# ticket: 488
+
"""
>>> test()
"""
+# ticket: 208
+
def go_py_empty():
"""
>>> go_py_empty()
+# ticket: 316
+
cimport cython
@cython.test_fail_if_path_exists("//SimpleCallNode//NameNode[@name = 'enumerate']")
+# ticket: 232
+
cdef class MyExt:
cdef object attr
+# ticket: 235
+
__doc__ = u"""
>>> class FakeSeq(object):
... def __init__(self, length):
+# ticket: 409
+
def simple():
"""
>>> simple()
+# ticket: 258
+
cdef extern from "Python.h":
ctypedef class __builtin__.list [object PyListObject]:
+# ticket: 260
+
def floor_div_float(double a, double b):
"""
>>> floor_div_float(2, 1.5)
+# ticket: 480
+
def f(x):
return x
incremented one step after the last iteration.
"""
cdef int i, j, k
- for i from 0 <= i < 10 by get_step(): pass
+ for i from 0 <= i < 5+5 by get_step(): pass
for j from 0 <= j < 10: pass
for k from 10 > k > 0: pass
return i, j, k
+# ticket: 254
+
def double_target(a, b):
"""
>>> double_target(0, 4)
+# ticket: 601
cdef unsigned long size2():
return 3
+# ticket: 533
def for_in():
"""
+# ticket: 372
+
cimport cython
@cython.test_assert_path_exists("//ForFromStatNode")
+# ticket: 228
+
__doc__ = u"""
>>> def py_iterator():
... if True: return
+# ticket: 494
+
__doc__ = """
>>> A.foo = foo
>>> print A().foo()
+# ticket: 494
+
cimport cython
class SomeNumber(object):
--- /dev/null
+# mode: run
+# tag: generators, lambda
+
+def genexpr():
+ """
+ >>> genexpr()
+ [0, 2, 4, 6, 8]
+ """
+ x = 'abc'
+ result = list( x*2 for x in range(5) )
+ assert x == 'abc' # don't leak
+ return result
+
+def genexpr_if():
+ """
+ >>> genexpr_if()
+ [0, 4, 8]
+ """
+ x = 'abc'
+ result = list( x*2 for x in range(5) if x % 2 == 0 )
+ assert x == 'abc' # don't leak
+ return result
+
+def genexpr_with_lambda():
+ """
+ >>> genexpr_with_lambda()
+ [0, 4, 8]
+ """
+ x = 'abc'
+ result = list( x*2 for x in range(5) if (lambda x:x % 2)(x) == 0 )
+ assert x == 'abc' # don't leak
+ return result
+
+def genexpr_of_lambdas(int N):
+ """
+ >>> [ (f(), g()) for f,g in genexpr_of_lambdas(5) ]
+ [(0, 0), (1, 2), (2, 4), (3, 6), (4, 8)]
+ """
+ return ( ((lambda : x), (lambda : x*2)) for x in range(N) )
--- /dev/null
+# mode: run
+# tag: typeinference, generators
+
+cimport cython
+
+def test_type_inference():
+ """
+ >>> list(test_type_inference())
+ [(2.0, 'double'), (2.0, 'double'), (2.0, 'double')]
+ """
+ x = 1.0
+ for i in range(3):
+ yield x * 2.0, cython.typeof(x)
+
+def test_unicode_loop():
+ """
+ >>> chars = list(test_unicode_loop())
+ 1 Py_UCS4
+ 2 Py_UCS4
+ 2 Py_UCS4
+ 2 Py_UCS4
+ 2 Py_UCS4
+ >>> len(chars)
+ 4
+ >>> ''.join(chars) == 'abcd'
+ True
+ """
+ ustr = u'abcd'
+ print 1, cython.typeof(ustr[0])
+ for c in ustr:
+ print 2, cython.typeof(c)
+ yield c
+
+def test_nonlocal_disables_inference():
+ """
+ >>> chars = list(test_nonlocal_disables_inference())
+ 1 Python object
+ 2 Python object
+ 2 Python object
+ >>> len(chars)
+ 2
+ >>> ''.join(chars) == 'ab'
+ True
+ """
+ ustr = u'ab'
+ print 1, cython.typeof(ustr[0])
+ def gen():
+ nonlocal ustr
+ for c in ustr:
+ print 2, cython.typeof(c)
+ yield c
+ return gen()
--- /dev/null
+# mode: run
+# tag: generators
+
+try:
+ from builtins import next # Py3k
+except ImportError:
+ def next(it):
+ return it.next()
+
+if hasattr(__builtins__, 'GeneratorExit'):
+ GeneratorExit = __builtins__.GeneratorExit
+else: # < 2.5
+ GeneratorExit = StopIteration
+
+def very_simple():
+ """
+ >>> x = very_simple()
+ >>> next(x)
+ 1
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> x = very_simple()
+ >>> x.send(1)
+ Traceback (most recent call last):
+ TypeError: can't send non-None value to a just-started generator
+ """
+ yield 1
+
+
+def simple():
+ """
+ >>> x = simple()
+ >>> list(x)
+ [1, 2, 3]
+ """
+ yield 1
+ yield 2
+ yield 3
+
+def simple_seq(seq):
+ """
+ >>> x = simple_seq("abc")
+ >>> list(x)
+ ['a', 'b', 'c']
+ """
+ for i in seq:
+ yield i
+
+def simple_send():
+ """
+ >>> x = simple_send()
+ >>> next(x)
+ >>> x.send(1)
+ 1
+ >>> x.send(2)
+ 2
+ >>> x.send(3)
+ 3
+ """
+ i = None
+ while True:
+ i = yield i
+
+def raising():
+ """
+ >>> x = raising()
+ >>> next(x)
+ Traceback (most recent call last):
+ KeyError: 'foo'
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ yield {}['foo']
+
+def with_outer(*args):
+ """
+ >>> x = with_outer(1, 2, 3)
+ >>> list(x())
+ [1, 2, 3]
+ """
+ def generator():
+ for i in args:
+ yield i
+ return generator
+
+def with_outer_raising(*args):
+ """
+ >>> x = with_outer_raising(1, 2, 3)
+ >>> list(x())
+ [1, 2, 3]
+ """
+ def generator():
+ for i in args:
+ yield i
+ raise StopIteration
+ return generator
+
+def test_close():
+ """
+ >>> x = test_close()
+ >>> x.close()
+ >>> x = test_close()
+ >>> next(x)
+ >>> x.close()
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ while True:
+ yield
+
+def test_ignore_close():
+ """
+ >>> x = test_ignore_close()
+ >>> x.close()
+ >>> x = test_ignore_close()
+ >>> next(x)
+ >>> x.close()
+ Traceback (most recent call last):
+ RuntimeError: generator ignored GeneratorExit
+ """
+ try:
+ yield
+ except GeneratorExit:
+ yield
+
+def check_throw():
+ """
+ >>> x = check_throw()
+ >>> x.throw(ValueError)
+ Traceback (most recent call last):
+ ValueError
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> x = check_throw()
+ >>> next(x)
+ >>> x.throw(ValueError)
+ >>> next(x)
+ >>> x.throw(IndexError, "oops")
+ Traceback (most recent call last):
+ IndexError: oops
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ while True:
+ try:
+ yield
+ except ValueError:
+ pass
+
+def test_first_assignment():
+ """
+ >>> gen = test_first_assignment()
+ >>> next(gen)
+ 5
+ >>> next(gen)
+ 10
+ >>> next(gen)
+ (5, 10)
+ """
+ cdef x = 5 # first
+ yield x
+ cdef y = 10 # first
+ yield y
+ yield (x,y)
+
+def test_swap_assignment():
+ """
+ >>> gen = test_swap_assignment()
+ >>> next(gen)
+ (5, 10)
+ >>> next(gen)
+ (10, 5)
+ """
+ x,y = 5,10
+ yield (x,y)
+ x,y = y,x # no ref-counting here
+ yield (x,y)
+
+
+class Foo(object):
+ """
+ >>> obj = Foo()
+ >>> list(obj.simple(1, 2, 3))
+ [1, 2, 3]
+ """
+ def simple(self, *args):
+ for i in args:
+ yield i
+
+def generator_nonlocal():
+ """
+ >>> g = generator_nonlocal()
+ >>> list(g(5))
+ [2, 3, 4, 5, 6]
+ """
+ def f(x):
+ def g(y):
+ nonlocal x
+ for i in range(y):
+ x += 1
+ yield x
+ return g
+ return f(1)
+
+def test_nested(a, b, c):
+ """
+ >>> obj = test_nested(1, 2, 3)
+ >>> [i() for i in obj]
+ [1, 2, 3, 4]
+ """
+ def one():
+ return a
+ def two():
+ return b
+ def three():
+ return c
+ def new_closure(a, b):
+ def sum():
+ return a + b
+ return sum
+ yield one
+ yield two
+ yield three
+ yield new_closure(a, c)
+
+
+def tolist(func):
+ def wrapper(*args, **kwargs):
+ return list(func(*args, **kwargs))
+ return wrapper
+
+@tolist
+def test_decorated(*args):
+ """
+ >>> test_decorated(1, 2, 3)
+ [1, 2, 3]
+ """
+ for i in args:
+ yield i
+
+def test_return(a):
+ """
+ >>> d = dict()
+ >>> obj = test_return(d)
+ >>> next(obj)
+ 1
+ >>> next(obj)
+ Traceback (most recent call last):
+ StopIteration
+ >>> d['i_was_here']
+ True
+ """
+ yield 1
+ a['i_was_here'] = True
+ return
+
+def test_copied_yield(foo):
+ """
+ >>> class Manager(object):
+ ... def __enter__(self):
+ ... return self
+ ... def __exit__(self, type, value, tb):
+ ... pass
+ >>> list(test_copied_yield(Manager()))
+ [1]
+ """
+ with foo:
+ yield 1
+
+def test_nested_yield():
+ """
+ >>> obj = test_nested_yield()
+ >>> next(obj)
+ 1
+ >>> obj.send(2)
+ 2
+ >>> obj.send(3)
+ 3
+ >>> obj.send(4)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ yield (yield (yield 1))
+
+def test_inside_lambda():
+ """
+ >>> obj = test_inside_lambda()()
+ >>> next(obj)
+ 1
+ >>> next(obj)
+ 2
+ >>> next(obj)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ return lambda:((yield 1), (yield 2))
+
+def test_nested_gen(int n):
+ """
+ >>> [list(a) for a in test_nested_gen(5)]
+ [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]
+ """
+ for a in range(n):
+ yield (b for b in range(a))
+
+def test_lambda(n):
+ """
+ >>> [i() for i in test_lambda(3)]
+ [0, 1, 2]
+ """
+ for i in range(n):
+ yield lambda : i
--- /dev/null
+# mode: run
+# tag: generators
+
+try:
+ from builtins import next # Py3k
+except ImportError:
+ def next(it):
+ return it.next()
+
+
+def very_simple():
+ """
+ >>> x = very_simple()
+ >>> next(x)
+ 1
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> x = very_simple()
+ >>> x.send(1)
+ Traceback (most recent call last):
+ TypeError: can't send non-None value to a just-started generator
+ """
+ yield 1
+
+
+def simple():
+ """
+ >>> x = simple()
+ >>> list(x)
+ [1, 2, 3]
+ """
+ yield 1
+ yield 2
+ yield 3
+
+def simple_seq(seq):
+ """
+ >>> x = simple_seq("abc")
+ >>> list(x)
+ ['a', 'b', 'c']
+ """
+ for i in seq:
+ yield i
+
+def simple_send():
+ """
+ >>> x = simple_send()
+ >>> next(x)
+ >>> x.send(1)
+ 1
+ >>> x.send(2)
+ 2
+ >>> x.send(3)
+ 3
+ """
+ i = None
+ while True:
+ i = yield i
+
+def raising():
+ """
+ >>> x = raising()
+ >>> next(x)
+ Traceback (most recent call last):
+ KeyError: 'foo'
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ yield {}['foo']
+
+def with_outer(*args):
+ """
+ >>> x = with_outer(1, 2, 3)
+ >>> list(x())
+ [1, 2, 3]
+ """
+ def generator():
+ for i in args:
+ yield i
+ return generator
+
+def with_outer_raising(*args):
+ """
+ >>> x = with_outer_raising(1, 2, 3)
+ >>> list(x())
+ [1, 2, 3]
+ """
+ def generator():
+ for i in args:
+ yield i
+ raise StopIteration
+ return generator
+
+def test_close():
+ """
+ >>> x = test_close()
+ >>> x.close()
+ >>> x = test_close()
+ >>> next(x)
+ >>> x.close()
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ while True:
+ yield
+
+def test_ignore_close():
+ """
+ >>> x = test_ignore_close()
+ >>> x.close()
+ >>> x = test_ignore_close()
+ >>> next(x)
+ >>> x.close()
+ Traceback (most recent call last):
+ RuntimeError: generator ignored GeneratorExit
+ """
+ try:
+ yield
+ except GeneratorExit:
+ yield
+
+def check_throw():
+ """
+ >>> x = check_throw()
+ >>> x.throw(ValueError)
+ Traceback (most recent call last):
+ ValueError
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ >>> x = check_throw()
+ >>> next(x)
+ >>> x.throw(ValueError)
+ >>> next(x)
+ >>> x.throw(IndexError, "oops")
+ Traceback (most recent call last):
+ IndexError: oops
+ >>> next(x)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ while True:
+ try:
+ yield
+ except ValueError:
+ pass
+
+def check_yield_in_except():
+ """
+ >>> import sys
+ >>> orig_exc = sys.exc_info()[0]
+ >>> g = check_yield_in_except()
+ >>> next(g)
+ >>> next(g)
+ >>> orig_exc is sys.exc_info()[0] or sys.exc_info()[0]
+ True
+ """
+ try:
+ yield
+ raise ValueError
+ except ValueError:
+ yield
+
+def test_swap_assignment():
+ """
+ >>> gen = test_swap_assignment()
+ >>> next(gen)
+ (5, 10)
+ >>> next(gen)
+ (10, 5)
+ """
+ x,y = 5,10
+ yield (x,y)
+ x,y = y,x # no ref-counting here
+ yield (x,y)
+
+
+class Foo(object):
+ """
+ >>> obj = Foo()
+ >>> list(obj.simple(1, 2, 3))
+ [1, 2, 3]
+ """
+ def simple(self, *args):
+ for i in args:
+ yield i
+
+def test_nested(a, b, c):
+ """
+ >>> obj = test_nested(1, 2, 3)
+ >>> [i() for i in obj]
+ [1, 2, 3, 4]
+ """
+ def one():
+ return a
+ def two():
+ return b
+ def three():
+ return c
+ def new_closure(a, b):
+ def sum():
+ return a + b
+ return sum
+ yield one
+ yield two
+ yield three
+ yield new_closure(a, c)
+
+
+def tolist(func):
+ def wrapper(*args, **kwargs):
+ return list(func(*args, **kwargs))
+ return wrapper
+
+@tolist
+def test_decorated(*args):
+ """
+ >>> test_decorated(1, 2, 3)
+ [1, 2, 3]
+ """
+ for i in args:
+ yield i
+
+def test_return(a):
+ """
+ >>> d = dict()
+ >>> obj = test_return(d)
+ >>> next(obj)
+ 1
+ >>> next(obj)
+ Traceback (most recent call last):
+ StopIteration
+ >>> d['i_was_here']
+ True
+ """
+ yield 1
+ a['i_was_here'] = True
+ return
+
+def test_copied_yield(foo):
+ """
+ >>> class Manager(object):
+ ... def __enter__(self):
+ ... return self
+ ... def __exit__(self, type, value, tb):
+ ... pass
+ >>> list(test_copied_yield(Manager()))
+ [1]
+ """
+ with foo:
+ yield 1
+
+def test_nested_yield():
+ """
+ >>> obj = test_nested_yield()
+ >>> next(obj)
+ 1
+ >>> obj.send(2)
+ 2
+ >>> obj.send(3)
+ 3
+ >>> obj.send(4)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ yield (yield (yield 1))
+
+def test_inside_lambda():
+ """
+ >>> obj = test_inside_lambda()()
+ >>> next(obj)
+ 1
+ >>> next(obj)
+ 2
+ >>> next(obj)
+ Traceback (most recent call last):
+ StopIteration
+ """
+ return lambda:((yield 1), (yield 2))
+
+def test_nested_gen(n):
+ """
+ >>> [list(a) for a in test_nested_gen(5)]
+ [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]
+ """
+ for a in range(n):
+ yield (b for b in range(a))
+
+def test_lambda(n):
+ """
+ >>> [i() for i in test_lambda(3)]
+ [0, 1, 2]
+ """
+ for i in range(n):
+ yield lambda : i
+# ticket: 491
def test_genexpr():
"""
+# ticket: 600
cimport cython
+# ticket: 326
+
__doc__ = u"""
>>> hash(A(5))
+# ticket: 267
+
"""
>>> constants(4)
1
cdef type t
from sys import maxunicode
- print maxunicode == sys.maxunicode
+ print(maxunicode == sys.maxunicode)
from types import ModuleType as t
- print t is types.ModuleType
+ print(t is types.ModuleType)
try:
from sys import version_info as maxunicode
except TypeError, e:
- print e
+ print(e)
try:
from sys import maxunicode as t
except TypeError, e:
- print e
+ print(e)
+# ticket: 544
def count(i=[0]):
i[0] += 1
+# ticket: 400
cimport cython
+# ticket: 431
+
__doc__ = u"""
>>> s == s_interned
True
+# ticket: 562
+
class IPOW:
"""
>>> IPOW().__ipow__('a')
+# mode: run
+# tag: lambda
+# ticket: 195
+
__doc__ = u"""
#>>> py_identity = lambda x:x
#>>> py_identity(1) == cy_identity(1)
+# mode: run
+# tag: lambda
+# ticket: 605
+
cdef int cdef_CONST = 123
CONST = 456
+# mode: run
+# tag: lambda
+# ticket: 603
+
# Module scope lambda functions
+
__doc__ = """
>>> pow2(16)
256
+# ticket: 237
#def add_large_c():
# cdef unsigned long long val = 2**30 + 2**30
# return val
+# tag: cpp
+
cimport libcpp
cimport libcpp.deque
+# mode: run
+# tag: closures
+# ticket: 598
# cython: language_level=3
def list_comp_in_closure():
-__doc__ = u"""
->>> sorted( get_locals(1,2,3, k=5) .items())
-[('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
-
-"""
+# mode: run
+# tag: builtins, locals, dir
def get_locals(x, *args, **kwds):
+ """
+ >>> sorted( get_locals(1,2,3, k=5) .items())
+ [('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
+ """
cdef int z = 5
y = "hi"
return locals()
+def get_dir(x, *args, **kwds):
+ """
+ >>> sorted( get_dir(1,2,3, k=5) )
+ ['args', 'kwds', 'x', 'y', 'z']
+ """
+ cdef int z = 5
+ y = "hi"
+ return dir()
+
def in_locals(x, *args, **kwds):
"""
>>> in_locals('z')
y = "hi"
return x in locals()
+def in_dir(x, *args, **kwds):
+ """
+ >>> in_dir('z')
+ True
+ >>> in_dir('args')
+ True
+ >>> in_dir('X')
+ False
+ """
+ cdef int z = 5
+ y = "hi"
+ return x in dir()
+
def sorted(it):
l = list(it)
l.sort()
+# ticket: 430
+
__doc__ = u"""
>>> sorted( get_locals(1,2,3, k=5) .items())
[('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
+# ticket: 429
+
__doc__ = u"""
>>> sorted( get_locals(1,2,3, k=5) .items())
[('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
+# ticket: 422
+
"""
>>> Foo.incr.__module__ is not None
True
+# ticket: 5
# this is ticket #5
__doc__ = u"""
+# ticket: 470
+
__doc__ = u"""
>>> func(**{'a' : 7})
True
--- /dev/null
+def simple():
+ """
+ >>> simple()
+ 1
+ 2
+ """
+ x = 1
+ y = 2
+ def f():
+ nonlocal x
+ nonlocal x, y
+ print(x)
+ print(y)
+ f()
+
+def assign():
+ """
+ >>> assign()
+ 1
+ """
+ xx = 0
+ def ff():
+ nonlocal xx
+ xx += 1
+ print(xx)
+ ff()
+
+def nested():
+ """
+ >>> nested()
+ 1
+ """
+ x = 0
+ def fx():
+ def gx():
+ nonlocal x
+ x=1
+ print(x)
+ return gx
+ fx()()
+
+def arg(x):
+ """
+ >>> arg('x')
+ xyy
+ """
+ def appendy():
+ nonlocal x
+ x += 'y'
+ x+='y'
+ appendy()
+ print x
+ return
+
+def argtype(int n):
+ """
+ >>> argtype(0)
+ 1
+ """
+ def inc():
+ nonlocal n
+ n += 1
+ inc()
+ print n
+ return
+
+def ping_pong():
+ """
+ >>> f = ping_pong()
+ >>> inc, dec = f(0)
+ >>> inc()
+ 1
+ >>> inc()
+ 2
+ >>> dec()
+ 1
+ >>> inc()
+ 2
+ >>> dec()
+ 1
+ >>> dec()
+ 0
+ """
+ def f(x):
+ def inc():
+ nonlocal x
+ x += 1
+ return x
+ def dec():
+ nonlocal x
+ x -= 1
+ return x
+ return inc, dec
+ return f
+
+def methods():
+ """
+ >>> f = methods()
+ >>> c = f(0)
+ >>> c.inc()
+ 1
+ >>> c.inc()
+ 2
+ >>> c.dec()
+ 1
+ >>> c.dec()
+ 0
+ """
+ def f(x):
+ class c:
+ def inc(self):
+ nonlocal x
+ x += 1
+ return x
+ def dec(self):
+ nonlocal x
+ x -= 1
+ return x
+ return c()
+ return f
+
+def class_body(int x, y):
+ """
+ >>> c = class_body(2,99)
+ >>> c.z
+ (3, 2)
+ >>> c.x #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ AttributeError: ...
+ >>> c.y #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ AttributeError: ...
+ """
+ class c(object):
+ nonlocal x
+ nonlocal y
+ y = 2
+ x += 1
+ z = x,y
+ return c()
+
+def nested_nonlocals(x):
+ """
+ >>> g = nested_nonlocals(1)
+ >>> h = g()
+ >>> h()
+ 3
+ """
+ def g():
+ nonlocal x
+ x -= 2
+ def h():
+ nonlocal x
+ x += 4
+ return x
+ return h
+ return g
+# ticket: 172
+# tag: numpy
+
__doc__ = u"""
>>> 1
1
+# ticket: 155
+# tag: numpy
+
"""
>>> myfunc()
0.5
+# tag: numpy
+
"""
>>> import sys
>>> 'numpy' in sys.modules
+# tag: numpy
# cannot be named "numpy" in order to not clash with the numpy module!
cimport numpy as np
dtype=[('x', '!f8'), ('y', '!f8')])
"""
+
+ if np.__version__ >= '1.6':
+ __doc__ += u"""
+ The following expose bugs in Numpy (versions prior to 2011-04-02):
+
+ >>> print(test_partially_packed_align(np.zeros((1,), dtype=np.dtype([('a', 'b'), ('b', 'i'), ('sub', np.dtype('b,i')), ('c', 'i')], align=True))))
+ array([(22, 23, (24, 25), 26)],
+ dtype=[('a', '|i1'), ('', '|V3'), ('b', '!i4'), ('sub', [('f0', '|i1'), ('f1', '!i4')]), ('', '|V3'), ('c', '!i4')])
+
+ >>> print(test_partially_packed_align_2(np.zeros((1,), dtype=np.dtype([('a', 'b'), ('b', 'i'), ('c', 'b'), ('sub', np.dtype('b,i', align=True))]))))
+ array([(22, 23, 24, (27, 28))],
+ dtype=[('a', '|i1'), ('b', '!i4'), ('c', '|i1'), ('sub', [('f0', '|i1'), ('', '|V3'), ('f1', '!i4')])])
+
+ >>> print(test_partially_packed_align(np.zeros((1,), dtype=np.dtype([('a', 'b'), ('b', 'i'), ('sub', np.dtype('b,i')), ('c', 'i')], align=False)))) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: ...
+
+ >>> print(test_partially_packed_align_2(np.zeros((1,), dtype=np.dtype([('a', 'b'), ('b', 'i'), ('c', 'b'), ('sub', np.dtype('b,i', align=False))])))) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ ValueError: ...
+ """
+
except:
__doc__ = u""
char a
int b
+cdef struct PartiallyPackedStruct:
+ char a
+ int b
+ PackedStruct sub
+ int c
+
+cdef packed struct PartiallyPackedStruct2:
+ char a
+ int b
+ char c
+ UnpackedStruct sub
+
def test_packed_align(np.ndarray[PackedStruct] arr):
arr[0].a = 22
arr[0].b = 23
arr[0].b = 23
return repr(arr).replace('<', '!').replace('>', '!')
+def test_partially_packed_align(np.ndarray[PartiallyPackedStruct] arr):
+ arr[0].a = 22
+ arr[0].b = 23
+ arr[0].sub.a = 24
+ arr[0].sub.b = 25
+ arr[0].c = 26
+ return repr(arr).replace('<', '!').replace('>', '!')
+
+def test_partially_packed_align_2(np.ndarray[PartiallyPackedStruct2] arr):
+ arr[0].a = 22
+ arr[0].b = 23
+ arr[0].c = 24
+ arr[0].sub.a = 27
+ arr[0].sub.b = 28
+ return repr(arr).replace('<', '!').replace('>', '!')
+
def test_complextypes():
cdef np.complex64_t x64 = 1, y64 = 1j
cdef np.complex128_t x128 = 1, y128 = 1j
+# ticket: 290
+
"""
>>> f()
(9, 9)
+# ticket: 425
+
cimport cython
@cython.test_assert_path_exists(
+# tag: posix
from libc.stdio cimport *
from posix.unistd cimport *
from posix.fcntl cimport *
+# tag: pstats
# cython: profile = True
__doc__ = u"""
KeyError: 'f_noprof'
>>> short_stats['f_raise']
100
+
+ >>> short_stats['withgil_prof']
+ 100
+ >>> short_stats['withgil_noprof']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'withgil_noprof'
+
+ >>> short_stats['nogil_prof']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'nogil_prof'
+ >>> short_stats['nogil_noprof']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'nogil_noprof'
+
>>> try:
... os.unlink(statsfile)
... except:
n += f_inline(i)
n += f_inline_prof(i)
n += f_noprof(i)
+ n += nogil_noprof(i)
+ n += nogil_prof(i)
+ n += withgil_noprof(i)
+ n += withgil_prof(i)
try:
n += f_raise(i+2)
except RuntimeError:
cdef long f_raise(long) except -2:
raise RuntimeError
+
+@cython.profile(False)
+cdef int withgil_noprof(long a) with gil:
+ return (a)
+@cython.profile(True)
+cdef int withgil_prof(long a) with gil:
+ return (a)
+
+@cython.profile(False)
+cdef int nogil_noprof(long a) nogil:
+ return a
+@cython.profile(True)
+cdef int nogil_prof(long a) nogil:
+ return a
+
import cython
+NULL = 5
+_NULL = NULL
+
def test_sizeof():
"""
>>> test_sizeof()
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]
+def test_declare(n):
+ """
+ >>> test_declare(100)
+ (100, 100)
+ >>> test_declare(100.5)
+ (100, 100)
+ >>> test_declare(None) #doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ TypeError: ...
+ """
+ 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):
return y[0]
## CURRENTLY BROKEN - FIXME!!
+## Is this test make sense? Implicit conversion in pure Python??
## @cython.locals(x=cython.int)
## @cython.locals(y=cython.bint)
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])
+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
+def test_struct(n, x):
+ """
+ >>> test_struct(389, 1.64493)
+ (389, 1.64493)
+ """
+ a = cython.declare(MyStruct2)
+ a[0] = MyStruct(is_integral=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
@my_locals(a=cython.p_void)
def test_imports():
"""
- >>> test_imports() # (True, True)
- True
+ >>> test_imports()
+ (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
+ return a == d, compiled == my_compiled
## CURRENTLY BROKEN - FIXME!!
-## MyStruct3 = typedef(MyStruct[3])
-## MyStruct4 = my_typedef(MyStruct[4])
-## MyStruct5 = cy.typedef(MyStruct[5])
+# MyStruct3 = typedef(MyStruct[3])
+# MyStruct4 = my_typedef(MyStruct[4])
+# MyStruct5 = cy.typedef(MyStruct[5])
def test_declare_c_types(n):
"""
+# ticket: 489
+
"""
>>> xxx
[0, 1, 2, 3]
+# ticket: 313
# Ensure casting still works to void*
"""
+# ticket: 650
cimport cython
... else: print('NOT RAISED!')
"""
raise MemoryError()
+
+def raise_me_instance_value():
+ """
+ >>> raise_me_instance_value()
+ Traceback (most recent call last):
+ ...
+ MemoryError: oom
+ """
+ raise MemoryError("oom")
+# ticket: 203
+
cdef int get_bound(int m):
print u"get_bound(%s)"%m
return m
#!/usr/bin/env python
+
__doc__=u"""
>>> t = RefCountInMeth()
>>> t.chk_meth()
--- /dev/null
+# cython: language_level=3
+import sys
+# fool Python we are in distutils
+if sys.version_info >= (3,):
+ __name__='distutils.cytest_relativeimport_T542'
+else:
+ __name__=b'distutils.cytest_relativeimport_T542'
+from distutils import cmd, core, version
+
+from .core import *
+def test_relative():
+ """
+ >>> test_relative() == (cmd, core, 'distutils.version')
+ True
+ """
+ from . import cmd, core
+ from . import (version, core)
+ from .version import __name__
+ return cmd, core, __name__
+
+def test_absolute():
+ """
+ >>> test_absolute() # doctest: +ELLIPSIS
+ Traceback (most recent call last):
+ ImportError: No module named ...debug...
+ """
+ import debug
+ return
+
+__doc__ = """
+>>> setup == core.setup
+True
+"""
--- /dev/null
+from distutils import core, version
+__name__='distutils.core.cytest_relativeimport_T542' # fool Python we are in distutils
+from . import *
+
+__doc__ = """
+>>> core.setup == setup
+True
+"""
+# ticket: 404
+
cdef long foo(long x):
print "foo(%s)" % x
return x
+# ticket: 561
# The patch in #561 changes code generation for most special methods
# to remove the Cython-generated wrapper and let PyType_Ready()
# generate its own wrapper. (This wrapper would be used, for instance,
+# ticket: 561
+# tag: py2
# This file tests the behavior of special methods under Python 2
# after #561. (Only methods whose behavior differs between Python 2 and 3
# are tested here; see special_methods_T561.pyx for the rest of the tests.)
+# ticket: 561
+# tag: py3
# This file tests the behavior of special methods under Python 3
# after #561. (Only methods whose behavior differs between Python 2 and 3
# are tested here; see special_methods_T561.pyx for the rest of the tests.)
+# ticket: 399
+
__doc__ = u"""
>>> test(-2)
-2
+# ticket: 664
+
def assign():
"""
>>> assign()
+# ticket: 412
+
cdef int i = 'x'
cdef char c = 'x'
cdef char* s = 'x'
>>> len(bytes_uescape)
28
+ >>> (sys.version_info[0] >= 3 and sys.maxunicode == 1114111 and len(str_uescape) == 3 or
+ ... sys.version_info[0] >= 3 and sys.maxunicode == 65535 and len(str_uescape) == 4 or
+ ... sys.version_info[0] < 3 and len(str_uescape) == 17 or
+ ... len(str_uescape))
+ True
+ >>> (sys.version_info[0] >= 3 and str_uescape[0] == 'c' or
+ ... sys.version_info[0] < 3 and str_uescape[0] == '\\' or
+ ... str_uescape[0])
+ True
+ >>> print(str_uescape[-1])
+ B
+
>>> newlines == "Aaa\n"
True
uresc = ur'\12\'\"\\'
bytes_uescape = b'\u1234\U12345678\u\u1\u12\uX'
+str_uescape = '\u0063\U00012345\x42'
newlines = "Aaa\n"
+# ticket: 409
# Extracted from sage/plot/plot3d/index_face_set.pyx:502
# Turns out to be a bug in implementation of PEP 3132 (Extended Iterable Unpacking)
+# ticket: 654
# function call arguments
+# ticket: 454
cimport cython
-__doc__ = u"""
->>> print(foo())
-a
-"""
-
# Indirectly makes sure the cleanup happens correctly on breaking.
-def foo():
- for x in "abc":
+
+def try_except_break():
+ """
+ >>> print(try_except_break())
+ a
+ """
+ for x in list("abc"):
try:
x()
except:
break
- for x in "abc":
+ return x
+
+def try_break_except():
+ """
+ >>> print(try_break_except())
+ a
+ """
+ for x in list("abc"):
+ try:
+ break
+ except:
+ pass
+ return x
+
+def try_no_break_except_return():
+ """
+ >>> print(try_no_break_except_return())
+ a
+ """
+ for x in list("abc"):
try:
x()
+ break
except:
return x
+ return x
+# ticket: 298
+
"""
>>> func()
0 0
a = int(1)
assert typeof(a) == "Python object", typeof(a)
b = not int(3)
- assert typeof(b) == "int", typeof(b)
+ assert typeof(b) == "bint", typeof(b)
c = +int(3)
assert typeof(c) == "Python object", typeof(c)
d = -int(5)
+# ticket: 287
+
__doc__ = u"""
>>> print( "%d" % Int() )
2
+# ticket: 373
+
import math
cdef class MyClass:
+# ticket: 303
+
__doc__ = """
>>> readonly() #doctest: +ELLIPSIS
Traceback (most recent call last):
+# ticket: 417
#cython: autotestdict=True
cdef class Foo:
+# ticket: 359
+
__doc__ = u"""
>>> py_string1.decode('ASCII') == 'test toast taste'
True
+# ticket: 184
+
"""
>>> c_call()
(-10, 10)
+# ticket: 536
__doc__ = """
>>> inner_result
['ENTER']
->>> result
+>>> result # doctest: +ELLIPSIS
+['ENTER', ...EXIT (<...ValueError...>,...ValueError..., <traceback object at ...)...]
+
+>>> inner_result_no_exc
+['ENTER']
+>>> result_no_exc
['ENTER', 'EXIT (None, None, None)']
"""
-result = []
-
class ContextManager(object):
+ def __init__(self, result):
+ self.result = result
def __enter__(self):
- result.append("ENTER")
+ self.result.append("ENTER")
def __exit__(self, *values):
- result.append("EXIT %r" % (values,))
+ self.result.append("EXIT %r" % (values,))
+ return True
+
+result_no_exc = []
+
+with ContextManager(result_no_exc) as c:
+ inner_result_no_exc = result_no_exc[:]
+
+result = []
-with ContextManager() as c:
+with ContextManager(result) as c:
inner_result = result[:]
+ raise ValueError('TEST')
+
with ContextManager(u"value") as x:
pass
-def with_return():
- """
- >>> with_return()
- enter
- exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
- """
- with ContextManager(u"value") as x:
- # FIXME: DISABLED - currently crashes!!
- # return x
- pass
-
def with_exception(exit_ret):
"""
>>> with_exception(None)
--- /dev/null
+import sys
+
+def typename(t):
+ name = type(t).__name__
+ if sys.version_info < (2,5):
+ if name == 'classobj' and issubclass(t, MyException):
+ name = 'type'
+ elif name == 'instance' and isinstance(t, MyException):
+ name = 'MyException'
+ return "<type '%s'>" % name
+
+class MyException(Exception):
+ pass
+
+class ContextManager(object):
+ def __init__(self, value, exit_ret = None):
+ self.value = value
+ self.exit_ret = exit_ret
+
+ def __exit__(self, a, b, tb):
+ print("exit %s %s %s" % (typename(a), typename(b), typename(tb)))
+ return self.exit_ret
+
+ def __enter__(self):
+ print("enter")
+ return self.value
+
+def no_as():
+ """
+ >>> no_as()
+ enter
+ hello
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager("value"):
+ print("hello")
+
+def basic():
+ """
+ >>> basic()
+ enter
+ value
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager("value") as x:
+ print(x)
+
+def with_pass():
+ """
+ >>> with_pass()
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager("value") as x:
+ pass
+
+def with_return():
+ """
+ >>> print(with_return())
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ value
+ """
+ with ContextManager("value") as x:
+ return x
+
+def with_break():
+ """
+ >>> print(with_break())
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ a
+ """
+ for c in list("abc"):
+ with ContextManager("value") as x:
+ break
+ print("FAILED")
+ return c
+
+def with_continue():
+ """
+ >>> print(with_continue())
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ enter
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ c
+ """
+ for c in list("abc"):
+ with ContextManager("value") as x:
+ continue
+ print("FAILED")
+ return c
+
+def with_exception(exit_ret):
+ """
+ >>> with_exception(None)
+ enter
+ value
+ exit <type 'type'> <type 'MyException'> <type 'traceback'>
+ outer except
+ >>> with_exception(True)
+ enter
+ value
+ exit <type 'type'> <type 'MyException'> <type 'traceback'>
+ """
+ try:
+ with ContextManager("value", exit_ret=exit_ret) as value:
+ print(value)
+ raise MyException()
+ except:
+ print("outer except")
+
+def functions_in_with():
+ """
+ >>> f = functions_in_with()
+ enter
+ exit <type 'type'> <type 'MyException'> <type 'traceback'>
+ outer except
+ >>> f(1)[0]
+ 1
+ >>> print(f(1)[1])
+ value
+ """
+ try:
+ with ContextManager("value") as value:
+ def f(x): return x, value
+ make = lambda x:x()
+ raise make(MyException)
+ except:
+ print("outer except")
+ return f
+
+def multitarget():
+ """
+ >>> multitarget()
+ enter
+ 1 2 3 4 5
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
+ print('%s %s %s %s %s' % (a, b, c, d, e))
+
+def tupletarget():
+ """
+ >>> tupletarget()
+ enter
+ (1, 2, (3, (4, 5)))
+ exit <type 'NoneType'> <type 'NoneType'> <type 'NoneType'>
+ """
+ with ContextManager((1, 2, (3, (4, 5)))) as t:
+ print(t)
+
+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('value') as y,\
+ ContextManager(3), ContextManager((1, 2, (3, (4, 5)))) as (a, b, (c, (d, e))):
+ with ContextManager('nested') as nested:
+ print(x)
+ print(y)
+ print('%s %s %s %s %s' % (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)
+# tag: cpp
cimport cpp_overload_wrapper_lib as cppwrap_lib
+# tag: cpp
+
cimport cython
+# tag: cpp
cimport cppwrap_lib