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