1 //
2 //  Copyright (c) 2008-2010 Barry A. Scott
3 //
4 //
5 //  simple_moduile.cxx
6 //
7 //  This module defines a single function.
8 //
9 #ifdef _MSC_VER
10 // disable warning C4786: symbol greater than 255 character,
11 // nessesary to ignore as <map> causes lots of warning
12 #pragma warning(disable: 4786)
13 #endif
14 
15 #include "CXX/Objects.hxx"
16 #include "CXX/Extensions.hxx"
17 
18 #include <assert.h>
19 
20 class new_style_class: public Py::PythonClass< new_style_class >
21 {
22 public:
new_style_class(Py::PythonClassInstance * self,Py::Tuple & args,Py::Dict & kwds)23     new_style_class( Py::PythonClassInstance *self, Py::Tuple &args, Py::Dict &kwds )
24     : Py::PythonClass< new_style_class >::PythonClass( self, args, kwds )
25     , m_value( "default value" )
26     {
27         std::cout << "new_style_class c'tor Called with " << args.length() << " normal arguments." << std::endl;
28         Py::List names( kwds.keys() );
29         std::cout << "and with " << names.length() << " keyword arguments:" << std::endl;
30         for( Py::List::size_type i=0; i< names.length(); i++ )
31         {
32             Py::String name( names[i] );
33             std::cout << "    " << name << std::endl;
34         }
35     }
36 
~new_style_class()37     virtual ~new_style_class()
38     {
39         std::cout << "~new_style_class." << std::endl;
40     }
41 
cxx_method(long a,long b)42     long cxx_method( long a, long b )
43     {
44         return a * b + 3;
45     }
46 
init_type(void)47     static void init_type(void)
48     {
49         behaviors().name( "new_style_class" );
50         behaviors().doc( "documentation for new_style_class class" );
51         behaviors().supportGetattro();
52         behaviors().supportSetattro();
53 
54         PYCXX_ADD_NOARGS_METHOD( func_noargs, new_style_class_func_noargs, "docs for new_style_class_func_noargs" );
55         PYCXX_ADD_VARARGS_METHOD( func_varargs, new_style_class_func_varargs, "docs for new_style_class_func_varargs" );
56         PYCXX_ADD_KEYWORDS_METHOD( func_keyword, new_style_class_func_keyword, "docs for new_style_class_func_keyword" );
57 
58         PYCXX_ADD_NOARGS_METHOD( func_noargs_raise_exception, new_style_class_func_noargs_raise_exception,  "docs for new_style_class_func_noargs_raise_exception" );
59 
60         // Call to make the type ready for use
61         behaviors().readyType();
62     }
63 
new_style_class_func_noargs(void)64     Py::Object new_style_class_func_noargs( void )
65     {
66         std::cout << "new_style_class_func_noargs Called." << std::endl;
67         std::cout << "value ref count " << m_value.reference_count() << std::endl;
68         return Py::None();
69     }
PYCXX_NOARGS_METHOD_DECL(new_style_class,new_style_class_func_noargs)70     PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs )
71 
72     Py::Object new_style_class_func_varargs( const Py::Tuple &args )
73     {
74         std::cout << "new_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl;
75         return Py::None();
76     }
PYCXX_VARARGS_METHOD_DECL(new_style_class,new_style_class_func_varargs)77     PYCXX_VARARGS_METHOD_DECL( new_style_class, new_style_class_func_varargs )
78 
79     Py::Object new_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds )
80     {
81         std::cout << "new_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl;
82         Py::List names( kwds.keys() );
83         std::cout << "and with " << names.length() << " keyword arguments:" << std::endl;
84         for( Py::List::size_type i=0; i< names.length(); i++ )
85         {
86             Py::String name( names[i] );
87             std::cout << "    " << name << std::endl;
88         }
89         return Py::None();
90     }
PYCXX_KEYWORDS_METHOD_DECL(new_style_class,new_style_class_func_keyword)91     PYCXX_KEYWORDS_METHOD_DECL( new_style_class, new_style_class_func_keyword )
92 
93     Py::Object new_style_class_func_noargs_raise_exception( void )
94     {
95         std::cout << "new_style_class_func_noargs_raise_exception Called." << std::endl;
96         throw Py::RuntimeError( "its an error" );
97     }
PYCXX_NOARGS_METHOD_DECL(new_style_class,new_style_class_func_noargs_raise_exception)98     PYCXX_NOARGS_METHOD_DECL( new_style_class, new_style_class_func_noargs_raise_exception )
99 
100     Py::Object getattro( const Py::String &name_ )
101     {
102         std::string name( name_.as_std_string( "utf-8" ) );
103 
104         if( name == "value" )
105         {
106             return m_value;
107         }
108         else
109         {
110             return genericGetAttro( name_ );
111         }
112     }
113 
setattro(const Py::String & name_,const Py::Object & value)114     int setattro( const Py::String &name_, const Py::Object &value )
115     {
116         std::string name( name_.as_std_string( "utf-8" ) );
117 
118         if( name == "value" )
119         {
120             m_value = value;
121             return 0;
122         }
123         else
124         {
125             return genericSetAttro( name_, value );
126         }
127     }
128 
129     Py::String m_value;
130 };
131 
132 
133 class old_style_class: public Py::PythonExtension< old_style_class >
134 {
135 public:
old_style_class()136     old_style_class()
137     {
138     }
139 
~old_style_class()140     virtual ~old_style_class()
141     {
142     }
143 
init_type(void)144     static void init_type(void)
145     {
146         behaviors().name( "old_style_class" );
147         behaviors().doc( "documentation for old_style_class class" );
148         behaviors().supportGetattr();
149 
150         add_noargs_method( "old_style_class_func_noargs", &old_style_class::old_style_class_func_noargs );
151         add_varargs_method( "old_style_class_func_varargs", &old_style_class::old_style_class_func_varargs );
152         add_keyword_method( "old_style_class_func_keyword", &old_style_class::old_style_class_func_keyword );
153     }
154 
155     // override functions from PythonExtension
getattr(const char * name)156     virtual Py::Object getattr( const char *name )
157     {
158         return getattr_methods( name );
159     }
160 
old_style_class_func_noargs(void)161     Py::Object old_style_class_func_noargs( void )
162     {
163         std::cout << "old_style_class_func_noargs Called." << std::endl;
164         return Py::None();
165     }
166 
old_style_class_func_varargs(const Py::Tuple & args)167     Py::Object old_style_class_func_varargs( const Py::Tuple &args )
168     {
169         std::cout << "old_style_class_func_varargs Called with " << args.length() << " normal arguments." << std::endl;
170         return Py::None();
171     }
172 
old_style_class_func_keyword(const Py::Tuple & args,const Py::Dict & kwds)173     Py::Object old_style_class_func_keyword( const Py::Tuple &args, const Py::Dict &kwds )
174     {
175         std::cout << "old_style_class_func_keyword Called with " << args.length() << " normal arguments." << std::endl;
176         Py::List names( kwds.keys() );
177         std::cout << "and with " << names.length() << " keyword arguments:" << std::endl;
178         for( Py::List::size_type i=0; i< names.length(); i++ )
179         {
180             Py::String name( names[i] );
181             std::cout << "    " << name << std::endl;
182         }
183         return Py::None();
184     }
185 };
186 
187 class simple_module : public Py::ExtensionModule<simple_module>
188 {
189 public:
simple_module()190     simple_module()
191     : Py::ExtensionModule<simple_module>( "simple" ) // this must be name of the file on disk e.g. simple.so or simple.pyd
192     {
193         old_style_class::init_type();
194         new_style_class::init_type();
195 
196         add_noargs_method( "mod_func_noargs", &simple_module::mod_func_noargs, "documentation for mod_func_noargs()" );
197         add_varargs_method( "mod_func_varargs", &simple_module::mod_func_varargs, "documentation for mod_func_varargs()" );
198         add_keyword_method( "mod_func_keyword", &simple_module::mod_func_keyword, "documentation for mod_func_keyword()" );
199 
200         add_varargs_method("old_style_class", &simple_module::factory_old_style_class, "documentation for old_style_class()");
201         add_keyword_method("make_instance", &simple_module::make_instance, "documentation for make_instance()");
202 
203         add_keyword_method("decode_test", &simple_module::decode_test, "documentation for decode_test()");
204         add_keyword_method("encode_test", &simple_module::encode_test, "documentation for encode_test()");
205         add_keyword_method("derived_class_test", &simple_module::derived_class_test, "documentation for derived_class_test()");
206 
207         // after initialize the moduleDictionary will exist
208         initialize( "documentation for the simple module" );
209 
210         Py::Dict d( moduleDictionary() );
211         d["var"] = Py::String( "var value" );
212         Py::Object x( new_style_class::type() );
213         d["new_style_class"] = x;
214     }
215 
~simple_module()216     virtual ~simple_module()
217     {}
218 
219 private:
decode_test(const Py::Tuple & args,const Py::Dict &)220     Py::Object decode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ )
221     {
222         Py::String s( args[0] );
223         return s.decode("utf-8");
224     }
225 
encode_test(const Py::Tuple & args,const Py::Dict &)226     Py::Object encode_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ )
227     {
228         Py::String s( args[0] );
229         return s.encode("utf-8");
230     }
231 
derived_class_test(const Py::Tuple & args,const Py::Dict &)232     Py::Object derived_class_test( const Py::Tuple &args, const Py::Dict &/*kwds*/ )
233     {
234         Py::PythonClassObject<new_style_class> py_nsc( args[0] );
235         new_style_class *cxx_nsc = py_nsc.getCxxObject();
236 
237         Py::Long a( args[1] );
238         Py::Long b( args[2] );
239 
240         long result = cxx_nsc->cxx_method( a, b );
241 
242         return Py::Long( result );
243     }
244 
mod_func_noargs()245     Py::Object mod_func_noargs()
246     {
247         std::cout << "mod_func_noargs Called." << std::endl;
248         return Py::None();
249     }
250 
mod_func_varargs(const Py::Tuple & args)251     Py::Object mod_func_varargs( const Py::Tuple &args )
252     {
253         std::cout << "mod_func_varargs Called with " << args.length() << " normal arguments." << std::endl;
254         return Py::None();
255     }
256 
mod_func_keyword(const Py::Tuple & args,const Py::Dict & kwds)257     Py::Object mod_func_keyword( const Py::Tuple &args, const Py::Dict &kwds )
258     {
259         std::cout << "mod_func_varargs Called with " << args.length() << " normal arguments." << std::endl;
260         Py::List names( kwds.keys() );
261         std::cout << "and with " << names.length() << " keyword arguments:" << std::endl;
262         for( Py::List::size_type i=0; i< names.length(); i++ )
263         {
264             Py::String name( names[i] );
265             std::cout << "    " << name << std::endl;
266         }
267 
268         if( args.length() > 0 )
269         {
270             Py::Object x( args[0] );
271             try
272             {
273                 Py::PythonClassObject<new_style_class> x2( x );
274                 std::cout << "C++ pointer " << x2.getCxxObject() << std::endl;
275             }
276             catch( Py::TypeError &e )
277             {
278                 // must clear the error
279                 e.clear();
280                 std::cout << "arg 1 is not a new_style_class" << std::endl;
281             }
282         }
283 
284         return Py::None();
285     }
286 
make_instance(const Py::Tuple & args,const Py::Dict & kwds)287     Py::Object make_instance( const Py::Tuple &args, const Py::Dict &kwds )
288     {
289         std::cout << "make_instance Called with " << args.length() << " normal arguments." << std::endl;
290         Py::List names( kwds.keys() );
291         std::cout << "and with " << names.length() << " keyword arguments:" << std::endl;
292         for( Py::List::size_type i=0; i< names.length(); i++ )
293         {
294             Py::String name( names[i] );
295             std::cout << "    " << name << std::endl;
296         }
297 
298         Py::Callable class_type( new_style_class::type() );
299 
300         Py::PythonClassObject<new_style_class> new_style_obj( class_type.apply( args, kwds ) );
301 
302         return new_style_obj;
303     }
304 
305 
factory_old_style_class(const Py::Tuple &)306     Py::Object factory_old_style_class( const Py::Tuple &/*args*/ )
307     {
308         Py::Object obj = Py::asObject( new old_style_class );
309         return obj;
310     }
311 };
312 
313 #if defined( _WIN32 )
314 #define EXPORT_SYMBOL __declspec( dllexport )
315 #else
316 #define EXPORT_SYMBOL
317 #endif
318 
319 #if PY_MAJOR_VERSION == 3
320 static simple_module *simple;
321 
PyInit_simple()322 extern "C" EXPORT_SYMBOL PyObject *PyInit_simple()
323 {
324 #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL)
325     Py::InitialisePythonIndirectPy::Interface();
326 #endif
327 
328     simple = new simple_module;
329     return simple->module().ptr();
330 }
331 
332 // symbol required for the debug version
PyInit_simple_d()333 extern "C" EXPORT_SYMBOL PyObject *PyInit_simple_d()
334 {
335     return PyInit_simple();
336 }
337 
338 #else
339 
340 static simple_module *simple;
341 
initsimple()342 extern "C" EXPORT_SYMBOL void initsimple()
343 {
344 #if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL)
345     Py::InitialisePythonIndirectPy::Interface();
346 #endif
347 
348     simple = new simple_module;
349 }
350 
351 // symbol required for the debug version
initsimple_d()352 extern "C" EXPORT_SYMBOL void initsimple_d()
353 {
354     initsimple();
355 }
356 #endif
357