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:
@@ -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.
|
||||
|
||||
78
pyste/doc/adding_new_methods.html
Normal file
78
pyste/doc/adding_new_methods.html
Normal 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>-></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>& </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>"World"</span><span class=special>, </span><span class=string>"hello.h"</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>"greet"</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>>>> </span><span class=identifier>import </span><span class=identifier>hello
|
||||
</span><span class=special>>>> </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>()
|
||||
>>> </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>)
|
||||
>>> </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>>>> </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 © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
<font size="2">Permission to copy, use, modify, sell and distribute this document
|
||||
is granted provided this copyright notice appears in all copies. This document
|
||||
is provided "as is" without express or implied warranty, and with
|
||||
no claim as to its suitability for any purpose. </font> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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>
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
|
||||
@@ -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 © 2003 Bruno da Silva de Oliveira<br>Copyright © 2002-2003 Joel de Guzman<br><br>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
13
pyste/tests/add_test.h
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace add_test {
|
||||
|
||||
struct C
|
||||
{
|
||||
int x;
|
||||
};
|
||||
|
||||
const int get_x(C& c)
|
||||
{
|
||||
return c.x;
|
||||
}
|
||||
|
||||
}
|
||||
2
pyste/tests/add_test.pyste
Normal file
2
pyste/tests/add_test.pyste
Normal 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
12
pyste/tests/add_testUT.py
Normal 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()
|
||||
Reference in New Issue
Block a user