Merged pull request #12 from bhy/T423.
authorrobertwb <robertwb@gmail.com>
Tue, 26 Apr 2011 19:25:23 +0000 (12:25 -0700)
committerrobertwb <robertwb@gmail.com>
Tue, 26 Apr 2011 19:25:23 +0000 (12:25 -0700)
T423 explicit execption chaining

576 files changed:
Cython/Build/BuildExecutable.py [new file with mode: 0755]
Cython/Build/Tests/__init__.py
Cython/Compiler/Buffer.py
Cython/Compiler/Builtin.py
Cython/Compiler/CmdLine.py
Cython/Compiler/Code.pxd
Cython/Compiler/Code.py
Cython/Compiler/Errors.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Future.py
Cython/Compiler/Lexicon.py
Cython/Compiler/Main.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Naming.py
Cython/Compiler/Nodes.py
Cython/Compiler/Optimize.py
Cython/Compiler/Options.py
Cython/Compiler/ParseTreeTransforms.pxd
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.pxd
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Scanning.py
Cython/Compiler/Symtab.py
Cython/Compiler/Tests/TestTreeFragment.py
Cython/Compiler/Tests/__init__.py
Cython/Compiler/TreeFragment.py
Cython/Compiler/TypeInference.py
Cython/Compiler/UtilNodes.py
Cython/Compiler/__init__.py
Cython/Debugger/Tests/__init__.py
Cython/Debugger/__init__.py
Cython/Distutils/__init__.py
Cython/Includes/cpython/__init__.pxd
Cython/Includes/libcpp/string.pxd [new file with mode: 0644]
Cython/Includes/numpy.pxd
Cython/Plex/Errors.py
Cython/Plex/Scanners.py
Cython/Runtime/__init__.py
Cython/Shadow.py
Cython/Tests/__init__.py
MANIFEST.in
Tools/cython-mode.el
bin/cythonrun [new file with mode: 0755]
cython.py [changed mode: 0644->0755]
docs/.hgignore [new file with mode: 0644]
docs/Makefile [new file with mode: 0644]
docs/README [new file with mode: 0644]
docs/TODO [new file with mode: 0644]
docs/_static/cython-logo-light.png [new file with mode: 0644]
docs/_static/cythonlogo.png [new file with mode: 0644]
docs/_static/favicon.ico [new file with mode: 0644]
docs/_templates/layout.html [new file with mode: 0644]
docs/conf.py [new file with mode: 0644]
docs/examples/tutorial/fib1/fib.pyx [new file with mode: 0644]
docs/examples/tutorial/fib1/setup.py [new file with mode: 0644]
docs/examples/tutorial/great_circle/c1.pyx [new file with mode: 0644]
docs/examples/tutorial/great_circle/c2.pyx [new file with mode: 0644]
docs/examples/tutorial/great_circle/p1.py [new file with mode: 0644]
docs/examples/tutorial/primes/primes.py [new file with mode: 0644]
docs/examples/tutorial/primes/primes.pyx [new file with mode: 0644]
docs/examples/tutorial/primes/setup.py [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/sphinxext/cython_highlighting.py [new file with mode: 0644]
docs/sphinxext/ipython_console_highlighting.py [new file with mode: 0644]
docs/src/quickstart/build.rst [new file with mode: 0644]
docs/src/quickstart/cythonize.rst [new file with mode: 0644]
docs/src/quickstart/demo.pyx [new file with mode: 0644]
docs/src/quickstart/htmlreport.png [new file with mode: 0644]
docs/src/quickstart/index.rst [new file with mode: 0644]
docs/src/quickstart/install.rst [new file with mode: 0644]
docs/src/quickstart/overview.rst [new file with mode: 0644]
docs/src/quickstart/sage.png [new file with mode: 0644]
docs/src/reference/Makefile [new file with mode: 0644]
docs/src/reference/compilation.rst [new file with mode: 0644]
docs/src/reference/directives.rst [new file with mode: 0644]
docs/src/reference/extension_types.rst [new file with mode: 0644]
docs/src/reference/index.rst [new file with mode: 0644]
docs/src/reference/interfacing_with_other_code.rst [new file with mode: 0644]
docs/src/reference/language_basics.rst [new file with mode: 0644]
docs/src/reference/limitations.rst [new file with mode: 0644]
docs/src/reference/special_mention.rst [new file with mode: 0644]
docs/src/reference/special_methods_table.rst [new file with mode: 0644]
docs/src/tutorial/appendix.rst [new file with mode: 0644]
docs/src/tutorial/caveats.rst [new file with mode: 0644]
docs/src/tutorial/cdef_classes.rst [new file with mode: 0644]
docs/src/tutorial/clibraries.rst [new file with mode: 0644]
docs/src/tutorial/data.py [new file with mode: 0644]
docs/src/tutorial/external.rst [new file with mode: 0644]
docs/src/tutorial/index.rst [new file with mode: 0644]
docs/src/tutorial/numpy.rst [new file with mode: 0644]
docs/src/tutorial/profiling_tutorial.rst [new file with mode: 0644]
docs/src/tutorial/pure.rst [new file with mode: 0644]
docs/src/tutorial/pxd_files.rst [new file with mode: 0644]
docs/src/tutorial/queue_example/cqueue.pxd [new file with mode: 0644]
docs/src/tutorial/queue_example/queue.pyx [new file with mode: 0644]
docs/src/tutorial/readings.rst [new file with mode: 0644]
docs/src/tutorial/related_work.rst [new file with mode: 0644]
docs/src/tutorial/strings.rst [new file with mode: 0644]
docs/src/userguide/debugging.rst [new file with mode: 0644]
docs/src/userguide/early_binding_for_speed.rst [new file with mode: 0644]
docs/src/userguide/extension_types.rst [new file with mode: 0644]
docs/src/userguide/external_C_code.rst [new file with mode: 0644]
docs/src/userguide/index.rst [new file with mode: 0644]
docs/src/userguide/language_basics.rst [new file with mode: 0644]
docs/src/userguide/limitations.rst [new file with mode: 0644]
docs/src/userguide/numpy_tutorial.rst [new file with mode: 0644]
docs/src/userguide/overview.rst [new file with mode: 0644]
docs/src/userguide/pxd_package.rst [new file with mode: 0644]
docs/src/userguide/pyrex_differences.rst [new file with mode: 0644]
docs/src/userguide/sharing_declarations.rst [new file with mode: 0644]
docs/src/userguide/source_files_and_compilation.rst [new file with mode: 0644]
docs/src/userguide/special_methods.rst [new file with mode: 0644]
docs/src/userguide/tutorial.rst [new file with mode: 0644]
docs/src/userguide/wrapping_CPlusPlus.rst [new file with mode: 0644]
docs/todo.txt [new file with mode: 0644]
docs/welcome.rst [new file with mode: 0644]
pyximport/pyximport.py
runtests.py
setup.py
tests/bugs.txt
tests/compile/a/__init__.py
tests/compile/a_capi.pyx
tests/compile/argdefault.pyx
tests/compile/arrayargs.pyx
tests/compile/arrayptrcompat.pyx
tests/compile/arraytoptrarg.pyx
tests/compile/ass2longlong.pyx
tests/compile/assert2.pyx
tests/compile/behnel4.pyx
tests/compile/belchenko1.pyx
tests/compile/bufaccess_noassignT444.pyx
tests/compile/builtin.pyx
tests/compile/builtinfuncs.pyx
tests/compile/c_directives.pyx
tests/compile/callingconvention.pyx
tests/compile/cargdef.pyx
tests/compile/carrdecl.pyx
tests/compile/cascmp.pyx
tests/compile/cassign.pyx
tests/compile/cast_ctypedef_array_T518.pyx
tests/compile/casttoexttype.pyx
tests/compile/cdefexternempty.pyx
tests/compile/cdefexternfromstar.pyx
tests/compile/cenum.pyx
tests/compile/cforfromloop.pyx
tests/compile/cimport_package_module_T4.pyx
tests/compile/cimportfrom_T248.pyx
tests/compile/classmethargdefault.pyx
tests/compile/cnamespec.pyx
tests/compile/cnumop.pyx
tests/compile/coercetovoidptr.pyx
tests/compile/complexbasetype.pyx
tests/compile/constexpr.pyx
tests/compile/coventry1.pyx
tests/compile/cpdef.pyx
tests/compile/cpp_enums.pyx
tests/compile/cpp_operators.pyx
tests/compile/cpp_structs.pyx
tests/compile/cpp_templated_ctypedef.pyx
tests/compile/cpp_templates.pyx
tests/compile/cstructreturn.pyx
tests/compile/ctypedef.pyx
tests/compile/ctypedef_public_class_T355.pyx
tests/compile/ctypedefclass.pyx
tests/compile/ctypedefenum.pyx
tests/compile/ctypedefpubapi.pyx
tests/compile/ctypedefstruct.pyx
tests/compile/ctypedefunion.pyx
tests/compile/cunsignedlong.pyx
tests/compile/cverylongtypes.pyx
tests/compile/declandimpl.pyx
tests/compile/declarations.pyx
tests/compile/del.pyx
tests/compile/delslice.pyx
tests/compile/docstrings.pyx
tests/compile/doda1.pyx
tests/compile/dotted_cimport.pyx
tests/compile/dotted_cimport_submodule/__init__.pyx
tests/compile/drake1.pyx
tests/compile/ellipsis_T488.pyx
tests/compile/emptytry.pyx
tests/compile/enumintcompat.pyx
tests/compile/eqcmp.pyx
tests/compile/ewing1.pyx
tests/compile/ewing3.pyx
tests/compile/ewing4.pyx
tests/compile/ewing5.pyx
tests/compile/ewing6.pyx
tests/compile/ewing7.pyx
tests/compile/ewing8.pyx
tests/compile/ewing9.pyx
tests/compile/excvalcheck.pyx
tests/compile/excvaldecl.pyx
tests/compile/excvalreturn.pyx
tests/compile/extargdefault.pyx
tests/compile/extcmethcall.pyx
tests/compile/extcoerce.pyx
tests/compile/extdelattr.pyx
tests/compile/extdelitem.pyx
tests/compile/extdelslice.pyx
tests/compile/extdescrdel.pyx
tests/compile/extdescrget.pyx
tests/compile/extdescrset.pyx
tests/compile/extern.pyx
tests/compile/extexttype.pyx
tests/compile/extforward.pyx
tests/compile/extgetattr.pyx
tests/compile/extgetitem.pyx
tests/compile/exthash.pyx
tests/compile/extimported.pyx
tests/compile/extimportedsubtype.pyx
tests/compile/extindex.pyx
tests/compile/extinheritdel.pyx
tests/compile/extinheritset.pyx
tests/compile/extpropertyall.pyx
tests/compile/extpropertydel.pyx
tests/compile/extpropertydoc.pyx
tests/compile/extpropertyget.pyx
tests/compile/extpropertyset.pyx
tests/compile/extpymemberdef.pyx
tests/compile/extsetattr.pyx
tests/compile/extsetitem.pyx
tests/compile/extsetslice.pyx
tests/compile/first_assignment.pyx
tests/compile/for.pyx
tests/compile/forfromelse.pyx
tests/compile/formfeed.pyx
tests/compile/fromimport.pyx
tests/compile/fromimport_star.pyx [new file with mode: 0644]
tests/compile/funcptr.pyx
tests/compile/future_imports.pyx [new file with mode: 0644]
tests/compile/gencall.pyx
tests/compile/globalonly.pyx
tests/compile/globalstmt.pyx
tests/compile/globvardef.pyx
tests/compile/gustafsson2.pyx
tests/compile/hinsen2.pyx
tests/compile/huss2.pyx
tests/compile/ia_cdefblock.pyx
tests/compile/import.pyx
tests/compile/index.pyx
tests/compile/indices.pyx
tests/compile/ishimoto1.pyx
tests/compile/ishimoto4.pyx
tests/compile/jiba3.pyx
tests/compile/jiba4.pyx
tests/compile/jiba5.pyx
tests/compile/jiba6.pyx
tests/compile/johnson1.pyx
tests/compile/johnson2.pyx
tests/compile/khavkine1.pyx
tests/compile/kleckner1.pyx
tests/compile/lepage_2.pyx
tests/compile/libc_all.pyx
tests/compile/libc_errno.pyx
tests/compile/libc_math.pyx
tests/compile/libc_signal.pyx
tests/compile/longunsigned.pyx
tests/compile/magcmp.pyx
tests/compile/msvc_strings.pyx
tests/compile/nogil.pyx
tests/compile/nonctypedefclass.pyx
tests/compile/none.pyx
tests/compile/notnonearg.pyx
tests/compile/nullptr.pyx
tests/compile/omittedargnames.pyx
tests/compile/pinard4.pyx
tests/compile/posix_pxds.pyx
tests/compile/publicapi_api.pyx [new file with mode: 0644]
tests/compile/publicapi_mix.pyx [new file with mode: 0644]
tests/compile/publicapi_pub.pyx [new file with mode: 0644]
tests/compile/publicapi_pxd_mix.pxd [new file with mode: 0644]
tests/compile/publicapi_pxd_mix.pyx [new file with mode: 0644]
tests/compile/pxd_override_T230.py
tests/compile/pyclass.pyx
tests/compile/pylong.pyx
tests/compile/r_pernici1.pyx
tests/compile/signedtypes.pyx
tests/compile/slicex.pyx
tests/compile/specialfloatvals.pyx
tests/compile/specmethargdefault.pyx
tests/compile/specmethdocstring.pyx
tests/compile/specmethextarg.pyx
tests/compile/traceback.pyx
tests/compile/tryexcept.pyx
tests/compile/tryfinally.pyx
tests/compile/typecast.pyx
tests/compile/types_and_names.pyx
tests/compile/watts2.pyx
tests/compile/weakref_T276.pyx
tests/compile/while.pyx
tests/compile/withgil.pyx
tests/errors/break_outside_loop.pyx
tests/errors/buffertypedef_T117.pyx
tests/errors/builtin_type_inheritance.pyx
tests/errors/callargs.pyx
tests/errors/callingnonexisting_T307.pyx
tests/errors/cdef_members_T517.pyx
tests/errors/cdef_syntax.pyx
tests/errors/cdefkwargs.pyx
tests/errors/cdefoptargs.pyx
tests/errors/cdefspecial.pyx
tests/errors/cmethbasematch.pyx
tests/errors/compile_time_unraisable_T370.pyx
tests/errors/continue_outside_loop.pyx
tests/errors/cpdef_syntax.pyx
tests/errors/cpp_no_constructor.pyx
tests/errors/cython3_bytes.pyx
tests/errors/declareafteruse_T158.pyx
tests/errors/def_nogil.pyx
tests/errors/e2_packedstruct_T290.pyx
tests/errors/e_addop.pyx
tests/errors/e_argdefault.pyx
tests/errors/e_ass.pyx
tests/errors/e_assnone.pyx
tests/errors/e_autotestdict.pyx
tests/errors/e_badexcvaltype.pyx
tests/errors/e_badfuncargtype.pyx
tests/errors/e_badpyparam.pyx
tests/errors/e_badtypeuse.pyx
tests/errors/e_bitop.pyx
tests/errors/e_boolcoerce.pyx
tests/errors/e_bufaccess.pyx
tests/errors/e_bufaccess2.pyx
tests/errors/e_callnonfunction.pyx
tests/errors/e_callspec.pyx
tests/errors/e_cdef_keywords_T241.pyx
tests/errors/e_cdef_missing_declarator.pyx
tests/errors/e_cdefassign.pyx
tests/errors/e_cdefemptysue.pyx
tests/errors/e_cenum.pyx
tests/errors/e_cmethbasematch.pyx
tests/errors/e_cmp.pyx
tests/errors/e_cstruct.pyx
tests/errors/e_ctypedefforward.pyx
tests/errors/e_ctypedefornot.pyx
tests/errors/e_declarations.pyx
tests/errors/e_decorators.pyx
tests/errors/e_del.pyx
tests/errors/e_directives.pyx
tests/errors/e_exceptclause.pyx
tests/errors/e_excvalfunctype.pyx
tests/errors/e_extweakref.pyx
tests/errors/e_func_in_pxd.pyx
tests/errors/e_generators.pyx [new file with mode: 0644]
tests/errors/e_index.pyx
tests/errors/e_int_literals_py2.py
tests/errors/e_int_literals_py3.py
tests/errors/e_multass.pyx
tests/errors/e_nargs.pyx
tests/errors/e_nogilcmeth.pyx
tests/errors/e_nogilfunctype.pyx
tests/errors/e_nonlocal_T490.pyx [new file with mode: 0644]
tests/errors/e_nosignword.pyx
tests/errors/e_notnone.pyx
tests/errors/e_notnone2.pyx
tests/errors/e_numop.pyx
tests/errors/e_packedstruct_T290.pyx
tests/errors/e_powop.pyx
tests/errors/e_pxdimpl.pyx
tests/errors/e_pyobinstruct.pyx
tests/errors/e_return.pyx
tests/errors/e_sizeofincomplete.pyx
tests/errors/e_slice.pyx
tests/errors/e_strcoerce.pyx
tests/errors/e_subop.pyx
tests/errors/e_switch.pyx
tests/errors/e_tempcast.pyx
tests/errors/e_undefexttype.pyx
tests/errors/e_unop.pyx
tests/errors/e_while.pyx
tests/errors/empty.pyx
tests/errors/encoding.pyx
tests/errors/extclassattrsetting.pyx
tests/errors/extended_unpacking.pyx
tests/errors/extended_unpacking_parser.pyx
tests/errors/extended_unpacking_parser2.pyx
tests/errors/futurebraces.pyx
tests/errors/invalid_cast.pyx
tests/errors/invalid_hex_escape0.pyx
tests/errors/invalid_hex_escape1.pyx
tests/errors/invalid_uescape.pyx
tests/errors/invalid_uescape0.pyx
tests/errors/invalid_uescape2.pyx
tests/errors/literal_lists.pyx
tests/errors/missing_baseclass_in_predecl_T262.pyx
tests/errors/missing_self_in_cpdef_method_T156.pyx
tests/errors/missing_self_in_cpdef_method_T165.pyx
tests/errors/nogil.pyx
tests/errors/nogilcmeth.pyx
tests/errors/nogilfunctype.pyx
tests/errors/nonconst_def.pyx
tests/errors/notcimportedT418.pyx
tests/errors/pxd_cdef_class_declaration_T286.pyx
tests/errors/py_ucs4_type_errors.pyx
tests/errors/py_unicode_type_errors.pyx
tests/errors/pyobjcastdisallow_T313.pyx
tests/errors/return_outside_function_T135.pyx
tests/errors/se_badindent.pyx
tests/errors/se_badindent2.pyx
tests/errors/se_mixtabspace.pyx
tests/errors/se_multass.pyx
tests/errors/string_assignments.pyx
tests/errors/subtyping_final_class.pyx
tests/errors/tree_assert.pyx
tests/errors/typoT304.pyx
tests/errors/undefinedname.pyx
tests/errors/void_as_arg.pyx
tests/errors/w_cdef_override.pyx [new file with mode: 0644]
tests/run/always_allow_keywords_T295.pyx
tests/run/args_unpacking_in_closure_T658.pyx
tests/run/arithmetic_analyse_types.pyx [new file with mode: 0644]
tests/run/arithmetic_analyse_types_helper.h [new file with mode: 0644]
tests/run/auto_cpdef.py [new file with mode: 0644]
tests/run/auto_cpdef_closures.py [new file with mode: 0644]
tests/run/autotestdict_skip.pyx
tests/run/bad_c_struct_T252.pyx
tests/run/bint.pyx
tests/run/bint_binop_T145.pyx
tests/run/bint_property_T354.pyx
tests/run/bound_builtin_methods_T589.pyx
tests/run/bufaccess.pyx
tests/run/buffmt.pyx
tests/run/builtin_methods_return_values.pyx [new file with mode: 0644]
tests/run/builtin_py3.pyx
tests/run/builtin_type_inheritance_T608.pyx
tests/run/builtin_types_none_T166.pyx
tests/run/builtinnames.pyx
tests/run/c_int_types_T255.pyx
tests/run/c_type_methods_T236.pyx
tests/run/capiimpl.pyx
tests/run/cascaded_list_unpacking_T467.pyx
tests/run/cascaded_typed_assignments_T466.pyx
tests/run/cdef_bool_T227.pyx
tests/run/cdef_class_field.pyx [new file with mode: 0644]
tests/run/cdef_decorator_directives_T183.pyx
tests/run/cdef_locals_decorator_T477.pyx [new file with mode: 0644]
tests/run/cdef_members_T517.pyx
tests/run/cdef_methods_T462.pyx
tests/run/cdef_setitem_T284.pyx
tests/run/cfunc_call_tuple_args_T408.pyx
tests/run/char_constants_T99.pyx
tests/run/charcomparisonT412.pyx
tests/run/charptr_comparison_T582.pyx
tests/run/cimport_cython_T505.pyx
tests/run/class_attribute_init_values_T18.pyx
tests/run/class_func_in_control_structures_T87.pyx
tests/run/class_scope.py [new file with mode: 0644]
tests/run/class_scope_T671.py [new file with mode: 0644]
tests/run/class_scope_del_T684.py [new file with mode: 0644]
tests/run/classdecorators_T336.pyx
tests/run/closure_arg_type_error.pyx
tests/run/closure_class_T596.pyx
tests/run/closure_decorators_T478.pyx
tests/run/closure_inside_cdef_T554.pyx
tests/run/closure_name_mangling_T537.pyx
tests/run/closure_self.pyx [new file with mode: 0644]
tests/run/closure_tests_1.pyx
tests/run/closure_tests_2.pyx
tests/run/closure_tests_3.pyx
tests/run/closure_tests_4.pyx
tests/run/closures_T82.pyx
tests/run/complex_cast_T445.pyx
tests/run/complex_int_T446.pyx
tests/run/complex_numbers_T305.pyx
tests/run/complex_numbers_c89_T398.pyx
tests/run/complex_numbers_c99_T398.pyx
tests/run/complex_numbers_cxx_T398.pyx
tests/run/contains_T455.pyx
tests/run/cpdef_temps_T411.pyx
tests/run/cpp_bool.pyx
tests/run/cpp_classes.pyx
tests/run/cpp_exceptions.pyx
tests/run/cpp_exceptions_nogil.pyx
tests/run/cpp_namespaces.pyx
tests/run/cpp_nested_templates.pyx
tests/run/cpp_nonstdint.pyx
tests/run/cpp_operators.pyx
tests/run/cpp_stl.pyx
tests/run/cpp_stl_string.pyx [new file with mode: 0644]
tests/run/cpp_stl_vector.pyx
tests/run/cpp_templates.pyx
tests/run/crashT245.pyx
tests/run/ctypedef_int_types_T333.pyx
tests/run/cython3.pyx
tests/run/decorators_T593.pyx
tests/run/delete.pyx
tests/run/directive_locals_in_pxd.pxd [new file with mode: 0644]
tests/run/directive_locals_in_pxd.py [new file with mode: 0644]
tests/run/division_T384.pyx
tests/run/ellipsis_T488.pyx
tests/run/empty_for_loop_T208.pyx
tests/run/enumerate_T316.pyx
tests/run/ext_instance_type_T232.pyx
tests/run/extended_unpacking_T235.pyx
tests/run/extended_unpacking_T409.pyx
tests/run/extern_builtins_T258.pyx
tests/run/float_floor_division_T260.pyx
tests/run/float_len_T480.pyx
tests/run/for_decrement.pyx
tests/run/for_from_float_T254.pyx
tests/run/for_from_pyvar_loop_T601.pyx
tests/run/for_in_break_continue_T533.pyx
tests/run/for_in_range_T372.pyx
tests/run/funcexc_iter_T228.pyx
tests/run/function_as_method_T494.pyx
tests/run/function_binding_T494.pyx
tests/run/generator_expressions.pyx [new file with mode: 0644]
tests/run/generator_type_inference.pyx [new file with mode: 0644]
tests/run/generators.pyx [new file with mode: 0644]
tests/run/generators_py.py [new file with mode: 0644]
tests/run/genexpr_T491.pyx
tests/run/genexpr_iterable_lookup_T600.pyx
tests/run/hash_T326.pyx
tests/run/ifelseexpr_T267.pyx
tests/run/importfrom.pyx
tests/run/in_list_with_side_effects_T544.pyx
tests/run/int_float_builtins_as_casts_T400.pyx
tests/run/intern_T431.pyx
tests/run/ipow_crash_T562.pyx
tests/run/lambda_T195.pyx
tests/run/lambda_class_T605.pyx
tests/run/lambda_module_T603.pyx
tests/run/large_consts_T237.pyx
tests/run/libcpp_all.pyx
tests/run/list_comp_in_closure_T598.pyx
tests/run/locals.pyx
tests/run/locals_expressions_T430.pyx
tests/run/locals_rebind_T429.pyx
tests/run/method_module_name_T422.pyx
tests/run/methodmangling_T5.pyx
tests/run/non_dict_kwargs_T470.pyx
tests/run/nonlocal_T490.pyx [new file with mode: 0644]
tests/run/numpy_ValueError_T172.pyx
tests/run/numpy_bufacc_T155.pyx
tests/run/numpy_cimport.pyx
tests/run/numpy_test.pyx
tests/run/packedstruct_T290.pyx
tests/run/parallel_swap_assign_T425.pyx
tests/run/posix_test.pyx
tests/run/pstats_profile_test.pyx
tests/run/pure_py.py
tests/run/pyfunction_redefine_T489.pyx
tests/run/pyobjcast_T313.pyx
tests/run/raise_memory_error_T650.pyx
tests/run/range_optimisation_T203.pyx
tests/run/refcount_in_meth.pyx
tests/run/relativeimport_T542.pyx [new file with mode: 0644]
tests/run/relativeimport_star_T542.pyx [new file with mode: 0644]
tests/run/short_circuit_T404.pyx
tests/run/special_methods_T561.pyx
tests/run/special_methods_T561_py2.pyx
tests/run/special_methods_T561_py3.pyx
tests/run/ssize_t_T399.pyx
tests/run/starred_target_T664.pyx
tests/run/str_char_coercion_T412.pyx
tests/run/strliterals.pyx
tests/run/temp_alloc_T409.pyx
tests/run/temp_sideeffects_T654.pyx
tests/run/tp_new_T454.pyx
tests/run/trybreak.pyx
tests/run/tupleunpack_T298.pyx
tests/run/type_inference.pyx
tests/run/type_slots_int_long_T287.pyx
tests/run/typeddefaultargT373.pyx
tests/run/typedfieldbug_T303.pyx
tests/run/typetest_T417.pyx
tests/run/unsigned_char_ptr_bytes_conversion_T359.pyx
tests/run/unsignedbehaviour_T184.pyx
tests/run/with_statement_module_level_T536.pyx
tests/run/withstat.pyx
tests/run/withstat_py.py [new file with mode: 0644]
tests/wrappers/cpp_overload_wrapper.pyx
tests/wrappers/cpp_references.pyx
tests/wrappers/cppwrap.pyx

diff --git a/Cython/Build/BuildExecutable.py b/Cython/Build/BuildExecutable.py
new file mode 100755 (executable)
index 0000000..492c242
--- /dev/null
@@ -0,0 +1,132 @@
+"""
+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:])
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index 86eb69c76b4d0849a8cf657cad471c6179bd9e8c..103d4ef80573e141413e22ee6ad329f38f084601 100644 (file)
@@ -747,7 +747,8 @@ typedef struct {
   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,
@@ -762,7 +763,8 @@ 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;
@@ -936,12 +938,12 @@ static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) {
     __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;
@@ -967,7 +969,7 @@ static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) {
     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;
     }
 
@@ -1008,14 +1010,6 @@ static int __Pyx_BufFmt_ProcessTypeChunk(__Pyx_BufFmt_Context* ctx) {
   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) {
@@ -1041,8 +1035,7 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
           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 '>':
@@ -1051,15 +1044,13 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
           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 */
         {
@@ -1090,6 +1081,7 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
         ctx->new_count = 1;
         ctx->enc_count = 0;
         ctx->enc_type = 0;
+        ctx->enc_packmode = ctx->new_packmode;
         ++ts;
         break;
       case 'Z':
@@ -1103,13 +1095,15 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
       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;
         }
@@ -1117,7 +1111,7 @@ static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const cha
         ctx->new_count = 1;
         got_Z = 0;
         break;
-        case ':':
+      case ':':
         ++ts;
         while(*ts != ':') ++ts;
         ++ts;
@@ -1168,7 +1162,7 @@ static CYTHON_INLINE int __Pyx_GetBufferAndValidate(Py_buffer* buf, PyObject* ob
       "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;
index d9c4207e184ed63a1f7eea5528748e9ae8081f27..dce7c16fea16db8dd3277cbba30c054cacb4f9f6 100644 (file)
@@ -478,9 +478,9 @@ builtin_types_table = [
 
     ("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?
@@ -494,9 +494,9 @@ builtin_types_table = [
                                     ]),
 #    ("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", []),
 ]
index 60eff8dbd4e026108c89f1fff557ec7e653ba10b..c13b6d5b978b936fd8ca9dba62f95c62feebba98 100644 (file)
@@ -38,6 +38,7 @@ Options:
   -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
 """
 
@@ -131,12 +132,18 @@ def parse_command_line(args):
                 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])
index 87de03a87a9bc9a04ab2579839d59260d7065b2a..df37da95e51e0b0c49407626fd3243a823a84c31 100644 (file)
@@ -34,6 +34,8 @@ cdef class FunctionState:
     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)
@@ -57,9 +59,10 @@ cdef class StringConst:
     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
index 2c34515c2a496d5574aaa6c183f6e0faf9c7fbc6..c4c766cb367c1bc83cb13b00f4ff8b31aee1c864 100644 (file)
@@ -1,4 +1,4 @@
-# cython: language_level = 3
+# cython: language_level = 3, py2_import=True
 #
 #   Pyrex - Code output module
 #
@@ -23,6 +23,21 @@ try:
 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.
     #
@@ -117,6 +132,7 @@ class FunctionState(object):
         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
 
@@ -270,6 +286,9 @@ class FunctionState(object):
                 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.
@@ -312,8 +331,16 @@ class StringConst(object):
         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
 
@@ -332,47 +359,52 @@ class StringConst(object):
             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
@@ -475,6 +507,7 @@ class GlobalState(object):
         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']
@@ -582,7 +615,7 @@ class GlobalState(object):
             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()
@@ -592,12 +625,21 @@ class GlobalState(object):
             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):
@@ -646,31 +688,22 @@ class GlobalState(object):
         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):
@@ -707,8 +740,15 @@ class GlobalState(object):
 
         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))
@@ -732,6 +772,17 @@ class GlobalState(object):
 
                 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,
@@ -742,6 +793,8 @@ class GlobalState(object):
                     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("};")
 
@@ -999,8 +1052,10 @@ class CCodeWriter(object):
     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
@@ -1297,6 +1352,8 @@ class CCodeWriter(object):
         #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__':
@@ -1366,6 +1423,9 @@ class CCodeWriter(object):
     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)
 
@@ -1402,3 +1462,26 @@ class PyrexCodeWriter(object):
     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
index fc59dfc98de8ddd709639302f2ba4f251256ebd2..025d1a6e00788c6cf770c233508dec341752b42a 100644 (file)
@@ -176,6 +176,8 @@ def message(position, message, level=1):
 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:
index 2f51d4fb092116d83c8a900bcb311debd484f48c..5a5f0c2c07280a33d5870abc0f8e918315140a40 100755 (executable)
@@ -77,12 +77,15 @@ class ExprNode(Node):
     #               [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:
@@ -452,6 +455,9 @@ class ExprNode(Node):
 
     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__))
@@ -497,7 +503,7 @@ class ExprNode(Node):
 
     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
@@ -1109,16 +1115,6 @@ class StringNode(PyConstNode):
             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):
@@ -1126,7 +1122,8 @@ class StringNode(PyConstNode):
 
     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
@@ -1333,7 +1330,7 @@ class NameNode(AtomicExprNode):
             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
@@ -1430,7 +1427,7 @@ class NameNode(AtomicExprNode):
         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
@@ -1441,7 +1438,7 @@ class NameNode(AtomicExprNode):
         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()
@@ -1519,7 +1516,7 @@ class NameNode(AtomicExprNode):
         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"
@@ -1628,9 +1625,10 @@ class NameNode(AtomicExprNode):
                 #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:
@@ -1639,7 +1637,7 @@ class NameNode(AtomicExprNode):
                                 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(),
@@ -1675,17 +1673,17 @@ class NameNode(AtomicExprNode):
     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)
@@ -1728,20 +1726,33 @@ class BackquoteNode(ExprNode):
         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:
@@ -1758,10 +1769,11 @@ class ImportNode(ExprNode):
         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())
 
@@ -1898,6 +1910,40 @@ class NextNode(AtomicExprNode):
         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
@@ -1932,7 +1978,7 @@ class TempNode(ExprNode):
 
     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:
@@ -1942,6 +1988,9 @@ class TempNode(ExprNode):
     def analyse_types(self, env):
         return self.type
 
+    def analyse_target_declaration(self, env):
+        pass
+
     def generate_result_code(self, code):
         pass
 
@@ -4442,15 +4491,18 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
         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):
@@ -4461,30 +4513,12 @@ class GeneratorExpressionNode(ScopedExprNode):
             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)
 
@@ -4497,7 +4531,8 @@ class InlinedGeneratorExpressionNode(GeneratorExpressionNode):
 
     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:
@@ -4508,7 +4543,7 @@ class InlinedGeneratorExpressionNode(GeneratorExpressionNode):
             # 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()
@@ -5055,32 +5090,98 @@ class LambdaNode(InnerFunctionNode):
         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))
 
 #-------------------------------------------------------------------
 #
@@ -5236,7 +5337,8 @@ class UnaryPlusNode(UnopNode):
     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"
@@ -5255,7 +5357,8 @@ class UnaryMinusNode(UnopNode):
 
     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:
@@ -5280,7 +5383,8 @@ class TildeNode(UnopNode):
 
     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()
 
@@ -5315,7 +5419,10 @@ class DecrementIncrementNode(CUnopNode):
     #  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()
@@ -5854,6 +5961,9 @@ class NumBinopNode(BinopNode):
                 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
@@ -7591,10 +7701,10 @@ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
 
 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;
@@ -7618,8 +7728,23 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list) {
     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);
@@ -7708,7 +7833,7 @@ static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) {
 #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);
@@ -7786,7 +7911,7 @@ PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObje
     PyObject *ns;
     PyObject *str;
 
-    prep = PyObject_GetAttrString(metaclass, "__prepare__");
+    prep = PyObject_GetAttrString(metaclass, (char *)"__prepare__");
     if (!prep) {
         if (!PyErr_ExceptionMatches(PyExc_AttributeError))
             return NULL;
@@ -8403,3 +8528,123 @@ static int %(binding_cfunc)s_init(void) {
 
 }
 """ % 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],
+)
index 9955a81382622945186171ab6aa56bde6a637138..f3fc91485af20c861041072088919ecbb10c0d65 100644 (file)
@@ -3,7 +3,7 @@ def _get_feature(name):
     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")
@@ -11,5 +11,6 @@ with_statement = _get_feature("with_statement")
 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
index ad736df130f12d153373abd8aa58faa7571db3e5..35843851bc9eceb2db3e8b49b8a6834597b872fc 100644 (file)
@@ -1,4 +1,4 @@
-# cython: language_level=3
+# cython: language_level=3, py2_import=True
 #
 #   Cython Scanner - Lexical Definitions
 #
index 993d8d9985a612896c18d817069deba72598ffe3..fb8d6fcb02d5d9ffdc7fea9b4774e763164ac3e4 100644 (file)
@@ -135,8 +135,8 @@ class Context(object):
             PostParse(self),
             _specific_post_parse,
             InterpretCompilerDirectives(self, self.compiler_directives),
-            _align_function_definitions,
             MarkClosureVisitor(self),
+            _align_function_definitions,
             ConstantFolding(),
             FlattenInListTransform(),
             WithTransform(self),
@@ -613,7 +613,7 @@ def run_pipeline(source, options, full_module_name = None):
         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':
index a66d43b70413f3b5730a9c75803fabdd10ecacc4..738d13600b27da6a71e8cfed42d2c659d45afc13 100644 (file)
@@ -96,14 +96,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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)
@@ -112,32 +114,40 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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:
@@ -158,63 +168,68 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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)
@@ -224,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             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:
@@ -233,8 +248,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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):
@@ -424,8 +440,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                         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)
 
@@ -685,6 +702,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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("")
@@ -721,10 +739,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
 
     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):
@@ -786,10 +806,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
     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):
@@ -813,7 +836,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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)")
@@ -844,7 +866,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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:
@@ -870,21 +891,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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)
@@ -924,7 +947,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             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:
@@ -942,9 +964,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                     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.
@@ -963,24 +989,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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*/" % (
@@ -1241,7 +1269,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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;")
@@ -1744,9 +1775,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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();")
@@ -1754,8 +1785,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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))
@@ -1803,6 +1834,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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)
 
@@ -1990,6 +2024,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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:
@@ -2088,19 +2134,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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,
@@ -2108,7 +2156,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 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):
@@ -2333,6 +2381,45 @@ bad:
 
 #------------------------------------------------------------------------------------
 
+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*/
@@ -2377,6 +2464,62 @@ bad:
 """ % {'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*/
@@ -2600,7 +2743,8 @@ bad:
 """ % {'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
@@ -2615,41 +2759,52 @@ refnanny_utility_code = UtilityCode(proto="""
     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 = """
index d351efd6a73cbdd24e989a448f6d207927c0dd7d..20dbea3ba3717dae5e5edb585885bd2af0d04cbf 100644 (file)
@@ -19,6 +19,7 @@ funcdoc_prefix    = pyrex_prefix + "doc_"
 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_"
@@ -51,6 +52,7 @@ lambda_func_prefix = pyrex_prefix + "lambda_"
 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"
@@ -107,10 +109,6 @@ exc_lineno_name = pyrex_prefix + "exc_lineno"
 
 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__"
index 4835f8fe45c1d0dc2e306c5a08840010883d441d..4405fefa46fc911c2d57d0aeb6096787ab1f4a4a 100644 (file)
@@ -23,7 +23,7 @@ from PyrexTypes import py_object_type, error_type, CFuncType
 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
@@ -535,7 +535,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
     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 = []
@@ -543,6 +543,17 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             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")
@@ -925,9 +936,11 @@ class CVarDefNode(StatNode):
     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
@@ -944,7 +957,10 @@ class CVarDefNode(StatNode):
         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,
@@ -962,7 +978,7 @@ class CVarDefNode(StatNode):
                     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")
@@ -970,7 +986,7 @@ class CVarDefNode(StatNode):
                     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
 
 
@@ -980,6 +996,7 @@ class CStructOrUnionDefNode(StatNode):
     #  kind          "struct" or "union"
     #  typedef_flag  boolean
     #  visibility    "public" or "private"
+    #  api           boolean
     #  in_pxd        boolean
     #  attributes    [CVarDefNode] or None
     #  entry         Entry
@@ -995,7 +1012,8 @@ class CStructOrUnionDefNode(StatNode):
             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
@@ -1078,6 +1096,7 @@ class CEnumDefNode(StatNode):
     #  items          [CEnumDefItemNode]
     #  typedef_flag   boolean
     #  visibility     "public" or "private"
+    #  api            boolean
     #  in_pxd         boolean
     #  entry          Entry
 
@@ -1086,7 +1105,7 @@ class CEnumDefNode(StatNode):
     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
@@ -1097,7 +1116,7 @@ class CEnumDefNode(StatNode):
         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" % (
@@ -1129,7 +1148,7 @@ class CEnumDefItemNode(StatNode):
                 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)
 
 
@@ -1137,6 +1156,7 @@ class CTypeDefNode(StatNode):
     #  base_type    CBaseTypeNode
     #  declarator   CDeclaratorNode
     #  visibility   "public" or "private"
+    #  api          boolean
     #  in_pxd       boolean
 
     child_attrs = ["base_type", "declarator"]
@@ -1147,7 +1167,7 @@ class CTypeDefNode(StatNode):
         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
 
@@ -1171,6 +1191,8 @@ class FuncDefNode(StatNode, BlockNode):
     assmt = None
     needs_closure = False
     needs_outer_scope = False
+    is_generator = False
+    is_generator_body = False
     modifiers = []
 
     def analyse_default_values(self, env):
@@ -1191,6 +1213,22 @@ class FuncDefNode(StatNode, BlockNode):
             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
 
@@ -1214,6 +1252,9 @@ class FuncDefNode(StatNode, BlockNode):
         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
 
@@ -1248,9 +1289,10 @@ class FuncDefNode(StatNode, BlockNode):
                     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
@@ -1300,6 +1342,8 @@ class FuncDefNode(StatNode, BlockNode):
                     (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()
@@ -1379,7 +1423,7 @@ class FuncDefNode(StatNode, BlockNode):
         # -------------------------
         # ----- Function body -----
         # -------------------------
-        self.body.generate_execution_code(code)
+        self.generate_function_body(env, code)
 
         # ----- Default return value
         code.putln("")
@@ -1461,14 +1505,10 @@ class FuncDefNode(StatNode, BlockNode):
             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)
@@ -1583,20 +1623,24 @@ class FuncDefNode(StatNode, BlockNode):
         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("}")
@@ -1622,16 +1666,23 @@ class CFuncDefNode(FuncDefNode):
 
     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")
@@ -1646,6 +1697,7 @@ class CFuncDefNode(FuncDefNode):
             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
@@ -1740,7 +1792,6 @@ class CFuncDefNode(FuncDefNode):
     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:
@@ -1754,24 +1805,20 @@ class CFuncDefNode(FuncDefNode):
         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:
@@ -1899,6 +1946,7 @@ class DefNode(FuncDefNode):
     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
@@ -1984,6 +2032,17 @@ class DefNode(FuncDefNode):
                             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:
@@ -2017,28 +2076,18 @@ class DefNode(FuncDefNode):
         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
@@ -2183,14 +2232,7 @@ class DefNode(FuncDefNode):
             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
 
@@ -2239,6 +2281,8 @@ class DefNode(FuncDefNode):
             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
@@ -2342,8 +2386,8 @@ class DefNode(FuncDefNode):
             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))
@@ -2420,14 +2464,24 @@ class DefNode(FuncDefNode):
         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:
@@ -2646,19 +2700,18 @@ class DefNode(FuncDefNode):
             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)
@@ -2828,9 +2881,9 @@ class DefNode(FuncDefNode):
             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.
@@ -2903,6 +2956,146 @@ class DefNode(FuncDefNode):
     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.
@@ -3253,7 +3446,7 @@ class CClassDefNode(ClassDefNode):
             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
@@ -3341,6 +3534,24 @@ class GlobalNode(StatNode):
         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.
     #
@@ -3365,6 +3576,7 @@ class ExprStatNode(StatNode):
                 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):
@@ -3964,7 +4176,9 @@ class RaiseStatNode(StatNode):
         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
@@ -4635,14 +4849,134 @@ class WithStatNode(StatNode):
     """
     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
     #
@@ -4708,12 +5042,12 @@ class TryExceptStatNode(StatNode):
         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:*/ {")
@@ -4732,14 +5066,15 @@ class TryExceptStatNode(StatNode):
             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:
@@ -4751,9 +5086,10 @@ class TryExceptStatNode(StatNode):
         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(
@@ -4762,19 +5098,24 @@ class TryExceptStatNode(StatNode):
 
             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
@@ -4801,7 +5142,7 @@ class ExceptClauseNode(Node):
     #  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
@@ -4819,8 +5160,6 @@ class ExceptClauseNode(Node):
     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):
@@ -4841,7 +5180,6 @@ class ExceptClauseNode(Node):
             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)
 
@@ -4896,7 +5234,7 @@ class ExceptClauseNode(Node):
             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')
@@ -4906,24 +5244,32 @@ class ExceptClauseNode(Node):
         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)
 
@@ -4963,6 +5309,9 @@ class TryFinallyStatNode(StatNode):
 
     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
@@ -4996,6 +5345,8 @@ class TryFinallyStatNode(StatNode):
         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:*/ {")
@@ -5922,6 +6273,31 @@ static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb)
 
 #------------------------------------------------------------------------------------
 
+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,
index ae3b2408ab53e92fce63ab5bf984e7d7979d3a02..d4821ca1ee774c885434ad402e3ffe002494bc49 100644 (file)
@@ -1170,11 +1170,12 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
             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
@@ -1603,6 +1604,15 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             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.
         """
@@ -2145,7 +2155,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
     _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")
@@ -2157,7 +2167,7 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
             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, [
index 35a7e7ee151642e326165378da53376fb3b4faec..7a46c1bbf3ea9c290a63f7b259f779919399c2a7 100644 (file)
@@ -2,7 +2,10 @@
 #  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
@@ -22,6 +25,15 @@ annotate = False
 # 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.
@@ -78,6 +90,7 @@ directive_defaults = {
     '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,
index a4c2368c1a5504833402022e385b1234b98caf97..078b8e0c42fcc10db7b83987ac76157a9fe621ee 100644 (file)
@@ -19,6 +19,7 @@ cdef class NormalizeTree(CythonTransform):
 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)
 
 
@@ -45,6 +46,11 @@ cdef class AlignFunctionDefinitions(CythonTransform):
     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
 
@@ -52,6 +58,7 @@ cdef class CreateClosureClasses(CythonTransform):
     cdef list path
     cdef bint in_lambda
     cdef module_scope
+    cdef generator_class
 
 cdef class GilCheck(VisitorTransform):
     cdef list env_stack
index 11a2baeeebd94894e84216c3d6f5dc15a03634fd..00de70a359adb9046849b946e4e9a49ac91f7a53 100644 (file)
@@ -11,11 +11,12 @@ import Naming
 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
@@ -182,6 +183,7 @@ class PostParse(ScopeTrackingTransform):
 
     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):
@@ -189,14 +191,33 @@ class PostParse(ScopeTrackingTransform):
         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
 
@@ -299,6 +320,20 @@ class PostParse(ScopeTrackingTransform):
 
         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
@@ -584,7 +619,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
         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 = {}
 
@@ -604,8 +639,8 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
                 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
@@ -863,81 +898,55 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
         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.
@@ -1177,7 +1186,7 @@ if VALUE is not None:
             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
@@ -1190,7 +1199,7 @@ if VALUE is not None:
                 }, 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)
 
@@ -1218,7 +1227,8 @@ if VALUE is not None:
     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
@@ -1363,7 +1373,8 @@ class AlignFunctionDefinitions(CythonTransform):
                 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
@@ -1381,19 +1392,57 @@ class AlignFunctionDefinitions(CythonTransform):
 
     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):
@@ -1406,6 +1455,27 @@ class MarkClosureVisitor(CythonTransform):
         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):
@@ -1426,7 +1496,6 @@ class MarkClosureVisitor(CythonTransform):
         self.needs_closure = True
         return node
 
-
 class CreateClosureClasses(CythonTransform):
     # Output closure classes in module scope for all functions
     # that really need it.
@@ -1435,24 +1504,84 @@ class CreateClosureClasses(CythonTransform):
         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
@@ -1471,8 +1600,11 @@ class CreateClosureClasses(CythonTransform):
                 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
@@ -1482,8 +1614,10 @@ class CreateClosureClasses(CythonTransform):
 
         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
@@ -1498,11 +1632,13 @@ class CreateClosureClasses(CythonTransform):
                                     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)
@@ -1595,25 +1731,40 @@ class TransformBuiltinMethods(EnvTransform):
                 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()
index 3c64665261e6402ea5e5fe5cbb0c2cbd2288d042..5d479b2a880bf8fdf9214b69d6ca1cac4df70bcf 100644 (file)
@@ -84,6 +84,7 @@ cdef p_genexp(PyrexScanner s, expr)
 #-------------------------------------------------------
 
 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)
index 9caaa39920b6bdc6952890aad35c41b8b16680db..4e2c55ad2c2aee350487bbac841dac8b4e0695cc 100644 (file)
@@ -1,4 +1,4 @@
-# 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
 #
@@ -615,7 +615,7 @@ def p_atom(s):
             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)
@@ -1045,6 +1045,12 @@ def p_global_statement(s):
     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 == '=':
@@ -1215,6 +1221,7 @@ def p_import_statement(s):
                 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)
@@ -1223,13 +1230,31 @@ def p_from_import_statement(s, first_statement = 0):
     # 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 == '*':
@@ -1251,6 +1276,8 @@ def p_from_import_statement(s, first_statement = 0):
     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":
@@ -1284,6 +1311,7 @@ def p_from_import_statement(s, first_statement = 0):
         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)
 
@@ -1431,7 +1459,7 @@ def p_for_from_relation(s):
         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
@@ -1603,6 +1631,8 @@ def p_simple_statement(s, first_statement = 0):
     #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':
@@ -1635,15 +1665,27 @@ def p_simple_statement_list(s, ctx, first_statement = 0):
     # 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
 
@@ -1780,9 +1822,14 @@ def p_statement_list(s, ctx, first_statement = 0):
     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)
@@ -2425,7 +2472,7 @@ def p_c_enum_definition(s, pos, ctx):
     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':
@@ -2486,7 +2533,7 @@ def p_c_struct_or_union_definition(s, pos, ctx):
     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()
@@ -2571,7 +2618,8 @@ def p_ctypedef_statement(s, ctx):
         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):
@@ -2698,8 +2746,8 @@ def p_c_class_definition(s, pos,  ctx):
         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':
@@ -2723,7 +2771,10 @@ def p_c_class_definition(s, pos,  ctx):
             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,
@@ -2787,7 +2838,7 @@ def p_code(s, level=None):
             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 = {}
index a5bbb787e0eace26a6c7e1ac4e88e67c36bbccd1..0870cf22d78472e2dd70081ed24619dcfb66f10f 100755 (executable)
@@ -17,10 +17,10 @@ class BaseType(object):
 
     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)
@@ -56,7 +56,7 @@ class PyrexType(BaseType):
     #  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.
@@ -80,7 +80,7 @@ class PyrexType(BaseType):
     #    Coerces array type into pointer type for use as
     #    a formal argument type.
     #
-        
+
     is_pyobject = 0
     is_unspecified = 0
     is_extension_type = 0
@@ -108,44 +108,44 @@ class PyrexType(BaseType):
     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.
@@ -167,7 +167,7 @@ def public_decl(base_code, dll_linkage):
         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:
@@ -189,38 +189,38 @@ class CTypedefType(BaseType):
     #  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)
@@ -229,7 +229,7 @@ class CTypedefType(BaseType):
 
     def __repr__(self):
         return "<CTypedefType %s>" % self.typedef_cname
-    
+
     def __str__(self):
         return self.typedef_name
 
@@ -303,7 +303,7 @@ class BufferType(BaseType):
     #  Delegates most attribute
     #  lookups to the base type. ANYTHING NOT DEFINED
     #  HERE IS DELEGATED!
-    
+
     # dtype            PyrexType
     # ndim             int
     # mode             str
@@ -322,7 +322,7 @@ class BufferType(BaseType):
         self.mode = mode
         self.negative_indices = negative_indices
         self.cast = cast
-    
+
     def as_argument_type(self):
         return self
 
@@ -345,10 +345,10 @@ class PyObjectType(PyrexType):
     buffer_defaults = None
     is_extern = False
     is_subclassed = False
-    
+
     def __str__(self):
         return "Python object"
-    
+
     def __repr__(self):
         return "<PyObjectType>"
 
@@ -362,8 +362,8 @@ class PyObjectType(PyrexType):
     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"
@@ -398,15 +398,15 @@ class BuiltinObjectType(PyObjectType):
         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
 
@@ -427,13 +427,13 @@ class BuiltinObjectType(PyObjectType):
                     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)
 
@@ -460,7 +460,7 @@ class BuiltinObjectType(PyObjectType):
         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
@@ -493,12 +493,12 @@ class PyExtensionType(PyObjectType):
     #  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
@@ -515,28 +515,28 @@ class PyExtensionType(PyObjectType):
         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
@@ -545,7 +545,7 @@ class PyExtensionType(PyObjectType):
                 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
@@ -573,14 +573,14 @@ class PyExtensionType(PyObjectType):
 
     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):
     #
@@ -589,7 +589,7 @@ 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
@@ -597,7 +597,7 @@ class CType(PyrexType):
 
     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
 
@@ -624,18 +624,18 @@ class CVoidType(CType):
     #
 
     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
 
@@ -647,27 +647,27 @@ class CNumericType(CType):
     #   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:
@@ -675,7 +675,7 @@ class CNumericType(CType):
         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
@@ -846,7 +846,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyInt_to_py_%(TypeName)s(%(type)s val) {
     } 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);
     }
 }
@@ -913,6 +913,8 @@ class CAnonEnumType(CIntType):
 
 class CReturnCodeType(CIntType):
 
+    to_py_function = "__Pyx_Owned_Py_None"
+
     is_returncode = 1
 
 
@@ -925,6 +927,9 @@ class CBIntType(CIntType):
     def __repr__(self):
         return "<CNumericType bint>"
 
+    def __str__(self):
+        return 'bint'
+
 
 class CPyUCS4IntType(CIntType):
     # Py_UCS4
@@ -1096,22 +1101,22 @@ class CFloatType(CNumericType):
     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
@@ -1123,7 +1128,7 @@ class CComplexType(CNumericType):
             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 = {}
@@ -1135,7 +1140,7 @@ class CComplexType(CNumericType):
             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
@@ -1153,7 +1158,7 @@ class CComplexType(CNumericType):
     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)
@@ -1167,7 +1172,7 @@ class CComplexType(CNumericType):
         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
@@ -1175,12 +1180,12 @@ class CComplexType(CNumericType):
              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
@@ -1190,8 +1195,8 @@ class CComplexType(CNumericType):
                     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),
@@ -1211,7 +1216,7 @@ class CComplexType(CNumericType):
                              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))
@@ -1229,13 +1234,13 @@ class CComplexType(CNumericType):
                              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]
@@ -1250,10 +1255,10 @@ class CComplexType(CNumericType):
 
     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',
@@ -1524,31 +1529,31 @@ impl="""
 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
@@ -1559,38 +1564,38 @@ class CArrayType(CType):
         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
@@ -1603,13 +1608,13 @@ class CPtrType(CType):
                 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:
@@ -1621,7 +1626,7 @@ class CPtrType(CType):
 class CNullPtrType(CPtrType):
 
     is_null_ptr = 1
-    
+
 
 class CReferenceType(BaseType):
 
@@ -1632,20 +1637,20 @@ 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:
@@ -1667,10 +1672,10 @@ class CFuncType(CType):
     #  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,
@@ -1686,7 +1691,7 @@ class CFuncType(CType):
         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:
@@ -1702,14 +1707,14 @@ class CFuncType(CType):
             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)
@@ -1745,7 +1750,7 @@ class CFuncType(CType):
 
     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 ###
@@ -1779,11 +1784,11 @@ class CFuncType(CType):
         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
@@ -1819,7 +1824,7 @@ class CFuncType(CType):
         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())
@@ -1827,18 +1832,18 @@ class CFuncType(CType):
     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 = []
@@ -1876,7 +1881,7 @@ class CFuncType(CType):
         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)
@@ -1888,7 +1893,7 @@ class CFuncType(CType):
     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
@@ -1905,7 +1910,7 @@ class CFuncType(CType):
                              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
 
@@ -1930,13 +1935,13 @@ class CFuncTypeArg(object):
         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)
 
@@ -1950,11 +1955,11 @@ class StructUtilityCode(object):
         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;")
@@ -1977,7 +1982,7 @@ class StructUtilityCode(object):
         if self.forward_decl:
             proto.putln(self.type.declaration_code('') + ';')
         proto.putln(self.header + ";")
-        
+
 
 class CStructOrUnionType(CType):
     #  name          string
@@ -1986,12 +1991,12 @@ class CStructOrUnionType(CType):
     #  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
@@ -2004,7 +2009,7 @@ class CStructOrUnionType(CType):
         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
@@ -2019,15 +2024,15 @@ class CStructOrUnionType(CType):
                     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
@@ -2059,7 +2064,7 @@ class CStructOrUnionType(CType):
 
     def is_complete(self):
         return self.scope is not None
-    
+
     def attributes_known(self):
         return self.is_complete()
 
@@ -2082,12 +2087,12 @@ class CppClassType(CType):
     #  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
@@ -2103,11 +2108,11 @@ class CppClassType(CType):
             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
@@ -2154,7 +2159,7 @@ class CppClassType(CType):
             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:
@@ -2173,23 +2178,23 @@ class CppClassType(CType):
         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]
@@ -2201,10 +2206,10 @@ class TemplatePlaceholderType(CType):
             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)
@@ -2227,15 +2232,15 @@ class CEnumType(CType):
         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
@@ -2253,7 +2258,7 @@ class CStringType(object):
 
     is_string = 1
     is_unicode = 0
-    
+
     to_py_function = "PyBytes_FromString"
     from_py_function = "PyBytes_AsString"
     exception_value = "NULL"
@@ -2265,32 +2270,32 @@ class CStringType(object):
 
 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"
 
@@ -2300,39 +2305,39 @@ class CUCharPtrType(CStringType, CPtrType):
 
 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"
 
@@ -2462,7 +2467,7 @@ modifiers_and_name_to_type = {
 
 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)
@@ -2485,7 +2490,7 @@ def best_match(args, functions, pos=None):
     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
@@ -2495,7 +2500,7 @@ def best_match(args, functions, pos=None):
     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 = []
@@ -2527,7 +2532,7 @@ def best_match(args, functions, pos=None):
             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]
@@ -2538,10 +2543,10 @@ def best_match(args, functions, pos=None):
             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
@@ -2561,14 +2566,14 @@ def best_match(args, functions, pos=None):
                 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])
@@ -2588,7 +2593,7 @@ def widest_numeric_type(type1, type2):
             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
@@ -2680,7 +2685,7 @@ def simple_c_type(signed, longness, name):
     # 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_'):
@@ -2714,7 +2719,7 @@ def parse_basic_type(name):
         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
@@ -2758,7 +2763,7 @@ def c_ref_type(base_type):
 
 def same_type(type1, type2):
     return type1.same_as(type2)
-    
+
 def assignable_from(type1, type2):
     return type1.assignable_from(type2)
 
@@ -2780,6 +2785,7 @@ type_conversion_predeclarations = """
 #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);
index cc51ba1523dca33f8428f45d936d75a30d4fb5f0..2a79d945daccd61a1a4034b2bd150c6300baf5a0 100644 (file)
@@ -1,4 +1,4 @@
-# cython: infer_types=True, language_level=3
+# cython: infer_types=True, language_level=3, py2_import=True
 #
 #   Cython Scanner
 #
@@ -36,7 +36,7 @@ def get_lexicon():
 #------------------------------------------------------------------
 
 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",
@@ -45,7 +45,7 @@ py_reserved_words = [
 
 pyx_reserved_words = py_reserved_words + [
     "include", "ctypedef", "cdef", "cpdef",
-    "cimport", "by", "DEF", "IF", "ELIF", "ELSE"
+    "cimport", "DEF", "IF", "ELIF", "ELSE"
 ]
 
 class Method(object):
index d5c8dd20e3c4a6c530fdbdb8f6f325d8785b9b1f..6425a26de17f6616a665c3f1de3cf82eface069a 100644 (file)
@@ -211,6 +211,7 @@ class Scope(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
@@ -228,6 +229,7 @@ class Scope(object):
     #                                      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
@@ -361,10 +363,10 @@ class Scope(object):
     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)
@@ -374,21 +376,22 @@ class Scope(object):
         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)
@@ -398,16 +401,18 @@ class Scope(object):
         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)
@@ -416,7 +421,8 @@ class Scope(object):
             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:
@@ -484,10 +490,10 @@ class Scope(object):
                 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)
@@ -495,13 +501,13 @@ class Scope(object):
         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':
@@ -514,6 +520,7 @@ class Scope(object):
                 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
 
@@ -549,11 +556,16 @@ class Scope(object):
         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
@@ -728,6 +740,8 @@ class PreImportScope(Scope):
 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)
@@ -751,7 +765,10 @@ class BuiltinScope(Scope):
             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):
@@ -793,6 +810,8 @@ class BuiltinScope(Scope):
         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
@@ -902,29 +921,36 @@ class ModuleScope(Scope):
         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):
@@ -995,13 +1021,13 @@ class ModuleScope(Scope):
         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:
@@ -1035,8 +1061,8 @@ class ModuleScope(Scope):
         # 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:
@@ -1283,12 +1309,12 @@ class LocalScope(Scope):
         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
@@ -1304,6 +1330,16 @@ class LocalScope(Scope):
             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.
@@ -1321,6 +1357,7 @@ class LocalScope(Scope):
                 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
@@ -1354,7 +1391,7 @@ class GeneratorExpressionScope(Scope):
         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)
@@ -1369,6 +1406,12 @@ class GeneratorExpressionScope(Scope):
         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):
 
@@ -1397,7 +1440,7 @@ class StructOrUnionScope(Scope):
         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
@@ -1419,7 +1462,8 @@ class StructOrUnionScope(Scope):
     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
@@ -1463,16 +1507,30 @@ class PyClassScope(ClassScope):
     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)
 
@@ -1513,7 +1571,7 @@ class CClassScope(ClassScope):
                 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:
@@ -1553,7 +1611,7 @@ class CClassScope(ClassScope):
                 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
@@ -1569,7 +1627,8 @@ class CClassScope(ClassScope):
         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
@@ -1694,7 +1753,8 @@ class CppClassScope(Scope):
         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
@@ -1735,15 +1795,16 @@ class CppClassScope(Scope):
             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
@@ -1767,8 +1828,9 @@ class CppClassScope(Scope):
                 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
 
index 76a0af40fd68d07babdd04f1feb14fa7415e34ed..3352c71d57e6e749003f39335460fc2c41d28d46 100644 (file)
@@ -54,11 +54,10 @@ class TestTreeFragments(CythonTest):
             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
index ea30561d839798e1ef284fb70adc009fda12db16..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -1 +1 @@
-#empty
+# empty file
index c50f4f9555567cb08390f869621d5b2993b71b58..6ab0bf7085709f9a8b4a77e6fd68d440453a7f6b 100644 (file)
@@ -121,16 +121,15 @@ class TemplateTransform(VisitorTransform):
         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):
@@ -161,9 +160,8 @@ class TemplateTransform(VisitorTransform):
     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)
 
index c788d02c3897a515dd62adbc70cc733d6758c95a..3ff3daf76130ad3ee745cfdbf1470b3f0595086e 100644 (file)
@@ -221,8 +221,9 @@ class SimpleAssignmentTypeInferer(object):
     # 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
@@ -238,6 +239,10 @@ class SimpleAssignmentTypeInferer(object):
         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))
@@ -250,6 +255,7 @@ class SimpleAssignmentTypeInferer(object):
                             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]:
@@ -258,6 +264,7 @@ class SimpleAssignmentTypeInferer(object):
                     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:
index 3aff81f83a410e2599d298ac4e5d2822695b8d54..42f68e928c18e5e9daab650741d9889a8bf0ea9a 100644 (file)
@@ -134,6 +134,10 @@ class ResultRefNode(AtomicExprNode):
             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
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index 41bf9be5e11994fc815c24ef59cf0568fbf30d77..4a24001f15fa6b82dd3c41ab172da0df1dbe2970 100644 (file)
@@ -1,12 +1,2 @@
-# 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
index 356547ac91538aedd251486c18a9ec3ee9a3a977..bcf8b806cf202d569063686772cecc308bb4c9d0 100644 (file)
 #     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.
@@ -40,7 +42,7 @@
 ## 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
diff --git a/Cython/Includes/libcpp/string.pxd b/Cython/Includes/libcpp/string.pxd
new file mode 100644 (file)
index 0000000..2fefe57
--- /dev/null
@@ -0,0 +1,114 @@
+
+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*)
index 7ddd00ba992e1e7b140c489b1a1741cede091368..6b36670a838893ae3e5c1f610a38fffaee372052 100644 (file)
@@ -190,6 +190,9 @@ cdef extern from "numpy/arrayobject.h":
             # 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)
index 965e8d3517c989f2b383412b63b194be709a993f..891873b56feba2f951cd3ac0c97488eb7af1725a 100644 (file)
@@ -39,7 +39,7 @@ class UnrecognizedInput(PlexError):
 
   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):
index 36ed9d19c92cf82b6254520f1283f0c00cc9ee20..315742f309de1ad94f6cebbf6e485cd004d62f55 100644 (file)
@@ -299,6 +299,11 @@ class Scanner(object):
     """
     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 = (
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index d0e401ea81bf6ecc988f1705da90bdc7302e0843..e909a99031eeee29a0b52f6e711b25740b2d79da 100644 (file)
@@ -2,13 +2,29 @@
 
 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):
@@ -38,11 +54,11 @@ def cmod(a, b):
 
 # 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
@@ -53,9 +69,9 @@ def typeof(arg):
 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()
@@ -75,25 +91,28 @@ del _nogil
 
 # 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
@@ -108,6 +127,14 @@ class PointerType(CythonType):
             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):
@@ -116,9 +143,18 @@ class ArrayType(PointerType):
 
 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:
@@ -129,10 +165,22 @@ class StructType(CythonType):
 
 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):
@@ -173,9 +221,8 @@ class typedef(CythonType):
     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
 
 
@@ -229,4 +276,4 @@ for t in int_types + float_types + complex_types + other_types:
         gs["%s_%s" % ('p'*i, t)] = globals()[t]._pointer(i)
 
 void = typedef(None)
-NULL = None
+NULL = p_void(0)
index ea30561d839798e1ef284fb70adc009fda12db16..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -1 +1 @@
-#empty
+# empty file
index b061910c6895b9a54f5890620bf6b1bb206b2a3a..239252e72b893e818ee944e3ca8a9bb04d1ae873 100644 (file)
@@ -16,7 +16,7 @@ include Demos/embed/*
 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
index 53487da16c41118d4b051ab138666e028d50bde9..66a2d5e353ab5c6425b8caace6003f04bbf56f74 100644 (file)
@@ -1,6 +1,8 @@
 ;; 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))
diff --git a/bin/cythonrun b/bin/cythonrun
new file mode 100755 (executable)
index 0000000..1c61954
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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:])
old mode 100644 (file)
new mode 100755 (executable)
index c8987bb..5dbd25c
--- a/cython.py
+++ b/cython.py
@@ -1,9 +1,18 @@
+#!/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)
 
diff --git a/docs/.hgignore b/docs/.hgignore
new file mode 100644 (file)
index 0000000..23f13a1
--- /dev/null
@@ -0,0 +1,9 @@
+syntax: glob
+
+*.pyc
+*~
+.*.swp
+
+syntax: regexp
+^build/
+^_build/
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644 (file)
index 0000000..70a45cb
--- /dev/null
@@ -0,0 +1,68 @@
+# 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."
diff --git a/docs/README b/docs/README
new file mode 100644 (file)
index 0000000..fa4603f
--- /dev/null
@@ -0,0 +1,14 @@
+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
diff --git a/docs/TODO b/docs/TODO
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/docs/_static/cython-logo-light.png b/docs/_static/cython-logo-light.png
new file mode 100644 (file)
index 0000000..5fd5f20
Binary files /dev/null and b/docs/_static/cython-logo-light.png differ
diff --git a/docs/_static/cythonlogo.png b/docs/_static/cythonlogo.png
new file mode 100644 (file)
index 0000000..2b4ee54
Binary files /dev/null and b/docs/_static/cythonlogo.png differ
diff --git a/docs/_static/favicon.ico b/docs/_static/favicon.ico
new file mode 100644 (file)
index 0000000..db92af5
Binary files /dev/null and b/docs/_static/favicon.ico differ
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
new file mode 100644 (file)
index 0000000..a071c96
--- /dev/null
@@ -0,0 +1,14 @@
+{% 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 %}
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644 (file)
index 0000000..5607c5f
--- /dev/null
@@ -0,0 +1,163 @@
+# -*- 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
diff --git a/docs/examples/tutorial/fib1/fib.pyx b/docs/examples/tutorial/fib1/fib.pyx
new file mode 100644 (file)
index 0000000..043d71e
--- /dev/null
@@ -0,0 +1,6 @@
+def fib(n):
+    """Print the Fibonacci series up to n."""
+    a, b = 0, 1
+    while b < n:
+        print b,
+        a, b = b, a + b
diff --git a/docs/examples/tutorial/fib1/setup.py b/docs/examples/tutorial/fib1/setup.py
new file mode 100644 (file)
index 0000000..bda9101
--- /dev/null
@@ -0,0 +1,9 @@
+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"])]
+)
+
diff --git a/docs/examples/tutorial/great_circle/c1.pyx b/docs/examples/tutorial/great_circle/c1.pyx
new file mode 100644 (file)
index 0000000..c0694a2
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/docs/examples/tutorial/great_circle/c2.pyx b/docs/examples/tutorial/great_circle/c2.pyx
new file mode 100644 (file)
index 0000000..eb4915c
--- /dev/null
@@ -0,0 +1,13 @@
+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
diff --git a/docs/examples/tutorial/great_circle/p1.py b/docs/examples/tutorial/great_circle/p1.py
new file mode 100644 (file)
index 0000000..c0694a2
--- /dev/null
@@ -0,0 +1,12 @@
+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
diff --git a/docs/examples/tutorial/primes/primes.py b/docs/examples/tutorial/primes/primes.py
new file mode 100644 (file)
index 0000000..a25fdd8
--- /dev/null
@@ -0,0 +1,15 @@
+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
+
diff --git a/docs/examples/tutorial/primes/primes.pyx b/docs/examples/tutorial/primes/primes.pyx
new file mode 100644 (file)
index 0000000..63c42a5
--- /dev/null
@@ -0,0 +1,19 @@
+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
+
diff --git a/docs/examples/tutorial/primes/setup.py b/docs/examples/tutorial/primes/setup.py
new file mode 100644 (file)
index 0000000..ca5ea49
--- /dev/null
@@ -0,0 +1,9 @@
+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"])]
+)
+
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..683e691
--- /dev/null
@@ -0,0 +1,11 @@
+
+Welcome to Cython's Documentation
+=================================
+
+.. toctree::
+   :maxdepth: 2
+
+   src/quickstart/index
+   src/tutorial/index
+   src/userguide/index
+   src/reference/index
diff --git a/docs/sphinxext/cython_highlighting.py b/docs/sphinxext/cython_highlighting.py
new file mode 100644 (file)
index 0000000..3a2e5f9
--- /dev/null
@@ -0,0 +1,182 @@
+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()
diff --git a/docs/sphinxext/ipython_console_highlighting.py b/docs/sphinxext/ipython_console_highlighting.py
new file mode 100644 (file)
index 0000000..4f0104d
--- /dev/null
@@ -0,0 +1,75 @@
+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()
diff --git a/docs/src/quickstart/build.rst b/docs/src/quickstart/build.rst
new file mode 100644 (file)
index 0000000..b15987a
--- /dev/null
@@ -0,0 +1,60 @@
+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
diff --git a/docs/src/quickstart/cythonize.rst b/docs/src/quickstart/cythonize.rst
new file mode 100644 (file)
index 0000000..04e0d9d
--- /dev/null
@@ -0,0 +1,126 @@
+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
diff --git a/docs/src/quickstart/demo.pyx b/docs/src/quickstart/demo.pyx
new file mode 100644 (file)
index 0000000..b1851ff
--- /dev/null
@@ -0,0 +1,81 @@
+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")
diff --git a/docs/src/quickstart/htmlreport.png b/docs/src/quickstart/htmlreport.png
new file mode 100644 (file)
index 0000000..a07a53d
Binary files /dev/null and b/docs/src/quickstart/htmlreport.png differ
diff --git a/docs/src/quickstart/index.rst b/docs/src/quickstart/index.rst
new file mode 100644 (file)
index 0000000..3f2c439
--- /dev/null
@@ -0,0 +1,10 @@
+Getting Started
+===============
+
+.. toctree::
+   :maxdepth: 2
+
+   overview
+   install
+   build
+   cythonize
diff --git a/docs/src/quickstart/install.rst b/docs/src/quickstart/install.rst
new file mode 100644 (file)
index 0000000..626b434
--- /dev/null
@@ -0,0 +1,52 @@
+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
diff --git a/docs/src/quickstart/overview.rst b/docs/src/quickstart/overview.rst
new file mode 100644 (file)
index 0000000..f356688
--- /dev/null
@@ -0,0 +1,54 @@
+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.
diff --git a/docs/src/quickstart/sage.png b/docs/src/quickstart/sage.png
new file mode 100644 (file)
index 0000000..b19df05
Binary files /dev/null and b/docs/src/quickstart/sage.png differ
diff --git a/docs/src/reference/Makefile b/docs/src/reference/Makefile
new file mode 100644 (file)
index 0000000..70a45cb
--- /dev/null
@@ -0,0 +1,68 @@
+# 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."
diff --git a/docs/src/reference/compilation.rst b/docs/src/reference/compilation.rst
new file mode 100644 (file)
index 0000000..fff850d
--- /dev/null
@@ -0,0 +1,249 @@
+.. 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.
diff --git a/docs/src/reference/directives.rst b/docs/src/reference/directives.rst
new file mode 100644 (file)
index 0000000..33ad093
--- /dev/null
@@ -0,0 +1,4 @@
+Compiler Directives
+===================
+
+TODO. See http://wiki.cython.org/enhancements/compilerdirectives
\ No newline at end of file
diff --git a/docs/src/reference/extension_types.rst b/docs/src/reference/extension_types.rst
new file mode 100644 (file)
index 0000000..46ece2b
--- /dev/null
@@ -0,0 +1,522 @@
+.. 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/reference/index.rst b/docs/src/reference/index.rst
new file mode 100644 (file)
index 0000000..2cd290a
--- /dev/null
@@ -0,0 +1,31 @@
+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`
diff --git a/docs/src/reference/interfacing_with_other_code.rst b/docs/src/reference/interfacing_with_other_code.rst
new file mode 100644 (file)
index 0000000..73e2fb8
--- /dev/null
@@ -0,0 +1,26 @@
+.. highlight:: cython
+
+.. _interfacing_with_other_code:
+
+***************************
+Interfacing with Other Code
+***************************
+
+==
+C
+==
+
+===
+C++
+===
+
+=======
+Fortran
+=======
+
+=====
+Numpy
+=====
+
+
+
diff --git a/docs/src/reference/language_basics.rst b/docs/src/reference/language_basics.rst
new file mode 100644 (file)
index 0000000..d0d99e1
--- /dev/null
@@ -0,0 +1,778 @@
+.. 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/src/reference/limitations.rst b/docs/src/reference/limitations.rst
new file mode 100644 (file)
index 0000000..a4a3ff0
--- /dev/null
@@ -0,0 +1,8 @@
+.. highlight:: cython
+
+.. _limitations:
+
+***********
+Limitations
+***********
+
diff --git a/docs/src/reference/special_mention.rst b/docs/src/reference/special_mention.rst
new file mode 100644 (file)
index 0000000..0b40771
--- /dev/null
@@ -0,0 +1,8 @@
+.. highlight:: cython
+
+.. _special_mention:
+
+
+***************
+Special Mention
+***************
diff --git a/docs/src/reference/special_methods_table.rst b/docs/src/reference/special_methods_table.rst
new file mode 100644 (file)
index 0000000..d3d1c6f
--- /dev/null
@@ -0,0 +1,218 @@
+.. _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                                |
++-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+
+
+
+
+
diff --git a/docs/src/tutorial/appendix.rst b/docs/src/tutorial/appendix.rst
new file mode 100644 (file)
index 0000000..4583793
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/docs/src/tutorial/caveats.rst b/docs/src/tutorial/caveats.rst
new file mode 100644 (file)
index 0000000..c4629d9
--- /dev/null
@@ -0,0 +1,19 @@
+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. 
diff --git a/docs/src/tutorial/cdef_classes.rst b/docs/src/tutorial/cdef_classes.rst
new file mode 100644 (file)
index 0000000..5a4aff1
--- /dev/null
@@ -0,0 +1,141 @@
+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
+      <...>
diff --git a/docs/src/tutorial/clibraries.rst b/docs/src/tutorial/clibraries.rst
new file mode 100644 (file)
index 0000000..bebd584
--- /dev/null
@@ -0,0 +1,476 @@
+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/
diff --git a/docs/src/tutorial/data.py b/docs/src/tutorial/data.py
new file mode 100644 (file)
index 0000000..f002762
--- /dev/null
@@ -0,0 +1,40 @@
+{
+ '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}'''}
+ ],
+}
diff --git a/docs/src/tutorial/external.rst b/docs/src/tutorial/external.rst
new file mode 100644 (file)
index 0000000..35df8f4
--- /dev/null
@@ -0,0 +1,79 @@
+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.
diff --git a/docs/src/tutorial/index.rst b/docs/src/tutorial/index.rst
new file mode 100644 (file)
index 0000000..3d1a6aa
--- /dev/null
@@ -0,0 +1,19 @@
+Tutorials
+=========
+
+.. toctree::
+   :maxdepth: 2
+
+   external
+   clibraries
+   cdef_classes
+   pxd_files
+   caveats
+   profiling_tutorial
+   strings
+   pure
+   numpy
+   readings
+   related_work
+   appendix
+
diff --git a/docs/src/tutorial/numpy.rst b/docs/src/tutorial/numpy.rst
new file mode 100644 (file)
index 0000000..fec107f
--- /dev/null
@@ -0,0 +1,313 @@
+=======================
+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).
+
diff --git a/docs/src/tutorial/profiling_tutorial.rst b/docs/src/tutorial/profiling_tutorial.rst
new file mode 100644 (file)
index 0000000..5dc6a63
--- /dev/null
@@ -0,0 +1,300 @@
+.. 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.
+
+
diff --git a/docs/src/tutorial/pure.rst b/docs/src/tutorial/pure.rst
new file mode 100644 (file)
index 0000000..9976e85
--- /dev/null
@@ -0,0 +1,152 @@
+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
+
diff --git a/docs/src/tutorial/pxd_files.rst b/docs/src/tutorial/pxd_files.rst
new file mode 100644 (file)
index 0000000..fc85f9d
--- /dev/null
@@ -0,0 +1,41 @@
+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.
diff --git a/docs/src/tutorial/queue_example/cqueue.pxd b/docs/src/tutorial/queue_example/cqueue.pxd
new file mode 100644 (file)
index 0000000..a6c5d57
--- /dev/null
@@ -0,0 +1,17 @@
+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)
diff --git a/docs/src/tutorial/queue_example/queue.pyx b/docs/src/tutorial/queue_example/queue.pyx
new file mode 100644 (file)
index 0000000..fd8addf
--- /dev/null
@@ -0,0 +1,95 @@
+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
diff --git a/docs/src/tutorial/readings.rst b/docs/src/tutorial/readings.rst
new file mode 100644 (file)
index 0000000..607e871
--- /dev/null
@@ -0,0 +1,26 @@
+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
diff --git a/docs/src/tutorial/related_work.rst b/docs/src/tutorial/related_work.rst
new file mode 100644 (file)
index 0000000..cd1d584
--- /dev/null
@@ -0,0 +1,50 @@
+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.
diff --git a/docs/src/tutorial/strings.rst b/docs/src/tutorial/strings.rst
new file mode 100644 (file)
index 0000000..2c2627f
--- /dev/null
@@ -0,0 +1,370 @@
+.. 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.
diff --git a/docs/src/userguide/debugging.rst b/docs/src/userguide/debugging.rst
new file mode 100644 (file)
index 0000000..0f03616
--- /dev/null
@@ -0,0 +1,286 @@
+.. 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
diff --git a/docs/src/userguide/early_binding_for_speed.rst b/docs/src/userguide/early_binding_for_speed.rst
new file mode 100644 (file)
index 0000000..d44498d
--- /dev/null
@@ -0,0 +1,131 @@
+.. 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.
+
diff --git a/docs/src/userguide/extension_types.rst b/docs/src/userguide/extension_types.rst
new file mode 100644 (file)
index 0000000..9d37c1d
--- /dev/null
@@ -0,0 +1,576 @@
+.. 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.
+
+
+
diff --git a/docs/src/userguide/external_C_code.rst b/docs/src/userguide/external_C_code.rst
new file mode 100644 (file)
index 0000000..14910c2
--- /dev/null
@@ -0,0 +1,465 @@
+.. 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`.
+
diff --git a/docs/src/userguide/index.rst b/docs/src/userguide/index.rst
new file mode 100644 (file)
index 0000000..3f18fac
--- /dev/null
@@ -0,0 +1,31 @@
+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::
+
diff --git a/docs/src/userguide/language_basics.rst b/docs/src/userguide/language_basics.rst
new file mode 100644 (file)
index 0000000..3cbbcc0
--- /dev/null
@@ -0,0 +1,567 @@
+.. 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.
+
diff --git a/docs/src/userguide/limitations.rst b/docs/src/userguide/limitations.rst
new file mode 100644 (file)
index 0000000..6dbadc8
--- /dev/null
@@ -0,0 +1,75 @@
+.. 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.
diff --git a/docs/src/userguide/numpy_tutorial.rst b/docs/src/userguide/numpy_tutorial.rst
new file mode 100644 (file)
index 0000000..aafeea7
--- /dev/null
@@ -0,0 +1,496 @@
+.. 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.
+
diff --git a/docs/src/userguide/overview.rst b/docs/src/userguide/overview.rst
new file mode 100644 (file)
index 0000000..6e2a6db
--- /dev/null
@@ -0,0 +1,32 @@
+.. 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`.
+
diff --git a/docs/src/userguide/pxd_package.rst b/docs/src/userguide/pxd_package.rst
new file mode 100644 (file)
index 0000000..df733e8
--- /dev/null
@@ -0,0 +1,49 @@
+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.
+
diff --git a/docs/src/userguide/pyrex_differences.rst b/docs/src/userguide/pyrex_differences.rst
new file mode 100644 (file)
index 0000000..bf7cd03
--- /dev/null
@@ -0,0 +1,342 @@
+.. 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. 
+
diff --git a/docs/src/userguide/sharing_declarations.rst b/docs/src/userguide/sharing_declarations.rst
new file mode 100644 (file)
index 0000000..ac01815
--- /dev/null
@@ -0,0 +1,241 @@
+.. 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``.
+
diff --git a/docs/src/userguide/source_files_and_compilation.rst b/docs/src/userguide/source_files_and_compilation.rst
new file mode 100644 (file)
index 0000000..32b7df6
--- /dev/null
@@ -0,0 +1,198 @@
+.. 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.
+
diff --git a/docs/src/userguide/special_methods.rst b/docs/src/userguide/special_methods.rst
new file mode 100644 (file)
index 0000000..2272c62
--- /dev/null
@@ -0,0 +1,373 @@
+.. _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".
+
diff --git a/docs/src/userguide/tutorial.rst b/docs/src/userguide/tutorial.rst
new file mode 100644 (file)
index 0000000..7c884e6
--- /dev/null
@@ -0,0 +1,171 @@
+.. 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`.
+
diff --git a/docs/src/userguide/wrapping_CPlusPlus.rst b/docs/src/userguide/wrapping_CPlusPlus.rst
new file mode 100644 (file)
index 0000000..22d1585
--- /dev/null
@@ -0,0 +1,426 @@
+.. 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.
+
+
diff --git a/docs/todo.txt b/docs/todo.txt
new file mode 100644 (file)
index 0000000..2c53f42
--- /dev/null
@@ -0,0 +1,24 @@
+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. 
diff --git a/docs/welcome.rst b/docs/welcome.rst
new file mode 100644 (file)
index 0000000..aee8d9d
--- /dev/null
@@ -0,0 +1,121 @@
+.. 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/
+
+
+
+
+
+
+
+
+
+
+
+
+
index ac509a46ec6cc5535c90cd80578d205c0ca4298f..05d6cda089e87264108f8ff2f585a74e6525da6c 100644 (file)
@@ -205,7 +205,10 @@ class PyxImporter(object):
         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
@@ -258,7 +261,8 @@ class PyImporter(PyxImporter):
         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:
@@ -269,7 +273,7 @@ class PyImporter(PyxImporter):
             # 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:
@@ -285,13 +289,13 @@ class PyImporter(PyxImporter):
         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:
index bea63575c41b724b1982c703a89a3c303bac29d7..e9d09f1562f12ea5d12ce986601e06812ffa9f19 100644 (file)
@@ -22,11 +22,32 @@ try:
 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
 
@@ -47,26 +68,23 @@ if sys.platform == 'win32':
     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
@@ -75,11 +93,16 @@ VER_DEP_MODULES = {
                                           ]),
     (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
@@ -105,6 +128,38 @@ COMPILER = None
 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++':
@@ -166,17 +221,15 @@ class TestBuilder(object):
 
     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']:
@@ -191,67 +244,81 @@ class TestBuilder(object):
         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)
@@ -263,13 +330,14 @@ class TestBuilder(object):
                           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
@@ -281,16 +349,26 @@ class CythonCompileTestCase(unittest.TestCase):
         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:
@@ -352,10 +430,10 @@ class CythonCompileTestCase(unittest.TestCase):
 
     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"):
@@ -512,64 +590,70 @@ class CythonRunTestCase(CythonCompileTestCase):
             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):
@@ -667,6 +751,11 @@ class CythonUnitTestCase(CythonRunTestCase):
 
 
 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)
@@ -692,20 +781,23 @@ class CythonPyregrTestCase(CythonRunTestCase):
         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)
 
@@ -914,11 +1006,11 @@ class MissingDependencyExcluder:
             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
@@ -932,7 +1024,7 @@ class VersionDependencyExcluder:
             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)
@@ -952,9 +1044,37 @@ class FileListExcluder:
         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
@@ -1187,16 +1307,16 @@ def main():
     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)
@@ -1206,7 +1326,7 @@ def main():
     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")) ]
@@ -1240,15 +1360,15 @@ def main():
         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
index 7c52b7ef73809400f3fc53ada6f7eea21bc85d61..cb4f996dd241e9fb0d60e1f2702a9e105a82ec4e 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -18,6 +18,7 @@ def add_command_class(name, cls):
 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
index a5cebffc18125f01e9b968bd90f6ac4fa45ce58f..c586868ee99e8a6b4609ac2e72a50519b282391b 100644 (file)
@@ -10,8 +10,6 @@ cfunc_call_tuple_args_T408
 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
@@ -19,14 +17,15 @@ genexpr_iterable_lookup_T600
 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
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index 4d8bfa95c239b77b3dd93c32fe3fda067d24fa6d..8aefe30589870fb5f38fd8a2887c17279ae3c23d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef public struct Foo:
     int a, b
 
@@ -11,6 +13,12 @@ cdef public class C[type C_Type, object C_Obj]:
 
 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
 
@@ -19,3 +27,6 @@ cdef public void g(Blarg *x):
 
 cdef public api void h(Zax *x):
     pass
+
+cdef extern from "a_capi.h":
+    pass
index e008feded82bc6b180606d4aa5f69944b8bf3107..2b62c5d1f38914bc382c6028ee877c57c5e3ccd1 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef swallow
 
 def spam(w, int x = 42, y = "grail", z = swallow):
index 535e4319f062e1b08d9a38124525ce3c764db674..bdc904075d1070ce51c6ea949cdd2006c469d919 100644 (file)
@@ -1,3 +1,4 @@
+# mode: compile
 
 cdef extern from *:
 
index c38df36a71d2e8a4ea12b6a15feb934445f25754..1b7977698ba524dba91c6f068b45f096719ec895 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum E:
     z
 
index 57f9be38dad7f59b6e12f7ed75832df0877bbe6c..2afa45fcbe66cce786a5073cee02a14e16fb3abf 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f1(char *argv[]):
     f2(argv)
 
index 87457ee145b39d3f1f60a3c5d02b4af2854bd164..8127cc348721b8e00001fc38aa9ef4cc9c0d9178 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void spam():
     cdef long long L
     cdef unsigned long long U
index f34c0964ca851687596fdae0c0eca8a99460c526..f53040df1aeec2824494e137b4d5eafc25279a86 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 def f(a, b):
     assert a, a+b
index de064c07188e00256c2ab47b2516ea92704b7f91..e8b4f4eb31d68255da8e303c92915c263514e258 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum E:
     spam, eggs
 
index f7437212910ec9d7cef1b180eaafec49420a50da..12a31b48e6a0513c82c91cf89a5b8c8740821bae 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from *:
     ctypedef int intptr_t
 
index 061a4e2ddb58f904d02e534a6b4e05e91c6c9849..3a3b38765d5677030a024bc661abcfb3e6efc886 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 444
+# mode: compile
 
 def test():
      cdef object[int] not_assigned_to
index 542e53272b0d0f0f42dcbd794fd6623cecf35f32..9ae30fdbaddda89d6eca4a6f14df34ee38963568 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 def f():
     x = open("foo")
index 096ee870e313e35feb83d66719659c6fda32965c..86379bde20566de835abe8afabcbc60690fc2776 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int f() except -1:
     cdef object x, y, z, w
     cdef int i
index 1d505daaa6bf47b62c0bf60e39536ef34f247f90..0ede90ba8e8d138fe5dc417acbf2dc47014324f8 100644 (file)
@@ -1,3 +1,4 @@
+# mode: compile
 # cython: boundscheck  =  False
 # cython: ignoreme = OK
 # cython: warn.undeclared = False
index 0e3fa9dbe33bf92795baa4eb9014e6d628155842..ce236ed799cffdb235fda24ded9e6855e175027d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "callingconvention.h":
     pass
 
index 58421cb8921dee8043242b5e6122c13e8a462efa..55fe9b74bf3fdf9dddb659a436b0763af26d7433 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(obj, int i, float f, char *s1, char s2[]):
     pass
 
index 44cba442595441a03a00726845430950735cb120..930e2d19cb58148b8d1a0ee9409dc1b3682cb09d 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef extern:
     cdef func(int[])
index d2ebddb53ddeb75af1695f731f6c24ffbf1f6a27..c36997fbbc15a02cf2bcb01fe03ffd1be14ee09e 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void foo():
     cdef int bool, int1=0, int2=0, int3=0, int4=0
     cdef object obj1, obj2, obj3, obj4
index a6bd7994e91058ba8f83d8bbef77693e6a37016b..6a21c19ed96aa8774ddf4e00f91560fefe1d3669 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void foo():
     cdef int i1, i2=0
     cdef char c1=0, c2
index f6785062437632ee09da5bcff345e71f4f227e5e..a62f4cf4cba10b171695f67977bec2d7db978a16 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 518
+# mode: compile
+
 cdef extern from "cast_ctypedef_array_T518_helper.h":
     cdef struct __foo_struct:
        int i, j
index 518ae0f72c213fff1957a9e376dbd7abfc6e03b8..b497cab98e5405f9c8b8974949b716868c7d53f9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern class external.Spam:
     pass
 
index be4d65caa3c7b53f1afff29c80dcb10c09ed1990..33053edc7225ad72c06411a591d191953c21eb3a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "cheese.h":
     pass
 
index 11ecbdf2808d48027d3a46ffada89871f8175b7d..1a3c3fd45ac12f44058df1d3d27b4e7784f71fc2 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from *:
     int spam
 
index 4b90156ea15977187f1778588074382cc37a6ac9..33d5c230634c7f235b750984147edad1eba10ec3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum Spam:
     a
     b, c,
index 2466f8252c3222eee272d3cad4f93a1ff17b114f..1a769824c18fd1f9a1bd5e244eaa222d2ad1f6a4 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int i, j, k
 cdef object a, b, x
 
index 54367cb6bfb531a2321b66011145f23c6f3a8c0b..28403f12292ea49aef167b678e888503d44be269 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 4
+# mode: compile
+
 from a cimport b
 
 cdef int **t = b.foo(NULL)
index 6be755063df2739bb66cd0213e1be7a0b062067a..13796baf105bd7e81cda1bbabf2c0fa86333dfe3 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 248
+# mode: compile
+
 from ewing8 cimport (Foo,
 
 
index 3d246eff2df67cdd979f171eff7fccd7cf0023b7..1bed42a7c389b6a9d7c226092053c7d2778c01fd 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 __doc__ = u"""
     >>> s = Swallow()
     >>> s.spam(1)
index 161045e85598b262ac5618b8b7498b5c19874e0b..f67911d647db264c612c8adde65fa8da9af42111 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "cnamespec.h":
     int a "c_a", b "c_b"
 
index d94bd8d19e5ab416096ad651834d1645425943e9..5b0f1063232e612e274f48525ae77d31eb614166 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f():
     cdef int int1, int2=0, int3=1
     cdef char char1=0
index 38c2705b8d0886b00e805772dc0f78fef8498e42..c6032aea755984beb083382be98cd426cc811a1c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f():
     cdef void *p
     cdef char *q=NULL
index 2e56dcdce482620b757791914a45c27212aeb28a..6976eda23bbd615273c2c9556481e32ca96dd77e 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern (int *[42]) spam, grail, swallow
 
 cdef (int (*)()) brian():
index c76b5a3e75fe6ac27e7a86ba1ab023fae1ba308c..d5daa04266991d218f4f2e12c1075f9ad9a2aaf0 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum Grail:
     k = 42
 
index 828c1fc9dc0bd2883760235a5e7618142d377e65..f9ff187350eeefad677ebf36c372a04b1c012d21 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef class Tst:
     cdef foo,
index 1c3ed5284e19a2f906c3d30049ab7ca6b131e4f2..7eec85f759568d4e51c81b2560d690b1be976fd3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class A:
     cpdef a(self):
         ma(self)
index bccfacd65b7e7e2188ab4b46d73edec5446c91a0..b738dee05f2ed414eef6bf811e8e5ed4e5695665 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: compile
+
 cdef extern from "cpp_enums.h":
     cdef enum Enum1:
         Item1
index 6b661b6be5ab620d04cbd9581d73e0e6683db0f3..a38dba1469f9e303a9f63a1fc441293026177e91 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: compile
+
 cdef extern from "operators.h":
     cdef cppclass Operators:
         Operators(int)
index c7b86935cf269628b6f0fedbe46d555367a197ef..3aac0cd8105b5239b5c8c4dcf210c86292c08e57 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: compile
+
 cdef extern from "point.h" namespace "geometry":
 
     cdef struct Point:
index 634b46f53173d7a58a205082b281ccf3b7e93c58..1051a6489eef1df1aa14697e139fa1393aef0efc 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: compile
+
 cdef extern from *:
     cdef cppclass Foo[T]:
         pass
index 7fba995f46be01cefe59e3f1f70dc7891e2eaf87..fefa96be1dc05f05590bf3f9fa2eb4a51e3d8c65 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: compile
+
 cdef extern from "templates.h":
     cdef cppclass TemplateTest1[T]:
         TemplateTest1()
index cf2af37b983e1dacd9d46e78aa4095936ff9cec1..3d516dd2dc91af4c0c39c64b000119762782a217 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef struct Foo:
     int blarg
 
index 6b557842d41ea54c03bc0f650aba92de1b224347..23ea01bc8edf2b8ce078960cafa1104c5f8c95fa 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef int *IntPtr
 ctypedef unsigned long ULong
 cdef extern IntPtr spam
index 18178e40e3d635a2378437b8b8605894e3f20db8..505f9d67faf2e79e019e2e473add4aa646141eb6 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 355
+# mode: compile
+
 ctypedef public class Time [type MyTime_Type, object MyTimeObject]:
      def __init__(self, seconds):
          self.seconds = seconds
index cebd75c3fe1ba64b3dec5c222ef99425280aa02f..70fec73b929e8e7aae4d16dd38a82fbb81962983 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef class spam:
     pass
 
index 3810f484322a4054884b9673c61171d891c4858f..fc22b053c3e9914ad8121cc41e61f66de23b317f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef enum parrot_state:
     alive = 1
     dead = 2
index 091dc3d84a98974f43c4cd4120978c6dfbaa0e4a..e7d3d428c0f7463138669fab6f8118cd841ae9a9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef public api class Foo [type PyFoo_Type, object PyFooObject]:
     pass
 
index 825583ecd7339c93706a5c914cbab11dd029db5f..703cada718b41ff70994a3d0df4d36d77318bef3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef struct order:
     int spam
     int eggs
index aea471990e2a82f440ff3538c5078e7db4ebd03c..b0648f30f10ce9eac06e6512a18862813357976d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef union pet:
     int cat
     float dog
index fe72850f96d6f4e456aa4c86a48f6631f77c97f1..15cac5ed161b11d3ec32a57e9ee36c34f91375c1 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f():
     cdef unsigned long x
     cdef object y=0
index 47d3a73b6199c9722ad0a34a5a44477ef285d68b..ec6063ceb0d674333dc4fbc9af987942151821b5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern short int s
 cdef extern long int l
 cdef extern long long ll
index 760ba7a9a20ad32eb8ccbc0e8e978907470a4d58..3445fbffc9361a7cfe966dc5f43206e789a7bf0b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Tomato:
 
     def eject(self):
index b8705770e31f65e4744d051e83d273c374d1c051..52ba46b01138b5bdc54c5bd7d29ef05076b84549 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "declarations.h":
     pass
 
index a89761b81d5bb72adb4cd7339c3b36e35132bbb7..5ad36b40cceea28857f27b23c689692f4770e88c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(a, b):
     global g
     del g
index 20d192c21ba895c69945839697d6051f7fa3d98b..5d7c9b395e5a680cf48cf90284027178dbc06d4c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void spam():
     cdef object x
     del x[17:42]
index 1c258f7c0cdfae1273eea04553fd9cc330386e62..378b0af51ce9f44a36836117c3dc09248b3f80ff 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 "Welcome to the parrot module. It is currently resting."
 
 def zap(polly, volts):
index 15b089d7f6bb1f9052e25c2aa0f19db8c27a2505..791e712974cfc288bdb5a9c9b65c28a3e4768b04 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
     pass
 
index c9362671c48094618167345b2f6cffcb6918e103..85a2e23465d59ceb62ecfd4b2153de7a1a5fe267 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cimport dotted_cimport_submodule.a
 import dotted_cimport_submodule.b
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fa81adaff68e06d8e915a6afa375f62f7e5a8fad 100644 (file)
@@ -0,0 +1 @@
+# empty file
index afb09f0fd5840a020a626dd67f5d9c0bb1ee318e..80c791676386a2040f9aef30996e37f7d412c54d 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef char *s
 s = r'\"HT\"'
index a745112e39d1b8e0bb6420e16dfebbabeae4c96a..d90d2163462f73f5d672ef1475a5586949cd9659 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 488
+# mode: compile
 #from ... import foo
 
 print ...
index 8cdc71de8e56c43f789abc5c987cd8585d1af109..747bd2b86236fb34140a795ea69b0d0c6ba6ba16 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f():
     try:
         pass
index 0a56a6db57e953a2f829434211bc852ed090e2bc..aee38aa69fa2934ac45baeb2cd5330fb43c22806 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum E:
     a
 
index ec99f63ba24bc8f5828ec1ef88d24a85d4cee8e5..05447b68682d54b6101b767df014e6b5a755bc0d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void foo():
     cdef int bool, int1=0, int2=0
     cdef float float1=0, float2=0
index 689abfc3b8181176f555a1a709657fdc82c6ff61..1445d671e1f2dd3fd31642c221cdb8e5d0f530b5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int blarg(int i):
     pass
 
index 1f02b7ce5501b917cb1a4dd691ae070b145974d5..01eaf052a2993c195f35f7b74f1ecf5b45e06405 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class C:
     cdef f(self):
         pass
index 1d86f3dfcf1b307ef7c03b9330cbede877d07faf..902707a5b4f2c8e25de420c3b69a3b10425dde4f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f():
     "This is a pseudo doc string."
 
index d55e314e9acd9b0ff508d98ec834273cf14ee436..aa72ffa880bfa55858c7063bd384e04cb41d7121 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef char *f():
     raise Exception
 
index c7c05069648bc09592136316d7198669284d32fc..11baeefe30eb0669c74868e5c28066359f6c4684 100644 (file)
@@ -1,3 +1,4 @@
+# mode: compile
 # Spurious gcc3.3 warnings about incompatible pointer
 # types passed to C method
 
index e3028c76866e9296c59344ef33fe2aca5c764468..2544f19c67cc269bec41a92044b15ec3dd4990ce 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class A:
     cdef void f(self, x):
         pass
index d6717bf13d48794ca1d340df54687505e7b18b8c..c7fa306b87839ebeb1b03fe1f985b14357442d11 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef class Blarg:
     pass
index e4b0365db88881f7257d756c23a6be70d5668de0..3bda53d50b21c6a82b18be6f0adfa3d331bd3c64 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef struct xmlDoc:
     int i
index 9c84eb624a6e9eadd24b29bc4e218cd36962f71a..5044d5b41968e063e019430ce9a3363ca2b0ba28 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "excvalcheck.h":
     pass
 
index fd1a446a315c251cbd1d36b1f7ea6e525e2b8623..63f3c65dc3b6edc2e97bcb764bc31affd3cf2fe7 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int spam() except 42:
     pass
 
index ee6a7db896cc309c459c15426b282956317d0bb3..235fff62778f73e99e7c94c9fe061026890325cb 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int spam() except -1:
     eggs = 42
 
index f6e070f2c5959f649a754c6639875f4c0ec19055..158e821cc0c7f83ed773b130e15b01e908429e57 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern class somewhere.Swallow:
     pass
 
index d9815e356512fb0baeaf3d066d968596d464edfe..3dc693e74b18475aa11448c6413694489bface16 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     cdef int tons
index fb2d58880ad856477e20a3054ba546a9dae5bc34..a66432608a2793a84f6fe06fc733d27fbb89fc0d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Grail:
 
     def __add__(int x, float y):
index a77f84e9d0ee27ff7898eedbcc38ddbc1ffa35f6..41bc27b9370ce3bab5c756044f7e0450dc2ad5cf 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __delattr__(self, n):
index c6104ff2d9505e0472435ef4e9c743f891e39fa5..4e4bcf7d80c4eaa60fc39841aefea0841f29224b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __delitem__(self, i):
index cfdfff607bcdc2aef1287c48cf257303b70c31e2..611a3c5e4e09b35d76f14940949c09dbb3fccfea 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __delslice__(self, Py_ssize_t i, Py_ssize_t j):
index b49516a7641b9fba9ba757b2d99c64444bf6a683..09a091245dff41f9d739af7b5abd5f82eaa62416 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Foo:
 
     def __delete__(self, i):
index b988a46f245a2519ef2ec201ddf250e3e0795dca..181dc499395479623f4fe286599920c44e8c09c7 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Foo:
 
     def __get__(self, i, c):
index 50161aac70115254a7b5ecd104ce22a24294b20c..deb59c28381efed6cab654e367054aa12e7e0ebe 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Foo:
 
     def __set__(self, i, v):
index 958e40d6edc72c181bc4f4249f1d5d877f100dd3..a3d57df1f816a8a5803f780cb8b5abf125506344 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern int i
 cdef extern char *s[]
 cdef extern void spam(char c)
index 8d63dce7504196f142fa1cbaf074c1a73a287394..1c51aada024739974320e6cf0e7674e5d92fa947 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern class external.Spam [object SpamObject]:
     pass
 
index fd571a14e63ba9a37e49b24ef2c34db56b3e4f6d..2a0346024b2fffba2fd4346a64dd15c22dad5434 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam
 
 cdef class Grail:
index c18fa92980025d53e0d8be1ef1cf21a2ec7fd9aa..9aec9582d59c87523416f5e6f9776f0bef983621 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __getattr__(self, x):
index 2f5cc7ede5ec222da71e6b77d3f4ae3c60058c94..4612f7f470047addb9321d9ace664df57272213f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __getitem__(self, x):
index 865edb70201130c237be38f0400716e982fe3615..20d9ebb2493661f3c377313e4921e1670a4cbff5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __hash__(self):
index 7d32048d66887b48a95799746fdf11649e70af78..1ef503ba43c4ad2b86579c9805ac27ff82ad534c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern class Spam.Eggs.Ham:
     pass
 
index c1fb75141947ac8e1d144ae873fe2f76183867ad..8096a5569a0f799a6f502b13a2f6a81c3597a281 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 from crunchytype cimport Crunchy
 
 cdef class Sub2(Crunchy):
index cc158543d58cb5a96c50a6a293fc39878ac6b868..a7b218ee387ab5ee4292bbf01b358a7791fb255a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __index__(self):
index c47670eafa9dc156ec902570204c651243dda1ba..ffdf23063a2f20d99a9320acd8b7845fd721f107 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Parrot:
     pass
 
index 17309f62e651a418b7c2158d5c7852a913218dc7..b15222cf26ff4254e02f64d35af92cd379244e14 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Parrot:
     pass
 
index 4cfd91609b4e5155cc47e2d0c7e704ecbc2a3dcf..4739933f36eac36d1b45353b388c3d23146ef44d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     property eggs:
index 27f943ca517c6120895a40149a57cb78ab8ecec1..e01ac0fe0d7e3c571ff61bd0aad5a6873e77fd8d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     property eggs:
index dd043e84f67513f312175cd3a72184fa20c07ad1..7082fe625f19ab39b34d210e2063e03d21b3459d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     property eggs:
index c1a93885817b2be72081749dcb3d4680ebc15554..d450b7bfb807ce77fd8868f35b8cceed2bbdccd2 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     property eggs:
index 8c6e85108197253a0405fbc2275a7421a7925bf3..69ea120f68e2124b90a787244fd73beb3e34596d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     property eggs:
index 61bf6d1b9a60eb03ce39ef23204c39f3f99fba81..fd7f68a0573cb1771278117b38787f7896052856 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
     cdef public char c
     cdef public int i
index 73f61eb986ec400fa4a0c7035408ec6aeddb7361..0dade9b2eb98cb78905312a8738ccc95e9c8c4f6 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __setattr__(self, n, x):
index 7c42627022e023e2d2e10ef6a5077143de309942..b94d8b7ba813043b1eaae6986d90aeb90357c464 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __setitem__(self, i, x):
index 51b047e5feafc1b0172ba4e03cc4cce800360bb9..1141deb3b5ddbe328da732f4372367b3e7f243ca 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
 
     def __setslice__(self, Py_ssize_t i, Py_ssize_t j, x):
index 2bd74d0240c96df666f86da00c6c8d83817c7ee9..729bbc563f59206daea7821c678da3a4ac285021 100644 (file)
@@ -1,3 +1,4 @@
+# mode: compile
 
 cimport cython
 
index ec9eab89b26dd1e92e99cea7cc9147d0f3004ed7..dbbdd4c4739217b042639808d8d317efe2150fd9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(a, b, c):
     cdef int i
     for a in b:
index 3350320d6d9b2dded9417a8b309ae48e7218c770..9da613a5603f3af165447b55d53dab210ee7bc54 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void spam():
     cdef int i, j=0, k=0
     for i from 0 <= i < 10:
index a5a41b29df6b0ea3f0332a7bb91a9105d946cee0..3dbf7d40cbd9c6f41ecf5c515e545ef809241fce 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int x
 
 x = 42
index e2a9e593ad6a989240fbf01e9a4a1bb8304409da..46f7b54420534e79275ee355d31c05ef54864180 100644 (file)
@@ -1,5 +1,15 @@
+# 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)
diff --git a/tests/compile/fromimport_star.pyx b/tests/compile/fromimport_star.pyx
new file mode 100644 (file)
index 0000000..6c19476
--- /dev/null
@@ -0,0 +1,6 @@
+# mode: compile
+
+from spam import *
+from ...spam.foo import *
+from . import *
+from ... import *
index 64fa290863e22680f9d2fa0a95add68026187b7d..5042383589752b96c438e533a9a5c6a04a05a627 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int grail():
     cdef int (*spam)()
     spam = &grail
diff --git a/tests/compile/future_imports.pyx b/tests/compile/future_imports.pyx
new file mode 100644 (file)
index 0000000..4501a88
--- /dev/null
@@ -0,0 +1,9 @@
+# mode: compile
+
+from __future__ import nested_scopes
+
+from __future__ import with_statement
+
+pass
+
+from __future__ import nested_scopes ; from __future__ import nested_scopes
index 06030cbbe3980a3b96f8bbdab8a2a2906e4a662d..a92b45a6dc89100e8cc6e345082242881bf941f7 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(x, y):
     x = y
 
index 09444b081869136f5424951928126764855eed8f..97f739a48e92f7ef149921c49886b26f3f2566ee 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 global __name__
 print __name__
 
index b0e84ee80f5cbb5f14aa1317027e3f523d5bb4d6..3a43c812e01fd060a7fda78d8ef21358d984494b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f():
     global a,b,c,d
     a = b
index 9349016a2ac036b3e5fc29c47bf3257210c4c105..3c782b390ffc181011100e2e3ae84d84694b4a1d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int a_global_int
 cdef a_global_pyobject
 
index c4c38f99ea75c00f919e3761515e94a226251571..f3a7f29a5bb64063f6585613648541020bbb473a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef enum someenum_t:
     ENUMVALUE_1
     ENUMVALUE_2
index 390fe2b16a646ffa5b176714f1f8ce1cbc8f32a1..86e2c4cf0eb625c0ad056431368f5c6f9fb2031d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class vector:
     def __div__(vector self, double factor):
         cdef object result = vector()
index 92e2d475a92dfa02993607a98acf8f3f34d8c34f..b93bd5ab1fcef423cb3d347e210b18e619d0c571 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef enum Color:
     red
     white
index 57ecfcca7dc354daafb7c1244232c78bcfe2da9f..3409e3b03577481aec830c016aceec3f6d0b0e5c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef:
 
     struct PrivFoo:
index 5b677300a7fc3e6044c9d137429a95f1ac44eeaa..47e9d4ac1be978414d4e3fd79cd942483bdb432f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f():
     import spam
     import spam.eggs
index 38cdde60dedd885ef444684aa8aeb716f7aa2678..179b70944c8966d6058fa5de5edb24d9dc9af893 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(obj1, obj2, obj3):
     cdef int int1, int2=0, int3=0
     cdef float flt1, *ptr1=NULL
index 6daab50da2e57adb6590d400d857a1757c026115..64c28bd7b37ca6d71381fa4ab6ddae54c352637c 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef int* a
 cdef object x
 
index 4cf478c9fae9811e79355142df8682a6e5ab474d..80a55da055cc8007e602dde9b5880a59dd3a8981 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class A:
 
     def __getitem__(self, x):
index c6bd0df9997023d08e36669bb74a4f9380c164c8..4c1ff841aace2b9d6aaf7691c947203f157ad066 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void __stdcall f():
     pass
 
index e550ba73f7236fdee8f3296f0f4ac05b699566c8..ca131da27afa2adafee9bac070445bd0a57fd0dd 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Position
 cdef class Point(Position)
 cdef class Vector(Point)
index 46fcf7768e4e26920396bda52a6228cd8ba5e398..0ad9462a227b73ce060ce9719d97469602dc6801 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef class A:
   cdef object x
index 9a4063f33867aff24b7875f63cdfd8fe287896f9..a3a7beb66c534a835aa00689658b74cfbc68aed4 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f():
     cdef int i=0
     global mylist
index 5470fa074f2e9343b83799e1578337410cfcc63a..efa52a70deda292bda7195d3866a826a04e818ea 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "string.h":
     void memcpy(void* des, void* src, int size)
 
index 4b08d22adf20f777a8a13b0b25c602f01d7eb3b7..122268b469ea7788cca570dd6eaee047a3f606d9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 ctypedef enum foo:
     FOO
 
index a767afbb5c57a4368a6b14bb0c70a6a66c1d84d7..6297138f3f38ce5497cca6e8263b8f31cf4336ec 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class C:
 
     cdef object foo
index dce5edbba86860f32ad2419cdd193d4ef327f513..32d89f94baa58720a309aad0411c28ec102498b3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class T:
     cdef int a[1]
 
index eb8aa28ed0c8e988bc40c4a67d9839bfc9a90204..81051523a353ff211e1c705c0a8237de409c1c1f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(x,):
     pass
 
index 79fda814911412979a0f8b97afd0fbe5698a28af..9cb35f477640b72a472b09e8f939fbc62583b55a 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 ctypedef struct BB:
     void (*f) (void* state)
index be428a40fc9cd97d9e6f858ad2234cdae818467f..cfe765cebf5780a060df8fdd20f9ec75309a9dce 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cimport libc
 
 cimport libc.stdio
index 07d4df97ccca5ad8d76087611001936bdec11213..66631647ac3f2a17d2681c037b403d67034c8d6b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 from libc.errno  cimport *
 
 if errno == EDOM   : pass
index 08e59907a0d2b9c97f3cc5ae0a8df09d8f1ed023..ff5632f35c8763e09f39a252d2999723a5063336 100644 (file)
@@ -1,3 +1,5 @@
+# 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,
index 4e162c19d9d806ff8add7c66ba867e7bd5f40549..ee8921fc05009e76794dffe3c15d81c217f56dcc 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 from libc.signal cimport *
 
 cdef void sighdl(int signum) nogil:
index 17e9ee242672473bfdd8a66a1c5f6f1d7fc86b8c..8d696d1c947c1cc5f6d07babcfbbec3af7bff898 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef extern unsigned long x
 cdef extern long unsigned y
index 8f81edc2231e0dfdb024e04127c36a21e227ffdd..665f09371718314f0105dd3a656d217ef33159dc 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void foo():
     cdef int bool, int1=0, int2=0
     bool = int1 < int2
index 5887ff310e986edbcb01a9f5aa323afcf9559bad..f3079c380181a14d01354dce2a6fa62a8567d962 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 """A long module docstring.\r
 \r
 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer sit amet\r
index 213ae60e22138a8c1f8015a7d006a2202d84bbf1..0da960478c434ade2df523f56b3ce5d810e0fa7b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern object g(object x) nogil
 cdef extern void g2(object x) nogil
 
index abbbe4d26f020b4029f54e9d023aac58be2fd8ba..514b7e310f84788e02234a3dc0c6d956e14c838b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class spam:
     pass
 
index 2d51c5caf63ebe6154e05b9e612b6324dd789afb..b83bc75b33d2ad0d9735cd58cba4489490a31bdf 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void spam():
     eggs = None
 
index 711cf9e0558ee0ec9e5dae5a1c53046f1e4ba35b..c974a2340afa062c47a3b3f4b60349222cddf023 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern class external.Spam [object Spam]: pass
 cdef extern class external.Eggs [object Eggs]: pass
 
index fe4b96b26f9029932436d94d0a9569c2c705d1f4..35b42d83b657d54996041d1c0f9074577715b1fb 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef char *p1
 cdef int *p2
 cdef int x
index 85fe92a1a3492beca9710e86dddc7deabfdcb1b6..3c7fa99bb13100e6315831e662ecaf4e9cf6222c 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef extern void spam(int, char *)
 
index dfdd3179fb0a22d202e678a5f059a9dd8141adc1..8f321839da2c436adecea4f8e8fbbf592eabfd2f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 __doc__ = u"""
     >>> fiches_CP
     []
index 4a6995f60a946e279f3c18e22cac8268820a5498..03d6bd150908ae1abd1f9a70cf5b7ea7468c419a 100644 (file)
@@ -1,3 +1,6 @@
+# tag: posix
+# mode: compile
+
 cimport posix
 
 cimport posix.unistd
diff --git a/tests/compile/publicapi_api.pyx b/tests/compile/publicapi_api.pyx
new file mode 100644 (file)
index 0000000..ddf520d
--- /dev/null
@@ -0,0 +1,66 @@
+# 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)
+
+# --
diff --git a/tests/compile/publicapi_mix.pyx b/tests/compile/publicapi_mix.pyx
new file mode 100644 (file)
index 0000000..8936dc8
--- /dev/null
@@ -0,0 +1,78 @@
+# 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
+
+# --
diff --git a/tests/compile/publicapi_pub.pyx b/tests/compile/publicapi_pub.pyx
new file mode 100644 (file)
index 0000000..ee93841
--- /dev/null
@@ -0,0 +1,66 @@
+# 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)
+
+# --
diff --git a/tests/compile/publicapi_pxd_mix.pxd b/tests/compile/publicapi_pxd_mix.pxd
new file mode 100644 (file)
index 0000000..1810c10
--- /dev/null
@@ -0,0 +1,68 @@
+# --
+
+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
+
+# --
diff --git a/tests/compile/publicapi_pxd_mix.pyx b/tests/compile/publicapi_pxd_mix.pyx
new file mode 100644 (file)
index 0000000..d3881d1
--- /dev/null
@@ -0,0 +1,17 @@
+# 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
index b0f1bfe46048011cfd3d1d090d9e6376aa75a9fe..463f81cfa5bec9f1daaf2a2eda22ef1e51a37d50 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 class A:
     def foo(self):
         return "A"
index c7974d2ae0494d7310f5730a85ca6c7c3dda4ccc..26b755709647c8022cbbcc0aa640d8bc346de16b 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 class Spam:
 
     def eggs(self):
index a6c537c41543d3d4b6034a3447ef3016303a7b74..f4938fab9f81aa4857651f51d803709150a5eec8 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef extern from "Python.h":
     ctypedef struct PyTypeObject:
         pass
index 6425c3c7a5b026641e097d4f69b333a611b3b07f..5548d60b19c0626e721327786c9ab971bd914187 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 __doc__ = u"""
 >>> main()
 3.14159265358979323846
index 6ca99969d035076abe554a84bc3a9053ea262987..d897ac3d9f528d6d6239addfaabb77928e8f1ecd 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef struct S:
     char c
     unsigned char uc
index b18620b2fd27a40574564b3ccde84d418e2ed890..045d612fa611cd8af86f3f041edc253e9e9a4e96 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 def f(a, b, c, d, e, f, g, h, i):
     a = b[c:d, e:f:g, ..., h, :i:]
index 1575e1f321e5ae88a6b561d7a1b0f2918f031b9d..6ed5b9efcfd85314b93ba81860cba5531373c1b7 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 DEF nan = float('nan')
 DEF inf = float('inf')
 DEF minf = -float('inf')
index fa0c5cf516b562f47de26891d3c8cb979ce5fc91..468ee8373cd714b90e85e400d6b961e165fd38b0 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Grail:
 
     def __cinit__(self, spam = None):
index b28875a8fef134c673e3204beb928cb98b97f9e8..cacff950cc227e425ea3bde32fa6ce03be153332 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class C:
     def __cinit__(self):
         "This is an unusable docstring."
index ab1f7e9143c0ff2f68efbb246facea39dfc1f1bd..3105e21371e9289f93bd68557006c32b94394314 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef class Spam:
     cdef int eggs
 
index 9edfc72d65eb2159eadfdab55617be956eb7921d..04cecaf4d7d69637d5d41c3c1f38a644d88b3d8e 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def spam():
     raise Exception
 
index fcfe83cecf15c108439f5670d62c5666ac3d19f6..85788bf4a0eb2664641b986b0e3816fe9da611b4 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(a, b, c, x):
     cdef int i
     a = b + c
index 4528607a3b2ca94ae738a7bc01fd3eb9f5d8c39f..c6f4e2ed435b82213a22c2044989dfa84058fb38 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(a, b, c, x):
     cdef int i
     a = b + c
index f56a9be8727322368440c5eab55633946946def5..a72cf3ce1a461f9f6ad088993895eeee316f74ed 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f(obj):
     cdef size_t i=0
     cdef char *p
index e24bb0f197557b9c515a573279769721b6fafc13..8ded94e4d441023348cdf6a2ab69597a2261c7cd 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 print sizeof(point*)
 
 cdef foo(int i0, int i, list L0, list L, point p0, point p, point* ps):
index f1f14d88e7f718c0a6f10f0c8f4ad483e5996701..a14e8c2780a11043831c70cc5d847c5fc312b777 100644 (file)
@@ -1,2 +1,4 @@
+# mode: compile
+
 cdef int x
 x = 0xFFFFFFFF
index 2100761826f334eabeaf7b14ffd8beeb4402edec..d56f67303913f11680b9d96a3131eae834899ca0 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 276
+# mode: compile
+
 __doc__ = u"""
 """
 
index 439cb3d2c2e5d1e7269205a42ff76b9bf121a182..2ca65742eb18e5cc87991d5165cf64cebbc060c5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 def f(a, b):
     cdef int i = 5
 
index fa77d6ed1b6c4aa7acdbb429e033f997d0d4c2c6..19bf69f6e9833a378ca054aa95a2bd2120d75e6d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: compile
+
 cdef void f() with gil:
     x = 42
 
index c28144231657822f1ad0bb6310b3db3558fbe0a2..f20b4d335312c0b54d49e322d98cebd3b86ded87 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 break
 
@@ -26,11 +27,11 @@ def bool_result():
 
 
 _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
 '''
index 21878a4f86a1bc9fed1f0eca7b6b1177138cce95..927ea23bd6584718e5c664d0726ac1151aa22daa 100644 (file)
@@ -1,5 +1,8 @@
+# ticket: 117
+# mode: error
+
 ctypedef object[float] mybuffer
 
 _ERRORS = u"""
-1:23: Syntax error in ctypedef statement
+4:23: Syntax error in ctypedef statement
 """
index 79ff24a53fadbe2b9ee88bde98f085a64fee759b..c7c02222dc155d2b1b8275fed8b3d639040e03bc 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 # current restriction: cannot inherit from PyVarObject (see ticket #152)
 
@@ -11,7 +12,7 @@ cdef class MyStr(str): # only in Py2, but can't know that during compilation
     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
 """
index e9c1b36990c1aa730e56d7055412add9a75388dd..73db3a9776653566a1cac8512f5bdd28a15cb3b2 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def f(*args, **kwargs):
     pass
 
@@ -16,5 +18,5 @@ def test():
 # 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
 """
index b66f64641111510b066193bf308d6297ec6fcc78..b699326ec94bd6189e897e334eabfa3621c9dc15 100644 (file)
@@ -1,5 +1,8 @@
+# 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
 """
index ee95a4081ef7a73f1cc1b7cb7b18e21d19536403..0b7dfe38087916f527baaad5a665ce221b698c8c 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 517
+# mode: error
+
 ctypedef void* VoidP
 
 cdef class Spam:
@@ -15,12 +18,12 @@ cdef class Bar:
     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'
 """
 
index 0af661015cb0300aa4be8175a585401009796f30..af2d0d70c6f83e03a828cb4fc5fc9b583271cd56 100644 (file)
@@ -1,10 +1,11 @@
+# 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'
 """
index d0d3385c7844fbef8e4b7bd3d19b6184677603b5..a4477e2daf09313eb7cb1b5025413e5aea35530d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 __doc__ = u"""
     >>> call2()
     >>> call3()
index 858c7fd920aac4b28fffb4aa3786ab6430a95b4c..ad807c8d0dd5014c39d2c5405089ffea25efd2ba 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def call5():
     b(1,2,3,4,5)
 
@@ -5,5 +7,5 @@ cdef b(a, b, c=1, d=2):
     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)
 """
index 53a484eaa01f2d2f2329e00f767807f4462b2f93..0998856aaf36a266fd9a29d76f7325b2277de259 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 cdef class Test:
     cdef __cinit__(self):
@@ -7,6 +8,6 @@ cdef class Test:
         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'
 """
index b0b1222e3bb6d65e6ef2f5451c027c63def8ea19..9e309f16f47e966559aeff969dd675c270943165 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef class C:
     cdef void f(self):
         pass
@@ -7,6 +9,6 @@ cdef class D(C):
         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
 """
index 6a6c903d733f165812a8a544ac42410c28802e29..963f280fbc1dd7c505248aa0cd72a265608afb44 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 370
+# mode: error
 
 cdef int raiseit():
     raise IndexError
index f8309158bd64ef67b8b1f320a8f0b87f90cf9d07..8942bbfec84d0f5d8e1341d9015709189372729f 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 continue
 
@@ -25,11 +26,11 @@ def bool_result():
     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
 '''
index 654a1fe09db92b8fb3d51f725f21d40e74be7907..7c60881359a0436cfe865f0a4651f5c1b48b29c4 100644 (file)
@@ -1,9 +1,10 @@
+# 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'
 """
index de752478187db6d9a5104ceb602ea53f642e830d..9bb016d6582832d3d1157187ccb6df9a9b4fceac 100644 (file)
@@ -1,3 +1,6 @@
+# tag: cpp
+# mode: error
+
 cdef extern from *:
     cdef cppclass Foo:
         Foo()
@@ -6,5 +9,5 @@ cdef extern from *:
 new Foo(1, 2)
 
 _ERRORS = u"""
-6:7: no suitable method found
+9:7: no suitable method found
 """
index a8ad4f66e2c6185037b6e50223dfeb9d33951ada..7d0c84a00bbb584647b56b457737947bff8a51b5 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # -*- coding: utf-8 -*-
 # cython: language_level=3
 
@@ -5,5 +6,5 @@ escaped = b'abc\xc3\xbc\xc3\xb6\xc3\xa4'
 invalid = b'abcüöä'
 
 _ERRORS = """
-5:10: bytes can only contain ASCII literal characters.
+6:10: bytes can only contain ASCII literal characters.
 """
index de75ce629782c7fed96265500039ee82f3170a40..bfcd6ca974fe4ce126738138968e08a5f91b2a76 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 158
+# mode: error
+
 def mult_decl_test():
     print "%s" % vv
     print "%s" % s
@@ -51,24 +54,24 @@ cdef unsigned long long var[100][100]
 
 # 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
 """
index 85cf3c73b4490480ef11d3ce76f2b6f0827074da..16a94cbf92f5abe02e8d861aa89037a633839ad1 100644 (file)
@@ -1,7 +1,8 @@
+# mode: error
 
 def test() nogil:
     pass
 
 _ERRORS = """
-2:0: Python function cannot be declared nogil
+3:0: Python function cannot be declared nogil
 """
index d5628772c209054d756546217a4df5dfdb8c1869..1a0f40f186248636cdf8b4fdf5a3d0a6a0582124 100644 (file)
@@ -1,6 +1,9 @@
+# ticket: 290
+# mode: error
+
 cdef packed foo:
     pass
 
 _ERRORS = u"""
-1:12: Expected 'struct', found 'foo'
+4:12: Expected 'struct', found 'foo'
 """
index 2edae5928c2574437071da0094cba5536b7d2220..650591565cf19f230460d5e0a61d0ee2c13a7194 100644 (file)
@@ -1,8 +1,10 @@
+# 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 *)
 """
index 70c472dd6be9bd9b03c36696605f8ed965d18677..d8828741f5042a280c15d01c898cf79aa17a1dc7 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef spam(int i, char *s = "blarg", float f): # can't have default value
        pass
 
@@ -10,8 +12,8 @@ cdef class Grail:
                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
 """
index 0d1a0a4a49b9554e4f78ab55646f1ce63d487aa8..1665971fa80fef131dd4a8693ef7a6ab46a90fa5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef void foo(obj):
        cdef int i1
        cdef char *p1
@@ -8,7 +10,7 @@ cdef void foo(obj):
        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
 """
index 83015cea02873d97e34491a9d75313416accb8eb..b8e9ba761d0a8db9713dc9aaf106f0029cb3a90c 100644 (file)
@@ -1,5 +1,7 @@
+# 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
 """
index 17f123624a2b7f4b22f2aa915a75b063472e3b67..a5d56f3d262891f971333276e9d6e03fc7847f67 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cimport cython
 
 @cython.autotestdict(False)
@@ -5,5 +7,5 @@ def foo():
     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
 """
index b14a7ec5d50fb55ed6892bbbc14e4daf58f6b001..ff2cb1f7be594f988eaedaeee9e7a335ca2c6cee 100644 (file)
@@ -1,7 +1,9 @@
+# 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
 """
index 5e23d3030d00dbea9469159646c68b45dcb6c8f3..cece614b724388e57c9987da9f9226fb14bab889 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct Spam
 
 cdef extern int spam(void)           # function argument cannot be void
@@ -6,7 +8,7 @@ cdef int tomato(Spam s):             # incomplete type
        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
 """
index 38b4b2bc499ad9c4dacf616d8b548b55b549e32a..576acd799bf43182ebc77fb9c1361ff48e161659 100644 (file)
@@ -1,7 +1,9 @@
+# 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 *'
 """
index 70c4166fd698baead97d69f96fe842cd4f8f7c1f..23cebd0b85584503714a79b2e6c7907dd7af9685 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct Grail
 
 cdef extern object xobj # Python object cannot be extern
@@ -24,19 +26,19 @@ cdef NoSuchType* ptr
 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
 """
index 1547c8b577587861c3868488fb98adb6da267000..0ced9edbb09566126bea494a493b50cf8f0052cb 100644 (file)
@@ -1,7 +1,9 @@
+# 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 *)
 """
index 2be2d0a790bac1bd830de0ccadad01656be04ee3..36a9b229d74c4df473c5da9f4fdb3409578147cb 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 ctypedef struct struct_type_not_boolean:
     int i
     float f
@@ -28,15 +30,15 @@ if union_not_boolean:
 
 
 _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
 """
index f93d1107decdb6f37c659cabd20c20a4c5cbafb6..bc5b9c0f324964a95edb7422a0e572ee065c3831 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef object[int] buf
 cdef class A:
     cdef object[int] buf
@@ -13,9 +15,9 @@ def f():
     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
index 24fc68a329c33796c03201e8b09a3bfef7b29628..943ac5a28623c6ed41246974d172736f2bbba015 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cimport e_bufaccess_pxd # was needed to provoke a bug involving ErrorType
 import cython
 
@@ -27,9 +29,9 @@ def withnogil_acquire(x):
         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
 """
index 0f4c19efa28b0efba68b188cedf74812d23537b5..8dab29a0c4b7528c376cad27de21b4cd45f776f2 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef int i
 i()
 
@@ -14,7 +16,7 @@ cdef int x():
 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'
 """
index b4cd0409ecf5d38d03372a56c522f81f2814e44a..cd02e6c8adb1d64d21ae426690540cad7aedc2cb 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cimport cython
 
 @cython.callspec("")
@@ -37,8 +39,8 @@ p4 = h4
 #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)'
index e8289aaaa1e7663e88b3e47686e671b8d3d96339..3b1355eefff0dbefee419a9dd0bd7dcab76e6a03 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 241
+# mode: error
+
 cdef some_function(x, y):
     pass
 
@@ -14,6 +17,6 @@ a.some_method(1, 2)
 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.
 """
index 0b303fbef2a1d18da870f54276565265d98579f5..97e9fde41352b42789c9fd54773bb59c6460f37c 100644 (file)
@@ -1,7 +1,9 @@
+# mode: error
+
 cdef int
 
 cdef extern from *:
        void f(int)
 _ERRORS = u"""
-1:8: Empty declarator
+3:8: Empty declarator
 """
index f4a38fda3f84734c63be555b114cffff5e0e72b4..853359635f729639ad46dc00b22f34036ffad240 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef class A:
     cdef int value = 3
 
@@ -6,6 +8,6 @@ cdef extern from *:
         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
 """
index d71a8ab3cfc9efd82ad2302730eedae20472e7a5..f71370f4a1e41c54ca3a374375ba380e69d430c3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct spam:
        pass
 
@@ -7,7 +9,7 @@ ctypedef union eggs:
 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
 """
index 70656e105cf0c103323f39c8b8d352884fb506a1..05df9612397bc8a1aeef6ae8d0805f6cb40a9f2f 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef enum Spam:
        a, b, c
 
@@ -6,5 +8,5 @@ cdef void f():
        a = 42      # assignment to non-lvalue
 
 _ERRORS = u"""
-6:3: Assignment to non-lvalue 'a'
+8:3: Assignment to non-lvalue 'a'
 """
index b434c82a3d35d610d31f6ecd9beeea5fa996867a..45651f90644fbc4f2139791d7059bf5c1145bedf 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef class C:
        cdef void f(self):
                pass
@@ -6,6 +8,6 @@ cdef class D(C):
        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
 """
index 2ec33a58f790b2b9822f9af96790f398d7edb5f1..2b6e5e64845dede2b17d0d6a4df4429159c4f3d0 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef void foo():
        cdef int bool, int1
        cdef char *ptr2
@@ -12,7 +14,7 @@ cdef void foo():
        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 *)
 """
index 3f7e9a6e207a6a9b8e328088e29ddb5b4a0343fa..3d4ce9b143c5fd79afaed6cfff5f5ad5b789456e 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct Spam:
        int i
        char c
@@ -22,10 +24,10 @@ cdef void eggs(Spam s):
 
 
 _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'
 """
index f2358fd585f2e2443e4567c4798a3a6f6eb45fca..2b992c097967dc57be98cf0d3f398e5cc8a6cddf 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 ctypedef struct Spam
 
 cdef extern from *:
@@ -8,5 +10,5 @@ ctypedef struct Spam:
 
 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'
 """
index 632ba780dc5211020fa5ec5b82362543260e16b0..67563099fe052e0d4af7ced07b966864364f624a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct Foo
 
 ctypedef struct Foo:
@@ -12,6 +14,6 @@ cdef Foo f
 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'
 """
index 388978d177b82e45da606bc49b2ff79bd5ae6162..732fea293532d36e3dfd100821eba9c572511e37 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef extern void fa[5]()
 cdef extern int af()[5]
 cdef extern int ff()()
@@ -10,8 +12,8 @@ cdef void f():
 
 
 _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
 """
index 85d83c6e61f101b94147b16d1e379f86a199e88c..5abc1fc2958f9612af3e4d3c4a28728689d10a7f 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 _ERRORS = u"""
 4:4 Expected a newline after decorator
index 172bae73a6abbd6634efe5313925d2743ff216cf..63116b407298b4396c7252c1f23b8a64832c76b9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef struct S:
        int m
 
@@ -11,8 +13,8 @@ def f(a):
        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
 """
index f7f777acbb30e0bad73e2269f20d6f3fc3bd6686..a8e57427d43a18a83acd3a4be332d98eccf87ee8 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 # cython: nonexistant = True
 # cython: boundscheck = true
@@ -9,6 +10,6 @@ print 3
 # 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'
 """
index 0d997f866be1a994f2c9ff9ad499de396f60d858..3dcb37c024adaaf616fb20e3b2e064f824b4cb65 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 try:
     raise KeyError
@@ -11,6 +12,6 @@ except AttributeError:
     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
 """
index 44b8c050266520ee817cf94f322d37ade121774d..9ab2e802aad56ed60c3f774045962f6fb095bc4d 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 ctypedef int (*spamfunc)(int, char *) except 42
 ctypedef int (*grailfunc)(int, char *)
 
@@ -7,6 +9,6 @@ cdef spamfunc spam
 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'
 """
index 4b68996960ae0288827bff06b987ba052856fedf..fc5f343481dcf9bc05ecffbf902a9f1191fe2ad5 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef class C:
        cdef object __weakref__
 
@@ -13,12 +15,12 @@ cdef void f():
        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__
 """
index e8a158c393ce726a7d25feea20f9ffba168432a2..dd7ca017d4ee5b029f2076338ba084784683f22a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cimport e_func_in_pxd_support
 
 _ERRORS = u"""
diff --git a/tests/errors/e_generators.pyx b/tests/errors/e_generators.pyx
new file mode 100644 (file)
index 0000000..d13da55
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
+"""
index 726d78567872b4da5ac2dda3ee4b9b2743312b9f..e32e1a1399ac077ed892291da97e9b272e5c1344 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def f(obj1, obj2):
        cdef int int1, int2, int3
        cdef float flt1, *ptr1
@@ -7,8 +9,8 @@ def f(obj1, obj2):
        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
 """
index 692d232b432f7e1a11f45378a86e7ca00396d923..9eef366733cd98ec1347dcf4908e1ba83292e948 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # cython: language_level=2
 
 def int_literals():
@@ -9,7 +10,7 @@ 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
 """
index ead9dfdb018ac4f07d066a8c35f39c3e88073f0c..351fcd065b6966d8c26eebd8b7aa08da585040dd 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # cython: language_level=3
 
 def int_literals():
@@ -9,9 +10,9 @@ 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
 """
index 68a552f89e11468520a14df758377547ffb7e518..2005d5b08df6e20aa983737b963a8ea44a773cb5 100644 (file)
@@ -1,7 +1,9 @@
+# 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'
 """
index 81ba78fbacc19a1b255ee1a7048297df6ea419fc..7cc2a95a145abc0cb6550bf28ab1ecb5a7d0793a 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef extern grail(char *s, int i)
 cdef extern spam(char *s, int i,...)
 
@@ -8,9 +10,9 @@ cdef f():
        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)
 """
index ec596524dd26cbb2329d65ac76b4f3d06753f2b7..02ab59b4b8a1f4835cf2f54eefd80cab02477d3f 100644 (file)
@@ -1,8 +1,10 @@
+# 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
 """
index f45b4d4a7b793d4d0d296d5a0c5960ccb818d4b4..4ec06c1a2123979fed3694b20145c99b521a4caf 100644 (file)
@@ -1,8 +1,10 @@
+# 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'
 """
diff --git a/tests/errors/e_nonlocal_T490.pyx b/tests/errors/e_nonlocal_T490.pyx
new file mode 100644 (file)
index 0000000..55d7e3a
--- /dev/null
@@ -0,0 +1,36 @@
+# 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
+"""
index 1931f46759416b72eb2a60046c35e8bb5a14e8c2..a755e25c71f015c9b614877ff654973092de3527 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef signed   float       e
 cdef unsigned float       f
 cdef signed   double      g
@@ -7,10 +9,10 @@ cdef unsigned long double j
 
 
 _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
 """
index de6c294a3d055bd7b6f56dea3ea27d1a3748424b..25679762e7e7d5ac13751b38e7feb96f89a94e70 100644 (file)
@@ -1,7 +1,9 @@
+# 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
 """
index 8e2fe3ec449a415c9b17ee039328f01baf6d268f..dd4f85d0baf0b17bd08d8015cea2a60076d39fdd 100644 (file)
@@ -1,6 +1,8 @@
+# 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'
 """
index 60831cf7e36974c4e16ca9fd8b6ba8f91bac1cb4..cada3c86b4bdc9c9fc1e07d2a339b01c9d570154 100644 (file)
@@ -1,7 +1,9 @@
+# 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 *)
 """
index 408246c83f6160a61130106fc20cb2e8400a62de..cf2df11fd54e0aa496ab882133a0a5001628fab9 100644 (file)
@@ -1,7 +1,10 @@
+# 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'
 """
index 85ef57bebbc8a5747af762af348d5b3b5972e1c5..bfef061b03b632155b4f8ec81c5a10f2b85774e4 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def f():
        cdef char *str1
        cdef float flt1, flt2, flt3
@@ -5,6 +7,6 @@ def f():
        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 *)
 """
index bf110223f9dd590d9e4e28d78220118156a1dcc3..a1e40287be90d72868c373ae7beefdb29393d020 100644 (file)
@@ -1,7 +1,9 @@
+# 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'
 """
index a77ddf4ab597533776367252b5c8f323e120aed8..c5342f16ac76dd4b0c93c4032e5d40c6532216b0 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef object x
 
 cdef struct spam:
@@ -7,5 +9,5 @@ def f():
        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
 """
index e06f76ad891ab49d0094ec5a44fa4fb2dfc745d1..21ecb8b4c820f388a7f30a877b55f04efcd61271 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef void g():
        cdef int i
        return i # error
@@ -7,7 +9,7 @@ cdef int h():
        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'
 """
index 3fc08583aeb3c619e8c71417d69b4ff6642f5b71..56e5582bcb6db7060558af3fd78bfe038eb897dc 100644 (file)
@@ -1,6 +1,8 @@
+# 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'
 """
index 6deda6fb29553b1a0471a5e1548026a9d4d977b9..4a14ba5a3ad6029761e5e6ffc3d184130813a497 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def f(obj2):
     cdef int *ptr1
     obj1 = obj2[ptr1::] # error
@@ -15,10 +17,10 @@ for a in int_ptr[2:2:a]:
     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
 """
index fa491044c6e72c1c03d133e09fd590177c6d3ff9..515657ea11842f8a37518c75045c21854e195afa 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef int c1 = "t"     # works
 cdef int c2 = "te"    # fails
 cdef int cx = "test"  # fails
@@ -10,8 +12,8 @@ cdef int u3 = u"\xFF"          # 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.
 """
index 90dfa72bc1c5dfe3f425b45835724c86f41a6ed5..6594d02e64ba0c1228b51cded790c67e9603b4fb 100644 (file)
@@ -1,9 +1,11 @@
+# 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 *'
 """
index f75d17829c523657f26cd080e5e85f88f0aeb649..ff67d4018252e95d7fb0cade2bdc64f91bd5da9e 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef int x = 3
 
 if x == NONEXISTING:
@@ -8,5 +10,5 @@ elif x == 4:
     print 34
 
 _ERRORS = u"""
-3:19: undeclared name not builtin: NONEXISTING
+5:19: undeclared name not builtin: NONEXISTING
 """
index d334f16d74535d99fe5653bafb144bb762d95176..ff89915e2e8d0e3c0330cf4f83d3988bdbc24eb3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef object blarg
 
 def foo(obj):
@@ -6,5 +8,5 @@ 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
 """
index 23b7903a999dbef9b2e18c4afd6de9713be513bd..3a68f8b3cc94668847d4cbb84339a4e934055264 100644 (file)
@@ -1,6 +1,8 @@
+# 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
 """
index 994f1f36e61d0f239dff9bdc13cc02b5bf76961e..302a3e737c6dcd146a6c8ad54286c511d4e1c234 100644 (file)
@@ -1,9 +1,11 @@
+# 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 *)
 """
index 5a5d5c19fb5672bcf92c9d879b25164d319d8c90..95d2c491f96403228b192c848a450185c149b4e0 100644 (file)
@@ -1,8 +1,10 @@
+# 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
 """
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4260cdc746c8acf56206b5e39ed8f398810bc7bf 100644 (file)
@@ -0,0 +1 @@
+# mode: error
index 39fcdf611e72b83a401bd106e175dca13b4ae84a..2866edc40fa919325c4eb2ca9665b2698a394a40 100644 (file)
@@ -1,9 +1,10 @@
 # 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))
 """
index bc6cc93e6c19e037e0803636e2708fddb9672d98..29182cad7005fd39a65ff21e17cfbc2dd2286010 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 __doc__ = u"""
 >>> e = ExtClass()
 >>> e.get()
@@ -13,5 +15,5 @@ cdef class ExtClass:
     _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
 """
index bdcb69df43294be47c652a43cf0281de06d1a35c..eeae75670786fa7c42d485d62fb3fd2b35b8397e 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 # invalid syntax (not handled by the parser)
 
@@ -32,19 +33,19 @@ def types(l):
 
 _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
 """
index 874985a98b36dabdc6d322d1615f8fda6830fc20..e362510bc749545e42c1d596febe97376cdeeef0 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 # wrong size RHS (as handled by the parser)
 
@@ -22,11 +23,11 @@ def length_recursive():
 
 
 _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
 """
index 627709312205312254aa322f83b406a140dc5eb1..13bdc884826335203742e059aefb78dfd4477cff 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 # invalid syntax (as handled by the parser)
 
@@ -6,6 +7,6 @@ def syntax():
 
 
 _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
 """
index 850036bb011c03bd0274abcafb0abec417cfa7eb..c5cb4d63f1e6f27ea5302fed75ef9574e7822a1d 100644 (file)
@@ -1,5 +1,7 @@
+# mode: error
+
 from __future__ import braces
 
 _ERRORS = u"""
-1:23: not a chance
+3:23: not a chance
 """
index 3bce8b0273b9fea7be784c6de6ef3df8c013641e..256b96c2727f47fbe240c1c743a82995c799e5d8 100644 (file)
@@ -1,6 +1,8 @@
+# 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
 """
index ea5fb9255b1dbf255356a5674783d0816060ce9e..7b3a48f89fc347c8ea789f342c30bba423ebef64 100644 (file)
@@ -1,6 +1,7 @@
+# mode: error
 
 '\x'
 
 _ERRORS = '''
-2:1: Invalid hex escape '\x'
+3:1: Invalid hex escape '\x'
 '''
index 3e47eff8067c0ae6cbcb2c75a96f48a55ab21f7e..6fe93e137e4f67d118cecef55acb6b8e81780af7 100644 (file)
@@ -1,6 +1,7 @@
+# mode: error
 
 '\x1'
 
 _ERRORS = '''
-2:1: Invalid hex escape '\x'
+3:1: Invalid hex escape '\x'
 '''
index a203665944393f5c6733e34953bd0cff9c142779..bc2487a55ad9a2d967b72e4f97b83f6ed6bf50a8 100644 (file)
@@ -1,6 +1,7 @@
+# mode: error
 
 u'\uXYZ'
 
 _ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
 '''
index 93d87ae016d56f76e8002a2aefbc277bfafc85b4..685f405e18f6d8f424b0b0dbc76b654f30aa28f1 100644 (file)
@@ -1,6 +1,7 @@
+# mode: error
 
 u'\u'
 
 _ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
 '''
index e98e0ce9b825e7865ea2e58d2cf1a120d5e848a8..9a22eb1e26d74bc53610896fdf8e2ca898a2266a 100644 (file)
@@ -1,6 +1,7 @@
+# mode: error
 
 u'\u12'
 
 _ERRORS = '''
-2:2: Invalid unicode escape '\u'
+3:2: Invalid unicode escape '\u'
 '''
index 7c49f961fc238e8184ecb7244a273f91f90aa808..2b445c6ec53d0f158cacb6c3168eff881f5c9a28 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 def f():
     cdef int* p
     if false():
@@ -7,5 +9,5 @@ def 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
 """
index 23e07048c8f2b5707596f88df6206c17817766bb..ece07b15546405436887547cc6cc0c68fd3b22b3 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 262
+# mode: error
+
 cdef class Album
 
 cdef class SessionStruct:
index 7f060e49a7562cb52189e8982992d5d689d57801..21241a2210f986afda2206ff392fbf8fb39158fb 100644 (file)
@@ -1,8 +1,10 @@
+# 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
 """
index 3b66bc72d123bdcc5a0357d870e85f57525ba096..6a95922d53232982c9d07baa1316babaaf553310 100644 (file)
@@ -1,8 +1,10 @@
+# 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)
 """
index 623d1ff405b6884997496cbab1be33ba99d00d40..512e1b67d164ca589dea13b15058516c3fd02877 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef object f(object x) nogil:
     pass
 
@@ -90,71 +92,71 @@ def bare_pyvar_name(object x):
 # 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
 """
index c7b3ce382595532bb995bf1561a236d692c99f4f..c2c2cc3c9538e1a11c29b2dc81eb60db39365239 100644 (file)
@@ -1,8 +1,10 @@
+# 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
 """
index 9b5580f09f70e458386af2306d8d6888b6be5fa4..9baec0c18cedfd089f2b9c3c64cc9f459ccb8020 100644 (file)
@@ -1,3 +1,5 @@
+# mode: error
+
 cdef extern from *:
     cdef void f()
     cdef void (*fp)() nogil
@@ -10,5 +12,5 @@ gp = g
 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'
 """
index 5432738a527b64b93c15161a98b8554b61189e2f..4b7c101f1a59af7d48e8d2e313de1a3285b3ee39 100644 (file)
@@ -1,7 +1,9 @@
+# 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'
 """
index c2dbd0e0d1d59a78f5d0cc34a6dd3642e054ea06..980d66555bfa250dfe667525f77899ed8ff83aef 100644 (file)
@@ -1,7 +1,10 @@
+# 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
 """
index 7114bf8f6d7d886d16b528f704dcd07222e4ae8c..0c968f701fdd28a1ff509e6043379077bb66a135 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 286
+# mode: error
+
 cdef class A:
     pass
 
index 639b33249f737141723c47013b5fb483981478b2..d9ed8255d2861a216215f4d0b17145c8ba82a9e1 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # -*- coding: iso-8859-1 -*-
 
 cdef Py_UCS4 char_ASCII = u'A'
@@ -17,8 +18,8 @@ def char_too_long_latin1():
 
 
 _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.
 """
index 17fdc9b0941ba3a49e277d7b4af84f0c240f76d7..47e33489731632a893f2ecd66db95b5d7dcea808 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # -*- coding: iso-8859-1 -*-
 
 cdef Py_UNICODE char_ASCII = u'A'
@@ -17,8 +18,8 @@ def char_too_long_latin1():
 
 
 _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.
 """
index 35c9b2784e0d996fc7658dde1a7dacb9b5834616..5048719d8241fafdfb9e46e7faf8706b740ee79f 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 313
+# mode: error
 
 a = 3
 
@@ -5,5 +7,5 @@ cdef void* allowed = <void*>a
 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
 """
index 82778ea2ebe1ed3718d10d13fc30817a31c81797..8877278069d254ff5e613f50dd1e2e0a7ed05bf6 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 135
+# mode: error
 
 def _runtime_True():
     return True
@@ -29,13 +31,13 @@ else:
 
 
 _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
 '''
index 01f87351773e0a32dd09a6e24f5da20eba6c5ce1..cf4361d081483e5a173d4b754b6fa05256834de4 100644 (file)
@@ -1,6 +1,8 @@
+# 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
 """
index a224b707a650dcfd6b2aca28a4abe6096e00f073..4288b96a01e382d9bed13acea4bdc7ae5edcb0ff 100644 (file)
@@ -1,7 +1,9 @@
+# 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
 """
index c8b62102146634b9ed78a2b85741536e9da1f26b..aba75a9e1295600785a34404ea1cffb29b633250 100644 (file)
@@ -1,6 +1,8 @@
+# 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
 """
index 14bef3b38efc61e6e5a4459d39002caf30e176ca..cad699e28b6b5c80adc11ce8f8b7f4391e436be0 100644 (file)
@@ -1,6 +1,8 @@
+# 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)
 """
index dd8d3aec30a03c42090d8dfa4bc51c70f4238094..820d19cc5ec26914f00e1a654ea42c6fcfed72d8 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 # coding: ASCII
 
 # ok:
@@ -50,26 +51,26 @@ cdef list  l_f2 = b1
 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'
 """
index 477669b1dd9bd1e5dac285f769a755250bf1da88..05c5a9e9ed1b58f63933615564b2bf5d2bc57835 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 cimport cython
 
@@ -9,5 +10,5 @@ cdef class SubType(FinalClass):
     pass
 
 _ERRORS = """
-8:5: Base class 'FinalClass' of type 'SubType' is final
+9:5: Base class 'FinalClass' of type 'SubType' is final
 """
index ef931b9810b416f78b6aad997825b88ee08f5785..81ae9a1d395cbb13d249d51d3882d7e20931f8f6 100644 (file)
@@ -1,3 +1,4 @@
+# mode: error
 
 cimport cython
 
@@ -10,8 +11,8 @@ def test():
 
 
 _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
 """
index 8dc4b0623ba62fa81ada022dd84fb41122e85df0..7c736c898d936a5519664b1e3a9cf1a1e9457dbb 100644 (file)
@@ -1,7 +1,9 @@
+# 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
 """
index a18645ffb17681e677e9e0003335ade9b79167d0..4990dde37856263691719004dd3dd9405acc51d0 100644 (file)
@@ -1,9 +1,11 @@
+# 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_
 """
index 7736ae92b86430b91992fdae65ee4ab0b941c793..6122b00edd48541f23fde654867469ee0e59c837 100644 (file)
@@ -1,6 +1,8 @@
+# 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.
 """
diff --git a/tests/errors/w_cdef_override.pyx b/tests/errors/w_cdef_override.pyx
new file mode 100644 (file)
index 0000000..e3e5156
--- /dev/null
@@ -0,0 +1,13 @@
+# mode: error
+# tags: werror
+
+cdef foo():
+    pass
+
+def foo():
+    pass
+
+_ERRORS = u"""
+7:0: 'foo' redeclared
+7:0: Overriding cdef method with def method.
+"""
index 2e47dec6971e29ca37d4ac7d2d9da5bb8b40a2f3..132489b6afc40ca13a94ed95ab0545f410b65fb8 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 295
+
 cimport cython
 
 
index c81d8365c7518ca2def0fd4c1dfe26f45c2efd0d..98b57743b7e09ef8a8b26f4bc4d592120d6ebb85 100644 (file)
@@ -1,3 +1,6 @@
+# mode: run
+# tag: closures
+# ticket: 658
 
 def outer(int x, *args, **kwargs):
     """
diff --git a/tests/run/arithmetic_analyse_types.pyx b/tests/run/arithmetic_analyse_types.pyx
new file mode 100644 (file)
index 0000000..7d5e416
--- /dev/null
@@ -0,0 +1,62 @@
+# 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)
diff --git a/tests/run/arithmetic_analyse_types_helper.h b/tests/run/arithmetic_analyse_types_helper.h
new file mode 100644 (file)
index 0000000..72145c9
--- /dev/null
@@ -0,0 +1,27 @@
+/* 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;
+}
diff --git a/tests/run/auto_cpdef.py b/tests/run/auto_cpdef.py
new file mode 100644 (file)
index 0000000..97b8a76
--- /dev/null
@@ -0,0 +1,39 @@
+# 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']
diff --git a/tests/run/auto_cpdef_closures.py b/tests/run/auto_cpdef_closures.py
new file mode 100644 (file)
index 0000000..68ad664
--- /dev/null
@@ -0,0 +1,22 @@
+# 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
index 9042606ddc7c635372bab5723069c908fafb1dae..3ea6d82a0dd354103e201d33b2112fe80aac4f2b 100644 (file)
@@ -1,4 +1,5 @@
 #cython: autotestdict=True
+
 """
 Tests that autotestdict doesn't come into effect when
 a __test__ is defined manually.
index 2b457f235d16615d3c2aa867ffcc59525cd9a158..247a55202f673f9ec9c77fb31d0f6742da8bacec 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 252
+
 cdef cf(default=None):
     return default
 
index 8f498825d992da87930a60cc927511278def21c1..86502043c10f3efe8db045df59049d1ce9d6b084 100644 (file)
@@ -1,23 +1,41 @@
-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)
index 2717272ed41b0deb5dc6615a093c0ab262dc2299..5f5ef658c23da8eec6789bc748417490c1903c0e 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 145
 
 cimport cython
 
index 9a9ce86ccda2e29abdb14a5b053a49e98e75429f..5a461ac76e1318ce3ab371f4c54ac47c2535b77b 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 354
 
 cdef class Test:
     """
index 4e9cff0b8c7f8e25371d89bbcfc16d561cfee2dc..8896eaec5a7ae5c481723e272bec3658d734d665 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 589
 
 cimport cython
 
index 6f26cf8fbf626013e9d6a8656fed2a2e205c32a3..393d3fe5e0f89b8fc588d1695d4a12a3e07b4245 100644 (file)
@@ -1281,6 +1281,16 @@ cdef struct NestedStruct:
     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
@@ -1301,6 +1311,26 @@ cdef class NestedStructMockBuffer(MockBuffer):
     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):
     """
@@ -1325,6 +1355,35 @@ def nested_struct(object[NestedStruct] 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
index 622ca7e70f2862c9bb49add9c6f19818a80574d8..8ffaad26d563c8650265df40674f8eb750d97e16 100644 (file)
@@ -155,7 +155,7 @@ def char3int(fmt):
     >>> 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")
@@ -169,7 +169,7 @@ def char3int(fmt):
         ...
     ValueError: Buffer dtype mismatch; next field is at offset 1 but 4 expected
 
-    #TODO char3int("=cxxx@iii")
+    >>> char3int("=cxxx@iii")
 
     Error:
     >>> char3int("cii")
@@ -277,11 +277,25 @@ cdef packed struct PackedSubStruct:
     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):
@@ -291,12 +305,13 @@ 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):
         ...
@@ -305,6 +320,63 @@ def packed_struct(fmt):
     """
     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
diff --git a/tests/run/builtin_methods_return_values.pyx b/tests/run/builtin_methods_return_values.pyx
new file mode 100644 (file)
index 0000000..e117987
--- /dev/null
@@ -0,0 +1,89 @@
+# 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)
index 55aa0e0563768ca0162337d070dd8d12835703d6..98da710050d0a681f70b94de31ab10c60d536ccf 100644 (file)
@@ -1,3 +1,5 @@
+# tag: py3
+
 __doc__ = u"""
 >>> test_xrange()
 0
index 8229a3829f9039148cae27d3e06b085280849ebf..af80dae67be82f863f15aebd1e529c9cc20c1ef7 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 608
 
 cdef class MyInt(int):
     """
index fc3db82fa697959a5e7208d3c7e6074a0a92bd53..33cabffa889b171d78d690f9eb426adcf1c03037 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 166
+
 __doc__ = u"""
 >>> l = None
 >>> l.append(2)
index 1d018a55aaeb05e15395ba8c7d2dd13a29d854e4..465395829f507ac913e5e833617c2b29fa86ccf2 100644 (file)
@@ -56,14 +56,3 @@ def test_for_in_range(arg):
     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
index 82ca0e57372183953dd96f3d8aec09a63442d271..4e94309612524a8305f9eb0c1e57b54fa0dd7fa6 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 255
+
 __doc__ = u""
 
 # -------------------------------------------------------------------
index 9286d8a29d79ca62c08d1f72a94e571f969804cb..e5161f6c4c7d40649e8a1268e5ba5f061e820005 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 236
 
 __doc__ = ''
 
index e7ea7e2b7f8fa89542860ca15468e8ee11c91ed9..4efe058219f0c286dc26d4f04bc9abb52adec0a5 100644 (file)
@@ -2,8 +2,20 @@ __doc__ = u"""
 >>> 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]:
@@ -12,3 +24,12 @@ 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
+
index c1187e9ff06fbc1631f1fcbd947d1f8a63262bb3..3008bddafe2e1bbc74838260b975128b3612e070 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 467
 
 def simple_parallel_assignment_from_call():
     """
index 8f03a25305b56602e42c24a5d0e2fa17e8bd8bef..ac75485252483f62aa06734cc2ee092505119ebe 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 466
 # extension to T409
 
 def simple_parallel_typed():
index 1d4f2fc2bce9da3d954b5a8a9a05a869650a53ff..88996395141579a0c1faa6d7854deb1ae87f3804 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 227
+
 from cpython.bool cimport bool
 
 def foo(bool a):
diff --git a/tests/run/cdef_class_field.pyx b/tests/run/cdef_class_field.pyx
new file mode 100644 (file)
index 0000000..eda9324
--- /dev/null
@@ -0,0 +1,20 @@
+# 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)
index 69afe9342fd1fcb418c4b7f8f57785490da664ca..84b05a8df7784f5ef4f6388727f00d172ebae4fc 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 183
+
 cimport cython
 
 @cython.cdivision(True)
diff --git a/tests/run/cdef_locals_decorator_T477.pyx b/tests/run/cdef_locals_decorator_T477.pyx
new file mode 100644 (file)
index 0000000..2b40d05
--- /dev/null
@@ -0,0 +1,31 @@
+# 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)
index 82699de4965197993acad169ce715407eb7f446a..e726da90bc7e8331050e012352a14c51ab848471 100644 (file)
@@ -1,4 +1,6 @@
+# ticket: 517
 #cython: embedsignature=True
+
 __doc__ = u"""
 >>> a = A()
 >>> a.h = 7
index 24440ddf03de68f46132dc46775cd8c514fab7f7..dde15adbc7d1a3000065df2b60514912bafb74de 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 462
 
 cimport cython
 
index 03ff384e427cca54b5984e158559d0698429f122..3a7bcb780e98e7a4afbdcc67b1ffcbd6975c0d76 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 284
+
 def no_cdef():
     """
     >>> no_cdef()
index eddf68ceaa26d6d40c8cdd6424ee4e0e2af06acf..16532973749e6a24f51e474fdcf0dd7eb6140d46 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 408
+
 __doc__ = """
 >>> call_with_tuple(1, 1.2, 'test', [1,2,3])
 (1, 1.2, 'test', [1, 2, 3])
index a5fe9172158e40a63fbc54c24a0d7eb2def553be..aa2550b52b39438b7e99c19bf4b0c17b460d01f2 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 99
+
 cdef char c = 'c'
 cdef char* s = 'abcdef'
 
index ece80a97f73d53aa7a7bc1fe0ca3184a4ce77f78..b9316a36c51581583d6354c5011ae60f64d12717 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 412
+
 def f():
     """
     >>> f()
index aecb5b92b1ef6f6bf1f96cf0b3f31ebb4b5e5639..3701921cf75b247dc5322e85e83a8a48db4001d5 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 582
 
 cimport cython
 
index 13a89d83209831e3afea60b3a9130d3470f4fcd0..20d2daf3ab00ea34a5ebd5e9dc18d7d1a3ad174f 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 505
+
 cimport cython
 
 cdef extern from "Python.h":
index 7372275a483ab060d3d930ed1b2fb316850ab2f3..5e12f665f7b2c8f42aa51bd59f7f85c556a966a9 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 18
+
 __doc__ = u"""
 >>> f = PyFoo()
 >>> print(f.bar)
index ed810793e2a92cdc2b68f2500e891cabc38abbbd..53bf03bb06a172a5ebc74485e441c7dde9bf3133 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 87
 
 __doc__ = u"""
 >>> d = Defined()
diff --git a/tests/run/class_scope.py b/tests/run/class_scope.py
new file mode 100644 (file)
index 0000000..8a3f610
--- /dev/null
@@ -0,0 +1,14 @@
+# 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
diff --git a/tests/run/class_scope_T671.py b/tests/run/class_scope_T671.py
new file mode 100644 (file)
index 0000000..a09bc87
--- /dev/null
@@ -0,0 +1,12 @@
+# 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
diff --git a/tests/run/class_scope_del_T684.py b/tests/run/class_scope_del_T684.py
new file mode 100644 (file)
index 0000000..43368f3
--- /dev/null
@@ -0,0 +1,15 @@
+# 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
index 07444c7b95e4a4a680e06334770ba95ee0a0d5e0..c29c1cbaaece1c0c06c0181584ea6562bd27b08e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 336
+
 __doc__ = u"""
 >>> print('\\n'.join(calls))
 Py-Honk PyTestClass
index a2a65594189223aa88bb75d3812b25348f538374..e1873ae1f8c3ec0af385950099523cd734d7de57 100644 (file)
@@ -1,3 +1,5 @@
+# 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
index e2a23418346f8ab101e015f6661200c3fcfe3694..6a92d9f82b608baf3dbb4e5abfed7fd42a35e365 100644 (file)
@@ -1,3 +1,7 @@
+# mode: run
+# tag: closures
+# ticket: 596
+
 def simple(a, b):
     """
     >>> kls = simple(1, 2)
index 38a74a0a6e1ae113f3610c23479e8c7c7ec21b1a..e1c5f4918952debcf61928f72b34e19d8b7a314d 100644 (file)
@@ -1,3 +1,7 @@
+# mode: run
+# tag: closures
+# ticket: 478
+
 __doc__ = """
     >>> Num(13).is_prime()
     args (Num(13),) kwds {}
index 1232c6b7d5dc87a34beb0604f2a8ede7430a5978..494f17fac19ff3d4ba15fb73e00de8a617f23c98 100644 (file)
@@ -1,3 +1,7 @@
+# mode: run
+# tag: closures
+# ticket: 554
+
 def call_f(x):
     """
     >>> call_f(2)
index f874ce144578e3b50e8bc8a731fd5001b3837dfc..0324109ec667813851a0cb976f3cd7acf95a2ffa 100644 (file)
@@ -1,3 +1,6 @@
+# mode: run
+# tag: closures
+# ticket: 537
 
 __doc__ = u"""
 >>> f1 = nested1()
diff --git a/tests/run/closure_self.pyx b/tests/run/closure_self.pyx
new file mode 100644 (file)
index 0000000..cfc6249
--- /dev/null
@@ -0,0 +1,40 @@
+# 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
index 82d412e8f78634451f3cfd80a7c2881d0530b0bb..af443894cc7d7e961b597a578f1c7f8a68c429da 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+# tag: closures
 #
 # closure_tests_1.pyx
 #
index 1b86ffb88d616eacd387c0fa47921d6b4eb9eb77..ace26653cbd7295dd8d9a46f7df8c089e7caa3f1 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+# tag: closures
 #
 # closure_tests_2.pyx
 #
index 4babb99298a90ec390fa9e56a70a32bc227b5d8c..3d0543d0a921a1acfcb08d4038eaf87451ccc4c9 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+# tag: closures
 #
 # closure_tests_3.pyx
 #
index 81e164504562aaef067e5dde0f44b1e965d570dd..1451e24b93901d13732b57248a0e7f7ad5decba3 100644 (file)
@@ -1,3 +1,5 @@
+# mode: run
+# tag: closures
 #
 # closure_tests_4.pyx
 #
index cbb0a4dfad09457d07425d96cd4b26d694e48e99..86e0405d7801556b690a8ca15b3ece8366a98241 100644 (file)
@@ -1,3 +1,6 @@
+# mode: run
+# tag: closures
+# ticket: 82
 
 cimport cython
 
index d64c685c5d09641f247b3bd56049a6c1e20f97d7..62709c9c1bbebbd77d5279700b6c731a4590bcdf 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 445
+
 def complex_double_cast(double x, double complex z):
     """
     >>> complex_double_cast(1, 4-3j)
index f2f2ef02a0b976ffcb87327bca3a496b168534c8..956ea8eb2cf0200868bdb122a0281f17457f9bc6 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 446
+
 import cython
 
 cdef extern from "complex_int_T446_fix.h":
index 9bcafe74dc12035819e0139ba157143ba21a6539..78969ed835567712764dd636d4d61435865d5d93 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 305
+
 cimport cython
 
 def test_object_conversion(o):
index b098d122837964a81dd78dba3eea7cb58d4f783b..7d680a1674f09f3ccc884bfbcf5050361ba1ff31 100644 (file)
@@ -1,2 +1,4 @@
+# ticket: 398
+
 cdef extern from "complex_numbers_c89_T398.h": pass
 include "complex_numbers_T305.pyx"
index ede240696bccf11a18449bba821aa7c92bff63e3..762c24b02a7b4fad78328565c9267047b6bcee18 100644 (file)
@@ -1,2 +1,4 @@
+# ticket: 398
+
 cdef extern from "complex_numbers_c99_T398.h": pass
 include "complex_numbers_T305.pyx"
index 75e912475058af63a8d7f954784ab2b85d48c9f6..9b9b69a7355a5113a22ad4a67d14f9f3043ea89e 100644 (file)
@@ -1,2 +1,4 @@
+# ticket: 398
+
 cdef extern from "complex_numbers_cxx_T398.h": pass
 include "complex_numbers_T305.pyx"
index c66906f3e5ddfc5e3435a0499951414fdcdce476..5caed0b8691276277987f09c7a2f8fe9e6184916 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 455
+
 def in_sequence(x, seq):
     """
     >>> in_sequence(1, [])
index 7b96f1ce51aa576eaaa9d1d7bbc4e9c2dbbfabb3..061d9ef13e5335d088b263768190eacc9fc365f6 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 411
+
 cdef class A:
     """
     >>> A().is_True()
index 14a7b81e9696b0fdb593fb17647492e49176cfab..68fea8064e634cd39e59b4b69f21be0aac7c7e3f 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 from libcpp cimport bool
 
 def test_bool(bool a):
index 7005cec16c33f046b5b1e8e85635696748e24389..b2c9e7eba5ec94512078c6becc2a6c4d8c32f0a6 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 __doc__ = u"""
     >>> test_new_del()
     (2, 2)
index 28cc66799de2008f49a9e4d3f02a1f18b264ea28..dbbfc9f0bddf2f90ee45394e1c5f2e712732f55b 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cdef int raise_py_error() except *:
     raise TypeError("custom")
 
index 3fe982225a54dac50047462bf7a641d8a3c9fa61..49acad9db92de79546eb77c2e752658f213a18d3 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cdef int raise_TypeError() except *:
     raise TypeError("custom")
 
index 40bf18de6349e8d8833068fe7d9c2d1534a3e070..08774a2b8f03753d69ba66f230a1af231ce3c12c 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cdef extern from "cpp_namespaces_helper.h" namespace "A":
     ctypedef int A_t
     A_t A_func(A_t first, A_t)
index 7768a035cab3f9e04f37bc8f5af113069ef0ed98..f4795226686e433a83e06db8ac9793d1367a582d 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 from cython.operator cimport dereference as deref
 
 cdef extern from "cpp_templates_helper.h":
index 17c6a23e9becd5d90a2a52dd59e3296007d71210..62153d190ef7619e4ed1f9aba44c321d8cff45fd 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cdef extern from "cpp_nonstdint.h":
     ctypedef int Int24
     ctypedef int Int56
index 8cb97f939141591af64c24c36fae5898b00678ea..73ace96aa7415dbc7549ab3ea79f120286f8d99f 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cimport cython.operator
 from cython.operator cimport dereference as deref
 
index 4d3c0f05bd6be74ae1a760146cae2cd0d6fb97b3..f3bf5b562d05e1f6ab3976240e5ef6e7c5ccbc4f 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cdef extern from "vector" namespace "std":
 
     cdef cppclass vector[T]:
diff --git a/tests/run/cpp_stl_string.pyx b/tests/run/cpp_stl_string.pyx
new file mode 100644 (file)
index 0000000..2d4a9bd
--- /dev/null
@@ -0,0 +1,177 @@
+# 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)
index 4e03706bf2171e4e901734119389387861ad5f6d..979c40d685ab34eab3b62f7959aeb35c9609abd3 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 from cython.operator cimport dereference as d
 from cython.operator cimport preincrement as incr
 
index 12007f4c317cdbe2f848f83f30939384ec65a7f1..877f6d0eec5c5fb6431c0964c6209e1868133050 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 from cython.operator import dereference as deref
 
 cdef extern from "cpp_templates_helper.h":
index 511beaefa4bfdf63b2df1335db6c88a36f807b02..862deca37cdcdb9eb609feaaa2a7c996d1300147 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 245
+
 cimport crashT245_pxd
 
 def f():
index 65963d01cf22aeb85cacd233beef16668d754fd3..4cfe35b9a8240615c2d30334ba34a7cf09105254 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 333
 #cython: autotestdict=True
 
 # -------------------------------------------------------------------
index d3f416e8384524a9e0e8b9da8759e00880835feb..475a3deb22088cd7bea472ad58857c89f66d1a24 100644 (file)
@@ -1,4 +1,6 @@
 # cython: language_level=3
+# mode: run
+# tag: generators, python3
 
 cimport cython
 
@@ -89,6 +91,16 @@ def list_comp():
     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():
     """
index e9119ad23692af701168b2f2b74380254754f491..e2b5993913ce268c43e269db2a212fe6f5a99b8a 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 593
+
 """
 >>> am_i_buggy
 False
index 7157078a0ba3b99f92162457d1ad1db275d5efd8..efe121c7994fb3c6c7ee4a191e902de55f0df24e 100644 (file)
@@ -87,3 +87,12 @@ def del_local(a):
     """
     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...
diff --git a/tests/run/directive_locals_in_pxd.pxd b/tests/run/directive_locals_in_pxd.pxd
new file mode 100644 (file)
index 0000000..4fa9f02
--- /dev/null
@@ -0,0 +1,10 @@
+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=*)
diff --git a/tests/run/directive_locals_in_pxd.py b/tests/run/directive_locals_in_pxd.py
new file mode 100644 (file)
index 0000000..87e7320
--- /dev/null
@@ -0,0 +1,31 @@
+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)
index 7c4ba4abdbc64eb235c81ae137312028a1f34967..301dc3a61744b698e5c145eda9821ce99c12be83 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 384
+
 """
 >>> test(3)
 (3+1j)
index 909ee608dac0cf7a592d2bbdc5f751d1c3fa5f02..e7892dbc904c3ad83e731d1e41c449c889639923 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 488
+
 """
 >>> test()
 """
index 46deed25079bfaaf914c258298893a638091d6e0..88a134f2594aaec96b117fddcffe629eab86fcff 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 208
+
 def go_py_empty():
     """
     >>> go_py_empty()
index 5b66c6bb6205ebeb4973eae27cbe838f58ea9126..658f2fe6f724701bf19474bb9b64d5bfea2150bb 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 316
+
 cimport cython
 
 @cython.test_fail_if_path_exists("//SimpleCallNode//NameNode[@name = 'enumerate']")
index 29bf7008292bbc5a0670b86e9ab55c6c24173713..9538a9b96833c9739295f28b8336e91ddeb335de 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 232
+
 cdef class MyExt:
     cdef object attr
 
index 9f7e9cac91c8fe26be20693af78f77d3f88b9daa..4ce1ecf61df6f3f5cf47a3c76047285aa93cbdfd 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 235
+
 __doc__ = u"""
     >>> class FakeSeq(object):
     ...     def __init__(self, length):
index 7b001e1b076e6ce93dfcc2f6af773ce0d7bf70b3..1198a15f34aef60f92a8e73e849874a72ffc6226 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 409
+
 def simple():
     """
     >>> simple()
index 902063bc13023f0db28044710649e3cb9bf6f3cf..d732931ddcf1e1a9fad29e4482777093a5d60432 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 258
+
 cdef extern from "Python.h":
 
     ctypedef class __builtin__.list  [object PyListObject]:
index 7b135ac776915c7c5a7d95762e9c48007a222c40..66f6f83f7ec7efa7bbcb42815da158889cb873df 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 260
+
 def floor_div_float(double a, double b):
     """
     >>> floor_div_float(2, 1.5)
index d5651a2014c3eb61fbff22fbea3de1d1db977d36..efb456c542889c411c16fe9c445d46c4b5043220 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 480
+
 def f(x):
     return x
 
index 57db916191323f3e1b1dc2f67479b1b449eba129..02be71f6fec9fb21210f1ebe18e69a8e5705513b 100644 (file)
@@ -33,7 +33,7 @@ def from_loop_indices():
     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
index 554d97715afe50db36e2921edd9a34f83e8db04c..0ea153a9cf11bf87cdd9acafbe94728de0b78343 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 254
+
 def double_target(a, b):
     """
     >>> double_target(0, 4)
index 11b7e195a8aa50520b0467d8a333169fd1401ebe..30fc2b7daa3a8e09e5ab5e1e7ac1c0aeb7457a5a 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 601
 
 cdef unsigned long size2():
     return 3
index 23c27246bc56358af626de55d84d1f67e89ba53c..0baa9fa491221fad0bb4ea584a98a02fabc9bdcb 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 533
 
 def for_in():
     """
index 6ba4ee47f38fc0591edbb25ba8a44ce56b2b7b43..7244d40fe9b70daa17f7de7d2b4f2a2ea63c9920 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 372
+
 cimport cython
 
 @cython.test_assert_path_exists("//ForFromStatNode")
index 0fa6563e48d9b027e09b2d66a17f3e174ef07699..0c5bde250ddb6801a089d6e5ac80f0e51ae18724 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 228
+
 __doc__ = u"""
 >>> def py_iterator():
 ...    if True: return
index ee2bc53e1ee75950bf6711e091e20dd38c4a44aa..111a211a51dd5e1c2c60b19edf62a6a7deae6c9b 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 494
+
 __doc__ = """
     >>> A.foo = foo
     >>> print A().foo()
index 820d52ea04e266e40eac4ace3f683f6ddee38f4f..b41221e2c0e64e579ee72818b5e9e2d73503c5b2 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 494
+
 cimport cython
 
 class SomeNumber(object):
diff --git a/tests/run/generator_expressions.pyx b/tests/run/generator_expressions.pyx
new file mode 100644 (file)
index 0000000..f525da7
--- /dev/null
@@ -0,0 +1,39 @@
+# 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) )
diff --git a/tests/run/generator_type_inference.pyx b/tests/run/generator_type_inference.pyx
new file mode 100644 (file)
index 0000000..6a5c90e
--- /dev/null
@@ -0,0 +1,52 @@
+# 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()
diff --git a/tests/run/generators.pyx b/tests/run/generators.pyx
new file mode 100644 (file)
index 0000000..a501c76
--- /dev/null
@@ -0,0 +1,320 @@
+# 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
diff --git a/tests/run/generators_py.py b/tests/run/generators_py.py
new file mode 100644 (file)
index 0000000..57a11d0
--- /dev/null
@@ -0,0 +1,301 @@
+# 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
index b2babf072ef4cb28a6402c9d59e8e18e5b51e3a5..7fa6c17546aa151b6a65cacf454e29fd743b7708 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 491
 
 def test_genexpr():
     """
index fa64da0273fd6ae3175ec08c0e683d1d0d3cc70a..429022f94cf787bf7cffea185b8f4cec1cf135e1 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 600
 
 cimport cython
 
index 32bcc59d0bc7abf184ce4aa69786aae134c04089..0d8b42e47d98755081472b1250c8c5e4545a966e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 326
+
 __doc__ = u"""
 
     >>> hash(A(5))
index 41f412a60d302067adaa594df9e9d980791eca2c..5f32628b2c1930c40f825681796da023d400e040 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 267
+
 """
 >>> constants(4)
 1
index 93d4e5eb0ac2a661828cfcc8d574a6e44a7a419d..52bc676113de36bc893af3fbd76202618d68f26a 100644 (file)
@@ -61,16 +61,16 @@ def typed_imports():
     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)
index aa6e6c233cf805a10daff7cbac47f86201241d3a..3bb3954c38831e18533b996ca29c565847944b6a 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 544
 
 def count(i=[0]):
     i[0] += 1
index c4d4b0647cc75611f6d6d7f0c51342b462e65e8c..c18ee01e61292cfdb3189f708aa31112dfa9297e 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 400
 
 cimport cython
 
index 5cbd00666e543f810c6b23a2fbf99f86318dd3b0..5851d97417b40e2f265dde7609aec89c81bc8573 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 431
+
 __doc__ = u"""
 >>> s == s_interned
 True
index 2cba79010d8b58348bbf4c77674d022ff68f2376..6fea958b503c19a8ed61a5f1cb7a2ef786fe2c9f 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 562
+
 class IPOW:
     """
     >>> IPOW().__ipow__('a')
index 447f3d4fa169e2f3971576a884e5969434c1acda..fdbde9982e68142fb2cb6ca821a00e3a58452688 100644 (file)
@@ -1,3 +1,7 @@
+# mode: run
+# tag: lambda
+# ticket: 195
+
 __doc__ = u"""
 #>>> py_identity = lambda x:x
 #>>> py_identity(1) == cy_identity(1)
index eb3b8a527db52b3627aea230ac3532455e62871d..82e1ff8a7086c96c2ef288b122db7b1d2dcadce1 100644 (file)
@@ -1,3 +1,7 @@
+# mode: run
+# tag: lambda
+# ticket: 605
+
 cdef int cdef_CONST = 123
 CONST = 456
 
index 8bc3ef0b21825be7cc1dfb6e45a4df7d735e96b2..245f869377712205305bfacbafde8d06f2b3c33a 100644 (file)
@@ -1,4 +1,9 @@
+# mode: run
+# tag: lambda
+# ticket: 603
+
 # Module scope lambda functions
+
 __doc__ = """
 >>> pow2(16)
 256
index 4eccf30b43cd38c187a7ea38fe1a854fb9a4a3ed..f11a24541e8ffac42c68b0878b8fe4beee3b7bb1 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 237
 #def add_large_c():
 #    cdef unsigned long long val = 2**30 + 2**30
 #    return val
index 5eaf009e29ddac4c48a86fa64a84be46d426c671..97cc5ab75fba0346de7b38abfb858a09dec90da2 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cimport libcpp
 
 cimport libcpp.deque
index 3e833601c743b7793748e130e7dd286b403b6c87..3f418add1efd159eea168f750a1a113a46d64fa3 100644 (file)
@@ -1,3 +1,6 @@
+# mode: run
+# tag: closures
+# ticket: 598
 # cython: language_level=3
 
 def list_comp_in_closure():
index 6209224a29bf12f5c1a77dae710d1479b977477b..0da74c2040fa47be1b460852c54bfccd34b5b51b 100644 (file)
@@ -1,14 +1,24 @@
-__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')
@@ -22,6 +32,19 @@ def in_locals(x, *args, **kwds):
     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()
index 36a044f0738f526dc58d592ae2a89f9bf513b377..78d58fc8b28bb75bc14e83ba08f95d3f1ba338e9 100644 (file)
@@ -1,3 +1,5 @@
+# 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)]
index 2c9d7969a201193951344ed7efe5444efe79c625..9b3f06a5a192c8883188231f4fc5a7be87fabfc8 100644 (file)
@@ -1,3 +1,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)]
index f7334c266d0ac010f8849a6a81b9ca881e4099c9..fbefa21444db9afaefc985ce01ceb72999e8fb37 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 422
+
 """
 >>> Foo.incr.__module__ is not None
 True
index c3dd0b2fafb2a3091c3aef6058aecf1e28ba4b39..44b165b8354a1d3feec6b512930b3d86161bf32e 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 5
 # this is ticket #5
 
 __doc__ = u"""
index 1a4f17ba5ad121761aa8552d64bd9cd184016bdf..47221fa014bf4d7f6ef905f49bc883e0a0b0e96e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 470
+
 __doc__ = u"""
 >>> func(**{'a' : 7})
 True
diff --git a/tests/run/nonlocal_T490.pyx b/tests/run/nonlocal_T490.pyx
new file mode 100644 (file)
index 0000000..0a5a80d
--- /dev/null
@@ -0,0 +1,157 @@
+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
index 6930ee411e672633117e098af5739645ab1d69a7..66558eefc1875c5214348192acf25f80b3d8c1a4 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 172
+# tag: numpy
+
 __doc__ = u"""
     >>> 1
     1
index 38549a028090ec1a07659d82293f4e1892d252af..6de42a289669bcb4ded9d14b9612a281bb5142c8 100644 (file)
@@ -1,3 +1,6 @@
+# ticket: 155
+# tag: numpy
+
 """
 >>> myfunc()
 0.5
index 51ce5196077135463619670f77c6104929b310e5..7c23d77259afc721fc19e922f4e2f2015c0a4003 100644 (file)
@@ -1,3 +1,5 @@
+# tag: numpy
+
 """
 >>> import sys
 >>> 'numpy' in sys.modules
index 052d2ae4d9a418213747ea7fb2e8aebf977357bb..3886e13ddad2215872541cf4452ebba5fe7d4caa 100644 (file)
@@ -1,3 +1,4 @@
+# tag: numpy
 # cannot be named "numpy" in order to not clash with the numpy module!
 
 cimport numpy as np
@@ -209,6 +210,30 @@ try:
           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""
 
@@ -401,6 +426,18 @@ cdef struct UnpackedStruct:
     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
@@ -411,6 +448,22 @@ def test_unpacked_align(np.ndarray[UnpackedStruct] arr):
     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
index 2c6bcc72f03ca643f1316bcc464c4b34ba6276a5..203008ca72508b3514fd0d40aaf10e12caa2a55c 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 290
+
 """
 >>> f()
 (9, 9)
index aafdbec003cdabcaa4cb5569708dc6f4f47bf055..fb7d1ac291032086f621a93edaa2f1de23d72d04 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 425
+
 cimport cython
 
 @cython.test_assert_path_exists(
index 5c11c9e0b1f11e9dbb98ed5d273bace3c16ccd75..18fc3cffe350b6a220e340dbad5b48dbf6e67def 100644 (file)
@@ -1,3 +1,4 @@
+# tag: posix
 from libc.stdio   cimport *
 from posix.unistd cimport *
 from posix.fcntl  cimport *
index f9d2d5c3574599b833976d81018a4da0cfbe4ced..7735d493809f4af63d4ee4deb41bc2b188fc97f5 100644 (file)
@@ -1,3 +1,4 @@
+# tag: pstats
 # cython: profile = True
 
 __doc__ = u"""
@@ -20,6 +21,23 @@ __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:
@@ -43,6 +61,10 @@ def test_profile(long N):
         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:
@@ -68,3 +90,18 @@ cdef int f_noprof(long a):
 
 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
+
index 3adfb3716c3cee53f52e4486d81e03884820dc71..e46f65f7b069cc3c7b4b7689ee9af13376471e1d 100644 (file)
@@ -1,5 +1,8 @@
 import cython
 
+NULL = 5
+_NULL = NULL
+
 def test_sizeof():
     """
     >>> test_sizeof()
@@ -19,26 +22,24 @@ def 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):
@@ -59,6 +60,7 @@ def test_address(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)
@@ -93,21 +95,19 @@ def test_with_nogil(nogil):
             result = True
     return result
 
-## CURRENTLY BROKEN - FIXME!!
-
-## MyUnion = cython.union(n=cython.int, x=cython.double)
-## MyStruct = cython.struct(is_integral=cython.bint, data=MyUnion)
-## MyStruct2 = cython.typedef(MyStruct[2])
+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
@@ -116,24 +116,21 @@ from cython import declare as my_declare, locals as my_locals, p_void as my_void
 @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):
     """
index 7add38801e9f7d1131b5035fba468bb2f875f713..cf393407f345d0b5a9061cd040ea6bad2efa1ccd 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 489
+
 """
 >>> xxx
 [0, 1, 2, 3]
index aac975af3eb7ffa147a44b4eb0a311414dcd88d1..fb4ef80a02a90a9e64321f8cef666f111f021b0f 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 313
 # Ensure casting still works to void*
 
 """
index da14948871235aedda7b50e6e21a66a511fa8303..065faf2c9afb78ff85e4782b9c22aca955cf33e3 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 650
 
 cimport cython
 
@@ -22,3 +23,12 @@ def raise_me_instance():
     ... 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")
index 690dd1ddc7c38e8f9edd23348410ae91aa16f2e4..880d8952de123913157980e51296455c7f77325e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 203
+
 cdef int get_bound(int m):
     print u"get_bound(%s)"%m
     return m
index 88c7d892453a3ce9c98f019f9836ae7cca360b8e..0118a640995d292c07d55c964248ad9eb6698773 100644 (file)
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+
 __doc__=u"""
 >>> t = RefCountInMeth()
 >>> t.chk_meth()
diff --git a/tests/run/relativeimport_T542.pyx b/tests/run/relativeimport_T542.pyx
new file mode 100644 (file)
index 0000000..d6edf83
--- /dev/null
@@ -0,0 +1,33 @@
+# 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
+"""
diff --git a/tests/run/relativeimport_star_T542.pyx b/tests/run/relativeimport_star_T542.pyx
new file mode 100644 (file)
index 0000000..fde63a1
--- /dev/null
@@ -0,0 +1,8 @@
+from distutils import core, version
+__name__='distutils.core.cytest_relativeimport_T542' # fool Python we are in distutils
+from . import *
+
+__doc__ = """
+>>> core.setup == setup
+True
+"""
index b49e328bef088e5b2ebf1b949602ccd416519fd3..09affaf7a6586c34ddc40734c278ffcb12bfdb8e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 404
+
 cdef long foo(long x):
     print "foo(%s)" % x
     return x
index 3a6eb1c0645193c20a895c38a3d7efd42eb20498..fba5e93ed4b9d1c46ad8cb8570438a8c4d6387b7 100644 (file)
@@ -1,3 +1,4 @@
+# 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,
index 1031976ce1f38b65ac7e0f7d71722d7d64dc8da9..285f820f66e809bc3a35df10def23c05f7976730 100644 (file)
@@ -1,3 +1,5 @@
+# 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.)
index 5574067e948c608bf7b5f62fbd52259e39ecb191..9320022549ff104e343a9ca5ceb270bee7dd978c 100644 (file)
@@ -1,3 +1,5 @@
+# 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.)
index b4559477710c4e477e37bc36387d4471a76489ed..4a8f65d68aa9ecf0762fd6be8b43892cbc6ab9ba 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 399
+
 __doc__ = u"""
 >>> test(-2)
 -2
index b0e206990d3402ca2dafd28a9a118f551dc3e8ba..0d291c6482d082a6a3b4da751538b6c960efd439 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 664
+
 def assign():
     """
     >>> assign()
index ff796e90cefb3bccdd95eb7f4fa3a6d1d0a38528..6a470e2b74b0f6cb456b1f82a88bab58f1e7500e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 412
+
 cdef int   i = 'x'
 cdef char  c = 'x'
 cdef char* s = 'x'
index 5194668e13beb0b34aac9338527d21ce8112aa93..f50ca49c2eaa12838f4eedde7fbf522329a433a1 100644 (file)
@@ -132,6 +132,18 @@ __doc__ = ur"""
     >>> 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
     
@@ -173,6 +185,7 @@ bresc = br'\12\'\"\\'
 uresc = ur'\12\'\"\\'
 
 bytes_uescape = b'\u1234\U12345678\u\u1\u12\uX'
+str_uescape = '\u0063\U00012345\x42'
 
 newlines = "Aaa\n"
 
index 823a0a5c5d44240dde2e4db0a3c40ed80639dd5a..383e1ef6fb2aeac64bca100b132d37d7b2ef9422 100644 (file)
@@ -1,3 +1,4 @@
+# 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)
 
index fc44ba2bc367ab7d9755e7655d6959f02d37c534..6bb5ee5489776d1f33f66d8a79b71ca46e3cebcf 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 654
 
 # function call arguments
 
index 2482f6125c6fe2bb36dda19750b89cc9a24a5aee..893ef9b1b5dd8a23101cbfe820f48d4077cb2cb8 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 454
 
 cimport cython
 
index 3db9c7ec2ea35f322e98e30c82135fb86069a065..2f603ba9ff476495aa0c1a2044108a022d524faf 100644 (file)
@@ -1,17 +1,38 @@
-__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
index 87f24bb941fa0286686df74738e0519de951d787..7763b1fc72e068e4b0a8d386aef3d97a69ff89e5 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 298
+
 """
 >>> func()
 0 0
index 992bdcc227789ec88aa7a90ec7720d7e531acfbc..61ec7c8e7f993303b1b39c9c322fa0d1dd605970 100644 (file)
@@ -156,7 +156,7 @@ def unary_operators():
     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)
index 654ff6e3664588e1b5c9435b1e9d4ff7c19e5cf7..2426225b56a3705b95ff721cce658cd1b8380101 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 287
+
 __doc__ = u"""
 >>> print( "%d" % Int() )
 2
index bfb6047a50f9db11deec64f6b7261e9a33245dba..98ac85c3aa5cfe1add8e94b53609646f0c74c16e 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 373
+
 import math
 
 cdef class MyClass:
index aeb5c93a66d4c6e0b08245382bfff18067b0fa0b..cd736f745c4a7ac7db7dd4da52d06ffdbe810705 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 303
+
 __doc__ = """
 >>> readonly() #doctest: +ELLIPSIS
 Traceback (most recent call last):
index 09b1c0bd061dc1f93b728a9c615701817e89df6d..757e15b8d2585ef1e156296a32a8c04163fb2302 100644 (file)
@@ -1,3 +1,4 @@
+# ticket: 417
 #cython: autotestdict=True
 
 cdef class Foo:
index f525c9057e9e57d3a77a068588c830ca8c956b3e..c40c5036ca7646cc55b2462fdc49ad7d95aab365 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 359
+
 __doc__ = u"""
 >>> py_string1.decode('ASCII') == 'test toast taste'
 True
index 225de2f36fba7b71e95887a5f99bffa92507f62c..9cbf65fc124d85c5104b4ebb07216822cad4eb89 100644 (file)
@@ -1,3 +1,5 @@
+# ticket: 184
+
 """
 >>> c_call()
 (-10, 10)
index daf38d3d5121796184929800bbe3752842661ab9..506c362f9e93b8d30dd0b84a7987e5e80237bfe3 100644 (file)
@@ -1,18 +1,34 @@
+# 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')
+    
index ad037e2880bd8664d1fb4fae2f2fff6200cb0ae9..67bef98276f630231f111c8ceef7882fa1f50518 100644 (file)
@@ -56,17 +56,6 @@ def with_pass():
     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)
diff --git a/tests/run/withstat_py.py b/tests/run/withstat_py.py
new file mode 100644 (file)
index 0000000..8345b59
--- /dev/null
@@ -0,0 +1,272 @@
+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)
index 8b9b84112070e00f06feb58d01d458e6c8d25fec..cc00ee8326d7163ba7d334bb02cd2e4f643b2421 100644 (file)
@@ -1,3 +1,4 @@
+# tag: cpp
 
 cimport cpp_overload_wrapper_lib as cppwrap_lib
 
index ec19a5a2e080ade59aeda047c5578a5e00041d1b..cc8a0b9018598825600e4c35adfedbc1f2e7ca12 100644 (file)
@@ -1,3 +1,5 @@
+# tag: cpp
+
 cimport cython
 
 
index 6dfeced8e973058db76b47d3618cd3c355a59add..b07a5c6511616c4ed0b93401be592b05fc810721 100644 (file)
@@ -1,3 +1,4 @@
+# tag: cpp
 
 cimport cppwrap_lib