From ef2a02c39652d69ac311da03b47aef17dace6e01 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Sat, 19 Sep 2009 02:32:41 +0000 Subject: [PATCH] Merged 2009 GSoC work from sandbox-branches/bhy/py3k branch back into trunk. [SVN r56305] --- build/Jamfile.v2 | 148 +++++++++++------- doc/news.html | 36 +++++ .../python/converter/builtin_converters.hpp | 22 ++- .../python/converter/pyobject_traits.hpp | 2 + include/boost/python/detail/operator_id.hpp | 4 + include/boost/python/detail/wrap_python.hpp | 13 ++ include/boost/python/enum.hpp | 4 + include/boost/python/exec.hpp | 7 + include/boost/python/list.hpp | 12 +- include/boost/python/lvalue_from_pytype.hpp | 4 +- include/boost/python/module_init.hpp | 39 +++-- include/boost/python/object/iterator.hpp | 4 + include/boost/python/object/make_instance.hpp | 2 +- include/boost/python/object_core.hpp | 13 ++ .../boost/python/opaque_pointer_converter.hpp | 3 +- include/boost/python/operators.hpp | 4 + include/boost/python/str.hpp | 8 + src/converter/builtin_converters.cpp | 121 ++++++++++++-- src/converter/from_python.cpp | 21 ++- src/converter/registry.cpp | 7 +- src/dict.cpp | 2 +- src/exec.cpp | 10 +- src/list.cpp | 22 ++- src/module.cpp | 19 ++- src/object/class.cpp | 99 +++++++++--- src/object/enum.cpp | 40 ++++- src/object/function.cpp | 26 ++- src/object/life_support.cpp | 7 +- src/object_operators.cpp | 11 ++ src/object_protocol.cpp | 10 +- src/str.cpp | 105 +++++++++---- test/Jamfile.v2 | 23 ++- test/a_map_indexing_suite.cpp | 8 + test/crossmod_opaque.py | 2 +- test/defaults.py | 7 - test/dict.py | 2 +- test/exec.cpp | 10 +- test/exec.py | 4 +- test/iterator.py | 2 +- test/list.cpp | 7 + test/list.py | 6 +- test/long.py | 12 +- test/m1.cpp | 6 +- test/m2.cpp | 10 ++ test/map_indexing_suite.py | 2 +- test/opaque.py | 2 +- test/pickle2.py | 2 +- test/str.cpp | 5 + test/str.py | 2 +- test/test_builtin_converters.py | 36 ++--- test/tuple.py | 2 +- test/upcast.cpp | 4 +- 52 files changed, 734 insertions(+), 245 deletions(-) mode change 100755 => 100644 include/boost/python/detail/operator_id.hpp mode change 100755 => 100644 include/boost/python/lvalue_from_pytype.hpp mode change 100755 => 100644 src/object_protocol.cpp mode change 100755 => 100644 test/a_map_indexing_suite.cpp mode change 100755 => 100644 test/upcast.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index e01a27b7..803f8bc5 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -4,6 +4,7 @@ import os ; import modules ; +import feature ; import python ; @@ -22,6 +23,22 @@ if ! [ python.configured ] && ! ( --without-python in [ modules.peek : ARGV ] ) } } +rule find-py3-version +{ + local versions = [ feature.values python ] ; + local py3ver ; + for local v in $(versions) + { + if $(v) >= 3.0 + { + py3ver = $(v) ; + } + } + return $(py3ver) ; +} + +py3-version = [ find-py3-version ] ; + project boost/python : source-location ../src ; @@ -29,66 +46,79 @@ project boost/python rule cond ( test ? : yes * : no * ) { if $(test) { return $(yes) ; } else { return $(no) ; } } rule unless ( test ? : yes * : no * ) { if ! $(test) { return $(yes) ; } else { return $(no) ; } } -lib boost_python - : # sources - numeric.cpp - list.cpp - long.cpp - dict.cpp - tuple.cpp - str.cpp - slice.cpp +rule lib_boost_python ( is-py3 ? ) +{ - converter/from_python.cpp - converter/registry.cpp - converter/type_id.cpp - object/enum.cpp - object/class.cpp - object/function.cpp - object/inheritance.cpp - object/life_support.cpp - object/pickle_support.cpp - errors.cpp - module.cpp - converter/builtin_converters.cpp - converter/arg_to_python_base.cpp - object/iterator.cpp - object/stl_iterator.cpp - object_protocol.cpp - object_operators.cpp - wrapper.cpp - import.cpp - exec.cpp - object/function_doc_signature.cpp - : # requirements - static:BOOST_PYTHON_STATIC_LIB - BOOST_PYTHON_SOURCE - - # On Windows, all code using Python has to link to the Python - # import library. - # - # On *nix we never link libboost_python to libpython. When - # extending Python, all Python symbols are provided by the - # Python interpreter executable. When embedding Python, the - # client executable is expected to explicitly link to - # /python//python (the target representing libpython) itself. - # - # python_for_extensions is a target defined by Boost.Build to - # provide the Python include paths, and on Windows, the Python - # import library, as usage requirements. - [ cond [ python.configured ] : /python//python_for_extensions ] - - # we prevent building when there is no python available - # as it's not possible anyway, and to cause dependents to - # fail to build - [ unless [ python.configured ] : no ] + lib [ cond $(is-py3) : boost_python3 : boost_python ] + : # sources + numeric.cpp + list.cpp + long.cpp + dict.cpp + tuple.cpp + str.cpp + slice.cpp - on:BOOST_DEBUG_PYTHON - : # default build - shared - : # usage requirements - static:BOOST_PYTHON_STATIC_LIB - on:BOOST_DEBUG_PYTHON - ; + converter/from_python.cpp + converter/registry.cpp + converter/type_id.cpp + object/enum.cpp + object/class.cpp + object/function.cpp + object/inheritance.cpp + object/life_support.cpp + object/pickle_support.cpp + errors.cpp + module.cpp + converter/builtin_converters.cpp + converter/arg_to_python_base.cpp + object/iterator.cpp + object/stl_iterator.cpp + object_protocol.cpp + object_operators.cpp + wrapper.cpp + import.cpp + exec.cpp + object/function_doc_signature.cpp + : # requirements + static:BOOST_PYTHON_STATIC_LIB + BOOST_PYTHON_SOURCE + + # On Windows, all code using Python has to link to the Python + # import library. + # + # On *nix we never link libboost_python to libpython. When + # extending Python, all Python symbols are provided by the + # Python interpreter executable. When embedding Python, the + # client executable is expected to explicitly link to + # /python//python (the target representing libpython) itself. + # + # python_for_extensions is a target defined by Boost.Build to + # provide the Python include paths, and on Windows, the Python + # import library, as usage requirements. + [ cond [ python.configured ] : /python//python_for_extensions ] + + # we prevent building when there is no python available + # as it's not possible anyway, and to cause dependents to + # fail to build + [ unless [ python.configured ] : no ] + on:BOOST_DEBUG_PYTHON + [ cond $(is-py3) : $(py3-version) ] + : # default build + shared + : # usage requirements + static:BOOST_PYTHON_STATIC_LIB + on:BOOST_DEBUG_PYTHON + ; + +} + +lib_boost_python ; boost-install boost_python ; + +if $(py3-version) +{ + lib_boost_python yes ; + boost-install boost_python3 ; +} diff --git a/doc/news.html b/doc/news.html index a2418951..da57caeb 100644 --- a/doc/news.html +++ b/doc/news.html @@ -32,7 +32,43 @@
+
Current SVN
+
+
    +
  • Python 3 support:
  • +
      +
    • All the current Boost.Python test cases passed. Extension modules using + Boost.Python expected to support Python 3 smoothly.
    • +
    • Introduced object.contains where x.contains(y) + is equivalent to Python code y in x. + Now dict.has_key is just a wrapper of object.contains. +
    • +
    • When building against Python 3, str.decode will be removed.
    • +
    • When building against Python 3, the original signature of list.sort, which is: +
      void sort(object_cref cmpfunc);
      + will change to: +
      void sort(args_proxy const &args, kwds_proxy const &kwds);
      + + This is because in Python 3 list.sort requires all its arguments be keyword arguments. + So you should call it like this: +
      x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true))));
      + +
    • +
    • According to PEP 3123, + when building Boost.Python against Python older than 2.6, the following macros will + be defined in Boost.Python header: +
      +# define Py_TYPE(o)    (((PyObject*)(o))->ob_type)
      +# define Py_REFCNT(o)  (((PyObject*)(o))->ob_refcnt)
      +# define Py_SIZE(o)    (((PyVarObject*)(o))->ob_size)
      + So extension writers can use these macro directly, to make code clean and compatible with Python 3. +
    • +
    +
+
+ +
1.39.0 Release
    diff --git a/include/boost/python/converter/builtin_converters.hpp b/include/boost/python/converter/builtin_converters.hpp index df32ad21..63ae1e1a 100644 --- a/include/boost/python/converter/builtin_converters.hpp +++ b/include/boost/python/converter/builtin_converters.hpp @@ -90,6 +90,14 @@ namespace detail BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T,expr) // Specialize converters for signed and unsigned T to Python Int +#if PY_VERSION_HEX >= 0x03000000 + +# define BOOST_PYTHON_TO_INT(T) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyLong_FromLong(x), &PyLong_Type) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned T, ::PyLong_FromUnsignedLong(x), &PyLong_Type) + +#else + # define BOOST_PYTHON_TO_INT(T) \ BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x), &PyInt_Type) \ BOOST_PYTHON_TO_PYTHON_BY_VALUE( \ @@ -98,6 +106,7 @@ namespace detail (std::numeric_limits::max)()) \ ? ::PyLong_FromUnsignedLong(x) \ : ::PyInt_FromLong(x), &PyInt_Type) +#endif // Bool is not signed. #if PY_VERSION_HEX >= 0x02030000 @@ -116,17 +125,24 @@ BOOST_PYTHON_TO_INT(long) // using Python's macro instead of Boost's - we don't seem to get the // config right all the time. # ifdef HAVE_LONG_LONG -BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, ::PyLong_FromLongLong(x), &PyInt_Type) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x), &PyInt_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed BOOST_PYTHON_LONG_LONG, ::PyLong_FromLongLong(x), &PyLong_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x), &PyLong_Type) # endif # undef BOOST_TO_PYTHON_INT +#if PY_VERSION_HEX >= 0x03000000 +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x), &PyUnicode_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x), &PyUnicode_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyUnicode_FromStringAndSize(x.data(),implicit_cast(x.size())), &PyUnicode_Type) +#else BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x), &PyString_Type) BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x), &PyString_Type) BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyString_FromStringAndSize(x.data(),implicit_cast(x.size())), &PyString_Type) +#endif + #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),implicit_cast(x.size())), &PyString_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),implicit_cast(x.size())), &PyUnicode_Type) # endif BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x), &PyFloat_Type) BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x), &PyFloat_Type) diff --git a/include/boost/python/converter/pyobject_traits.hpp b/include/boost/python/converter/pyobject_traits.hpp index 03ef4460..43e384af 100644 --- a/include/boost/python/converter/pyobject_traits.hpp +++ b/include/boost/python/converter/pyobject_traits.hpp @@ -34,7 +34,9 @@ struct pyobject_traits // This is not an exhaustive list; should be expanded. BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Type); BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(List); +#if PY_VERSION_HEX < 0x03000000 BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Int); +#endif BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Long); BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Dict); BOOST_PYTHON_BUILTIN_OBJECT_TRAITS(Tuple); diff --git a/include/boost/python/detail/operator_id.hpp b/include/boost/python/detail/operator_id.hpp old mode 100755 new mode 100644 index 4a2785ed..25642fba --- a/include/boost/python/detail/operator_id.hpp +++ b/include/boost/python/detail/operator_id.hpp @@ -47,7 +47,11 @@ enum operator_id op_ixor, op_ior, op_complex, +#if PY_VERSION_HEX >= 0x03000000 + op_bool, +#else op_nonzero, +#endif op_repr }; diff --git a/include/boost/python/detail/wrap_python.hpp b/include/boost/python/detail/wrap_python.hpp index af76fcce..4868a987 100644 --- a/include/boost/python/detail/wrap_python.hpp +++ b/include/boost/python/detail/wrap_python.hpp @@ -175,6 +175,19 @@ typedef int pid_t; ( (op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) #endif +// Define Python 3 macros for Python 2.x +#if PY_VERSION_HEX < 0x02060000 + +# define Py_TYPE(o) (((PyObject*)(o))->ob_type) +# define Py_REFCNT(o) (((PyObject*)(o))->ob_refcnt) +# define Py_SIZE(o) (((PyVarObject*)(o))->ob_size) + +# define PyVarObject_HEAD_INIT(type, size) \ + PyObject_HEAD_INIT(type) size, + +#endif + + #ifdef __MWERKS__ # pragma warn_possunwant off #elif _MSC_VER diff --git a/include/boost/python/enum.hpp b/include/boost/python/enum.hpp index c47f8477..9631a0ed 100644 --- a/include/boost/python/enum.hpp +++ b/include/boost/python/enum.hpp @@ -79,7 +79,11 @@ void* enum_::convertible_from_python(PyObject* obj) template void enum_::construct(PyObject* obj, converter::rvalue_from_python_stage1_data* data) { +#if PY_VERSION_HEX >= 0x03000000 + T x = static_cast(PyLong_AS_LONG(obj)); +#else T x = static_cast(PyInt_AS_LONG(obj)); +#endif void* const storage = ((converter::rvalue_from_python_storage*)data)->storage.bytes; new (storage) T(x); data->convertible = storage; diff --git a/include/boost/python/exec.hpp b/include/boost/python/exec.hpp index 359830a4..3ed1e15c 100644 --- a/include/boost/python/exec.hpp +++ b/include/boost/python/exec.hpp @@ -20,6 +20,13 @@ object BOOST_PYTHON_DECL eval(str string, object global = object(), object local = object()); +// Execute an individual python statement from str. +// global and local are the global and local scopes respectively, +// used during execution. +object +BOOST_PYTHON_DECL +exec_statement(str string, object global = object(), object local = object()); + // Execute python source code from str. // global and local are the global and local scopes respectively, // used during execution. diff --git a/include/boost/python/list.hpp b/include/boost/python/list.hpp index 0f6d1e8e..e3dbf711 100644 --- a/include/boost/python/list.hpp +++ b/include/boost/python/list.hpp @@ -19,7 +19,7 @@ namespace detail { void append(object_cref); // append object to end - long count(object_cref value) const; // return number of occurrences of value + Py_ssize_t count(object_cref value) const; // return number of occurrences of value void extend(object_cref sequence); // extend list by appending sequence elements @@ -37,8 +37,12 @@ namespace detail void reverse(); // reverse *IN PLACE* void sort(); // sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1 +#if PY_VERSION_HEX >= 0x03000000 + void sort(args_proxy const &args, + kwds_proxy const &kwds); +#else void sort(object_cref cmpfunc); - +#endif protected: list_base(); // new list @@ -113,13 +117,15 @@ class list : public detail::list_base base::remove(object(value)); } +#if PY_VERSION_HEX <= 0x03000000 void sort() { base::sort(); } - + template void sort(T const& value) { base::sort(object(value)); } +#endif public: // implementation detail -- for internal use only BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(list, base) diff --git a/include/boost/python/lvalue_from_pytype.hpp b/include/boost/python/lvalue_from_pytype.hpp old mode 100755 new mode 100644 index 019d4ae5..e15dfbbb --- a/include/boost/python/lvalue_from_pytype.hpp +++ b/include/boost/python/lvalue_from_pytype.hpp @@ -63,7 +63,7 @@ struct extract_member { static MemberType& execute(InstanceType& c) { - (void)c.ob_type; // static assertion + (void)Py_TYPE(&c); // static assertion return c.*member; } }; @@ -75,7 +75,7 @@ struct extract_identity { static InstanceType& execute(InstanceType& c) { - (void)c.ob_type; // static assertion + (void)Py_TYPE(&c); // static assertion return c; } }; diff --git a/include/boost/python/module_init.hpp b/include/boost/python/module_init.hpp index aaf2a0f9..e552dcce 100644 --- a/include/boost/python/module_init.hpp +++ b/include/boost/python/module_init.hpp @@ -11,40 +11,49 @@ namespace boost { namespace python { namespace detail { -BOOST_PYTHON_DECL void init_module(char const* name, void(*)()); +BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*)()); }}} -# if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(BOOST_PYTHON_STATIC_MODULE) +# if PY_VERSION_HEX >= 0x03000000 -# define BOOST_PYTHON_MODULE_INIT(name) \ -void init_module_##name(); \ -extern "C" __declspec(dllexport) void init##name() \ +# define _BOOST_PYTHON_MODULE_INIT(name) \ +PyObject* PyInit_##name() \ +{ \ + return boost::python::detail::init_module( \ + #name,&init_module_##name); \ +} \ +void init_module_##name() + +# else + +# define _BOOST_PYTHON_MODULE_INIT(name) \ +void init##name() \ { \ boost::python::detail::init_module( \ #name,&init_module_##name); \ } \ void init_module_##name() +# endif + +# if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(BOOST_PYTHON_STATIC_MODULE) + +# define BOOST_PYTHON_MODULE_INIT(name) \ +void init_module_##name(); \ +extern "C" __declspec(dllexport) _BOOST_PYTHON_MODULE_INIT(name) + # elif BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY # define BOOST_PYTHON_MODULE_INIT(name) \ void init_module_##name(); \ -extern "C" __attribute__ ((visibility("default"))) void init##name() \ -{ \ - boost::python::detail::init_module(#name, &init_module_##name); \ -} \ -void init_module_##name() +extern "C" __attribute__ ((visibility("default"))) _BOOST_PYTHON_MODULE_INIT(name) # else # define BOOST_PYTHON_MODULE_INIT(name) \ void init_module_##name(); \ -extern "C" void init##name() \ -{ \ - boost::python::detail::init_module(#name, &init_module_##name); \ -} \ -void init_module_##name() +extern "C" _BOOST_PYTHON_MODULE_INIT(name) # endif diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp index 3e24afd2..ab748fe8 100644 --- a/include/boost/python/object/iterator.hpp +++ b/include/boost/python/object/iterator.hpp @@ -129,7 +129,11 @@ namespace detail return class_(name, no_init) .def("__iter__", identity_function()) .def( +#if PY_VERSION_HEX >= 0x03000000 + "__next__" +#else "next" +#endif , make_function( next_fn() , policies diff --git a/include/boost/python/object/make_instance.hpp b/include/boost/python/object/make_instance.hpp index 55771eca..8f355fe2 100644 --- a/include/boost/python/object/make_instance.hpp +++ b/include/boost/python/object/make_instance.hpp @@ -43,7 +43,7 @@ struct make_instance_impl // Note the position of the internally-stored Holder, // for the sake of destruction - instance->ob_size = offsetof(instance_t, storage); + Py_SIZE(instance) = offsetof(instance_t, storage); // Release ownership of the python object protect.cancel(); diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 0342ef2e..5857422f 100644 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -126,6 +126,10 @@ namespace api const_object_objattribute attr(object const&) const; object_objattribute attr(object const&); + // Wrap 'in' operator (aka. __contains__) + template + object contains(T const& key) const; + // item access // const_object_item operator[](object_cref) const; @@ -483,6 +487,15 @@ object api::object_operators::operator()(detail::args_proxy const &args, } + +template +template +object api::object_operators::contains(T const& key) const +{ + return this->attr("__contains__")(object(key)); +} + + inline object::object() : object_base(python::incref(Py_None)) {} diff --git a/include/boost/python/opaque_pointer_converter.hpp b/include/boost/python/opaque_pointer_converter.hpp index 745a5cd4..10eb4234 100644 --- a/include/boost/python/opaque_pointer_converter.hpp +++ b/include/boost/python/opaque_pointer_converter.hpp @@ -121,8 +121,7 @@ opaque opaque::instance; template PyTypeObject opaque::type_object = { - PyObject_HEAD_INIT(0) - 0, + PyVarObject_HEAD_INIT(NULL, 0) 0, sizeof( BOOST_DEDUCED_TYPENAME opaque::python_instance ), 0, diff --git a/include/boost/python/operators.hpp b/include/boost/python/operators.hpp index e929779e..9a60b344 100644 --- a/include/boost/python/operators.hpp +++ b/include/boost/python/operators.hpp @@ -341,7 +341,11 @@ BOOST_PYTHON_UNARY_OPERATOR(neg, -, operator-) BOOST_PYTHON_UNARY_OPERATOR(pos, +, operator+) BOOST_PYTHON_UNARY_OPERATOR(abs, abs, abs) BOOST_PYTHON_UNARY_OPERATOR(invert, ~, operator~) +#if PY_VERSION_HEX >= 0x03000000 +BOOST_PYTHON_UNARY_OPERATOR(bool, !!, operator!) +#else BOOST_PYTHON_UNARY_OPERATOR(nonzero, !!, operator!) +#endif BOOST_PYTHON_UNARY_OPERATOR(int, long, int_) BOOST_PYTHON_UNARY_OPERATOR(long, PyLong_FromLong, long_) BOOST_PYTHON_UNARY_OPERATOR(float, double, float_) diff --git a/include/boost/python/str.hpp b/include/boost/python/str.hpp index 86bc3ba6..426a3a25 100644 --- a/include/boost/python/str.hpp +++ b/include/boost/python/str.hpp @@ -37,10 +37,12 @@ namespace detail long count(object_cref sub, object_cref start, object_cref end) const; +#if PY_VERSION_HEX < 0x03000000 object decode() const; object decode(object_cref encoding) const; object decode(object_cref encoding, object_cref errors) const; +#endif object encode() const; object encode(object_cref encoding) const; @@ -185,6 +187,7 @@ class str : public detail::str_base return base::count(object(sub), object(start)); } +#if PY_VERSION_HEX < 0x03000000 object decode() const { return base::decode(); } template @@ -198,6 +201,7 @@ class str : public detail::str_base { return base::decode(object(encoding),object(errors)); } +#endif object encode() const { return base::encode(); } @@ -404,7 +408,11 @@ namespace converter { template <> struct object_manager_traits +#if PY_VERSION_HEX >= 0x03000000 + : pytype_object_manager_traits<&PyUnicode_Type,str> +#else : pytype_object_manager_traits<&PyString_Type,str> +#endif { }; } diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index b3fcd9ea..c9d6bcbf 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -37,12 +37,20 @@ void shared_ptr_deleter::operator()(void const*) namespace { + // An lvalue conversion function which extracts a char const* from a // Python String. +#if PY_VERSION_HEX < 0x03000000 void* convert_to_cstring(PyObject* obj) { return PyString_Check(obj) ? PyString_AsString(obj) : 0; } +#else + void* convert_to_cstring(PyObject* obj) + { + return PyUnicode_Check(obj) ? _PyUnicode_AsString(obj) : 0; + } +#endif // Given a target type and a SlotPolicy describing how to perform a // given conversion, registers from_python converters which use the @@ -90,6 +98,52 @@ namespace } }; + // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc + // "slot" which just returns its argument. + extern "C" PyObject* identity_unaryfunc(PyObject* x) + { + Py_INCREF(x); + return x; + } + unaryfunc py_object_identity = identity_unaryfunc; + +#if PY_VERSION_HEX >= 0x03000000 + // As in Python 3 there is only one integer type, we can have much + // simplified logic. + // XXX(bhy) maybe the code will work with 2.6 or even 2.5? + struct int_rvalue_from_python_base + { + static unaryfunc* get_slot(PyObject* obj) + { + return PyLong_Check(obj) ? &py_object_identity : 0; + } + static PyTypeObject const* get_pytype() {return &PyLong_Type;} + }; + + template + struct signed_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + long x = PyLong_AsLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast(x); + } + }; + + template + struct unsigned_int_rvalue_from_python : int_rvalue_from_python_base + { + static T extract(PyObject* intermediate) + { + unsigned long x = PyLong_AsUnsignedLong(intermediate); + if (PyErr_Occurred()) + throw_error_already_set(); + return numeric_cast(x); + } + }; +#else // PY_VERSION_HEX >= 0x03000000 // A SlotPolicy for extracting signed integer types from Python objects struct signed_int_rvalue_from_python_base { @@ -121,16 +175,7 @@ namespace return numeric_cast(x); } }; - - // identity_unaryfunc/py_object_identity -- manufacture a unaryfunc - // "slot" which just returns its argument. - extern "C" PyObject* identity_unaryfunc(PyObject* x) - { - Py_INCREF(x); - return x; - } - unaryfunc py_object_identity = identity_unaryfunc; - + // A SlotPolicy for extracting unsigned integer types from Python objects struct unsigned_int_rvalue_from_python_base { @@ -178,6 +223,7 @@ namespace } } }; +#endif // PY_VERSION_HEX >= 0x03000000 // Checking Python's macro instead of Boost's - we don't seem to get // the config right all the time. Furthermore, Python's is defined @@ -190,6 +236,9 @@ namespace { static unaryfunc* get_slot(PyObject* obj) { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Check(obj) ? &py_object_identity : 0; +#else PyNumberMethods* number_methods = obj->ob_type->tp_as_number; if (number_methods == 0) return 0; @@ -202,19 +251,22 @@ namespace return &number_methods->nb_long; else return 0; +#endif } - static PyTypeObject const* get_pytype() { return &PyInt_Type;} + static PyTypeObject const* get_pytype() { return &PyLong_Type;} }; struct long_long_rvalue_from_python : long_long_rvalue_from_python_base { static BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) { +#if PY_VERSION_HEX < 0x03000000 if (PyInt_Check(intermediate)) { return PyInt_AS_LONG(intermediate); } else +#endif { BOOST_PYTHON_LONG_LONG result = PyLong_AsLongLong(intermediate); @@ -230,11 +282,13 @@ namespace { static unsigned BOOST_PYTHON_LONG_LONG extract(PyObject* intermediate) { +#if PY_VERSION_HEX < 0x03000000 if (PyInt_Check(intermediate)) { return numeric_cast(PyInt_AS_LONG(intermediate)); } else +#endif { unsigned BOOST_PYTHON_LONG_LONG result = PyLong_AsUnsignedLongLong(intermediate); @@ -252,7 +306,9 @@ namespace { static unaryfunc* get_slot(PyObject* obj) { -#if PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) +#if PY_VERSION_HEX >= 0x03000000 + return obj == Py_None || PyLong_Check(obj) ? &py_object_identity : 0; +#elif PY_VERSION_HEX >= 0x02040000 && defined(BOOST_PYTHON_BOOL_INT_STRICT) return obj == Py_None || PyBool_Check(obj) ? &py_object_identity : 0; #else return obj == Py_None || PyInt_Check(obj) ? &py_object_identity : 0; @@ -285,8 +341,10 @@ namespace // For integer types, return the tp_int conversion slot to avoid // creating a new object. We'll handle that below +#if PY_VERSION_HEX < 0x03000000 if (PyInt_Check(obj)) return &number_methods->nb_int; +#endif return (PyLong_Check(obj) || PyFloat_Check(obj)) ? &number_methods->nb_float : 0; @@ -294,11 +352,13 @@ namespace static double extract(PyObject* intermediate) { +#if PY_VERSION_HEX < 0x03000000 if (PyInt_Check(intermediate)) { return PyInt_AS_LONG(intermediate); } else +#endif { return PyFloat_AS_DOUBLE(intermediate); } @@ -306,22 +366,36 @@ namespace static PyTypeObject const* get_pytype() { return &PyFloat_Type;} }; + unaryfunc py_unicode_as_string_unaryfunc = PyUnicode_AsUTF8String; + // A SlotPolicy for extracting C++ strings from Python objects. struct string_rvalue_from_python { // If the underlying object is "string-able" this will succeed static unaryfunc* get_slot(PyObject* obj) { - return (PyString_Check(obj)) - ? &obj->ob_type->tp_str : 0; +#if PY_VERSION_HEX >= 0x03000000 + return (PyUnicode_Check(obj)) ? &py_unicode_as_string_unaryfunc : 0; +#else + return (PyString_Check(obj)) ? &obj->ob_type->tp_str : 0; + +#endif }; // Remember that this will be used to construct the result object +#if PY_VERSION_HEX >= 0x03000000 + static std::string extract(PyObject* intermediate) + { + return std::string(PyBytes_AsString(intermediate),PyBytes_Size(intermediate)); + } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} +#else static std::string extract(PyObject* intermediate) { return std::string(PyString_AsString(intermediate),PyString_Size(intermediate)); } static PyTypeObject const* get_pytype() { return &PyString_Type;} +#endif }; #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) @@ -341,7 +415,11 @@ namespace { return PyUnicode_Check(obj) ? &py_object_identity +#if PY_VERSION_HEX >= 0x03000000 + : PyBytes_Check(obj) +#else : PyString_Check(obj) +#endif ? &py_encode_string : 0; }; @@ -384,10 +462,12 @@ namespace PyComplex_RealAsDouble(intermediate) , PyComplex_ImagAsDouble(intermediate)); } +#if PY_VERSION_HEX < 0x03000000 else if (PyInt_Check(intermediate)) { return PyInt_AS_LONG(intermediate); } +#endif else { return PyFloat_AS_DOUBLE(intermediate); @@ -399,12 +479,20 @@ namespace BOOST_PYTHON_DECL PyObject* do_return_to_python(char x) { +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_FromStringAndSize(&x, 1); +#else return PyString_FromStringAndSize(&x, 1); +#endif } BOOST_PYTHON_DECL PyObject* do_return_to_python(char const* x) { +#if PY_VERSION_HEX >= 0x03000000 + return x ? PyUnicode_FromString(x) : boost::python::detail::none(); +#else return x ? PyString_FromString(x) : boost::python::detail::none(); +#endif } BOOST_PYTHON_DECL PyObject* do_return_to_python(PyObject* x) @@ -459,13 +547,18 @@ void initialize_builtin_converters() slot_rvalue_from_python,complex_rvalue_from_python>(); // Add an lvalue converter for char which gets us char const* +#if PY_VERSION_HEX < 0x03000000 registry::insert(convert_to_cstring,type_id(),&converter::wrap_pytype<&PyString_Type>::get_pytype); +#else + registry::insert(convert_to_cstring,type_id(),&converter::wrap_pytype<&PyUnicode_Type>::get_pytype); +#endif // Register by-value converters to std::string, std::wstring #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) slot_rvalue_from_python(); # endif slot_rvalue_from_python(); + } }}} // namespace boost::python::converter diff --git a/src/converter/from_python.cpp b/src/converter/from_python.cpp index efe2bb19..0af47609 100644 --- a/src/converter/from_python.cpp +++ b/src/converter/from_python.cpp @@ -96,7 +96,12 @@ BOOST_PYTHON_DECL void* rvalue_from_python_stage2( if (!data.convertible) { handle<> msg( - ::PyString_FromFormat( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s" , converters.target_type.name() , source->ob_type->tp_name @@ -196,7 +201,12 @@ namespace void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type) { handle<> msg( - ::PyString_FromFormat( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( "No registered converter was able to extract a C++ %s to type %s" " from this Python object of type %s" , ref_type @@ -218,7 +228,12 @@ namespace if (source->ob_refcnt <= 1) { handle<> msg( - ::PyString_FromFormat( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( "Attempt to return dangling %s to object of type: %s" , ref_type , converters.target_type.name())); diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index b09a7985..d203ea8c 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -70,7 +70,12 @@ BOOST_PYTHON_DECL PyObject* registration::to_python(void const volatile* source) if (this->m_to_python == 0) { handle<> msg( - ::PyString_FromFormat( +#if PY_VERSION_HEX >= 0x3000000 + ::PyUnicode_FromFormat +#else + ::PyString_FromFormat +#endif + ( "No to_python (by-value) converter found for C++ type: %s" , this->target_type.name() ) diff --git a/src/dict.cpp b/src/dict.cpp index 441b0257..77d840d4 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -84,7 +84,7 @@ object dict_base::get(object_cref k, object_cref d) const bool dict_base::has_key(object_cref k) const { - return extract(this->attr("has_key")(k)); + return extract(this->contains(k)); } list dict_base::items() const diff --git a/src/exec.cpp b/src/exec.cpp index fb2a0350..e772dcd7 100644 --- a/src/exec.cpp +++ b/src/exec.cpp @@ -88,11 +88,19 @@ object BOOST_PYTHON_DECL exec_file(str filename, object global, object local) if (local.ptr() == none.ptr()) local = global; // should be 'char const *' but older python versions don't use 'const' yet. char *f = python::extract(filename); +#if PY_VERSION_HEX >= 0x03000000 + // TODO(bhy) temporary workaround for Python 3. + // should figure out a way to avoid binary incompatibilities as the Python 2 + // version did. + FILE *fs = fopen(f, "r"); +#else // Let python open the file to avoid potential binary incompatibilities. PyObject *pyfile = PyFile_FromString(f, const_cast("r")); if (!pyfile) throw std::invalid_argument(std::string(f) + " : no such file"); python::handle<> file(pyfile); - PyObject* result = PyRun_File(PyFile_AsFile(file.get()), + FILE *fs = PyFile_AsFile(file.get()); +#endif + PyObject* result = PyRun_File(fs, f, Py_file_input, global.ptr(), local.ptr()); diff --git a/src/list.cpp b/src/list.cpp index 2c29251b..de54335e 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -48,7 +48,11 @@ void list_base::extend(object_cref sequence) long list_base::index(object_cref value) const { object result_obj(this->attr("index")(value)); +#if PY_VERSION_HEX >= 0x03000000 + ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else long result = PyInt_AsLong(result_obj.ptr()); +#endif if (result == -1) throw_error_already_set(); return result; @@ -69,7 +73,11 @@ void list_base::insert(ssize_t index, object_cref item) void list_base::insert(object const& index, object_cref x) { +#if PY_VERSION_HEX >= 0x03000000 + ssize_t index_ = PyLong_AsSsize_t(index.ptr()); +#else long index_ = PyInt_AsLong(index.ptr()); +#endif if (index_ == -1 && PyErr_Occurred()) throw_error_already_set(); this->insert(index_, x); @@ -121,17 +129,29 @@ void list_base::sort() } } +#if PY_VERSION_HEX >= 0x03000000 +void list_base::sort(args_proxy const &args, + kwds_proxy const &kwds) +{ + this->attr("sort")(args, kwds); +} +#else void list_base::sort(object_cref cmpfunc) { this->attr("sort")(cmpfunc); } +#endif // For some reason, moving this to the end of the TU suppresses an ICE // with vc6. -long list_base::count(object_cref value) const +Py_ssize_t list_base::count(object_cref value) const { object result_obj(this->attr("count")(value)); +#if PY_VERSION_HEX >= 0x03000000 + Py_ssize_t result = PyLong_AsSsize_t(result_obj.ptr()); +#else long result = PyInt_AsLong(result_obj.ptr()); +#endif if (result == -1) throw_error_already_set(); return result; diff --git a/src/module.cpp b/src/module.cpp index 864651ca..5bfbfd1f 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -24,11 +24,25 @@ namespace PyMethodDef initial_methods[] = { { 0, 0, 0, 0 } }; } -BOOST_PYTHON_DECL void init_module(char const* name, void(*init_function)()) +BOOST_PYTHON_DECL PyObject* init_module(char const* name, void(*init_function)()) { - +#if PY_VERSION_HEX >= 0x03000000 + static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + name, + 0, /* m_doc */ + -1, /* m_size */ + initial_methods, + 0, /* m_reload */ + 0, /* m_traverse */ + 0, /* m_clear */ + 0, /* m_free */ + }; + PyObject* m = PyModule_Create(&moduledef); +#else PyObject* m = Py_InitModule(const_cast(name), initial_methods); +#endif if (m != 0) { @@ -38,6 +52,7 @@ BOOST_PYTHON_DECL void init_module(char const* name, void(*init_function)()) handle_exception(init_function); } + return m; } }}} // namespace boost::python::detail diff --git a/src/object/class.cpp b/src/object/class.cpp index 64d1d6d0..3e29693b 100644 --- a/src/object/class.cpp +++ b/src/object/class.cpp @@ -67,8 +67,44 @@ extern "C" PyObject *prop_set; PyObject *prop_del; PyObject *prop_doc; + int getter_doc; } propertyobject; + // Copied from Python source and removed the part for setting docstring, + // since we don't have a setter for __doc__ and trying to set it will + // cause the init fail. + static int property_init(PyObject *self, PyObject *args, PyObject *kwds) + { + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *prop = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + kwlist, &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + prop->prop_get = get; + prop->prop_set = set; + prop->prop_del = del; + prop->prop_doc = doc; + prop->getter_doc = 0; + + return 0; + } + + static PyObject * static_data_descr_get(PyObject *self, PyObject * /*obj*/, PyObject * /*type*/) { @@ -106,10 +142,9 @@ extern "C" } static PyTypeObject static_data_object = { - PyObject_HEAD_INIT(0)//&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Boost.Python.StaticProperty"), - PyType_Type.tp_basicsize, + sizeof(propertyobject), 0, 0, /* tp_dealloc */ 0, /* tp_print */ @@ -143,7 +178,7 @@ static PyTypeObject static_data_object = { static_data_descr_get, /* tp_descr_get */ static_data_descr_set, /* tp_descr_set */ 0, /* tp_dictoffset */ - 0, /* tp_init */ + property_init, /* tp_init */ 0, /* tp_alloc */ 0, // filled in with type_new /* tp_new */ 0, // filled in with __PyObject_GC_Del /* tp_free */ @@ -160,17 +195,20 @@ static PyTypeObject static_data_object = { namespace objects { +#if PY_VERSION_HEX < 0x03000000 + // XXX Not sure why this run into compiling error in Python 3 extern "C" { // This declaration needed due to broken Python 2.2 headers extern DL_IMPORT(PyTypeObject) PyProperty_Type; } +#endif BOOST_PYTHON_DECL PyObject* static_data() { if (static_data_object.tp_dict == 0) { - static_data_object.ob_type = &PyType_Type; + Py_TYPE(&static_data_object) = &PyType_Type; static_data_object.tp_base = &PyProperty_Type; if (PyType_Ready(&static_data_object)) return 0; @@ -203,15 +241,14 @@ extern "C" // If we found a static data descriptor, call it directly to // force it to set the static data member if (a != 0 && PyObject_IsInstance(a, objects::static_data())) - return a->ob_type->tp_descr_set(a, obj, value); + return Py_TYPE(a)->tp_descr_set(a, obj, value); else return PyType_Type.tp_setattro(obj, name, value); } } static PyTypeObject class_metatype_object = { - PyObject_HEAD_INIT(0)//&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Boost.Python.class"), PyType_Type.tp_basicsize, 0, @@ -266,7 +303,7 @@ static PyTypeObject class_metatype_object = { // object. void instance_holder::install(PyObject* self) throw() { - assert(self->ob_type->ob_type == &class_metatype_object); + assert(Py_TYPE(Py_TYPE(self)) == &class_metatype_object); m_next = ((objects::instance<>*)self)->objects; ((objects::instance<>*)self)->objects = this; } @@ -279,7 +316,7 @@ namespace objects { if (class_metatype_object.tp_dict == 0) { - class_metatype_object.ob_type = &PyType_Type; + Py_TYPE(&class_metatype_object) = &PyType_Type; class_metatype_object.tp_base = &PyType_Type; if (PyType_Ready(&class_metatype_object)) return type_handle(); @@ -308,7 +345,7 @@ namespace objects Py_XDECREF(kill_me->dict); - inst->ob_type->tp_free(inst); + Py_TYPE(inst)->tp_free(inst); } static PyObject * @@ -318,7 +355,12 @@ namespace objects PyObject* d = type_->tp_dict; PyObject* instance_size_obj = PyObject_GetAttrString(d, const_cast("__instance_size__")); - long instance_size = instance_size_obj ? PyInt_AsLong(instance_size_obj) : 0; + Py_ssize_t instance_size = instance_size_obj ? +#if PY_VERSION_HEX >= 0x03000000 + PyLong_AsSsize_t(instance_size_obj) : 0; +#else + PyInt_AsLong(instance_size_obj) : 0; +#endif if (instance_size < 0) instance_size = 0; @@ -332,7 +374,12 @@ namespace objects // like, so we'll store the total size of the object // there. A negative number indicates that the extra // instance memory is not yet allocated to any holders. - result->ob_size = -(static_cast(offsetof(instance<>,storage) + instance_size)); +#if PY_VERSION_HEX >= 0x02060000 + Py_SIZE(result) = +#else + result->ob_size = +#endif + -(static_cast(offsetof(instance<>,storage) + instance_size)); } return (PyObject*)result; } @@ -368,8 +415,7 @@ namespace objects }; static PyTypeObject class_type_object = { - PyObject_HEAD_INIT(0) //&class_metatype_object) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Boost.Python.instance"), offsetof(instance<>,storage), /* tp_basicsize */ 1, /* tp_itemsize */ @@ -424,7 +470,7 @@ namespace objects { if (class_type_object.tp_dict == 0) { - class_type_object.ob_type = incref(class_metatype().get()); + Py_TYPE(&class_type_object) = incref(class_metatype().get()); class_type_object.tp_base = &PyBaseObject_Type; if (PyType_Ready(&class_type_object)) return type_handle(); @@ -436,7 +482,7 @@ namespace objects BOOST_PYTHON_DECL void* find_instance_impl(PyObject* inst, type_info type, bool null_shared_ptr_only) { - if (inst->ob_type->ob_type != &class_metatype_object) + if (Py_TYPE(Py_TYPE(inst)) != &class_metatype_object) return 0; instance<>* self = reinterpret_cast*>(inst); @@ -526,7 +572,7 @@ namespace objects d["__doc__"] = doc; object result = object(class_metatype())(name, bases, d); - assert(PyType_IsSubtype(result.ptr()->ob_type, &PyType_Type)); + assert(PyType_IsSubtype(Py_TYPE(result.ptr()), &PyType_Type)); if (scope().ptr() != Py_None) scope().attr(name) = result; @@ -589,8 +635,9 @@ namespace objects void class_base::add_static_property(char const* name, object const& fget) { object property( - (python::detail::new_reference) - PyObject_CallFunction(static_data(), const_cast("O"), fget.ptr())); + (python::detail::new_reference) + PyObject_CallFunction(static_data(), const_cast("O"), fget.ptr()) + ); this->setattr(name, property); } @@ -650,7 +697,7 @@ namespace objects ::PyErr_Format( PyExc_TypeError , const_cast("staticmethod expects callable object; got an object of type %s, which is not callable") - , callable->ob_type->tp_name + , Py_TYPE(callable)->tp_name ); throw_error_already_set(); @@ -680,18 +727,18 @@ namespace objects void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std::size_t holder_size) { - assert(self_->ob_type->ob_type == &class_metatype_object); + assert(Py_TYPE(Py_TYPE(self_)) == &class_metatype_object); objects::instance<>* self = (objects::instance<>*)self_; int total_size_needed = holder_offset + holder_size; - if (-self->ob_size >= total_size_needed) + if (-Py_SIZE(self) >= total_size_needed) { // holder_offset should at least point into the variable-sized part assert(holder_offset >= offsetof(objects::instance<>,storage)); // Record the fact that the storage is occupied, noting where it starts - self->ob_size = holder_offset; + Py_SIZE(self) = holder_offset; return (char*)self + holder_offset; } else @@ -705,9 +752,9 @@ void* instance_holder::allocate(PyObject* self_, std::size_t holder_offset, std: void instance_holder::deallocate(PyObject* self_, void* storage) throw() { - assert(self_->ob_type->ob_type == &class_metatype_object); + assert(Py_TYPE(Py_TYPE(self_)) == &class_metatype_object); objects::instance<>* self = (objects::instance<>*)self_; - if (storage != (char*)self + self->ob_size) + if (storage != (char*)self + Py_SIZE(self)) { PyMem_Free(storage); } diff --git a/src/object/enum.cpp b/src/object/enum.cpp index b4cc4984..3063320c 100644 --- a/src/object/enum.cpp +++ b/src/object/enum.cpp @@ -18,7 +18,11 @@ namespace boost { namespace python { namespace objects { struct enum_object { +#if PY_VERSION_HEX >= 0x03000000 + PyLongObject base_object; +#else PyIntObject base_object; +#endif PyObject* name; }; @@ -32,19 +36,32 @@ extern "C" { static PyObject* enum_repr(PyObject* self_) { - const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast("__module__"))); + // XXX(bhy) Potentional memory leak here since PyObject_GetAttrString returns a new reference + // const char *mod = PyString_AsString(PyObject_GetAttrString( self_, const_cast("__module__"))); + PyObject *mod = PyObject_GetAttrString( self_, "__module__"); enum_object* self = downcast(self_); if (!self->name) { - return PyString_FromFormat("%s.%s(%ld)", mod, self_->ob_type->tp_name, PyInt_AS_LONG(self_)); + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s(%ld)", mod, self_->ob_type->tp_name, PyLong_AsLong(self_)); +#else + PyString_FromFormat("%s.%s(%ld)", PyString_AsString(mod), self_->ob_type->tp_name, PyInt_AS_LONG(self_)); +#endif } else { - char* name = PyString_AsString(self->name); + PyObject* name = self->name; if (name == 0) return 0; - return PyString_FromFormat("%s.%s.%s", mod, self_->ob_type->tp_name, name); + return +#if PY_VERSION_HEX >= 0x03000000 + PyUnicode_FromFormat("%S.%s.%S", mod, self_->ob_type->tp_name, name); +#else + PyString_FromFormat("%s.%s.%s", + PyString_AsString(mod), self_->ob_type->tp_name, PyString_AsString(name)); +#endif } } @@ -53,7 +70,11 @@ extern "C" enum_object* self = downcast(self_); if (!self->name) { +#if PY_VERSION_HEX >= 0x03000000 + return PyLong_Type.tp_str(self_); +#else return PyInt_Type.tp_str(self_); +#endif } else { @@ -63,8 +84,7 @@ extern "C" } static PyTypeObject enum_type_object = { - PyObject_HEAD_INIT(0) // &PyType_Type - 0, + PyVarObject_HEAD_INIT(NULL, 0) // &PyType_Type const_cast("Boost.Python.enum"), sizeof(enum_object), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -84,7 +104,9 @@ static PyTypeObject enum_type_object = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT +#if PY_VERSION_HEX < 0x03000000 | Py_TPFLAGS_CHECKTYPES +#endif | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ @@ -125,8 +147,12 @@ namespace { if (enum_type_object.tp_dict == 0) { - enum_type_object.ob_type = incref(&PyType_Type); + Py_TYPE(&enum_type_object) = incref(&PyType_Type); +#if PY_VERSION_HEX >= 0x03000000 + enum_type_object.tp_base = &PyLong_Type; +#else enum_type_object.tp_base = &PyInt_Type; +#endif if (PyType_Ready(&enum_type_object)) throw_error_already_set(); } diff --git a/src/object/function.cpp b/src/object/function.cpp index d49d0228..0054966e 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -105,9 +105,9 @@ function::function( } PyObject* p = this; - if (function_type.ob_type == 0) + if (Py_TYPE(&function_type) == 0) { - function_type.ob_type = &PyType_Type; + Py_TYPE(&function_type) = &PyType_Type; ::PyType_Ready(&function_type); } @@ -435,9 +435,13 @@ void function::add_to_namespace( function* new_func = downcast(attribute.ptr()); PyObject* dict = 0; +#if PY_VERSION_HEX < 0x03000000 + // Old-style class gone in Python 3 if (PyClass_Check(ns)) dict = ((PyClassObject*)ns)->cl_dict; - else if (PyType_Check(ns)) + else +#endif + if (PyType_Check(ns)) dict = ((PyTypeObject*)ns)->tp_dict; else dict = PyObject_GetAttrString(ns, const_cast("__dict__")); @@ -595,9 +599,18 @@ extern "C" static PyObject * function_descr_get(PyObject *func, PyObject *obj, PyObject *type_) { +#if PY_VERSION_HEX >= 0x03000000 + // The implement is different in Python 3 because of the removal of unbound method + if (obj == Py_None || obj == NULL) { + Py_INCREF(func); + return func; + } + return PyMethod_New(func, obj); +#else if (obj == Py_None) obj = NULL; return PyMethod_New(func, obj, type_); +#endif } static void @@ -641,7 +654,11 @@ extern "C" { function* f = downcast(op); if (f->name().ptr() == Py_None) +#if PY_VERSION_HEX >= 0x03000000 + return PyUnicode_InternFromString(""); +#else return PyString_InternFromString(""); +#endif else return python::incref(f->name().ptr()); } @@ -665,8 +682,7 @@ static PyGetSetDef function_getsetlist[] = { }; PyTypeObject function_type = { - PyObject_HEAD_INIT(0) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Boost.Python.function"), sizeof(function), 0, diff --git a/src/object/life_support.cpp b/src/object/life_support.cpp index 013253b5..b7e9aa86 100644 --- a/src/object/life_support.cpp +++ b/src/object/life_support.cpp @@ -36,8 +36,7 @@ extern "C" } PyTypeObject life_support_type = { - PyObject_HEAD_INIT(0)//(&PyType_Type) - 0, + PyVarObject_HEAD_INIT(NULL, 0)//(&PyType_Type) const_cast("Boost.Python.life_support"), sizeof(life_support), 0, @@ -92,9 +91,9 @@ PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient) if (nurse == Py_None || nurse == patient) return nurse; - if (life_support_type.ob_type == 0) + if (Py_TYPE(&life_support_type) == 0) { - life_support_type.ob_type = &PyType_Type; + Py_TYPE(&life_support_type) = &PyType_Type; PyType_Ready(&life_support_type); } diff --git a/src/object_operators.cpp b/src/object_operators.cpp index b6f1c5fb..b993245f 100644 --- a/src/object_operators.cpp +++ b/src/object_operators.cpp @@ -38,7 +38,13 @@ BOOST_PYTHON_DECL object operator op(object const& l, object const& r) \ BOOST_PYTHON_BINARY_OPERATOR(+, Add) BOOST_PYTHON_BINARY_OPERATOR(-, Subtract) BOOST_PYTHON_BINARY_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// We choose FloorDivide instead of TrueDivide to keep the semantic +// conform with C/C++'s '/' operator +BOOST_PYTHON_BINARY_OPERATOR(/, FloorDivide) +#else BOOST_PYTHON_BINARY_OPERATOR(/, Divide) +#endif BOOST_PYTHON_BINARY_OPERATOR(%, Remainder) BOOST_PYTHON_BINARY_OPERATOR(<<, Lshift) BOOST_PYTHON_BINARY_OPERATOR(>>, Rshift) @@ -58,7 +64,12 @@ BOOST_PYTHON_DECL object& operator op##=(object& l, object const& r) \ BOOST_PYTHON_INPLACE_OPERATOR(+, Add) BOOST_PYTHON_INPLACE_OPERATOR(-, Subtract) BOOST_PYTHON_INPLACE_OPERATOR(*, Multiply) +#if PY_VERSION_HEX >= 0x03000000 +// Same reason as above for choosing FloorDivide instead of TrueDivide +BOOST_PYTHON_INPLACE_OPERATOR(/, FloorDivide) +#else BOOST_PYTHON_INPLACE_OPERATOR(/, Divide) +#endif BOOST_PYTHON_INPLACE_OPERATOR(%, Remainder) BOOST_PYTHON_INPLACE_OPERATOR(<<, Lshift) BOOST_PYTHON_INPLACE_OPERATOR(>>, Rshift) diff --git a/src/object_protocol.cpp b/src/object_protocol.cpp old mode 100755 new mode 100644 index 8606fa2b..95c8c73e --- a/src/object_protocol.cpp +++ b/src/object_protocol.cpp @@ -103,6 +103,7 @@ namespace // slicing code copied directly out of the Python implementation static PyObject * apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ { +#if PY_VERSION_HEX < 0x03000000 PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; @@ -114,7 +115,9 @@ namespace // slicing code copied directly out of the Python implementation return NULL; return PySequence_GetSlice(u, ilow, ihigh); } - else { + else +#endif + { PyObject *slice = PySlice_New(v, w, NULL); if (slice != NULL) { PyObject *res = PyObject_GetItem(u, slice); @@ -130,6 +133,7 @@ namespace // slicing code copied directly out of the Python implementation assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) /* u[v:w] = x */ { +#if PY_VERSION_HEX < 0x03000000 PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; @@ -144,7 +148,9 @@ namespace // slicing code copied directly out of the Python implementation else return PySequence_SetSlice(u, ilow, ihigh, x); } - else { + else +#endif + { PyObject *slice = PySlice_New(v, w, NULL); if (slice != NULL) { int res; diff --git a/src/str.cpp b/src/str.cpp index ddde1a53..0bc225aa 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -10,16 +10,33 @@ namespace boost { namespace python { namespace detail { detail::new_reference str_base::call(object const& arg_) { return (detail::new_reference)PyObject_CallFunction( - (PyObject*)&PyString_Type, const_cast("(O)"), +#if PY_VERSION_HEX >= 0x03000000 + (PyObject*)&PyUnicode_Type, +#else + (PyObject*)&PyString_Type, +#endif + const_cast("(O)"), arg_.ptr()); } str_base::str_base() - : object(detail::new_reference(::PyString_FromString(""))) + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString("") +#else + ::PyString_FromString("") +#endif + )) {} str_base::str_base(const char* s) - : object(detail::new_reference(::PyString_FromString(s))) + : object(detail::new_reference( +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromString(s) +#else + ::PyString_FromString(s) +#endif + )) {} namespace { @@ -38,9 +55,12 @@ namespace { str_base::str_base(char const* start, char const* finish) : object( detail::new_reference( - ::PyString_FromStringAndSize( - start, str_size_as_py_ssize_t(finish - start) - ) +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + (start, str_size_as_py_ssize_t(finish - start)) ) ) {} @@ -48,9 +68,12 @@ str_base::str_base(char const* start, char const* finish) str_base::str_base(char const* start, std::size_t length) // new str : object( detail::new_reference( - ::PyString_FromStringAndSize( - start, str_size_as_py_ssize_t(length) - ) +#if PY_VERSION_HEX >= 0x03000000 + ::PyUnicode_FromStringAndSize +#else + ::PyString_FromStringAndSize +#endif + ( start, str_size_as_py_ssize_t(length) ) ) ) {} @@ -92,6 +115,7 @@ long str_base::count(object_cref sub, object_cref start, object_cref end) const return extract(this->attr("count")(sub,start,end)); } +#if PY_VERSION_HEX < 0x03000000 object str_base::decode() const { return this->attr("decode")(); @@ -106,6 +130,7 @@ object str_base::decode(object_cref encoding, object_cref errors) const { return this->attr("decode")(encoding,errors); } +#endif object str_base::encode() const { @@ -122,9 +147,16 @@ object str_base::encode(object_cref encoding, object_cref errors) const return this->attr("encode")(encoding,errors); } + +#if PY_VERSION_HEX >= 0x03000000 + #define _BOOST_PYTHON_ASLONG PyLong_AsLong +#else + #define _BOOST_PYTHON_ASLONG PyInt_AsLong +#endif + bool str_base::endswith(object_cref suffix) const { - bool result = PyInt_AsLong(this->attr("endswith")(suffix).ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("endswith")(suffix).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -135,7 +167,7 @@ BOOST_PYTHON_DEFINE_STR_METHOD(expandtabs, 1) long str_base::find(object_cref sub) const { - long result = PyInt_AsLong(this->attr("find")(sub).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -143,7 +175,7 @@ long str_base::find(object_cref sub) const long str_base::find(object_cref sub, object_cref start) const { - long result = PyInt_AsLong(this->attr("find")(sub,start).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -151,7 +183,7 @@ long str_base::find(object_cref sub, object_cref start) const long str_base::find(object_cref sub, object_cref start, object_cref end) const { - long result = PyInt_AsLong(this->attr("find")(sub,start,end).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("find")(sub,start,end).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -159,7 +191,7 @@ long str_base::find(object_cref sub, object_cref start, object_cref end) const long str_base::index(object_cref sub) const { - long result = PyInt_AsLong(this->attr("index")(sub).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -167,7 +199,7 @@ long str_base::index(object_cref sub) const long str_base::index(object_cref sub, object_cref start) const { - long result = PyInt_AsLong(this->attr("index")(sub,start).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -175,7 +207,7 @@ long str_base::index(object_cref sub, object_cref start) const long str_base::index(object_cref sub, object_cref start, object_cref end) const { - long result = PyInt_AsLong(this->attr("index")(sub,start,end).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("index")(sub,start,end).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -183,7 +215,7 @@ long str_base::index(object_cref sub, object_cref start, object_cref end) const bool str_base::isalnum() const { - bool result = PyInt_AsLong(this->attr("isalnum")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalnum")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -191,7 +223,7 @@ bool str_base::isalnum() const bool str_base::isalpha() const { - bool result = PyInt_AsLong(this->attr("isalpha")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("isalpha")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -199,7 +231,7 @@ bool str_base::isalpha() const bool str_base::isdigit() const { - bool result = PyInt_AsLong(this->attr("isdigit")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("isdigit")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -207,7 +239,7 @@ bool str_base::isdigit() const bool str_base::islower() const { - bool result = PyInt_AsLong(this->attr("islower")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("islower")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -215,7 +247,7 @@ bool str_base::islower() const bool str_base::isspace() const { - bool result = PyInt_AsLong(this->attr("isspace")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("isspace")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -223,7 +255,7 @@ bool str_base::isspace() const bool str_base::istitle() const { - bool result = PyInt_AsLong(this->attr("istitle")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("istitle")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -231,7 +263,7 @@ bool str_base::istitle() const bool str_base::isupper() const { - bool result = PyInt_AsLong(this->attr("isupper")().ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("isupper")().ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -246,7 +278,7 @@ BOOST_PYTHON_DEFINE_STR_METHOD(replace, 3) long str_base::rfind(object_cref sub) const { - long result = PyInt_AsLong(this->attr("rfind")(sub).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -254,7 +286,7 @@ long str_base::rfind(object_cref sub) const long str_base::rfind(object_cref sub, object_cref start) const { - long result = PyInt_AsLong(this->attr("rfind")(sub,start).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -262,7 +294,7 @@ long str_base::rfind(object_cref sub, object_cref start) const long str_base::rfind(object_cref sub, object_cref start, object_cref end) const { - long result = PyInt_AsLong(this->attr("rfind")(sub,start,end).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rfind")(sub,start,end).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -270,7 +302,7 @@ long str_base::rfind(object_cref sub, object_cref start, object_cref end) const long str_base::rindex(object_cref sub) const { - long result = PyInt_AsLong(this->attr("rindex")(sub).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -278,7 +310,7 @@ long str_base::rindex(object_cref sub) const long str_base::rindex(object_cref sub, object_cref start) const { - long result = PyInt_AsLong(this->attr("rindex")(sub,start).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -286,7 +318,7 @@ long str_base::rindex(object_cref sub, object_cref start) const long str_base::rindex(object_cref sub, object_cref start, object_cref end) const { - long result = PyInt_AsLong(this->attr("rindex")(sub,start,end).ptr()); + long result = _BOOST_PYTHON_ASLONG(this->attr("rindex")(sub,start,end).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -322,7 +354,7 @@ list str_base::splitlines(object_cref keepends) const bool str_base::startswith(object_cref prefix) const { - bool result = PyInt_AsLong(this->attr("startswith")(prefix).ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -330,7 +362,7 @@ bool str_base::startswith(object_cref prefix) const bool str_base::startswith(object_cref prefix, object_cref start) const { - bool result = PyInt_AsLong(this->attr("startswith")(prefix,start).ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; @@ -338,12 +370,14 @@ bool str_base::startswith(object_cref prefix, object_cref start) const bool str_base::startswith(object_cref prefix, object_cref start, object_cref end) const { - bool result = PyInt_AsLong(this->attr("startswith")(prefix,start,end).ptr()); + bool result = _BOOST_PYTHON_ASLONG(this->attr("startswith")(prefix,start,end).ptr()); if (PyErr_Occurred()) throw_error_already_set(); return result; } +#undef _BOOST_PYTHON_ASLONG + BOOST_PYTHON_DEFINE_STR_METHOD(strip, 0) BOOST_PYTHON_DEFINE_STR_METHOD(swapcase, 0) BOOST_PYTHON_DEFINE_STR_METHOD(title, 0) @@ -357,7 +391,12 @@ static struct register_str_pytype_ptr { const_cast( converter::registry::lookup(boost::python::type_id()) - ).m_class_object = &PyString_Type; + ) +#if PY_VERSION_HEX >= 0x03000000 + .m_class_object = &PyUnicode_Type; +#else + .m_class_object = &PyString_Type; +#endif } }register_str_pytype_ptr_; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5f66be63..686e9487 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -65,6 +65,20 @@ test-suite python # : # target-name # ] +[ run error_already_set.cpp /boost/python//boost_python/static $(PY) + : # no args + : # no input files + : # no requirements + : # target-name +] + +[ run error_already_set.cpp ../build//boost_python/shared /python//python + : # no args + : # no input files + : # no requirements + : exec-dynamic # target-name +] + [ bpl-test crossmod_exception : crossmod_exception.py crossmod_exception_a.cpp crossmod_exception_b.cpp @@ -77,12 +91,15 @@ bpl-test crossmod_exception [ bpl-test shared_ptr ] [ bpl-test enable_shared_from_this ] [ bpl-test andreas_beyer ] +[ bpl-test wrapper_held_type ] + +[ bpl-test polymorphism2_auto_ptr + : polymorphism2_auto_ptr.py polymorphism2.py polymorphism2_auto_ptr.cpp +] + [ bpl-test polymorphism ] [ bpl-test polymorphism2 ] -[ bpl-test wrapper_held_type ] -[ bpl-test polymorphism2_auto_ptr ] - [ bpl-test auto_ptr ] [ bpl-test minimal ] diff --git a/test/a_map_indexing_suite.cpp b/test/a_map_indexing_suite.cpp old mode 100755 new mode 100644 index 30b5ea03..07a0a6b9 --- a/test/a_map_indexing_suite.cpp +++ b/test/a_map_indexing_suite.cpp @@ -48,7 +48,11 @@ struct AFromPython static void* convertible(PyObject* obj_ptr) { +#if PY_VERSION_HEX >= 0x03000000 + if (!PyLong_Check(obj_ptr)) return 0; +#else if (!PyInt_Check(obj_ptr)) return 0; +#endif return obj_ptr; } @@ -60,7 +64,11 @@ struct AFromPython (boost::python::converter::rvalue_from_python_storage< A >*) data)-> storage.bytes; +#if PY_VERSION_HEX >= 0x03000000 + new (storage) A((int)PyLong_AsLong(obj_ptr)); +#else new (storage) A((int)PyInt_AsLong(obj_ptr)); +#endif data->convertible = storage; } }; diff --git a/test/crossmod_opaque.py b/test/crossmod_opaque.py index 2c8075bc..a7a3cf2c 100644 --- a/test/crossmod_opaque.py +++ b/test/crossmod_opaque.py @@ -1,4 +1,4 @@ -# -*- coding: iso-latin-1 -*- +# -*- coding: latin-1 -*- # Copyright Gottfried Ganßauge 2006. # Distributed under the Boost Software License, Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at diff --git a/test/defaults.py b/test/defaults.py index e68293df..cd51a4a4 100644 --- a/test/defaults.py +++ b/test/defaults.py @@ -2,13 +2,6 @@ # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) """ -# Use builtin True/False when available: ->>> try: -... assert(True == 1) -... except: -... True = 1 -... False = 0 - >>> from defaults_ext import * >>> bar(1) 'int(1); char(D); string(default); double(0.0); ' diff --git a/test/dict.py b/test/dict.py index 4f8018c3..a321beea 100644 --- a/test/dict.py +++ b/test/dict.py @@ -20,7 +20,7 @@ [(1, {'key2': 'value2'}), ('key1', 'value1')] >>> print dict_from_sequence([(1,1),(2,2),(3,3)]) {1: 1, 2: 2, 3: 3} ->>> test_templates(printer) +>>> test_templates(printer) #doctest: +NORMALIZE_WHITESPACE a test string 13 None diff --git a/test/exec.cpp b/test/exec.cpp index d6874d6b..afd02d60 100644 --- a/test/exec.cpp +++ b/test/exec.cpp @@ -59,7 +59,13 @@ void eval_test() void exec_test() { // Register the module with the interpreter - if (PyImport_AppendInittab(const_cast("embedded_hello"), initembedded_hello) == -1) + if (PyImport_AppendInittab(const_cast("embedded_hello"), +#if PY_VERSION_HEX >= 0x03000000 + PyInit_embedded_hello +#else + initembedded_hello +#endif + ) == -1) throw std::runtime_error("Failed to add embedded_hello to the interpreter's " "builtin modules"); // Retrieve the main module @@ -105,7 +111,7 @@ void exec_test_error() { // Execute a statement that raises a python exception. python::dict global; - python::object result = python::exec("print unknown \n", global, global); + python::object result = python::exec("print(unknown) \n", global, global); } void exercise_embedding_html() diff --git a/test/exec.py b/test/exec.py index 5a8faf79..c7bf28f3 100644 --- a/test/exec.py +++ b/test/exec.py @@ -2,5 +2,5 @@ # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -print 'Hello World !' -number = 42 +if 1: + number = 42 diff --git a/test/iterator.py b/test/iterator.py index 3cc641e6..96f5fd04 100644 --- a/test/iterator.py +++ b/test/iterator.py @@ -53,7 +53,7 @@ >>> ll.push_back(x) >>> x.push_back(7) >>> ll.push_back(x) ->>> for a in ll: +>>> for a in ll: #doctest: +NORMALIZE_WHITESPACE ... for b in a: ... print b, ... print diff --git a/test/list.cpp b/test/list.cpp index b573dcf7..3e9fcbe6 100644 --- a/test/list.cpp +++ b/test/list.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #define BOOST_ENABLE_ASSERT_HANDLER @@ -109,11 +111,16 @@ void exercise(list x, object y, object print) print("sorted:"); x.pop(2); // make sorting predictable + x.pop(2); // remove [1,2] so the list is sortable in py3k x.sort(); print(x); print("reverse sorted:"); +#if PY_VERSION_HEX >= 0x03000000 + x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true)))); +#else x.sort(¬cmp); +#endif print(x); list w; diff --git a/test/list.py b/test/list.py index c01f9268..8be21123 100644 --- a/test/list.py +++ b/test/list.py @@ -73,7 +73,7 @@ X(22) ... >>> y = X(42) ->>> exercise(letters, y, printer) +>>> exercise(letters, y, printer) #doctest: +NORMALIZE_WHITESPACE after append: ['h', 'e', 'l', 'l', 'o', '.', [1, 2], X(42), 5, X(3)] number of X(42) instances: 1 @@ -97,9 +97,9 @@ removing 666 reversing... ['y', 'x', X(3), [1, 2], '.', 'o', 'l', 'l', 'e', 'h'] sorted: -[[1, 2], '.', 'e', 'h', 'l', 'l', 'o', 'x', 'y'] +['.', 'e', 'h', 'l', 'l', 'o', 'x', 'y'] reverse sorted: -['y', 'x', 'o', 'l', 'l', 'h', 'e', '.', [1, 2]] +['y', 'x', 'o', 'l', 'l', 'h', 'e', '.'] ''' def run(args = None): diff --git a/test/long.py b/test/long.py index c2c41f6c..13d8775b 100644 --- a/test/long.py +++ b/test/long.py @@ -3,12 +3,12 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ''' >>> from long_ext import * ->>> new_long() -0L ->>> longify(42) -42L ->>> longify_string('300') -300L +>>> print new_long() +0 +>>> print longify(42) +42 +>>> print longify_string('300') +300 >>> is_long(20L) 'yes' >>> is_long('20') diff --git a/test/m1.cpp b/test/m1.cpp index ff075076..a873bc35 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -32,8 +32,7 @@ struct NoddyObject : PyObject }; PyTypeObject NoddyType = { - PyObject_HEAD_INIT(NULL) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Noddy"), sizeof(NoddyObject), 0, @@ -104,8 +103,7 @@ struct extract_simple_object }; PyTypeObject SimpleType = { - PyObject_HEAD_INIT(NULL) - 0, + PyVarObject_HEAD_INIT(NULL, 0) const_cast("Simple"), sizeof(SimpleObject), 0, diff --git a/test/m2.cpp b/test/m2.cpp index 2d1c0c9a..5bcdea60 100644 --- a/test/m2.cpp +++ b/test/m2.cpp @@ -13,6 +13,11 @@ #include #include "simple_type.hpp" +#if PY_VERSION_HEX >= 0x03000000 +# define PyString_FromString PyUnicode_FromString +# define PyInt_FromLong PyLong_FromLong +#endif + // Get a simple (by value) from the argument, and return the // string it holds. PyObject* unwrap_simple(simple x) @@ -52,6 +57,11 @@ PyObject* unwrap_int_const_ref(int const& x) return PyInt_FromLong(x); } +#if PY_VERSION_HEX >= 0x03000000 +# undef PyString_FromString +# undef PyInt_FromLong +#endif + // rewrap extracts a T from the argument, then converts the T back // to a PyObject* and returns it. template diff --git a/test/map_indexing_suite.py b/test/map_indexing_suite.py index 01fa943d..9d9e2b26 100644 --- a/test/map_indexing_suite.py +++ b/test/map_indexing_suite.py @@ -197,7 +197,7 @@ kiwi >>> tm["kimpo"] = X("bbb") >>> print_xmap(tm) [ (joel, aaa) (kimpo, bbb) ] ->>> for el in tm: +>>> for el in tm: #doctest: +NORMALIZE_WHITESPACE ... print el.key(), ... dom = el.data() joel kimpo diff --git a/test/opaque.py b/test/opaque.py index d10ac784..2ee0aa0c 100644 --- a/test/opaque.py +++ b/test/opaque.py @@ -1,4 +1,4 @@ -# -*- coding: iso-latin-1 -*- +# -*- coding: latin-1 -*- # Copyright Gottfried Ganßauge 2003..2006. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/pickle2.py b/test/pickle2.py index 54d9fddc..2ad663ff 100644 --- a/test/pickle2.py +++ b/test/pickle2.py @@ -29,7 +29,7 @@ r'''>>> import pickle2_ext >>> wd.__dict__ {'x': 1} >>> try: pstr = pickle.dumps(wd) - ... except RuntimeError, err: print err[0] + ... except RuntimeError, err: print err ... Incomplete pickle support (__getstate_manages_dict__ not set) ''' diff --git a/test/str.cpp b/test/str.cpp index 98e3cc26..0505b250 100644 --- a/test/str.cpp +++ b/test/str.cpp @@ -26,8 +26,13 @@ void work_with_string(object print) print(data.capitalize()); print('[' + data.center(30) + ']'); print(data.count("t")); +#if PY_VERSION_HEX < 0x03000000 print(data.encode("utf-8")); print(data.decode("utf-8")); +#else + print(data.encode("utf-8").attr("decode")("utf-8")); + print(data.encode("utf-8").attr("decode")("utf-8")); +#endif BOOST_ASSERT(!data.endswith("xx")); BOOST_ASSERT(!data.startswith("test")); diff --git a/test/str.py b/test/str.py index f8c89662..5f10580c 100644 --- a/test/str.py +++ b/test/str.py @@ -7,7 +7,7 @@ ... for x in args: print x, ... print ... ->>> work_with_string(printer) +>>> work_with_string(printer) #doctest: +NORMALIZE_WHITESPACE ['this', 'is', 'a', 'demo', 'string'] ['this', 'is', 'a', 'demo string'] this<->is<->a<->demo<->string diff --git a/test/test_builtin_converters.py b/test/test_builtin_converters.py index 7b0084fa..5a6c8c50 100644 --- a/test/test_builtin_converters.py +++ b/test/test_builtin_converters.py @@ -77,10 +77,10 @@ False >>> hex(rewrap_value_unsigned_long(0x80000001L)).replace('L','') '0x80000001' ->>> rewrap_value_long_long(42) -42L ->>> rewrap_value_unsigned_long_long(42) -42L +>>> rewrap_value_long_long(42) == 42 +True +>>> rewrap_value_unsigned_long_long(42) == 42 +True show that we have range checking. @@ -130,23 +130,13 @@ False >>> rewrap_value_string('yo, wassup?') 'yo, wassup?' ->>> try: -... if unicode: pass -... except: -... print "u'yo, wassup?'" -... else: -... eval("rewrap_value_wstring(u'yo, wassup?')") -u'yo, wassup?' - +>>> print rewrap_value_wstring(u'yo, wassup?') +yo, wassup? + test that overloading on unicode works: ->>> try: -... if unicode: pass -... except: -... print "u'yo, wassup?'" -... else: -... eval("rewrap_value_string(u'yo, wassup?')") -u'yo, wassup?' +>>> print rewrap_value_string(u'yo, wassup?') +yo, wassup? wrap strings with embedded nulls: @@ -198,10 +188,10 @@ u'yo, wassup?' 42 >>> rewrap_const_reference_unsigned_long(42) 42 ->>> rewrap_const_reference_long_long(42) -42L ->>> rewrap_const_reference_unsigned_long_long(42) -42L +>>> rewrap_const_reference_long_long(42) == 42 +True +>>> rewrap_const_reference_unsigned_long_long(42) == 42 +True >>> assert abs(rewrap_const_reference_float(4.2) - 4.2) < .000001 diff --git a/test/tuple.py b/test/tuple.py index 065b20ac..9d25aef4 100644 --- a/test/tuple.py +++ b/test/tuple.py @@ -11,7 +11,7 @@ ('t', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', ' ', 's', 't', 'r', 'i', 'n', 'g') >>> t1 = convert_to_tuple("this is") >>> t2 = (1,2,3,4) ->>> test_operators(t1,t2,printer) +>>> test_operators(t1,t2,printer) #doctest: +NORMALIZE_WHITESPACE ('t', 'h', 'i', 's', ' ', 'i', 's', 1, 2, 3, 4) >>> make_tuple() () diff --git a/test/upcast.cpp b/test/upcast.cpp old mode 100755 new mode 100644 index 9b66c3d8..255429f1 --- a/test/upcast.cpp +++ b/test/upcast.cpp @@ -13,7 +13,7 @@ int main() { PyTypeObject o; Y y; - BOOST_TEST(&boost::python::upcast(&o)->ob_refcnt == &o.ob_refcnt); - BOOST_TEST(&boost::python::upcast(&y)->ob_refcnt == &y.ob_refcnt); + BOOST_TEST(&Py_REFCNT(boost::python::upcast(&o)) == &Py_REFCNT(&o)); + BOOST_TEST(&Py_REFCNT(boost::python::upcast(&y)) == &Py_REFCNT(&y)); return boost::report_errors(); }