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:
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -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 |
@@ -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>"foo"</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>"foo"</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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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><> </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>"__main__"</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><>(</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><>(</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><>( </span><span class=identifier>PyRun_String</span><span class=special>(</span><span class=string>"result = 5 ** 2"</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><</span><span class=keyword>int</span><span class=special>>( </span><span class=identifier>main_namespace</span><span class=special>[</span><span class=string>"result"</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
|
||||
|
||||
@@ -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> ("Pie-Steh")
|
||||
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
|
||||
|
||||
@@ -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<void (string s) > funcptr;
|
||||
|
||||
void foo(funcptr fp)
|
||||
{
|
||||
fp("hello,world!");
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(test)
|
||||
{
|
||||
def("foo",foo) ;
|
||||
}
|
||||
</pre>
|
||||
|
||||
And then:
|
||||
|
||||
<pre>
|
||||
>>> def hello(s):
|
||||
... print s
|
||||
...
|
||||
>>> foo(hello)
|
||||
hello, world!
|
||||
</pre>
|
||||
|
||||
The short answer is: "you can't". 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& b, std::auto_ptr<A> 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>
|
||||
|
||||
|
||||
@@ -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 - <boost/python/opaque_pointer_converter.hpp></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
|
||||
<boost/python/opaque_pointer_converter.hpp></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<P></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<P></code></h3>
|
||||
|
||||
<p><code>opaque_pointer_converter<></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<class Pointer>
|
||||
struct opaque_pointer_converter
|
||||
: to_python_converter<
|
||||
Pointer, opaque_pointer_converter<Pointer> >
|
||||
{
|
||||
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>© Copyright 2003 Haufe Mediengruppe. All Rights
|
||||
Reserved.</i></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -194,10 +194,9 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 1, 3)
|
||||
|
||||
BOOST_PYTHON_MODULE(args_ext)
|
||||
{
|
||||
def("f", f,
|
||||
f_overloads(
|
||||
args("x", "y", "z"), "This is f's docstring"
|
||||
));
|
||||
def("f", f, args("x", "y", "z")
|
||||
, "This is f's docstring"
|
||||
);
|
||||
|
||||
|
||||
class_<Y>("Y")
|
||||
@@ -205,17 +204,16 @@ BOOST_PYTHON_MODULE(args_ext)
|
||||
|
||||
class_<X>("X", "This is X's docstring")
|
||||
.def("f1", &X::f,
|
||||
X_f_overloads(
|
||||
args("x", "y", "z"), "f's docstring"
|
||||
)[return_internal_reference<>()]
|
||||
)
|
||||
X_f_overloads(args("x", "y", "z"),
|
||||
"f's docstring"
|
||||
)[return_internal_reference<>()])
|
||||
;
|
||||
}
|
||||
</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>
|
||||
|
||||
|
||||
@@ -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 - <boost/python/raw_function.hpp></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 <boost/python/raw_function.hpp></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 <class F>
|
||||
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 <boost/python/def.hpp>
|
||||
#include <boost/python/tuple.hpp>
|
||||
#include <boost/python/dict.hpp>
|
||||
#include <boost/python/module.hpp>
|
||||
#include <boost/python/raw_function.hpp>
|
||||
|
||||
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>
|
||||
>>> from raw_test import *
|
||||
|
||||
>>> 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>© Copyright <a href=
|
||||
"../../../../people/dave_abrahams.htm">Dave Abrahams</a> 2002. All Rights
|
||||
Reserved.</i></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 - <boost/python/return_opaque_pointer.hpp></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
|
||||
<boost/python/return_opaque_pointer.hpp></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 <class R> struct apply;
|
||||
};
|
||||
}}
|
||||
</pre>
|
||||
|
||||
<h4><a name="return_opaque_pointer-spec-metafunctions"></a>Class
|
||||
<code>return_opaque_pointer</code> metafunctions</h4>
|
||||
<pre>
|
||||
template <class R> struct apply
|
||||
</pre>
|
||||
|
||||
<dl class="metafunction-semantics">
|
||||
<dt><b>Returns:</b> <code>typedef
|
||||
detail::opaque_conversion_holder<R>
|
||||
type;</code></dt>
|
||||
</dl>
|
||||
|
||||
<h2><a name="examples"></a>Example</h2>
|
||||
|
||||
<h3>C++ Module Definition</h3>
|
||||
<pre>
|
||||
# include <boost/python/return_opaque_pointer.hpp>
|
||||
# include <boost/python/def.hpp>
|
||||
# include <boost/python/module.hpp>
|
||||
# include <boost/python/return_value_policy.hpp>
|
||||
|
||||
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<bpl::return_opaque_pointer>());
|
||||
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>© Copyright 2003 Haufe Mediengruppe. All Rights
|
||||
Reserved.</i></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
35
pyste/NEWS
35
pyste/NEWS
@@ -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.
|
||||
2
pyste/dist/.cvsignore
vendored
2
pyste/dist/.cvsignore
vendored
@@ -1,2 +0,0 @@
|
||||
*.zip
|
||||
*.pyc
|
||||
51
pyste/dist/create_build.py
vendored
51
pyste/dist/create_build.py
vendored
@@ -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
6
pyste/dist/setup.py
vendored
@@ -1,6 +0,0 @@
|
||||
from distutils.core import setup
|
||||
import py2exe
|
||||
import sys
|
||||
|
||||
sys.path.append('../src')
|
||||
setup(name='pyste', scripts=['../src/pyste.py'])
|
||||
@@ -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>
|
||||
|
||||
@@ -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 "<tt>hello.cpp</tt>" 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 "free" 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 "free" 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>
|
||||
|
||||
@@ -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&</tt>, the policy
|
||||
<tt>return_value_policy<copy_const_reference>()</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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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>'<<'</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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
>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"
|
||||
|
||||
</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><module>.cpp</tt>), or in multiple mode,
|
||||
names a output directory for the files (default: <tt><module></tt>).</p>
|
||||
<p>
|
||||
<tt>--no-using</tt> tells Pyste to don't declare "<tt>using namespace boost;</tt>" in the
|
||||
<tt>--no-using</tt> tells pyste to don't declare "<tt>using namespace boost;</tt>" 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 "pyste" and this is causing conflicts.</p>
|
||||
<p>
|
||||
So, the usage is simple enough:</p>
|
||||
<code><pre>>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>>python pyste.py --module=mymodule --multiple file.pyste file2.pyste ...</pre></code><p>
|
||||
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).</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>
|
||||
|
||||
@@ -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><</span><span class=identifier>C</span><span class=special>> </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><</span><span class=identifier>C</span><span class=special>> </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>-></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><</span><span class=identifier>C</span><span class=special>> </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><< </span><span class=identifier>c</span><span class=special>-></span><span class=identifier>value </span><span class=special><< </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<C></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 © 2003 Bruno da Silva de Oliveira<br>Copyright © 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 "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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 "Template"
|
||||
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>"DPoint"</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
|
||||
("int double" or ["int", "double"] would both work).
|
||||
</td>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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><</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string</span><span class=special>> </span><span class=identifier>names</span><span class=special>();
|
||||
</span></pre></code>
|
||||
<p>
|
||||
But you don't want to export <tt>std::vector<std::string></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<string>, 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><</span><span class=identifier>string</span><span class=special>> </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><</span><span class=identifier>string</span><span class=special>>::</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 "<tt>test_wrappers.h</tt>" 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 "<tt>test_wrappers.h</tt>", and in the interface file:</p>
|
||||
<code><pre>
|
||||
<span class=identifier>Include</span><span class=special>(</span><span class=string>"test_wrappers.h"</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>"names"</span><span class=special>, </span><span class=string>"test.h"</span><span class=special>)
|
||||
@@ -68,14 +63,14 @@ You can optionally declare the function in the interface file itself:</p>
|
||||
</span><span class=string>""</span><span class=string>"
|
||||
list names_wrapper()
|
||||
{
|
||||
// code to call name() and convert the vector to a list...
|
||||
// call name() and convert the vector to a list...
|
||||
}
|
||||
"</span><span class=string>""</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>"names"</span><span class=special>, </span><span class=string>"test.h"</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>-></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>-></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>"C"</span><span class=special>, </span><span class=string>"test.h"</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>"names_wrapper"</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>
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
.sconsign
|
||||
*.obj
|
||||
*.cpp
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "basic.h"
|
||||
|
||||
namespace basic {
|
||||
|
||||
int C::static_value = 3;
|
||||
const int C::const_static_value = 100;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#ifndef ENUMS_H
|
||||
#define ENUMS_H
|
||||
|
||||
namespace enums {
|
||||
|
||||
enum color { red, blue };
|
||||
@@ -20,5 +17,3 @@ struct X
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(); }
|
||||
};
|
||||
@@ -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')
|
||||
@@ -1,4 +0,0 @@
|
||||
#include "nested.h"
|
||||
|
||||
int nested::X::staticXValue = 10;
|
||||
int nested::X::Y::staticYValue = 20;
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
47
pyste/example/operator.h
Normal 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;
|
||||
}
|
||||
|
||||
12
pyste/example/operator.pyste
Normal file
12
pyste/example/operator.pyste
Normal 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)
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "operators.h"
|
||||
|
||||
double operators::C::x = 10;
|
||||
@@ -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
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
C = Class('operators::C', 'operators.h')
|
||||
#exclude(C.operator['+'])
|
||||
Class('operators::C', 'operators.h')
|
||||
|
||||
@@ -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
|
||||
@@ -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')
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace templates {
|
||||
|
||||
template <class T>
|
||||
template <class X, class Y>
|
||||
struct Point
|
||||
{
|
||||
T x;
|
||||
T y;
|
||||
X x;
|
||||
Y y;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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')
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
|
||||
@@ -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
78
pyste/src/CodeUnit.py
Normal 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'
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
@@ -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
|
||||
@@ -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
7
pyste/src/enumerate.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from __future__ import generators
|
||||
|
||||
def enumerate(seq):
|
||||
i = 0
|
||||
for x in seq:
|
||||
yield i, x
|
||||
i += 1
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 >')
|
||||
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#==============================================================================
|
||||
|
||||
DEBUG = False
|
||||
USING_BOOST_NS = True
|
||||
|
||||
class namespaces:
|
||||
boost = 'boost::'
|
||||
|
||||
@@ -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'
|
||||
@@ -1,8 +1,3 @@
|
||||
*.pyc
|
||||
*.exp
|
||||
*.lib
|
||||
*.obj
|
||||
*.arg
|
||||
*.dll
|
||||
*.cpp
|
||||
.sconsign
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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()
|
||||
19
pyste/tests/build_pyste_nt.bat
Normal file
19
pyste/tests/build_pyste_nt.bat
Normal 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
|
||||
@@ -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__':
|
||||
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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__':
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
@@ -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
Reference in New Issue
Block a user