[pygccxml-commit] SF.net SVN: pygccxml: [1369] pyplusplus_dev
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2008-07-13 20:49:52
|
Revision: 1369 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1369&view=rev Author: roman_yakovenko Date: 2008-07-13 13:50:00 -0700 (Sun, 13 Jul 2008) Log Message: ----------- adding initial support for ctypes module Modified Paths: -------------- pyplusplus_dev/pyplusplus/code_creators/__init__.py pyplusplus_dev/pyplusplus/code_creators/global_variable.py pyplusplus_dev/pyplusplus/code_creators/member_variable.py pyplusplus_dev/pyplusplus/code_repository/__init__.py pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py pyplusplus_dev/pyplusplus/module_creator/creator.py pyplusplus_dev/unittests/bool_by_ref_tester.py pyplusplus_dev/unittests/data/bool_by_ref_to_be_exported.hpp pyplusplus_dev/unittests/data/global_variables_to_be_exported.cpp pyplusplus_dev/unittests/data/global_variables_to_be_exported.hpp pyplusplus_dev/unittests/data/member_variables_to_be_exported.hpp pyplusplus_dev/unittests/global_variables_tester.py pyplusplus_dev/unittests/member_variables_tester.py Modified: pyplusplus_dev/pyplusplus/code_creators/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/__init__.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/code_creators/__init__.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -91,6 +91,7 @@ from global_variable import global_variable_t from global_variable import array_gv_t from global_variable import array_gv_wrapper_t +from global_variable import global_variable_addressof_t from member_variable import member_variable_base_t from member_variable import member_variable_t @@ -101,6 +102,7 @@ from member_variable import array_mv_wrapper_t from member_variable import mem_var_ref_t from member_variable import mem_var_ref_wrapper_t +from member_variable import member_variable_addressof_t from class_declaration import class_t from class_declaration import class_wrapper_t Modified: pyplusplus_dev/pyplusplus/code_creators/global_variable.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/global_variable.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/code_creators/global_variable.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -56,7 +56,7 @@ else: obj_identifier = algorithm.create_identifier( self, '::boost::python::object' ) ref_identifier = algorithm.create_identifier( self, '::boost::ref' ) - result.append( ' = %s( %s( %s ) );' % ( obj_identifier, ref_identifier, self.decl_identifier ) ) + result.append( ' = %s( %s( %s ) );' % ( obj_identifier, ref_identifier, self.decl_identifier ) ) return ''.join( result ) class array_gv_t( global_variable_base_t ): @@ -74,7 +74,7 @@ def _create_impl( self ): if self.declaration.already_exposed: return '' - + answer = [] answer.append( algorithm.create_identifier( self, '::boost::python::scope' ) ) answer.append( '().attr("%s")' % self.alias ) @@ -141,7 +141,7 @@ def _create_impl( self ): if self.declaration.already_exposed: return '' - + answer = [self._create_namespaces_name()] answer.append( self.wrapper_type.decl_string ) answer.append( ''.join([ self.wrapper_creator_name, '(){']) ) @@ -157,3 +157,28 @@ def _get_system_headers_impl( self ): return [code_repository.array_1.file_name] + +class global_variable_addressof_t( global_variable_base_t ): + """ + Creates boost.python code that exposes address of global variable. + + This functionality is pretty powerful if you use it with "ctypes" - + standard package. + """ + def __init__(self, variable ): + global_variable_base_t.__init__( self, variable=variable ) + + def _create_impl(self): + if self.declaration.already_exposed: + return '' + + assert isinstance( self.declaration, pygccxml.declarations.variable_t ) + result = [] + #TODO: porting to 64Bit is welcome + result.append( algorithm.create_identifier( self, '::boost::python::scope' ) ) + result.append( '().attr("%s")' % self.alias ) + result.append( ' = boost::uint32_t( boost::addressof( %s ) );' % self.decl_identifier ) + return ''.join( result ) + + def _get_system_headers_impl( self ): + return [code_repository.ctypes_integration.file_name] Modified: pyplusplus_dev/pyplusplus/code_creators/member_variable.py =================================================================== --- pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/code_creators/member_variable.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -30,7 +30,7 @@ def _set_wrapper( self, new_wrapper ): self._wrapper = new_wrapper wrapper = property( _get_wrapper, _set_wrapper ) - + def _get_system_headers_impl( self ): files = [] if self.declaration.getter_call_policies: @@ -38,7 +38,7 @@ if self.declaration.setter_call_policies: files.append( self.declaration.setter_call_policies.header_file ) return files - + class member_variable_t( member_variable_base_t ): """ Creates boost.python code that exposes member variable. @@ -130,12 +130,12 @@ doc = self.documentation add_property = 'add_property' add_property_args = [ '"%s"' % self.alias ] - getter_code = declarations.call_invocation.join( + getter_code = declarations.call_invocation.join( make_getter , [ '&' + self.decl_identifier , self.declaration.getter_call_policies.create( self ) ] , os.linesep + self.indent( self.PARAM_SEPARATOR, 6) ) - + add_property_args.append( getter_code ) if not self.declaration.is_read_only: setter_code = '' @@ -143,14 +143,14 @@ if self.declaration.setter_call_policies \ and not self.declaration.setter_call_policies.is_default(): setter_args.append( self.declaration.setter_call_policies.create( self ) ) - setter_code = declarations.call_invocation.join( + setter_code = declarations.call_invocation.join( make_setter , setter_args , os.linesep + self.indent( self.PARAM_SEPARATOR, 6) ) add_property_args.append( setter_code) if doc: add_property_args.append( doc ) - return declarations.call_invocation.join( + return declarations.call_invocation.join( add_property , add_property_args , os.linesep + self.indent( self.PARAM_SEPARATOR, 4 ) ) @@ -391,7 +391,7 @@ answer = [] answer.append( 'typedef %s;' % self.wrapper.wrapper_creator_type.create_typedef( 'array_wrapper_creator' ) ) answer.append( os.linesep * 2 ) - + doc = '' if self.declaration.type_qualifiers.has_static: answer.append( self.parent.class_var_name + '.add_static_property' ) @@ -425,7 +425,7 @@ answer.append( os.linesep ) answer.append( '}' ) return ''.join( answer ) - + def _get_system_headers_impl( self ): return [] @@ -445,7 +445,7 @@ @property def wrapper_type( self ): tmpl = "%(namespace)s::%(constness)sarray_1_t< %(item_type)s, %(array_size)d>" - + constness = '' if declarations.is_const( self.declaration.type ): constness = 'const_' @@ -463,14 +463,14 @@ if declarations.is_const( self.declaration.type ): wrapped_cls_type = declarations.const_t( wrapped_cls_type ) return declarations.reference_t( wrapped_cls_type ) - + @property def wrapper_creator_type(self): return declarations.free_function_type_t( return_type=self.wrapper_type , arguments_types=[self.wrapped_class_type] ) - - @property + + @property def wrapper_creator_name(self): return '_'.join( ['pyplusplus', self.declaration.name, 'wrapper'] ) @@ -494,8 +494,8 @@ def _get_system_headers_impl( self ): return [code_repository.array_1.file_name] - + class mem_var_ref_t( member_variable_base_t ): """ Creates C++ code that creates accessor for class member variable, that has type reference. @@ -644,3 +644,39 @@ def _get_system_headers_impl( self ): return [] + +class member_variable_addressof_t( member_variable_base_t ): + """ + Creates boost.python code that exposes address of member variable. + + This functionality is pretty powerful if you use it with "ctypes" - + standard package. + + """ + def __init__(self, variable, wrapper=None ): + member_variable_base_t.__init__( self, variable=variable, wrapper=wrapper ) + + def _create_impl( self ): + doc = '' #static property does not support documentation + if self.declaration.type_qualifiers.has_static: + add_property = 'add_static_property' + else: + if self.documentation: + doc = self.documentation + add_property = 'add_property' + answer = [ add_property ] + answer.append( '( ' ) + answer.append('"%s"' % self.alias) + answer.append( self.PARAM_SEPARATOR ) + + answer.append( 'pyplus_conv::make_addressof_getter(&%s)' + % self.decl_identifier ) + if doc: + answer.append( self.PARAM_SEPARATOR ) + answer.append( doc ) + answer.append( ' ) ' ) + + return ''.join( answer ) + + def _get_system_headers_impl( self ): + return [code_repository.ctypes_integration.file_name] Modified: pyplusplus_dev/pyplusplus/code_repository/__init__.py =================================================================== --- pyplusplus_dev/pyplusplus/code_repository/__init__.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/code_repository/__init__.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -19,8 +19,15 @@ import convenience import return_range import call_policies +import ctypes_integration -all = [ array_1, gil_guard, convenience, call_policies, named_tuple, return_range ] +all = [ array_1 + , gil_guard + , convenience + , call_policies + , named_tuple + , return_range + , ctypes_integration ] headers = map( lambda f: f.file_name, all ) Modified: pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py =================================================================== --- pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/decl_wrappers/variable_wrapper.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -21,6 +21,7 @@ self._apply_smart_ptr_wa = False self._is_read_only = None self._use_make_functions = None + self._expose_address = None __call_policies_doc__ = \ """There are usecase, when exporting member variable forces Py++ to @@ -89,7 +90,27 @@ self._use_make_functions = value use_make_functions = property( get_use_make_functions, set_use_make_functions , doc=__use_make_functions_doc__) + + __expose_address_doc__ = \ + """There are some cases when Boost.Python doesn't provide a convenient way + to expose the variable to Python. For example: + double* x[10]; + //or + char* buffer; //in case you want to modify the buffer in place + + In this cases Py++ doesn't help too. In these cases it is possible to expose + the actual address of the variable. After that, you can use built-in "ctypes" + package to edit the content of the variable. + """ + def get_expose_address( self ): + return self._expose_address + def set_expose_address( self, value ): + self._expose_address = value + expose_address = property( get_expose_address, set_expose_address + , doc= __expose_address_doc__ ) + + def __find_out_is_read_only(self): type_ = declarations.remove_alias( self.type ) @@ -127,14 +148,15 @@ return messages.W1033 if self.bits == 0 and self.name == "": return messages.W1034 - if declarations.is_array( self.type ) and declarations.array_size( self.type ) < 1: - return messages.W1045 + if not self.expose_address: + if declarations.is_array( self.type ) and declarations.array_size( self.type ) < 1: + return messages.W1045 type_ = declarations.remove_alias( self.type ) type_ = declarations.remove_const( type_ ) if declarations.is_pointer( type_ ): - if self.type_qualifiers.has_static: + if not self.expose_address and self.type_qualifiers.has_static: return messages.W1035 - if python_traits.is_immutable( type_.base ): + if not self.expose_address and python_traits.is_immutable( type_.base ): return messages.W1036 units = declarations.decompose_type( type_ ) Modified: pyplusplus_dev/pyplusplus/module_creator/creator.py =================================================================== --- pyplusplus_dev/pyplusplus/module_creator/creator.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/pyplusplus/module_creator/creator.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -309,7 +309,7 @@ if not ( None is element_type ) and class_traits.is_my_case( element_type ): value_cls = class_traits.get_declaration( element_type ) has_prerequisits = value_cls.less_than_comparable \ - and value_cls.equality_comparable + and value_cls.equality_comparable if ( not has_prerequisits ) and ( value_cls not in created_value_traits ): created_value_traits.add( value_cls ) element_type_cc = code_creators.value_traits_t( value_cls ) @@ -576,19 +576,19 @@ self.__extmodule.adopt_declaration_creator( wrapper ) #next constructors are not present in code, but compiler generated - #Boost.Python requiers them to be declared in the wrapper class + #Boost.Python requiers them to be declared in the wrapper class noncopyable_vars = self.curr_decl.find_noncopyable_vars() - + copy_constr = self.curr_decl.find_copy_constructor() if not self.curr_decl.noncopyable and copy_constr and copy_constr.is_artificial: cccc = code_creators.copy_constructor_wrapper_t( class_=self.curr_decl) wrapper.adopt_creator( cccc ) - trivial_constr = self.curr_decl.find_trivial_constructor() + trivial_constr = self.curr_decl.find_trivial_constructor() if trivial_constr and trivial_constr.is_artificial and not noncopyable_vars: tcons = code_creators.null_constructor_wrapper_t( class_=self.curr_decl ) wrapper.adopt_creator( tcons ) - + exposed = self.expose_overloaded_mem_fun_using_macro( cls_decl, cls_cc ) cls_parent_cc.adopt_creator( cls_cc ) @@ -655,6 +655,15 @@ self.__types_db.update( self.curr_decl ) self.__dependencies_manager.add_exported( self.curr_decl ) + if self.curr_decl.expose_address: + creator_type = None + if isinstance( self.curr_decl.parent, declarations.namespace_t ): + creator_type = code_creators.global_variable_addressof_t + else: + creator_type = code_creators.member_variable_addressof_t + self.curr_code_creator.adopt_creator( creator_type(self.curr_decl) ) + return + if declarations.is_array( self.curr_decl.type ): if self._register_array_1( self.curr_decl.type ): array_1_registrator = code_creators.array_1_registrator_t( array_type=self.curr_decl.type ) Modified: pyplusplus_dev/unittests/bool_by_ref_tester.py =================================================================== --- pyplusplus_dev/unittests/bool_by_ref_tester.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/bool_by_ref_tester.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -33,7 +33,7 @@ module.listener.__init__(self) def listen( self, id, name, skip): print "Python: listen called with", id, name, skip - return True ## Test always returns True... + return 11## Test always returns True... c = list1() ret = module.callListener( c ) Modified: pyplusplus_dev/unittests/data/bool_by_ref_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/bool_by_ref_to_be_exported.hpp 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/data/bool_by_ref_to_be_exported.hpp 2008-07-13 20:50:00 UTC (rev 1369) @@ -5,13 +5,13 @@ class listener { public: - virtual void listen(int id, const std::string& name, bool& skip) { + virtual void listen(int id, const std::string& name, int& skip) { throw std::runtime_error ( std::string ("Virtual function listener::listen called!") ); } }; bool callListener ( listener* myListener) { - bool skip = false; + int skip = 10; std::cout << "C++: Calling myListener->listen\n"; myListener->listen(100, "test", skip); std::cout << "C++: Called OK " << skip <<"\n"; Modified: pyplusplus_dev/unittests/data/global_variables_to_be_exported.cpp =================================================================== --- pyplusplus_dev/unittests/data/global_variables_to_be_exported.cpp 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/data/global_variables_to_be_exported.cpp 2008-07-13 20:50:00 UTC (rev 1369) @@ -5,20 +5,25 @@ #include "global_variables_to_be_exported.hpp" -namespace global_variables{ +namespace global_variables{ const color const_var = red; color non_const_var = blue; data garray[10]; double arr_of_doubles[100]; - + void init_garray(){ for( int i =0; i < 10; ++i ){ garray[i].value = -i; } } +int some_value = -7; +int get_some_value(){ return some_value; } +unsigned int get_some_value_address(){ return (unsigned int)( &some_value ); } + } -const char someSin[3] = "AB"; \ No newline at end of file + +const char someSin[3] = "AB"; Modified: pyplusplus_dev/unittests/data/global_variables_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/global_variables_to_be_exported.hpp 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/data/global_variables_to_be_exported.hpp 2008-07-13 20:50:00 UTC (rev 1369) @@ -6,7 +6,7 @@ #ifndef __global_variables_to_be_exported_hpp__ #define __global_variables_to_be_exported_hpp__ -namespace global_variables{ +namespace global_variables{ enum color{ red, green, blue }; @@ -19,6 +19,12 @@ extern double arr_of_doubles[100]; void init_garray(); +extern int some_value; + +int get_some_value(); + +unsigned int get_some_value_address(); + } Modified: pyplusplus_dev/unittests/data/member_variables_to_be_exported.hpp =================================================================== --- pyplusplus_dev/unittests/data/member_variables_to_be_exported.hpp 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/data/member_variables_to_be_exported.hpp 2008-07-13 20:50:00 UTC (rev 1369) @@ -9,12 +9,12 @@ #include <string> #include <iostream> -namespace member_variables{ +namespace member_variables{ struct point{ enum color{ red, green, blue }; - - point() + + point() : prefered_color( blue ) , x( -1 ) , y( 2 ) @@ -42,7 +42,7 @@ unsigned int a : 1; unsigned int : 0; const unsigned int b : 11; -}; +}; unsigned int get_a(const bit_fields_t& inst); void set_a( bit_fields_t& inst, unsigned int new_value ); @@ -55,17 +55,17 @@ } } - struct variable_t{ + struct variable_t{ variable_t() : value(-9){} - int value; + int value; }; int get_ivars_item( int index ){ return ivars[index]; } - + const variable_t vars[3]; - int ivars[10]; + int ivars[10]; int ivars2[10]; }; @@ -78,10 +78,10 @@ }; struct tree_node_t{ - + data_t *data; tree_node_t *left; - tree_node_t *right; + tree_node_t *right; const tree_node_t *parent; tree_node_t(const tree_node_t* parent=0) @@ -90,7 +90,7 @@ , right( 0 ) , parent( parent ) {} - + ~tree_node_t(){ std::cout << "\n~tree_node_t"; } @@ -108,7 +108,7 @@ fundamental_t( EFruit& fruit, const int& i ) : m_fruit( fruit ), m_i( i ) {} - + EFruit& m_fruit; const int& m_i; }; @@ -151,5 +151,17 @@ } +namespace ctypes{ + struct image_t{ + image_t(){ + data = new int[5]; + for(int i=0; i<5; i++){ + data[i] = i; + } + } + int* data; + }; } + +} #endif//__member_variables_to_be_exported_hpp__ Modified: pyplusplus_dev/unittests/global_variables_tester.py =================================================================== --- pyplusplus_dev/unittests/global_variables_tester.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/global_variables_tester.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -5,22 +5,24 @@ import os import sys +import ctypes import unittest import fundamental_tester_base class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'global_variables' - + def __init__( self, *args ): - fundamental_tester_base.fundamental_tester_base_t.__init__( + fundamental_tester_base.fundamental_tester_base_t.__init__( self , tester_t.EXTENSION_NAME , *args ) - - def customize(self, mb ): + + def customize(self, mb ): mb.variable('non_const_var').alias = 'NonConstVar' + mb.variable( 'some_value' ).expose_address = True - def run_tests(self, module): + def run_tests(self, module): self.failUnless( module.NonConstVar == module.color.blue ) self.failUnless( module.const_var == module.color.red ) module.init_garray() @@ -28,11 +30,19 @@ for index in range( 10 ): self.failUnless( -index == module.garray[index].value ) self.failUnless( 3 == len( module.someSin ) - and module.someSin[0] == 'A' + and module.someSin[0] == 'A' and module.someSin[1] == 'B' and module.someSin[2] == '\0' ) + + self.failUnless( module.some_value == module.get_some_value_address() ) + self.failUnless( -7 == module.get_some_value() ) + x = ctypes.c_int.from_address( module.some_value ) + self.failUnless( x.value == module.get_some_value() ) + x.value = 9 + self.failUnless( x.value == module.get_some_value() == 9) + def create_suite(): - suite = unittest.TestSuite() + suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) return suite Modified: pyplusplus_dev/unittests/member_variables_tester.py =================================================================== --- pyplusplus_dev/unittests/member_variables_tester.py 2008-07-13 20:48:20 UTC (rev 1368) +++ pyplusplus_dev/unittests/member_variables_tester.py 2008-07-13 20:50:00 UTC (rev 1369) @@ -5,35 +5,39 @@ import os import sys +import ctypes import unittest import fundamental_tester_base +import pdb class tester_t(fundamental_tester_base.fundamental_tester_base_t): EXTENSION_NAME = 'member_variables' - + def __init__( self, *args ): - fundamental_tester_base.fundamental_tester_base_t.__init__( + fundamental_tester_base.fundamental_tester_base_t.__init__( self , tester_t.EXTENSION_NAME , *args ) - - def customize(self, mb ): + + def customize(self, mb ): mb.variable( 'prefered_color' ).alias = 'PreferedColor' mb.classes().always_expose_using_scope = True + image = mb.class_( 'image_t' ) + image.var( 'data' ).expose_address = True def change_default_color( self, module ): module.point.default_color = module.point.color.blue - + def change_prefered_color( self, module ): - xypoint = module.point() + xypoint = module.point() xypoint.PreferedColor = module.point.color.blue - + def set_b( self, bf, value ): bf.b = value - - def run_tests(self, module): + + def run_tests(self, module): self.failIfRaisesAny( module.point ) - xypoint = module.point() + xypoint = module.point() self.failUnless( module.point.instance_count == 1) self.failUnless( xypoint.instance_count == 1) self.failUnless( module.point.default_color == module.point.color.red) @@ -49,43 +53,52 @@ self.failUnless( 1 == bf.a ) self.failUnless( bf.b == module.get_b( bf ) ) self.failIfNotRaisesAny( lambda: self.set_b( bf, 23 ) ) - + array = module.array_t() self.failUnless( len( array.vars ) == 3 ) for i in range( len( array.vars ) ): self.failUnless( array.vars[i].value == -9 ) self.failUnless( len( array.ivars ) == 10 ) - + ivars = array.ivars del array #testing call policies for i in range(20): for index in range(10): self.failUnless( ivars[index] == -index ) - + array = module.array_t() for index in range( len(array.ivars) ): array.ivars[index] = index * index self.failUnless( array.get_ivars_item( index ) == index * index ) - + tree = module.create_tree() self.failUnless( tree.parent is None ) self.failUnless( tree.data.value == 0 ) self.failUnless( tree.right is None ) self.failUnless( tree.left ) self.failUnless( tree.left.data.value == 1 ) - + tree.right = module.create_tree() self.failUnless( tree.right.parent is None ) self.failUnless( tree.right.data.value == 0 ) self.failUnless( tree.right.right is None ) self.failUnless( tree.right.left ) self.failUnless( tree.right.left.data.value == 1 ) - + mem_var_str = module.mem_var_str_t() mem_var_str.identity( module.mem_var_str_t.class_name ) - + + image = module.image_t() + + #pdb.set_trace() + data_type = ctypes.POINTER( ctypes.c_int ) + data = data_type.from_address( image.data ) + for j in range(5): + print '%d : %d' % ( j, data[j] ) + + def create_suite(): - suite = unittest.TestSuite() + suite = unittest.TestSuite() suite.addTest( unittest.makeSuite(tester_t)) return suite @@ -93,4 +106,4 @@ unittest.TextTestRunner(verbosity=2).run( create_suite() ) if __name__ == "__main__": - run_suite() \ No newline at end of file + run_suite() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |