2
0
mirror of https://github.com/boostorg/python.git synced 2026-02-22 15:42:16 +00:00

This commit was manufactured by cvs2svn to create tag

'merged_to_RC_1_30_0'.

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

View File

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

View File

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

View File

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

6
pyste/dist/setup.py vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +0,0 @@
@echo off
call nt_build_all.bat
runtests.py
call nt_clean.bat
call nt_build_all.bat --multiple
runtests.py
call nt_clean.bat

View File

@@ -1,15 +0,0 @@
@echo off
call nt_build_pyste.bat basic %1
call nt_build_pyste.bat enums %1
call nt_build_pyste.bat header_test %1
call nt_build_pyste.bat nested %1
call nt_build_pyste.bat operators %1
call nt_build_pyste.bat smart_ptr %1
call nt_build_pyste.bat templates %1
call nt_build_pyste.bat unions %1
call nt_build_pyste.bat virtual %1
call nt_build_pyste.bat virtual2 %1
call nt_build_pyste.bat wrappertest %1
call nt_build_pyste.bat opaque %1
call nt_build_pyste.bat inherit %1

View File

@@ -1,8 +0,0 @@
@echo off
set BOOST_INCLUDE=D:\Programming\Libraries\boost-cvs\boost
set out=_%1.cpp
if "%2" == "--multiple" set out=_%1
rem python ../src/pyste.py %2 -I%BOOST_INCLUDE -I../example --module=%1 --out=%out ../example/%1.pyste
pyste %2 -I%BOOST_INCLUDE -I../example --module=%1 --out=%out ../example/%1.pyste
scons --quiet multiple=%2 %1.dll

View File

@@ -1,24 +0,0 @@
@echo off
rm -Rf _basic
rm -Rf _enums
rm -Rf _header_test
rm -Rf _nested
rm -Rf _operators
rm -Rf _smart_ptr
rm -Rf _templates
rm -Rf _unions
rm -Rf _virtual
rm -Rf _virtual2
rm -Rf _wrappertest
rm -Rf _opaque
rm -Rf _inherit
rm -f *.cpp
rm -f *.obj
rm -f *.exp
rm -f *.arg
rm -f *.dll
rm -f *.pyc
rm -f *.lib
rm -f ../example/*.obj

View File

@@ -1,5 +1,5 @@
import sys
sys.path.append('../src')
sys.path.append('..')
import unittest
from policies import *
@@ -35,8 +35,7 @@ class PoliciesTest(unittest.TestCase):
self.assertEqual(x.Code(), ret % 'copy_non_const_reference')
x = return_value_policy(manage_new_object)
self.assertEqual(x.Code(), ret % 'manage_new_object')
x = return_value_policy(return_opaque_pointer)
self.assertEqual(x.Code(), ret % 'return_opaque_pointer')
def testReturnWithCustodiam(self):
'test the mix of return_internal with custodian'

20
pyste/tests/test_all.bat Normal file
View File

@@ -0,0 +1,20 @@
@echo off
call build_pyste_nt basic ../example/basic.pyste
call build_pyste_nt enums ../example/enums.pyste
call build_pyste_nt header_test ../example/header_test.pyste
call build_pyste_nt nested ../example/nested.pyste
call build_pyste_nt operators ../example/operators.pyste
call build_pyste_nt templates ../example/templates.pyste
call build_pyste_nt virtual ../example/virtual.pyste
call build_pyste_nt wrappertest ../example/wrappertest.pyste
call build_pyste_nt unions ../example/unions.pyste
runtests.py
if errorlevel != 0 goto end
rm *.dll
rm *.pyc
:end

View File

@@ -1,88 +0,0 @@
#!/usr/bin/python
import os
import glob
import shutil
def build_pyste_files(multiple):
# list all pyste files in the example directory
examples = glob.glob('../example/*.pyste')
# generate the cpp file for each example
for example in examples:
path, filename = os.path.split(example)
module = os.path.splitext(filename)[0]
os.system('python ../src/pyste.py %s -I%s --module=%s %s' % \
(multiple, path, module, example))
def compile_pyste_files(multiple):
if not multiple:
# compile each cpp into a shared library
for cpp in glob.glob('*.cpp'):
print
print 'compiling', cpp
out = os.path.splitext(cpp)[0] + '.so'
cmdline = 'g++ -shared -o %s -I../example ' \
'-I/usr/include/python2.2 -lboost_python %s' % (out, cpp)
os.system(cmdline)
else:
modules = get_modules()
# list cpp files in each module directory
print
for module in modules:
# compile each
for file in glob.glob(module+'/*.cpp'):
print 'compiling', file
out = os.path.splitext(file)[0] + '.obj'
cmdline = 'g++ -shared -c -o %s -I../example ' \
'-I/usr/include/python2.2 %s' % (out, file)
os.system(cmdline)
# generate a dynamic library
print 'linking'
objs = ' '.join([x for x in glob.glob(module+'/*.obj')])
out = module + '.so'
cmdline = 'g++ -shared -o %s -lboost_python %s' % (out, objs)
os.system(cmdline)
def run_tests():
if os.system('python runtests.py') != 0:
raise RuntimeError, 'tests failed'
def cleanup():
extensions = '*.cpp *.so *.pyc'
files = []
for ext in extensions.split():
files += glob.glob(ext)
for file in files:
try:
os.remove(file)
except OSError: pass
modules = get_modules()
for module in modules:
try:
shutil.rmtree(module)
except OSError: pass
def main(multiple):
build_pyste_files(multiple)
compile_pyste_files(multiple)
run_tests()
cleanup()
def get_modules():
def getname(file):
return os.path.splitext(os.path.basename(file))[0]
return [getname(x) for x in glob.glob('../example/*.pyste')]
if __name__ == '__main__':
try:
main('--multiple')
main('')
except RuntimeError, e:
print e