2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-19 04:22:16 +00:00

This commit was manufactured by cvs2svn to create tag

'merged_to_RC_1_30_0'.

[SVN r19627]
This commit is contained in:
nobody
2003-08-16 01:05:44 +00:00
parent b8028729eb
commit f5af86616d
113 changed files with 595 additions and 4935 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -9,10 +9,12 @@
:Author: Ralf W. Grosse-Kunstleve
:status: Draft
:copyright: Copyright David Abrahams and Ralf W. Grosse-Kunstleve 2003. All rights reserved
.. contents:: Table of Contents
.. _`Boost Consulting`: http://www.boost-consulting.com
==========
@@ -629,22 +631,19 @@ virtual functions. At least one very promising project has been
started to write a front-end which can generate these dispatchers (and
other wrapping code) automatically from C++ headers.
Pyste_ is being developed by Bruno da Silva de Oliveira. It builds on
GCC_XML_, which generates an XML version of GCC's internal program
representation. Since GCC is a highly-conformant C++ compiler, this
ensures correct handling of the most-sophisticated template code and
full access to the underlying type system. In keeping with the
Boost.Python philosophy, a Pyste interface description is neither
intrusive on the code being wrapped, nor expressed in some unfamiliar
language: instead it is a 100% pure Python script. If Pyste is
successful it will mark a move away from wrapping everything directly
in C++ for many of our users. It will also allow us the choice to
shift some of the metaprogram code from C++ to Python. We expect that
soon, not only our users but the Boost.Python developers themselves
will be "thinking hybrid" about their own code.
Pyste builds on GCC_XML_, which generates an XML version of GCC's
internal program representation. Since GCC is a highly-conformant C++
compiler, this ensures correct handling of the most-sophisticated
template code and full access to the underlying type system. In
keeping with the Boost.Python philosophy, a Pyste interface
description is neither intrusive on the code being wrapped, nor
expressed in some unfamiliar language: instead it is a 100% pure
Python script. If Pyste is successful it will mark a move away from
wrapping everything directly in C++ for many of our users. We expect
that soon, not only our users but the Boost.Python developers
themselves will be "thinking hybrid" about their own code.
.. _`GCC_XML`: http://www.gccxml.org/HTML/Index.html
.. _`Pyste`: http://www.boost.org/libs/python/pyste
---------------
Serialization
@@ -771,6 +770,15 @@ This almost looks and works like regular Python code, but it is pure
C++. Of course we can wrap C++ functions which accept or return
``object`` instances.
.. =====================
Development history
=====================
XXX Outline of development history to illustrate that the
library is mature. XXX
This can be postponed for the PyConDC paper
=================
Thinking hybrid
=================
@@ -808,7 +816,7 @@ mainly concentrated on the C++ parts. However, as the toolbox is
becoming more complete, more and more newly added functionality can be
implemented in Python.
.. image:: python_cpp_mix.jpg
.. image:: python_cpp_mix.png
This figure shows the estimated ratio of newly added C++ and Python
code over time as new algorithms are implemented. We expect this
@@ -818,87 +826,6 @@ language is the return on our investment in Boost.Python. The ability
to access all of our code from Python allows a broader group of
developers to use it in the rapid development of new applications.
=====================
Development history
=====================
The first version of Boost.Python was developed in 2000 by Dave
Abrahams at Dragon Systems, where he was privileged to have Tim Peters
as a guide to "The Zen of Python". One of Dave's jobs was to develop
a Python-based natural language processing system. Since it was
eventually going to be targeting embedded hardware, it was always
assumed that the compute-intensive core would be rewritten in C++ to
optimize speed and memory footprint [#proto]_. The project also wanted to
test all of its C++ code using Python test scripts [#test]_. The only
tool we knew of for binding C++ and Python was SWIG_, and at the time
its handling of C++ was weak. It would be false to claim any deep
insight into the possible advantages of Boost.Python's approach at
this point. Dave's interest and expertise in fancy C++ template
tricks had just reached the point where he could do some real damage,
and Boost.Python emerged as it did because it filled a need and
because it seemed like a cool thing to try.
This early version was aimed at many of the same basic goals we've
described in this paper, differing most-noticeably by having a
slightly more cumbersome syntax and by lack of special support for
operator overloading, pickling, and component-based development.
These last three features were quickly added by Ullrich Koethe and
Ralf Grosse-Kunstleve [#feature]_, and other enthusiastic contributors arrived
on the scene to contribute enhancements like support for nested
modules and static member functions.
By early 2001 development had stabilized and few new features were
being added, however a disturbing new fact came to light: Ralf had
begun testing Boost.Python on pre-release versions of a compiler using
the EDG_ front-end, and the mechanism at the core of Boost.Python
responsible for handling conversions between Python and C++ types was
failing to compile. As it turned out, we had been exploiting a very
common bug in the implementation of all the C++ compilers we had
tested. We knew that as C++ compilers rapidly became more
standards-compliant, the library would begin failing on more
platforms. Unfortunately, because the mechanism was so central to the
functioning of the library, fixing the problem looked very difficult.
Fortunately, later that year Lawrence Berkeley and later Lawrence
Livermore National labs contracted with `Boost Consulting`_ for support
and development of Boost.Python, and there was a new opportunity to
address fundamental issues and ensure a future for the library. A
redesign effort began with the low level type conversion architecture,
building in standards-compliance and support for component-based
development (in contrast to version 1 where conversions had to be
explicitly imported and exported across module boundaries). A new
analysis of the relationship between the Python and C++ objects was
done, resulting in more intuitive handling for C++ lvalues and
rvalues.
The emergence of a powerful new type system in Python 2.2 made the
choice of whether to maintain compatibility with Python 1.5.2 easy:
the opportunity to throw away a great deal of elaborate code for
emulating classic Python classes alone was too good to pass up. In
addition, Python iterators and descriptors provided crucial and
elegant tools for representing similar C++ constructs. The
development of the generalized ``object`` interface allowed us to
further shield C++ programmers from the dangers and syntactic burdens
of the Python 'C' API. A great number of other features including C++
exception translation, improved support for overloaded functions, and
most significantly, CallPolicies for handling pointers and
references, were added during this period.
In October 2002, version 2 of Boost.Python was released. Development
since then has concentrated on improved support for C++ runtime
polymorphism and smart pointers. Peter Dimov's ingenious
``boost::shared_ptr`` design in particular has allowed us to give the
hybrid developer a consistent interface for moving objects back and
forth across the language barrier without loss of information. At
first, we were concerned that the sophistication and complexity of the
Boost.Python v2 implementation might discourage contributors, but the
emergence of Pyste_ and several other significant feature
contributions have laid those fears to rest. Daily questions on the
Python C++-sig and a backlog of desired improvements show that the
library is getting used. To us, the future looks bright.
.. _`EDG`: http://www.edg.com
=============
Conclusions
=============
@@ -924,24 +851,3 @@ the ground up, we can approach design with new confidence and power.
.. [VELD1995] T. Veldhuizen, "Expression Templates," C++ Report,
Vol. 7 No. 5 June 1995, pp. 26-31.
http://osl.iu.edu/~tveldhui/papers/Expression-Templates/exprtmpl.html
===========
Footnotes
===========
.. [#proto] In retrospect, it seems that "thinking hybrid" from the
ground up might have been better for the NLP system: the
natural component boundaries defined by the pure python
prototype turned out to be inappropriate for getting the
desired performance and memory footprint out of the C++ core,
which eventually caused some redesign overhead on the Python
side when the core was moved to C++.
.. [#test] We also have some reservations about driving all C++
testing through a Python interface, unless that's the only way
it will be ultimately used. Any transition across language
boundaries with such different object models can inevitably
mask bugs.
.. [#feature] These features were expressed very differently in v1 of
Boost.Python

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -83,7 +83,7 @@ respectively. In our <tt>foo</tt> function the minimum number of arguments is 1
and the maximum number of arguments is 4. The <tt>def(...)</tt> function will
automatically add all the foo variants for us:</p>
<code><pre>
<span class=identifier>def</span><span class=special>(</span><span class=string>&quot;foo&quot;</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
<span class=special>.</span><span class=identifier>def</span><span class=special>(</span><span class=string>&quot;foo&quot;</span><span class=special>, </span><span class=identifier>foo</span><span class=special>, </span><span class=identifier>foo_overloads</span><span class=special>());
</span></pre></code>
<a name="boost_python_member_function_overloads"></a><h2>BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS</h2><p>
Objects here, objects there, objects here there everywhere. More frequently

View File

@@ -994,7 +994,7 @@ respectively. In our [^foo] function the minimum number of arguments is 1
and the maximum number of arguments is 4. The [^def(...)] function will
automatically add all the foo variants for us:
def("foo", foo, foo_overloads());
.def("foo", foo, foo_overloads());
[h2 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS]
@@ -1330,258 +1330,6 @@ create a new scope around a class:
.value("blue", blue)
;
[def Py_Initialize [@http://www.python.org/doc/current/api/initialization.html#l2h-652 Py_Initialize]]
[def Py_Finalize [@http://www.python.org/doc/current/api/initialization.html#l2h-656 Py_Finalize]]
[def PyRun_String [@http://www.python.org/doc/current/api/veryhigh.html#l2h-55 PyRun_String]]
[def PyRun_File [@http://www.python.org/doc/current/api/veryhigh.html#l2h-56 PyRun_File]]
[def Py_eval_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-58 Py_eval_input]]
[def Py_file_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-59 Py_file_input]]
[def Py_single_input [@http://www.python.org/doc/current/api/veryhigh.html#l2h-60 Py_single_input]]
[def Py_XINCREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-65 Py_XINCREF]]
[def Py_XDECREF [@http://www.python.org/doc/current/api/countingRefs.html#l2h-67 Py_XDECREF]]
[def PyImport_AppendInittab [@http://www.python.org/doc/current/api/importing.html#l2h-137 PyImport_AppendInittab]]
[def PyImport_AddModule [@http://www.python.org/doc/current/api/importing.html#l2h-125 PyImport_AddModule]]
[def PyModule_New [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-591 PyModule_New]]
[def PyModule_GetDict [@http://www.python.org/doc/current/api/moduleObjects.html#l2h-594 PyModule_GetDict]]
[page:0 Embedding]
By now you should know how to use Boost.Python to call your C++ code from
Python. However, sometimes you may need to do the reverse: call Python code
from the C++-side. This requires you to ['embed] the Python interpreter
into your C++ program.
Currently, Boost.Python does not directly support everything you'll need
when embedding. Therefore you'll need to use the
[@http://www.python.org/doc/current/api/api.html Python/C API] to fill in
the gaps. However, Boost.Python already makes embedding a lot easier and,
in a future version, it may become unnecessary to touch the Python/C API at
all. So stay tuned... :-)
[h2 Building embedded programs]
To be able to use embedding in your programs, they have to be linked to
both Boost.Python's and Python's static link library.
Boost.Python's static link library comes in two variants. Both are located
in Boost's [^/libs/python/build/bin-stage] subdirectory. On Windows, the
variants are called [^boost_python.lib] (for release builds) and
[^boost_python_debug.lib] (for debugging). If you can't find the libraries,
you probably haven't built Boost.Python yet. See [@../../building.html
Building and Testing] on how to do this.
Python's static link library can be found in the [^/libs] subdirectory of
your Python directory. On Windows it is called pythonXY.lib where X.Y is
your major Python version number.
Additionally, Python's [^/include] subdirectory has to be added to your
include path.
In a Jamfile, all the above boils down to:
[pre
projectroot c:\projects\embedded_program ; # location of the program
# bring in the rules for python
SEARCH on python.jam = $(BOOST_BUILD_PATH) ;
include python.jam ;
exe embedded_program # name of the executable
: #sources
embedded_program.cpp
: # requirements
<find-library>boost_python <library-path>c:\boost\libs\python
$(PYTHON_PROPERTIES)
<library-path>$(PYTHON_LIB_PATH)
<find-library>$(PYTHON_EMBEDDED_LIBRARY) ;
]
[h2 Getting started]
Being able to build is nice, but there is nothing to build yet. Embedding
the Python interpreter into one of your C++ programs requires these 4
steps:
# '''#include''' [^<boost/python.hpp>][br][br]
# Call Py_Initialize() to start the interpreter and create the [^__main__] module.[br][br]
# Call other Python C API routines to use the interpreter.[br][br]
# Call Py_Finalize() to stop the interpreter and release its resources.
(Of course, there can be other C++ code between all of these steps.)
[:['[*Now that we can embed the interpreter in our programs, lets see how to put it to use...]]]
[page:1 Using the interpreter]
As you probably already know, objects in Python are reference-counted.
Naturally, the [^PyObject]s of the Python/C API are also reference-counted.
There is a difference however. While the reference-counting is fully
automatic in Python, the Python/C API requires you to do it
[@http://www.python.org/doc/current/api/refcounts.html by hand]. This is
messy and especially hard to get right in the presence of C++ exceptions.
Fortunately Boost.Python provides the [@../../v2/handle.html handle] class
template to automate the process.
[h2 Reference-counting handles]
There are two ways in which a function in the Python/C API can return a
[^PyObject*]: as a ['borrowed reference] or as a ['new reference]. Which of
these a function uses, is listed in that function's documentation. The two
require slightely different approaches to reference-counting but both can
be 'handled' by Boost.Python.
For a function returning a ['borrowed reference] we'll have to tell the
[^handle] that the [^PyObject*] is borrowed with the aptly named
[@../../v2/handle.html#borrowed-spec borrowed] function. Two functions
returning borrowed references are PyImport_AddModule and PyModule_GetDict.
The former returns a reference to an already imported module, the latter
retrieves a module's namespace dictionary. Let's use them to retrieve the
namespace of the [^__main__] module:
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) ));
Because the Python/C API doesn't know anything about [^handle]s, we used
the [@../../v2/handle.html#handle-spec-observers get] member function to
retrieve the [^PyObject*] from which the [^handle] was constructed.
For a function returning a ['new reference] we can just create a [^handle]
out of the raw [^PyObject*] without wrapping it in a call to borrowed. One
such function that returns a new reference is PyRun_String which we'll
discuss in the next section.
[blurb __detail__ [*Handle is a class ['template], so why haven't we been using any template parameters?][br]
[br]
[^handle] has a single template parameter specifying the type of the managed object. This type is [^PyObject] 99% of the time, so the parameter was defaulted to [^PyObject] for convenience. Therefore we can use the shorthand [^handle<>] instead of the longer, but equivalent, [^handle<PyObject>].
]
[h2 Running Python code]
To run Python code from C++ there is a family of functions in the API
starting with the PyRun prefix. You can find the full list of these
functions [@http://www.python.org/doc/current/api/veryhigh.html here]. They
all work similarly so we will look at only one of them, namely:
PyObject* PyRun_String(char *str, int start, PyObject *globals, PyObject *locals)
PyRun_String takes the code to execute as a null-terminated (C-style)
string in its [^str] parameter. The function returns a new reference to a
Python object. Which object is returned depends on the [^start] paramater.
The [^start] parameter is the start symbol from the Python grammar to use
for interpreting the code. The possible values are:
[table Start symbols
[Py_eval_input] [for interpreting isolated expressions]
[Py_file_input] [for interpreting sequences of statements]
[Py_single_input] [for interpreting a single statement]
]
When using Py_eval_input, the input string must contain a single expression
and its result is returned. When using Py_file_input, the string can
contain an abitrary number of statements and None is returned.
Py_single_input works in the same way as Py_file_input but only accepts a
single statement.
Lastly, the [^globals] and [^locals] parameters are Python dictionaries
containing the globals and locals of the context in which to run the code.
For most intents and purposes you can use the namespace dictionary of the
[^__main__] module for both parameters.
We have already seen how to get the [^__main__] module's namespace so let's
run some Python code in it:
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) ));
handle<>( PyRun_String("hello = file('hello.txt', 'w')\n"
"hello.write('Hello world!')\n"
"hello.close()", Py_file_input,
main_namespace.get(), main_namespace.get()) );
This should create a file called 'hello.txt' in the current directory
containing a phrase that is well-known in programming circles.
__note__ [*Note] that we wrap the return value of PyRun_String in a
(nameless) [^handle] even though we are not interested in it. If we didn't
do this, the the returned object would be kept alive unnecessarily. Unless
you want to be a Dr. Frankenstein, always wrap [^PyObject*]s in [^handle]s.
[h2 Beyond handles]
It's nice that [^handle] manages the reference counting details for us, but
other than that it doesn't do much. Often we'd like to have a more useful
class to manipulate Python objects. But we have already seen such a class
in the [@object_interface.html previous section]: the aptly named [^object]
class and it's derivatives. What we haven't seen, is that they can be
constructed from a [^handle]. The following examples should illustrate this
fact:
handle<> main_module(borrowed( PyImport_AddModule("__main__") ));
dict main_namespace(handle<>(borrowed( PyModule_GetDict(main_module.get()) )));
handle<>( PyRun_String("result = 5 ** 2", Py_file_input,
main_namespace.ptr(), main_namespace.ptr()) );
int five_squared = extract<int>( main_namespace["result"] );
Here we create a dictionary object for the [^__main__] module's namespace.
Then we assign 5 squared to the result variable and read this variable from
the dictionary. Another way to achieve the same result is to let
PyRun_String return the result directly with Py_eval_input:
object result(handle<>( PyRun_String("5 ** 2", Py_eval_input,
main_namespace.ptr(), main_namespace.ptr()) ));
int five_squared = extract<int>(result);
__note__ [*Note] that [^object]'s member function to return the wrapped
[^PyObject*] is called [^ptr] instead of [^get]. This makes sense if you
take into account the different functions that [^object] and [^handle]
perform.
[h2 Exception handling]
If an exception occurs in the execution of some Python code, the PyRun_String function returns a null pointer. Constructing a [^handle] out of this null pointer throws [@../../v2/errors.html#error_already_set-spec error_already_set], so basically, the Python exception is automatically translated into a C++ exception when using [^handle]:
try
{
object result(handle<>( PyRun_String("5/0", Py_eval_input,
main_namespace.ptr(), main_namespace.ptr()) ));
// execution will never get here:
int five_divided_by_zero = extract<int>(result);
}
catch(error_already_set)
{
// handle the exception in some way
}
The [^error_already_set] exception class doesn't carry any information in itself. To find out more about the Python exception that occurred, you need to use the [@http://www.python.org/doc/api/exceptionHandling.html exception handling functions] of the Python/C API in your catch-statement. This can be as simple as calling [@http://www.python.org/doc/api/exceptionHandling.html#l2h-70 PyErr_Print()] to print the exception's traceback to the console, or comparing the type of the exception with those of the [@http://www.python.org/doc/api/standardExceptions.html standard exceptions]:
catch(error_already_set)
{
if (PyErr_ExceptionMatches(PyExc_ZeroDivisionError))
{
// handle ZeroDivisionError specially
}
else
{
// print all other errors to stderr
PyErr_Print();
}
}
(To retrieve even more information from the exception you can use some of the other exception handling functions listed [@http://www.python.org/doc/api/exceptionHandling.html here].)
If you'd rather not have [^handle] throw a C++ exception when it is constructed, you can use the [@../../v2/handle.html#allow_null-spec allow_null] function in the same way you'd use borrowed:
handle<> result(allow_null( PyRun_String("5/0", Py_eval_input,
main_namespace.ptr(), main_namespace.ptr()) ));
if (!result)
// Python exception occurred
else
// everything went okay, it's safe to use the result
[page Iterators]
In C++, and STL in particular, we see iterators everywhere. Python also has

View File

@@ -145,15 +145,13 @@ previous section</a>: the aptly named <tt>object</tt>
class and it's derivatives. What we haven't seen, is that they can be
constructed from a <tt>handle</tt>. The following examples should illustrate this
fact:</p>
<code>
<pre>
<code><pre>
<span class=identifier>handle</span><span class=special>&lt;&gt; </span><span class=identifier>main_module</span><span class=special>(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyImport_AddModule</span><span class=special>(</span><span class=string>&quot;__main__&quot;</span><span class=special>) ));
</span><span class=identifier>dict </span><span class=identifier>main_namespace</span><span class=special>(</span><span class=identifier>handle</span><span class=special>&lt;&gt;(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) )));
</span><span class=identifier>main_namespace </span><span class=identifier>dict</span><span class=special>(</span><span class=identifier>handle</span><span class=special>&lt;&gt;(</span><span class=identifier>borrowed</span><span class=special>( </span><span class=identifier>PyModule_GetDict</span><span class=special>(</span><span class=identifier>main_module</span><span class=special>.</span><span class=identifier>get</span><span class=special>()) )));
</span><span class=identifier>handle</span><span class=special>&lt;&gt;( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>&quot;result = 5 ** 2&quot;</span><span class=special>, </span><span class=identifier>Py_file_input</span><span class=special>,
</span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>(), </span><span class=identifier>main_namespace</span><span class=special>.</span><span class=identifier>ptr</span><span class=special>()) );
</span><span class=keyword>int </span><span class=identifier>five_squared </span><span class=special>= </span><span class=identifier>extract</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;( </span><span class=identifier>main_namespace</span><span class=special>[</span><span class=string>&quot;result&quot;</span><span class=special>] );
</span></pre>
</code>
</span></pre></code>
<p>
Here we create a dictionary object for the <tt>__main__</tt> module's namespace.
Then we assign 5 squared to the result variable and read this variable from

View File

@@ -31,15 +31,6 @@
<p><a href="../../../../people/dave_abrahams.htm">Dave Abrahams</a> is
the architect, designer, and implementor of <b>Boost.Python</b>.</p>
<p><a href="mailto:brett.calcott@paradise.net.nz">Brett Calcott</a>
contributed and maintains the Visual Studio project files and
documentation.</p>
<p><a href="mailto:Gottfried.Ganssauge-at-haufe.de">Gottfried
Ganßauge</a> supplied support for opaque pointer conversions,
complete with documentation and a regression test (and I didn't
even have to ask him for those)!
<p>Joel de Guzman implemented the <a href="overloads.html">default
argument support</a> and wrote the excellent <a href=
"../tutorial/index.html">tutorial documentation</a>.</p>
@@ -72,17 +63,6 @@
use the new preproccessor metaprogramming constructs and helping us to
work around buggy and slow C++ preprocessors.</p>
<p><a href="nicodemus-at-globalite.com.br">Bruno da Silva de
Oliveira</a> contributed the ingenious <a
href="../../pyste/index.html">Pyste</a> (&quot;Pie-Steh&quot;)
code generator.
<p><a href="mailto:nickm@sitius.com">Nikolay Mladenov</a> contributed
<code>staticmethod</code> support.</p>
<p>Martin Casado solved some sticky problems which allow us to build the
Boost.Python shared library for AIX's crazy dynamic linking model.</p>
<p><a href="mailto:achim@procoders.net">Achim Domma</a> contributed some
of the <a href="reference.html#object_wrappers">Object Wrappers</a> and
HTML templates for this documentation. Dave Hawkes contributed
@@ -91,6 +71,16 @@
definition syntax. Pearu Pearson wrote some of the test cases that are in
the current test suite.</p>
<p><a href="mailto:brett.calcott@paradise.net.nz">Brett Calcott</a>
contributed and maintains the Visual Studio project files and
documentation.</p>
<p><a href="mailto:nickm@sitius.com">Nikolay Mladenov</a> contributed
<code>staticmethod</code> support.</p>
<p>Martin Casado solved some sticky problems which allow us to build the
Boost.Python shared library for AIX's crazy dynamic linking model.</p>
<p>The development of this version of Boost.Python was funded in part by
the <a href="http://www.llnl.gov/">Lawrence Livermore National
Laboratories</a> and by the <a href="http://cci.lbl.gov/">Computational

View File

@@ -29,10 +29,6 @@
<hr>
<dl class="page-index">
<dt><a href="#funcptr">How can I wrap a function which takes a
function pointer as an argument?</a><dd>
<dt><a href="#dangling">I'm getting the "attempt to return dangling
reference" error. What am I doing wrong?</a></dt>
@@ -60,57 +56,6 @@
</dl>
<hr>
<h2><a name="funcptr">How can I wrap a function which takes a
function pointer as an argument?</a></h2>
If what you're trying to do is something like this:
<pre>
typedef boost::function&lt;void (string s) &gt; funcptr;
void foo(funcptr fp)
{
fp(&quot;hello,world!&quot;);
}
BOOST_PYTHON_MODULE(test)
{
def(&quot;foo&quot;,foo) ;
}
</pre>
And then:
<pre>
&gt;&gt;&gt; def hello(s):
... print s
...
&gt;&gt;&gt; foo(hello)
hello, world!
</pre>
The short answer is: &quot;you can't&quot;. This is not a
Boost.Python limitation so much as a limitation of C++. The
problem is that a Python function is actually data, and the only
way of associating data with a C++ function pointer is to store it
in a static variable of the function. The problem with that is
that you can only associate one piece of data with every C++
function, and we have no way of compiling a new C++ function
on-the-fly for every Python function you decide to pass
to <code>foo</code>. In other words, this could work if the C++
function is always going to invoke the <em>same</em> Python
function, but you probably don't want that.
<p>If you have the luxury of changing the C++ code you're
wrapping, pass it an <code>object</code> instead and call that;
the overloaded function call operator will invoke the Python
function you pass it behind the <code>object</code>.
<p>For more perspective on the issue, see <a
href="http://aspn.activestate.com/ASPN/Mail/Message/1554837">this
posting</a>.
<hr>
<h2><a name="dangling">I'm getting the "attempt to return dangling
reference" error. What am I doing wrong?</a></h2>
That exception is protecting you from causing a nasty crash. It usually
@@ -547,7 +492,7 @@ void b_insert(B&amp; b, std::auto_ptr&lt;A&gt; a)
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
18 March, 2003
23 January, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>

View File

@@ -1,142 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;boost/python/opaque_pointer_converter.hpp&gt;</title>
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header
&lt;boost/python/opaque_pointer_converter.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#classes">Classes</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#opaque_pointer_converter-spec">Class template
<code>opaque_pointer_converter&lt;P&gt;</code></a></dt>
<dd>
<dl class="page-index">
<dt><a href="#opaque_pointer_converter-spec-synopsis">Class template
<code>opaque_pointer_converter</code> synopsis</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="#macros">Macros</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">Macro
<code>BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</code></a></dt>
</dl>
</dd>
<dt><a href="#examples">Example</a></dt>
<dt><a href="#see-also">See Also</a></dt>
</dl>
<hr>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="opaque_pointer_converter-spec"></a>Class template
<code>opaque_pointer_converter&lt;P&gt;</code></h3>
<p><code>opaque_pointer_converter&lt;&gt;</code> is derived from
<a href="to_python_converter.html#to_python_converter-spec">
<code>to_python_converter</code></a>
and registers itself as an
<a href="lvalue_from_pytype.html#lvalue_from_pytype-spec">
<code>lvalue_from_pytype</code></a> converter from Python objects
into pointers to undefined types.
Thus it may be used as a converter from opaque pointers into
Python objects and vice versa.</p>
<h4><a name="opaque_pointer_converter-spec-synopsis"></a>Class template
<code>opaque_pointer_converter</code> synopsis</h4>
<pre>
namespace boost { namespace python
{
template&lt;class Pointer&gt;
struct opaque_pointer_converter
: to_python_converter&lt;
Pointer, opaque_pointer_converter&lt;Pointer&gt; &gt;
{
explicit opaque_pointer_converter(char const* name);
};
}}
</pre>
<h4><a name="opaque_pointer_converter-spec-constructor"></a>Class template
<code>opaque_pointer_converter</code> constructor</h4>
<pre>
explicit opaque_pointer_converter(char const* name);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b>
<p>Registers the instance as a
<a href="lvalue_from_pytype.html#lvalue_from_pytype-spec">
<code>lvalue_from_pytype</code></a> converter from Python objects
into opaque pointers.</p>
<p>The name is used for the type of the Python Objects created;
it should be printable but needn't be an
<a href="definitions.html#ntbs">ntbs</a> because the object type is
not supposed to be user constructible within python scripts.</p>
</dt>
</dl>
<h2><a name="macros"></a>Macros</h2>
<h3><a name="BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec"></a>
Macro BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)</h3>
<p>This macro must be used to define specializations of the
<a href="type_id.html#type_id-spec">type_id</a> function
which can't be instantiated for incomplete types.</p>
<h4>Note</h4>
<p>In order for this to work in a cross-module environment the macro must
be invoked in every translation unit which uses the
opaque_pointer_converter.</p>
<h2><a name="examples"></a>Example</h2>
please see example for <a href="return_opaque_pointer.html#example">
return_opaque_pointer</a>.
<h2><a name="see-also"></a>See Also</h2>
<p>
<a href="return_opaque_pointer.html">return_opaque_pointer</a>
</p>
<p>Revised
10 March, 2003
</p>
<p><i>&copy; Copyright 2003 Haufe Mediengruppe. All Rights
Reserved.</i></p>
</body>
</html>

View File

@@ -194,10 +194,9 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 1, 3)
BOOST_PYTHON_MODULE(args_ext)
{
def(&quot;f&quot;, f,
f_overloads(
args(&quot;x&quot;, &quot;y&quot;, &quot;z&quot;), &quot;This is f's docstring&quot;
));
def(&quot;f&quot;, f, args(&quot;x&quot;, &quot;y&quot;, &quot;z&quot;)
, &quot;This is f's docstring&quot;
);
class_&lt;Y&gt;(&quot;Y&quot;)
@@ -205,17 +204,16 @@ BOOST_PYTHON_MODULE(args_ext)
class_&lt;X&gt;(&quot;X&quot;, &quot;This is X's docstring&quot;)
.def(&quot;f1&quot;, &amp;X::f,
X_f_overloads(
args(&quot;x&quot;, &quot;y&quot;, &quot;z&quot;), &quot;f's docstring&quot;
)[return_internal_reference&lt;&gt;()]
)
X_f_overloads(args(&quot;x&quot;, &quot;y&quot;, &quot;z&quot;),
&quot;f's docstring&quot;
)[return_internal_reference&lt;&gt;()])
;
}
</pre>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
15 April, 2003
15 December, 2002
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>

View File

@@ -1,116 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta name="generator" content=
"HTML Tidy for Cygwin (vers 1st April 2002), see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;boost/python/raw_function.hpp&gt;</title>
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header &lt;boost/python/raw_function.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#functions">Functions</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#raw_function-spec">raw_function</a></dt>
</dl>
</dd>
<dt><a href="#examples">Example</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p><code><a href="#raw_function-spec">raw_function</a>(...)</code>
is used to convert a function taking a <a
href="tuple.html#tuple-spec">tuple</a> and a <a
href="dict.html#dict-spec">dict</a> into a Python callable object
which accepts a variable number of arguments and arbitrary keyword
arguments.
<h2><a name="functions"></a>Functions</h2>
<a name="raw_function-spec"></a>raw_function
<pre>
template &lt;class F&gt;
object raw_function(F f, std::size_t min_args = 0);
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> <code>f(tuple(), dict())</code> is
well-formed.</dt>
<dt><b>Returns:</b> a <a href=
"http://www.python.org/doc/current/lib/built-in-funcs.html#l2h-6">callable</a> object which requires at least <code>min_args</code> arguments. When called, the actual non-keyword arguments will be passed in a <a
href="tuple.html#tuple-spec">tuple</a> as the first argument to <code>f</code>, and the keyword arguments will be passed in a <a
href="dict.html#dict-spec">dict</a> as the second argument to <code>f</code>.
</dd>
</dl>
<h2><a name="examples"></a>Example</h2>
C++:
<pre>
#include &lt;boost/python/def.hpp&gt;
#include &lt;boost/python/tuple.hpp&gt;
#include &lt;boost/python/dict.hpp&gt;
#include &lt;boost/python/module.hpp&gt;
#include &lt;boost/python/raw_function.hpp&gt;
using namespace boost::python;
tuple raw(tuple args, dict kw)
{
return make_tuple(args, kw);
}
BOOST_PYTHON_MODULE(raw_test)
{
def("raw", raw_function(raw));
}
</pre>
Python:
<pre>
&gt;&gt;&gt; from raw_test import *
&gt;&gt;&gt; raw(3, 4, foo = 'bar', baz = 42)
((3, 4), {'foo': 'bar', 'baz': 42})
</pre>
<p>
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
7 March, 2003
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href=
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002. All Rights
Reserved.</i></p>
</body>
</html>

View File

@@ -749,96 +749,6 @@
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="return_opaque_pointer.html">return_opaque_pointer.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="return_opaque_pointer.html#return_opaque_pointer-spec">
return_opaque_pointer</a></dt>
</dl>
</dd>
</dl>
</dd>
</dl>
</dd>
</dl>
@@ -896,144 +806,6 @@
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html">opaque_pointer_converter.hpp</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#classes">Classes</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#opaque_pointer_converter-spec">
opaque_pointer_converter</a></dt>
</dl>
</dd>
<dt><a href="opaque_pointer_converter.html#macros">Macros</a></dt>
<dd>
<dl class="index">
<dt><a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="to_python_converter.html">to_python_converter.hpp</a></dt>
<dd>

View File

@@ -1,189 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../boost.css">
<title>Boost.Python - &lt;boost/python/return_opaque_pointer.hpp&gt;</title>
</head>
<body>
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../../index.htm"><img height="86" width="277"
alt="C++ Boost" src="../../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center"><a href="../index.html">Boost.Python</a></h1>
<h2 align="center">Header
&lt;boost/python/return_opaque_pointer.hpp&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#classes">Classes</a></dt>
<dd>
<dl class="page-index">
<dt><a href="#return_opaque_pointer-spec">Class
<code>return_opaque_pointer</code></a></dt>
<dd>
<dl class="page-index">
<dt><a href="#return_opaque_pointer-spec-synopsis">Class
<code>return_opaque_pointer</code> synopsis</a></dt>
<dt><a href="#return_opaque_pointer-spec-metafunctions">Class
<code>return_opaque_pointer</code> metafunctions</a></dt>
</dl>
</dd>
</dl>
</dd>
<dt><a href="#examples">Example</a></dt>
<dt><a href="#see-also">See Also</a></dt>
</dl>
<hr>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="return_opaque_pointer-spec"></a>Class
<code>return_opaque_pointer</code></h3>
<p><code>return_opaque_pointer</code> is a model of
<a href="ResultConverter.html#ResultConverterGenerator-concept">
ResultConverterGenerator</a>
which can be used to wrap C++ functions returning pointers to
undefined types such that the return value is copied into a
new Python object.</p>
<p>In addition to specifying the <code>return_opaque_pointer</code>
policy the <a href="opaque_pointer_converter.html#BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID-spec">
<code>BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID</code></a> macro must be
used to define specializations for the
<a href="type_id.html#type_id-spec">type_id</a> function
on the type pointed to by returned pointer.</p>
<h4><a name="return_opaque_pointer-spec-synopsis"></a>Class
<code>return_opaque_pointer</code> synopsis</h4>
<pre>
namespace boost { namespace python
{
struct return_opaque_pointer
{
template &lt;class R&gt; struct apply;
};
}}
</pre>
<h4><a name="return_opaque_pointer-spec-metafunctions"></a>Class
<code>return_opaque_pointer</code> metafunctions</h4>
<pre>
template &lt;class R&gt; struct apply
</pre>
<dl class="metafunction-semantics">
<dt><b>Returns:</b> <code>typedef
detail::opaque_conversion_holder&lt;R&gt;
type;</code></dt>
</dl>
<h2><a name="examples"></a>Example</h2>
<h3>C++ Module Definition</h3>
<pre>
# include &lt;boost/python/return_opaque_pointer.hpp&gt;
# include &lt;boost/python/def.hpp&gt;
# include &lt;boost/python/module.hpp&gt;
# include &lt;boost/python/return_value_policy.hpp&gt;
typedef struct opaque_ *opaque;
opaque the_op = ((opaque) 0x47110815);
opaque get () { return the_op; }
void use (opaque op) {
if (op != the_op)
throw std::runtime_error (std::string ("failed"));
}
void failuse (opaque op) {
if (op == the_op)
throw std::runtime_error (std::string ("success"));
}
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(opaque_)
namespace bpl = boost::python;
BOOST_PYTHON_MODULE(opaque_ext)
{
bpl::def (
"get", &::get, bpl::return_value_policy&lt;bpl::return_opaque_pointer&gt;());
bpl::def ("use", &::use);
bpl::def ("failuse", &::failuse);
}
</pre>
<h3>Python Code</h3>
<pre>
"""
>>> from opaque_ext import *
>>> #
>>> # Check for correct conversion
>>> use(get())
>>> failuse(get())
Traceback (most recent call last):
...
RuntimeError: success
>>> #
>>> # Check that there is no conversion from integers ...
>>> use(0)
Traceback (most recent call last):
...
TypeError: bad argument type for built-in operation
>>> #
>>> # ... and from strings to opaque objects
>>> use("")
Traceback (most recent call last):
...
TypeError: bad argument type for built-in operation
"""
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
sys.exit(run()[0])
</pre>
<h2><a name="see-also"></a>See Also</h2>
<p>
<a href="opaque_pointer_converter.html">
opaque_pointer_converter</a>
</p>
<p>Revised
28 January, 2003
</p>
<p><i>&copy; Copyright 2003 Haufe Mediengruppe. All Rights
Reserved.</i></p>
</body>
</html>

View File

@@ -44,14 +44,12 @@
# include <boost/python/object_protocol.hpp>
# include <boost/python/object_protocol_core.hpp>
# include <boost/python/operators.hpp>
# include <boost/python/opaque_pointer_converter.hpp>
# include <boost/python/other.hpp>
# include <boost/python/overloads.hpp>
# include <boost/python/pointee.hpp>
# include <boost/python/ptr.hpp>
# include <boost/python/reference_existing_object.hpp>
# include <boost/python/return_internal_reference.hpp>
# include <boost/python/return_opaque_pointer.hpp>
# include <boost/python/return_value_policy.hpp>
# include <boost/python/scope.hpp>
# include <boost/python/self.hpp>

View File

@@ -290,28 +290,19 @@ class class_ : public objects::class_base
//
// Data member access
//
template <class D>
self& def_readonly(char const* name, D const& d)
template <class D, class B>
self& def_readonly(char const* name, D B::*pm_)
{
return this->def_readonly_impl(name, d, 0);
D T::*pm = pm_;
this->add_property(name, make_getter(pm));
return *this;
}
template <class D>
self& def_readwrite(char const* name, D const& d)
template <class D, class B>
self& def_readwrite(char const* name, D B::*pm_)
{
return this->def_readwrite_impl(name, d, 0);
}
template <class D>
self& def_readonly(char const* name, D& d)
{
return this->def_readonly_impl(name, d, 0);
}
template <class D>
self& def_readwrite(char const* name, D& d)
{
return this->def_readwrite_impl(name, d, 0);
D T::*pm = pm_;
return this->add_property(name, make_getter(pm), make_setter(pm));
}
// Property creation
@@ -343,34 +334,6 @@ class class_ : public objects::class_base
return *this;
}
template <class Get>
self& add_static_property(char const* name, Get fget)
{
base::add_static_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
);
return *this;
}
template <class Get, class Set>
self& add_static_property(char const* name, Get fget, Set fset)
{
base::add_static_property(
name
, object(
detail::member_function_cast<T,Get>::stage1(fget).stage2((T*)0).stage3(fget)
)
, object(
detail::member_function_cast<T,Set>::stage1(fset).stage2((T*)0).stage3(fset)
)
);
return *this;
}
template <class U>
self& setattr(char const* name, U const& x)
{
@@ -399,32 +362,6 @@ class class_ : public objects::class_base
}
private: // helper functions
template <class D, class B>
self& def_readonly_impl(char const* name, D B::*pm_, int)
{
D T::*pm = pm_;
return this->add_property(name, make_getter(pm));
}
template <class D, class B>
self& def_readwrite_impl(char const* name, D B::*pm_, int)
{
D T::*pm = pm_;
return this->add_property(name, make_getter(pm), make_setter(pm));
}
template <class D>
self& def_readonly_impl(char const* name, D& d, ...)
{
return this->add_static_property(name, make_getter(d));
}
template <class D>
self& def_readwrite_impl(char const* name, D& d, ...)
{
return this->add_static_property(name, make_getter(d), make_setter(d));
}
inline void register_() const;
//

View File

@@ -18,16 +18,12 @@
# include <boost/python/detail/indirect_traits.hpp>
# include <boost/python/detail/config.hpp>
# include <boost/python/detail/wrap_python.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/type_traits/transform_traits.hpp>
# include <boost/type_traits/add_const.hpp>
# include <boost/type_traits/add_reference.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/identity.hpp>
# include <boost/bind.hpp>
@@ -75,169 +71,74 @@ namespace detail
}
};
template <class Data, class Policies>
struct datum
{
static PyObject* get(Data *p, PyObject* args_, PyObject*, Policies const& policies)
{
// find the result converter
typedef typename Policies::result_converter result_converter;
typedef typename boost::add_reference<Data>::type source;
typename mpl::apply1<result_converter,source>::type cr;
if (!policies.precall(args_)) return 0;
PyObject* result = cr( *p );
return policies.postcall(args_, result);
}
static PyObject* set(Data* p, PyObject* args_, PyObject*, Policies const& policies)
{
// check that each of the arguments is convertible
typedef typename add_const<Data>::type target1;
typedef typename add_reference<target1>::type target;
arg_from_python<target> c0(PyTuple_GET_ITEM(args_, 0));
if (!c0.convertible()) return 0;
if (!policies.precall(args_)) return 0;
*p = c0(PyTuple_GET_ITEM(args_, 0));
return policies.postcall(args_, detail::none());
}
};
template <class T>
struct default_getter_by_ref
: mpl::and_<
mpl::bool_<
to_python_value<
typename add_reference<typename add_const<T>::type>::type
>::uses_registry
>
, is_reference_to_class<
typename add_reference<typename add_const<T>::type>::type
>
>
{
};
// If it's a regular class type (not an object manager or other
// type for which we have to_python specializations, use
// return_internal_reference so that we can do things like
// x.y.z = 1
// and get the right result.
template <class T>
struct default_member_getter_policy
: mpl::if_<
default_getter_by_ref<T>
, return_internal_reference<>
, return_value_policy<return_by_value>
>
{};
template <class T>
struct default_datum_getter_policy
: mpl::if_<
default_getter_by_ref<T>
, return_value_policy<reference_existing_object>
, return_value_policy<return_by_value>
>
{};
template <class D, class Policies>
inline object make_getter(D* p, Policies const& policies, int)
struct default_getter_policy
{
return objects::function_object(
::boost::bind(
&detail::datum<D,Policies>::get, p, _1, _2
, policies)
, 0);
}
typedef typename add_reference<
typename add_const<T>::type
>::type t_cref;
template <class D>
inline object make_getter(D* p, not_specified, long)
{
typedef typename default_datum_getter_policy<D>::type policies;
return make_getter(p, policies(), 0L);
}
BOOST_STATIC_CONSTANT(
bool, by_ref = to_python_value<t_cref>::uses_registry
&& is_reference_to_class<t_cref>::value);
template <class C, class D, class Policies>
inline object make_getter(D C::*pm, Policies const& policies, int)
{
typedef typename mpl::if_c<
by_ref
, return_internal_reference<>
, return_value_policy<return_by_value>
>::type type;
};
}
template <class C, class D>
object make_getter(D C::*pm)
{
typedef typename detail::default_getter_policy<D>::type policy;
return objects::function_object(
::boost::bind(
&detail::member<D,C,policy>::get, pm, _1, _2
, policy())
, 1);
}
template <class C, class D, class Policies>
object make_getter(D C::*pm, Policies const& policies)
{
return objects::function_object(
::boost::bind(
&detail::member<D,C,Policies>::get, pm, _1, _2
, policies)
, 1);
}
template <class C, class D>
inline object make_getter(D C::*pm, not_specified, long)
{
typedef typename default_member_getter_policy<D>::type policies;
return make_getter(pm, policies(), 0L);
}
template <class D, class Policies>
inline object make_getter(D& d, Policies const& policies, ...)
{
return detail::make_getter(&d, policies, 0L);
}
template <class D, class Policies>
inline object make_setter(D* p, Policies const& policies, long)
{
return objects::function_object(
::boost::bind(
&detail::datum<D,Policies>::set, p, _1, _2
, policies)
, 1);
}
template <class C, class D, class Policies>
inline object make_setter(D C::*pm, Policies const& policies, long)
{
return objects::function_object(
::boost::bind(
&detail::member<D,C,Policies>::set, pm, _1, _2
, policies)
, 2);
}
template <class D, class Policies>
inline object make_setter(D& x, Policies const& policies, ...)
{
return detail::make_setter(&x, policies, 0L);
}
}
template <class D, class Policies>
inline object make_getter(D& d, Policies const& policies)
template <class C, class D>
object make_setter(D C::*pm)
{
return detail::make_getter(d, policies, 0L);
return objects::function_object(
::boost::bind(
&detail::member<D,C,default_call_policies>::set, pm, _1, _2
, default_call_policies())
, 2);
}
template <class D>
inline object make_getter(D& x)
template <class C, class D, class Policies>
object make_setter(D C::*pm, Policies const& policies)
{
return detail::make_getter(x, detail::not_specified(), 0L);
}
template <class D, class Policies>
inline object make_setter(D& x, Policies const& policies)
{
return detail::make_setter(x, policies, 0L);
}
template <class D>
inline object make_setter(D& x)
{
return detail::make_setter(x, default_call_policies(), 0L);
return objects::function_object(
::boost::bind(
&detail::member<D,C,Policies>::set, pm, _1, _2
, policies)
, 2);
}
}} // namespace boost::python
#endif // DATA_MEMBERS_DWA2002328_HPP

View File

@@ -80,7 +80,6 @@ namespace detail
template <class T>
object make_function1(T fn, ...) { return make_function(fn); }
inline
object make_function1(object const& x, object const*) { return x; }
}

View File

@@ -1,18 +0,0 @@
// Copyright Gottfried Ganßauge 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
# ifndef BOOST_PYTHON_DETAIL_DEALLOC_HPP_
# define BOOST_PYTHON_DETAIL_DEALLOC_HPP_
namespace boost { namespace python { namespace detail {
extern "C"
{
inline void dealloc(PyObject* self)
{
PyObject_Del(self);
}
}
}}} // namespace boost::python::detail
# endif // BOOST_PYTHON_DETAIL_DEALLOC_HPP_

View File

@@ -219,7 +219,7 @@ namespace detail
char const* name,
OverloadsT const& overloads,
NameSpaceT& name_space,
SigT)
SigT const& sig)
{
typedef typename mpl::front<SigT>::type return_type;
typedef typename OverloadsT::void_return_type void_return_type;

View File

@@ -280,8 +280,9 @@ struct is_pointer_to_function
struct false_helper1
{
template <class T>
struct apply : mpl::false_
struct apply
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
};
@@ -299,13 +300,22 @@ struct true_helper1
BOOST_STATIC_CONSTANT(
bool, value
= sizeof(reference_to_const_helper(t)) == sizeof(inner_yes_type));
typedef mpl::bool_<value> type;
};
};
template <bool ref = true>
struct is_reference_to_const_helper1 : true_helper1
{
# if 0
template <class T>
struct apply
{
static T t;
BOOST_STATIC_CONSTANT(
bool, value
= sizeof(reference_to_const_helper(t)) == sizeof(inner_yes_type));
};
# endif
};
template <>
@@ -321,6 +331,7 @@ struct is_reference_to_const
};
template <bool ref = true>
struct is_reference_to_non_const_helper1
{

View File

@@ -1,18 +0,0 @@
// Copyright David Abrahams 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#ifndef IS_SHARED_PTR_DWA2003224_HPP
# define IS_SHARED_PTR_DWA2003224_HPP
# include <boost/python/detail/is_xxx.hpp>
# include <boost/shared_ptr.hpp>
namespace boost { namespace python { namespace detail {
BOOST_PYTHON_IS_XXX_DEF(shared_ptr, shared_ptr, 1)
}}} // namespace boost::python::detail
#endif // IS_SHARED_PTR_DWA2003224_HPP

View File

@@ -37,13 +37,9 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
void enable_pickling(bool getstate_manages_dict);
protected:
// Retrieve the underlying object
void add_property(char const* name, object const& fget);
void add_property(char const* name, object const& fget, object const& fset);
void add_static_property(char const* name, object const& fget);
void add_static_property(char const* name, object const& fget, object const& fset);
// Retrieve the underlying object
void setattr(char const* name, object const&);
// Set a special attribute in the class which tells Boost.Python

View File

@@ -1,131 +0,0 @@
// Copyright Gottfried Ganßauge 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
/*
* Generic Conversion of opaque C++-pointers to a Python-Wrapper.
*/
# ifndef OPAQUE_POINTER_CONVERTER_HPP_
# define OPAQUE_POINTER_CONVERTER_HPP_
# include <boost/python/lvalue_from_pytype.hpp>
# include <boost/python/to_python_converter.hpp>
# include <boost/python/detail/dealloc.hpp>
# include <boost/python/detail/none.hpp>
# include <boost/type_traits/remove_pointer.hpp>
// opaque_pointer_converter --
//
// usage: opaque_pointer_converter<Pointer>("name")
//
// registers to- and from- python conversions for a type Pointer,
// and a corresponding Python type called "name".
//
// Note:
// In addition you need to define specializations for type_id
// on the type pointed to by Pointer using
// BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)
//
// For an example see libs/python/test/opaque.cpp
//
namespace boost { namespace python {
namespace detail {
template <class R>
struct opaque_pointer_converter_requires_a_pointer_type
# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
{}
# endif
;
}
template <class Pointer>
struct opaque_pointer_converter
: to_python_converter<
Pointer, opaque_pointer_converter<Pointer> >
{
BOOST_STATIC_CONSTANT(
bool, ok = is_pointer<Pointer>::value);
typedef typename mpl::if_c<
ok
, Pointer
, detail::opaque_pointer_converter_requires_a_pointer_type<Pointer>
>::type ptr_type;
private:
struct instance;
public:
explicit opaque_pointer_converter(char const* name)
{
type_object.tp_name = const_cast<char *> (name);
lvalue_from_pytype<
opaque_pointer_converter<ptr_type>,
&opaque_pointer_converter<ptr_type>::type_object
>();
}
static PyObject* convert(ptr_type x)
{
PyObject *result = 0;
if (x != 0) {
instance *o = PyObject_New (instance, &type_object);
o->x = x;
result = &o->base_;
} else {
result = detail::none();
}
return (result);
}
static typename ::boost::remove_pointer<ptr_type>::type&
execute(instance &p_)
{
return *p_.x;
}
private:
static PyTypeObject type_object;
// This is a POD so we can use PyObject_Del on it, for example.
struct instance
{
PyObject base_;
ptr_type x;
};
};
template <class Pointer>
PyTypeObject opaque_pointer_converter<Pointer>::type_object =
{
PyObject_HEAD_INIT(NULL)
0,
0,
sizeof(typename opaque_pointer_converter<Pointer>::instance),
0,
::boost::python::detail::dealloc
};
}} // namespace boost::python
# ifdef BOOST_MSVC
// MSC works without this workaround, but needs another one ...
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(Pointee)
# else
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
namespace boost { namespace python { \
template<> \
inline type_info type_id(boost::type<Pointee>*) { \
return type_info (typeid (Pointee *)); \
} \
template<> \
inline type_info type_id( \
boost::type<const volatile Pointee &>*) { \
return type_info (typeid (Pointee *)); \
} \
}}
# endif
# endif // OPAQUE_POINTER_CONVERTER_HPP_

View File

@@ -6,10 +6,14 @@
#ifndef RAW_FUNCTION_DWA200336_HPP
# define RAW_FUNCTION_DWA200336_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/python/tuple.hpp>
# include <boost/python/dict.hpp>
# include <boost/python/object/py_function.hpp>
# include <boost/mpl/vector/vector10.hpp>
# include <boost/limits.hpp>
# include <cstddef>
namespace boost { namespace python {
@@ -25,21 +29,32 @@ namespace detail
{
return incref(
object(
f(tuple(borrowed_reference(args)), dict(borrowed_reference(keywords)))
f(
tuple(borrowed_reference(args))
, keywords ? dict(borrowed_reference(keywords)) : dict()
)
).ptr()
);
}
private:
F f;
};
object BOOST_PYTHON_DECL make_raw_function(objects::py_function, std::size_t min_args);
object BOOST_PYTHON_DECL make_raw_function(objects::py_function);
}
template <class F>
object raw_function(F f, std::size_t min_args = 0)
{
return detail::make_raw_function(detail::raw_dispatcher<F>(f), min_args);
return detail::make_raw_function(
objects::py_function(
detail::raw_dispatcher<F>(f)
, mpl::vector1<PyObject*>()
, min_args
, std::numeric_limits<unsigned>::max()
)
);
}
}} // namespace boost::python

View File

@@ -1,51 +0,0 @@
// Copyright Gottfried Ganßauge 2003. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
/*
* Generic Return value converter generator for opaque C++-pointers
*/
# ifndef RETURN_OPAQUE_POINTER_HPP_
# define RETURN_OPAQUE_POINTER_HPP_
# include <boost/python/opaque_pointer_converter.hpp>
# include <boost/python/detail/indirect_traits.hpp>
# include <boost/mpl/if.hpp>
namespace boost { namespace python {
namespace detail {
template <class Pointer>
struct opaque_conversion_holder {
inline PyObject *operator () (Pointer p) {
static opaque_pointer_converter<Pointer> converter (
typeid (Pointer).name());
return converter.convert(p);
}
};
template <class R>
struct return_opaque_pointer_requires_a_pointer_type
# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
{}
# endif
;
}
struct return_opaque_pointer
{
template <class R>
struct apply
{
BOOST_STATIC_CONSTANT(
bool, ok = is_pointer<R>::value);
typedef typename mpl::if_c<
ok
, detail::opaque_conversion_holder<R>
, detail::return_opaque_pointer_requires_a_pointer_type<R>
>::type type;
};
};
}} // namespace boost::python
# endif // RETURN_OPAQUE_POINTER_HPP_

View File

@@ -1,35 +0,0 @@
07 Apr 2003
- Removed the warnings about forward declarations: it was not accurate enough.
Another strategy must be thought of.
- Fixed bug in the --multiple mode, where the order of the class instantiations
could end up wrong.
- Lots of fixes in the documentation, pointed out by Dirk Gerrits. Thanks Dirk!
- Fixed support for the return_opaque_pointer policy (the support macro was not
being declared).
06 Apr 2003
Support for the improved static data members support of Boost.Python.
05 Apr 2003
New option for generating the bindings: --multiple.
02 Apr 2003
Forward declarations are now detected and a warning is generated.
24 Mar 2003
Default policy for functions/methods that return const T& is now
return_value_policy<copy_const_reference>().
22 Mar 2003
Exporting virtual methods of the base classes in the derived classes too.
21 Mar 2003
Added manual support for boost::shared_ptr and std::auto_ptr (see doc).
19 Mar 2003
Added support for int, double, float and long operators acting as expected in
python.
14 Mar 2003
Fixed bug: Wrappers for protected and virtual methods were not being generated.

View File

@@ -1,2 +0,0 @@
*.zip
*.pyc

View File

@@ -1,51 +0,0 @@
import os
import sys
import shutil
import fnmatch
from zipfile import ZipFile, ZIP_DEFLATED
def findfiles(directory, mask):
def visit(files, dir, names):
for name in names:
if fnmatch.fnmatch(name, mask):
files.append(os.path.join(dir, name))
files = []
os.path.walk(directory, visit, files)
return files
def main():
# test if PyXML is installed
try:
import _xmlplus.parsers.expat
pyxml = '--includes _xmlplus.parsers.expat'
except ImportError:
pyxml = ''
# create exe
status = os.system('python setup.py py2exe %s >& build.log' % pyxml)
if status != 0:
raise RuntimeError, 'Error creating EXE'
# create distribution
import pyste
version = pyste.__VERSION__
zip = ZipFile('pyste-%s.zip' % version, 'w', ZIP_DEFLATED)
# include the base files
dist_dir = 'dist/pyste'
for basefile in os.listdir(dist_dir):
zip.write(os.path.join(dist_dir, basefile), os.path.join('pyste', basefile))
# include documentation
for doc_file in findfiles('../doc', '*.*'):
dest_name = os.path.join('pyste/doc', doc_file[3:])
zip.write(doc_file, dest_name)
zip.write('../index.html', 'pyste/doc/index.html')
zip.close()
# cleanup
os.remove('build.log')
shutil.rmtree('build')
shutil.rmtree('dist')
if __name__ == '__main__':
sys.path.append('../src')
main()

6
pyste/dist/setup.py vendored
View File

@@ -1,6 +0,0 @@
from distutils.core import setup
import py2exe
import sys
sys.path.append('../src')
setup(name='pyste', scripts=['../src/pyste.py'])

View File

@@ -4,7 +4,6 @@
<title>Exporting All Declarations from a Header</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="wrappers.html">
<link rel="next" href="smart_pointers.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
@@ -21,7 +20,7 @@
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
</tr>
</table>
<p>
@@ -64,7 +63,7 @@ the members of the header object like this:</p>
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="wrappers.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><a href="smart_pointers.html"><img src="theme/r_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
</tr>
</table>
<br>

View File

@@ -51,13 +51,13 @@ Here's the interface file for it, named <tt>world.pyste</tt>:</p>
<p>
and that's it!</p>
<p>
The next step is invoke Pyste in the command-line:</p>
The next step is invoke pyste in the command-line:</p>
<code><pre>python pyste.py --module=hello world.pyste</pre></code><p>
this will create a file &quot;<tt>hello.cpp</tt>&quot; in the directory where the command was
run. </p>
<p>
Pyste supports the following features:</p>
<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both &quot;free&quot; enums and class enums)</li><li>Nested Classes</li><li>Support for <tt>boost::shared_ptr</tt> and <tt>std::auto_ptr</tt></li></ul><table border="0">
<ul><li>Functions</li><li>Classes</li><li>Class Templates</li><li>Virtual Methods</li><li>Overloading</li><li>Attributes </li><li>Enums (both &quot;free&quot; enums and class enums)</li><li>Nested Classes</li></ul><table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><img src="theme/l_arr_disabled.gif" border="0"></td>

View File

@@ -55,21 +55,10 @@ function:</p>
<td class="note_box">
<img src="theme/note.gif"></img> <b>What if a function or method needs a policy and the user
doesn't set one?</b><br><br> If a function/method needs a policy and one was not
set, Pyste will issue a error. The user should then go in the interface file
and set the policy for it, otherwise the generated cpp won't compile.
</td>
</tr>
</table>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/note.gif"></img>
Note that, for functions/methods that return <tt>const T&amp;</tt>, the policy
<tt>return_value_policy&lt;copy_const_reference&gt;()</tt> wil be used by default, because
that's normally what you want. You can change it to something else if you need
to, though.
doesn't set one?</b><br><br>
If a function/method needs a policy and one was not set, Pyste will issue a error.
The user should then go in the interface file and set the policy for it,
otherwise the generated cpp won't compile.
</td>
</tr>
</table>

View File

@@ -30,7 +30,7 @@ Here's the interface file for it, named [^world.pyste]:
and that's it!
The next step is invoke Pyste in the command-line:
The next step is invoke pyste in the command-line:
[pre python pyste.py --module=hello world.pyste]
@@ -47,21 +47,20 @@ Pyste supports the following features:
* Attributes
* Enums (both "free" enums and class enums)
* Nested Classes
* Support for [^boost::shared_ptr] and [^std::auto_ptr]
[page Running Pyste]
To run Pyste, you will need:
To run pyste, you will need:
* Python 2.2, available at [@http://www.python.org python's website].
* Python 2.2, avaiable at [@http://www.python.org python's website].
* The great [@http://effbot.org elementtree] library, from Fredrik Lundh.
* The excellent GCCXML, from Brad King.
Installation for the tools is available in their respective webpages.
Installation for the tools is avaiable in their respective webpages.
[blurb
[$theme/note.gif] GCCXML must be accessible in the PATH environment variable, so
that Pyste can call it. How to do this varies from platform to platform.
that pyste can call it. How to do this varies from platform to platform.
]
[h2 Ok, now what?]
@@ -72,56 +71,31 @@ Well, now let's fire it up:
'''
>python pyste.py
Pyste version 0.6.5
Usage:
pyste [options] --module=<name> interface-files
where options are:
-I <path> add an include path
-D <symbol> define symbol
--multiple create various cpps, instead of only one
(useful during development)
--out specify output filename (default: <module>.cpp)
in --multiple mode, this will be a directory
-I <path> add an include path
-D <symbol> define symbol
--no-using do not declare "using namespace boost";
use explicit declarations instead
--pyste-ns=<name> set the namespace where new types will be declared;
default is the empty namespace
--debug writes the xml for each file parsed in the current
directory
-h, --help print this help and exit
-v, --version print version information
default is "pyste"
'''
]
Options explained:
The [^-I] and [^-D] are preprocessor flags, which are needed by GCCXML to parse
the header files correctly and by Pyste to find the header files declared in the
The [^-I] and [^-D] are preprocessor flags, which are needed by gccxml to parse the header files correctly and by pyste to find the header files declared in the
interface files.
[^--multiple] tells Pyste to generate multiple cpps for this module (one for
each header parsed) in the directory named by [^--out], instead of the usual
single cpp file. This mode is useful during development of a binding, because
you are constantly changing source files, re-generating the bindings and
recompiling. This saves a lot of time in compiling.
[^--out] names the output file (default: [^<module>.cpp]), or in multiple mode,
names a output directory for the files (default: [^<module>]).
[^--no-using] tells Pyste to don't declare "[^using namespace boost;]" in the
[^--no-using] tells pyste to don't declare "[^using namespace boost;]" in the
generated cpp, using the namespace boost::python explicitly in all declarations.
Use only if you're having a name conflict in one of the files.
Use [^--pyste-ns] to change the namespace where new types are declared (for
instance, the virtual wrappers). Use only if you are having any problems. By
default, Pyste uses the empty namespace.
[^--debug] will write in the current directory a xml file as outputted by GCCXML
for each header parsed. Useful for bug reports.
[^-h, --help, -v, --version] are self-explaining, I believe. ;)
instance, the virtual wrappers). Use only if one of your header files declare a
namespace named "pyste" and this is causing conflicts.
So, the usage is simple enough:
@@ -129,13 +103,7 @@ So, the usage is simple enough:
will generate a file [^mymodule.cpp] in the same dir where the command was
executed. Now you can compile the file using the same instructions of the
[@../../doc/tutorial/doc/building_hello_world.html tutorial]. Or, if you prefer:
[pre >python pyste.py --module=mymodule --multiple file.pyste file2.pyste ...]
will create a directory named "mymodule" in the current directory, and will
generate a bunch of cpp files, one for each header exported. You can then
compile them all into a single shared library (or dll).
[@../../doc/tutorial/doc/building_hello_world.html tutorial].
[h2 Wait... how do I set those I and D flags?]
@@ -152,15 +120,11 @@ which for Visual C++ 6 is normally located at:
with that, you should have little trouble setting up the flags.
[blurb [$theme/note.gif][*A note about Psyco][br][br]
Although you don't have to install [@http://psyco.sourceforge.net/ Psyco] to use Pyste, if you do, Pyste will make use of it to speed up the wrapper generation. Speed ups of 30% can be achieved, so it's highly recommended.
]
[page The Interface Files]
The interface files are the heart of Pyste. The user creates one or more
interface files declaring the classes and functions he wants to export, and then
invokes Pyste passing the interface files to it. Pyste then generates a single
invokes pyste passing the interface files to it. Pyste then generates a single
cpp file with Boost.Python code, with all the classes and functions exported.
Besides declaring the classes and functions, the user has a number of other
@@ -221,14 +185,7 @@ with the function [^exclude]:
exclude(World.greet)
exclude(World.msg)
To access the operators of a class, access the member [^operator] like this
(supposing that [^C] is a class being exported):
exclude(C.operator['+'])
exclude(C.operator['*'])
exclude(C.operator['<<'])
The string inside the brackets is the same as the name of the operator in C++.[br]
Easy, huh? [$theme/smiley.gif]
[page:1 Policies]
@@ -255,22 +212,15 @@ function:
[blurb
[$theme/note.gif] [*What if a function or method needs a policy and the user
doesn't set one?][br][br] If a function/method needs a policy and one was not
set, Pyste will issue a error. The user should then go in the interface file
and set the policy for it, otherwise the generated cpp won't compile.
]
[blurb
[$theme/note.gif]
Note that, for functions/methods that return [^const T&], the policy
[^return_value_policy<copy_const_reference>()] wil be used by default, because
that's normally what you want. You can change it to something else if you need
to, though.
doesn't set one?][br][br]
If a function/method needs a policy and one was not set, Pyste will issue a error.
The user should then go in the interface file and set the policy for it,
otherwise the generated cpp won't compile.
]
[page:1 Templates]
Template classes can easily be exported too, but you can't export the template
Template Classes can easily exported too, but you can't export the "Template"
itself... you have to export instantiations of it! So, if you want to export a
[^std::vector], you will have to export vectors of int, doubles, etc.
@@ -297,7 +247,7 @@ rename the instantiations:
double_inst = Point("double") // another way to do the same
rename(double_inst, "DPoint")
Note that you can rename, exclude, set policies, etc, in the [^Template] object
Note that you can rename, exclude, set policies, etc, in the [^Template] class
like you would do with a [^Function] or a [^Class]. This changes affect all
[*future] instantiations:
@@ -318,7 +268,7 @@ If you want to change a option of a particular instantiation, you can do so:
[blurb [$theme/note.gif] [*What if my template accepts more than one type?]
[br][br]
When you want to instantiate a template with more than one type, you can pass
When you want to instantiate a Template with more than one type, you can pass
either a string with the types separated by whitespace, or a list of strings
'''("int double" or ["int", "double"]''' would both work).
]
@@ -329,20 +279,14 @@ Suppose you have this function:
std::vector<std::string> names();
But you don't want to export [^std::vector<std::string>], you want this function
to return a python list of strings. Boost.Python has excellent support for
that:
But you don't want to export a vector<string>, you want this function to return
a python list of strings. Boost.Python has an excellent support for that:
list names_wrapper()
{
list result;
// call original function
vector<string> v = names();
// put all the strings inside the python list
vector<string>::iterator it;
for (it = v.begin(); it != v.end(); ++it){
result.append(*it);
}
// put each string in the vector in the list
return result;
}
@@ -351,8 +295,9 @@ that:
def("names", &names_wrapper);
}
Nice heh? Pyste supports this mechanism too. You declare the [^names_wrapper]
function in a header named "[^test_wrappers.h]" and in the interface file:
Nice heh?
Pyste supports this mechanism too. You declare the [^names_wrapper] function in a
header, like "[^test_wrappers.h]", and in the interface file:
Include("test_wrappers.h")
names = Function("names", "test.h")
@@ -364,13 +309,13 @@ You can optionally declare the function in the interface file itself:
"""
list names_wrapper()
{
// code to call name() and convert the vector to a list...
// call name() and convert the vector to a list...
}
""")
names = Function("names", "test.h")
set_wrapper(names, names_wrapper)
The same mechanism can be used with methods too. Just remember that the first
The same mechanism can be done with methods too. Just remember that the first
parameter of wrappers for methods is a pointer to the class, like in
Boost.Python:
@@ -381,7 +326,7 @@ Boost.Python:
list names_wrapper(C* c)
{
// same as before, calling c->names() and converting result to a list
// same as before, calling c->names() and converting result to a list
}
And then in the interface file:
@@ -389,13 +334,6 @@ And then in the interface file:
C = Class("C", "test.h")
set_wrapper(C.names, "names_wrapper")
[blurb
[$theme/note.gif]Even though Boost.Python accepts either a pointer or a
reference to the class in wrappers for member functions as the first parameter,
Pyste expects them to be a [*pointer]. Doing otherwise will prevent your
code to compile when you set a wrapper for a virtual method.
]
[page:1 Exporting All Declarations from a Header]
Pyste also supports a mechanism to export all declarations found in a header
@@ -430,38 +368,3 @@ the members of the header object like this:
rename(hello.World.greet, "Greet")
exclude(hello.World.set, "Set")
[page:1 Smart Pointers]
Pyste for now has manual support for smart pointers. Suppose:
struct C
{
int value;
};
boost::shared_ptr<C> newC(int value)
{
boost::shared_ptr<C> c( new C() );
c->value = value;
return c;
}
void printC(boost::shared_ptr<C> c)
{
std::cout << c->value << std::endl;
}
To make [^newC] and [^printC] work correctly, you have to tell Pyste that a
convertor for [^boost::shared_ptr<C>] is needed.
C = Class('C', 'C.h')
use_shared_ptr(C)
Function('newC', 'C.h')
Function('printC', 'C.h')
For [^std::auto_ptr]'s, use the function [^use_auto_ptr].
This system is temporary, and in the future the converters will automatically be
exported if needed, without the need to tell Pyste about them explicitly.

View File

@@ -50,15 +50,7 @@ with the function <tt>exclude</tt>:</p>
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>World</span><span class=special>.</span><span class=identifier>msg</span><span class=special>)
</span></pre></code>
<p>
To access the operators of a class, access the member <tt>operator</tt> like this
(supposing that <tt>C</tt> is a class being exported):</p>
<code><pre>
<span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'+'</span><span class=special>])
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'*'</span><span class=special>])
</span><span class=identifier>exclude</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=keyword>operator</span><span class=special>[</span><span class=literal>'&lt;&lt;'</span><span class=special>])
</span></pre></code>
<p>
The string inside the brackets is the same as the name of the operator in C++.<br></p>
Easy, huh? <img src="theme/smiley.gif"></img></p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>

View File

@@ -25,19 +25,19 @@
</tr>
</table>
<p>
To run Pyste, you will need:</p>
<ul><li>Python 2.2, available at <a href="http://www.python.org">
To run pyste, you will need:</p>
<ul><li>Python 2.2, avaiable at <a href="http://www.python.org">
python's website</a>.</li><li>The great <a href="http://effbot.org">
elementtree</a> library, from Fredrik Lundh.</li><li>The excellent <a href="http://www.gccxml.org">
GCCXML</a>, from Brad King.</li></ul><p>
Installation for the tools is available in their respective webpages.</p>
Installation for the tools is avaiable in their respective webpages.</p>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/note.gif"></img> <a href="http://www.gccxml.org">
GCCXML</a> must be accessible in the PATH environment variable, so
that Pyste can call it. How to do this varies from platform to platform.
that pyste can call it. How to do this varies from platform to platform.
</td>
</tr>
</table>
@@ -47,68 +47,37 @@ Well, now let's fire it up:</p>
&gt;python pyste.py
Pyste version 0.6.5
Usage:
pyste [options] --module=&lt;name&gt; interface-files
where options are:
-I &lt;path&gt; add an include path
-D &lt;symbol&gt; define symbol
--multiple create various cpps, instead of only one
(useful during development)
--out specify output filename (default: &lt;module&gt;.cpp)
in --multiple mode, this will be a directory
-I &lt;path&gt; add an include path
-D &lt;symbol&gt; define symbol
--no-using do not declare &quot;using namespace boost&quot;;
use explicit declarations instead
--pyste-ns=&lt;name&gt; set the namespace where new types will be declared;
default is the empty namespace
--debug writes the xml for each file parsed in the current
directory
-h, --help print this help and exit
-v, --version print version information
default is &quot;pyste&quot;
</pre></code><p>
Options explained:</p>
<p>
The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by <a href="http://www.gccxml.org">
GCCXML</a> to parse
the header files correctly and by Pyste to find the header files declared in the
The <tt>-I</tt> and <tt>-D</tt> are preprocessor flags, which are needed by gccxml to parse the header files correctly and by pyste to find the header files declared in the
interface files.</p>
<p>
<tt>--multiple</tt> tells Pyste to generate multiple cpps for this module (one for
each header parsed) in the directory named by <tt>--out</tt>, instead of the usual
single cpp file. This mode is useful during development of a binding, because
you are constantly changing source files, re-generating the bindings and
recompiling. This saves a lot of time in compiling.</p>
<p>
<tt>--out</tt> names the output file (default: <tt>&lt;module&gt;.cpp</tt>), or in multiple mode,
names a output directory for the files (default: <tt>&lt;module&gt;</tt>).</p>
<p>
<tt>--no-using</tt> tells Pyste to don't declare &quot;<tt>using namespace boost;</tt>&quot; in the
<tt>--no-using</tt> tells pyste to don't declare &quot;<tt>using namespace boost;</tt>&quot; in the
generated cpp, using the namespace boost::python explicitly in all declarations.
Use only if you're having a name conflict in one of the files.</p>
<p>
Use <tt>--pyste-ns</tt> to change the namespace where new types are declared (for
instance, the virtual wrappers). Use only if you are having any problems. By
default, Pyste uses the empty namespace.</p>
<p>
<tt>--debug</tt> will write in the current directory a xml file as outputted by <a href="http://www.gccxml.org">
GCCXML</a>
for each header parsed. Useful for bug reports.</p>
<p>
<tt>-h, --help, -v, --version</tt> are self-explaining, I believe. ;)</p>
instance, the virtual wrappers). Use only if one of your header files declare a
namespace named &quot;pyste&quot; and this is causing conflicts.</p>
<p>
So, the usage is simple enough:</p>
<code><pre>&gt;python pyste.py --module=mymodule file.pyste file2.pyste ...</pre></code><p>
will generate a file <tt>mymodule.cpp</tt> in the same dir where the command was
executed. Now you can compile the file using the same instructions of the
<a href="../../doc/tutorial/doc/building_hello_world.html">
tutorial</a>. Or, if you prefer:</p>
<code><pre>&gt;python pyste.py --module=mymodule --multiple file.pyste file2.pyste ...</pre></code><p>
will create a directory named &quot;mymodule&quot; in the current directory, and will
generate a bunch of cpp files, one for each header exported. You can then
compile them all into a single shared library (or dll).</p>
tutorial</a>. </p>
<a name="wait____how_do_i_set_those_i_and_d_flags_"></a><h2>Wait... how do I set those I and D flags?</h2><p>
Don't worry: normally <a href="http://www.gccxml.org">
GCCXML</a> is already configured correctly for your plataform,
@@ -124,15 +93,6 @@ which for Visual C++ 6 is normally located at:</p>
</span></pre></code>
<p>
with that, you should have little trouble setting up the flags.</p>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/note.gif"></img><b>A note about Psyco</b><br><br>
Although you don't have to install <a href="http://psyco.sourceforge.net/">
Psyco</a> to use Pyste, if you do, Pyste will make use of it to speed up the wrapper generation. Speed ups of 30% can be achieved, so it's highly recommended.
</td>
</tr>
</table>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>

View File

@@ -1,74 +0,0 @@
<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Smart Pointers</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="exporting_all_declarations_from_a_header.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
<tr>
<td><img src="theme/c%2B%2Bboost.gif">
</td>
<td width="85%">
<font size="6" face="Verdana, Arial, Helvetica, sans-serif"><b>Smart Pointers</b></font>
</td>
</tr>
</table>
<br>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
</tr>
</table>
<p>
Pyste for now has manual support for smart pointers. Suppose:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>C
</span><span class=special>{
</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>;
};
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special>&lt;</span><span class=identifier>C</span><span class=special>&gt; </span><span class=identifier>newC</span><span class=special>(</span><span class=keyword>int </span><span class=identifier>value</span><span class=special>)
{
</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special>&lt;</span><span class=identifier>C</span><span class=special>&gt; </span><span class=identifier>c</span><span class=special>( </span><span class=keyword>new </span><span class=identifier>C</span><span class=special>() );
</span><span class=identifier>c</span><span class=special>-&gt;</span><span class=identifier>value </span><span class=special>= </span><span class=identifier>value</span><span class=special>;
</span><span class=keyword>return </span><span class=identifier>c</span><span class=special>;
}
</span><span class=keyword>void </span><span class=identifier>printC</span><span class=special>(</span><span class=identifier>boost</span><span class=special>::</span><span class=identifier>shared_ptr</span><span class=special>&lt;</span><span class=identifier>C</span><span class=special>&gt; </span><span class=identifier>c</span><span class=special>)
{
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>cout </span><span class=special>&lt;&lt; </span><span class=identifier>c</span><span class=special>-&gt;</span><span class=identifier>value </span><span class=special>&lt;&lt; </span><span class=identifier>std</span><span class=special>::</span><span class=identifier>endl</span><span class=special>;
}
</span></pre></code>
<p>
To make <tt>newC</tt> and <tt>printC</tt> work correctly, you have to tell Pyste that a
convertor for <tt>boost::shared_ptr&lt;C&gt;</tt> is needed.</p>
<code><pre>
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=literal>'C'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
</span><span class=identifier>use_shared_ptr</span><span class=special>(</span><span class=identifier>C</span><span class=special>)
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'newC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
</span><span class=identifier>Function</span><span class=special>(</span><span class=literal>'printC'</span><span class=special>, </span><span class=literal>'C.h'</span><span class=special>)
</span></pre></code>
<p>
For <tt>std::auto_ptr</tt>'s, use the function <tt>use_auto_ptr</tt>.</p>
<p>
This system is temporary, and in the future the converters will automatically be
exported if needed, without the need to tell Pyste about them explicitly.</p>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="exporting_all_declarations_from_a_header.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
</tr>
</table>
<br>
<hr size="1"><p class="copyright">Copyright &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>
<font size="2">Permission to copy, use, modify, sell and distribute this document
is granted provided this copyright notice appears in all copies. This document
is provided &quot;as is&quot; without express or implied warranty, and with
no claim as to its suitability for any purpose. </font> </p>
</body>
</html>

View File

@@ -25,7 +25,7 @@
</tr>
</table>
<p>
Template classes can easily be exported too, but you can't export the template
Template Classes can easily exported too, but you can't export the &quot;Template&quot;
itself... you have to export instantiations of it! So, if you want to export a
<tt>std::vector</tt>, you will have to export vectors of int, doubles, etc.</p>
<p>
@@ -55,7 +55,7 @@ rename the instantiations:</p>
</span><span class=identifier>rename</span><span class=special>(</span><span class=identifier>double_inst</span><span class=special>, </span><span class=string>&quot;DPoint&quot;</span><span class=special>)
</span></pre></code>
<p>
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> object
Note that you can rename, exclude, set policies, etc, in the <tt>Template</tt> class
like you would do with a <tt>Function</tt> or a <tt>Class</tt>. This changes affect all
<b>future</b> instantiations:</p>
<code><pre>
@@ -80,7 +80,7 @@ If you want to change a option of a particular instantiation, you can do so:</p>
<td class="note_box">
<img src="theme/note.gif"></img> <b>What if my template accepts more than one type?</b>
<br><br>
When you want to instantiate a template with more than one type, you can pass
When you want to instantiate a Template with more than one type, you can pass
either a string with the types separated by whitespace, or a list of strings
(&quot;int double&quot; or [&quot;int&quot;, &quot;double&quot;] would both work).
</td>

View File

@@ -27,7 +27,7 @@
<p>
The interface files are the heart of Pyste. The user creates one or more
interface files declaring the classes and functions he wants to export, and then
invokes Pyste passing the interface files to it. Pyste then generates a single
invokes pyste passing the interface files to it. Pyste then generates a single
cpp file with <a href="../../index.html">
Boost.Python</a> code, with all the classes and functions exported.</p>
<p>

View File

@@ -30,21 +30,15 @@ Suppose you have this function:</p>
<span class=identifier>std</span><span class=special>::</span><span class=identifier>vector</span><span class=special>&lt;</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>&gt; </span><span class=identifier>names</span><span class=special>();
</span></pre></code>
<p>
But you don't want to export <tt>std::vector&lt;std::string&gt;</tt>, you want this function
to return a python list of strings. <a href="../../index.html">
Boost.Python</a> has excellent support for
that:</p>
But you don't want to export a vector&lt;string&gt;, you want this function to return
a python list of strings. <a href="../../index.html">
Boost.Python</a> has an excellent support for that:</p>
<code><pre>
<span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>()
{
</span><span class=identifier>list </span><span class=identifier>result</span><span class=special>;
// </span><span class=identifier>call </span><span class=identifier>original </span><span class=identifier>function
</span><span class=identifier>vector</span><span class=special>&lt;</span><span class=identifier>string</span><span class=special>&gt; </span><span class=identifier>v </span><span class=special>= </span><span class=identifier>names</span><span class=special>();
// </span><span class=identifier>put </span><span class=identifier>all </span><span class=identifier>the </span><span class=identifier>strings </span><span class=identifier>inside </span><span class=identifier>the </span><span class=identifier>python </span><span class=identifier>list
</span><span class=identifier>vector</span><span class=special>&lt;</span><span class=identifier>string</span><span class=special>&gt;::</span><span class=identifier>iterator </span><span class=identifier>it</span><span class=special>;
</span><span class=keyword>for </span><span class=special>(</span><span class=identifier>it </span><span class=special>= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(); </span><span class=identifier>it </span><span class=special>!= </span><span class=identifier>v</span><span class=special>.</span><span class=identifier>end</span><span class=special>(); ++</span><span class=identifier>it</span><span class=special>){
</span><span class=identifier>result</span><span class=special>.</span><span class=identifier>append</span><span class=special>(*</span><span class=identifier>it</span><span class=special>);
}
// </span><span class=identifier>put </span><span class=identifier>each </span><span class=identifier>string </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>vector </span><span class=identifier>in </span><span class=identifier>the </span><span class=identifier>list
</span><span class=keyword>return </span><span class=identifier>result</span><span class=special>;
}
@@ -54,8 +48,9 @@ that:</p>
}
</span></pre></code>
<p>
Nice heh? Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt>
function in a header named &quot;<tt>test_wrappers.h</tt>&quot; and in the interface file:</p>
Nice heh?
Pyste supports this mechanism too. You declare the <tt>names_wrapper</tt> function in a
header, like &quot;<tt>test_wrappers.h</tt>&quot;, and in the interface file:</p>
<code><pre>
<span class=identifier>Include</span><span class=special>(</span><span class=string>&quot;test_wrappers.h&quot;</span><span class=special>)
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>&quot;names&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</span><span class=special>)
@@ -68,14 +63,14 @@ You can optionally declare the function in the interface file itself:</p>
</span><span class=string>&quot;&quot;</span><span class=string>&quot;
list names_wrapper()
{
// code to call name() and convert the vector to a list...
// call name() and convert the vector to a list...
}
&quot;</span><span class=string>&quot;&quot;</span><span class=special>)
</span><span class=identifier>names </span><span class=special>= </span><span class=identifier>Function</span><span class=special>(</span><span class=string>&quot;names&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</span><span class=special>)
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>names</span><span class=special>, </span><span class=identifier>names_wrapper</span><span class=special>)
</span></pre></code>
<p>
The same mechanism can be used with methods too. Just remember that the first
The same mechanism can be done with methods too. Just remember that the first
parameter of wrappers for methods is a pointer to the class, like in
<a href="../../index.html">
Boost.Python</a>:</p>
@@ -87,7 +82,7 @@ Boost.Python</a>:</p>
</span><span class=identifier>list </span><span class=identifier>names_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>* </span><span class=identifier>c</span><span class=special>)
{
// </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-&gt;</span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list
// </span><span class=identifier>same </span><span class=identifier>as </span><span class=identifier>before</span><span class=special>, </span><span class=identifier>calling </span><span class=identifier>c</span><span class=special>-&gt;</span><span class=identifier>names</span><span class=special>() </span><span class=keyword>and </span><span class=identifier>converting </span><span class=identifier>result </span><span class=identifier>to </span><span class=identifier>a </span><span class=identifier>list
</span><span class=special>}
</span></pre></code>
<p>
@@ -96,18 +91,6 @@ And then in the interface file:</p>
<span class=identifier>C </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;C&quot;</span><span class=special>, </span><span class=string>&quot;test.h&quot;</span><span class=special>)
</span><span class=identifier>set_wrapper</span><span class=special>(</span><span class=identifier>C</span><span class=special>.</span><span class=identifier>names</span><span class=special>, </span><span class=string>&quot;names_wrapper&quot;</span><span class=special>)
</span></pre></code>
<table width="80%" border="0" align="center">
<tr>
<td class="note_box">
<img src="theme/note.gif"></img>Even though <a href="../../index.html">
Boost.Python</a> accepts either a pointer or a
reference to the class in wrappers for member functions as the first parameter,
Pyste expects them to be a <b>pointer</b>. Doing otherwise will prevent your
code to compile when you set a wrapper for a virtual method.
</td>
</tr>
</table>
<table border="0">
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>

View File

@@ -1,2 +1 @@
.sconsign
*.obj
*.cpp

View File

@@ -1,8 +0,0 @@
#include "basic.h"
namespace basic {
int C::static_value = 3;
const int C::const_static_value = 100;
}

View File

@@ -1,15 +1,7 @@
#ifndef BASIC_H
#define BASIC_H
#include <string>
namespace basic {
struct C
{
// test virtuallity
C(): value(1), const_value(0) {}
virtual int f(int x = 10)
{
return x*2;
@@ -18,42 +10,16 @@ struct C
int foo(int x=1){
return x+1;
}
const std::string& name() { return _name; }
void set_name(const std::string& name) { _name = name; }
std::string _name;
// test data members
static int static_value;
static const int const_static_value;
int value;
const int const_value;
// test static functions
static int mul(int x=2, int y=3) { return x*y; }
};
inline int call_f(C& c)
int call_f(C& c)
{
return c.f();
}
inline int call_f(C& c, int x)
int call_f(C& c, int x)
{
return c.f(x);
}
inline int get_static()
{
return C::static_value;
}
inline int get_value(C& c)
{
return c.value;
}
}
#endif

View File

@@ -1,5 +1,2 @@
Class('basic::C', 'basic.h')
Function('basic::call_f', 'basic.h')
Function('basic::get_static', 'basic.h')
Function('basic::get_value', 'basic.h')

View File

@@ -1,6 +1,3 @@
#ifndef ENUMS_H
#define ENUMS_H
namespace enums {
enum color { red, blue };
@@ -20,5 +17,3 @@ struct X
};
}
#endif

View File

@@ -1,6 +1,3 @@
#ifndef HEADER_TEST_H
#define HEADER_TEST_H
#include <map>
#include <string>
@@ -8,7 +5,7 @@ namespace header_test {
enum choice { red, blue };
inline std::string choice_str(choice c)
std::string choice_str(choice c)
{
std::map<choice, std::string> choice_map;
choice_map[red] = "red";
@@ -27,5 +24,3 @@ struct C
};
}
#endif

View File

@@ -1,18 +0,0 @@
template<typename T>
class A
{
public:
void set(T v) { mData = v; }
T get() const { return mData; }
private:
T mData;
};
class B : public A<int>
{
public:
int go() { return get(); }
};

View File

@@ -1,8 +0,0 @@
# Doesn't work:
A = Template('A', 'inherit.h')
A_int = A('int')
Class('B', 'inherit.h')
# Does work:
#AllFromHeader('inherit.h')

View File

@@ -1,4 +0,0 @@
#include "nested.h"
int nested::X::staticXValue = 10;
int nested::X::Y::staticYValue = 20;

View File

@@ -1,6 +1,3 @@
#ifndef NESTED_H
#define NESTED_H
namespace nested {
struct X
@@ -19,8 +16,9 @@ struct X
int valueX;
};
int X::staticXValue = 10;
int X::Y::staticYValue = 20;
typedef X Root;
}
#endif

View File

@@ -1,47 +0,0 @@
#ifndef OPAQUE_H
#define OPAQUE_H
#include <iostream>
namespace opaque {
struct C {
C(int v): value(v) {}
int value;
};
inline C* new_C()
{
return new C(10);
}
inline int get(C* c)
{
return c->value;
}
struct D {
D(double v): value(v) {}
double value;
};
struct A
{
D* new_handle()
{
return new D(3.0);
}
double get(D* d)
{
return d->value;
}
int f(int x=0) { return x; }
};
}
#endif

View File

@@ -1,5 +0,0 @@
foo = Function('opaque::new_C', 'opaque.h')
set_policy(foo, return_value_policy(return_opaque_pointer))
Function('opaque::get', 'opaque.h' )
A = Class('opaque::A', 'opaque.h')
set_policy(A.new_handle, return_value_policy(return_opaque_pointer))

47
pyste/example/operator.h Normal file
View File

@@ -0,0 +1,47 @@
#include <iostream>
struct C
{
static double x;
double value;
const C operator+(const C other) const
{
C c;
c.value = value + other.value;
return c;
}
operator int() const
{
return value;
}
double operator()()
{
return x;
}
double operator()(double other)
{
return x + other;
}
};
double C::x = 10;
const C operator*(const C& lhs, const C& rhs)
{
C c;
c.value = lhs.value * rhs.value;
return c;
}
std::ostream& operator <<( std::ostream& s, const C& c)
{
std::cout << "here";
s << "C instance: ";
return s;
}

View File

@@ -0,0 +1,12 @@
Include('iostream')
test = Wrapper('sum',
'''
const C sum(const C&, const C&)
{
std::cout << "sum!" << std::endl;
return C();
}
'''
)
C = Class('C', 'operator.h')
set_wrapper(C.operator['+'], test)

View File

@@ -1,3 +0,0 @@
#include "operators.h"
double operators::C::x = 10;

View File

@@ -1,7 +1,3 @@
#ifndef OPERATORS_H
#define OPERATORS_H
#include <iostream>
namespace operators {
@@ -19,7 +15,7 @@ struct C
}
operator int() const
{
return (int)value;
return value;
}
double operator()()
@@ -32,18 +28,16 @@ struct C
return C::x + other;
}
operator const char*() { return "C"; }
};
inline const C operator*(const C& lhs, const C& rhs)
double C::x = 10;
const C operator*(const C& lhs, const C& rhs)
{
C c;
c.value = lhs.value * rhs.value;
return c;
}
}
#endif

View File

@@ -1,2 +1 @@
C = Class('operators::C', 'operators.h')
#exclude(C.operator['+'])
Class('operators::C', 'operators.h')

View File

@@ -1,29 +0,0 @@
#ifndef SMART_PTR_H
#define SMART_PTR_H
#include <memory>
#include <boost/shared_ptr.hpp>
namespace smart_ptr {
struct C
{
int value;
};
inline boost::shared_ptr<C> NewC() { return boost::shared_ptr<C>( new C() ); }
struct D
{
boost::shared_ptr<C> Get() { return ptr; }
void Set( boost::shared_ptr<C> c ) { ptr = c; }
private:
boost::shared_ptr<C> ptr;
};
inline std::auto_ptr<D> NewD() { return std::auto_ptr<D>( new D() ); }
}
#endif

View File

@@ -1,6 +0,0 @@
C = Class('smart_ptr::C', 'smart_ptr.h')
use_shared_ptr(C)
D = Class('smart_ptr::D', 'smart_ptr.h')
use_auto_ptr(D)
Function('smart_ptr::NewC', 'smart_ptr.h')
Function('smart_ptr::NewD', 'smart_ptr.h')

View File

@@ -1,10 +1,10 @@
namespace templates {
template <class T>
template <class X, class Y>
struct Point
{
T x;
T y;
X x;
Y y;
};
}

View File

@@ -1,8 +1,9 @@
Point = Template('templates::Point', 'templates.h')
rename(Point.x, 'i')
rename(Point.y, 'j')
IPoint = Point('int')
FPoint = Point('double', 'FPoint')
IPoint = Point('int double')
FPoint = Point('double int', 'FPoint')
rename(IPoint, 'IPoint')
rename(IPoint.x, 'x')
rename(IPoint.y, 'y')

View File

@@ -20,6 +20,6 @@ private:
virtual const char* name() { return "C"; }
};
inline int call_f(C& c) { return c.f(); }
int call_f(C& c) { return c.f(); }
}

View File

@@ -1,27 +0,0 @@
namespace virtual2 {
struct A
{
virtual int f() { return 0; }
virtual int f1() { return 10; }
};
struct B: A
{
virtual int f() { return 1; }
virtual int f2() { return 20; }
};
inline int call_fs(A*a)
{
int r = a->f1();
B* b = dynamic_cast<B*>(a);
return r + b->f2();
}
inline int call_f(A* a)
{
return a->f();
}
}

View File

@@ -1,4 +0,0 @@
Class('virtual2::A', 'virtual2.h')
Class('virtual2::B', 'virtual2.h')
Function('virtual2::call_fs', 'virtual2.h')
Function('virtual2::call_f', 'virtual2.h')

View File

@@ -6,7 +6,7 @@
namespace wrappertest {
inline std::vector<int> Range(int count)
std::vector<int> Range(int count)
{
std::vector<int> v;
v.reserve(count);
@@ -34,13 +34,6 @@ struct C
}
};
struct A
{
virtual int f() { return 1; };
};
inline int call_foo(A* a){ return a->f(); }
}
#endif

View File

@@ -13,9 +13,3 @@ list MulWrapper(wrappertest::C& c, int value){
C = Class('wrappertest::C', 'wrappertest.h')
set_wrapper(C.Mul, mul)
A = Class('wrappertest::A', 'wrappertest.h')
set_wrapper(A.f, 'f_wrapper')
Function('wrappertest::call_foo', 'wrappertest.h')

View File

@@ -11,7 +11,7 @@ template <class T>
list VectorToList(const std::vector<T> & v)
{
list res;
typename std::vector<T>::const_iterator it;
std::vector<T>::const_iterator it;
for(it = v.begin(); it != v.end(); ++it){
res.append(*it);
}
@@ -19,10 +19,8 @@ list VectorToList(const std::vector<T> & v)
return res;
}
inline list RangeWrapper(int count){
list RangeWrapper(int count){
return VectorToList(wrappertest::Range(count));
}
inline int f_wrapper(wrappertest::A*) { return 10; }
#endif

View File

@@ -60,11 +60,6 @@
<a href="doc/exporting_all_declarations_from_a_header.html">Exporting All Declarations from a Header</a>
</td>
</tr>
<tr>
<td class="toc_cells_L1">
<a href="doc/smart_pointers.html">Smart Pointers</a>
</td>
</tr>
</table>
<br>
<hr size="1"><p class="copyright">Copyright &copy; 2003 Bruno da Silva de Oliveira<br>Copyright &copy; 2002-2003 Joel de Guzman<br><br>

View File

@@ -1,14 +1,11 @@
import exporters
from Exporter import Exporter
from declarations import *
from enumerate import enumerate
from settings import *
from policies import *
from SingleCodeUnit import SingleCodeUnit
from CodeUnit import CodeUnit
from EnumExporter import EnumExporter
from utils import makeid, enumerate
from copy import deepcopy
import exporterutils
import re
#==============================================================================
# ClassExporter
@@ -36,22 +33,16 @@ class ClassExporter(Exporter):
self.sections['scope'] = []
# declarations: outside the BOOST_PYTHON_MODULE macro
self.sections['declaration'] = []
self.sections['declaration-outside'] = []
self.sections['include'] = []
# a list of Constructor instances
self.constructors = []
self.wrapper_generator = None
# a list of code units, generated by nested declarations
self.nested_codeunits = []
self._exported_opaque_pointers = {}
def ScopeName(self):
return makeid(self.class_.FullName()) + '_scope'
def Unit(self):
return makeid(self.class_.name)
return _ID(self.class_.FullName()) + '_scope'
def Name(self):
@@ -71,28 +62,24 @@ class ClassExporter(Exporter):
[x for x in self.class_.members if x.visibility == Scope.public]
def ClassBases(self):
bases = []
def GetBases(class_):
this_bases = [self.GetDeclaration(x.name) for x in class_.bases]
bases.extend(this_bases)
for base in this_bases:
GetBases(base)
GetBases(self.class_)
return bases
def Order(self):
'''Return the TOTAL number of bases that this class has, including the
bases' bases. Do this because base classes must be instantialized
before the derived classes in the module definition.
'''
return '%s_%s' % (len(self.ClassBases()), self.class_.FullName())
def BasesCount(classname):
decl = self.GetDeclaration(classname)
bases = [x.name for x in decl.bases]
total = 0
for base in bases:
total += BasesCount(base)
return len(bases) + total
return BasesCount(self.class_.FullName())
def Export(self, codeunit, exported_names):
self.CheckForwardDeclarations()
self.ExportBasics()
self.ExportBases(exported_names)
self.ExportConstructors()
@@ -102,17 +89,9 @@ class ClassExporter(Exporter):
self.ExportOperators()
self.ExportNestedClasses(exported_names)
self.ExportNestedEnums()
self.ExportSmartPointer()
self.ExportOpaquePointerPolicies()
self.Write(codeunit)
def CheckForwardDeclarations(self):
for m in self.public_members:
if isinstance(m, Function):
exporterutils.WarnForwardDeclarations(m)
def Write(self, codeunit):
indent = self.INDENT
boost_ns = namespaces.python
@@ -157,9 +136,6 @@ class ClassExporter(Exporter):
declarations += nested_unit.Section('declaration')
if declarations:
codeunit.Write('declaration', declarations + '\n')
declarations_outside = '\n'.join(self.sections['declaration-outside'])
if declarations_outside:
codeunit.Write('declaration-outside', declarations_outside + '\n')
# write the includes to the codeunit
includes = '\n'.join(self.sections['include'])
@@ -254,32 +230,50 @@ class ClassExporter(Exporter):
continue
name = self.info[var.name].rename or var.name
fullname = var.FullName()
if var.type.const:
def_ = '.def_readonly'
if var.static:
code = '%s->attr("%s") = %s;' % (self.ScopeName(), name, fullname)
self.Add('scope', code)
else:
def_ = '.def_readwrite'
code = '%s("%s", &%s)' % (def_, name, fullname)
self.Add('inside', code)
if var.type.const:
def_ = '.def_readonly'
else:
def_ = '.def_readwrite'
code = '%s("%s", &%s)' % (def_, name, fullname)
self.Add('inside', code)
printed_policy_warnings = {}
def CheckPolicy(self, m):
'Warns the user if this method needs a policy'
def IsString(type):
return type.const and type.name == 'char' and isinstance(type, PointerType)
needs_policy = isinstance(m.result, (ReferenceType, PointerType))
if IsString(m.result):
needs_policy = False
has_policy = self.info[m.name].policy is not None
if needs_policy and not has_policy:
warning = '---> Error: Method "%s" needs a policy.' % m.FullName()
if warning not in self.printed_policy_warnings:
print warning
print
self.printed_policy_warnings[warning] = 1
def ExportMethods(self):
'Export all the non-virtual methods of this class'
def OverloadName(m):
'Returns the name of the overloads struct for the given method'
return makeid(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
return _ID(m.FullName()) + ('_overloads_%i_%i' % (m.minArgs, m.maxArgs))
declared = {}
def DeclareOverloads(m):
'Declares the macro for the generation of the overloads'
if not m.virtual:
if m.static:
func = m.FullName()
macro = 'BOOST_PYTHON_FUNCTION_OVERLOADS'
else:
func = m.name
macro = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS'
code = '%s(%s, %s, %i, %i)\n' % (macro, OverloadName(m), func, m.minArgs, m.maxArgs)
func = m.name
code = 'BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(%s, %s, %i, %i)\n'
code = code % (OverloadName(m), func, m.minArgs, m.maxArgs)
if code not in declared:
declared[code] = True
self.Add('declaration', code)
@@ -306,28 +300,24 @@ class ClassExporter(Exporter):
methods = [x for x in self.public_members if IsExportable(x)]
for method in methods:
method_info = self.info[method.name]
# skip this method if it was excluded by the user
if method_info.exclude:
continue
if self.info[method.name].exclude:
continue # skip this method
# rename the method if the user requested
name = method_info.rename or method.name
name = self.info[method.name].rename or method.name
# warn the user if this method needs a policy and doesn't have one
method_info.policy = exporterutils.HandlePolicy(method, method_info.policy)
self.CheckPolicy(method)
# check for policies
policy = method_info.policy or ''
policy = self.info[method.name].policy or ''
if policy:
policy = ', %s%s()' % (namespaces.python, policy.Code())
# check for overloads
overload = ''
if method.minArgs != method.maxArgs:
# add the overloads for this method
DeclareOverloads(method)
overload_name = OverloadName(method)
DeclareOverloads(method)
overload = ', %s%s()' % (namespaces.pyste, overload_name)
# build the .def string to export the method
@@ -342,7 +332,7 @@ class ClassExporter(Exporter):
code = '.staticmethod("%s")' % name
self.Add('inside', code)
# add wrapper code if this method has one
wrapper = method_info.wrapper
wrapper = self.info[method.name].wrapper
if wrapper and wrapper.code:
self.Add('declaration', wrapper.code)
@@ -356,7 +346,7 @@ class ClassExporter(Exporter):
break
if has_virtual_methods:
generator = _VirtualWrapperGenerator(self.class_, self.ClassBases(), self.info)
generator = _VirtualWrapperGenerator(self.class_, self.info)
self.Add('template', generator.FullName())
for definition in generator.GenerateDefinitions():
self.Add('inside', definition)
@@ -375,16 +365,12 @@ class ClassExporter(Exporter):
'()' : '__call__',
}
# converters which have a special name in python
# it's a map of a regular expression of the converter's result to the
# appropriate python name
# converters which has a special name in python
SPECIAL_CONVERTERS = {
re.compile(r'(const)?\s*double$') : '__float__',
re.compile(r'(const)?\s*float$') : '__float__',
re.compile(r'(const)?\s*int$') : '__int__',
re.compile(r'(const)?\s*long$') : '__long__',
re.compile(r'(const)?\s*char\s*\*?$') : '__str__',
re.compile(r'(const)?.*::basic_string<.*>\s*(\*|\&)?$') : '__str__',
'double' : '__float__',
'float' : '__float__',
'int' : '__int__',
'long' : '__long__',
}
@@ -497,18 +483,16 @@ class ClassExporter(Exporter):
converters = [x for x in self.public_members if type(x) == ConverterOperator]
def ConverterMethodName(converter):
result_fullname = converter.result.FullName()
result_name = converter.result.name
for regex, method_name in self.SPECIAL_CONVERTERS.items():
if regex.match(result_fullname):
return method_name
result_fullname = converter.result.name
if result_fullname in self.SPECIAL_CONVERTERS:
return self.SPECIAL_CONVERTERS[result_fullname]
else:
# extract the last name from the full name
result_name = makeid(result_name)
result_name = _ID(result_fullname.split('::')[-1])
return 'to_' + result_name
for converter in converters:
info = self.info['operator'][converter.result.FullName()]
info = self.info['operator'][converter.result.name]
# check if this operator should be excluded
if info.exclude:
continue
@@ -539,7 +523,7 @@ class ClassExporter(Exporter):
nested_info.name = nested_class.FullName()
exporter = ClassExporter(nested_info)
exporter.SetDeclarations(self.declarations + [nested_class])
codeunit = SingleCodeUnit(None, None)
codeunit = CodeUnit(None)
exporter.Export(codeunit, exported_names)
self.nested_codeunits.append(codeunit)
@@ -552,30 +536,22 @@ class ClassExporter(Exporter):
enum_info.name = enum.FullName()
exporter = EnumExporter(enum_info)
exporter.SetDeclarations(self.declarations + [enum])
codeunit = SingleCodeUnit(None, None)
codeunit = CodeUnit(None)
exporter.Export(codeunit, None)
self.nested_codeunits.append(codeunit)
def ExportSmartPointer(self):
smart_ptr = self.info.smart_ptr
if smart_ptr:
self.Add('template', smart_ptr % self.class_.FullName())
def ExportOpaquePointerPolicies(self):
# check all methods for 'return_opaque_pointer' policies
methods = [x for x in self.public_members if isinstance(x, Method)]
for method in methods:
return_opaque_policy = return_value_policy(return_opaque_pointer)
if self.info[method.name].policy == return_opaque_policy:
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % method.result.name
if macro not in self._exported_opaque_pointers:
self.Add('declaration-outside', macro)
self._exported_opaque_pointers[macro] = 1
def _ID(name):
'Returns the name as a valid identifier'
for invalidchar in ('::', '<', '>', ' ', ','):
name = name.replace(invalidchar, '_')
# avoid duplications of '_' chars
names = [x for x in name.split('_') if x]
return '_'.join(names)
#==============================================================================
# Virtual Wrapper utils
#==============================================================================
@@ -597,13 +573,10 @@ def _ParamsInfo(m, count=None):
class _VirtualWrapperGenerator(object):
'Generates code to export the virtual methods of the given class'
def __init__(self, class_, bases, info):
def __init__(self, class_, info):
self.class_ = class_
self.bases = deepcopy(bases)
self.info = info
self.wrapper_name = makeid(class_.FullName()) + '_Wrapper'
self.virtual_methods = None
self.GenerateVirtualMethods()
self.wrapper_name = _ID(class_.FullName()) + '_Wrapper'
def DefaultImplementationNames(self, method):
@@ -648,18 +621,6 @@ class _VirtualWrapperGenerator(object):
# default implementations (with overloading)
# only for classes that are not abstract, and public methods
def DefaultImpl(method, param_names):
'Return the body of a default implementation wrapper'
wrapper = self.info[method.name].wrapper
if not wrapper:
# return the default implementation of the class
return '%s%s::%s(%s);\n' % \
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
else:
# return a call for the wrapper
params = ', '.join(['this'] + param_names)
return '%s%s(%s);\n' % (return_str, wrapper.FullName(), params)
if not method.abstract and method.visibility == Scope.public:
minArgs = method.minArgs
maxArgs = method.maxArgs
@@ -668,7 +629,8 @@ class _VirtualWrapperGenerator(object):
params, param_names, param_types = _ParamsInfo(method, argNum)
decl += '\n'
decl += indent + '%s %s(%s)%s {\n' % (result, impl_name, params, constantness)
decl += indent*2 + DefaultImpl(method, param_names)
decl += indent*2 + '%s%s::%s(%s);\n' % \
(return_str, self.class_.FullName(), method.name, ', '.join(param_names))
decl += indent + '}\n'
return decl
@@ -683,7 +645,7 @@ class _VirtualWrapperGenerator(object):
class_name = self.class_.FullName()
wrapper_name = pyste + self.wrapper_name
result = method.result.FullName()
is_method_unique = self.IsMethodUnique(method.name)
is_method_unique = self.class_.IsUnique(method.name)
constantness = ''
if method.const:
constantness = ' const'
@@ -699,7 +661,7 @@ class _VirtualWrapperGenerator(object):
param_list = [x.FullName() for x in method.parameters[:argNum]]
params = ', '.join(param_list)
signature = '%s (%s::*)(%s)%s' % (result, wrapper_name, params, constantness)
default_pointer = '(%s)&%s::%s' % (signature, wrapper_name, impl_name)
default_pointer = '(%s)%s::%s' % (signature, wrapper_name, impl_name)
default_pointers.append(default_pointer)
# get the pointer of the method
@@ -721,36 +683,13 @@ class _VirtualWrapperGenerator(object):
return namespaces.pyste + self.wrapper_name
def GenerateVirtualMethods(self):
'''To correctly export all virtual methods, we must also make wrappers
for the virtual methods of the bases of this class, as if the methods
were from this class itself.
This method creates the instance variable self.virtual_methods.
'''
def VirtualMethods(self):
def IsVirtual(m):
return type(m) == Method and m.virtual
all_members = self.class_.members[:]
for base in self.bases:
for base_member in base.members:
base_member.class_ = self.class_.FullName()
all_members.append(base_member)
# extract the virtual methods, avoiding duplications
self.virtual_methods = []
already_added = {}
for member in all_members:
if IsVirtual(member) and not member.FullName() in already_added:
self.virtual_methods.append(member)
already_added[member.FullName()] = 0
return [m for m in self.class_.members if IsVirtual(m)]
def IsMethodUnique(self, method):
count = {}
for m in self.virtual_methods:
count[m.name] = count.get(m.name, 0) + 1
return count[m.name] == 1
def Constructors(self):
def IsValid(m):
return isinstance(m, Constructor) and m.visibility == Scope.public
@@ -759,7 +698,7 @@ class _VirtualWrapperGenerator(object):
def GenerateDefinitions(self):
defs = []
for method in self.virtual_methods:
for method in self.VirtualMethods():
exclude = self.info[method.name].exclude
# generate definitions only for public methods and non-abstract methods
if method.visibility == Scope.public and not method.abstract and not exclude:
@@ -792,7 +731,7 @@ class _VirtualWrapperGenerator(object):
code += cons_code
# generate the body
body = []
for method in self.virtual_methods:
for method in self.VirtualMethods():
if not self.info[method.name].exclude:
body.append(self.Declaration(method, indent))
body = '\n'.join(body)

78
pyste/src/CodeUnit.py Normal file
View File

@@ -0,0 +1,78 @@
from settings import *
#==============================================================================
# RemoveDuplicatedLines
#==============================================================================
def RemoveDuplicatedLines(text):
includes = text.splitlines()
d = dict([(include, 0) for include in includes])
return '\n'.join(d.keys())
#==============================================================================
# CodeUnit
#==============================================================================
class CodeUnit:
'''
Represents a cpp file, where other objects can write in one of the
predefined sections.
The avaiable sections are:
include - The include area of the cpp file
declaration - The part before the module definition
module - Inside the BOOST_PYTHON_MODULE macro
'''
USING_BOOST_NS = True
def __init__(self, modulename):
self.modulename = modulename
# define the avaiable sections
self.code = {}
self.code['include'] = ''
self.code['declaration'] = ''
self.code['module'] = ''
def Write(self, section, code):
'write the given code in the section of the code unit'
if section not in self.code:
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
self.code[section] += code
def Section(self, section):
return self.code[section]
def Save(self, filename):
'Writes this code unit to the filename'
space = '\n\n'
fout = file(filename, 'w')
# includes
includes = RemoveDuplicatedLines(self.code['include'])
fout.write('\n' + self._leftEquals('Includes'))
fout.write('#include <boost/python.hpp>\n')
fout.write(includes)
fout.write(space)
# using
if self.USING_BOOST_NS:
fout.write(self._leftEquals('Using'))
fout.write('using namespace boost::python;\n\n')
# declarations
if self.code['declaration']:
pyste_namespace = namespaces.pyste[:-2]
fout.write(self._leftEquals('Declarations'))
fout.write('namespace %s {\n\n\n' % pyste_namespace)
fout.write(self.code['declaration'])
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
fout.write(space)
# module
fout.write(self._leftEquals('Module'))
fout.write('BOOST_PYTHON_MODULE(%s)\n{\n' % self.modulename)
fout.write(self.code['module'])
fout.write('}\n')
def _leftEquals(self, s):
s = '// %s ' % s
return s + ('='*(80-len(s))) + '\n'

View File

@@ -19,8 +19,6 @@ class CppParser:
defines = []
self.includes = includes
self.defines = defines
self._cache = []
self._CACHE_SIZE = 5
def _includeparams(self, filename):
@@ -38,19 +36,6 @@ class CppParser:
return ' '.join(defines)
def UpdateCache(self, include, tail, declarations, header):
self._cache.append((include, tail, declarations, header))
if len(self._cache) > self._CACHE_SIZE:
self._cache.pop(0)
def Cache(self, include, tail):
for cache_include, cache_tail, declarations, header in self._cache:
if cache_include == include and cache_tail == tail:
return declarations, header
return None
def FindFileName(self, include):
if os.path.isfile(include):
return include
@@ -62,17 +47,13 @@ class CppParser:
raise RuntimeError, 'Header file "%s" not found!' % name
def parse(self, include, tail=None):
def parse(self, include, symbols=None, tail=None):
'''Parses the given filename, and returns (declaration, header). The
header returned is normally the same as the given to this method,
except if tail is not None: in this case, the header is copied to a temp
filename and the tail code is appended to it before being passed on to gcc.
This temp filename is then returned.
'''
# check if this header was already parsed
cached = self.Cache(include, tail)
if cached:
return cached
filename = self.FindFileName(include)
# copy file to temp folder, if needed
if tail:
@@ -92,14 +73,14 @@ class CppParser:
# call gccxml
cmd = 'gccxml %s %s %s -fxml=%s' \
% (includes, defines, infilename, xmlfile)
if symbols:
cmd += ' -fxml-start=' + ','.join(symbols)
status = os.system(cmd)
if status != 0 or not os.path.isfile(xmlfile):
raise CppParserError, 'Error executing gccxml'
# parse the resulting xml
declarations = ParseDeclarations(xmlfile)
# cache the results
self.UpdateCache(include, tail, declarations, infilename)
# return the declarations
# return the declarations
return declarations, infilename
finally:
if settings.DEBUG and os.path.isfile(xmlfile):

View File

@@ -1,6 +1,5 @@
from Exporter import Exporter
from settings import *
import utils
#==============================================================================
# EnumExporter
@@ -29,11 +28,3 @@ class EnumExporter(Exporter):
code += in_indent + '.value("%s", %s)\n' % (rename, value_fullname)
code += indent + ';\n\n'
codeunit.Write('module', code)
def Unit(self):
return utils.makeid(self.info.include)
def Order(self):
return self.info.name

View File

@@ -12,10 +12,6 @@ class Exporter:
self.info = info
self.parser_tail = parser_tail
def Name(self):
return self.info.name
def Parse(self, parser):
self.parser = parser
@@ -44,8 +40,11 @@ class Exporter:
pass
def Unit(self):
raise NotImplementedError
def Name(self):
'''Returns the name of this Exporter. The name will be added to the
list of names exported, which may have a use for other exporters.
'''
return None
def GetDeclarations(self, fullname):
@@ -62,11 +61,9 @@ class Exporter:
def Order(self):
'''Returns a string that uniquely identifies this instance. All
exporters will be sorted by Order before being exported.
'''Returns a number that indicates to which order this exporter
belongs. The exporters will be called from the lowest order to the
highest order.
This function will only be called after Parse has been called.
'''
raise NotImplementedError
def Unit(self):
return self.info.include
return None # don't care

View File

@@ -2,31 +2,38 @@ from Exporter import Exporter
from policies import *
from declarations import *
from settings import *
import utils
import exporterutils
#==============================================================================
# FunctionExporter
#==============================================================================
class FunctionExporter(Exporter):
'Generates boost.python code to export the given function.'
def __init__(self, info, tail=None):
Exporter.__init__(self, info, tail)
self._exported_opaque_pointers = {}
def Export(self, codeunit, exported_names):
decls = self.GetDeclarations(self.info.name)
for decl in decls:
self.info.policy = exporterutils.HandlePolicy(decl, self.info.policy)
exporterutils.WarnForwardDeclarations(decl)
self.CheckPolicy(decl)
self.ExportDeclaration(decl, len(decls) == 1, codeunit)
self.ExportOpaquePointer(decl, codeunit)
self.GenerateOverloads(decls, codeunit)
self.GenerateOverloads(decls, codeunit)
def Name(self):
return self.info.name
def CheckPolicy(self, func):
'Warns the user if this function needs a policy'
def IsString(type):
return type.const and type.name == 'char' and isinstance(type, PointerType)
needs_policy = isinstance(func.result, (ReferenceType, PointerType))
if IsString(func.result):
needs_policy = False
if needs_policy and self.info.policy is None:
print '---> Error: Function "%s" needs a policy.' % func.FullName()
print
def ExportDeclaration(self, decl, unique, codeunit):
name = self.info.rename or decl.name
defs = namespaces.python + 'def("%s", ' % name
@@ -76,19 +83,3 @@ class FunctionExporter(Exporter):
else:
return ''
def ExportOpaquePointer(self, function, codeunit):
if self.info.policy == return_value_policy(return_opaque_pointer):
type = function.result.name
macro = 'BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(%s)' % type
if macro not in self._exported_opaque_pointers:
codeunit.Write('declaration-outside', macro)
self._exported_opaque_pointers[macro] = 1
def Order(self):
return self.info.name
def Unit(self):
return utils.makeid(self.info.include)

View File

@@ -105,7 +105,6 @@ class GCCXMLParser(object):
else:
res = Type(decl.FullName(), const)
res.volatile = volatile
res.incomplete = decl.incomplete
return res
@@ -222,7 +221,6 @@ class GCCXMLParser(object):
bases = self.GetBases(element.get('bases'))
location = self.GetLocation(element.get('location'))
context = self.GetDecl(element.get('context'))
incomplete = bool(element.get('incomplete', False))
if isinstance(context, str):
class_ = Class(name, context, [], abstract, bases)
self.AddDecl(class_)
@@ -234,7 +232,6 @@ class GCCXMLParser(object):
# we have to add the declaration of the class before trying
# to parse its members, to avoid recursion.
class_.location = location
class_.incomplete = incomplete
self.Update(id, class_)
# now we can get the members
class_.members = self.GetMembers(element.get('members'))
@@ -261,14 +258,14 @@ class GCCXMLParser(object):
def ParseReferenceType(self, id, element):
type_ = self.GetType(element.get('type'))
expand = not isinstance(type_, FunctionType)
ref = ReferenceType(type_.name, type_.const, None, type_.incomplete, expand)
ref = ReferenceType(type_.name, type_.const, None, expand)
self.Update(id, ref)
def ParsePointerType(self, id, element):
type_ = self.GetType(element.get('type'))
expand = not isinstance(type_, FunctionType)
ref = PointerType(type_.name, type_.const, None, type_.incomplete, expand)
ref = PointerType(type_.name, type_.const, None, expand)
self.Update(id, ref)

View File

@@ -63,12 +63,5 @@ class HeaderExporter(Exporter):
exporter.SetDeclarations(self.declarations)
exporters.exporters.append(exporter)
def Unit(self):
return None # doesn't write anything by himself
def Order(self):
return self.info.include

View File

@@ -17,8 +17,3 @@ class IncludeExporter(Exporter):
def Parse(self, parser):
pass
def Order(self):
return self.info.include
def Unit(self):
return '__all__' # include it in all generated cpps (multiple mode)

View File

@@ -1,104 +0,0 @@
from SingleCodeUnit import SingleCodeUnit
import os
import utils
from SmartFile import SmartFile
#==============================================================================
# MultipleCodeUnit
#==============================================================================
class MultipleCodeUnit(object):
'''
Represents a bunch of cpp files, where each cpp file represents a header
to be exported by pyste. Another cpp, named <module>.cpp is created too.
'''
def __init__(self, modulename, outdir):
self.modulename = modulename
self.outdir = outdir
self.codeunits = {} # maps from a header to a SingleCodeUnit
self.functions = []
self._current = None
def _FunctionName(self, code_unit_name):
return '_Export_%s' % utils.makeid(code_unit_name)
def _FileName(self, code_unit_name):
filename = os.path.basename(code_unit_name)
filename = '_%s.cpp' % os.path.splitext(filename)[0]
return os.path.join(self.outdir, filename)
def SetCurrent(self, code_unit_name):
'Changes the current code unit'
try:
if code_unit_name is not None:
codeunit = self.codeunits[code_unit_name]
else:
codeunit = None
except KeyError:
filename = self._FileName(code_unit_name)
function_name = self._FunctionName(code_unit_name)
codeunit = SingleCodeUnit(None, filename)
codeunit.module_definition = 'void %s()' % function_name
self.codeunits[code_unit_name] = codeunit
if code_unit_name != '__all__':
self.functions.append(function_name)
self._current = codeunit
def Current(self):
return self._current
current = property(Current, SetCurrent)
def Write(self, section, code):
if self._current is not None:
self.current.Write(section, code)
def Section(self, section):
if self._current is not None:
return self.current.Section(section)
def _CreateOutputDir(self):
try:
os.mkdir(self.outdir)
except OSError: pass # already created
def Save(self):
# create the directory where all the files will go
self._CreateOutputDir();
# write all the codeunits, merging first the contents of
# the special code unit named __all__
__all__ = self.codeunits.get('__all__')
for name, codeunit in self.codeunits.items():
if name != '__all__':
if __all__:
codeunit.Merge(__all__)
codeunit.Save()
# generate the main cpp
filename = os.path.join(self.outdir, self.modulename + '.cpp')
fout = SmartFile(filename, 'w')
fout.write(utils.left_equals('Include'))
fout.write('#include <boost/python.hpp>\n\n')
fout.write(utils.left_equals('Exports'))
for function in self.functions:
fout.write('void %s();\n' % function)
fout.write('\n')
fout.write(utils.left_equals('Module'))
fout.write('BOOST_PYTHON_MODULE(%s)\n' % self.modulename)
fout.write('{\n')
indent = ' ' * 4
for function in self.functions:
fout.write(indent)
fout.write('%s();\n' % function)
fout.write('}\n')

View File

@@ -1,84 +0,0 @@
from settings import namespaces
import settings
from utils import remove_duplicated_lines, left_equals
from SmartFile import SmartFile
#==============================================================================
# SingleCodeUnit
#==============================================================================
class SingleCodeUnit:
'''
Represents a cpp file, where other objects can write in one of the
predefined sections.
The avaiable sections are:
include - The include area of the cpp file
declaration - The part before the module definition
module - Inside the BOOST_PYTHON_MODULE macro
'''
def __init__(self, modulename, filename):
self.modulename = modulename
self.filename = filename
# define the avaiable sections
self.code = {}
# include section
self.code['include'] = ''
# declaration section (inside namespace)
self.code['declaration'] = ''
# declaration (outside namespace)
self.code['declaration-outside'] = ''
# inside BOOST_PYTHON_MACRO
self.code['module'] = ''
# create the default module definition
self.module_definition = 'BOOST_PYTHON_MODULE(%s)' % modulename
def Write(self, section, code):
'write the given code in the section of the code unit'
if section not in self.code:
raise RuntimeError, 'Invalid CodeUnit section: %s' % section
self.code[section] += code
def Merge(self, other):
for section in ('include', 'declaration', 'declaration-outside', 'module'):
self.code[section] = self.code[section] + other.code[section]
def Section(self, section):
return self.code[section]
def Save(self):
'Writes this code unit to the filename'
space = '\n\n'
fout = SmartFile(self.filename, 'w')
# includes
includes = remove_duplicated_lines(self.code['include'])
fout.write('\n' + left_equals('Includes'))
fout.write('#include <boost/python.hpp>\n')
fout.write(includes)
fout.write(space)
# using
if settings.USING_BOOST_NS:
fout.write(left_equals('Using'))
fout.write('using namespace boost::python;\n\n')
# declarations
declaration = self.code['declaration']
declaration_outside = self.code['declaration-outside']
if declaration_outside or declaration:
fout.write(left_equals('Declarations'))
fout.write(declaration_outside + '\n\n')
if declaration:
pyste_namespace = namespaces.pyste[:-2]
fout.write('namespace %s {\n\n\n' % pyste_namespace)
fout.write(declaration)
fout.write('\n\n}// namespace %s\n' % pyste_namespace)
fout.write(space)
# module
fout.write(left_equals('Module'))
fout.write(self.module_definition + '\n')
fout.write('{\n')
fout.write(self.code['module'])
fout.write('}\n')

View File

@@ -1,55 +0,0 @@
import os
import md5
#==============================================================================
# SmartFile
#==============================================================================
class SmartFile(object):
'''
A file-like object used for writing files. The given file will only be
actually written to disk if there's not a file with the same name, or if
the existing file is *different* from the file to be written.
'''
def __init__(self, filename, mode='w'):
self.filename = filename
self.mode = mode
self._contents = []
self._closed = False
def __del__(self):
if not self._closed:
self.close()
def write(self, string):
self._contents.append(string)
def _dowrite(self, contents):
f = file(self.filename, self.mode)
f.write(contents)
f.close()
def _GetMD5(self, string):
return md5.new(string).digest()
def close(self):
# if the filename doesn't exist, write the file right away
this_contents = ''.join(self._contents)
if not os.path.isfile(self.filename):
self._dowrite(this_contents)
else:
# read the contents of the file already in disk
f = file(self.filename)
other_contents = f.read()
f.close()
# test the md5 for both files
this_md5 = self._GetMD5(this_contents)
other_md5 = self._GetMD5(other_contents)
if this_md5 != other_md5:
self._dowrite(this_contents)
self._closed = True

View File

@@ -15,9 +15,6 @@ class Declaration(object):
self.namespace = namespace
# tuple (filename, line)
self.location = '', -1
# if a declaration is incomplete it means that it was
# forward declared
self.incomplete = False
def FullName(self):
@@ -209,18 +206,13 @@ class Method(Function):
def PointerDeclaration(self):
'returns a declaration of a pointer to this function'
if self.static:
# static methods are like normal functions
return Function.PointerDeclaration(self)
else:
# using syntax of methods
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
const = ''
if self.const:
const = 'const'
return '(%s (%s::*)(%s) %s)&%s' %\
(result, self.class_, params, const, self.FullName())
result = self.result.FullName()
params = ', '.join([x.FullName() for x in self.parameters])
const = ''
if self.const:
const = 'const'
return '(%s (%s::*)(%s) %s)&%s' %\
(result, self.class_, params, const, self.FullName())
class Constructor(Method):
@@ -266,21 +258,20 @@ class ConverterOperator(ClassOperator):
'An operator in the form "operator OtherClass()".'
def FullName(self):
return self.class_ + '::operator ' + self.result.FullName()
return self.class_ + '::operator ' + self.result.name
class Type(Declaration):
'Represents a type.'
def __init__(self, name, const=False, default=None, incomplete=False):
def __init__(self, name, const=False, default=None):
Declaration.__init__(self, name, None)
# whatever the type is constant or not
self.const = const
# used when the Type is a function argument
self.default = default
self.volatile = False
self.incomplete = incomplete
def __repr__(self):
if self.const:
@@ -313,8 +304,8 @@ class ArrayType(Type):
class ReferenceType(Type):
'A reference type.'
def __init__(self, name, const=False, default=None, incomplete=False, expandRef=True):
Type.__init__(self, name, const, default, incomplete)
def __init__(self, name, const=False, default=None, expandRef=True):
Type.__init__(self, name, const, default)
self.expand = expandRef
@@ -330,8 +321,8 @@ class ReferenceType(Type):
class PointerType(Type):
'A pointer type.'
def __init__(self, name, const=False, default=None, incomplete=False, expandPointer=False):
Type.__init__(self, name, const, default, incomplete)
def __init__(self, name, const=False, default=None, expandPointer=False):
Type.__init__(self, name, const, default)
self.expand = expandPointer

7
pyste/src/enumerate.py Normal file
View File

@@ -0,0 +1,7 @@
from __future__ import generators
def enumerate(seq):
i = 0
for x in seq:
yield i, x
i += 1

View File

@@ -3,8 +3,6 @@ Various helpers for interface files.
'''
from settings import *
from policies import *
from declarations import *
#==============================================================================
# FunctionWrapper
@@ -26,66 +24,3 @@ class FunctionWrapper(object):
return namespaces.pyste + self.name
else:
return self.name
_printed_warnings = {} # used to avoid double-prints of warnings
#==============================================================================
# HandlePolicy
#==============================================================================
def HandlePolicy(function, policy):
'''Show a warning to the user if the function needs a policy and doesn't
have one. Return a policy to the function, which is the given policy itself
if it is not None, or a default policy for this method.
'''
def IsString(type):
'Return True if the Type instance can be considered a string'
return type.const and type.name == 'char' and isinstance(type, PointerType)
def IsPyObject(type):
return type.FullName() == '_object *' # internal name of PyObject
result = function.result
# basic test if the result type demands a policy
needs_policy = isinstance(result, (ReferenceType, PointerType))
# if the function returns const char*, a policy is not needed
if IsString(result) or IsPyObject(result):
needs_policy = False
# if returns a const T&, set the default policy
if policy is None and result.const and isinstance(result, ReferenceType):
policy = return_value_policy(copy_const_reference)
# show a warning to the user, if needed
if needs_policy and policy is None:
global _printed_warnings
warning = '---> Error: %s returns a pointer or a reference, ' \
'but no policy was specified.' % function.FullName()
if warning not in _printed_warnings:
print warning
print
# avoid double prints of the same warning
_printed_warnings[warning] = 1
return policy
#==============================================================================
# WarnForwardDeclarations
#==============================================================================
def WarnForwardDeclarations(function):
'''Checks if any of the parameters or the result of the function are
incomplete types.'''
types = [function.result] + function.parameters
types = [x for x in types if x]
for type in types:
if type.incomplete:
msg = '---> Error: %s is forward declared. Please include the ' \
'appropriate header with its definition' % type.name
# disable this for now... it was reporting too many false
# forward declarations to be useful
if 0 and msg not in _printed_warnings:
print msg
print
_printed_warnings[msg] = 1

View File

@@ -7,7 +7,6 @@ from IncludeExporter import IncludeExporter
from EnumExporter import EnumExporter
from HeaderExporter import HeaderExporter
from exporterutils import FunctionWrapper
from utils import makeid
#==============================================================================
@@ -91,7 +90,7 @@ class IncludeInfo(DeclarationInfo):
def GenerateName(name, type_list):
name = name.replace('::', '_')
names = [name] + type_list
return makeid('_'.join(names))
return '_'.join(names)
class ClassTemplateInfo(DeclarationInfo):
@@ -185,11 +184,4 @@ def instantiate(template, types, rename=None):
if isinstance(types, str):
types = types.split()
return template.Instantiate(types, rename)
def use_shared_ptr(option):
option._Attribute('smart_ptr', 'boost::shared_ptr< %s >')
def use_auto_ptr(option):
option._Attribute('smart_ptr', 'std::auto_ptr< %s >')

View File

@@ -19,13 +19,6 @@ class Policy:
return ' >'
def __eq__(self, other):
try:
return self.Code() == other.Code()
except AttributeError:
return False
class return_internal_reference(Policy):
'Ties the return value to one of the parameters.'
@@ -80,4 +73,3 @@ reference_existing_object = 'reference_existing_object'
copy_const_reference = 'copy_const_reference'
copy_non_const_reference = 'copy_non_const_reference'
manage_new_object = 'manage_new_object'
return_opaque_pointer = 'return_opaque_pointer'

View File

@@ -1,52 +1,33 @@
'''
Pyste version %s
Usage:
pyste [options] --module=<name> interface-files
where options are:
-I <path> add an include path
-D <symbol> define symbol
--multiple create various cpps, instead of only one
(useful during development)
--out specify output filename (default: <module>.cpp)
in --multiple mode, this will be a directory
-I <path> add an include path
-D <symbol> define symbol
--no-using do not declare "using namespace boost";
use explicit declarations instead
--pyste-ns=<name> set the namespace where new types will be declared;
default is the empty namespace
--debug writes the xml for each file parsed in the current
directory
-h, --help print this help and exit
-v, --version print version information
default is "pyste"
'''
import sys
import os
import getopt
import exporters
import SingleCodeUnit
import MultipleCodeUnit
import CodeUnit
import infos
import exporterutils
import settings
from policies import *
from CppParser import CppParser, CppParserError
import time
from Exporter import Exporter
from FunctionExporter import FunctionExporter
from ClassExporter import ClassExporter
from IncludeExporter import IncludeExporter
from HeaderExporter import HeaderExporter
__VERSION__ = '0.7.3'
def RecursiveIncludes(include):
'Return a list containg the include dir and all its subdirectories'
dirs = [include]
def visit(arg, dir, names):
# ignore CVS dirs
if os.path.split(dir)[1] != 'CVS':
dirs.append(dir)
os.path.walk(include, visit, None)
return dirs
def GetDefaultIncludes():
if 'INCLUDE' in os.environ:
include = os.environ['INCLUDE']
@@ -58,59 +39,39 @@ def GetDefaultIncludes():
def ParseArguments():
def Usage():
print __doc__ % __VERSION__
print __doc__
sys.exit(1)
try:
options, files = getopt.getopt(
sys.argv[1:],
'R:I:D:vh',
['module=', 'multiple', 'out=', 'no-using', 'pyste-ns=', 'debug', 'version', 'help'])
except getopt.GetoptError, e:
print
print 'ERROR:', e
Usage()
options, files = getopt.getopt(sys.argv[1:], 'I:D:', ['module=', 'out=', 'no-using', 'pyste-ns=', 'debug'])
includes = GetDefaultIncludes()
defines = []
module = None
out = None
multiple = False
for opt, value in options:
if opt == '-I':
includes.append(value)
elif opt == '-D':
defines.append(value)
elif opt == '-R':
includes.extend(RecursiveIncludes(value))
elif opt == '--module':
module = value
elif opt == '--out':
out = value
elif opt == '--no-using':
settings.namespaces.python = 'boost::python::'
settings.USING_BOOST_NS = False
CodeUnit.CodeUnit.USING_BOOST_NS = False
elif opt == '--pyste-ns':
settings.namespaces.pyste = value + '::'
elif opt == '--debug':
settings.DEBUG = True
elif opt == '--multiple':
multiple = True
elif opt in ['-h', '--help']:
Usage()
elif opt in ['-v', '--version']:
print 'Pyste version %s' % __VERSION__
sys.exit(2)
else:
print 'Unknown option:', opt
Usage()
if not files or not module:
Usage()
Usage()
if not out:
out = module
if not multiple:
out += '.cpp'
return includes, defines, module, out, files, multiple
out = module + '.cpp'
return includes, defines, module, out, files
def CreateContext():
@@ -128,8 +89,6 @@ def CreateContext():
context['set_policy'] = infos.set_policy
context['exclude'] = infos.exclude
context['set_wrapper'] = infos.set_wrapper
context['use_shared_ptr'] = infos.use_shared_ptr
context['use_auto_ptr'] = infos.use_auto_ptr
# policies
context['return_internal_reference'] = return_internal_reference
context['with_custodian_and_ward'] = with_custodian_and_ward
@@ -137,7 +96,6 @@ def CreateContext():
context['reference_existing_object'] = reference_existing_object
context['copy_const_reference'] = copy_const_reference
context['copy_non_const_reference'] = copy_non_const_reference
context['return_opaque_pointer'] = return_opaque_pointer
context['manage_new_object'] = manage_new_object
# utils
context['Wrapper'] = exporterutils.FunctionWrapper
@@ -145,7 +103,7 @@ def CreateContext():
def Main():
includes, defines, module, out, interfaces, multiple = ParseArguments()
includes, defines, module, out, interfaces = ParseArguments()
# execute the interface files
for interface in interfaces:
context = CreateContext()
@@ -166,32 +124,31 @@ def Main():
exports.sort()
exports = [x for _, x in exports]
# now generate the wrapper code
if multiple:
codeunit = MultipleCodeUnit.MultipleCodeUnit(module, out)
else:
codeunit = SingleCodeUnit.SingleCodeUnit(module, out)
codeunit = CodeUnit.CodeUnit(module)
exported_names = []
for export in exports:
if multiple:
codeunit.SetCurrent(export.Unit())
export.GenerateCode(codeunit, exported_names)
exported_names.append(export.Name())
codeunit.Save()
codeunit.Save(out)
print 'Module %s generated' % module
return 0
def UsePsyco():
'Tries to use psyco if possible'
'Tries to use psyco if it is installed'
try:
import psyco
psyco.profile()
except: pass
import elementtree.XMLTreeBuilder as XMLTreeBuilder
import GCCXMLParser
psyco.bind(XMLTreeBuilder.fixtext)
psyco.bind(XMLTreeBuilder.fixname)
psyco.bind(XMLTreeBuilder.TreeBuilder)
psyco.bind(GCCXMLParser.GCCXMLParser)
except ImportError: pass
if __name__ == '__main__':
start = time.clock()
UsePsyco()
status = Main()
print '%0.2f seconds' % (time.clock()-start)
sys.exit(status)

View File

@@ -4,7 +4,6 @@
#==============================================================================
DEBUG = False
USING_BOOST_NS = True
class namespaces:
boost = 'boost::'

View File

@@ -1,47 +0,0 @@
from __future__ import generators
import string
#==============================================================================
# enumerate
#==============================================================================
def enumerate(seq):
i = 0
for x in seq:
yield i, x
i += 1
#==============================================================================
# makeid
#==============================================================================
_valid_chars = string.ascii_letters + string.digits + '_'
_valid_chars = dict(zip(_valid_chars, _valid_chars))
def makeid(name):
'Returns the name as a valid identifier'
newname = []
for char in name:
if char not in _valid_chars:
char = '_'
newname.append(char)
newname = ''.join(newname)
# avoid duplications of '_' chars
names = [x for x in newname.split('_') if x]
return '_'.join(names)
#==============================================================================
# remove_duplicated_lines
#==============================================================================
def remove_duplicated_lines(text):
includes = text.splitlines()
d = dict([(include, 0) for include in includes])
return '\n'.join(d.keys())
#==============================================================================
# left_equals
#==============================================================================
def left_equals(s):
s = '// %s ' % s
return s + ('='*(80-len(s))) + '\n'

View File

@@ -1,8 +1,3 @@
*.pyc
*.exp
*.lib
*.obj
*.arg
*.dll
*.cpp
.sconsign

View File

@@ -1,59 +0,0 @@
import glob
import sys
import os
# constants
if sys.platform == 'win32':
BOOST_ROOT = 'D:/Programming/Libraries/boost-cvs'
STLPORT_ROOT = 'D:/Programming/Libraries/stlport-4.5.3'
PYTHON_ROOT = 'C:/Python'
if BOOST_ROOT:
BOOST_INCLUDE = BOOST_ROOT + '/boost'
BOOST_LIB = BOOST_ROOT + '/lib'
if STLPORT_ROOT:
STLPORT_INCLUDE = STLPORT_ROOT + '/stlport'
STLPORT_LIB = STLPORT_ROOT + '/lib'
if PYTHON_ROOT:
PYTHON_INCLUDE = PYTHON_ROOT + '/include'
PYTHON_LIB = PYTHON_ROOT + '/libs'
LIBS = ['boost_python', 'python22']
INCLUDES = ['../example']
if sys.platform == 'win32':
CXX = 'icl'
CXXFLAGS='/GR /GX /MD /nologo'
INCLUDES += [BOOST_INCLUDE, STLPORT_INCLUDE, PYTHON_INCLUDE]
LIBPATH = [STLPORT_LIB, PYTHON_LIB, BOOST_LIB]
else:
CXX = 'g++'
CXXFLAGS = ''
LIBPATH = []
#INCLUDES = ['..']
# Create the environment
env = Environment(
CXX=CXX,
CXXFLAGS=CXXFLAGS,
CPPPATH=INCLUDES,
LIBS=LIBS,
LIBPATH=LIBPATH)
# Build all the cpp files
modules = [os.path.splitext(os.path.basename(x))[0] for x in glob.glob('../example/*.pyste')]
for module in modules:
multiple = ARGUMENTS.get('multiple', '')
example_cpp = '../example/%s.cpp' % module
if os.path.isfile(example_cpp):
sources = [example_cpp]
else:
sources = []
if multiple:
env.SharedLibrary(target=module, source=sources + glob.glob('_%s/*.cpp'%module))
else:
env.SharedLibrary(target=module, source=sources + ['_%s.cpp' % module])

View File

@@ -1,80 +0,0 @@
import sys
sys.path.append('../src')
from SmartFile import *
import unittest
import tempfile
import os
import time
class SmartFileTest(unittest.TestCase):
FILENAME = tempfile.mktemp()
def setUp(self):
self._Clean()
def tearDown(self):
self._Clean()
def _Clean(self):
try:
os.remove(self.FILENAME)
except OSError: pass
def testNonExistant(self):
"Must override the file, as there's no file in the disk yet"
self.assert_(not os.path.isfile(self.FILENAME))
f = SmartFile(self.FILENAME, 'w')
f.write('Testing 123\nTesting again.')
f.close()
self.assert_(os.path.isfile(self.FILENAME))
def testOverride(self):
"Must override the file, because the contents are different"
contents = 'Contents!\nContents!'
# create the file normally first
f = file(self.FILENAME, 'w')
f.write(contents)
f.close()
file_time = os.path.getmtime(self.FILENAME)
self.assert_(os.path.isfile(self.FILENAME))
time.sleep(2)
f = SmartFile(self.FILENAME, 'w')
f.write(contents + '_')
f.close()
new_file_time = os.path.getmtime(self.FILENAME)
self.assert_(new_file_time != file_time)
def testNoOverride(self):
"Must not override the file, because the contents are the same"
contents = 'Contents!\nContents!'
# create the file normally first
f = file(self.FILENAME, 'w')
f.write(contents)
f.close()
file_time = os.path.getmtime(self.FILENAME)
self.assert_(os.path.isfile(self.FILENAME))
time.sleep(2)
f = SmartFile(self.FILENAME, 'w')
f.write(contents)
f.close()
new_file_time = os.path.getmtime(self.FILENAME)
self.assert_(new_file_time == file_time)
def testAutoClose(self):
"Must be closed when garbage-collected"
def foo():
f = SmartFile(self.FILENAME)
f.write('testing')
self.assert_(not os.path.isfile(self.FILENAME))
foo()
self.assert_(os.path.isfile(self.FILENAME))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,19 @@
@echo off
setlocal
set MODULE_NAME=%1
set PYSTE_FILE=%2
set BOOST_ROOT=d:/programming/libraries/boost-cvs
set PYTHON_ROOT=c:/python
set STLPORT_ROOT=d:/programming/libraries/stlport-4.5.3
set PYSTE_FILE_DIR=%@PATH[%PYSTE_FILE]
python ../src/pyste.py -I%PYSTE_FILE_DIR --out=%MODULE_NAME.cpp --module=%MODULE_NAME %PYSTE_FILE
icl /nologo /LD /GR /GX -I%PYSTE_FILE_DIR -I%STLPORT_ROOT/stlport -I%BOOST_ROOT/boost -I%PYTHON_ROOT/include %MODULE_NAME.cpp /link /libpath:%PYTHON_ROOT/libs /libpath:%BOOST_ROOT/lib /libpath:%STLPORT_ROOT/lib boost_python.lib
rm %MODULE_NAME.cpp
rm %MODULE_NAME.exp
rm %MODULE_NAME.lib
rm %MODULE_NAME.obj
endlocal

View File

@@ -1,11 +1,11 @@
import unittest
from basic import *
import os
class BasicExampleTest(unittest.TestCase):
def testIt(self):
from basic import C, call_f
# test virtual functions
class D(C):
def f(self, x=10):
return x+1
@@ -21,45 +21,6 @@ class BasicExampleTest(unittest.TestCase):
self.assertEqual(call_f(c, 4), 8)
self.assertEqual(call_f(d), 11)
self.assertEqual(call_f(d, 3), 4)
# test data members
def testValue(value):
self.assertEqual(c.value, value)
self.assertEqual(d.value, value)
self.assertEqual(get_value(c), value)
self.assertEqual(get_value(d), value)
testValue(1)
c.value = 30
d.value = 30
testValue(30)
self.assertEqual(c.const_value, 0)
self.assertEqual(d.const_value, 0)
def set_const_value():
c.const_value = 12
self.assertRaises(AttributeError, set_const_value)
# test static data-members
def testStatic(value):
self.assertEqual(C.static_value, value)
self.assertEqual(c.static_value, value)
self.assertEqual(D.static_value, value)
self.assertEqual(d.static_value, value)
self.assertEqual(get_static(), value)
testStatic(3)
C.static_value = 10
testStatic(10)
self.assertEqual(C.const_static_value, 100)
def set_const_static():
C.const_static_value = 1
self.assertRaises(AttributeError, set_const_static)
# test static function
def test_mul(result, *args):
self.assertEqual(C.mul(*args), result)
self.assertEqual(c.mul(*args), result)
test_mul(6)
test_mul(3, 1)
test_mul(16, 8, 2)
if __name__ == '__main__':

View File

@@ -1,20 +0,0 @@
import unittest
from inherit import *
class InheritExampleTest(unittest.TestCase):
def testIt(self):
a = A_int()
b = B()
self.assert_(isinstance(b, A_int))
self.assert_(issubclass(B, A_int))
a.set(10)
self.assertEqual(a.get(), 10)
b.set(1)
self.assertEqual(b.go(), 1)
self.assertEqual(b.get(), 1)
if __name__ == '__main__':
unittest.main()

View File

@@ -1,18 +0,0 @@
import unittest
from opaque import *
class OpaqueTest(unittest.TestCase):
def testIt(self):
c = new_C()
self.assertEqual(get(c), 10)
a = A()
d = a.new_handle()
self.assertEqual(a.get(d), 3.0)
self.assertEqual(a.f(), 0)
self.assertEqual(a.f(3), 3)
if __name__ == '__main__':
unittest.main()

View File

@@ -19,7 +19,6 @@ class OperatorTest(unittest.TestCase):
self.assertEqual(d(), 10)
self.assertEqual(c(3.0), 13.0)
self.assertEqual(d(6.0), 16.0)
self.assertEqual(str(c), "C")
if __name__ == '__main__':

View File

@@ -1,16 +0,0 @@
import unittest
from smart_ptr import *
class BasicExampleTest(unittest.TestCase):
def testIt(self):
c = NewC()
d = NewD()
c.value = 3
d.Set(c)
c1 = d.Get()
c1.value = 6
self.assertEqual(c.value, 6)
if __name__ == '__main__':
unittest.main()

View File

@@ -6,19 +6,19 @@ class TemplatesTest(unittest.TestCase):
def testIt(self):
fp = FPoint()
fp.i = 3.0
fp.j = 4.0
fp.j = 4
ip = IPoint()
ip.x = 10
ip.y = 3
ip.y = 3.0
self.assertEqual(fp.i, 3.0)
self.assertEqual(fp.j, 4.0)
self.assertEqual(fp.j, 4)
self.assertEqual(ip.x, 10)
self.assertEqual(ip.y, 3)
self.assertEqual(ip.y, 3.0)
self.assertEqual(type(fp.i), float)
self.assertEqual(type(fp.j), float)
self.assertEqual(type(fp.j), int)
self.assertEqual(type(ip.x), int)
self.assertEqual(type(ip.y), int)
self.assertEqual(type(ip.y), float)

View File

@@ -1,28 +0,0 @@
import unittest
from virtual2 import *
class Virtual2Test(unittest.TestCase):
def testIt(self):
a = A()
self.assertEqual(a.f1(), 10)
b = B()
self.assertEqual(b.f1(), 10)
self.assertEqual(b.f2(), 20)
self.assertEqual(call_fs(b), 30)
self.assertEqual(call_f(a), 0)
self.assertEqual(call_f(b), 1)
class C(B):
def f1(self): return 1
def f2(self): return 2
def f(self): return 100
c = C()
self.assertEqual(call_fs(c), 3)
self.assertEqual(call_fs(c), 3)
self.assertEqual(call_f(c), 100)
if __name__ == '__main__':
unittest.main()

View File

@@ -7,14 +7,5 @@ class WrapperTest(unittest.TestCase):
self.assertEqual(Range(10), range(10))
self.assertEqual(C().Mul(10), [x*10 for x in range(10)])
a = A()
self.assertEqual(a.f(), 10)
self.assertEqual(call_foo(a), 10)
class D(A):
def f(self): return 2
d = D()
self.assertEqual(d.f(), 2)
self.assertEqual(call_foo(d), 2)
if __name__ == '__main__':
unittest.main()

Some files were not shown because too many files have changed in this diff Show More