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

- New construct, add_method.

[SVN r18650]
This commit is contained in:
Bruno da Silva de Oliveira
2003-06-03 01:48:51 +00:00
parent ec750a44c9
commit 5d1e245858
13 changed files with 218 additions and 126 deletions

View File

@@ -1,3 +1,6 @@
2 June 2003
Added a new construct, add_method. See documentation.
23 May 2003
Support for global variables added.
Various bug fixes.
@@ -7,8 +10,10 @@ Fixed bug where in a certain cases the GCCXMLParser would end up with multiple
declarations of the same class
22 Apr 2003
- Now shows a warning when the user tries to export a forward-declared class. Forward-declared classes are ignored by the AllFromHeader construct.
- Fixed a bug where classes, functions and enums where being exported, even if excluded from a AllFromHeader construct.
- Now shows a warning when the user tries to export a forward-declared class.
Forward-declared classes are ignored by the AllFromHeader construct.
- Fixed a bug where classes, functions and enums where being exported, even if
excluded from a AllFromHeader construct.
16 Apr 2003
Added a more generic (but ugly) code to declare the smart pointer converters.

View File

@@ -0,0 +1,78 @@
<html>
<head>
<!-- Generated by the Spirit (http://spirit.sf.net) QuickDoc -->
<title>Adding New Methods</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="global_variables.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>Adding New Methods</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="global_variables.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>
Suppose that you want to add a function to a class, turning it into a method:</p>
<code><pre>
<span class=keyword>struct </span><span class=identifier>World
</span><span class=special>{
</span><span class=keyword>void </span><span class=identifier>set</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>) { </span><span class=keyword>this</span><span class=special>-&gt;</span><span class=identifier>msg </span><span class=special>= </span><span class=identifier>msg</span><span class=special>; }
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>msg</span><span class=special>;
};
</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>string </span><span class=identifier>greet</span><span class=special>(</span><span class=identifier>World</span><span class=special>&amp; </span><span class=identifier>w</span><span class=special>)
{
</span><span class=keyword>return </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>msg</span><span class=special>;
}
</span></pre></code>
<p>
Here, we want to make <tt>greet</tt> work as a method of the class <tt>World</tt>. We do
that using the <tt>add_method</tt> construct:</p>
<code><pre>
<span class=identifier>W </span><span class=special>= </span><span class=identifier>Class</span><span class=special>(</span><span class=string>&quot;World&quot;</span><span class=special>, </span><span class=string>&quot;hello.h&quot;</span><span class=special>)
</span><span class=identifier>add_method</span><span class=special>(</span><span class=identifier>W</span><span class=special>, </span><span class=string>&quot;greet&quot;</span><span class=special>)
</span></pre></code>
<p>
Notice also that then you can rename it, set its policy, just like a regular
method:</p>
<code><pre>
<span class=identifier>rename</span><span class=special>(</span><span class=identifier>W</span><span class=special>.</span><span class=identifier>greet</span><span class=special>, </span><span class=literal>'Greet'</span><span class=special>)
</span></pre></code>
<p>
Now from Python:</p>
<code><pre>
<span class=special>&gt;&gt;&gt; </span><span class=identifier>import </span><span class=identifier>hello
</span><span class=special>&gt;&gt;&gt; </span><span class=identifier>w </span><span class=special>= </span><span class=identifier>hello</span><span class=special>.</span><span class=identifier>World</span><span class=special>()
&gt;&gt;&gt; </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>set</span><span class=special>(</span><span class=literal>'Ni'</span><span class=special>)
&gt;&gt;&gt; </span><span class=identifier>w</span><span class=special>.</span><span class=identifier>greet</span><span class=special>()
</span><span class=literal>'Ni'
</span><span class=special>&gt;&gt;&gt; </span><span class=identifier>print </span><span class=literal>'Oh no! The knights who say Ni!'
</span><span class=identifier>Oh </span><span class=identifier>no</span><span class=special>! </span><span class=identifier>The </span><span class=identifier>knights </span><span class=identifier>who </span><span class=identifier>say </span><span class=identifier>Ni</span><span class=special>!
</span></pre></code>
<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="global_variables.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

@@ -4,6 +4,7 @@
<title>Global Variables</title>
<link rel="stylesheet" href="theme/style.css" type="text/css">
<link rel="prev" href="smart_pointers.html">
<link rel="next" href="adding_new_methods.html">
</head>
<body>
<table width="100%" height="48" border="0" cellspacing="2">
@@ -20,7 +21,7 @@
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
<td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<p>
@@ -36,7 +37,7 @@ functions, and export those.</p>
<tr>
<td width="30"><a href="../index.html"><img src="theme/u_arr.gif" border="0"></a></td>
<td width="30"><a href="smart_pointers.html"><img src="theme/l_arr.gif" border="0"></a></td>
<td width="20"><img src="theme/r_arr_disabled.gif" border="0"></td>
<td width="20"><a href="adding_new_methods.html"><img src="theme/r_arr.gif" border="0"></a></td>
</tr>
</table>
<br>

View File

@@ -477,3 +477,40 @@ Beware of non-const global variables: changes in Python won't reflect in C++!
If you really must change them in Python, you will have to write some accessor
functions, and export those.
[page:1 Adding New Methods]
Suppose that you want to add a function to a class, turning it into a method:
struct World
{
void set(std::string msg) { this->msg = msg; }
std::string msg;
};
std::string greet(World& w)
{
return w.msg;
}
Here, we want to make [^greet] work as a method of the class [^World]. We do
that using the [^add_method] construct:
W = Class("World", "hello.h")
add_method(W, "greet")
Notice also that then you can rename it, set its policy, just like a regular
method:
rename(W.greet, 'Greet')
Now from Python:
>>> import hello
>>> w = hello.World()
>>> w.set('Ni')
>>> w.greet()
'Ni'
>>> print 'Oh no! The knights who say Ni!'
Oh no! The knights who say Ni!

View File

@@ -70,6 +70,11 @@
<a href="doc/global_variables.html">Global Variables</a>
</td>
</tr>
<tr>
<td class="toc_cells_L1">
<a href="doc/adding_new_methods.html">Adding New Methods</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

@@ -271,27 +271,41 @@ class ClassExporter(Exporter):
self.Add('inside', code)
def OverloadName(self, method):
'Returns the name of the overloads struct for the given method'
name = makeid(method.FullName())
overloads = '_overloads_%i_%i' % (method.minArgs, method.maxArgs)
return name + overloads
def GetAddedMethods(self):
added_methods = self.info.__added__
result = []
if added_methods:
for name, rename in added_methods:
decl = self.GetDeclaration(name)
self.info[name].rename = rename
result.append(decl)
return result
def ExportMethods(self):
'Export all the non-virtual methods of this class'
'''Export all the non-virtual methods of this class, plus any function
that is to be exported as a method'''
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))
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)
if code not in declared:
declared[code] = True
self.Add('declaration', code)
if (isinstance(m, Method) and m.static) or type(m) == Function:
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, self.OverloadName(m), func, m.minArgs, m.maxArgs)
if code not in declared:
declared[code] = True
self.Add('declaration', code)
def Pointer(m):
@@ -301,7 +315,11 @@ class ClassExporter(Exporter):
if wrapper:
return '&' + wrapper.FullName()
# return normal pointers to the methods of the class
is_unique = self.class_.IsUnique(m.name)
if isinstance(m, Method):
is_unique = self.class_.IsUnique(m.name)
else:
# function
is_unique = len(self.GetDeclarations(m.FullName())) == 1
if is_unique:
return '&' + method.FullName()
else:
@@ -310,9 +328,10 @@ class ClassExporter(Exporter):
def IsExportable(m):
'Returns true if the given method is exportable by this routine'
ignore = (Constructor, ClassOperator, Destructor)
return isinstance(m, Method) and not isinstance(m, ignore) and not m.virtual
return isinstance(m, Function) and not isinstance(m, ignore) and not m.virtual
methods = [x for x in self.public_members if IsExportable(x)]
methods.extend(self.GetAddedMethods())
for method in methods:
method_info = self.info[method.name]
@@ -336,7 +355,7 @@ class ClassExporter(Exporter):
if method.minArgs != method.maxArgs:
# add the overloads for this method
DeclareOverloads(method)
overload_name = OverloadName(method)
overload_name = self.OverloadName(method)
overload = ', %s%s()' % (namespaces.pyste, overload_name)
# build the .def string to export the method
@@ -347,7 +366,7 @@ class ClassExporter(Exporter):
code += ')'
self.Add('inside', code)
# static method
if method.static:
if isinstance(method, Method) and method.static:
code = '.staticmethod("%s")' % name
self.Add('inside', code)
# add wrapper code if this method has one
@@ -593,7 +612,6 @@ class ClassExporter(Exporter):
self.Add('declaration-outside', macro)
self._exported_opaque_pointers[macro] = 1
#==============================================================================
# Virtual Wrapper utils

View File

@@ -8,10 +8,9 @@ class Exporter:
INDENT = ' ' * 4
def __init__(self, info, parser_tail=None, parser_decl=None):
def __init__(self, info, parser_tail=None):
self.info = info
self.parser_tail = parser_tail
self.parser_decl = parser_decl
def Name(self):
@@ -22,8 +21,7 @@ class Exporter:
self.parser = parser
header = self.info.include
tail = self.parser_tail
decl = self.parser_decl
declarations, parser_header = parser.parse(header, tail, decl)
declarations, parser_header = parser.parse(header, tail)
self.parser_header = parser_header
self.SetDeclarations(declarations)

View File

@@ -184,29 +184,34 @@ class InfoWrapper:
#==============================================================================
# Functions
#==============================================================================
def exclude(option):
option._Attribute('exclude', True)
def exclude(info):
info._Attribute('exclude', True)
def set_policy(option, policy):
option._Attribute('policy', policy)
def set_policy(info, policy):
info._Attribute('policy', policy)
def rename(option, name):
option._Attribute('rename', name)
def rename(info, name):
info._Attribute('rename', name)
def set_wrapper(option, wrapper):
def set_wrapper(info, wrapper):
if isinstance(wrapper, str):
wrapper = FunctionWrapper(wrapper)
option._Attribute('wrapper', wrapper)
info._Attribute('wrapper', wrapper)
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_shared_ptr(info):
info._Attribute('smart_ptr', 'boost::shared_ptr< %s >')
def use_auto_ptr(option):
option._Attribute('smart_ptr', 'std::auto_ptr< %s >')
def use_auto_ptr(info):
info._Attribute('smart_ptr', 'std::auto_ptr< %s >')
def add_method(info, name, rename=None):
added = info._Attribute('__added__')
if added is None:
info._Attribute('__added__', [(name, rename)])
else:
added.append((name, rename))

View File

@@ -37,7 +37,7 @@ from policies import *
from CppParser import CppParser, CppParserError
import time
__VERSION__ = '0.8.2'
__VERSION__ = '0.9.0'
def RecursiveIncludes(include):
'Return a list containg the include dir and all its subdirectories'
@@ -136,6 +136,7 @@ def CreateContext():
context['set_wrapper'] = infos.set_wrapper
context['use_shared_ptr'] = infos.use_shared_ptr
context['use_auto_ptr'] = infos.use_auto_ptr
context['add_method'] = infos.add_method
# policies
context['return_internal_reference'] = return_internal_reference
context['with_custodian_and_ward'] = with_custodian_and_ward

View File

@@ -1,83 +0,0 @@
// Includes ====================================================================
#include <boost/python.hpp>
#include <smart_ptr.h>
// Using =======================================================================
using namespace boost::python;
// Declarations ================================================================
namespace {
struct smart_ptr_A_Wrapper: smart_ptr::A
{
smart_ptr_A_Wrapper(PyObject* self_, const smart_ptr::A & p0):
smart_ptr::A(p0), self(self_) {}
smart_ptr_A_Wrapper(PyObject* self_):
smart_ptr::A(), self(self_) {}
int f() {
return call_method< int >(self, "f");
}
PyObject* self;
};
}// namespace
// Module ======================================================================
BOOST_PYTHON_MODULE(_smart_tr)
{
scope* smart_ptr_A_scope = new scope(
class_< smart_ptr::A, boost::noncopyable, smart_ptr_A_Wrapper >("A", init< >())
);
// Temporary code for smart pointers
objects::class_value_wrapper<
boost::shared_ptr< smart_ptr::A >, objects::make_ptr_instance<
smart_ptr::A, objects::pointer_holder<
boost::shared_ptr< smart_ptr::A >, smart_ptr::A >
>
>();
delete smart_ptr_A_scope;
scope* smart_ptr_C_scope = new scope(
class_< smart_ptr::C >("C", init< >())
.def(init< const smart_ptr::C & >())
.def_readwrite("value", &smart_ptr::C::value)
);
// Temporary code for smart pointers
objects::class_value_wrapper<
boost::shared_ptr< smart_ptr::C >, objects::make_ptr_instance<
smart_ptr::C, objects::pointer_holder<
boost::shared_ptr< smart_ptr::C >, smart_ptr::C >
>
>();
delete smart_ptr_C_scope;
scope* smart_ptr_D_scope = new scope(
class_< smart_ptr::D >("D", init< >())
.def(init< const smart_ptr::D & >())
.def("Get", &smart_ptr::D::Get)
.def("Set", &smart_ptr::D::Set)
);
// Temporary code for smart pointers
objects::class_value_wrapper<
std::auto_ptr< smart_ptr::D >, objects::make_ptr_instance<
smart_ptr::D, objects::pointer_holder<
std::auto_ptr< smart_ptr::D >, smart_ptr::D >
>
>();
delete smart_ptr_D_scope;
def("GetA", &smart_ptr::GetA);
def("NewA", &smart_ptr::NewA);
def("NewC", &smart_ptr::NewC);
def("NewD", &smart_ptr::NewD);
}

13
pyste/tests/add_test.h Normal file
View File

@@ -0,0 +1,13 @@
namespace add_test {
struct C
{
int x;
};
const int get_x(C& c)
{
return c.x;
}
}

View File

@@ -0,0 +1,2 @@
C = Class('add_test::C', 'add_test.h')
add_method(C, 'add_test::get_x')

12
pyste/tests/add_testUT.py Normal file
View File

@@ -0,0 +1,12 @@
import unittest
from _add_test import *
class AddMethodTest(unittest.TestCase):
def testIt(self):
c = C()
c.x = 10
self.assertEqual(c.get_x(), 10)
if __name__ == '__main__':
unittest.main()