diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index bf495a82..959a9b6f 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -45,6 +45,7 @@ lib boost_python wrapper.cpp import.cpp exec.cpp + object/function_doc_signature.cpp : # requirements static:BOOST_PYTHON_STATIC_LIB BOOST_PYTHON_SOURCE diff --git a/doc/news.html b/doc/news.html index 6e637a04..45a5b2f5 100644 --- a/doc/news.html +++ b/doc/news.html @@ -32,7 +32,43 @@
-
Current CVS
+
Current SVN
+ +
+
    +
  • Pythonic signatures are now automatically appended to the + docstrings. + +
  • Use docstring_options.hpp header + control the content of docstrings. + +
  • This new feature increases the size of the modules by about 14%. + If this is not acceptable it can be turned off by defining the macro + BOOST_PYTHON_NO_PY_SIGNATURES. Modules compiled with and without the macro + defined are compatible. +
  • +
  • If BOOST_PYTHON_NO_PY_SIGNATURES is undefined, this version defines the + macro BOOST_PYTHON_SUPPORTS_PY_SIGNATURES. This allows writing code that will compile + with older version of Boost.Python (see here). +
  • +
  • By defining BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE, and at a cost + of another 14% size increase, proper pythonic type is generated for the "self" + parameter of the __init__ methods. +
  • + +
  • To support this new feature changes were made to the + to_python_converter.hpp, + default_call_policies, + ResultConverter, + CallPolicies and some others. + Efforts were made not to have interface breaking changes. +
  • + +
+
+ +
12 May 2007 - 1.34.0 release
    diff --git a/doc/v2/CallPolicies.html b/doc/v2/CallPolicies.html index 5efbdcdb..9c00dbbe 100644 --- a/doc/v2/CallPolicies.html +++ b/doc/v2/CallPolicies.html @@ -8,7 +8,7 @@ - + Boost.Python - CallPolicies Concept @@ -60,6 +60,7 @@
  • postcall - Python argument tuple and result management after the wrapped object is invoked
  • +
  • extract_return_type - metafunction for extracting the return type from a given signature type sequence
  • CallPolicies Composition

    @@ -132,7 +133,16 @@ reference count must be decremented; if another existing object is returned, its reference count must be incremented. - + + P::extract_return_type + + A model of Metafunction. + + An MPL unary Metafunction used extract the return type from a given signature. By default it is derived from mpl::front. + + Models of CallPolicies are required to be CopyConstructible.
    diff --git a/doc/v2/ResultConverter.html b/doc/v2/ResultConverter.html index 671ebc77..f0932bda 100644 --- a/doc/v2/ResultConverter.html +++ b/doc/v2/ResultConverter.html @@ -1,10 +1,12 @@ + + - + Boost.Python - ResultConverter Concept @@ -24,10 +26,12 @@
    Introduction
    Concept Requirements
    -
    -
    ResultConverter Concept
    -
    ResultConverterGenerator Concept
    -
    +
    +
    +
    ResultConverter Concept
    +
    ResultConverterGenerator Concept
    +
    +

    Introduction

    @@ -79,6 +83,13 @@ denotes an object of type R. href="http://www.python.org/doc/current/api/exceptionHandling.html#l2h-71">PyErr_Occurred should return non-zero. + + c.get_pytype() + PyTypeObject const* + A pointer to a Python Type object corresponding to result of the conversion, + or 0. Used for documentation generation. If 0 is returned + the generated type in the documentation will be object . +

    ResultConverterGenerator Concept

    diff --git a/doc/v2/configuration.html b/doc/v2/configuration.html index 76ca48f8..84a1e098 100644 --- a/doc/v2/configuration.html +++ b/doc/v2/configuration.html @@ -139,6 +139,41 @@ compares typeid(T).name() instead of using and comparing the std::type_info objects directly. + + BOOST_PYTHON_NO_PY_SIGNATURES + + not defined + + If defined for a module no pythonic signatures are generated + for the docstrings of the module functions, and no python type is associated with any + of the converters registered by the module. This also reduces the binary size of the + module by about 14% (gcc compiled).
    + If defined for the boost_python runtime library, the default for the + docstring_options.enable_py_signatures() is set to false. + + + + + BOOST_PYTHON_SUPPORTS_PY_SIGNATURES + + defined if BOOST_PYTHON_NO_PY_SIGNATURES is undefined + + This macro is defined to enable a smooth transition from older Boost.Python versions + which do not support pythonic signatures. For example usage see + here. + + + + + BOOST_PYTHON_PY_SIGNATURES_PROPER_INIT_SELF_TYPE + + not defined + + If defined the python type of __init__ method "self" parameters + is properly generated, otherwise object is used. It is undefined + by default because it increases the binary size of the module by about 14% (gcc compiled). + +
    diff --git a/doc/v2/default_call_policies.html b/doc/v2/default_call_policies.html index 772b5c63..e28da03e 100644 --- a/doc/v2/default_call_policies.html +++ b/doc/v2/default_call_policies.html @@ -82,6 +82,7 @@ namespace boost { namespace python static PyObject* postcall(PyObject*, PyObject* result); typedef default_result_converter result_converter; + template <class Sig> struct extract_return_type : mpl::front<Sig>{}; }; }} @@ -161,7 +162,7 @@ struct return_value_policy : Base

    Revised - 13 November, 2002 + 11 June, 2007 diff --git a/doc/v2/docstring_options.html b/doc/v2/docstring_options.html index 0e4a9cde..a6e9041e 100644 --- a/doc/v2/docstring_options.html +++ b/doc/v2/docstring_options.html @@ -103,6 +103,8 @@ namespace boost { namespace python { docstring_options(bool show_user_defined, bool show_signatures); + docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures); + ~docstring_options(); void @@ -117,6 +119,18 @@ namespace boost { namespace python { void enable_signatures(); + void + disable_py_signatures(); + + void + enable_py_signatures(); + + void + disable_cpp_signatures(); + + void + enable_cpp_signatures(); + void disable_all(); @@ -139,7 +153,7 @@ docstring_options(bool show_all=true); object which controls the appearance of function and member-function docstrings defined in the code that follows. If show_all is true, both the - user-defined docstrings and the automatically generated C++ + user-defined docstrings and the automatically generated Python and C++ signatures are shown. If show_all is false the __doc__ attributes are None. @@ -154,12 +168,29 @@ docstring_options(bool show_user_defined, bool show_signatures); member-function docstrings defined in the code that follows. Iff show_user_defined is true, the user-defined docstrings are shown. Iff - show_signatures is true, C++ + show_signatures is true, Python and C++ signatures are automatically added. If both show_user_defined and show_signatures are false, the __doc__ attributes are None.

+
+docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures);
+
+ +
+
Effects: Constructs a docstring_options + object which controls the appearance of function and + member-function docstrings defined in the code that follows. + Iff show_user_defined is true, the + user-defined docstrings are shown. Iff + show_py_signatures is true, Python + signatures are automatically added. Iff + show_cpp_signatures is true, C++ + signatures are automatically added. If all parameters are + false, the __doc__ attributes are + None.
+

Class @@ -186,6 +217,10 @@ void disable_user_defined(); void enable_user_defined(); void disable_signatures(); void enable_signatures(); +void disable_py_signatures(); +void enable_py_signatures(); +void disable_cpp_signatures(); +void enable_cpp_signatures(); void disable_all(); void enable_all(); @@ -196,7 +231,7 @@ void enable_all(); *_user_defined() and *_signatures() member functions are provided for fine-grained control. The *_all() member functions are convenient shortcuts - to manipulate both settings simultaneously. + to manipulate all settings simultaneously.

Examples

@@ -219,7 +254,7 @@ BOOST_PYTHON_MODULE(demo)
 >>> import demo
 >>> print demo.foo.__doc__
-foo doc
+foo() -> None : foo doc
 C++ signature:
     foo(void) -> void
 
If compiled with @@ -253,21 +288,33 @@ BOOST_PYTHON_MODULE(demo) def("foo3", foo3, arg("f"), "foo3 doc"); doc_options.enable_user_defined(); def("foo4", foo4, arg("d"), "foo4 doc"); + doc_options.enable_py_signatures(); + def("foo5", foo4, arg("d"), "foo5 doc"); + doc_options.disable_py_signatures(); + doc_options.enable_cpp_signatures(); + def("foo6", foo4, arg("d"), "foo6 doc"); } Python code:
 >>> import demo
 >>> print demo.foo1.__doc__
-foo1 doc
+foo1( (int)i) -> int : foo1 doc
 C++ signature:
     foo1(int i) -> int
 >>> print demo.foo2.__doc__
+foo2( (int)l) -> int : 
 C++ signature:
     foo2(long l) -> int
 >>> print demo.foo3.__doc__
 None
 >>> print demo.foo4.__doc__
 foo4 doc
+>>> print demo.foo5.__doc__
+foo5( (float)d) -> int : foo5 doc
+>>> print demo.foo6.__doc__
+foo6 doc
+C++ signature:
+    foo6(double d) -> int
 

Wrapping from multiple C++ scopes

diff --git a/doc/v2/enum.html b/doc/v2/enum.html index 1bed29aa..270ba20b 100644 --- a/doc/v2/enum.html +++ b/doc/v2/enum.html @@ -89,7 +89,7 @@ namespace boost { namespace python template <class T> class enum_ : public object { - enum_(char const* name); + enum_(char const* name, char const* doc = 0); enum_<T>& value(char const* name, T); enum_<T>& export_values(); }; @@ -99,7 +99,7 @@ namespace boost { namespace python

Class template enum_ constructors

-enum_(char const* name);
+enum_(char const* name, char const* doc=0);
 
@@ -131,7 +131,7 @@ inline enum_<T>& value(char const* name, T x);
Effects: adds an instance of the wrapped enumeration type with value x to the type's dictionary as the - named attribute
. + named attribute.
Returns: *this
@@ -146,7 +146,7 @@ inline enum_<T>& export_values();
Effects: sets attributes in the current scope with the same names and values as all enumeration values exposed so far - by calling value()
. + by calling value().
Returns: *this
diff --git a/doc/v2/function_doc_signature.html b/doc/v2/function_doc_signature.html new file mode 100644 index 00000000..e439a77a --- /dev/null +++ b/doc/v2/function_doc_signature.html @@ -0,0 +1,216 @@ + + + + + + + + + + + Boost.Python - + <boost/python/doobject/function_doc_signature.hpp> + + + + + + + + + +
+

C++ Boost

+
+

Boost.Python

+ +

Header + <boost/python/object/function_doc_signature.hpp>

+
+
+ +

Contents

+ +
+
Introduction
+ +
Classes
+ +
+
+
Class + function_doc_signature_generator
+ +
+
+
Class + function_doc_signature_generator synopsis
+ +
+
+
+
+ +
Examples
+
+
+ +

Introduction

+ +

Boost.Python supports docstrings with automatic + appending of Pythonic and C++ signatures. This feature is implemented + by class function_doc_signature_generator + The class uses all of the overloads, supplied arg names and default values, as well as + the user-defined docstrings, to generate documentation for a given function.

+ +

Classes

+ +

Class + function_doc_signature_generator

+ +

+ The class has only one public function which returns a list of strings documenting the + overloads of a function. +

+ +

Class + function_doc_signature_generator synopsis

+
+namespace boost { namespace python { namespace objects {
+
+    class function_doc_signature_generator 
+    {
+      public:
+          static list function_doc_signatures(function const *f);
+    };
+
+}}}
+
+ + +

Examples

+ +

Docstrings generated with function_doc_signature_generator

+
+#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/args.hpp>
+#include <boost/python/tuple.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/overloads.hpp>
+#include <boost/python/raw_function.hpp>
+
+using namespace boost::python;
+
+tuple f(int x = 1, double y = 4.25, char const* z = "wow")
+{
+    return make_tuple(x, y, z);
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3)
+
+
+struct X
+{
+    tuple f(int x = 1, double y = 4.25, char const* z = "wow")
+    {
+        return make_tuple(x, y, z);
+    }
+};
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3)
+
+tuple raw_func(tuple args, dict kw)
+{
+    return make_tuple(args, kw);
+}
+
+BOOST_PYTHON_MODULE(args_ext)
+{
+    def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow")
+        , "This is f's docstring"
+        );
+
+    def("raw", raw_function(raw_func));
+
+    def("f1", f, f_overloads("f1's docstring", args("x", "y", "z")));
+
+
+    class_<X>("X", "This is X's docstring", init<>(args("self")))
+        .def("f", &X::f
+             , "This is X.f's docstring"
+             , args("self","x", "y", "z"))
+
+        ;
+
+}
+
+
+Python code: +
+>>> import args_ext
+>>> help(args_ext)
+Help on module args_ext:
+
+NAME
+    args_ext
+
+FILE
+    args_ext.pyd
+
+CLASSES
+    Boost.Python.instance(__builtin__.object)
+        X
+
+    class X(Boost.Python.instance)
+     |  This is X's docstring
+     |
+     |  Method resolution order:
+     |      X
+     |      Boost.Python.instance
+     |      __builtin__.object
+     |
+     |  Methods defined here:
+     |
+     |  __init__(...)
+     |      __init__( (object)self) -> None :
+     |       C++ signature:
+     |           void __init__(struct _object *)
+     |
+     |  f(...)
+     |      f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring
+     |      C++ signature:
+     |          class boost::python::tuple f(struct X {lvalue},int,double,char const *)
+     |
+     |    .................
+     |
+FUNCTIONS
+    f(...)
+        f([ (int)x=1 [, (float)y=4.25 [, (str)z='wow']]]) -> tuple : This is f's docstring
+        C++ signature:
+            class boost::python::tuple f([ int=1 [,double=4.25 [,char const *='wow']]])
+
+    f1(...)
+        f1([ (int)x [, (float)y [, (str)z]]]) -> tuple : f1's docstring
+        C++ signature:
+            class boost::python::tuple f1([ int [,double [,char const *]]])
+
+    raw(...)
+        object raw(tuple args, dict kwds) :
+        C++ signature:
+            object raw(tuple args, dict kwds)
+
+
+
+ +

© Copyright Nikolay Mladenov 2007.

+ + diff --git a/doc/v2/pytype_function.html b/doc/v2/pytype_function.html new file mode 100644 index 00000000..fcc2a7f9 --- /dev/null +++ b/doc/v2/pytype_function.html @@ -0,0 +1,370 @@ + + + + + + + + + + + Boost.Python - + <boost/python/doobject/pytype_function.hpp> + + + + + + + + + +
+

C++ Boost

+
+

Boost.Python

+ +

Header + <boost/python/converter/pytype_function.hpp>

+
+
+ +

Contents

+ +
+
Introduction
+ +
Classes
+ +
+
+
Class + wrap_pytype
+ +
+
+
Class + wrap_pytype synopsis
+ +
+
+
+
+ +
+
+
Class + registered_pytype
+ +
+
+
Class + registered_pytype synopsis
+ +
+
+
+
+ +
+
+
Class + expected_from_python_type
+ +
+
+
Class + expected_from_python_type synopsis
+ +
+
+
+
+ +
+
+
Class + to_python_target_type
+ +
+
+
Class + to_python_target_type synopsis
+ +
+
+
+
+ +
Examples
+
+
+ +

Introduction

+ +

To support Pythonic signatures the converters should supply a get_pytype function + returning a pointer to the associated PyTypeObject. See for example + ResultConverter or + to_python_converter. + The classes in this header file are meant to be used when implmenting get_pytype. + There are also _direct versions of the templates of class T which + should be used with undecorated type parameter, expected to be in the conversion registry when the module loads. +

+ +

Classes

+ +

Class + wrap_pytype

+ +

+ This template generates a static get_pytype member returning the template parameter. +

+ +

Class + wrap_pytype synopsis

+
+namespace boost { namespace python { namespace converter{
+
+    template < PyTypeObject const *pytype >
+    class wrap_pytype 
+    {
+      public:
+          static PyTypeObject const *get_pytype(){return pytype; }
+    };
+
+}}}
+
+ + +

Class + registered_pytype

+ +

+ This template should be used with template parameters which are (possibly decorated) + types exported to python using class_. + The generated a static get_pytype member + returns the corresponding python type. +

+ +

Class + registered_pytype synopsis

+
+namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class registered_pytype 
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+ + +

Class + expected_from_python_type

+ +

+ This template generates a static get_pytype member which inspects the registered + from_python converters for the type T and returns a matching python type. +

+ +

Class + expected_from_python_type synopsis

+
+namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class expected_from_python_type 
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+ + +

Class + to_python_target_type

+ +

+ This template generates a static get_pytype member returning the + python type to which T can be converted. +

+ +

Class + to_python_target_type synopsis

+
+namespace boost { namespace python { namespace converter{
+
+    template < class T >
+    class to_python_target_type 
+    {
+      public:
+          static PyTypeObject const *get_pytype();
+    };
+
+}}}
+
+ + +

Examples

+ + This example presumes that someone has implemented the standard noddy example + module from the Python documentation, and placed the corresponding + declarations in "noddy.h". Because + noddy_NoddyObject is the ultimate trivial extension type, + the example is a bit contrived: it wraps a function for which all + information is contained in the type of its return value. + +

C++ module definition

+
+#include <boost/python/reference.hpp>
+#include <boost/python/module.hpp>
+#include "noddy.h"
+
+struct tag {};
+tag make_tag() { return tag(); }
+
+using namespace boost::python;
+
+struct tag_to_noddy 
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
+: wrap_pytype<&noddy_NoddyType> //inherits get_pytype from wrap_pytype
+#endif
+{
+    static PyObject* convert(tag const& x)
+    {
+        return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
+    }
+};
+
+BOOST_PYTHON_MODULE(to_python_converter)
+{
+    def("make_tag", make_tag);
+    to_python_converter<tag, tag_to_noddy
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+          , true
+#endif
+          >(); //"true" because tag_to_noddy has member get_pytype
+}
+
+ + +

The following example registers to and from python converters using the templates +expected_from_python_type and to_pyhton_target_type. +

+
+#include <boost/python/module.hpp>
+#include <boost/python/def.hpp>
+#include <boost/python/extract.hpp>
+#include <boost/python/to_python_converter.hpp>
+#include <boost/python/class.hpp>
+
+using namespace boost::python;
+
+struct A
+{
+};
+
+struct B
+{
+  A a;
+  B(const A& a_):a(a_){}
+};
+
+// Converter from A to python int
+struct BToPython 
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //unnecessary overhead if py signatures are not supported
+   : converter::to_python_target_type<A>  //inherits get_pytype
+#endif
+{
+  static PyObject* convert(const B& b)
+  {
+    return incref(object(b.a).ptr());
+  }
+};
+
+// Conversion from python int to A
+struct BFromPython
+{
+  BFromPython()
+  {
+    boost::python::converter::registry::push_back
+        ( &convertible
+        , &construct
+        , type_id< B >()
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+        , &converter::expected_from_python_type<A>::get_pytype//convertible to A can be converted to B
+#endif
+        );
+  }
+
+  static void* convertible(PyObject* obj_ptr)
+  {
+      extract<const A&> ex(obj_ptr);
+      if (!ex.check()) return 0;
+      return obj_ptr;
+  }
+
+  static void construct(
+      PyObject* obj_ptr,
+      converter::rvalue_from_python_stage1_data* data)
+  {
+    void* storage = (
+        (converter::rvalue_from_python_storage< B >*)data)-> storage.bytes;
+
+    extract<const A&> ex(obj_ptr);
+    new (storage) B(ex());
+    data->convertible = storage;
+  }
+};
+
+
+B func(const B& b) { return b ; }
+
+BOOST_PYTHON_MODULE(pytype_function_ext)
+{
+  to_python_converter< B , BToPython
+#if defined BOOST_PYTHON_SUPPORTS_PY_SIGNATURES //invalid if py signatures are not supported
+             ,true 
+#endif
+             >(); //has get_pytype
+  BFromPython();
+
+  class_<A>("A") ;
+
+  def("func", &func);
+
+}
+
+
+
+>>> from pytype_function_ext import *
+>>> print func.__doc__
+func( (A)arg1) -> A :
+    C++ signature:
+         struct B func(struct B)
+
+ + +

© Copyright Nikolay Mladenov 2007.

+ + diff --git a/doc/v2/reference.html b/doc/v2/reference.html index 06a76d2c..7d8252fa 100644 --- a/doc/v2/reference.html +++ b/doc/v2/reference.html @@ -609,6 +609,66 @@
+
+ + +

Function documentation

+ +
+
function_doc_signature.hpp
+ +
+
+
Classes
+ +
+
+
function_doc_signature_generator
+ +
+
+
+
+
+
+
pytype_function.hpp
+ +
+
+
Classes
+ +
+
+
wrap_pytype
+ +
+
+
expected_from_python_type
+ +
+
+
to_python_target_type
+ +
+
+
registered_pytype
+ +
+
+
+
+
+
+
diff --git a/doc/v2/return_arg.html b/doc/v2/return_arg.html index 3ecfc898..a5ded0ce 100755 --- a/doc/v2/return_arg.html +++ b/doc/v2/return_arg.html @@ -125,6 +125,8 @@ namespace boost { namespace python { static PyObject* postcall(PyObject*, PyObject* result); struct result_converter{ template <class T> struct apply; }; + template <class Sig> struct extract_return_type : mpl::at_c<Sig, arg_pos>{}; + }; }} diff --git a/doc/v2/to_python_converter.html b/doc/v2/to_python_converter.html index 808db4b3..546cd8a1 100644 --- a/doc/v2/to_python_converter.html +++ b/doc/v2/to_python_converter.html @@ -108,6 +108,23 @@ A class type whose static member function convert does the real work of the conversion. + + bool has_get_pytype = false + + + PyTypeObject const * p = Conversion::get_pytype() . + + Optional member - if Conversion has get_pytype member supply + true for this parameters. + If present get_pytype is used to document the return type + of functions using this conversion. The get_pytype may be implemented + using the classes and functions + from pytype_function.hpp + NOTE : For backward compatibility this parameter may be passed after + checking if BOOST_PYTHON_SUPPORTS_PY_SIGNATURES is defined (see + here). + +

Class template @@ -115,7 +132,7 @@
 namespace boost { namespace python
 {
-  template <class T, class Conversion>
+  template <class T, class Conversion, bool convertion_has_get_pytype_member=false>
   struct to_python_converter
   {
       to_python_converter();
@@ -160,12 +177,16 @@ struct tag_to_noddy
     {
         return PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
     }
+    static PyTypeObject const* get_pytype()
+    {
+        return &noddy_NoddyType;
+    }
 };
 
 BOOST_PYTHON_MODULE(to_python_converter)
 {
     def("make_tag", make_tag);
-    to_python_converter<tag, tag_to_noddy>();
+    to_python_converter<tag, tag_to_noddy, true>(); //"true" because tag_to_noddy has member get_pytype
 }
 
@@ -195,7 +216,7 @@ BOOST_PYTHON_MODULE(to_python_converter)

Revised - 13 November, 2002 + 11 June, 2007

diff --git a/example/std_pair.cpp b/example/std_pair.cpp index 4a696ba5..edf98dd6 100644 --- a/example/std_pair.cpp +++ b/example/std_pair.cpp @@ -18,6 +18,7 @@ namespace { // Avoid cluttering the global namespace. return boost::python::incref( boost::python::make_tuple(p.first, p.second).ptr()); } + static PyTypeObject const *get_pytype () {return &PyTuple_Type; } }; // Helper for convenience. @@ -28,7 +29,9 @@ namespace { // Avoid cluttering the global namespace. { boost::python::to_python_converter< std::pair, - std_pair_to_tuple >(); + std_pair_to_tuple, + true //std_pair_to_tuple has get_pytype + >(); } }; diff --git a/include/boost/python/converter/as_to_python_function.hpp b/include/boost/python/converter/as_to_python_function.hpp index b343b4db..19a3efaa 100644 --- a/include/boost/python/converter/as_to_python_function.hpp +++ b/include/boost/python/converter/as_to_python_function.hpp @@ -39,6 +39,9 @@ struct as_to_python_function // but c'est la vie. return ToPython::convert(*const_cast(static_cast(x))); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const * get_pytype() { return ToPython::get_pytype(); } +#endif }; }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/builtin_converters.hpp b/include/boost/python/converter/builtin_converters.hpp index dddb154c..df32ad21 100644 --- a/include/boost/python/converter/builtin_converters.hpp +++ b/include/boost/python/converter/builtin_converters.hpp @@ -47,7 +47,7 @@ namespace detail } // Use expr to create the PyObject corresponding to x -# define BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T, expr) \ +# define BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T, expr, pytype)\ template <> struct to_python_value \ : detail::builtin_to_python \ { \ @@ -55,6 +55,10 @@ namespace detail { \ return (expr); \ } \ + inline PyTypeObject const* get_pytype() const \ + { \ + return (pytype); \ + } \ }; \ template <> struct to_python_value \ : detail::builtin_to_python \ @@ -63,6 +67,10 @@ namespace detail { \ return (expr); \ } \ + inline PyTypeObject const* get_pytype() const \ + { \ + return (pytype); \ + } \ }; # define BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T, expr) \ @@ -77,25 +85,25 @@ namespace detail } // Specialize argument and return value converters for T using expr -# define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr) \ - BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T,expr) \ +# define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr, pytype) \ + BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(T,expr, pytype) \ BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE(T,expr) // Specialize converters for signed and unsigned T to Python Int # define BOOST_PYTHON_TO_INT(T) \ - BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x)) \ + BOOST_PYTHON_TO_PYTHON_BY_VALUE(signed T, ::PyInt_FromLong(x), &PyInt_Type) \ BOOST_PYTHON_TO_PYTHON_BY_VALUE( \ unsigned T \ , static_cast(x) > static_cast( \ (std::numeric_limits::max)()) \ ? ::PyLong_FromUnsignedLong(x) \ - : ::PyInt_FromLong(x)) + : ::PyInt_FromLong(x), &PyInt_Type) // Bool is not signed. #if PY_VERSION_HEX >= 0x02030000 -BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyBool_FromLong(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyBool_FromLong(x), &PyBool_Type) #else -BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyInt_FromLong(x)) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(bool, ::PyInt_FromLong(x), &PyInt_Type) #endif // note: handles signed char and unsigned char, but not char (see below) @@ -108,25 +116,25 @@ 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)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(unsigned BOOST_PYTHON_LONG_LONG, ::PyLong_FromUnsignedLongLong(x)) +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) # endif # undef BOOST_TO_PYTHON_INT -BOOST_PYTHON_TO_PYTHON_BY_VALUE(char, converter::do_return_to_python(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(char const*, converter::do_return_to_python(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::string, ::PyString_FromStringAndSize(x.data(),implicit_cast(x.size()))) +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) #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()))) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::wstring, ::PyUnicode_FromWideChar(x.data(),implicit_cast(x.size())), &PyString_Type) # endif -BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, ::PyFloat_FromDouble(x)) -BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x)) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) -BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag())) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(float, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(double, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(long double, ::PyFloat_FromDouble(x), &PyFloat_Type) +BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE(PyObject*, converter::do_return_to_python(x), 0) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) +BOOST_PYTHON_TO_PYTHON_BY_VALUE(std::complex, ::PyComplex_FromDoubles(x.real(), x.imag()), &PyComplex_Type) # undef BOOST_PYTHON_RETURN_TO_PYTHON_BY_VALUE # undef BOOST_PYTHON_ARG_TO_PYTHON_BY_VALUE diff --git a/include/boost/python/converter/pyobject_traits.hpp b/include/boost/python/converter/pyobject_traits.hpp index ce7d3fb4..03ef4460 100644 --- a/include/boost/python/converter/pyobject_traits.hpp +++ b/include/boost/python/converter/pyobject_traits.hpp @@ -18,6 +18,9 @@ struct pyobject_traits // All objects are convertible to PyObject static bool check(PyObject*) { return true; } static PyObject* checked_downcast(PyObject* x) { return x; } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const* get_pytype() { return 0; } +#endif }; // diff --git a/include/boost/python/converter/pyobject_type.hpp b/include/boost/python/converter/pyobject_type.hpp index a02974cd..526f9f9d 100644 --- a/include/boost/python/converter/pyobject_type.hpp +++ b/include/boost/python/converter/pyobject_type.hpp @@ -14,7 +14,7 @@ BOOST_PYTHON_DECL PyObject* checked_downcast_impl(PyObject*, PyTypeObject*); // Used as a base class for specializations which need to provide // Python type checking capability. template -struct pyobject_type +struct pyobject_type { static bool check(PyObject* x) { @@ -27,6 +27,9 @@ struct pyobject_type (checked_downcast_impl)(x, pytype) ); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const* get_pytype() { return pytype; } +#endif }; }}} // namespace boost::python::converter diff --git a/include/boost/python/converter/pytype_function.hpp b/include/boost/python/converter/pytype_function.hpp new file mode 100755 index 00000000..95d0f66d --- /dev/null +++ b/include/boost/python/converter/pytype_function.hpp @@ -0,0 +1,132 @@ +// Copyright David Abrahams 2002, Nikolay Mladenov 2007. +// 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) +#ifndef WRAP_PYTYPE_NM20070606_HPP +# define WRAP_PYTYPE_NM20070606_HPP + +# include +# include +# include + + +namespace boost { namespace python { + +namespace converter +{ +template +struct wrap_pytype +{ + static PyTypeObject const* get_pytype() + { + return python_type; + } +}; + +typedef PyTypeObject const* (*pytype_function)(); + +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + + + +namespace detail +{ +struct unwind_type_id_helper{ + typedef python::type_info result_type; + template + static result_type execute(U* ){ + return python::type_id(); + } +}; + +template +inline python::type_info unwind_type_id_(boost::type* = 0, mpl::false_ * =0) +{ + return boost::python::detail::unwind_type (); +} + +inline python::type_info unwind_type_id_(boost::type* = 0, mpl::true_* =0) +{ + return type_id(); +} + +template +inline python::type_info unwind_type_id(boost::type* p= 0) +{ + return unwind_type_id_(p, (mpl::bool_::value >*)0 ); +} +} + + +template +struct expected_pytype_for_arg +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) + ); + return r ? r->expected_from_python_type(): 0; + } +}; + + +template +struct registered_pytype +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type*) 0, (mpl::bool_::value >*)0 ) + ); + return r ? r->m_class_object: 0; + } +}; + + +template +struct registered_pytype_direct +{ + static PyTypeObject const* get_pytype() + { + return registered::converters.m_class_object; + } +}; + +template +struct expected_from_python_type : expected_pytype_for_arg{}; + +template +struct expected_from_python_type_direct +{ + static PyTypeObject const* get_pytype() + { + return registered::converters.expected_from_python_type(); + } +}; + +template +struct to_python_target_type +{ + static PyTypeObject const *get_pytype() + { + const converter::registration *r=converter::registry::query( + detail::unwind_type_id_((boost::type*)0, (mpl::bool_::value >*)0 ) + ); + return r ? r->to_python_target_type(): 0; + } +}; + +template +struct to_python_target_type_direct +{ + static PyTypeObject const *get_pytype() + { + return registered::converters.to_python_target_type(); + } +}; +#endif + +}}} // namespace boost::python + +#endif // WRAP_PYTYPE_NM20070606_HPP diff --git a/include/boost/python/converter/registrations.hpp b/include/boost/python/converter/registrations.hpp index 0f335f95..7ef74e8f 100644 --- a/include/boost/python/converter/registrations.hpp +++ b/include/boost/python/converter/registrations.hpp @@ -27,6 +27,7 @@ struct rvalue_from_python_chain { convertible_function convertible; constructor_function construct; + PyTypeObject const* (*expected_pytype)(); rvalue_from_python_chain* next; }; @@ -43,6 +44,11 @@ struct BOOST_PYTHON_DECL registration // exception if no class has been registered. PyTypeObject* get_class_object() const; + // Return common denominator of the python class objects, + // convertable to target. Inspects the m_class_object and the value_chains. + PyTypeObject const* expected_from_python_type() const; + PyTypeObject const* to_python_target_type() const; + public: // data members. So sue me. const python::type_info target_type; @@ -57,6 +63,8 @@ struct BOOST_PYTHON_DECL registration // The unique to_python converter for the associated C++ type. to_python_function_t m_to_python; + PyTypeObject const* (*m_to_python_target_type)(); + // True iff this type is a shared_ptr. Needed for special rvalue // from_python handling. @@ -77,6 +85,7 @@ inline registration::registration(type_info target_type, bool is_shared_ptr) , rvalue_chain(0) , m_class_object(0) , m_to_python(0) + , m_to_python_target_type(0) , is_shared_ptr(is_shared_ptr) {} diff --git a/include/boost/python/converter/registry.hpp b/include/boost/python/converter/registry.hpp index 5492edf7..e037bbcc 100644 --- a/include/boost/python/converter/registry.hpp +++ b/include/boost/python/converter/registry.hpp @@ -27,16 +27,17 @@ namespace registry // Return a pointer to the corresponding registration, if one exists BOOST_PYTHON_DECL registration const* query(type_info); - BOOST_PYTHON_DECL void insert(to_python_function_t, type_info); + BOOST_PYTHON_DECL void insert(to_python_function_t, type_info, PyTypeObject const* (*to_python_target_type)() = 0); // Insert an lvalue from_python converter - BOOST_PYTHON_DECL void insert(void* (*convert)(PyObject*), type_info); + BOOST_PYTHON_DECL void insert(void* (*convert)(PyObject*), type_info, PyTypeObject const* (*expected_pytype)() = 0); // Insert an rvalue from_python converter BOOST_PYTHON_DECL void insert( convertible_function , constructor_function , type_info + , PyTypeObject const* (*expected_pytype)() = 0 ); // Insert an rvalue from_python converter at the tail of the @@ -45,6 +46,7 @@ namespace registry convertible_function , constructor_function , type_info + , PyTypeObject const* (*expected_pytype)() = 0 ); } diff --git a/include/boost/python/converter/shared_ptr_from_python.hpp b/include/boost/python/converter/shared_ptr_from_python.hpp index 577fb447..6b49c469 100644 --- a/include/boost/python/converter/shared_ptr_from_python.hpp +++ b/include/boost/python/converter/shared_ptr_from_python.hpp @@ -10,6 +10,9 @@ # include # include # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif # include namespace boost { namespace python { namespace converter { @@ -19,7 +22,11 @@ struct shared_ptr_from_python { shared_ptr_from_python() { - converter::registry::insert(&convertible, &construct, type_id >()); + converter::registry::insert(&convertible, &construct, type_id >() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type_direct::get_pytype +#endif + ); } private: diff --git a/include/boost/python/default_call_policies.hpp b/include/boost/python/default_call_policies.hpp index 800cce79..3d32d2eb 100644 --- a/include/boost/python/default_call_policies.hpp +++ b/include/boost/python/default_call_policies.hpp @@ -13,6 +13,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -49,6 +50,12 @@ struct default_call_policies typedef default_result_converter result_converter; typedef PyObject* argument_package; + + template + struct extract_return_type : mpl::front + { + }; + }; struct default_result_converter diff --git a/include/boost/python/detail/caller.hpp b/include/boost/python/detail/caller.hpp index 1054b6e2..e479bf42 100644 --- a/include/boost/python/detail/caller.hpp +++ b/include/boost/python/detail/caller.hpp @@ -11,12 +11,15 @@ # include # include +# include + # include # include # include # include # include +# include # include # include @@ -89,6 +92,27 @@ inline ResultConverter create_result_converter( { return ResultConverter(); } + +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +template +struct converter_target_type +{ + static PyTypeObject const *get_pytype() + { + return create_result_converter((PyObject*)0, (ResultConverter *)0, (ResultConverter *)0).get_pytype(); + } +}; + +template < > +struct converter_target_type +{ + static PyTypeObject const *get_pytype() + { + return 0; + } +}; +#endif + template struct caller_arity; @@ -203,11 +227,26 @@ struct caller_arity static unsigned min_arity() { return N; } - static signature_element const* signature() + static py_func_sig_info signature() { - return detail::signature::elements(); + const signature_element * sig = detail::signature::elements(); +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + + typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type::type rtype; + typedef typename select_result_converter::type result_converter; + + static const signature_element ret = { + (boost::is_void::value ? "void" : type_id().name()) + , &detail::converter_target_type::get_pytype + , boost::detail::indirect_traits::is_reference_to_non_const::value + }; + py_func_sig_info res = {sig, &ret }; +#else + py_func_sig_info res = {sig, sig }; +#endif + + return res; } - private: compressed_pair m_data; }; diff --git a/include/boost/python/detail/config.hpp b/include/boost/python/detail/config.hpp index cfd762b9..acafc037 100644 --- a/include/boost/python/detail/config.hpp +++ b/include/boost/python/detail/config.hpp @@ -134,4 +134,8 @@ #include #endif // auto-linking disabled +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +#define BOOST_PYTHON_SUPPORTS_PY_SIGNATURES // enables smooth transition +#endif + #endif // CONFIG_DWA052200_H_ diff --git a/include/boost/python/detail/defaults_def.hpp b/include/boost/python/detail/defaults_def.hpp index 9ce98a62..68799f83 100644 --- a/include/boost/python/detail/defaults_def.hpp +++ b/include/boost/python/detail/defaults_def.hpp @@ -168,7 +168,7 @@ namespace detail char const* doc) { // define the NTH stub function of stubs - define_stub_function::define(name, stubs, kw, policies, name_space, 0); + define_stub_function::define(name, stubs, kw, policies, name_space, doc); if (kw.second > kw.first) --kw.second; diff --git a/include/boost/python/detail/defaults_gen.hpp b/include/boost/python/detail/defaults_gen.hpp index 45274957..0b3e0e26 100644 --- a/include/boost/python/detail/defaults_gen.hpp +++ b/include/boost/python/detail/defaults_gen.hpp @@ -248,7 +248,7 @@ namespace detail BOOST_PYTHON_GEN_MEM_FUNCTION( \ fname, void_return_type, n_args, n_dflts, ;) \ \ - BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args + 1, n_dflts) \ }; # else // !defined(BOOST_NO_VOID_RETURNS) @@ -273,7 +273,7 @@ namespace detail fname, non_void_return_type, n_args, n_dflts, return) \ \ typedef non_void_return_type void_return_type; \ - BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args + 1, n_dflts) \ }; # endif // !defined(BOOST_NO_VOID_RETURNS) diff --git a/include/boost/python/detail/make_keyword_range_fn.hpp b/include/boost/python/detail/make_keyword_range_fn.hpp index bc959997..634bbb99 100644 --- a/include/boost/python/detail/make_keyword_range_fn.hpp +++ b/include/boost/python/detail/make_keyword_range_fn.hpp @@ -57,6 +57,9 @@ object make_keyword_range_constructor( , Holder* = 0 , ArgList* = 0, Arity* = 0) { +#if !defined( BOOST_PYTHON_NO_PY_SIGNATURES) && defined( BOOST_PYTHON_PY_SYGNATURES_PROPER_INIT_SELF_TYPE) + python_class::register_(); +#endif return detail::make_keyword_range_function( objects::make_holder ::template apply::execute diff --git a/include/boost/python/detail/python_type.hpp b/include/boost/python/detail/python_type.hpp new file mode 100755 index 00000000..f7630c17 --- /dev/null +++ b/include/boost/python/detail/python_type.hpp @@ -0,0 +1,37 @@ +// Copyright Nikolay Mladenov 2007. +// 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) +#ifndef BOOST_PYTHON_OBJECT_PYTHON_TYPE_H +#define BOOST_PYTHON_OBJECT_PYTHON_TYPE_H + +#include + +namespace boost {namespace python {namespace detail{ + + +template struct python_class : PyObject +{ + typedef python_class this_type; + + typedef T type; + + static void *converter (PyObject *p){ + return p; + } + + static void register_() + { + static bool first_time = true; + + if ( !first_time ) return; + + first_time = false; + converter::registry::insert(&converter, boost::python::type_id(), &converter::registered_pytype_direct::get_pytype); + } +}; + + +}}} //namespace boost :: python :: detail + +#endif //BOOST_PYTHON_OBJECT_PYTHON_TYPE_H diff --git a/include/boost/python/detail/signature.hpp b/include/boost/python/detail/signature.hpp index 26e986cc..11268b92 100644 --- a/include/boost/python/detail/signature.hpp +++ b/include/boost/python/detail/signature.hpp @@ -12,6 +12,7 @@ # include # include +# include # include # include @@ -24,9 +25,16 @@ namespace boost { namespace python { namespace detail { struct signature_element { char const* basename; + converter::pytype_function pytype_f; bool lvalue; }; +struct py_func_sig_info +{ + signature_element const *signature; + signature_element const *ret; +}; + template struct signature_arity; # define BOOST_PP_ITERATION_PARAMS_1 \ @@ -68,15 +76,25 @@ struct signature_arity { static signature_element const result[N+2] = { +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES # define BOOST_PP_LOCAL_MACRO(i) \ - { \ - type_id::type>().name() \ - , indirect_traits::is_reference_to_non_const::type>::value \ - }, + { \ + type_id::type>().name() \ + , &converter::expected_pytype_for_arg::type>::get_pytype \ + , indirect_traits::is_reference_to_non_const::type>::value \ + }, +#else +# define BOOST_PP_LOCAL_MACRO(i) \ + { \ + type_id::type>().name() \ + , 0 \ + , indirect_traits::is_reference_to_non_const::type>::value \ + }, +#endif # define BOOST_PP_LOCAL_LIMITS (0, N) # include BOOST_PP_LOCAL_ITERATE() - {0,0} + {0,0,0} }; return result; } diff --git a/include/boost/python/detail/unwind_type.hpp b/include/boost/python/detail/unwind_type.hpp new file mode 100755 index 00000000..3c6f8ca2 --- /dev/null +++ b/include/boost/python/detail/unwind_type.hpp @@ -0,0 +1,170 @@ +// Copyright David Abrahams 2002. +// 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) +#ifndef UNWIND_TYPE_DWA200222_HPP +# define UNWIND_TYPE_DWA200222_HPP + +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +#ifndef _MSC_VER //if forward declared, msvc6.5 does not recognize them as inline +// forward declaration, required (at least) by Tru64 cxx V6.5-042 +template +inline typename Generator::result_type +unwind_type(U const& p, Generator* = 0); + +// forward declaration, required (at least) by Tru64 cxx V6.5-042 +template +inline typename Generator::result_type +unwind_type(boost::type*p = 0, Generator* = 0); +#endif + +template +inline typename Generator::result_type +unwind_type_cv(U* p, cv_unqualified, Generator* = 0) +{ + return Generator::execute(p); +} + +template +inline typename Generator::result_type +unwind_type_cv(U const* p, const_, Generator* = 0) +{ + return unwind_type(const_cast(p), (Generator*)0); +} + +template +inline typename Generator::result_type +unwind_type_cv(U volatile* p, volatile_, Generator* = 0) +{ + return unwind_type(const_cast(p), (Generator*)0); +} + +template +inline typename Generator::result_type +unwind_type_cv(U const volatile* p, const_volatile_, Generator* = 0) +{ + return unwind_type(const_cast(p), (Generator*)0); +} + +template +inline typename Generator::result_type +unwind_ptr_type(U* p, Generator* = 0) +{ + typedef typename cv_category::type tag; + return unwind_type_cv(p, tag()); +} + +template +struct unwind_helper +{ + template + static typename Generator::result_type + execute(U p, Generator* = 0) + { + return unwind_ptr_type(p, (Generator*)0); + } +}; + +template <> +struct unwind_helper +{ + template + static typename Generator::result_type + execute(U& p, Generator* = 0) + { + return unwind_ptr_type(&p, (Generator*)0); + } +}; + +template +inline typename Generator::result_type +#ifndef _MSC_VER +unwind_type(U const& p, Generator*) +#else +unwind_type(U const& p, Generator* = 0) +#endif +{ + return unwind_helper::value>::execute(p, (Generator*)0); +} + +enum { direct_ = 0, pointer_ = 1, reference_ = 2, reference_to_pointer_ = 3 }; +template struct unwind_helper2; + +template <> +struct unwind_helper2 +{ + template + static typename Generator::result_type + execute(U(*)(), Generator* = 0) + { + return unwind_ptr_type((U*)0, (Generator*)0); + } +}; + +template <> +struct unwind_helper2 +{ + template + static typename Generator::result_type + execute(U*(*)(), Generator* = 0) + { + return unwind_ptr_type((U*)0, (Generator*)0); + } +}; + +template <> +struct unwind_helper2 +{ + template + static typename Generator::result_type + execute(U&(*)(), Generator* = 0) + { + return unwind_ptr_type((U*)0, (Generator*)0); + } +}; + +template <> +struct unwind_helper2 +{ + template + static typename Generator::result_type + execute(U&(*)(), Generator* = 0) + { + return unwind_ptr_type(U(0), (Generator*)0); + } +}; + +// Call this one with both template parameters explicitly specified +// and no function arguments: +// +// return unwind_type(); +// +// Doesn't work if T is an array type; we could handle that case, but +// why bother? +template +inline typename Generator::result_type +#ifndef _MSC_VER +unwind_type(boost::type*p, Generator*) +#else +unwind_type(boost::type*p =0, Generator* =0) +#endif +{ + BOOST_STATIC_CONSTANT(int, indirection + = (boost::is_pointer::value ? pointer_ : 0) + + (indirect_traits::is_reference_to_pointer::value + ? reference_to_pointer_ + : boost::is_reference::value + ? reference_ + : 0)); + + return unwind_helper2::execute((U(*)())0,(Generator*)0); +} + +}}} // namespace boost::python::detail + +#endif // UNWIND_TYPE_DWA200222_HPP diff --git a/include/boost/python/docstring_options.hpp b/include/boost/python/docstring_options.hpp index 507a4c5d..1914bd51 100755 --- a/include/boost/python/docstring_options.hpp +++ b/include/boost/python/docstring_options.hpp @@ -17,23 +17,38 @@ class BOOST_PYTHON_DECL docstring_options : boost::noncopyable docstring_options(bool show_all=true) { previous_show_user_defined_ = show_user_defined_; - previous_show_signatures_ = show_signatures_; + previous_show_py_signatures_ = show_py_signatures_; + previous_show_cpp_signatures_ = show_cpp_signatures_; show_user_defined_ = show_all; - show_signatures_ = show_all; + show_cpp_signatures_ = show_all; + show_py_signatures_ = show_all; } docstring_options(bool show_user_defined, bool show_signatures) { previous_show_user_defined_ = show_user_defined_; - previous_show_signatures_ = show_signatures_; + previous_show_cpp_signatures_ = show_cpp_signatures_; + previous_show_py_signatures_ = show_py_signatures_; show_user_defined_ = show_user_defined; - show_signatures_ = show_signatures; + show_cpp_signatures_ = show_signatures; + show_py_signatures_ = show_signatures; + } + + docstring_options(bool show_user_defined, bool show_py_signatures, bool show_cpp_signatures) + { + previous_show_user_defined_ = show_user_defined_; + previous_show_cpp_signatures_ = show_cpp_signatures_; + previous_show_py_signatures_ = show_py_signatures_; + show_user_defined_ = show_user_defined; + show_cpp_signatures_ = show_cpp_signatures; + show_py_signatures_ = show_py_signatures; } ~docstring_options() { show_user_defined_ = previous_show_user_defined_; - show_signatures_ = previous_show_signatures_; + show_cpp_signatures_ = previous_show_cpp_signatures_; + show_py_signatures_ = previous_show_py_signatures_; } void @@ -43,32 +58,68 @@ class BOOST_PYTHON_DECL docstring_options : boost::noncopyable enable_user_defined() { show_user_defined_ = true; } void - disable_signatures() { show_signatures_ = false; } + disable_py_signatures() + { + show_py_signatures_ = false; + } void - enable_signatures() { show_signatures_ = true; } + enable_py_signatures() + { + show_py_signatures_ = true; + } + + void + disable_cpp_signatures() + { + show_cpp_signatures_ = false; + } + + void + enable_cpp_signatures() + { + show_cpp_signatures_ = true; + } + + void + disable_signatures() + { + show_cpp_signatures_ = false; + show_py_signatures_ = false; + } + + void + enable_signatures() + { + show_cpp_signatures_ = true; + show_py_signatures_ = true; + } void disable_all() { show_user_defined_ = false; - show_signatures_ = false; + show_cpp_signatures_ = false; + show_py_signatures_ = false; } void enable_all() { show_user_defined_ = true; - show_signatures_ = true; + show_cpp_signatures_ = true; + show_py_signatures_ = true; } friend struct objects::function; private: static volatile bool show_user_defined_; - static volatile bool show_signatures_; + static volatile bool show_cpp_signatures_; + static volatile bool show_py_signatures_; bool previous_show_user_defined_; - bool previous_show_signatures_; + bool previous_show_cpp_signatures_; + bool previous_show_py_signatures_; }; }} // namespace boost::python diff --git a/include/boost/python/enum.hpp b/include/boost/python/enum.hpp index 24b616a4..57684530 100644 --- a/include/boost/python/enum.hpp +++ b/include/boost/python/enum.hpp @@ -19,7 +19,7 @@ struct enum_ : public objects::enum_base typedef objects::enum_base base; // Declare a new enumeration type in the current scope() - enum_(char const* name); + enum_(char const* name, char const* doc = 0); // Add a new enumeration value with the given name and value. inline enum_& value(char const* name, T); @@ -34,13 +34,15 @@ struct enum_ : public objects::enum_base }; template -inline enum_::enum_(char const* name) +inline enum_::enum_(char const* name, char const* doc ) : base( name , &enum_::to_python , &enum_::convertible_from_python , &enum_::construct - , type_id()) + , type_id() + , doc + ) { } diff --git a/include/boost/python/implicit.hpp b/include/boost/python/implicit.hpp index 14a69700..4d01b2fb 100644 --- a/include/boost/python/implicit.hpp +++ b/include/boost/python/implicit.hpp @@ -9,6 +9,9 @@ # include # include # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif # include namespace boost { namespace python { @@ -21,7 +24,11 @@ void implicitly_convertible(boost::type* = 0, boost::type* = 0) converter::registry::push_back( &functions::convertible , &functions::construct - , type_id()); + , type_id() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type_direct::get_pytype +#endif + ); } }} // namespace boost::python diff --git a/include/boost/python/init.hpp b/include/boost/python/init.hpp index a07359e6..6598fd35 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -245,7 +245,7 @@ class init : public init_base > : base(doc_, kw.range()) { typedef typename detail::error::more_keywords_than_init_arguments< - N, n_arguments::value + N, n_arguments::value + 1 >::too_many_keywords assertion; } @@ -254,7 +254,7 @@ class init : public init_base > : base(doc_, kw.range()) { typedef typename detail::error::more_keywords_than_init_arguments< - N, n_arguments::value + N, n_arguments::value + 1 >::too_many_keywords assertion; } @@ -363,7 +363,7 @@ namespace detail , char const* doc , detail::keyword_range keywords) { - detail::def_init_aux(cl, args, NArgs(), policies, 0, keywords); + detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords); if (keywords.second > keywords.first) --keywords.second; diff --git a/include/boost/python/lvalue_from_pytype.hpp b/include/boost/python/lvalue_from_pytype.hpp index 51660050..019d4ae5 100755 --- a/include/boost/python/lvalue_from_pytype.hpp +++ b/include/boost/python/lvalue_from_pytype.hpp @@ -6,6 +6,9 @@ # define LVALUE_FROM_PYTYPE_DWA2002130_HPP # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif # include # include @@ -81,12 +84,17 @@ struct extract_identity // Extractor's static execute function from Python objects whose type // object is python_type. template -struct lvalue_from_pytype +struct lvalue_from_pytype { lvalue_from_pytype() { - converter::registry::insert( - &extract, detail::extractor_type_id(&Extractor::execute)); + converter::registry::insert + ( &extract + , detail::extractor_type_id(&Extractor::execute) +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &get_pytype +#endif + ); } private: static void* extract(PyObject* op) @@ -98,6 +106,9 @@ struct lvalue_from_pytype : 0 ; } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const*get_pytype() { return python_type; } +#endif }; }} // namespace boost::python diff --git a/include/boost/python/make_constructor.hpp b/include/boost/python/make_constructor.hpp index 654a4f31..972de5fc 100755 --- a/include/boost/python/make_constructor.hpp +++ b/include/boost/python/make_constructor.hpp @@ -104,6 +104,14 @@ namespace detail // If the BasePolicy_ supplied a result converter it would be // ignored; issue an error if it's not the default. +#if defined _MSC_VER && _MSC_VER < 1300 + typedef is_same< + typename BasePolicy_::result_converter + , default_result_converter + > same_result_converter; + //see above for explanation + BOOST_STATIC_ASSERT(same_result_converter::value) ; +#else BOOST_MPL_ASSERT_MSG( (is_same< typename BasePolicy_::result_converter @@ -112,7 +120,7 @@ namespace detail , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS , (typename BasePolicy_::result_converter) ); - +#endif typedef constructor_result_converter result_converter; typedef offset_args > argument_package; }; diff --git a/include/boost/python/object/class_metadata.hpp b/include/boost/python/object/class_metadata.hpp index bf0e2748..05740b8e 100755 --- a/include/boost/python/object/class_metadata.hpp +++ b/include/boost/python/object/class_metadata.hpp @@ -238,6 +238,14 @@ struct class_metadata // inline static void maybe_register_pointer_to_python(void*,void*,void*) {} +#ifndef BOOST_PYTHON_NO_PY_SYGNATURES + inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*) + { + objects::copy_class_object(python::type_id(), python::type_id >()); + objects::copy_class_object(python::type_id(), python::type_id >()); + } +#endif + template inline static void maybe_register_pointer_to_python(T2*, mpl::false_*, mpl::false_*) { @@ -247,6 +255,10 @@ struct class_metadata , make_ptr_instance > >() ); +#ifndef BOOST_PYTHON_NO_PY_SYGNATURES + // explicit qualification of type_id makes msvc6 happy + objects::copy_class_object(python::type_id(), python::type_id()); +#endif } // // Support for registering to-python converters @@ -258,6 +270,10 @@ struct class_metadata inline static void maybe_register_class_to_python(T2*, mpl::false_) { python::detail::force_instantiate(class_cref_wrapper >()); +#ifndef BOOST_PYTHON_NO_PY_SYGNATURES + // explicit qualification of type_id makes msvc6 happy + objects::copy_class_object(python::type_id(), python::type_id()); +#endif } // diff --git a/include/boost/python/object/class_wrapper.hpp b/include/boost/python/object/class_wrapper.hpp index 5097ee5a..ffee7457 100644 --- a/include/boost/python/object/class_wrapper.hpp +++ b/include/boost/python/object/class_wrapper.hpp @@ -6,6 +6,9 @@ # define CLASS_WRAPPER_DWA20011221_HPP # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif # include namespace boost { namespace python { namespace objects { @@ -19,22 +22,28 @@ namespace boost { namespace python { namespace objects { template struct class_cref_wrapper - : to_python_converter > + : to_python_converter ,true> { static PyObject* convert(Src const& x) { return MakeInstance::execute(boost::ref(x)); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const *get_pytype() { return converter::registered_pytype_direct::get_pytype(); } +#endif }; template struct class_value_wrapper - : to_python_converter > + : to_python_converter ,true> { static PyObject* convert(Src x) { return MakeInstance::execute(x); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const *get_pytype() { return MakeInstance::get_pytype(); } +#endif }; }}} // namespace boost::python::objects diff --git a/include/boost/python/object/enum_base.hpp b/include/boost/python/object/enum_base.hpp index 7062ed90..be342742 100644 --- a/include/boost/python/object/enum_base.hpp +++ b/include/boost/python/object/enum_base.hpp @@ -21,7 +21,9 @@ struct BOOST_PYTHON_DECL enum_base : python::api::object , converter::to_python_function_t , converter::convertible_function , converter::constructor_function - , type_info); + , type_info + , const char *doc = 0 + ); void add_value(char const* name, long value); void export_values(); diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp index 5ef0f827..e44ca5b2 100644 --- a/include/boost/python/object/function.hpp +++ b/include/boost/python/object/function.hpp @@ -14,6 +14,7 @@ namespace boost { namespace python { namespace objects { + struct BOOST_PYTHON_DECL function : PyObject { function( @@ -53,6 +54,7 @@ struct BOOST_PYTHON_DECL function : PyObject object m_doc; object m_arg_names; unsigned m_nkeyword_values; + friend class function_doc_signature_generator; }; // diff --git a/include/boost/python/object/function_doc_signature.hpp b/include/boost/python/object/function_doc_signature.hpp new file mode 100755 index 00000000..4f00cb38 --- /dev/null +++ b/include/boost/python/object/function_doc_signature.hpp @@ -0,0 +1,36 @@ +// Copyright Nikolay Mladenov 2007. +// 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) +#ifndef FUNCTION_SIGNATURE_20070531_HPP +# define FUNCTION_SIGNATURE_20070531_HPP + +#include +#include +#include +#include + +#include + + +#include + +namespace boost { namespace python { namespace objects { + +class function_doc_signature_generator{ + static const char * py_type_str(const python::detail::signature_element &s); + static bool arity_cmp( function const *f1, function const *f2 ); + static bool are_seq_overloads( function const *f1, function const *f2 , bool check_docs); + static std::vector flatten(function const *f); + static std::vector split_seq_overloads( const std::vector &funcs, bool split_on_doc_change); + static str raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false); + static str parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types); + static str pretty_signature(function const *f, size_t n_overloads, bool cpp_types = false); + +public: + static list function_doc_signatures( function const * f); +}; + +}}}//end of namespace boost::python::objects + +#endif //FUNCTION_SIGNATURE_20070531_HPP diff --git a/include/boost/python/object/make_holder.hpp b/include/boost/python/object/make_holder.hpp index 83c18582..9d5de98d 100644 --- a/include/boost/python/object/make_holder.hpp +++ b/include/boost/python/object/make_holder.hpp @@ -11,6 +11,10 @@ # include # include +# include +#if !defined( BOOST_PYTHON_NO_PY_SIGNATURES) && defined( BOOST_PYTHON_PY_SYGNATURES_PROPER_INIT_SELF_TYPE) +# include +#endif # include # include @@ -74,7 +78,11 @@ struct make_holder # endif static void execute( - PyObject* p +#if !defined( BOOST_PYTHON_NO_PY_SIGNATURES) && defined( BOOST_PYTHON_PY_SYGNATURES_PROPER_INIT_SELF_TYPE) + boost::python::detail::python_class *p +#else + PyObject *p +#endif BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, t, a)) { typedef instance instance_t; diff --git a/include/boost/python/object/make_ptr_instance.hpp b/include/boost/python/object/make_ptr_instance.hpp index d045243b..9fdb23f6 100644 --- a/include/boost/python/object/make_ptr_instance.hpp +++ b/include/boost/python/object/make_ptr_instance.hpp @@ -29,7 +29,12 @@ struct make_ptr_instance { return get_class_object_impl(get_pointer(x)); } - +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static inline PyTypeObject const* get_pytype() + { + return converter::registered::converters.get_class_object(); + } +#endif private: template static inline PyTypeObject* get_class_object_impl(U const volatile* p) diff --git a/include/boost/python/object/py_function.hpp b/include/boost/python/object/py_function.hpp index b8ef5ab4..ba9aadf4 100644 --- a/include/boost/python/object/py_function.hpp +++ b/include/boost/python/object/py_function.hpp @@ -23,7 +23,7 @@ struct BOOST_PYTHON_DECL py_function_impl_base virtual PyObject* operator()(PyObject*, PyObject*) = 0; virtual unsigned min_arity() const = 0; virtual unsigned max_arity() const; - virtual python::detail::signature_element const* signature() const = 0; + virtual python::detail::py_func_sig_info signature() const = 0; }; template @@ -43,7 +43,7 @@ struct caller_py_function_impl : py_function_impl_base return m_caller.min_arity(); } - virtual python::detail::signature_element const* signature() const + virtual python::detail::py_func_sig_info signature() const { return m_caller.signature(); } @@ -69,9 +69,11 @@ struct signature_py_function_impl : py_function_impl_base return mpl::size::value - 1; } - virtual python::detail::signature_element const* signature() const + virtual python::detail::py_func_sig_info signature() const { - return python::detail::signature::elements(); + python::detail::signature_element const* sig = python::detail::signature::elements(); + python::detail::py_func_sig_info res = {sig, sig}; + return res; } private: @@ -102,9 +104,11 @@ struct full_py_function_impl : py_function_impl_base return m_max_arity; } - virtual python::detail::signature_element const* signature() const + virtual python::detail::py_func_sig_info signature() const { - return python::detail::signature::elements(); + python::detail::signature_element const* sig = python::detail::signature::elements(); + python::detail::py_func_sig_info res = {sig, sig}; + return res; } private: @@ -151,7 +155,12 @@ struct py_function python::detail::signature_element const* signature() const { - return m_impl->signature(); + return m_impl->signature().signature; + } + + python::detail::signature_element const& get_return_type() const + { + return *m_impl->signature().ret; } private: diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 6aa5df21..ecd7257f 100755 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -470,6 +470,9 @@ namespace converter { return python::detail::new_non_null_reference(x); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const *get_pytype() {return 0;} +#endif }; } diff --git a/include/boost/python/opaque_pointer_converter.hpp b/include/boost/python/opaque_pointer_converter.hpp index d2a7c94d..745a5cd4 100644 --- a/include/boost/python/opaque_pointer_converter.hpp +++ b/include/boost/python/opaque_pointer_converter.hpp @@ -93,8 +93,13 @@ private: if ((existing == 0) || (existing->m_to_python == 0)) { +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + converter::registry::insert(&extract, type_id(), &get_pytype); + converter::registry::insert(&wrap, type_id(), &get_pytype); +#else converter::registry::insert(&extract, type_id()); converter::registry::insert(&wrap, type_id()); +#endif } } @@ -105,6 +110,9 @@ private: }; static PyTypeObject type_object; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const *get_pytype(){return &type_object; } +#endif }; template diff --git a/include/boost/python/return_arg.hpp b/include/boost/python/return_arg.hpp index a6f651b6..c36f898d 100755 --- a/include/boost/python/return_arg.hpp +++ b/include/boost/python/return_arg.hpp @@ -8,10 +8,15 @@ # include # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif + # include # include # include +# include # include # include @@ -44,6 +49,9 @@ namespace detail { return none(); } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + PyTypeObject const *get_pytype() const { return converter::expected_pytype_for_arg::get_pytype() ; } +#endif }; }; }; @@ -82,6 +90,12 @@ struct return_arg : Base Py_DECREF(result); return incref( detail::get(mpl::int_(),args) ); } + + template + struct extract_return_type : mpl::at_c + { + }; + }; template < diff --git a/include/boost/python/to_python_converter.hpp b/include/boost/python/to_python_converter.hpp index b7dd3c3d..378d159e 100644 --- a/include/boost/python/to_python_converter.hpp +++ b/include/boost/python/to_python_converter.hpp @@ -9,13 +9,67 @@ # include # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif # include namespace boost { namespace python { -template -struct to_python_converter +#if 0 //get_pytype member detection +namespace detail { + typedef char yes_type; + typedef struct {char a[2]; } no_type; + template struct test_get_pytype1 { }; + template struct test_get_pytype2 { }; + + template yes_type tester(test_get_pytype1<&T::get_pytype>*); + + template yes_type tester(test_get_pytype2<&T::get_pytype>*); + + template no_type tester(...); + + template + struct test_get_pytype_base + { + BOOST_STATIC_CONSTANT(bool, value= (sizeof(detail::tester(0)) == sizeof(yes_type))); + }; + + template + struct test_get_pytype : boost::mpl::bool_::value> + { + }; + +} +#endif + +template < class T, class Conversion, bool has_get_pytype=false > +struct to_python_converter +{ +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +#if 0 //defined _MSC_VER && _MSC_VER >=1310 + //probably other compilers could come here as well + typedef typename detail::test_get_pytype HasGetPytype; +#else + typedef boost::mpl::bool_ HasGetPytype; +#endif + + static PyTypeObject const* get_pytype_1(boost::mpl::true_ *) + { + return Conversion::get_pytype(); + } + + static PyTypeObject const* get_pytype_1(boost::mpl::false_ *) + { + return 0; + } + static PyTypeObject const* get_pytype_impl() + { + return get_pytype_1((HasGetPytype*)0); + } +#endif + to_python_converter(); }; @@ -23,18 +77,23 @@ struct to_python_converter // implementation // -template -to_python_converter::to_python_converter() +template +to_python_converter::to_python_converter() { typedef converter::as_to_python_function< T, Conversion > normalized; - + converter::registry::insert( &normalized::convert - , type_id()); + , type_id() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &get_pytype_impl +#endif + ); } }} // namespace boost::python #endif // TO_PYTHON_CONVERTER_DWA200221_HPP + diff --git a/include/boost/python/to_python_indirect.hpp b/include/boost/python/to_python_indirect.hpp index a39b723d..23ad0263 100644 --- a/include/boost/python/to_python_indirect.hpp +++ b/include/boost/python/to_python_indirect.hpp @@ -12,6 +12,10 @@ # include +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif + # include # include @@ -36,7 +40,13 @@ struct to_python_indirect { return this->execute(const_cast(ref), is_pointer()); } - +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + inline PyTypeObject const* + get_pytype()const + { + return converter::registered_pytype::get_pytype(); + } +#endif private: template inline PyObject* execute(U* ptr, mpl::true_) const diff --git a/include/boost/python/to_python_value.hpp b/include/boost/python/to_python_value.hpp index 7c350bb4..3944b2ff 100644 --- a/include/boost/python/to_python_value.hpp +++ b/include/boost/python/to_python_value.hpp @@ -9,12 +9,12 @@ # include # include +# include # include # include # include # include -# include # include # include @@ -24,17 +24,57 @@ # include # include +# include namespace boost { namespace python { namespace detail { +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + +template +struct object_manager_get_pytype +{ + template + static PyTypeObject const* get( U& (*p)() =0) + { + return converter::object_manager_traits::get_pytype(); + } +}; + +template <> +struct object_manager_get_pytype +{ + template + static PyTypeObject const* get( U const& (*p)() =0) + { + return converter::object_manager_traits::get_pytype(); + } +}; + +#endif + template struct object_manager_to_python_value { typedef typename value_arg::type argument_type; PyObject* operator()(argument_type) const; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + typedef boost::mpl::bool_::value> is_t_handle; + typedef boost::detail::indirect_traits::is_reference_to_const is_t_const; + PyTypeObject const* get_pytype() const { + return get_pytype_aux((is_t_handle*)0); + } + + inline static PyTypeObject const* get_pytype_aux(mpl::true_*) {return converter::object_manager_traits::get_pytype();} + + inline static PyTypeObject const* get_pytype_aux(mpl::false_* ) + { + return object_manager_get_pytype::get((T(*)())0); + } + +#endif // This information helps make_getter() decide whether to try to // return an internal reference or not. I don't like it much, @@ -49,6 +89,9 @@ namespace detail typedef typename value_arg::type argument_type; PyObject* operator()(argument_type) const; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + PyTypeObject const* get_pytype() const {return converter::registered::converters.to_python_target_type();} +#endif // This information helps make_getter() decide whether to try to // return an internal reference or not. I don't like it much, @@ -62,11 +105,18 @@ namespace detail typedef typename value_arg::type argument_type; PyObject* operator()(argument_type) const; - +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + PyTypeObject const* get_pytype() const {return get_pytype((boost::type*)0);} +#endif // This information helps make_getter() decide whether to try to // return an internal reference or not. I don't like it much, // but it will have to serve for now. BOOST_STATIC_CONSTANT(bool, uses_registry = false); + private: +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + template + PyTypeObject const* get_pytype(boost::type &> *) const {return converter::registered::converters.to_python_target_type();} +#endif }; } diff --git a/src/converter/builtin_converters.cpp b/src/converter/builtin_converters.cpp index e1dead43..97976e03 100644 --- a/src/converter/builtin_converters.cpp +++ b/src/converter/builtin_converters.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ namespace &slot_rvalue_from_python::convertible , &slot_rvalue_from_python::construct , type_id() + , &SlotPolicy::get_pytype ); } @@ -100,6 +102,7 @@ namespace return (PyInt_Check(obj) || PyLong_Check(obj)) ? &number_methods->nb_int : 0; } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} }; template @@ -135,6 +138,7 @@ namespace return (PyInt_Check(obj) || PyLong_Check(obj)) ? &py_object_identity : 0; } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} }; template @@ -173,6 +177,7 @@ namespace else return 0; } + static PyTypeObject const* get_pytype() { return &PyInt_Type;} }; struct long_long_rvalue_from_python : long_long_rvalue_from_python_base @@ -228,6 +233,15 @@ namespace { return PyObject_IsTrue(intermediate); } + + static PyTypeObject const* get_pytype() + { +#if PY_VERSION_HEX >= 0x02030000 + return &PyBool_Type; +#else + return &PyInt_Type; +#endif + } }; // A SlotPolicy for extracting floating types from Python objects. @@ -259,6 +273,7 @@ namespace return PyFloat_AS_DOUBLE(intermediate); } } + static PyTypeObject const* get_pytype() { return &PyFloat_Type;} }; // A SlotPolicy for extracting C++ strings from Python objects. @@ -276,6 +291,7 @@ namespace { return std::string(PyString_AsString(intermediate),PyString_Size(intermediate)); } + static PyTypeObject const* get_pytype() { return &PyString_Type;} }; #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) @@ -316,6 +332,7 @@ namespace } return result; } + static PyTypeObject const* get_pytype() { return &PyUnicode_Type;} }; #endif @@ -346,6 +363,7 @@ namespace return PyFloat_AS_DOUBLE(intermediate); } } + static PyTypeObject const* get_pytype() { return &PyComplex_Type;} }; } @@ -411,7 +429,7 @@ void initialize_builtin_converters() slot_rvalue_from_python,complex_rvalue_from_python>(); // Add an lvalue converter for char which gets us char const* - registry::insert(convert_to_cstring,type_id()); + registry::insert(convert_to_cstring,type_id(),&converter::wrap_pytype<&PyString_Type>::get_pytype); // Register by-value converters to std::string, std::wstring #if defined(Py_USING_UNICODE) && !defined(BOOST_NO_STD_WSTRING) diff --git a/src/converter/registry.cpp b/src/converter/registry.cpp index 179111c6..b09a7985 100644 --- a/src/converter/registry.cpp +++ b/src/converter/registry.cpp @@ -20,6 +20,35 @@ #endif namespace boost { namespace python { namespace converter { +BOOST_PYTHON_DECL PyTypeObject const* registration::expected_from_python_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + std::set pool; + + for(rvalue_from_python_chain* r = rvalue_chain; r ; r=r->next) + if(r->expected_pytype) + pool.insert(r->expected_pytype()); + + //for now I skip the search for common base + if (pool.size()==1) + return *pool.begin(); + + return 0; + +} + +BOOST_PYTHON_DECL PyTypeObject const* registration::to_python_target_type() const +{ + if (this->m_class_object != 0) + return this->m_class_object; + + if (this->m_to_python_target_type != 0) + return this->m_to_python_target_type(); + + return 0; +} BOOST_PYTHON_DECL PyTypeObject* registration::get_class_object() const { @@ -168,15 +197,15 @@ namespace // namespace registry { - void insert(to_python_function_t f, type_info source_t) + void insert(to_python_function_t f, type_info source_t, PyTypeObject const* (*to_python_target_type)()) { # ifdef BOOST_PYTHON_TRACE_REGISTRY std::cout << "inserting to_python " << source_t << "\n"; # endif - to_python_function_t& slot = get(source_t)->m_to_python; + entry* slot = get(source_t); - assert(slot == 0); // we have a problem otherwise - if (slot != 0) + assert(slot->m_to_python == 0); // we have a problem otherwise + if (slot->m_to_python != 0) { std::string msg = ( std::string("to-Python converter for ") @@ -189,11 +218,12 @@ namespace registry throw_error_already_set(); } } - slot = f; + slot->m_to_python = f; + slot->m_to_python_target_type = to_python_target_type; } // Insert an lvalue from_python converter - void insert(convertible_function convert, type_info key) + void insert(convertible_function convert, type_info key, PyTypeObject const* (*exp_pytype)()) { # ifdef BOOST_PYTHON_TRACE_REGISTRY std::cout << "inserting lvalue from_python " << key << "\n"; @@ -204,13 +234,14 @@ namespace registry registration->next = found->lvalue_chain; found->lvalue_chain = registration; - insert(convert, 0, key); + insert(convert, 0, key,exp_pytype); } // Insert an rvalue from_python converter void insert(void* (*convertible)(PyObject*) , constructor_function construct - , type_info key) + , type_info key + , PyTypeObject const* (*exp_pytype)()) { # ifdef BOOST_PYTHON_TRACE_REGISTRY std::cout << "inserting rvalue from_python " << key << "\n"; @@ -219,6 +250,7 @@ namespace registry rvalue_from_python_chain *registration = new rvalue_from_python_chain; registration->convertible = convertible; registration->construct = construct; + registration->expected_pytype = exp_pytype; registration->next = found->rvalue_chain; found->rvalue_chain = registration; } @@ -226,7 +258,8 @@ namespace registry // Insert an rvalue from_python converter void push_back(void* (*convertible)(PyObject*) , constructor_function construct - , type_info key) + , type_info key + , PyTypeObject const* (*exp_pytype)()) { # ifdef BOOST_PYTHON_TRACE_REGISTRY std::cout << "push_back rvalue from_python " << key << "\n"; @@ -238,6 +271,7 @@ namespace registry rvalue_from_python_chain *registration = new rvalue_from_python_chain; registration->convertible = convertible; registration->construct = construct; + registration->expected_pytype = exp_pytype; registration->next = 0; *found = registration; } diff --git a/src/dict.cpp b/src/dict.cpp index 5ba4e726..ee2ee29f 100644 --- a/src/dict.cpp +++ b/src/dict.cpp @@ -171,4 +171,14 @@ list dict_base::values() const } } +static struct register_dict_pytype_ptr +{ + register_dict_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyDict_Type; + } +}register_dict_pytype_ptr_; + }}} // namespace boost::python diff --git a/src/list.cpp b/src/list.cpp index b8f31fb8..3c26950e 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -137,4 +137,14 @@ long list_base::count(object_cref value) const return result; } +static struct register_list_pytype_ptr +{ + register_list_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyList_Type; + } +}register_list_pytype_ptr_; + }}} // namespace boost::python diff --git a/src/object/enum.cpp b/src/object/enum.cpp index 1973270b..2fb215ca 100644 --- a/src/object/enum.cpp +++ b/src/object/enum.cpp @@ -121,7 +121,7 @@ object module_prefix(); namespace { - object new_enum_type(char const* name) + object new_enum_type(char const* name, char const *doc) { if (enum_type_object.tp_dict == 0) { @@ -143,6 +143,8 @@ namespace object module_name = module_prefix(); if (module_name) d["__module__"] = module_name; + if (doc) + d["__doc__"] = doc; object result = (object(metatype))(name, make_tuple(base), d); @@ -158,8 +160,9 @@ enum_base::enum_base( , converter::convertible_function convertible , converter::constructor_function construct , type_info id + , char const *doc ) - : object(new_enum_type(name)) + : object(new_enum_type(name, doc)) { converter::registration& converters = const_cast( diff --git a/src/object/function.cpp b/src/object/function.cpp index 8226bf59..360ce13d 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include +#include #include #include @@ -30,7 +32,12 @@ namespace boost { namespace python { volatile bool docstring_options::show_user_defined_ = true; - volatile bool docstring_options::show_signatures_ = true; + volatile bool docstring_options::show_cpp_signatures_ = true; +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + volatile bool docstring_options::show_py_signatures_ = true; +#else + volatile bool docstring_options::show_py_signatures_ = false; +#endif }} namespace boost { namespace python { namespace objects { @@ -411,6 +418,12 @@ void function::add_to_namespace( add_to_namespace(name_space, name_, attribute, 0); } +namespace detail +{ + extern char py_signature_tag[]; + extern char cpp_signature_tag[]; +} + void function::add_to_namespace( object const& name_space, char const* name_, object const& attribute, char const* doc) { @@ -487,6 +500,7 @@ void function::add_to_namespace( throw_error_already_set(); object mutable_attribute(attribute); +/* if (doc != 0 && docstring_options::show_user_defined_) { // Accumulate documentation @@ -517,6 +531,28 @@ void function::add_to_namespace( mutable_attribute.attr("__doc__") += str("\n ").join(make_tuple( "C++ signature:", f->signature(true))); } + */ + str _doc; + + if (docstring_options::show_py_signatures_) + { + _doc += str(reinterpret_cast(detail::py_signature_tag)); + } + if (doc != 0 && docstring_options::show_user_defined_) + _doc += doc; + + if (docstring_options::show_cpp_signatures_) + { + if(len(_doc)) + _doc += "\n "+str(reinterpret_cast(detail::cpp_signature_tag)); + else + _doc += " "+str(reinterpret_cast(detail::cpp_signature_tag)); + } + if(_doc) + { + object mutable_attribute(attribute); + mutable_attribute.attr("__doc__")= _doc; + } } BOOST_PYTHON_DECL void add_to_namespace( @@ -591,7 +627,10 @@ extern "C" static PyObject* function_get_doc(PyObject* op, void*) { function* f = downcast(op); - return python::incref(f->doc().ptr()); + list signatures = function_doc_signature_generator::function_doc_signatures(f); + if(!signatures) return python::detail::none(); + signatures.reverse(); + return python::incref( str("\n ").join(signatures).ptr()); } static int function_set_doc(PyObject* op, PyObject* doc, void*) diff --git a/src/object/function_doc_signature.cpp b/src/object/function_doc_signature.cpp new file mode 100755 index 00000000..c1ea8acb --- /dev/null +++ b/src/object/function_doc_signature.cpp @@ -0,0 +1,314 @@ +// Copyright Nikolay Mladenov 2007. +// 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) + +#include +#include +#include +#include +#include +#include + +#include + + +#include + +namespace boost { namespace python { namespace objects { + + bool function_doc_signature_generator::arity_cmp( function const *f1, function const *f2 ) + { + return f1->m_fn.max_arity() < f2->m_fn.max_arity(); + } + + bool function_doc_signature_generator::are_seq_overloads( function const *f1, function const *f2 , bool check_docs) + { + py_function const & impl1 = f1->m_fn; + py_function const & impl2 = f2->m_fn; + + //the number of parameters differs by 1 + if (impl2.max_arity()-impl1.max_arity() != 1) + return false; + + // if check docs then f1 shold not have docstring or have the same docstring as f2 + if (check_docs && f2->doc() != f1->doc() && f1->doc()) + return false; + + python::detail::signature_element const* s1 = impl1.signature(); + python::detail::signature_element const* s2 = impl2.signature(); + + unsigned size = impl1.max_arity()+1; + + for (unsigned i = 0; i != size; ++i) + { + //check if the argument types are the same + if (s1[i].basename != s2[i].basename) + return false; + + //return type + if (!i) continue; + + //check if the argument default values are the same + bool f1_has_names = bool(f1->m_arg_names); + bool f2_has_names = bool(f2->m_arg_names); + if ( f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=f1->m_arg_names[i-1] + || f1_has_names && !f2_has_names + || !f1_has_names && f2_has_names && f2->m_arg_names[i-1]!=python::object() + ) + return false; + } + return true; + } + + std::vector function_doc_signature_generator::flatten(function const *f) + { + object name = f->name(); + + std::vector res; + + while (f) { + + //this if takes out the not_implemented_function + if (f->name() == name) + res.push_back(f); + + f=f->m_overloads.get(); + } + + //std::sort(res.begin(),res.end(), &arity_cmp); + + return res; + } + std::vector function_doc_signature_generator::split_seq_overloads( const std::vector &funcs, bool split_on_doc_change) + { + std::vector res; + + std::vector::const_iterator fi = funcs.begin(); + + function const * last = *fi; + + while (++fi != funcs.end()){ + + //check if fi starts a new chain of overloads + if (!are_seq_overloads( last, *fi, split_on_doc_change )) + res.push_back(last); + + last = *fi; + } + + if (last) + res.push_back(last); + + return res; + } + + str function_doc_signature_generator::raw_function_pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + str res("object"); + + res = str("%s %s(%s)" % make_tuple( res, f->m_name, str("tuple args, dict kwds")) ); + + return res; + } + + const char * function_doc_signature_generator::py_type_str(const python::detail::signature_element &s) + { + if (s.basename==std::string("void")){ + static const char * none = "None"; + return none; + } + + PyTypeObject const * py_type = s.pytype_f?s.pytype_f():0; + if ( py_type ) + return py_type->tp_name; + else{ + static const char * object = "object"; + return object; + } + } + + str function_doc_signature_generator::parameter_string(py_function const &f, size_t n, object arg_names, bool cpp_types) + { + str param; + + python::detail::signature_element const * s = f.signature(); + if (cpp_types) + { + if(!n) + s = &f.get_return_type(); + if (s[n].basename == 0) + { + return str("..."); + } + + param = str(s[n].basename); + + if (s[n].lvalue) + param += " {lvalue}"; + + } + else + { + if (n) //we are processing an argument and trying to come up with a name for it + { + object kv; + if ( arg_names && (kv = arg_names[n-1]) ) + param = str( " (%s)%s" % make_tuple(py_type_str(s[n]),kv[0]) ); + else + param = str(" (%s)%s%d" % make_tuple(py_type_str(s[n]),"arg", n) ); + } + else //we are processing the return type + param = py_type_str(f.get_return_type()); + } + + //an argument - check for default value and append it + if(n && arg_names) + { + object kv(arg_names[n-1]); + if (kv && len(kv) == 2) + { + param = str("%s=%r" % make_tuple(param, kv[1])); + } + } + return param; + } + + str function_doc_signature_generator::pretty_signature(function const *f, size_t n_overloads, bool cpp_types ) + { + py_function + const& impl = f->m_fn; + ; + + + unsigned arity = impl.max_arity(); + + if(arity == unsigned(-1))// is this the proper raw function test? + { + return raw_function_pretty_signature(f,n_overloads,cpp_types); + } + + list formal_params; + + size_t n_extra_default_args=0; + + for (unsigned n = 0; n <= arity; ++n) + { + str param; + + formal_params.append( + parameter_string(impl, n, f->m_arg_names, cpp_types) + ); + + // find all the arguments with default values preceeding the arity-n_overloads + if (n && f->m_arg_names) + { + object kv(f->m_arg_names[n-1]); + + if (kv && len(kv) == 2) + { + //default argument preceeding the arity-n_overloads + if( n <= arity-n_overloads) + ++n_extra_default_args; + } + else + //argument without default, preceeding the arity-n_overloads + if( n <= arity-n_overloads) + n_extra_default_args = 0; + } + } + + n_overloads+=n_extra_default_args; + + if (!arity && cpp_types) + formal_params.append("void"); + + str ret_type (formal_params.pop(0)); + if (cpp_types ) + { + return str( + "%s %s(%s%s%s%s)" + % make_tuple + ( ret_type + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + )); + }else{ + return str( + "%s(%s%s%s%s) -> %s" + % make_tuple + ( f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , ret_type + )); + } + + return str( + "%s %s(%s%s%s%s) %s" + % make_tuple + ( cpp_types?ret_type:str("") + , f->m_name + , str(",").join(formal_params.slice(0,arity-n_overloads)) + , n_overloads ? (n_overloads!=arity?str(" [,"):str("[ ")) : str() + , str(" [,").join(formal_params.slice(arity-n_overloads,arity)) + , std::string(n_overloads,']') + , cpp_types?str(""):ret_type + )); + + } + + namespace detail { + char py_signature_tag[] = "PY signature : "; + char cpp_signature_tag[] = "C++ signature:"; + } + + list function_doc_signature_generator::function_doc_signatures( function const * f) + { + list signatures; + std::vector funcs = flatten( f); + std::vector split_funcs = split_seq_overloads( funcs, true); + std::vector::const_iterator sfi=split_funcs.begin(), fi; + size_t n_overloads=0; + for (fi=funcs.begin(); fi!=funcs.end(); ++fi) + { + if(*sfi == *fi){ + if((*fi)->doc()){ + str func_doc = str((*fi)->doc()); + int doc_len = len(func_doc); + bool show_py_signature = doc_len >=int(sizeof(detail::py_signature_tag)/sizeof(char)-1) + && str(detail::py_signature_tag)==func_doc.slice(0, int(sizeof(detail::py_signature_tag)/sizeof(char))-1); + bool show_cpp_signature = doc_len >=int(sizeof(detail::cpp_signature_tag)/sizeof(char)) + && str(detail::cpp_signature_tag)==func_doc.slice(- int(sizeof(detail::cpp_signature_tag)/sizeof(char))+1, _); + + str res; + if(show_py_signature) + { + str sig = pretty_signature(*fi, n_overloads,false); + res+=sig; + if(doc_len > int(sizeof(detail::py_signature_tag)/sizeof(char))-1 ) + res+=" : "+func_doc.slice(int(sizeof(detail::py_signature_tag)/sizeof(char))-1,_); + }else + res+=func_doc; + + if( show_cpp_signature) + res+=str("\n ")+pretty_signature(*fi, n_overloads,true); + + signatures.append(res); + } + ++sfi; + n_overloads = 0; + }else + ++n_overloads ; + } + return signatures; + } + + +}}} + diff --git a/src/str.cpp b/src/str.cpp index 5216cf54..7ee748a3 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -349,5 +349,15 @@ BOOST_PYTHON_DEFINE_STR_METHOD(title, 0) BOOST_PYTHON_DEFINE_STR_METHOD(translate, 1) BOOST_PYTHON_DEFINE_STR_METHOD(translate, 2) BOOST_PYTHON_DEFINE_STR_METHOD(upper, 0) + +static struct register_str_pytype_ptr +{ + register_str_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyString_Type; + } +}register_str_pytype_ptr_; }}} // namespace boost::python diff --git a/src/tuple.cpp b/src/tuple.cpp index a6820b70..b5696504 100644 --- a/src/tuple.cpp +++ b/src/tuple.cpp @@ -21,4 +21,15 @@ tuple_base::tuple_base(object_cref sequence) : object(call(sequence)) {} +static struct register_tuple_pytype_ptr +{ + register_tuple_pytype_ptr() + { + const_cast( + converter::registry::lookup(boost::python::type_id()) + ).m_class_object = &PyTuple_Type; + } +}register_tuple_pytype_ptr_; + + }}} // namespace boost::python diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0dffc26e..a13bfe01 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -135,6 +135,7 @@ bpl-test crossmod_opaque [ bpl-test nested ] [ bpl-test docstring ] +[ bpl-test pytype_function ] [ bpl-test vector_indexing_suite ] @@ -147,7 +148,7 @@ bpl-test crossmod_opaque hp_cxx:no ] [ python-extension map_indexing_suite_ext - : map_indexing_suite.cpp int_map_indexing_suite.cpp + : map_indexing_suite.cpp int_map_indexing_suite.cpp a_map_indexing_suite.cpp /boost/python//boost_python ] [ bpl-test map_indexing_suite : map_indexing_suite.py map_indexing_suite_ext ] diff --git a/test/a_map_indexing_suite.cpp b/test/a_map_indexing_suite.cpp new file mode 100755 index 00000000..30b5ea03 --- /dev/null +++ b/test/a_map_indexing_suite.cpp @@ -0,0 +1,84 @@ +// Copyright Joel de Guzman 2004. 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) + +#include +#include +#include +#include + +using namespace boost::python; + +struct A +{ + int value; + A() : value(0){}; + A(int v) : value(v) {}; +}; + +bool operator==(const A& v1, const A& v2) +{ + return (v1.value == v2.value); +} + +struct B +{ + A a; +}; + +// Converter from A to python int +struct AToPython +{ + static PyObject* convert(const A& s) + { + return boost::python::incref(boost::python::object((int)s.value).ptr()); + } +}; + +// Conversion from python int to A +struct AFromPython +{ + AFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< A >()); + } + + static void* convertible(PyObject* obj_ptr) + { + if (!PyInt_Check(obj_ptr)) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< A >*) + data)-> storage.bytes; + + new (storage) A((int)PyInt_AsLong(obj_ptr)); + data->convertible = storage; + } +}; + +void a_map_indexing_suite() +{ + + to_python_converter< A , AToPython >(); + AFromPython(); + + class_< std::map >("AMap") + .def(map_indexing_suite, true >()) + ; + + class_< B >("B") + .add_property("a", make_getter(&B::a, return_value_policy()), + make_setter(&B::a, return_value_policy())) + ; +} + + diff --git a/test/args.cpp b/test/args.cpp index 20e0e532..38796057 100644 --- a/test/args.cpp +++ b/test/args.cpp @@ -51,7 +51,7 @@ tuple raw_func(tuple args, dict kw) BOOST_PYTHON_MODULE(args_ext) { - def("f", f, args("x", "y", "z") + def("f", f, (arg("x")=1, arg("y")=4.25, arg("z")="wow") , "This is f's docstring" ); @@ -72,24 +72,24 @@ BOOST_PYTHON_MODULE(args_ext) .def("raw", raw_function(raw_func)) ; - class_("X", "This is X's docstring") - .def(init >(args("a0", "a1"))) + class_("X", "This is X's docstring", init<>(args("self"))) + .def(init >(args("self", "a0", "a1"))) .def("f", &X::f , "This is X.f's docstring" - , args("x", "y", "z")) + , args("self","x", "y", "z")) // Just to prove that all the different argument combinations work - .def("inner0", &X::inner, return_internal_reference<>(), args("n"), "docstring") - .def("inner1", &X::inner, return_internal_reference<>(), "docstring", args("n")) + .def("inner0", &X::inner, return_internal_reference<>(), args("self", "n"), "docstring") + .def("inner1", &X::inner, return_internal_reference<>(), "docstring", args("self", "n")) - .def("inner2", &X::inner, args("n"), return_internal_reference<>(), "docstring") - .def("inner3", &X::inner, "docstring", return_internal_reference<>(), args("n")) + .def("inner2", &X::inner, args("self", "n"), return_internal_reference<>(), "docstring") + .def("inner3", &X::inner, "docstring", return_internal_reference<>(), args("self", "n")) - .def("inner4", &X::inner, args("n"), "docstring", return_internal_reference<>()) - .def("inner5", &X::inner, "docstring", args("n"), return_internal_reference<>()) + .def("inner4", &X::inner, args("self", "n"), "docstring", return_internal_reference<>()) + .def("inner5", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()) - .def("f1", &X::f, X_f_overloads(args("x", "y", "z"))) - .def("f2", &X::f, X_f_overloads(args("x", "y", "z"), "f2's docstring")) + .def("f1", &X::f, X_f_overloads(args("self", "x", "y", "z"))) + .def("f2", &X::f, X_f_overloads(args("self", "x", "y", "z"), "f2's docstring")) ; def("inner", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()); diff --git a/test/args.py b/test/args.py index 2dcd9d1b..15be2b97 100644 --- a/test/args.py +++ b/test/args.py @@ -84,24 +84,24 @@ (2, 4.25, 'wow') >>> q.f1() (1, 4.25, 'wow') ->>> q.f2.__doc__.splitlines()[-4] -"f2's docstring" +>>> q.f2.__doc__.splitlines()[-3] +"f2( (X)self [, (int)x [, (float)y [, (str)z]]]) -> tuple : f2's docstring" ->>> X.f.__doc__.splitlines()[:3] -["This is X.f's docstring", '', 'C++ signature:'] +>>> X.f.__doc__.splitlines()[:2] +["f( (X)self, (int)x, (float)y, (str)z) -> tuple : This is X.f's docstring", ' C++ signature:'] >>> xfuncs = (X.inner0, X.inner1, X.inner2, X.inner3, X.inner4, X.inner5) >>> for f in xfuncs: ... print f(q,1).value(), ... print f(q, n = 1).value(), ... print f(q, n = 0).value(), -... print f.__doc__.splitlines()[:3] -1 1 0 ['docstring', '', 'C++ signature:'] -1 1 0 ['docstring', '', 'C++ signature:'] -1 1 0 ['docstring', '', 'C++ signature:'] -1 1 0 ['docstring', '', 'C++ signature:'] -1 1 0 ['docstring', '', 'C++ signature:'] -1 1 0 ['docstring', '', 'C++ signature:'] +... print f.__doc__.splitlines()[:2] +1 1 0 ['inner0( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] +1 1 0 ['inner1( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] +1 1 0 ['inner2( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] +1 1 0 ['inner3( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] +1 1 0 ['inner4( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] +1 1 0 ['inner5( (X)self, (bool)n) -> Y : docstring', ' C++ signature:'] >>> x = X(a1 = 44, a0 = 22) >>> x.inner0(0).value() @@ -136,49 +136,9 @@ if __name__ == '__main__': import sys status = run()[0] if (status == 0): print "Done." + import args_ext + help(args_ext) sys.exit(status) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/auto_ptr.py b/test/auto_ptr.py index 0e189a88..a1e24392 100644 --- a/test/auto_ptr.py +++ b/test/auto_ptr.py @@ -64,6 +64,24 @@ ... except TypeError: pass ... else: print 'expected a TypeError exception' +>>> print look.__doc__.splitlines()[0] +look( (X)arg1) -> int : + +>>> print steal.__doc__.splitlines()[0] +steal( (X)arg1) -> int : + +>>> print maybe_steal.__doc__.splitlines()[0] +maybe_steal( (X)arg1, (bool)arg2) -> int : + +>>> print make.__doc__.splitlines()[0] +make() -> X : + +>>> print callback.__doc__.splitlines()[0] +callback( (object)arg1) -> X : + +>>> print extract.__doc__.splitlines()[0] +extract( (object)arg1) -> X : + ''' def run(args = None): diff --git a/test/back_reference.py b/test/back_reference.py index 9ff809a0..ed595ad0 100644 --- a/test/back_reference.py +++ b/test/back_reference.py @@ -16,6 +16,9 @@ >>> assert y_identity(y) is y >>> y_equality(y, y) 1 + +>>> print y_identity.__doc__.splitlines()[0] +y_identity( (Y)arg1) -> object : ''' def run(args = None): diff --git a/test/data_members.cpp b/test/data_members.cpp index 5180c192..6d2cc7bd 100644 --- a/test/data_members.cpp +++ b/test/data_members.cpp @@ -52,7 +52,7 @@ int Var::static1 = 0; Y Var::static2(0); // Compilability regression tests -namespace +namespace boost_python_test { struct trivial { @@ -86,6 +86,7 @@ namespace BOOST_PYTHON_MODULE(data_members_ext) { + using namespace boost_python_test; class_("X", init()) .def("value", &X::value) .def("set", &X::set) diff --git a/test/defaults.cpp b/test/defaults.cpp index 5f95c544..4f3d3e57 100644 --- a/test/defaults.cpp +++ b/test/defaults.cpp @@ -159,10 +159,10 @@ BOOST_PYTHON_MODULE(defaults_ext) .def("get_state", &Y::get_state) ; - class_("X") + class_("X",no_init) - .def(init >("doc of init")) - .def(init()[default_call_policies()]) // what's a good policy here? + .def(init >("doc of init", args("self", "a", "b", "c", "d"))) + .def(init(args("self", "s", "b"))[default_call_policies()]) // what's a good policy here? .def("get_state", &X::get_state) .def("bar", &X::bar, X_bar_stubs()) .def("bar2", &X::bar2, X_bar_stubs2("doc of X::bar2")[return_internal_reference<>()]) diff --git a/test/defaults.py b/test/defaults.py index 8022f7a4..153f7de1 100644 --- a/test/defaults.py +++ b/test/defaults.py @@ -113,28 +113,19 @@ ... doc = obj.__doc__.splitlines() ... return "\\n".join(["|"+doc[i] for i in args]) ->>> print selected_doc(X.__init__, 0, 3, 6, 9, 11, 12, 14, 17) -|C++ signature: -|C++ signature: -|C++ signature: -|C++ signature: -| -|doc of init -|C++ signature: -|C++ signature: +>>> print selected_doc(X.__init__, 0, 1, 3, 4) +|__init__( (object)self [, (int)a [, (str)b [, (str)c [, (float)d]]]]) -> None : doc of init +| C++ signature: +| __init__( (object)self, (str)s, (bool)b) -> None : +| C++ signature: ->>> print selected_doc(Y.__init__, 0, 2) -|doc of Y init -|C++ signature: +>>> print selected_doc(Y.__init__, 0, 1) +|__init__( (object)arg1) -> None : doc of Y init +| C++ signature: ->>> print selected_doc(X.bar2, 0, 3, 6, 9, 11, 12, 14) -|C++ signature: -|C++ signature: -|C++ signature: -|C++ signature: -| -|doc of X::bar2 -|C++ signature: +>>> print selected_doc(X.bar2, 0, 1) +|bar2( (X)arg1 [, (int)arg2 [, (str)arg3 [, (str)arg4 [, (float)arg5]]]]) -> Y : doc of X::bar2 +| C++ signature: """ def run(args = None): diff --git a/test/docstring.cpp b/test/docstring.cpp index eb036d0f..c6cc0252 100644 --- a/test/docstring.cpp +++ b/test/docstring.cpp @@ -43,55 +43,74 @@ BOOST_PYTHON_MODULE(docstring_ext) , init( "this is the __init__ function\n" "its documentation has two lines." + , args("self", "value") ) ) .def("value", &X::value, - "gets the value of the object") + "gets the value of the object" + , args("self")) .def( "value", &X::value, - "also gets the value of the object") + "also gets the value of the object" + , args("self")) ; def("create", create, return_value_policy(), - "creates a new X object"); + "creates a new X object", args("value")); - def("fact", fact, "compute the factorial"); + def("fact", fact, "compute the factorial", args("n")); { docstring_options doc_options; doc_options.disable_user_defined(); - def("fact_usr_off_1", fact, "usr off 1"); + def("fact_usr_off_1", fact, "usr off 1", args("n")); doc_options.enable_user_defined(); - def("fact_usr_on_1", fact, "usr on 1"); + def("fact_usr_on_1", fact, "usr on 1", args("n")); doc_options.disable_user_defined(); - def("fact_usr_off_2", fact, "usr off 2"); + def("fact_usr_off_2", fact, "usr off 2", args("n")); } - def("fact_usr_on_2", fact, "usr on 2"); + def("fact_usr_on_2", fact, "usr on 2", args("n")); { docstring_options doc_options(true, false); - def("fact_sig_off_1", fact, "sig off 1"); + def("fact_sig_off_1", fact, "sig off 1", args("n")); doc_options.enable_signatures(); - def("fact_sig_on_1", fact, "sig on 1"); + def("fact_sig_on_1", fact, "sig on 1", args("n")); doc_options.disable_signatures(); - def("fact_sig_off_2", fact, "sig off 2"); + def("fact_sig_off_2", fact, "sig off 2", args("n")); } - def("fact_sig_on_2", fact, "sig on 2"); + def("fact_sig_on_2", fact, "sig on 2", args("n")); { docstring_options doc_options(false); - def("fact_usr_off_sig_off_1", fact, "usr off sig off 1"); + def("fact_usr_off_sig_off_1", fact, "usr off sig off 1", args("n")); { docstring_options nested_doc_options; - def("fact_usr_on_sig_on_1", fact, "usr on sig on 1"); + def("fact_usr_on_sig_on_1", fact, "usr on sig on 1", args("n")); nested_doc_options.disable_all(); nested_doc_options.enable_user_defined(); - def("fact_usr_on_sig_off_1", fact, "usr on sig off 1"); + def("fact_usr_on_sig_off_1", fact, "usr on sig off 1", args("n")); nested_doc_options.enable_all(); - def("fact_usr_on_sig_on_2", fact, "usr on sig on 2"); + def("fact_usr_on_sig_on_2", fact, "usr on sig on 2", args("n")); } - def("fact_usr_off_sig_off_2", fact, "usr off sig off 2"); + def("fact_usr_off_sig_off_2", fact, "usr off sig off 2", args("n")); } + + { + docstring_options doc_options(true); + doc_options.disable_cpp_signatures(); + def("fact_usr_on_psig_on_csig_off_1", fact, "usr on psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_on_psig_off_csig_on_1", fact, "usr on psig off csig on 1", args("n")); + doc_options.enable_py_signatures(); + doc_options.disable_user_defined(); + doc_options.disable_cpp_signatures(); + def("fact_usr_off_psig_on_csig_off_1", fact, "usr off psig on csig off 1", args("n")); + doc_options.enable_cpp_signatures(); + doc_options.disable_py_signatures(); + def("fact_usr_off_psig_off_csig_on_1", fact, "usr off psig off csig on 1", args("n")); + } } #include "module_tail.cpp" diff --git a/test/docstring.py b/test/docstring.py index c350d210..2ad98139 100644 --- a/test/docstring.py +++ b/test/docstring.py @@ -8,82 +8,99 @@ ... doc = obj.__doc__.splitlines() ... return "\\n".join(["|"+doc[i] for i in args]) ->>> print selected_doc(X.__init__, 0, 1, 3) -|this is the __init__ function +>>> print selected_doc(X.__init__, 0, 1, 2) +|__init__( (object)self, (int)value) -> None : this is the __init__ function |its documentation has two lines. -|C++ signature: +| C++ signature: ->>> print selected_doc(X.value, 0, 2, 4, 5, 7) -|gets the value of the object -|C++ signature: -| -|also gets the value of the object -|C++ signature: +>>> print selected_doc(X.value, 0, 1, 3, 4) +|value( (X)self) -> int : gets the value of the object +| C++ signature: +| value( (X)self) -> int : also gets the value of the object +| C++ signature: ->>> print selected_doc(create, 0, 2) -|creates a new X object -|C++ signature: +>>> print selected_doc(create, 0, 1) +|create( (int)value) -> X : creates a new X object +| C++ signature: ->>> print selected_doc(fact, 0, 2) -|compute the factorial -|C++ signature: +>>> print selected_doc(fact, 0, 1) +|fact( (int)n) -> int : compute the factorial +| C++ signature: >>> len(fact_usr_off_1.__doc__.splitlines()) -2 ->>> print selected_doc(fact_usr_off_1, 0) -|C++ signature: +3 +>>> print selected_doc(fact_usr_off_1, 0, 1) +|fact_usr_off_1( (int)n) -> int : +| C++ signature: >>> len(fact_usr_on_1.__doc__.splitlines()) -4 ->>> print selected_doc(fact_usr_on_1, 0, 2) -|usr on 1 -|C++ signature: +3 +>>> print selected_doc(fact_usr_on_1, 0, 1) +|fact_usr_on_1( (int)n) -> int : usr on 1 +| C++ signature: >>> len(fact_usr_off_2.__doc__.splitlines()) -2 ->>> print selected_doc(fact_usr_off_2, 0) -|C++ signature: +3 +>>> print selected_doc(fact_usr_off_2, 0,1) +|fact_usr_off_2( (int)n) -> int : +| C++ signature: >>> len(fact_usr_on_2.__doc__.splitlines()) -4 ->>> print selected_doc(fact_usr_on_2, 0, 2) -|usr on 2 -|C++ signature: +3 +>>> print selected_doc(fact_usr_on_2, 0, 1) +|fact_usr_on_2( (int)n) -> int : usr on 2 +| C++ signature: + >>> len(fact_sig_off_1.__doc__.splitlines()) 1 >>> print selected_doc(fact_sig_off_1, 0) |sig off 1 >>> len(fact_sig_on_1.__doc__.splitlines()) -4 ->>> print selected_doc(fact_sig_on_1, 0, 2) -|sig on 1 -|C++ signature: +3 +>>> print selected_doc(fact_sig_on_1, 0, 1) +|fact_sig_on_1( (int)n) -> int : sig on 1 +| C++ signature: + >>> len(fact_sig_off_2.__doc__.splitlines()) 1 >>> print selected_doc(fact_sig_off_2, 0) |sig off 2 >>> len(fact_sig_on_2.__doc__.splitlines()) -4 ->>> print selected_doc(fact_sig_on_2, 0, 2) -|sig on 2 -|C++ signature: +3 +>>> print selected_doc(fact_sig_on_2, 0, 1) +|fact_sig_on_2( (int)n) -> int : sig on 2 +| C++ signature: + >>> print fact_usr_off_sig_off_1.__doc__ None >>> len(fact_usr_on_sig_on_1.__doc__.splitlines()) -4 ->>> print selected_doc(fact_usr_on_sig_on_1, 0, 2) -|usr on sig on 1 -|C++ signature: +3 +>>> print selected_doc(fact_usr_on_sig_on_1, 0, 1) +|fact_usr_on_sig_on_1( (int)n) -> int : usr on sig on 1 +| C++ signature: + >>> len(fact_usr_on_sig_off_1.__doc__.splitlines()) 1 >>> print selected_doc(fact_usr_on_sig_off_1, 0) |usr on sig off 1 >>> len(fact_usr_on_sig_on_2.__doc__.splitlines()) -4 ->>> print selected_doc(fact_usr_on_sig_on_2, 0, 2) -|usr on sig on 2 -|C++ signature: ->>> print fact_usr_off_sig_off_2.__doc__ -None +3 +>>> print selected_doc(fact_usr_on_sig_on_2, 0, 1) +|fact_usr_on_sig_on_2( (int)n) -> int : usr on sig on 2 +| C++ signature: + +>>> print fact_usr_on_psig_on_csig_off_1.__doc__ +fact_usr_on_psig_on_csig_off_1( (int)n) -> int : usr on psig on csig off 1 + +>>> print selected_doc(fact_usr_on_psig_off_csig_on_1, 0, 1) +|usr on psig off csig on 1 +| C++ signature: + +>>> print fact_usr_off_psig_on_csig_off_1.__doc__ +fact_usr_off_psig_on_csig_off_1( (int)n) -> int + +>>> print selected_doc(fact_usr_off_psig_off_csig_on_1,0) +| C++ signature: + ''' diff --git a/test/implicit.py b/test/implicit.py index caa87fe8..f99c8d88 100644 --- a/test/implicit.py +++ b/test/implicit.py @@ -13,6 +13,19 @@ >>> try: make_x('fool') ... except TypeError: pass ... else: print 'no error' + +>>> print x_value.__doc__.splitlines()[0] +x_value( (X)arg1) -> int : + +>>> print make_x.__doc__.splitlines()[0] +make_x( (object)arg1) -> X : + +>>> print X.value.__doc__.splitlines()[0] +value( (X)arg1) -> int : + +>>> print X.set.__doc__.splitlines()[0] +set( (X)arg1, (object)arg2) -> None : + ''' def run(args = None): diff --git a/test/keywords_test.py b/test/keywords_test.py index fabf30eb..7f5da987 100644 --- a/test/keywords_test.py +++ b/test/keywords_test.py @@ -80,8 +80,8 @@ >>> f.set(1,1.0,"1") >>> f.a(), f.b(), f.n() (1, 1.0, '1') ->>> f.set2.__doc__.splitlines()[-4] -"set2's docstring" +>>> f.set2.__doc__.splitlines()[-3] +"set2( (Bar)arg1 [, (int)arg2 [, (float)arg3 [, (str)arg4]]]) -> None : set2's docstring" ''' diff --git a/test/m1.cpp b/test/m1.cpp index e1635b16..407924fe 100644 --- a/test/m1.cpp +++ b/test/m1.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "simple_type.hpp" #include "complicated.hpp" @@ -170,7 +171,8 @@ using boost::python::to_python_converter; // Wrap a simple by copying it into a Simple struct simple_to_python - : to_python_converter + : to_python_converter + //, boost::python::converter::wrap_pytype<&SimpleType> { static PyObject* convert(simple const& x) { @@ -178,6 +180,7 @@ struct simple_to_python p->x = x; return (PyObject*)p; } + static PyTypeObject const *get_pytype(){return &SimpleType; } }; struct int_from_noddy diff --git a/test/map_indexing_suite.cpp b/test/map_indexing_suite.cpp index 8b5e3b6e..899d71f2 100644 --- a/test/map_indexing_suite.cpp +++ b/test/map_indexing_suite.cpp @@ -26,61 +26,6 @@ std::string x_value(X const& x) return "gotya " + x.s; } -struct A -{ - int value; - A() : value(0){}; - A(int v) : value(v) {}; -}; - -bool operator==(const A& v1, const A& v2) -{ - return (v1.value == v2.value); -} - -struct B -{ - A a; -}; - -// Converter from A to python int -struct AToPython -{ - static PyObject* convert(const A& s) - { - return boost::python::incref(boost::python::object((int)s.value).ptr()); - } -}; - -// Conversion from python int to A -struct AFromPython -{ - AFromPython() - { - boost::python::converter::registry::push_back( - &convertible, - &construct, - boost::python::type_id< A >()); - } - - static void* convertible(PyObject* obj_ptr) - { - if (!PyInt_Check(obj_ptr)) return 0; - return obj_ptr; - } - - static void construct( - PyObject* obj_ptr, - boost::python::converter::rvalue_from_python_stage1_data* data) - { - void* storage = ( - (boost::python::converter::rvalue_from_python_storage< A >*) - data)-> storage.bytes; - - new (storage) A((int)PyInt_AsLong(obj_ptr)); - data->convertible = storage; - } -}; BOOST_PYTHON_MODULE(map_indexing_suite_ext) { @@ -115,17 +60,9 @@ BOOST_PYTHON_MODULE(map_indexing_suite_ext) .def(map_indexing_suite >, true>()) ; - to_python_converter< A , AToPython >(); - AFromPython(); - - class_< std::map >("AMap") - .def(map_indexing_suite, true >()) - ; - - class_< B >("B") - .add_property("a", make_getter(&B::a, return_value_policy()), - make_setter(&B::a, return_value_policy())) - ; + void a_map_indexing_suite(); // moved to a_map_indexing_suite.cpp to + a_map_indexing_suite(); // avoid MSVC 6/7 internal structure overflow + } #include "module_tail.cpp" diff --git a/test/newtest.py b/test/newtest.py index 604755ff..23c4298a 100644 --- a/test/newtest.py +++ b/test/newtest.py @@ -183,6 +183,8 @@ are a complicated constructor and member function, respectively. >>> dd = take_d(d_as_a) >>> dd.name() 'D' +>>> print g.__doc__.splitlines()[0] +g( (Simple)arg1) -> Simple : """ diff --git a/test/pickle1.cpp b/test/pickle1.cpp index c1f8c805..28845fc9 100644 --- a/test/pickle1.cpp +++ b/test/pickle1.cpp @@ -19,7 +19,7 @@ #include -namespace { +namespace boost_python_test { // A friendly class. class world @@ -52,6 +52,7 @@ namespace { BOOST_PYTHON_MODULE(pickle1_ext) { using namespace boost::python; + using namespace boost_python_test; class_("world", init()) .def("greet", &world::greet) .def_pickle(world_pickle_suite()) diff --git a/test/pickle2.cpp b/test/pickle2.cpp index eb50cca3..1c08cbd0 100644 --- a/test/pickle2.cpp +++ b/test/pickle2.cpp @@ -28,7 +28,7 @@ #include #include -namespace { // Avoid cluttering the global namespace. +namespace boost_python_test { // A friendly class. class world @@ -88,6 +88,7 @@ namespace { // Avoid cluttering the global namespace. BOOST_PYTHON_MODULE(pickle2_ext) { + using namespace boost_python_test; boost::python::class_( "world", boost::python::init()) .def("greet", &world::greet) diff --git a/test/pickle3.cpp b/test/pickle3.cpp index 2816a428..01ce27cf 100644 --- a/test/pickle3.cpp +++ b/test/pickle3.cpp @@ -29,7 +29,7 @@ # define make_tuple boost::python::make_tuple #endif -namespace { // Avoid cluttering the global namespace. +namespace boost_python_test { // A friendly class. class world @@ -100,6 +100,7 @@ namespace { // Avoid cluttering the global namespace. BOOST_PYTHON_MODULE(pickle3_ext) { + using namespace boost_python_test; boost::python::class_( "world", boost::python::init()) .def("greet", &world::greet) diff --git a/test/pickle4.cpp b/test/pickle4.cpp index 55fc8365..d9758c28 100644 --- a/test/pickle4.cpp +++ b/test/pickle4.cpp @@ -15,7 +15,7 @@ #include -namespace { +namespace boost_python_test { // A friendly class. class world @@ -35,6 +35,7 @@ namespace { BOOST_PYTHON_MODULE(pickle4_ext) { using namespace boost::python; + using namespace boost_python_test; class_("world", init()) .enable_pickling() .def("greet", &world::greet) diff --git a/test/pytype_function.cpp b/test/pytype_function.cpp new file mode 100644 index 00000000..46cce19e --- /dev/null +++ b/test/pytype_function.cpp @@ -0,0 +1,85 @@ +// Copyright Joel de Guzman 2004. 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) + +#include +#include +#include +#include +#include + +using namespace boost::python; + +struct A +{ +}; + +struct B +{ + A a; + B(const A& a_):a(a_){} +}; + +// Converter from A to python int +struct BToPython +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + : converter::to_python_target_type //inherits get_pytype +#endif +{ + static PyObject* convert(const B& b) + { + return boost::python::incref(boost::python::object(b.a).ptr()); + } +}; + +// Conversion from python int to A +struct BFromPython +{ + BFromPython() + { + boost::python::converter::registry::push_back( + &convertible, + &construct, + boost::python::type_id< B >() +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + , &converter::expected_from_python_type::get_pytype//convertible to A can be converted to B +#endif + ); + } + + static void* convertible(PyObject* obj_ptr) + { + extract ex(obj_ptr); + if (!ex.check()) return 0; + return obj_ptr; + } + + static void construct( + PyObject* obj_ptr, + boost::python::converter::rvalue_from_python_stage1_data* data) + { + void* storage = ( + (boost::python::converter::rvalue_from_python_storage< B >*)data)-> storage.bytes; + + extract ex(obj_ptr); + new (storage) B(ex()); + data->convertible = storage; + } +}; + + +B func(const B& b) { return b ; } + + +BOOST_PYTHON_MODULE(pytype_function_ext) +{ + to_python_converter< B , BToPython,true >(); //has get_pytype + BFromPython(); + + class_("A") ; + + def("func", &func); + +} + +#include "module_tail.cpp" diff --git a/test/pytype_function.py b/test/pytype_function.py new file mode 100755 index 00000000..d2f46c9f --- /dev/null +++ b/test/pytype_function.py @@ -0,0 +1,27 @@ +# Copyright David Abrahams 2004. 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) +""" +>>> from pytype_function_ext import * + +>>> print (' ').join(func.__doc__.splitlines()) +func( (A)arg1) -> A : C++ signature: struct B func(struct B) + +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) + + +