Commit 95d9d87b authored by Robert Bradshaw's avatar Robert Bradshaw

Merge branch 'master' of github.com:cython/cython

parents 7b9cfc30 40eff9ef
language: python language: python
sudo: false
cache:
pip: true
directories:
- $HOME/.ccache
python: python:
- 2.6
- 2.7 - 2.7
- 3.5
- 3.2 - 3.2
- 3.3 - 3.3
- 3.4 - 3.4
- 3.5 - 2.6
- 3.5-dev - 3.5-dev
- 3.6-dev
- pypy - pypy
- pypy3 - pypy3
env: env:
- BACKEND=c global:
- BACKEND=cpp - USE_CCACHE=1
- CCACHE_SLOPPINESS=pch_defines,time_macros
- CCACHE_COMPRESS=1
- CCACHE_MAXSIZE=100M
- PATH="/usr/lib/ccache:$PATH"
matrix:
- BACKEND=c
- BACKEND=cpp
branches: branches:
only: only:
- master - master
before_install:
- sudo apt-get update
- sudo apt-get install gdb python$( python -c 'import sys; print("%d.%d" % sys.version_info[:2])' )-dbg || true
- dpkg -l gdb || true
install: install:
- CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build - CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build
before_script: ccache -s
script: script:
- PYTHON_DBG="python$( python -c 'import sys; print("%d.%d" % sys.version_info[:2])' )-dbg" - PYTHON_DBG="python$( python -c 'import sys; print("%d.%d" % sys.version_info[:2])' )-dbg"
- if $PYTHON_DBG -V >&2; then CFLAGS="-O0 -ggdb" $PYTHON_DBG runtests.py -vv Debugger --backends=$BACKEND; fi - if $PYTHON_DBG -V >&2; then CFLAGS="-O0 -ggdb" $PYTHON_DBG runtests.py -vv Debugger --backends=$BACKEND; fi
- CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build_ext -i - CFLAGS="-O2 -ggdb -Wall -Wextra $(python -c 'import sys; print("-fno-strict-aliasing" if sys.version_info[0] == 2 else "")')" python setup.py build_ext -i
- CFLAGS="-O0 -ggdb -Wall -Wextra" python runtests.py -vv -x Debugger --backends=$BACKEND - CFLAGS="-O0 -ggdb -Wall -Wextra" python runtests.py -vv -x Debugger --backends=$BACKEND -j4
matrix: matrix:
allow_failures: allow_failures:
- python: pypy - python: pypy
- python: pypy3 - python: pypy3
- python: 3.5-dev - python: 3.5-dev
- python: 3.6-dev
exclude: exclude:
- python: pypy - python: pypy
env: BACKEND=cpp env: BACKEND=cpp
- python: pypy3 - python: pypy3
env: BACKEND=cpp env: BACKEND=cpp
addons:
apt:
packages:
- gdb
- python-dbg
- python3-dbg
...@@ -2,6 +2,17 @@ ...@@ -2,6 +2,17 @@
Cython Changelog Cython Changelog
================ ================
0.25 (2016-??-??)
=================
Features added
--------------
* IPython cell magic supports "-3" argument as in "%%cython -3".
* for-loop iteration over "std::string".
0.24 (2016-04-04) 0.24 (2016-04-04)
================= =================
......
...@@ -196,20 +196,21 @@ class DistutilsInfo(object): ...@@ -196,20 +196,21 @@ class DistutilsInfo(object):
self.values = {} self.values = {}
if source is not None: if source is not None:
for line in line_iter(source): for line in line_iter(source):
line = line.strip() line = line.lstrip()
if line != '' and line[0] != '#': if not line:
continue
if line[0] != '#':
break break
line = line[1:].strip() line = line[1:].lstrip()
if line[:10] == 'distutils:': if line[:10] == 'distutils:':
line = line[10:] key, _, value = [s.strip() for s in line[10:].partition('=')]
ix = line.index('=')
key = str(line[:ix].strip())
value = line[ix+1:].strip()
type = distutils_settings[key] type = distutils_settings[key]
if type in (list, transitive_list): if type in (list, transitive_list):
value = parse_list(value) value = parse_list(value)
if key == 'define_macros': if key == 'define_macros':
value = [tuple(macro.split('=')) for macro in value] value = [tuple(macro.split('=', 1))
if '=' in macro else (macro, None)
for macro in value]
self.values[key] = value self.values[key] = value
elif exn is not None: elif exn is not None:
for key in distutils_settings: for key in distutils_settings:
......
import sys
from .Dependencies import cythonize
if 'setuptools' in sys.modules:
from setuptools.command import build_ext as _build_ext
else:
from distutils.command import build_ext as _build_ext
class build_ext(_build_ext.build_ext):
def finalize_options(self):
self.distribution.ext_modules[:] = cythonize(
self.distribution.ext_modules)
super(build_ext, self).finalize_options()
...@@ -151,6 +151,10 @@ class CythonMagics(Magics): ...@@ -151,6 +151,10 @@ class CythonMagics(Magics):
self._import_all(module) self._import_all(module)
@magic_arguments.magic_arguments() @magic_arguments.magic_arguments()
@magic_arguments.argument(
'-3', dest='cython3', action='store_true', default=False,
help="Switch to Python 3 syntax."
)
@magic_arguments.argument( @magic_arguments.argument(
'-c', '--compile-args', action='append', default=[], '-c', '--compile-args', action='append', default=[],
help="Extra flags to pass to compiler via the `extra_compile_args` " help="Extra flags to pass to compiler via the `extra_compile_args` "
...@@ -172,7 +176,7 @@ class CythonMagics(Magics): ...@@ -172,7 +176,7 @@ class CythonMagics(Magics):
) )
@magic_arguments.argument( @magic_arguments.argument(
'-L', dest='library_dirs', metavar='dir', action='append', default=[], '-L', dest='library_dirs', metavar='dir', action='append', default=[],
help="Add a path to the list of libary directories (can be specified " help="Add a path to the list of library directories (can be specified "
"multiple times)." "multiple times)."
) )
@magic_arguments.argument( @magic_arguments.argument(
...@@ -265,9 +269,11 @@ class CythonMagics(Magics): ...@@ -265,9 +269,11 @@ class CythonMagics(Magics):
try: try:
opts = dict( opts = dict(
quiet=quiet, quiet=quiet,
annotate = args.annotate, annotate=args.annotate,
force = True, force=True,
) )
if args.cython3:
opts['language_level'] = 3
build_extension.extensions = cythonize([extension], **opts) build_extension.extensions = cythonize([extension], **opts)
except CompileError: except CompileError:
return return
......
...@@ -22,10 +22,19 @@ except ImportError: ...@@ -22,10 +22,19 @@ except ImportError:
from Cython.TestUtils import CythonTest from Cython.TestUtils import CythonTest
ip = get_ipython() ip = get_ipython()
code = py3compat.str_to_unicode("""def f(x): code = py3compat.str_to_unicode("""\
def f(x):
return 2*x return 2*x
""") """)
cython3_code = py3compat.str_to_unicode("""\
def f(x):
return 2 / x
def call(x):
return f(*(x,))
""")
if sys.platform == 'win32': if sys.platform == 'win32':
# not using IPython's decorators here because they depend on "nose" # not using IPython's decorators here because they depend on "nose"
...@@ -77,6 +86,14 @@ class TestIPythonMagic(CythonTest): ...@@ -77,6 +86,14 @@ class TestIPythonMagic(CythonTest):
ip.ex('import mymodule; g = mymodule.f(10)') ip.ex('import mymodule; g = mymodule.f(10)')
self.assertEqual(ip.user_ns['g'], 20.0) self.assertEqual(ip.user_ns['g'], 20.0)
def test_cython3(self):
# The Cython module named 'mymodule' defines the function f.
ip.run_cell_magic('cython', '-3', cython3_code)
# This module can now be imported in the interactive namespace.
ip.ex('g = f(10); h = call(10)')
self.assertEqual(ip.user_ns['g'], 2.0 / 10.0)
self.assertEqual(ip.user_ns['h'], 2.0 / 10.0)
@skip_win32 @skip_win32
def test_extlibs(self): def test_extlibs(self):
code = py3compat.str_to_unicode(""" code = py3compat.str_to_unicode("""
......
from .Dependencies import cythonize from .Dependencies import cythonize
from .Distutils import build_ext
...@@ -6302,7 +6302,7 @@ class AttributeNode(ExprNode): ...@@ -6302,7 +6302,7 @@ class AttributeNode(ExprNode):
# as an ordinary function. # as an ordinary function.
if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'): if entry.func_cname and not hasattr(entry.type, 'op_arg_struct'):
cname = entry.func_cname cname = entry.func_cname
if entry.type.is_static_method: if entry.type.is_static_method or env.parent_scope.is_cpp_class_scope:
ctype = entry.type ctype = entry.type
elif type.is_cpp_class: elif type.is_cpp_class:
error(self.pos, "%s not a static member of %s" % (entry.name, type)) error(self.pos, "%s not a static member of %s" % (entry.name, type))
...@@ -9271,6 +9271,13 @@ class AwaitExprNode(YieldFromExprNode): ...@@ -9271,6 +9271,13 @@ class AwaitExprNode(YieldFromExprNode):
return "__Pyx_Coroutine_Yield_From" return "__Pyx_Coroutine_Yield_From"
class AIterAwaitExprNode(AwaitExprNode):
# 'await' expression node used in async-for loops to support the pre-Py3.5.2 'aiter' protocol
def yield_from_func(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineAIterYieldFrom", "Coroutine.c"))
return "__Pyx_Coroutine_AIter_Yield_From"
class AwaitIterNextExprNode(AwaitExprNode): class AwaitIterNextExprNode(AwaitExprNode):
# 'await' expression node as part of 'async for' iteration # 'await' expression node as part of 'async for' iteration
# #
......
...@@ -6145,7 +6145,7 @@ class _ForInStatNode(LoopNode, StatNode): ...@@ -6145,7 +6145,7 @@ class _ForInStatNode(LoopNode, StatNode):
# Base class of 'for-in' statements. # Base class of 'for-in' statements.
# #
# target ExprNode # target ExprNode
# iterator IteratorNode | AwaitExprNode(AsyncIteratorNode) # iterator IteratorNode | AIterAwaitExprNode(AsyncIteratorNode)
# body StatNode # body StatNode
# else_clause StatNode # else_clause StatNode
# item NextNode | AwaitExprNode(AsyncNextNode) # item NextNode | AwaitExprNode(AsyncNextNode)
...@@ -6251,7 +6251,7 @@ class ForInStatNode(_ForInStatNode): ...@@ -6251,7 +6251,7 @@ class ForInStatNode(_ForInStatNode):
class AsyncForStatNode(_ForInStatNode): class AsyncForStatNode(_ForInStatNode):
# 'async for' statement # 'async for' statement
# #
# iterator AwaitExprNode(AsyncIteratorNode) # iterator AIterAwaitExprNode(AsyncIteratorNode)
# item AwaitIterNextExprNode(AsyncIteratorNode) # item AwaitIterNextExprNode(AsyncIteratorNode)
is_async = True is_async = True
...@@ -6260,7 +6260,7 @@ class AsyncForStatNode(_ForInStatNode): ...@@ -6260,7 +6260,7 @@ class AsyncForStatNode(_ForInStatNode):
assert 'item' not in kw assert 'item' not in kw
from . import ExprNodes from . import ExprNodes
# AwaitExprNodes must appear before running MarkClosureVisitor # AwaitExprNodes must appear before running MarkClosureVisitor
kw['iterator'] = ExprNodes.AwaitExprNode(iterator.pos, arg=iterator) kw['iterator'] = ExprNodes.AIterAwaitExprNode(iterator.pos, arg=iterator)
kw['item'] = ExprNodes.AwaitIterNextExprNode(iterator.pos, arg=None) kw['item'] = ExprNodes.AwaitIterNextExprNode(iterator.pos, arg=None)
_ForInStatNode.__init__(self, pos, **kw) _ForInStatNode.__init__(self, pos, **kw)
......
...@@ -116,6 +116,7 @@ directive_defaults = { ...@@ -116,6 +116,7 @@ directive_defaults = {
'internal' : False, 'internal' : False,
'profile': False, 'profile': False,
'no_gc_clear': False, 'no_gc_clear': False,
'no_gc': False,
'linetrace': False, 'linetrace': False,
'emit_code_comments': True, # copy original source code into C code comments 'emit_code_comments': True, # copy original source code into C code comments
'annotation_typing': False, # read type declarations from Python function annotations 'annotation_typing': False, # read type declarations from Python function annotations
...@@ -246,6 +247,7 @@ directive_scopes = { # defaults to available everywhere ...@@ -246,6 +247,7 @@ directive_scopes = { # defaults to available everywhere
'inline' : ('function',), 'inline' : ('function',),
'staticmethod' : ('function',), # FIXME: analysis currently lacks more specific function scope 'staticmethod' : ('function',), # FIXME: analysis currently lacks more specific function scope
'no_gc_clear' : ('cclass',), 'no_gc_clear' : ('cclass',),
'no_gc' : ('cclass',),
'internal' : ('cclass',), 'internal' : ('cclass',),
'autotestdict' : ('module',), 'autotestdict' : ('module',),
'autotestdict.all' : ('module',), 'autotestdict.all' : ('module',),
......
...@@ -3231,6 +3231,7 @@ builtin_cpp_conversions = { ...@@ -3231,6 +3231,7 @@ builtin_cpp_conversions = {
"std::unordered_set": 1, "std::unordered_set": 1,
"std::map": 2, "std::map": 2,
"std::unordered_map": 2, "std::unordered_map": 2,
"std::complex": 1,
} }
class CppClassType(CType): class CppClassType(CType):
......
...@@ -1889,7 +1889,7 @@ class CClassScope(ClassScope): ...@@ -1889,7 +1889,7 @@ class CClassScope(ClassScope):
def needs_gc(self): def needs_gc(self):
# If the type or any of its base types have Python-valued # If the type or any of its base types have Python-valued
# C attributes, then it needs to participate in GC. # C attributes, then it needs to participate in GC.
if self.has_cyclic_pyobject_attrs: if self.has_cyclic_pyobject_attrs and not self.directives.get('no_gc', False):
return True return True
base_type = self.parent_type.base_type base_type = self.parent_type.base_type
if base_type and base_type.scope is not None: if base_type and base_type.scope is not None:
......
...@@ -14,6 +14,11 @@ from distutils.dep_util import newer, newer_group ...@@ -14,6 +14,11 @@ from distutils.dep_util import newer, newer_group
from distutils import log from distutils import log
from distutils.command import build_ext as _build_ext from distutils.command import build_ext as _build_ext
from distutils import sysconfig from distutils import sysconfig
import warnings
warnings.warn(
"Cython.Distutils.build_ext does not properly handle dependencies "
"and is deprectated. Use Cython.Build.build_ext instead.")
try: try:
from __builtin__ import basestring from __builtin__ import basestring
......
...@@ -31,6 +31,9 @@ cdef extern from "Python.h": ...@@ -31,6 +31,9 @@ cdef extern from "Python.h":
ctypedef int (*visitproc)(PyObject*, void *) ctypedef int (*visitproc)(PyObject*, void *)
ctypedef int (*traverseproc)(PyObject*, visitproc, void*) ctypedef int (*traverseproc)(PyObject*, visitproc, void*)
ctypedef object (*descrgetfunc)(object, object, object)
ctypedef int (*descrsetfunc)(object, object, object) except -1
ctypedef struct PyTypeObject: ctypedef struct PyTypeObject:
const char* tp_name const char* tp_name
const char* tp_doc const char* tp_doc
...@@ -53,6 +56,10 @@ cdef extern from "Python.h": ...@@ -53,6 +56,10 @@ cdef extern from "Python.h":
richcmpfunc tp_richcompare richcmpfunc tp_richcompare
PyTypeObject* tp_base PyTypeObject* tp_base
PyObject* tp_dict
descrgetfunc tp_descr_get
descrsetfunc tp_descr_set
ctypedef struct PyObject: ctypedef struct PyObject:
Py_ssize_t ob_refcnt Py_ssize_t ob_refcnt
......
...@@ -15,6 +15,40 @@ cdef extern from "<string>" namespace "std" nogil: ...@@ -15,6 +15,40 @@ cdef extern from "<string>" namespace "std" nogil:
# as a string formed by a repetition of character c, n times. # as a string formed by a repetition of character c, n times.
string(size_t, char) except + string(size_t, char) except +
cppclass iterator:
iterator()
char& operator*()
iterator(iterator &)
iterator operator++()
iterator operator--()
bint operator==(iterator)
bint operator!=(iterator)
cppclass reverse_iterator:
char& operator*()
iterator operator++()
iterator operator--()
iterator operator+(size_t)
iterator operator-(size_t)
bint operator==(reverse_iterator)
bint operator!=(reverse_iterator)
bint operator<(reverse_iterator)
bint operator>(reverse_iterator)
bint operator<=(reverse_iterator)
bint operator>=(reverse_iterator)
cppclass const_iterator(iterator):
pass
cppclass const_reverse_iterator(reverse_iterator):
pass
iterator begin()
const_iterator const_begin "begin"()
iterator end()
const_iterator const_end "end"()
reverse_iterator rbegin()
const_reverse_iterator const_rbegin "rbegin"()
reverse_iterator rend()
const_reverse_iterator const_rend "rend"()
const char* c_str() const char* c_str()
const char* data() const char* data()
size_t size() size_t size()
......
...@@ -118,7 +118,7 @@ optimization = _Optimization() ...@@ -118,7 +118,7 @@ optimization = _Optimization()
overflowcheck.fold = optimization.use_switch = \ overflowcheck.fold = optimization.use_switch = \
optimization.unpack_method_calls = lambda arg: _EmptyDecoratorAndManager() optimization.unpack_method_calls = lambda arg: _EmptyDecoratorAndManager()
final = internal = type_version_tag = no_gc_clear = _empty_decorator final = internal = type_version_tag = no_gc_clear = no_gc = _empty_decorator
def inline(f, *args, **kwds): def inline(f, *args, **kwds):
......
...@@ -45,15 +45,40 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject ...@@ -45,15 +45,40 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject
//////////////////// CoroutineYieldFrom.proto //////////////////// //////////////////// CoroutineYieldFrom.proto ////////////////////
static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source); #define __Pyx_Coroutine_Yield_From(gen, source) __Pyx__Coroutine_Yield_From(gen, source, 0)
static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source, int warn);
//////////////////// CoroutineYieldFrom //////////////////// //////////////////// CoroutineYieldFrom ////////////////////
//@requires: Coroutine //@requires: Coroutine
//@requires: GetAwaitIter //@requires: GetAwaitIter
static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source) { static int __Pyx_WarnAIterDeprecation(PyObject *aiter) {
int result;
#if PY_MAJOR_VERSION >= 3
result = PyErr_WarnFormat(
PyExc_PendingDeprecationWarning, 1,
"'%.100s' implements legacy __aiter__ protocol; "
"__aiter__ should return an asynchronous "
"iterator, not awaitable",
Py_TYPE(aiter)->tp_name);
#else
result = PyErr_WarnEx(
PyExc_PendingDeprecationWarning,
"object implements legacy __aiter__ protocol; "
"__aiter__ should return an asynchronous "
"iterator, not awaitable",
1);
#endif
return result != 0;
}
static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source, int warn) {
PyObject *retval; PyObject *retval;
if (__Pyx_Coroutine_CheckExact(source)) { if (__Pyx_Coroutine_CheckExact(source)) {
if (warn && unlikely(__Pyx_WarnAIterDeprecation(source))) {
/* Warning was converted to an error. */
return NULL;
}
retval = __Pyx_Generator_Next(source); retval = __Pyx_Generator_Next(source);
if (retval) { if (retval) {
Py_INCREF(source); Py_INCREF(source);
...@@ -64,6 +89,11 @@ static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject ...@@ -64,6 +89,11 @@ static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject
PyObject *source_gen = __Pyx__Coroutine_GetAwaitableIter(source); PyObject *source_gen = __Pyx__Coroutine_GetAwaitableIter(source);
if (unlikely(!source_gen)) if (unlikely(!source_gen))
return NULL; return NULL;
if (warn && unlikely(__Pyx_WarnAIterDeprecation(source))) {
/* Warning was converted to an error. */
Py_DECREF(source_gen);
return NULL;
}
// source_gen is now the iterator, make the first next() call // source_gen is now the iterator, make the first next() call
if (__Pyx_Coroutine_CheckExact(source_gen)) { if (__Pyx_Coroutine_CheckExact(source_gen)) {
retval = __Pyx_Generator_Next(source_gen); retval = __Pyx_Generator_Next(source_gen);
...@@ -80,6 +110,53 @@ static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject ...@@ -80,6 +110,53 @@ static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject
} }
//////////////////// CoroutineAIterYieldFrom.proto ////////////////////
static CYTHON_INLINE PyObject* __Pyx_Coroutine_AIter_Yield_From(__pyx_CoroutineObject *gen, PyObject *source);
//////////////////// CoroutineAIterYieldFrom ////////////////////
//@requires: CoroutineYieldFrom
static CYTHON_INLINE PyObject* __Pyx_Coroutine_AIter_Yield_From(__pyx_CoroutineObject *gen, PyObject *source) {
#if PY_MAJOR_VERSION >= 3
__Pyx_PyAsyncMethodsStruct* am = __Pyx_PyType_AsAsync(source);
if (likely(am && am->am_anext)) {
// Starting with CPython 3.5.2, __aiter__ should return
// asynchronous iterators directly (not awaitables that
// resolve to asynchronous iterators.)
//
// Therefore, we check if the object that was returned
// from __aiter__ has an __anext__ method. If it does,
// we return it directly as StopIteration result,
// which avoids yielding.
//
// See http://bugs.python.org/issue27243 for more
// details.
PyErr_SetObject(PyExc_StopIteration, source);
return NULL;
}
#endif
#if PY_VERSION_HEX < 0x030500B2
if (!__Pyx_PyType_AsAsync(source)) {
#ifdef __Pyx_Coroutine_USED
if (!__Pyx_Coroutine_CheckExact(source)) // quickly rule out a likely case
#endif
{
// same as above in slow
PyObject *method = __Pyx_PyObject_GetAttrStr(source, PYIDENT("__anext__"));
if (method) {
Py_DECREF(method);
PyErr_SetObject(PyExc_StopIteration, source);
return NULL;
}
PyErr_Clear();
}
}
#endif
return __Pyx__Coroutine_Yield_From(gen, source, 1);
}
//////////////////// GetAwaitIter.proto //////////////////// //////////////////// GetAwaitIter.proto ////////////////////
static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAwaitableIter(PyObject *o); /*proto*/ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAwaitableIter(PyObject *o); /*proto*/
...@@ -196,7 +273,7 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAsyncIter(PyObject *obj) { ...@@ -196,7 +273,7 @@ static CYTHON_INLINE PyObject *__Pyx_Coroutine_GetAsyncIter(PyObject *obj) {
return NULL; return NULL;
} }
#else #else
// avoid 'unused function' warning // avoid C warning about 'unused function'
if (0) (void) __Pyx_PyObject_CallMethod0(obj, PYIDENT("__aiter__")); if (0) (void) __Pyx_PyObject_CallMethod0(obj, PYIDENT("__aiter__"));
#endif #endif
......
...@@ -227,3 +227,35 @@ cdef object {{cname}}(const map[X,Y]& s): ...@@ -227,3 +227,35 @@ cdef object {{cname}}(const map[X,Y]& s):
o[X_to_py(key_value.first)] = Y_to_py(key_value.second) o[X_to_py(key_value.first)] = Y_to_py(key_value.second)
cython.operator.preincrement(iter) cython.operator.preincrement(iter)
return o return o
#################### complex.from_py ####################
{{template_type_declarations}}
cdef extern from *:
cdef cppclass std_complex "std::complex" [T]:
std_complex()
std_complex(T, T) except +
@cname("{{cname}}")
cdef std_complex[X] {{cname}}(object o) except *:
cdef double complex z = o
return std_complex[X](<X>z.real, <X>z.imag)
#################### complex.to_py ####################
{{template_type_declarations}}
cdef extern from *:
cdef cppclass std_complex "std::complex" [T]:
X real()
X imag()
@cname("{{cname}}")
cdef object {{cname}}(const std_complex[X]& z):
cdef double complex tmp
tmp.real = <double>z.real()
tmp.imag = <double>z.imag()
return tmp
This example demonstrates how you can wrap a C API that has a callback interface, so that you can pass Python functions to it as callbacks. The files cheesefinder.h and cheesefinder.c represent the C library to be wrapped. The file cheese.pyx is the Pyrex module which wraps it. The file run_cheese.py demonstrates how to call the wrapper. This example demonstrates how you can wrap a C API
\ No newline at end of file that has a callback interface, so that you can
pass Python functions to it as callbacks.
The files cheesefinder.h and cheesefinder.c
represent the C library to be wrapped.
The file cheese.pyx is the Pyrex module
which wraps it.
The file run_cheese.py demonstrates how to
call the wrapper.
typedef void (*cheesefunc)(char *name, void *user_data);void find_cheeses(cheesefunc user_func, void *user_data); typedef void (*cheesefunc)(char *name, void *user_data);
\ No newline at end of file void find_cheeses(cheesefunc user_func, void *user_data);
This diff is collapsed.
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"><html><head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta name="GENERATOR" content="Mozilla/4.51 (Macintosh; I; PPC) [Netscape]"> <title>Cython - Front Page</title></head><body>&nbsp;<table CELLSPACING=0 CELLPADDING=10 WIDTH="500" ><tr><td VALIGN=TOP BGCOLOR="#FF9218"><font face="Arial,Helvetica"><font size=+4>Cython</font></font></td> <td ALIGN=RIGHT VALIGN=TOP WIDTH="200" BGCOLOR="#5DBACA"><font face="Arial,Helvetica"><font size=+1>A smooth blend of the finest Python&nbsp;</font></font><br><font face="Arial,Helvetica"><font size=+1>with the unsurpassed power&nbsp;</font></font><br><font face="Arial,Helvetica"><font size=+1>of raw C.</font></font></td></tr></table> <blockquote><font size=+1>Welcome to Cython, a language for writing Python extension modules. Cython makes creating an extension module is almost as easy as creating a Python module! To find out more, consult one of the edifying documents below.</font></blockquote> <h1><font face="Arial,Helvetica"><font size=+2>Documentation</font></font></h1> <blockquote><h2><font face="Arial,Helvetica"><font size=+1><a href="About.html">About Cython</a></font></font></h2> <blockquote><font size=+1>Read this to find out what Cython is all about and what it can do for you.</font></blockquote> <h2><font face="Arial,Helvetica"><font size=+1><a href="overview.html">Language Overview</a></font></font></h2> <blockquote><font size=+1>A description of all the features of the Cython language. This is the closest thing to a reference manual in existence yet.</font></blockquote> <h2><font face="Arial,Helvetica"><font size=+1><a href="FAQ.html">FAQ</a></font></font></h2> <blockquote><font size=+1>Want to know how to do something in Cython? Check here first<font face="Arial,Helvetica">.</font></font></blockquote></blockquote> <h1><font face="Arial,Helvetica"><font size=+2>Other Resources</font></font></h1> <blockquote><h2><font face="Arial,Helvetica"><font size=+1><a href="http://www.cosc.canterbury.ac.nz/~greg/python/Cython/mpj17-pyrex-guide/">Michael's Quick Guide to Cython</a></font></font></h2> <blockquote><font size=+1>This tutorial-style presentation will take you through the steps of creating some Cython modules to wrap existing C libraries. Contributed by <a href="mailto:mpj17@cosc.canterbury.ac.nz">Michael JasonSmith</a>.</font></blockquote> <h2><font face="Arial,Helvetica"><font size=+1><a href="mailto:greg@cosc.canterbury.ac.nz">Mail to the Author</a></font></font></h2> <blockquote><font size=+1>If you have a question that's not answered by anything here, you're not sure about something, or you have a bug to report or a suggestion to make, or anything at all to say about Cython, feel free to email me:<font face="Arial,Helvetica"> </font><tt><a href="mailto:greg@cosc.canterbury.ac.nz">greg@cosc.canterbury.ac.nz</a></tt></font></blockquote></blockquote> </body></html> <!doctype html public "-//w3c//dtd html 4.0 transitional//en">
\ No newline at end of file <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="GENERATOR" content="Mozilla/4.51 (Macintosh; I; PPC) [Netscape]">
<title>Cython - Front Page</title>
</head>
<body>
&nbsp;
<table CELLSPACING=0 CELLPADDING=10 WIDTH="500" >
<tr>
<td VALIGN=TOP BGCOLOR="#FF9218"><font face="Arial,Helvetica"><font size=+4>Cython</font></font></td>
<td ALIGN=RIGHT VALIGN=TOP WIDTH="200" BGCOLOR="#5DBACA"><font face="Arial,Helvetica"><font size=+1>A
smooth blend of the finest Python&nbsp;</font></font>
<br><font face="Arial,Helvetica"><font size=+1>with the unsurpassed power&nbsp;</font></font>
<br><font face="Arial,Helvetica"><font size=+1>of raw C.</font></font></td>
</tr>
</table>
<blockquote><font size=+1>Welcome to Cython, a language for writing Python
extension modules. Cython makes creating an extension module is almost as
easy as creating a Python module! To find out more, consult one of the
edifying documents below.</font></blockquote>
<h1>
<font face="Arial,Helvetica"><font size=+2>Documentation</font></font></h1>
<blockquote>
<h2>
<font face="Arial,Helvetica"><font size=+1><a href="About.html">About Cython</a></font></font></h2>
<blockquote><font size=+1>Read this to find out what Cython is all about
and what it can do for you.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size=+1><a href="overview.html">Language
Overview</a></font></font></h2>
<blockquote><font size=+1>A description of all the features of the Cython
language. This is the closest thing to a reference manual in existence
yet.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size=+1><a href="FAQ.html">FAQ</a></font></font></h2>
<blockquote><font size=+1>Want to know how to do something in Cython? Check
here first<font face="Arial,Helvetica">.</font></font></blockquote>
</blockquote>
<h1>
<font face="Arial,Helvetica"><font size=+2>Other Resources</font></font></h1>
<blockquote>
<h2>
<font face="Arial,Helvetica"><font size=+1><a href="http://www.cosc.canterbury.ac.nz/~greg/python/Cython/mpj17-pyrex-guide/">Michael's
Quick Guide to Cython</a></font></font></h2>
<blockquote><font size=+1>This tutorial-style presentation will take you
through the steps of creating some Cython modules to wrap existing C libraries.
Contributed by <a href="mailto:mpj17@cosc.canterbury.ac.nz">Michael JasonSmith</a>.</font></blockquote>
<h2>
<font face="Arial,Helvetica"><font size=+1><a href="mailto:greg@cosc.canterbury.ac.nz">Mail
to the Author</a></font></font></h2>
<blockquote><font size=+1>If you have a question that's not answered by
anything here, you're not sure about something, or you have a bug to report
or a suggestion to make, or anything at all to say about Cython, feel free
to email me:<font face="Arial,Helvetica"> </font><tt><a href="mailto:greg@cosc.canterbury.ac.nz">greg@cosc.canterbury.ac.nz</a></tt></font></blockquote>
</blockquote>
</body>
</html>
#include "Python.h" static PyObject *__Pyx_UnpackItem(PyObject *, int); static int __Pyx_EndUnpack(PyObject *, int); static int __Pyx_PrintItem(PyObject *); static int __Pyx_PrintNewline(void); static void __Pyx_ReRaise(void); static void __Pyx_RaiseWithTraceback(PyObject *, PyObject *, PyObject *); static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); static PyObject *__Pyx_GetExcValue(void); static PyObject *__Pyx_GetName(PyObject *dict, char *name); static PyObject *__pyx_m; static PyObject *__pyx_d; static PyObject *__pyx_b; PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args); /*proto*/ PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args) { int __pyx_v_kmax; int __pyx_v_n; int __pyx_v_k; int __pyx_v_i; int (__pyx_v_p[1000]); PyObject *__pyx_v_result; PyObject *__pyx_r; PyObject *__pyx_1 = 0; int __pyx_2; int __pyx_3; int __pyx_4; PyObject *__pyx_5 = 0; PyObject *__pyx_6 = 0; if (!PyArg_ParseTuple(__pyx_args, "i", &__pyx_v_kmax)) return 0; __pyx_v_result = Py_None; Py_INCREF(__pyx_v_result); /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":2 */ /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":3 */ /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":4 */ __pyx_1 = PyList_New(0); if (!__pyx_1) goto __pyx_L1; Py_DECREF(__pyx_v_result); __pyx_v_result = __pyx_1; __pyx_1 = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":5 */ __pyx_2 = (__pyx_v_kmax > 1000); if (__pyx_2) { /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":6 */ __pyx_v_kmax = 1000; goto __pyx_L2; } __pyx_L2:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":7 */ __pyx_v_k = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":8 */ __pyx_v_n = 2; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":9 */ while (1) { __pyx_L3:; __pyx_2 = (__pyx_v_k < __pyx_v_kmax); if (!__pyx_2) break; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":10 */ __pyx_v_i = 0; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":11 */ while (1) { __pyx_L5:; if (__pyx_3 = (__pyx_v_i < __pyx_v_k)) { __pyx_3 = ((__pyx_v_n % (__pyx_v_p[__pyx_v_i])) != 0); } if (!__pyx_3) break; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":12 */ __pyx_v_i = (__pyx_v_i + 1); } __pyx_L6:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":13 */ __pyx_4 = (__pyx_v_i == __pyx_v_k); if (__pyx_4) { /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":14 */ (__pyx_v_p[__pyx_v_k]) = __pyx_v_n; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":15 */ __pyx_v_k = (__pyx_v_k + 1); /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":16 */ __pyx_1 = PyObject_GetAttrString(__pyx_v_result, "append"); if (!__pyx_1) goto __pyx_L1; __pyx_5 = PyInt_FromLong(__pyx_v_n); if (!__pyx_5) goto __pyx_L1; __pyx_6 = PyTuple_New(1); if (!__pyx_6) goto __pyx_L1; PyTuple_SET_ITEM(__pyx_6, 0, __pyx_5); __pyx_5 = 0; __pyx_5 = PyObject_CallObject(__pyx_1, __pyx_6); if (!__pyx_5) goto __pyx_L1; Py_DECREF(__pyx_6); __pyx_6 = 0; Py_DECREF(__pyx_5); __pyx_5 = 0; goto __pyx_L7; } __pyx_L7:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":17 */ __pyx_v_n = (__pyx_v_n + 1); } __pyx_L4:; /* "ProjectsA:Python:Pyrex:Demos:primes.pyx":18 */ Py_INCREF(__pyx_v_result); __pyx_r = __pyx_v_result; goto __pyx_L0; __pyx_r = Py_None; Py_INCREF(__pyx_r); goto __pyx_L0; __pyx_L1:; Py_XDECREF(__pyx_1); Py_XDECREF(__pyx_5); Py_XDECREF(__pyx_6); __pyx_r = 0; __pyx_L0:; Py_DECREF(__pyx_v_result); return __pyx_r; } static struct PyMethodDef __pyx_methods[] = { {"primes", (PyCFunction)__pyx_f_primes, METH_VARARGS, 0}, {0, 0, 0, 0} }; void initprimes(void); /*proto*/ void initprimes(void) { __pyx_m = Py_InitModule4("primes", __pyx_methods, 0, 0, PYTHON_API_VERSION); __pyx_d = PyModule_GetDict(__pyx_m); __pyx_b = PyImport_AddModule("__builtin__"); PyDict_SetItemString(__pyx_d, "__builtins__", __pyx_b); }/* Runtime support code */ #include "Python.h"
static PyObject *__Pyx_UnpackItem(PyObject *, int);
static int __Pyx_EndUnpack(PyObject *, int);
static int __Pyx_PrintItem(PyObject *);
static int __Pyx_PrintNewline(void);
static void __Pyx_ReRaise(void);
static void __Pyx_RaiseWithTraceback(PyObject *, PyObject *, PyObject *);
static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list);
static PyObject *__Pyx_GetExcValue(void);
static PyObject *__Pyx_GetName(PyObject *dict, char *name);
static PyObject *__pyx_m;
static PyObject *__pyx_d;
static PyObject *__pyx_b;
PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args); /*proto*/
PyObject *__pyx_f_primes(PyObject *__pyx_self, PyObject *__pyx_args) {
int __pyx_v_kmax;
int __pyx_v_n;
int __pyx_v_k;
int __pyx_v_i;
int (__pyx_v_p[1000]);
PyObject *__pyx_v_result;
PyObject *__pyx_r;
PyObject *__pyx_1 = 0;
int __pyx_2;
int __pyx_3;
int __pyx_4;
PyObject *__pyx_5 = 0;
PyObject *__pyx_6 = 0;
if (!PyArg_ParseTuple(__pyx_args, "i", &__pyx_v_kmax)) return 0;
__pyx_v_result = Py_None; Py_INCREF(__pyx_v_result);
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":2 */
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":3 */
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":4 */
__pyx_1 = PyList_New(0); if (!__pyx_1) goto __pyx_L1;
Py_DECREF(__pyx_v_result);
__pyx_v_result = __pyx_1;
__pyx_1 = 0;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":5 */
__pyx_2 = (__pyx_v_kmax > 1000);
if (__pyx_2) {
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":6 */
__pyx_v_kmax = 1000;
goto __pyx_L2;
}
__pyx_L2:;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":7 */
__pyx_v_k = 0;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":8 */
__pyx_v_n = 2;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":9 */
while (1) {
__pyx_L3:;
__pyx_2 = (__pyx_v_k < __pyx_v_kmax);
if (!__pyx_2) break;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":10 */
__pyx_v_i = 0;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":11 */
while (1) {
__pyx_L5:;
if (__pyx_3 = (__pyx_v_i < __pyx_v_k)) {
__pyx_3 = ((__pyx_v_n % (__pyx_v_p[__pyx_v_i])) != 0);
}
if (!__pyx_3) break;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":12 */
__pyx_v_i = (__pyx_v_i + 1);
}
__pyx_L6:;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":13 */
__pyx_4 = (__pyx_v_i == __pyx_v_k);
if (__pyx_4) {
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":14 */
(__pyx_v_p[__pyx_v_k]) = __pyx_v_n;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":15 */
__pyx_v_k = (__pyx_v_k + 1);
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":16 */
__pyx_1 = PyObject_GetAttrString(__pyx_v_result, "append"); if (!__pyx_1) goto __pyx_L1;
__pyx_5 = PyInt_FromLong(__pyx_v_n); if (!__pyx_5) goto __pyx_L1;
__pyx_6 = PyTuple_New(1); if (!__pyx_6) goto __pyx_L1;
PyTuple_SET_ITEM(__pyx_6, 0, __pyx_5);
__pyx_5 = 0;
__pyx_5 = PyObject_CallObject(__pyx_1, __pyx_6); if (!__pyx_5) goto __pyx_L1;
Py_DECREF(__pyx_6); __pyx_6 = 0;
Py_DECREF(__pyx_5); __pyx_5 = 0;
goto __pyx_L7;
}
__pyx_L7:;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":17 */
__pyx_v_n = (__pyx_v_n + 1);
}
__pyx_L4:;
/* "ProjectsA:Python:Pyrex:Demos:primes.pyx":18 */
Py_INCREF(__pyx_v_result);
__pyx_r = __pyx_v_result;
goto __pyx_L0;
__pyx_r = Py_None; Py_INCREF(__pyx_r);
goto __pyx_L0;
__pyx_L1:;
Py_XDECREF(__pyx_1);
Py_XDECREF(__pyx_5);
Py_XDECREF(__pyx_6);
__pyx_r = 0;
__pyx_L0:;
Py_DECREF(__pyx_v_result);
return __pyx_r;
}
static struct PyMethodDef __pyx_methods[] = {
{"primes", (PyCFunction)__pyx_f_primes, METH_VARARGS, 0},
{0, 0, 0, 0}
};
void initprimes(void); /*proto*/
void initprimes(void) {
__pyx_m = Py_InitModule4("primes", __pyx_methods, 0, 0, PYTHON_API_VERSION);
__pyx_d = PyModule_GetDict(__pyx_m);
__pyx_b = PyImport_AddModule("__builtin__");
PyDict_SetItemString(__pyx_d, "__builtins__", __pyx_b);
}
/* Runtime support code */
/* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */ /* The following rule is necessary to have all slides appear in print! DO NOT REMOVE IT! */
.slide, ul {page-break-inside: avoid; visibility: visible !important;} .slide, ul {page-break-inside: avoid; visibility: visible !important;}
h1 {page-break-after: avoid;} h1 {page-break-after: avoid;}
body {font-size: 12pt; background: white;} body {font-size: 12pt; background: white;}
* {color: black;} * {color: black;}
#slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;} #slide0 h1 {font-size: 200%; border: none; margin: 0.5em 0 0.25em;}
#slide0 h3 {margin: 0; padding: 0;} #slide0 h3 {margin: 0; padding: 0;}
#slide0 h4 {margin: 0 0 0.5em; padding: 0;} #slide0 h4 {margin: 0 0 0.5em; padding: 0;}
#slide0 {margin-bottom: 3em;} #slide0 {margin-bottom: 3em;}
h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;} h1 {border-top: 2pt solid gray; border-bottom: 1px dotted silver;}
.extra {background: transparent !important;} .extra {background: transparent !important;}
div.extra, pre.extra, .example {font-size: 10pt; color: #333;} div.extra, pre.extra, .example {font-size: 10pt; color: #333;}
ul.extra a {font-weight: bold;} ul.extra a {font-weight: bold;}
p.example {display: none;} p.example {display: none;}
#header {display: none;} #header {display: none;}
#footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;} #footer h1 {margin: 0; border-bottom: 1px solid; color: gray; font-style: italic;}
#footer h2, #controls {display: none;} #footer h2, #controls {display: none;}
/* The following rule keeps the layout stuff out of print. Remove at your own risk! */ /* The following rule keeps the layout stuff out of print. Remove at your own risk! */
.layout, .layout * {display: none !important;} .layout, .layout * {display: none !important;}
...@@ -222,6 +222,32 @@ list in the Extensions when not using Cython:: ...@@ -222,6 +222,32 @@ list in the Extensions when not using Cython::
extension.sources[:] = sources extension.sources[:] = sources
return extensions return extensions
Another option is to make Cython a setup dependency of your system and use
Cython's build_ext module which runs ``cythonize`` as part of the build process::
setup(
setup_requires=[
'cython>=0.x',
],
extensions = [Extension("*", ["*.pyx"])],
cmdclass={'build_ext': Cython.Build.build_ext},
...
)
If you want to expose the C-level interface of your library for other
libraries to cimport from, use package_data to install the ``.pxd`` files,
e.g.::
setup(
package_data = {
'my_package': ['*.pxd'],
'my_package/sub_package': ['*.pxd'],
},
...
)
These ``.pxd`` files need not correspond have corresponding ``.pyx``
modules if they contain purely declarations of external libraries.
Compiling with ``pyximport`` Compiling with ``pyximport``
============================= =============================
......
...@@ -81,7 +81,7 @@ Methods ...@@ -81,7 +81,7 @@ Methods
Properties Properties
========== ==========
* Cython provides a special syntax:: * Cython provides a special (deprecated) syntax::
cdef class Spam: cdef class Spam:
...@@ -120,7 +120,7 @@ Properties ...@@ -120,7 +120,7 @@ Properties
def __cinit__(self): def __cinit__(self):
self.cheeses = [] self.cheeses = []
property cheese: property cheese: # note that this syntax is deprecated
def __get__(self): def __get__(self):
return "We don't have: %s" % self.cheeses return "We don't have: %s" % self.cheeses
......
...@@ -153,7 +153,7 @@ the same effect as the C directive ``#pragma pack(1)``. ...@@ -153,7 +153,7 @@ the same effect as the C directive ``#pragma pack(1)``.
cheddar, edam, cheddar, edam,
camembert camembert
Declaring an enum as ```cpdef`` will create a PEP 435-style Python wrapper:: Declaring an enum as ``cpdef`` will create a :pep:`435`-style Python wrapper::
cpdef enum CheeseState: cpdef enum CheeseState:
hard = 1 hard = 1
...@@ -267,7 +267,7 @@ Optional Arguments ...@@ -267,7 +267,7 @@ Optional Arguments
------------------ ------------------
* Are supported for ``cdef`` and ``cpdef`` functions * Are supported for ``cdef`` and ``cpdef`` functions
* There differences though whether you declare them in a ``.pyx`` file or a ``.pxd`` file * There are 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:: * When in a ``.pyx`` file, the signature is the same as it is in Python itself::
...@@ -538,8 +538,8 @@ Functions and Methods ...@@ -538,8 +538,8 @@ Functions and Methods
* Only "Python" functions can be called outside a Cython module from *Python interpreted code*. * Only "Python" functions can be called outside a Cython module from *Python interpreted code*.
Callable from Python Callable from Python (def)
===================== ==========================
* Are declared with the ``def`` statement * Are declared with the ``def`` statement
* Are called with Python objects * Are called with Python objects
...@@ -548,8 +548,8 @@ Callable from Python ...@@ -548,8 +548,8 @@ Callable from Python
.. _cdef: .. _cdef:
Callable from C Callable from C (cdef)
================ ======================
* Are declared with the ``cdef`` statement. * Are declared with the ``cdef`` statement.
* Are called with either Python objects or C values. * Are called with either Python objects or C values.
...@@ -557,8 +557,8 @@ Callable from C ...@@ -557,8 +557,8 @@ Callable from C
.. _cpdef: .. _cpdef:
Callable from both Python and C Callable from both Python and C (cpdef)
================================ =======================================
* Are declared with the ``cpdef`` statement. * Are declared with the ``cpdef`` statement.
* Can be called from anywhere, because it uses a little Cython magic. * Can be called from anywhere, because it uses a little Cython magic.
...@@ -567,18 +567,40 @@ Callable from both Python and C ...@@ -567,18 +567,40 @@ Callable from both Python and C
Overriding Overriding
========== ==========
``cpdef`` functions can override ``cdef`` functions:: ``cpdef`` methods can override ``cdef`` methods::
cdef class A: cdef class A:
cdef foo(self): cdef foo(self):
print "A" print "A"
cdef class B(A) cdef class B(A)
cdef foo(self, x=None) cdef foo(self, x=None)
print "B", x print "B", x
cdef class C(B): cdef class C(B):
cpdef foo(self, x=True, int k=3) cpdef foo(self, x=True, int k=3)
print "C", x, k print "C", x, k
When subclassing an extension type with a Python class,
``def`` methods can override ``cpdef`` methods but not ``cdef``
methods::
cdef class A:
cdef foo(self):
print("A")
cdef class B(A):
cpdef foo(self):
print("B")
class C(B): # NOTE: not cdef class
def foo(self):
print("C")
If ``C`` above would be an extension type (``cdef class``),
this would not work correctly.
The Cython compiler will give a warning in that case.
Function Pointers Function Pointers
================= =================
......
...@@ -201,7 +201,7 @@ Descriptor objects ...@@ -201,7 +201,7 @@ Descriptor objects
.. note:: .. note::
Descriptor objects are part of the support mechanism for new-style Descriptor objects are part of the support mechanism for new-style
Python classes. See the discussion of descriptors in the Python documentation. Python classes. See the discussion of descriptors in the Python documentation.
See also PEP 252, "Making Types Look More Like Classes", and PEP 253, See also :PEP:`252`, "Making Types Look More Like Classes", and :PEP:`253`,
"Subtyping Built-In Types". "Subtyping Built-In Types".
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
......
...@@ -138,9 +138,10 @@ Attributes in cdef classes behave differently from attributes in regular classes ...@@ -138,9 +138,10 @@ Attributes in cdef classes behave differently from attributes in regular classes
# Available in Python-space: # Available in Python-space:
cdef public double freq cdef public double freq
# Available in Python-space: # Available in Python-space:
property period: @property
def __get__(self): def period(self):
return 1.0 / self.freq return 1.0 / self.freq
def __set__(self, value): @period.setter
self.freq = 1.0 / value def period(self, value):
self.freq = 1.0 / value
<...> <...>
...@@ -67,7 +67,7 @@ Cython understands all Python string type prefixes: ...@@ -67,7 +67,7 @@ Cython understands all Python string type prefixes:
* ``b'bytes'`` for byte strings * ``b'bytes'`` for byte strings
* ``u'text'`` for Unicode strings * ``u'text'`` for Unicode strings
* ``f'formatted {value}'`` for formatted Unicode string literals as defined by * ``f'formatted {value}'`` for formatted Unicode string literals as defined by
`PEP 498 <https://www.python.org/dev/peps/pep-0498/>`_ (added in Cython 0.24) :PEP:`498` (added in Cython 0.24)
Unprefixed string literals become :obj:`str` objects when compiling Unprefixed string literals become :obj:`str` objects when compiling
with language level 2 and :obj:`unicode` objects (i.e. Python 3 with language level 2 and :obj:`unicode` objects (i.e. Python 3
...@@ -558,7 +558,7 @@ When string literals appear in the code, the source code encoding is ...@@ -558,7 +558,7 @@ When string literals appear in the code, the source code encoding is
important. It determines the byte sequence that Cython will store in important. It determines the byte sequence that Cython will store in
the C code for bytes literals, and the Unicode code points that Cython the C code for bytes literals, and the Unicode code points that Cython
builds for unicode literals when parsing the byte encoded source file. builds for unicode literals when parsing the byte encoded source file.
Following `PEP 263`_, Cython supports the explicit declaration of Following :PEP:`263`, Cython supports the explicit declaration of
source file encodings. For example, putting the following comment at source file encodings. For example, putting the following comment at
the top of an ``ISO-8859-15`` (Latin-9) encoded source file (into the 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 first or second line) is required to enable ``ISO-8859-15`` decoding
...@@ -567,14 +567,12 @@ in the parser:: ...@@ -567,14 +567,12 @@ in the parser::
# -*- coding: ISO-8859-15 -*- # -*- coding: ISO-8859-15 -*-
When no explicit encoding declaration is provided, the source code is When no explicit encoding declaration is provided, the source code is
parsed as UTF-8 encoded text, as specified by `PEP 3120`_. `UTF-8`_ 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 is a very common encoding that can represent the entire Unicode set of
characters and is compatible with plain ASCII encoded text that it characters and is compatible with plain ASCII encoded text that it
encodes efficiently. This makes it a very good choice for source code encodes efficiently. This makes it a very good choice for source code
files which usually consist mostly of ASCII characters. 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 .. _`UTF-8`: http://en.wikipedia.org/wiki/UTF-8
As an example, putting the following line into a UTF-8 encoded source As an example, putting the following line into a UTF-8 encoded source
...@@ -731,15 +729,14 @@ to the internal representation of the Unicode string. Instead, any ...@@ -731,15 +729,14 @@ to the internal representation of the Unicode string. Instead, any
Unicode character can be represented on all platforms without Unicode character can be represented on all platforms without
resorting to surrogate pairs. This implies that narrow builds no resorting to surrogate pairs. This implies that narrow builds no
longer exist from that version on, regardless of the size of longer exist from that version on, regardless of the size of
:c:type:`Py_UNICODE`. See :c:type:`Py_UNICODE`. See :PEP:`393` for details.
`PEP 393 <http://www.python.org/dev/peps/pep-0393/>`_ for details.
Cython 0.16 and later handles this change internally and does the right Cython 0.16 and later handles this change internally and does the right
thing also for single character values as long as either type inference thing also for single character values as long as either type inference
is applied to untyped variables or the portable :c:type:`Py_UCS4` type is applied to untyped variables or the portable :c:type:`Py_UCS4` type
is explicitly used in the source code instead of the platform specific is explicitly used in the source code instead of the platform specific
:c:type:`Py_UNICODE` type. Optimisations that Cython applies to the :c:type:`Py_UNICODE` type. Optimisations that Cython applies to the
Python unicode type will automatically adapt to PEP 393 at C compile Python unicode type will automatically adapt to :PEP:`393` at C compile
time, as usual. time, as usual.
Iteration Iteration
......
...@@ -176,8 +176,7 @@ References ...@@ -176,8 +176,7 @@ References
---------- ----------
The buffer interface used here is set out in The buffer interface used here is set out in
`PEP 3118, Revising the buffer protocol :PEP:`3118`, Revising the buffer protocol.
<http://legacy.python.org/dev/peps/pep-3118/>`_
A tutorial for using this API from C is on Jake Vanderplas's blog, A tutorial for using this API from C is on Jake Vanderplas's blog,
`An Introduction to the Python Buffer Protocol `An Introduction to the Python Buffer Protocol
...@@ -188,5 +187,5 @@ Reference documentation is available for ...@@ -188,5 +187,5 @@ Reference documentation is available for
and `Python 2 <https://docs.python.org/2.7/c-api/buffer.html>`_. and `Python 2 <https://docs.python.org/2.7/c-api/buffer.html>`_.
The Py2 documentation also describes an older buffer protocol The Py2 documentation also describes an older buffer protocol
that is no longer in use; that is no longer in use;
since Python 2.6, the PEP 3118 protocol has been implemented, since Python 2.6, the :PEP:`3118` protocol has been implemented,
and the older protocol is only relevant for legacy code. and the older protocol is only relevant for legacy code.
...@@ -223,7 +223,26 @@ extension types. ...@@ -223,7 +223,26 @@ extension types.
Properties Properties
============ ============
There is a special syntax for defining properties in an extension class:: You can declare properties in an extension class using the same syntax as in ordinary Python code::
cdef class Spam:
@property
def cheese(self):
# This is called when the property is read.
...
@cheese.setter
def cheese(self, value):
# This is called when the property is written.
...
@cheese.deleter
def cheese(self):
# This is called when the property is deleted.
There is also a special (deprecated) legacy syntax for defining properties in an extension class::
cdef class Spam: cdef class Spam:
...@@ -259,16 +278,17 @@ when it is deleted.:: ...@@ -259,16 +278,17 @@ when it is deleted.::
def __cinit__(self): def __cinit__(self):
self.cheeses = [] self.cheeses = []
property cheese: @property
def cheese(self):
return "We don't have: %s" % self.cheeses
def __get__(self): @cheese.setter
return "We don't have: %s" % self.cheeses def cheese(self):
self.cheeses.append(value)
def __set__(self, value): @cheese.deleter
self.cheeses.append(value) def cheese(self):
del self.cheeses[:]
def __del__(self):
del self.cheeses[:]
# Test input # Test input
from cheesy import CheeseShop from cheesy import CheeseShop
...@@ -514,6 +534,21 @@ which makes it impossible to clean up the cursor. ...@@ -514,6 +534,21 @@ which makes it impossible to clean up the cursor.
Using the ``no_gc_clear`` decorator this can not happen anymore because the Using the ``no_gc_clear`` decorator this can not happen anymore because the
references of a cursor object will not be cleared anymore. references of a cursor object will not be cleared anymore.
In rare cases, extension types can be guaranteed not to participate in cycles,
but the compiler won't be able to prove this. This would be the case if
the class can never reference itself, even indirectly.
In that case, you can manually disable cycle collection by using the
``no_gc`` decorator, but beware that doing so when in fact the extension type
can participate in cycles could cause memory leaks ::
@cython.no_gc
cdef class UserInfo:
cdef str name
cdef tuple addresses
If you can be sure addresses will contain only references to strings,
the above would be safe, and it may yield a significant speedup, depending on
your usage pattern.
Public and external extension types Public and external extension types
==================================== ====================================
......
...@@ -310,9 +310,7 @@ Synonyms ...@@ -310,9 +310,7 @@ Synonyms
Source code encoding Source code encoding
====================== ======================
.. TODO: add the links to the relevant PEPs Cython supports :PEP:`3120` and :PEP:`263`, i.e. you can start your Cython source
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. 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 This impacts the encoding of byte strings and the conversion of unicode string
literals like ``u'abcd'`` to unicode objects. literals like ``u'abcd'`` to unicode objects.
......
...@@ -128,6 +128,9 @@ It searches for this file along the path for include files ...@@ -128,6 +128,9 @@ It searches for this file along the path for include files
(as specified by ``-I`` command line options or the ``include_path`` (as specified by ``-I`` command line options or the ``include_path``
option to ``cythonize()``), as well as ``sys.path``. option to ``cythonize()``), as well as ``sys.path``.
Using ``package_data`` to install ``.pxd`` files in your ``setup.py`` script
allows other packages to cimport items from your module as a dependency.
Also, whenever you compile a file :file:`modulename.pyx`, the corresponding Also, whenever you compile a file :file:`modulename.pyx`, the corresponding
definition file :file:`modulename.pxd` is first searched for along the definition file :file:`modulename.pxd` is first searched for along the
include path (but not ``sys.path``), and if found, it is processed before include path (but not ``sys.path``), and if found, it is processed before
......
...@@ -329,8 +329,8 @@ Iterators ...@@ -329,8 +329,8 @@ Iterators
| __next__ | self | object | Get next item (called next in Python) | | __next__ | self | object | Get next item (called next in Python) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
Buffer interface [PEP 3118] (no Python equivalents - see note 1) Buffer interface [:PEP:`3118`] (no Python equivalents - see note 1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+ +-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| Name | Parameters | Return type | Description | | Name | Parameters | Return type | Description |
...@@ -371,11 +371,10 @@ Descriptor objects (see note 2) ...@@ -371,11 +371,10 @@ Descriptor objects (see note 2)
.. note:: (1) The buffer interface was intended for use by C code and is not directly .. 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 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 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. :PEP:`3118` buffer protocol in Python 2.6 and is no longer available in Python 3.
For a how-to guide to the new API, see :ref:`buffer`. For a how-to guide to the new API, see :ref:`buffer`.
.. note:: (2) Descriptor objects are part of the support mechanism for new-style .. note:: (2) Descriptor objects are part of the support mechanism for new-style
Python classes. See the discussion of descriptors in the Python documentation. Python classes. See the discussion of descriptors in the Python documentation.
See also PEP 252, "Making Types Look More Like Classes", and PEP 253, See also :PEP:`252`, "Making Types Look More Like Classes", and :PEP:`253`,
"Subtyping Built-In Types". "Subtyping Built-In Types".
...@@ -850,8 +850,10 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -850,8 +850,10 @@ class CythonCompileTestCase(unittest.TestCase):
if 'distutils' in self.tags: if 'distutils' in self.tags:
from Cython.Build.Dependencies import DistutilsInfo from Cython.Build.Dependencies import DistutilsInfo
from Cython.Utils import open_source_file
pyx_path = os.path.join(self.test_directory, self.module + ".pyx") pyx_path = os.path.join(self.test_directory, self.module + ".pyx")
DistutilsInfo(open(pyx_path)).apply(extension) with open_source_file(pyx_path) as f:
DistutilsInfo(f).apply(extension)
for matcher, fixer in list(EXT_EXTRAS.items()): for matcher, fixer in list(EXT_EXTRAS.items()):
if isinstance(matcher, str): if isinstance(matcher, str):
......
...@@ -6,14 +6,14 @@ import sys ...@@ -6,14 +6,14 @@ import sys
if sys.version_info >= (3, 5, 0, 'beta'): if sys.version_info >= (3, 5, 0, 'beta'):
# pass Cython implemented AsyncIter() into a Python async-for loop # pass Cython implemented AsyncIter() into a Python async-for loop
__doc__ = u""" __doc__ = u"""
>>> def test_py35(): >>> def test_py35(AsyncIterClass):
... buffer = [] ... buffer = []
... async def coro(): ... async def coro():
... async for i1, i2 in AsyncIter(1): ... async for i1, i2 in AsyncIterClass(1):
... buffer.append(i1 + i2) ... buffer.append(i1 + i2)
... return coro, buffer ... return coro, buffer
>>> testfunc, buffer = test_py35() >>> testfunc, buffer = test_py35(AsyncIterOld if sys.version_info < (3, 5, 2) else AsyncIter)
>>> buffer >>> buffer
[] []
...@@ -69,7 +69,7 @@ cdef class AsyncIter: ...@@ -69,7 +69,7 @@ cdef class AsyncIter:
self.aiter_calls = 0 self.aiter_calls = 0
self.max_iter_calls = max_iter_calls self.max_iter_calls = max_iter_calls
async def __aiter__(self): def __aiter__(self):
self.aiter_calls += 1 self.aiter_calls += 1
return self return self
...@@ -86,6 +86,15 @@ cdef class AsyncIter: ...@@ -86,6 +86,15 @@ cdef class AsyncIter:
return self.i, self.i return self.i, self.i
cdef class AsyncIterOld(AsyncIter):
"""
Same as AsyncIter, but with the old async-def interface for __aiter__().
"""
async def __aiter__(self):
self.aiter_calls += 1
return self
def test_for_1(): def test_for_1():
""" """
>>> testfunc, buffer = test_for_1() >>> testfunc, buffer = test_for_1()
...@@ -154,7 +163,7 @@ def test_for_3(): ...@@ -154,7 +163,7 @@ def test_for_3():
cdef class NonAwaitableFromAnext: cdef class NonAwaitableFromAnext:
async def __aiter__(self): def __aiter__(self):
return self return self
def __anext__(self): def __anext__(self):
...@@ -193,7 +202,7 @@ cdef class Iterable: ...@@ -193,7 +202,7 @@ cdef class Iterable:
def __init__(self): def __init__(self):
self.i = 0 self.i = 0
async def __aiter__(self): def __aiter__(self):
return self return self
async def __anext__(self): async def __anext__(self):
...@@ -270,14 +279,22 @@ def test_with_for(): ...@@ -270,14 +279,22 @@ def test_with_for():
print(I[0]) print(I[0])
cdef class AI: cdef class AI_old:
async def __aiter__(self): async def __aiter__(self):
1/0 1/0
def test_aiter_raises(): cdef class AI_new:
def __aiter__(self):
1/0
def test_aiter_raises(AI):
""" """
>>> test_aiter_raises() >>> test_aiter_raises(AI_old)
RAISED
0
>>> test_aiter_raises(AI_new)
RAISED RAISED
0 0
""" """
......
# tag: cpp
from libcpp.complex cimport complex as complex_class
def double_complex(complex_class[double] a):
"""
>>> double_complex(1 + 2j)
(1+2j)
>>> double_complex(1.5 + 2.5j)
(1.5+2.5j)
"""
return a
def double_int(complex_class[int] a):
"""
>>> double_int(1 + 2j)
(1+2j)
>>> double_int(1.5 + 2.5j)
(1+2j)
"""
return a
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
cdef double pi cdef double pi
from math import pi from math import pi
from libc.math cimport sin, cos from libc.math cimport sin, cos
from libcpp cimport bool
cdef extern from "shapes.h" namespace "shapes": cdef extern from "shapes.h" namespace "shapes":
cdef cppclass Shape: cdef cppclass Shape:
...@@ -42,6 +43,35 @@ def test_Poly(int n, float radius=1): ...@@ -42,6 +43,35 @@ def test_Poly(int n, float radius=1):
finally: finally:
del poly del poly
cdef cppclass BaseClass:
int n
int method():
return this.n
cdef cppclass SubClass(BaseClass):
bool override
__init__(bool override):
this.n = 1
this.override = override
int method():
if override:
return 0
else:
return BaseClass.method()
def test_BaseMethods(x):
"""
>>> test_BaseMethods(True)
0
>>> test_BaseMethods(False)
1
"""
cdef SubClass* subClass
try:
subClass = new SubClass(x)
return subClass.method()
finally:
del subClass
cdef cppclass WithStatic: cdef cppclass WithStatic:
@staticmethod @staticmethod
......
...@@ -300,3 +300,13 @@ def test_greater_than(char *a, char *b): ...@@ -300,3 +300,13 @@ def test_greater_than(char *a, char *b):
cdef string s = string(a) cdef string s = string(a)
cdef string t = string(b) cdef string t = string(b)
return (s > t, s > b, s >= b) return (s > t, s > b, s >= b)
def test_iteration(string s):
"""
>>> test_iteration(b'xyz')
[120, 121, 122]
>>> test_iteration(b'')
[]
"""
return [c for c in s]
#distutils: define_macros = DEFINE_NO_VALUE DEFINE_WITH_VALUE=0
cdef extern from "define_macro_helper.h" nogil:
int VAL;
def test():
"""
>>> test()
1
"""
return VAL
#pragma once
#ifdef DEFINE_NO_VALUE
#define VAL (DEFINE_WITH_VALUE + 1)
#else
#define VAL DEFINE_WITH_VALUE
#endif
...@@ -103,13 +103,13 @@ def pass_on_locals(f): ...@@ -103,13 +103,13 @@ def pass_on_locals(f):
f(locals()) f(locals())
f(l=locals()) f(l=locals())
f(l=locals(), a=1) f(l=locals(), a=1)
def locals_arrays(object[double, ndim=1] a):
def buffers_in_locals(object[char, ndim=1] a):
""" """
>>> import numpy as np >>> sorted(buffers_in_locals(b'abcdefg'))
>>> sorted(locals_arrays(np.arange(5,dtype='double')))
['a', 'b'] ['a', 'b']
""" """
cdef object[double, ndim=1] b = a.copy() cdef object[unsigned char, ndim=1] b = a
return locals() return locals()
"""
Check that the @cython.no_gc decorator disables generation of the
tp_clear and tp_traverse slots, that is, disables cycle collection.
"""
cimport cython
from cpython.ref cimport PyObject, Py_TYPE
# Force non-gc'd PyTypeObject when safety is guaranteed by user but not provable
cdef extern from *:
ctypedef struct PyTypeObject:
void (*tp_clear)(object)
void (*tp_traverse)(object)
def is_tp_clear_null(obj):
return (<PyTypeObject*>Py_TYPE(obj)).tp_clear is NULL
def is_tp_traverse_null(obj):
return (<PyTypeObject*>Py_TYPE(obj)).tp_traverse is NULL
@cython.no_gc
cdef class DisableGC:
"""
An extension type that has tp_clear and tp_traverse methods generated
to test that it actually clears the references to NULL.
>>> uut = DisableGC()
>>> is_tp_clear_null(uut)
True
>>> is_tp_traverse_null(uut)
True
"""
cdef public object requires_cleanup
def __cinit__(self):
self.requires_cleanup = (
"Tuples to strings don't really need cleanup, cannot take part of cycles",)
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
import re import re
import gc import gc
import sys import sys
import copy
#import types #import types
import pickle
import os.path import os.path
#import inspect #import inspect
import unittest import unittest
...@@ -128,6 +130,17 @@ def silence_coro_gc(): ...@@ -128,6 +130,17 @@ def silence_coro_gc():
gc.collect() gc.collect()
def min_py27(method):
return None if sys.version_info < (2, 7) else method
def ignore_py26(manager):
@contextlib.contextmanager
def dummy():
yield
return dummy() if sys.version_info < (2, 7) else manager
class AsyncBadSyntaxTest(unittest.TestCase): class AsyncBadSyntaxTest(unittest.TestCase):
@contextlib.contextmanager @contextlib.contextmanager
...@@ -1247,8 +1260,9 @@ class CoroutineTest(unittest.TestCase): ...@@ -1247,8 +1260,9 @@ class CoroutineTest(unittest.TestCase):
buffer = [] buffer = []
async def test1(): async def test1():
async for i1, i2 in AsyncIter(): with ignore_py26(self.assertWarnsRegex(PendingDeprecationWarning, "legacy")):
buffer.append(i1 + i2) async for i1, i2 in AsyncIter():
buffer.append(i1 + i2)
yielded, _ = run_async(test1()) yielded, _ = run_async(test1())
# Make sure that __aiter__ was called only once # Make sure that __aiter__ was called only once
...@@ -1260,12 +1274,13 @@ class CoroutineTest(unittest.TestCase): ...@@ -1260,12 +1274,13 @@ class CoroutineTest(unittest.TestCase):
buffer = [] buffer = []
async def test2(): async def test2():
nonlocal buffer nonlocal buffer
async for i in AsyncIter(): with ignore_py26(self.assertWarnsRegex(PendingDeprecationWarning, "legacy")):
buffer.append(i[0]) async for i in AsyncIter():
if i[0] == 20: buffer.append(i[0])
break if i[0] == 20:
else: break
buffer.append('what?') else:
buffer.append('what?')
buffer.append('end') buffer.append('end')
yielded, _ = run_async(test2()) yielded, _ = run_async(test2())
...@@ -1278,12 +1293,13 @@ class CoroutineTest(unittest.TestCase): ...@@ -1278,12 +1293,13 @@ class CoroutineTest(unittest.TestCase):
buffer = [] buffer = []
async def test3(): async def test3():
nonlocal buffer nonlocal buffer
async for i in AsyncIter(): with ignore_py26(self.assertWarnsRegex(PendingDeprecationWarning, "legacy")):
if i[0] > 20: async for i in AsyncIter():
continue if i[0] > 20:
buffer.append(i[0]) continue
else: buffer.append(i[0])
buffer.append('what?') else:
buffer.append('what?')
buffer.append('end') buffer.append('end')
yielded, _ = run_async(test3()) yielded, _ = run_async(test3())
...@@ -1330,7 +1346,7 @@ class CoroutineTest(unittest.TestCase): ...@@ -1330,7 +1346,7 @@ class CoroutineTest(unittest.TestCase):
def test_for_4(self): def test_for_4(self):
class I(object): class I(object):
async def __aiter__(self): def __aiter__(self):
return self return self
def __anext__(self): def __anext__(self):
...@@ -1360,8 +1376,9 @@ class CoroutineTest(unittest.TestCase): ...@@ -1360,8 +1376,9 @@ class CoroutineTest(unittest.TestCase):
return 123 return 123
async def foo(): async def foo():
async for i in I(): with self.assertWarnsRegex(PendingDeprecationWarning, "legacy"):
print('never going to happen') async for i in I():
print('never going to happen')
with self.assertRaisesRegex( with self.assertRaisesRegex(
TypeError, TypeError,
...@@ -1385,7 +1402,7 @@ class CoroutineTest(unittest.TestCase): ...@@ -1385,7 +1402,7 @@ class CoroutineTest(unittest.TestCase):
def __init__(self): def __init__(self):
self.i = 0 self.i = 0
async def __aiter__(self): def __aiter__(self):
return self return self
async def __anext__(self): async def __anext__(self):
...@@ -1462,6 +1479,21 @@ class CoroutineTest(unittest.TestCase): ...@@ -1462,6 +1479,21 @@ class CoroutineTest(unittest.TestCase):
class AI(object): class AI(object):
async def __aiter__(self): async def __aiter__(self):
1/0 1/0
async def foo():
nonlocal CNT
with self.assertWarnsRegex(PendingDeprecationWarning, "legacy"):
async for i in AI():
CNT += 1
CNT += 10
with self.assertRaises(ZeroDivisionError):
run_async(foo())
self.assertEqual(CNT, 0)
def test_for_8(self):
CNT = 0
class AI:
def __aiter__(self):
1/0
async def foo(): async def foo():
nonlocal CNT nonlocal CNT
async for i in AI(): async for i in AI():
...@@ -1469,8 +1501,74 @@ class CoroutineTest(unittest.TestCase): ...@@ -1469,8 +1501,74 @@ class CoroutineTest(unittest.TestCase):
CNT += 10 CNT += 10
with self.assertRaises(ZeroDivisionError): with self.assertRaises(ZeroDivisionError):
run_async(foo()) run_async(foo())
with warnings.catch_warnings():
warnings.simplefilter("error")
# Test that if __aiter__ raises an exception it propagates
# without any kind of warning.
run_async(foo())
self.assertEqual(CNT, 0) self.assertEqual(CNT, 0)
@min_py27
def test_for_9(self):
# Test that PendingDeprecationWarning can safely be converted into
# an exception (__aiter__ should not have a chance to raise
# a ZeroDivisionError.)
class AI:
async def __aiter__(self):
1/0
async def foo():
async for i in AI():
pass
with self.assertRaises(PendingDeprecationWarning):
with warnings.catch_warnings():
warnings.simplefilter("error")
run_async(foo())
@min_py27
def test_for_10(self):
# Test that PendingDeprecationWarning can safely be converted into
# an exception.
class AI:
async def __aiter__(self):
pass
async def foo():
async for i in AI():
pass
with self.assertRaises(PendingDeprecationWarning):
with warnings.catch_warnings():
warnings.simplefilter("error")
run_async(foo())
def test_copy(self):
async def func(): pass
coro = func()
with self.assertRaises(TypeError):
copy.copy(coro)
aw = coro.__await__()
try:
with self.assertRaises(TypeError):
copy.copy(aw)
finally:
aw.close()
def test_pickle(self):
async def func(): pass
coro = func()
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.assertRaises((TypeError, pickle.PicklingError)):
pickle.dumps(coro, proto)
aw = coro.__await__()
try:
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
with self.assertRaises((TypeError, pickle.PicklingError)):
pickle.dumps(aw, proto)
finally:
aw.close()
class CoroAsyncIOCompatTest(unittest.TestCase): class CoroAsyncIOCompatTest(unittest.TestCase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment