Package pyplusplus :: Package code_repository :: Module convenience

Source Code for Module pyplusplus.code_repository.convenience

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """ 
  7  This file contains C++ code needed to export one dimensional static arrays. 
  8  """ 
  9   
 10   
 11  namespace = "pyplusplus::convenience" 
 12   
 13  file_name = "__convenience.pypp.hpp" 
 14   
 15  code = \ 
 16  """// Copyright 2004-2008 Roman Yakovenko. 
 17  // Distributed under the Boost Software License, Version 1.0. (See 
 18  // accompanying file LICENSE_1_0.txt or copy at 
 19  // http://www.boost.org/LICENSE_1_0.txt) 
 20   
 21  #ifndef __convenience_pyplusplus_hpp__ 
 22  #define __convenience_pyplusplus_hpp__ 
 23   
 24  #include "boost/python.hpp" 
 25   
 26  namespace pyplusplus{ namespace convenience{ 
 27   
 28  //TODO: Replace index_type with Boost.Python defined ssize_t type. 
 29  //      This should be done by checking Python and Boost.Python version. 
 30  typedef int index_type; 
 31   
 32  inline void 
 33  raise_error( PyObject *exception, const char *message ){ 
 34     PyErr_SetString(exception, message); 
 35     boost::python::throw_error_already_set(); 
 36  } 
 37   
 38  inline index_type sequence_len(boost::python::object const& obj){ 
 39      if( !PySequence_Check( obj.ptr() ) ){ 
 40          raise_error( PyExc_TypeError, "Sequence expected" ); 
 41      } 
 42   
 43      index_type result = PyObject_Length( obj.ptr() ); 
 44      if( PyErr_Occurred() ){ 
 45          boost::python::throw_error_already_set(); 
 46      } 
 47      return result; 
 48  } 
 49   
 50  inline void 
 51  ensure_sequence( boost::python::object seq, index_type expected_length=-1 ){ 
 52      index_type length = sequence_len( seq ); 
 53      if( expected_length != -1 && length != expected_length ){ 
 54          std::stringstream err; 
 55          err << "Expected sequence length is " << expected_length << ". " 
 56              << "Actual sequence length is " << length << "."; 
 57          raise_error( PyExc_ValueError, err.str().c_str() ); 
 58      } 
 59  } 
 60   
 61  template< class ExpectedType > 
 62  void ensure_uniform_sequence( boost::python::object seq, index_type expected_length=-1 ){ 
 63      ensure_sequence( seq, expected_length ); 
 64   
 65      index_type length = sequence_len( seq ); 
 66      for( index_type index = 0; index < length; ++index ){ 
 67          boost::python::object item = seq[index]; 
 68   
 69          boost::python::extract<ExpectedType> type_checker( item ); 
 70          if( !type_checker.check() ){ 
 71              std::string expected_type_name( boost::python::type_id<ExpectedType>().name() ); 
 72   
 73              std::string item_type_name("different"); 
 74              PyObject* item_impl = item.ptr(); 
 75              if( item_impl && item_impl->ob_type && item_impl->ob_type->tp_name ){ 
 76                  item_type_name = std::string( item_impl->ob_type->tp_name ); 
 77              } 
 78   
 79              std::stringstream err; 
 80              err << "Sequence should contain only items with type \\"" << expected_type_name << "\\". " 
 81                  << "Item at position " << index << " has \\"" << item_type_name << "\\" type."; 
 82              raise_error( PyExc_ValueError, err.str().c_str() ); 
 83          } 
 84      } 
 85  } 
 86   
 87  template< class Iterator, class Inserter > 
 88  void copy_container( Iterator begin, Iterator end, Inserter inserter ){ 
 89      for( Iterator index = begin; index != end; ++index ) 
 90          inserter( *index ); 
 91  } 
 92   
 93  template< class Inserter > 
 94  void copy_sequence( boost::python::object const& seq, Inserter inserter ){ 
 95      index_type length = sequence_len( seq ); 
 96      for( index_type index = 0; index < length; ++index ){ 
 97          inserter = seq[index]; 
 98      } 
 99  } 
100   
101  template< class Inserter, class TItemType > 
102  void copy_sequence( boost::python::object const& seq, Inserter inserter, boost::type< TItemType > ){ 
103      index_type length = sequence_len( seq ); 
104      for( index_type index = 0; index < length; ++index ){ 
105          boost::python::object item = seq[index]; 
106          inserter = boost::python::extract< TItemType >( item ); 
107      } 
108  } 
109   
110  struct list_inserter{ 
111      list_inserter( boost::python::list& py_list ) 
112      : m_py_list( py_list ) 
113      {} 
114       
115      template< class T > 
116      void operator()( T const & value ){ 
117          m_py_list.append( value ); 
118      } 
119  private: 
120      boost::python::list& m_py_list; 
121  }; 
122   
123  template < class T > 
124  struct array_inserter_t{ 
125      array_inserter_t( T* array, index_type size ) 
126      : m_array( array ) 
127        , m_curr_pos( 0 ) 
128        , m_size( size ) 
129      {} 
130   
131      void insert( const T& item ){ 
132          if( m_size <= m_curr_pos ){ 
133              std::stringstream err; 
134              err << "Index out of range. Array size is" << m_size << ", " 
135                  << "current position is" << m_curr_pos << "."; 
136              raise_error( PyExc_ValueError, err.str().c_str() ); 
137          } 
138          m_array[ m_curr_pos ] = item; 
139          m_curr_pos += 1; 
140      } 
141   
142      array_inserter_t<T>&  
143      operator=( boost::python::object const & item ){ 
144          insert( boost::python::extract< T >( item ) ); 
145          return *this; 
146      } 
147       
148  private: 
149      T* m_array; 
150      index_type m_curr_pos; 
151      const index_type m_size; 
152  }; 
153   
154  template< class T> 
155  array_inserter_t<T> array_inserter( T* array, index_type size ){ 
156      return array_inserter_t<T>( array, size ); 
157  } 
158   
159  inline boost::python::object  
160  get_out_argument( boost::python::object result, const char* arg_name ){ 
161      if( !PySequence_Check( result.ptr() ) ){ 
162          return result; 
163      }     
164      boost::python::object cls = boost::python::getattr( result, "__class__" ); 
165      boost::python::object cls_name = boost::python::getattr( cls, "__name__" ); 
166      std::string name = boost::python::extract< std::string >( cls_name ); 
167      if( "named_tuple" == name ){ 
168          return boost::python::getattr( result, arg_name );     
169      } 
170      else{ 
171          return result; 
172      } 
173       
174  } 
175   
176  inline boost::python::object  
177  get_out_argument( boost::python::object result, index_type index ){ 
178      if( !PySequence_Check( result.ptr() ) ){ 
179          return result; 
180      }     
181      boost::python::object cls = boost::python::getattr( result, "__class__" ); 
182      boost::python::object cls_name = boost::python::getattr( cls, "__name__" ); 
183      std::string name = boost::python::extract< std::string >( cls_name ); 
184      if( "named_tuple" == name ){ 
185          return result[ index ];     
186      } 
187      else{ 
188          return result; 
189      } 
190  } 
191   
192  } /*pyplusplus*/ } /*convenience*/ 
193   
194  namespace pyplus_conv = pyplusplus::convenience; 
195   
196  #endif//__convenience_pyplusplus_hpp__ 
197   
198  """ 
199