New slice implementation
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments. Originally I needed this type for multidimensional slicing of Numeric arrays, but I decided to round out the type, boostify it, and pass it along. Dave, please let me know if there is anything you need me to do to make this meet your standards for acceptance into Boost.Python. I should be able to answer any questions you might have as early as late tomorrow night or Wednesday. -Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments.
Not sure how much overlap there is, but have you looked into the container indexing suite for existing __getitem__, __setitem__ and __delitem__ support? Joel's code is currently only in the CVS, but will be included in the 1.31 release of boost, AFAIK. It includes support for Python slices. -- Raoul Gough. export LESS='-X'
On Tue, 2004-01-06 at 11:09, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments.
Not sure how much overlap there is,
It turns out that there isn't much. slice::get_indicies() overlaps with the indexing suite's slicing support, but in a different way such that it might be OK to keep, anyway. My object really just provides a object manager for PySliceObject, rather than provide a container of objects initialized by a slice (such as the indexing_suite does).
but have you looked into the container indexing suite for existing __getitem__, __setitem__ and __delitem__ support? Joel's code is currently only in the CVS, but will be included in the 1.31 release of boost, AFAIK. It includes support for Python slices.
Well, I've looked at the indexing suite now, and there are several problems with its slice support. 1) Non-None values of step size are silently ignored. I wrote a patch for slice_helper<>::base_get_slice_data() to throw IndexError if step size is given. 2) Does not clip slice ranges to the max/min as appropriate for slices, instead it raises IndexError. (Patch fixes this) 3) Crashes when given slice indexes that run cross to each other (in STL parlance, stop is not reachable from start). I believe that the responsibility for handling this case is in the hands of the respective policies classes. Therefore, my patch targets vector_indexing_suite vice indexing_suite for these: foo = bar[-1:0] crashes, should return empty container. (Patched) del bar[-1:0] crashes, should be a no-op. (Patched) bar[-1:0] = foo crashes. It has weird insert()-like semantics in practice for lists, but I haven't seen it documented anywhere. (Patch throws IndexError in this case since performing a slice insertion to an empty slice should be an undefined operation). -Jonathan Brandmeyer ---crash_test.py--- # Uses the existing vector_indexing_suite_ext.cpp test modul from vector_indexing_suite_ext import * foo = FloatVec() # Weird initialization, why not supported by a constructor? foo[:] = [1,2,3,4,5,6] def print_vector(foo): s = '[ ' for x in foo: s += repr(x) + ' ' s += ']' print s # Should raise IndexError, or print backwards; actually prints the # original print_vector(foo[::-1]) # Should print the original, but instead raises IndexError print_vector(foo[-10:10]) # Should print an empty vector( "[ ]"); crashes print_vector(foo[-1:0]) # Should do nothing; crashes del foo[-1:0] # I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Tue, 2004-01-06 at 11:09, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments.
Not sure how much overlap there is,
It turns out that there isn't much. slice::get_indicies() overlaps with the indexing suite's slicing support, but in a different way such that it might be OK to keep, anyway. My object really just provides a object manager for PySliceObject, rather than provide a container of objects initialized by a slice (such as the indexing_suite does).
It sounds like the interfaces may be quite different, but isn't the functionality the same? Once you have a Python slice object, you can use this to access portions of a container via __getitem__ from the indexing suite. On the other hand, if the slice object is actually one of your python::slice objects, you could use its get_indices member function to access parts of a container as well. I guess the main difference is whether this is returned via a separate container, or via iterators into the existing container. Note the potential problems from the Python side, though, if the existing container disappears while those iterators still exist. BTW, wouldn't it be a good idea to have a slice constructor that takes a PySliceObject * as parameter?
but have you looked into the container indexing suite for existing __getitem__, __setitem__ and __delitem__ support? Joel's code is currently only in the CVS, but will be included in the 1.31 release of boost, AFAIK. It includes support for Python slices.
Well, I've looked at the indexing suite now, and there are several problems with its slice support.
1) Non-None values of step size are silently ignored. I wrote a patch for slice_helper<>::base_get_slice_data() to throw IndexError if step size is given.
2) Does not clip slice ranges to the max/min as appropriate for slices, instead it raises IndexError. (Patch fixes this)
3) Crashes when given slice indexes that run cross to each other (in STL parlance, stop is not reachable from start). I believe that the responsibility for handling this case is in the hands of the respective policies classes. Therefore, my patch targets vector_indexing_suite vice indexing_suite for these: foo = bar[-1:0] crashes, should return empty container. (Patched) del bar[-1:0] crashes, should be a no-op. (Patched) bar[-1:0] = foo crashes. It has weird insert()-like semantics in practice for lists, but I haven't seen it documented anywhere. (Patch throws IndexError in this case since performing a slice insertion to an empty slice should be an undefined operation).
What I should probably also have said in my original message is that I'm working on a new version of the indexing suite. It certainly fixes some of the issues you've identified - have a look for indexing_v2 in the archives or see http://home.clara.net/raoulgough/boost/. There are actually a lot of different issues in providing sensible __getitem__ support for C++ containers (for example, take a look at the proxy support in Joel's suite, or the container_proxy wrapper in mine). Please not that I'm not trying to put you off contributing code! I just think it doesn't make sense to duplicate functionality, so you should probably be aware of the existing work taking place in this area.
-Jonathan Brandmeyer
---crash_test.py--- # Uses the existing vector_indexing_suite_ext.cpp test modul from vector_indexing_suite_ext import * foo = FloatVec() # Weird initialization, why not supported by a constructor?
That's a good question, but it isn't necessarily that easy to answer. At least, not if you want to use the container's iterator-based constructor template. e.g. std::vector has a constructor template <class InputIterator> vector(InputIterator f, InputIterator l, const Allocator& a = Allocator()) which would be the best one to use. I still haven't figured out the details of providing this.
foo[:] = [1,2,3,4,5,6] def print_vector(foo): s = '[ ' for x in foo: s += repr(x) + ' ' s += ']' print s
An easier way: def print_vec(foo): print [x for x in foo]
# Should raise IndexError, or print backwards; actually prints the # original print_vector(foo[::-1])
That would be because the step value is ignored, right? In any case, it's very useful to try this kind of test with a real Python list to see what "should" happen:
v = [1,2,3,4,5] print v[::-1] Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: sequence index must be integer
Would have to look that one up in the Python reference to see if it's documented! The indexing_v2 suite prints [5,4,3,2] which also can't really be right.
# Should print the original, but instead raises IndexError print_vector(foo[-10:10])
This works in indexing_v2
# Should print an empty vector( "[ ]"); crashes print_vector(foo[-1:0])
also works in v2
# Should do nothing; crashes del foo[-1:0]
Check.
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
v = [1,2,3,4] v[-1:0] = [7,8,9] print v [1, 2, 3, 7, 8, 9, 4]
This also works the same in v2. What I've done with the indexing_v2 suite is to try and make it perform exactly as a Python list (at least, when used with a std::vector or similar). Unfortunately, the v2 support won't make it into the next release (1.31) because I'm still messing around with some changes to it. -- Raoul Gough. export LESS='-X'
Thanks for your submission, Jonathan! I can say right off that it looks like good code but it's missing tests and docs and I can't accept it without those. I haven't been ignoring it, but wanted to wait to wait for this little debate come to some conclusions... Raoul Gough <RaoulGough@yahoo.co.uk> writes:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Tue, 2004-01-06 at 11:09, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments.
Not sure how much overlap there is,
It turns out that there isn't much. slice::get_indicies() overlaps with the indexing suite's slicing support, but in a different way such that it might be OK to keep, anyway. My object really just provides a object manager for PySliceObject, rather than provide a container of objects initialized by a slice (such as the indexing_suite does).
It sounds like the interfaces may be quite different, but isn't the functionality the same?
Not exactly, IMO.
Once you have a Python slice object, you can use this to access portions of a container via __getitem__ from the indexing suite.
Yeah, or any other Python object that supports slicing.
On the other hand, if the slice object is actually one of your python::slice objects, you could use its get_indices member function to access parts of a container as well.
You don't need get_indices:
range(10)[slice(2,6)] [2, 3, 4, 5] range(10)[slice(2,6,2)] [2, 4]
Therefore: object slice262(object x) { return x[slice(2,6,2)] } Ought to work. But since there are no tests or examples I don't understand how get_indices is supposed to be used.
What I should probably also have said in my original message is that I'm working on a new version of the indexing suite. It certainly fixes some of the issues you've identified - have a look for indexing_v2 in the archives or see http://home.clara.net/raoulgough/boost/. There are actually a lot of different issues in providing sensible __getitem__ support for C++ containers (for example, take a look at the proxy support in Joel's suite, or the container_proxy wrapper in mine).
Please not that I'm not trying to put you off contributing code! I just think it doesn't make sense to duplicate functionality, so you should probably be aware of the existing work taking place in this area.
Having a slice object seems highly valuable to me. I don't know if get_indices really belongs in it, but I'll need to hear more from Jonathan. I hope the two of you can put your heads together to integrate whatever overlapping work you may be pursuing. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Thu, 2004-01-08 at 09:42, David Abrahams wrote:
Thanks for your submission, Jonathan! I can say right off that it looks like good code but it's missing tests and docs and I can't accept it without those.
Here is a start. I think that this covers tests and examples. Also, there is another patch to make slice_nil work right for both object.slice() and freestanding slice objects. Basically I made slice_nil its own class, descended from object with only a default constructor. _ is a static const instantiation of slice_nil to serve as the shortcut. This makes slice_nil() an alias for PyNone as required for freestanding slices and differentiates it from object as required for object.slice(). I suppose I could have taken the same approach as the object.slice() implementation for separating out slice_nil, but that would have taken 12 different constructors. Even though the new semantics of slice_nil are wildly different, in practice I think that it should still be source compatable for its intended usage. The tests in object.cpp continue to work properly. WRT documentation, do you use some kind of semiautomatic doc generator or just plain html editing? Thanks, -Jonathan Brandmeyer
On Thu, 2004-01-08 at 07:22, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Tue, 2004-01-06 at 11:09, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I have written a new implementation for free-standing slice objects. This allows you to create and query slice objects that include a step-size, as well as export a form of __getitem__ and/or __setitem__ that can receive slice arguments and tuples of slice arguments.
Not sure how much overlap there is,
It turns out that there isn't much. slice::get_indicies() overlaps with the indexing suite's slicing support, but in a different way such that it might be OK to keep, anyway. My object really just provides a object manager for PySliceObject, rather than provide a container of objects initialized by a slice (such as the indexing_suite does).
It sounds like the interfaces may be quite different, but isn't the functionality the same? Once you have a Python slice object, you can use this to access portions of a container via __getitem__ from the indexing suite. On the other hand, if the slice object is actually one of your python::slice objects, you could use its get_indices member function to access parts of a container as well. I guess the main difference is whether this is returned via a separate container, or via iterators into the existing container. Note the potential problems from the Python side, though, if the existing container disappears while those iterators still exist.
That bit about container lifetime is a very good point, but what I have in mind is performing modifying operations. That is, I want to be able to write a function that uses a Python slice object to address which elements of the container that I want to operate on, such as this: double partial_sum( std::vector<double>* Foo, slice index) { slice::range<std::vector<double> > bounds; try { bounds = index.get_indicies( Foo->begin(), Foo->end()); } catch (std::invalid_argument) return 0.0; double ret = 0.0; while (bounds.start != bounds.stop) { ret += *bounds.start; std::advance( bounds.start, bounds.step); } ret += bounds.start; return ret; }
BTW, wouldn't it be a good idea to have a slice constructor that takes a PySliceObject * as parameter?
I try to avoid raw PyObject*'s whenever possible, but I think that the answer is "no". The reason is that you have no idea how to properly manage it. That is partially what the detail::new_reference<>, detail::borrowed_reference<>, and detail::new_non_null_reference<> are for, right?. Feel free to correct me if I'm wrong.
---crash_test.py--- # Uses the existing vector_indexing_suite_ext.cpp test modul from vector_indexing_suite_ext import * foo = FloatVec() # Weird initialization, why not supported by a constructor?
That's a good question, but it isn't necessarily that easy to answer. At least, not if you want to use the container's iterator-based constructor template. e.g. std::vector has a constructor
I don't think you reasonably can use those iterator-based constructors unless you have a way of creating a [begin,end) pair of generic iterators descended from boost::python::object. Something that, when dereferenced, automatically calls extract<value_type>. The 'begin' iterator would also have to trap for IndexErroror and StopIteration and compare equal to the 'end' iterator afterwords. I smell another code contribution coming in a day or so for something just like this.
template <class InputIterator> vector(InputIterator f, InputIterator l, const Allocator& a = Allocator())
which would be the best one to use. I still haven't figured out the details of providing this.
Well, I don't know much about the metaprogramming guts of either suite, but I wrote this simple template to create a preallocated vector that I initialize with extract<>(), and exported it using "injected constructors" support: template<typename Container> boost::shared_ptr<Container> create_from_pysequence( object seq) { boost::shared_ptr<Container> ret( new Container(extract<int>(seq.attr("__len__")()))); object seq_i = seq.attr("__iter__")(); for ( typename Container::iterator i = ret->begin(); i != ret->end(); ++i) { *i = extract< typename Container::value_type>( seq_i.attr("next")()); } return ret; }
An easier way:
def print_vec(foo): print [x for x in foo]
Oooh. Nice.
# Should raise IndexError, or print backwards; actually prints the # original print_vector(foo[::-1])
That would be because the step value is ignored, right?
Yes.
In any case, it's very useful to try this kind of test with a real Python list to see what "should" happen:
v = [1,2,3,4,5] print v[::-1] Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: sequence index must be integer
Would have to look that one up in the Python reference to see if it's documented! The indexing_v2 suite prints [5,4,3,2] which also can't really be right.
Try it with Python 2.3. In Python 2.2, slicing support was extended for builtin sequences to support __getitem__(slice(start,stop,step)), whereas in Python 2.2 you only have the __getslice__(start,stop) form. I think that the right way to handle negative step sizes (when you can choose the algorithm) is to use reverse iterators. The reason is that when provided a negative step, the stop value defaults to "one before the beginning" and the start value defaults to the last element. So long as you are using the [begin,end) ranges for iterators, the only way to make that work safely is with a reverse iterator and algorithm that carefully accounts for the effects of non-singular step size.
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
v = [1,2,3,4] v[-1:0] = [7,8,9] print v [1, 2, 3, 7, 8, 9, 4]
Yes, that is what happens: performing an insertion before the provided start value. However, I think that it should be an undefined operation since the expression is utter nonsense. I've looked at the source code for PyListObject, and I think that this behavior is the result of bounds limiting rather than real error checking. Furthermore if you try it with Numeric (the original source of rich slices), you will find that it is a no-op, which is what I would rather see in Boost now that I think a little more about it. See Python bug# 873305 at http://sourceforge.net/tracker/?group_id=5470 -Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Thu, 2004-01-08 at 07:22, Raoul Gough wrote:
I guess the main difference is whether this is returned via a separate container, or via iterators into the existing container. Note the potential problems from the Python side, though, if the existing container disappears while those iterators still exist.
That bit about container lifetime is a very good point, but what I have in mind is performing modifying operations. That is, I want to be able to write a function that uses a Python slice object to address which elements of the container that I want to operate on, such as this:
double partial_sum( std::vector<double>* Foo, slice index) { slice::range<std::vector<double> > bounds; try { bounds = index.get_indicies( Foo->begin(), Foo->end()); } catch (std::invalid_argument) return 0.0; double ret = 0.0; while (bounds.start != bounds.stop) { ret += *bounds.start; std::advance( bounds.start, bounds.step); } ret += bounds.start; return ret; }
Yes, I guess it makes a good deal of sense to use iterators in this case. However, how would you make use of them from Python code?
BTW, wouldn't it be a good idea to have a slice constructor that takes a PySliceObject * as parameter?
I try to avoid raw PyObject*'s whenever possible, but I think that the answer is "no". The reason is that you have no idea how to properly manage it. That is partially what the detail::new_reference<>, detail::borrowed_reference<>, and detail::new_non_null_reference<> are for, right?. Feel free to correct me if I'm wrong.
I didn't necessarily mean a raw PySliceObject. All I'm getting at is, if you want to implement __getitem__ then you will end up with a PySliceObject created by the Python interpreter. AFAICS, you don't have a way of generating one of your slice objects from this. Am I missing something here?
part = v[1::4]
calls v.__getitem__ with a PySliceObject (1, None, 4) Regarding the borrowed_reference and so on, I did things that way at first myself (I guess you just copied the existing code like I did?). Apparently the preferred (and documented) way of doing this kind of thing is via boost::python::handle instead.
---crash_test.py--- # Uses the existing vector_indexing_suite_ext.cpp test modul from vector_indexing_suite_ext import * foo = FloatVec() # Weird initialization, why not supported by a constructor?
That's a good question, but it isn't necessarily that easy to answer. At least, not if you want to use the container's iterator-based constructor template. e.g. std::vector has a constructor
I don't think you reasonably can use those iterator-based constructors unless you have a way of creating a [begin,end) pair of generic iterators descended from boost::python::object. Something that, when dereferenced, automatically calls extract<value_type>. The 'begin' iterator would also have to trap for IndexErroror and StopIteration and compare equal to the 'end' iterator afterwords. I smell another code contribution coming in a day or so for something just like this.
That would be great! I never quite convinced myself that it could be done reliably - in particular, you have to convert one from-Python parameter to two iterators before calling the constructor. You have to know somehow when to do this, and when to convert the object to a single C++ parameter (e.g. constructing vector(5)).
template <class InputIterator> vector(InputIterator f, InputIterator l, const Allocator& a = Allocator())
which would be the best one to use. I still haven't figured out the details of providing this.
Well, I don't know much about the metaprogramming guts of either suite, but I wrote this simple template to create a preallocated vector that I initialize with extract<>(), and exported it using "injected constructors" support:
template<typename Container> boost::shared_ptr<Container> create_from_pysequence( object seq) { boost::shared_ptr<Container> ret( new Container(extract<int>(seq.attr("__len__")()))); object seq_i = seq.attr("__iter__")(); for ( typename Container::iterator i = ret->begin(); i != ret->end(); ++i) { *i = extract< typename Container::value_type>( seq_i.attr("next")()); } return ret; }
What does the constructor injection look like?
An easier way:
def print_vec(foo): print [x for x in foo]
Oooh. Nice.
# Should raise IndexError, or print backwards; actually prints the # original print_vector(foo[::-1])
That would be because the step value is ignored, right?
Yes.
In any case, it's very useful to try this kind of test with a real Python list to see what "should" happen:
v = [1,2,3,4,5] print v[::-1] Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: sequence index must be integer
Would have to look that one up in the Python reference to see if it's documented! The indexing_v2 suite prints [5,4,3,2] which also can't really be right.
Try it with Python 2.3. In Python 2.2, slicing support was extended for builtin sequences to support __getitem__(slice(start,stop,step)), whereas in Python 2.2 you only have the __getslice__(start,stop) form.
Ah, OK. Just tried it in 2.3 and got [5,4,3,2,1]. Must be an off-by-one error for the None case in my __getitem__.
I think that the right way to handle negative step sizes (when you can choose the algorithm) is to use reverse iterators. The reason is that when provided a negative step, the stop value defaults to "one before the beginning" and the start value defaults to the last element. So long as you are using the [begin,end) ranges for iterators, the only way to make that work safely is with a reverse iterator and algorithm that carefully accounts for the effects of non-singular step size.
I don't try to support slices unless the container has random access (and then there's no need for a reverse iterator).
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
v = [1,2,3,4] v[-1:0] = [7,8,9] print v [1, 2, 3, 7, 8, 9, 4]
Yes, that is what happens: performing an insertion before the provided start value. However, I think that it should be an undefined operation since the expression is utter nonsense. I've looked at the source code for PyListObject, and I think that this behavior is the result of bounds limiting rather than real error checking.
I don't understand this. Assigning something into an empty slice in a container always performs an insertion. More generally, assigning a longer list to a plain slice with fewer elements performs insertion. e.g.
l = [1,2,3,4] l[3:0] = [7,8,9] print l [1, 2, 3, 7, 8, 9, 4]
so why shouldn't this be exactly the same (in this case) as
l[-1:0] = [7,8,9]
Furthermore if you try it with Numeric (the original source of rich slices), you will find that it is a no-op, which is what I would rather see in Boost now that I think a little more about it.
I haven't used Numeric before - is it documented somewhere?
See Python bug# 873305 at http://sourceforge.net/tracker/?group_id=5470
I don't see any place to enter the bug number - how do I get to see bug 873305? -- Raoul Gough. export LESS='-X'
On Thu, 2004-01-08 at 20:55, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Thu, 2004-01-08 at 07:22, Raoul Gough wrote:
double partial_sum( std::vector<double>* Foo, slice index) { slice::range<std::vector<double> > bounds; try { bounds = index.get_indicies( Foo->begin(), Foo->end()); } catch (std::invalid_argument) return 0.0; double ret = 0.0; while (bounds.start != bounds.stop) { ret += *bounds.start; std::advance( bounds.start, bounds.step); } ret += bounds.start; return ret; }
Yes, I guess it makes a good deal of sense to use iterators in this case. However, how would you make use of them from Python code?
The idea is that you don't make use of the iterators from Python (Python has no notion of an iterator pair, anyway), you use the slice object to define the portion of the container to act upon as a kind of replacement for iterator pairs. Based on this question and the one about raw PySliceObject*'s, I don't think I've explained myself enough. Here is the rest of a complete, working example that uses the existing vector_indexing_suite and the patches I've proposed. // Add in the code from the above example, plus slice.hpp, slice.cpp, // and the patches I sent for slice_nil.hpp and object_core.hpp // Also add in the injected constructor that I wrote below in the // last message #include <boost/python.hpp> #include <boost/python/slice.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <boost/python/make_constructor.hpp> BOOST_PYTHON_MODULE(vector_test) { using namespace boost::python; class_<std::vector<double> >( "float_vector") .def( "__init__", make_constructor( create_from_pysequence<std::vector<double> >)) .def( vector_indexing_suite<std::vector<double> >()) .def( "partial_sum", &partial_sum) ; } ----end file---- And now, in Python you can do this:
x = float_vector( [1,2,3,4,5,6]) x.partial_sum( slice(None,None)) 21 x.partial_sum( slice(3,-1)) 9 x[3:].partial_sum(slice(None,None)) 15
BTW, wouldn't it be a good idea to have a slice constructor that takes a PySliceObject * as parameter?
I try to avoid raw PyObject*'s whenever possible, but I think that the answer is "no". The reason is that you have no idea how to properly manage it. That is partially what the detail::new_reference<>, detail::borrowed_reference<>, and detail::new_non_null_reference<> are for, right?. Feel free to correct me if I'm wrong.
I didn't necessarily mean a raw PySliceObject. All I'm getting at is, if you want to implement __getitem__ then you will end up with a PySliceObject created by the Python interpreter. AFAICS, you don't have a way of generating one of your slice objects from this. Am I missing something here?
part = v[1::4]
calls v.__getitem__ with a PySliceObject (1, None, 4)
*I* won't end up with a PySliceObject created by the Python interpreter, I will end up with a boost::python::slice object manager that has been automatically converted by def() and/or class_::def() from the original PySliceObject.
---crash_test.py--- # Uses the existing vector_indexing_suite_ext.cpp test modul from vector_indexing_suite_ext import * foo = FloatVec() # Weird initialization, why not supported by a constructor?
Well, I don't know much about the metaprogramming guts of either suite, but I wrote this simple template to create a preallocated vector that I initialize with extract<>(), and exported it using "injected constructors" support:
template<typename Container> boost::shared_ptr<Container> create_from_pysequence( object seq) { boost::shared_ptr<Container> ret( new Container(extract<int>(seq.attr("__len__")()))); object seq_i = seq.attr("__iter__")(); for ( typename Container::iterator i = ret->begin(); i != ret->end(); ++i) { *i = extract< typename Container::value_type>( seq_i.attr("next")()); } return ret; }
What does the constructor injection look like?
See above, and look at boost/libs/python/test/injected.{cpp,py}.
Ah, OK. Just tried it in 2.3 and got [5,4,3,2,1]. Must be an off-by-one error for the None case in my __getitem__.
I think that the right way to handle negative step sizes (when you can choose the algorithm) is to use reverse iterators. The reason is that when provided a negative step, the stop value defaults to "one before the beginning" and the start value defaults to the last element. So long as you are using the [begin,end) ranges for iterators, the only way to make that work safely is with a reverse iterator and algorithm that carefully accounts for the effects of non-singular step size.
I don't try to support slices unless the container has random access (and then there's no need for a reverse iterator).
Why not? There is no reason whatsoever not to support every container with bidirectional iterators. You can even slice on maps if you want to, although such a thing has been forbidden for python dict's.
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
v = [1,2,3,4] v[-1:0] = [7,8,9] print v [1, 2, 3, 7, 8, 9, 4]
Yes, that is what happens: performing an insertion before the provided start value. However, I think that it should be an undefined operation since the expression is utter nonsense. I've looked at the source code for PyListObject, and I think that this behavior is the result of bounds limiting rather than real error checking.
I don't understand this. Assigning something into an empty slice in a container always performs an insertion. More generally, assigning a longer list to a plain slice with fewer elements performs insertion. e.g.
No, assigning any sequence to a slice by calling object.__setslice__(slice, sequence) replaces the old slice with the values of the new slice IF the slice uses either -1 or 1 (either implicitly or explicitly) for its step size. If the step size is non-singular, then the sizes of the slice and the sequence must be identical.
l = [1,2,3,4] l[3:0] = [7,8,9]
Think about what this expression means: Starting at the fourth element inclusive, and ending at the first element, exclusive with an increment of forward 1, delete elements and replace them with the elements of the list [7,8,9]. That's like starting off by calling std::list::delete(start, stop) with a 'stop' iterator that is not reachable from 'start'! The issue isn't that you are performing an insertion after a well-defined point in the sequence, it is that you are performing a replacement of an undefined section of the sequence.
I haven't used Numeric before - is it documented somewhere?
See numpy.sourceforge.net and in Debian the python2.2-numeric, python2.3-numeric, and python-numeric-tutorial packages.
See Python bug# 873305 at http://sourceforge.net/tracker/?group_id=5470
I don't see any place to enter the bug number - how do I get to see bug 873305?
Sorry, that was my fault. Try this one: http://sourceforge.net/tracker/index.php?func=detail&aid=873305&group_id=5470&atid=305470 -Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Thu, 2004-01-08 at 20:55, Raoul Gough wrote: [snip]
part = v[1::4]
calls v.__getitem__ with a PySliceObject (1, None, 4)
*I* won't end up with a PySliceObject created by the Python interpreter, I will end up with a boost::python::slice object manager that has been automatically converted by def() and/or class_::def() from the original PySliceObject.
Well, that's the bit I don't understand. How do you create a boost::python::slice object from a PySliceObject without a suitable constructor? Unless you're just not interested in covering this case. [snip]
I don't try to support slices unless the container has random access (and then there's no need for a reverse iterator).
Why not? There is no reason whatsoever not to support every container with bidirectional iterators. You can even slice on maps if you want to, although such a thing has been forbidden for python dict's.
Sure it's possible. I didn't see much need to do it though. For instance, if you have a C++ std::list exposed to Python, do you really want to be able to do:
cxx_list[87]
or
cxx_list[20:80:4]
Maybe you do, but I think you would probably be better off with std::vector.
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
> v = [1,2,3,4] > v[-1:0] = [7,8,9] > print v [1, 2, 3, 7, 8, 9, 4]
Yes, that is what happens: performing an insertion before the provided start value. However, I think that it should be an undefined operation since the expression is utter nonsense. I've looked at the source code for PyListObject, and I think that this behavior is the result of bounds limiting rather than real error checking.
I don't understand this. Assigning something into an empty slice in a container always performs an insertion. More generally, assigning a longer list to a plain slice with fewer elements performs insertion. e.g.
No, assigning any sequence to a slice by calling object.__setslice__(slice, sequence) replaces the old slice with the values of the new slice IF the slice uses either -1 or 1 (either implicitly or explicitly) for its step size. If the step size is non-singular, then the sizes of the slice and the sequence must be identical.
The lack of a step size is what I was getting at with "plain slice". I guess I should have been more precise.
l = [1,2,3,4] l[3:0] = [7,8,9]
Think about what this expression means: Starting at the fourth element inclusive, and ending at the first element, exclusive with an increment of forward 1, delete elements and replace them with the elements of the list [7,8,9]. That's like starting off by calling std::list::delete(start, stop) with a 'stop' iterator that is not reachable from 'start'!
But that's not the way *Python* does things. Are you saying that lst[3:0] should just crash the interpreter? That's what a C++ algorithm would probably do with that kind of input.
The issue isn't that you are performing an insertion after a well-defined point in the sequence, it is that you are performing a replacement of an undefined section of the sequence.
I would argue that the section of the sequence *is* well defined.
I haven't used Numeric before - is it documented somewhere?
See numpy.sourceforge.net and in Debian the python2.2-numeric, python2.3-numeric, and python-numeric-tutorial packages.
From what I can see, the arrays can't change in length, so obviously
they don't support insertion, or replacing a shorter slice with a longer sequence.
See Python bug# 873305 at http://sourceforge.net/tracker/?group_id=5470
I don't see any place to enter the bug number - how do I get to see bug 873305?
Sorry, that was my fault. Try this one: http://sourceforge.net/tracker/index.php?func=detail&aid=873305&group_id=5470&atid=305470
I don't think I agree with what you're saying here. Would you agree that __getitem__ from e.g. lst[4:2] should be an empty sequence? Quoting from http://www.python.org/doc/current/lib/typesseq.html "(4) [...] If i is greater than or equal to j, the slice is empty." I think that's pretty clear for __getitem__. So now the question is, what is the result of replacing an empty slice in a container with a non-empty sequence? If the container supports insertion, inserting the sequence seems logical enough to me. -- Raoul Gough. export LESS='-X'
On Fri, 2004-01-09 at 08:19, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Thu, 2004-01-08 at 20:55, Raoul Gough wrote: [snip]
part = v[1::4]
calls v.__getitem__ with a PySliceObject (1, None, 4)
*I* won't end up with a PySliceObject created by the Python interpreter, I will end up with a boost::python::slice object manager that has been automatically converted by def() and/or class_::def() from the original PySliceObject.
Well, that's the bit I don't understand. How do you create a boost::python::slice object from a PySliceObject without a suitable constructor? Unless you're just not interested in covering this case.
What I believe happens is that PySlice_Check() is called on the PyObject* that is being tested to see if it can be wrapped. If true, then a slice object is created by calling boost::python::slice( detail::borrowed_reference(PyObject*)). Then, if you want to get the objects that the slice was defined with by calling slice::start(), slice::stop(), or slice::step(), each of those functions must cast the wrapped PyObject* to a PySliceObject*. This is guaranteed to be safe since the slice object is never created without either a) creating a new PySliceObject, or b) calling PySlice_Check() first. To the best of my knowledge, that's how most of the object managers work. Can you give me a complete example where you need this extra constructor? Maybe then I'll know how to answer you better.
# I think this should raise IndexError; crashes. foo[-1:0] = [7, 8, 9]
With a real python list, it inserts 7, 8, 9 before the last element:
>> v = [1,2,3,4] >> v[-1:0] = [7,8,9] >> print v [1, 2, 3, 7, 8, 9, 4]
Yes, that is what happens: performing an insertion before the provided start value. However, I think that it should be an undefined operation since the expression is utter nonsense. I've looked at the source code for PyListObject, and I think that this behavior is the result of bounds limiting rather than real error checking.
I don't understand this. Assigning something into an empty slice in a container always performs an insertion. More generally, assigning a longer list to a plain slice with fewer elements performs insertion. e.g.
No, assigning any sequence to a slice by calling object.__setslice__(slice, sequence) replaces the old slice with the values of the new slice IF the slice uses either -1 or 1 (either implicitly or explicitly) for its step size. If the step size is non-singular, then the sizes of the slice and the sequence must be identical.
The lack of a step size is what I was getting at with "plain slice". I guess I should have been more precise.
l = [1,2,3,4] l[3:0] = [7,8,9]
Think about what this expression means: Starting at the fourth element inclusive, and ending at the first element, exclusive with an increment of forward 1, delete elements and replace them with the elements of the list [7,8,9]. That's like starting off by calling std::list::delete(start, stop) with a 'stop' iterator that is not reachable from 'start'!
But that's not the way *Python* does things. Are you saying that lst[3:0] should just crash the interpreter? That's what a C++ algorithm would probably do with that kind of input.
No, I'm saying that lst[3:0] should be empty. The difference is that in the Python case we can immediately determine that the stop position is not reachable from the start position and take appropriate action: Do Nothing.
The issue isn't that you are performing an insertion after a well-defined point in the sequence, it is that you are performing a replacement of an undefined section of the sequence.
I would argue that the section of the sequence *is* well defined.
See Python bug# 873305 at
http://sourceforge.net/tracker/index.php?func=detail&aid=873305&group_id=5470&atid=305470
I don't think I agree with what you're saying here. Would you agree that __getitem__ from e.g. lst[4:2] should be an empty sequence?
Quoting from http://www.python.org/doc/current/lib/typesseq.html
"(4) [...] If i is greater than or equal to j, the slice is empty."
Section 5.3.3 of the Python Language Reference includes: "The slicing now selects all items with index k such that i <= k < j where i and j are the specified lower and upper bounds. This may be an empty sequence." I claim that not only are there no elements to be replaced in the case of __setitem__ with such a slice, but that this doesn't clearly define a point to insert new elements, either.
I think that's pretty clear for __getitem__.
Yes, and my patch doesn't modify that behavior.
So now the question is, what is the result of replacing an empty slice in a container with a non-empty sequence? If the container supports insertion, inserting the sequence seems logical enough to me.
So how do you define the point to perform the insertion? If the user asks to replace every element that is greater than or equal to the fourth and less than the first element, where do you place the new sequence? The current action for a built-in list is to range-limit the stop point to be not less than the start point, but I think that is just for safety rather than an API decision, and that it is wrong. -Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I don't think I agree with what you're saying here. Would you agree that __getitem__ from e.g. lst[4:2] should be an empty sequence?
Quoting from http://www.python.org/doc/current/lib/typesseq.html
"(4) [...] If i is greater than or equal to j, the slice is empty."
Section 5.3.3 of the Python Language Reference includes: "The slicing now selects all items with index k such that i <= k < j where i and j are the specified lower and upper bounds. This may be an empty sequence."
I claim that not only are there no elements to be replaced in the case of __setitem__ with such a slice, but that this doesn't clearly define a point to insert new elements, either.
Doesn't the following pretty much settle the question of what the Pythonic behavior is? $ python Python 2.3.2 (#1, Nov 14 2003, 18:13:01) [GCC 3.3.1 (cygming special)] on cygwin Type "help", "copyright", "credits" or "license" for more information.
l = range(100,120) l[5:2] = range(6) l [100, 101, 102, 103, 104, 0, 1, 2, 3, 4, 5, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119]
-- Dave Abrahams Boost Consulting www.boost-consulting.com
On Fri, 2004-01-09 at 11:39, David Abrahams wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I don't think I agree with what you're saying here. Would you agree that __getitem__ from e.g. lst[4:2] should be an empty sequence?
Quoting from http://www.python.org/doc/current/lib/typesseq.html
"(4) [...] If i is greater than or equal to j, the slice is empty."
Section 5.3.3 of the Python Language Reference includes: "The slicing now selects all items with index k such that i <= k < j where i and j are the specified lower and upper bounds. This may be an empty sequence."
I claim that not only are there no elements to be replaced in the case of __setitem__ with such a slice, but that this doesn't clearly define a point to insert new elements, either.
Doesn't the following pretty much settle the question of what the Pythonic behavior is?
$ python Python 2.3.2 (#1, Nov 14 2003, 18:13:01) [GCC 3.3.1 (cygming special)] on cygwin Type "help", "copyright", "credits" or "license" for more information.
l = range(100,120) l[5:2] = range(6) l [100, 101, 102, 103, 104, 0, 1, 2, 3, 4, 5, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119]
Yes it does. Maybe I'm being arrogant here, but I think that behavior is wrong, and I think it strongly enough that I submitted a patch to Python to change it. I think at this point we should just let this argument rest for a bit pending the resolution of the patch I submitted to Python, or at least, to move any additional comments to the sourceforge tracker for that patch. -Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Fri, 2004-01-09 at 08:19, Raoul Gough wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Thu, 2004-01-08 at 20:55, Raoul Gough wrote: [snip]
part = v[1::4]
calls v.__getitem__ with a PySliceObject (1, None, 4)
*I* won't end up with a PySliceObject created by the Python interpreter, I will end up with a boost::python::slice object manager that has been automatically converted by def() and/or class_::def() from the original PySliceObject.
Well, that's the bit I don't understand. How do you create a boost::python::slice object from a PySliceObject without a suitable constructor? Unless you're just not interested in covering this case.
What I believe happens is that PySlice_Check() is called on the PyObject* that is being tested to see if it can be wrapped. If true, then a slice object is created by calling boost::python::slice( detail::borrowed_reference(PyObject*)). Then, if you want to get the objects that the slice was defined with by calling slice::start(), slice::stop(), or slice::step(), each of those functions must cast the wrapped PyObject* to a PySliceObject*. This is guaranteed to be safe since the slice object is never created without either a) creating a new PySliceObject, or b) calling PySlice_Check() first. To the best of my knowledge, that's how most of the object managers work.
Can you give me a complete example where you need this extra constructor? Maybe then I'll know how to answer you better.
Sorry - my mistake! I missed the following in your code (at the end of the slice class): // This declaration, in conjunction with the specialization of // object_manager_traits<> below, allows C++ functions accepting // slice arguments to be called from from Python. These // constructors should never be used in client code. BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, object) I thought I'd seen all of the constructors, but missed this one, and searching for PySliceObject didn't find anything of course. Thanks for clarifying this for me. [snip]
So how do you define the point to perform the insertion? If the user asks to replace every element that is greater than or equal to the fourth and less than the first element, where do you place the new sequence?
Well, that's an interesting question when you put it like that, independant of implementation issues. In practice, I guess it's just natural that it should go at the starting index, since you would have initialized some kind of variable to this before determining that you're already outside the range of the slice. I know that's how my code works. -- Raoul Gough. export LESS='-X'
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
Can you give me a complete example where you need this extra constructor? Maybe then I'll know how to answer you better.
Sorry - my mistake! I missed the following in your code (at the end of the slice class):
// This declaration, in conjunction with the specialization of // object_manager_traits<> below, allows C++ functions accepting // slice arguments to be called from from Python. These // constructors should never be used in client code. BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, object)
I thought I'd seen all of the constructors, but missed this one, and searching for PySliceObject didn't find anything of course. Thanks for clarifying this for me.
[snip]
So how do you define the point to perform the insertion? If the user asks to replace every element that is greater than or equal to the fourth and less than the first element, where do you place the new sequence?
Well, that's an interesting question when you put it like that, independant of implementation issues. In practice, I guess it's just natural that it should go at the starting index, since you would have initialized some kind of variable to this before determining that you're already outside the range of the slice. I know that's how my code works.
You guys'll be sure to let me know if/when you come to some consensus about this stuff, right? -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Fri, 2004-01-09 at 22:12, David Abrahams wrote:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
Can you give me a complete example where you need this extra constructor? Maybe then I'll know how to answer you better.
Sorry - my mistake! I missed the following in your code (at the end of the slice class):
// This declaration, in conjunction with the specialization of // object_manager_traits<> below, allows C++ functions accepting // slice arguments to be called from from Python. These // constructors should never be used in client code. BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, object)
I thought I'd seen all of the constructors, but missed this one, and searching for PySliceObject didn't find anything of course. Thanks for clarifying this for me.
[snip]
So how do you define the point to perform the insertion? If the user asks to replace every element that is greater than or equal to the fourth and less than the first element, where do you place the new sequence?
Well, that's an interesting question when you put it like that, independant of implementation issues. In practice, I guess it's just natural that it should go at the starting index, since you would have initialized some kind of variable to this before determining that you're already outside the range of the slice. I know that's how my code works.
You guys'll be sure to let me know if/when you come to some consensus about this stuff, right?
If Mr. Gough doesn't have anything else, I think we've come to an agreement. For the documentation format, do you use some kind of semiautomatic system? If not, do you mind if I use a WYSIWYG system such as the html editor in Mozilla? To be honest, I don't know much about html code. Thanks, Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Fri, 2004-01-09 at 22:12, David Abrahams wrote:
Raoul Gough <RaoulGough@yahoo.co.uk> writes:
Can you give me a complete example where you need this extra constructor? Maybe then I'll know how to answer you better.
Sorry - my mistake! I missed the following in your code (at the end of the slice class):
// This declaration, in conjunction with the specialization of // object_manager_traits<> below, allows C++ functions accepting // slice arguments to be called from from Python. These // constructors should never be used in client code. BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(slice, object)
I thought I'd seen all of the constructors, but missed this one, and searching for PySliceObject didn't find anything of course. Thanks for clarifying this for me.
[snip]
So how do you define the point to perform the insertion? If the user asks to replace every element that is greater than or equal to the fourth and less than the first element, where do you place the new sequence?
Well, that's an interesting question when you put it like that, independant of implementation issues. In practice, I guess it's just natural that it should go at the starting index, since you would have initialized some kind of variable to this before determining that you're already outside the range of the slice. I know that's how my code works.
You guys'll be sure to let me know if/when you come to some consensus about this stuff, right?
If Mr. Gough doesn't have anything else, I think we've come to an agreement.
For the documentation format, do you use some kind of semiautomatic system?
Sadly, no. Maybe the next time around it'll be RestructuredText. You should feel free to use ReST for your docs, though. libs/python/todo.txt and libs/python/todo.html are done that way. Use a .rst extension for the ReST file, though, if you do that.
If not, do you mind if I use a WYSIWYG system such as the html editor in Mozilla? To be honest, I don't know much about html code.
No, I don't mind, as long as the editor doesn't cruft up the HTML with a lot of cr*pola. The output should have "logical coherence", e.g. no fixed positions and sizes for things that should be relative, etc. -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Tue, 2004-01-13 at 10:27, David Abrahams wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
For the documentation format, do you use some kind of semiautomatic system?
Sadly, no. Maybe the next time around it'll be RestructuredText. You should feel free to use ReST for your docs, though. libs/python/todo.txt and libs/python/todo.html are done that way. Use a .rst extension for the ReST file, though, if you do that.
If not, do you mind if I use a WYSIWYG system such as the html editor in Mozilla? To be honest, I don't know much about html code.
No, I don't mind, as long as the editor doesn't cruft up the HTML with a lot of cr*pola. The output should have "logical coherence", e.g. no fixed positions and sizes for things that should be relative, etc.
I basically wrote this page by editing the documentation page for the list class. Here is a first shot at it, please review for technical completeness. There are a few formatting tweaks that I still need to make, but I think that it should be OK otherwise. Some of the formatting information is specified relative to the page, so to view it properly you will want to copy the file to boost/libs/python/doc/v2/slice.html Thanks, Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
I basically wrote this page by editing the documentation page for the list class.
I can see that: <pre>namespace boost { namespace python<br>{<br> class list : public ^^^^ BTW, compare this with the HTML source for list.html and you'll see one of the main reasons people hate HTML to be edited with WYSIWYG tools. Sticking <br> tags in a <pre> block is just insane. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
BTW, compare this with the HTML source for list.html and you'll see one of the main reasons people hate HTML to be edited with WYSIWYG tools. Sticking <br> tags in a <pre> block is just insane.
Not that you're insane; it's your editor ;-) Note also: slice::get_indicies(RandomAccessIterator const& begin, RandomAccessIterator const& end); Is probably too wide and should be wrapped: slice::get_indicies( RandomAccessIterator const& begin, RandomAccessIterator const& end); -- Dave Abrahams Boost Consulting www.boost-consulting.com
On Wed, 2004-01-14 at 00:02, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BTW, compare this with the HTML source for list.html and you'll see one of the main reasons people hate HTML to be edited with WYSIWYG tools. Sticking <br> tags in a <pre> block is just insane.
Not that you're insane; it's your editor ;-)
I understand. Its fixed, I think.
Note also:
slice::get_indicies(RandomAccessIterator const& begin, RandomAccessIterator const& end);
Is probably too wide and should be wrapped:
slice::get_indicies( RandomAccessIterator const& begin, RandomAccessIterator const& end);
Done. Attached are diffs for boost/libs/python/doc/v2/reference.html, object.html, and the new file slice.html.
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Wed, 2004-01-14 at 00:02, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BTW, compare this with the HTML source for list.html and you'll see one of the main reasons people hate HTML to be edited with WYSIWYG tools. Sticking tags in a block is just insane.
Not that you're insane; it's your editor ;-)
I understand. Its fixed, I think.
Note also:
slice::get_indicies(RandomAccessIterator const& begin, RandomAccessIterator const& end);
Is probably too wide and should be wrapped:
slice::get_indicies( RandomAccessIterator const& begin, RandomAccessIterator const& end);
Done.
Much better. Preformatted text is still too wide in places (including the one I pointed at above, sorry). Also, the Throws clause from get_indicies leaves out which Python exception is raised. You should use the "raise" term as defined here: http://www.boost.org/libs/python/doc/v2/definitions.html#raise So you can avoid writing error_already_set over and over. You can use a hyperlink if you think it's needed for clarity. I think with those small changes it will be ready. Send me your sourceforge user id (the textual one) and I'll give you Boost CVS access so you can check this in yourself. -- Dave Abrahams Boost Consulting www.boost-consulting.com
I apologize for not getting back to you sooner on this. On Mon, 2004-01-19 at 12:13, David Abrahams wrote:
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
On Wed, 2004-01-14 at 00:02, David Abrahams wrote:
David Abrahams <dave@boost-consulting.com> writes:
BTW, compare this with the HTML source for list.html and you'll see one of the main reasons people hate HTML to be edited with WYSIWYG tools. Sticking tags in a block is just insane.
Not that you're insane; it's your editor ;-)
I understand. Its fixed, I think.
Note also:
slice::get_indicies(RandomAccessIterator const& begin, RandomAccessIterator const& end);
Is probably too wide and should be wrapped:
slice::get_indicies( RandomAccessIterator const& begin, RandomAccessIterator const& end);
Done.
Much better. Preformatted text is still too wide in places (including the one I pointed at above, sorry).
Fixed. Text within <pre> blocks is formatted to stay within 80 columns.
Also, the Throws clause from get_indicies leaves out which Python exception is raised. You should use the "raise" term as defined here:
http://www.boost.org/libs/python/doc/v2/definitions.html#raise
Done.
So you can avoid writing error_already_set over and over. You can use a hyperlink if you think it's needed for clarity.
I think with those small changes it will be ready. Send me your sourceforge user id (the textual one) and I'll give you Boost CVS access so you can check this in yourself.
My Sourceforge ID is "jbrandmeyer". There is also (hopefully only) one remaining detail. How exactly is the testsuite driven? Or, phrased differently, what do I need to do to get the tests to run automatically when you execute `bjam test`? Thanks, Jonathan Brandmeyer
Jonathan Brandmeyer <jbrandmeyer@earthlink.net> writes:
sourceforge user id (the textual one) and I'll give you Boost CVS access so you can check this in yourself.
My Sourceforge ID is "jbrandmeyer".
Added.
There is also (hopefully only) one remaining detail. How exactly is the testsuite driven? Or, phrased differently, what do I need to do to get the tests to run automatically when you execute `bjam test`?
If it isn't obvious after looking at libs/python/test/Jamfile, let me know and I'll give you more detail. -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hi, I need to use the new conversion -> register_ptr_to_python.hpp in my project and register_ptr_to_python.hpp is only available in the CVS version of the boost. So what I did is I got the cvs version and was trying to add the project file into my project using Microsoft VC++ 7.0. For that I was trying to include the boost/libs/python/build/VisualStudio/"project file". It was asking me whether it should be converted for VC7.0. When you do that it says the file is corrupted "unable to load the project". Please let me know how to get the project file of boost.python on VC++ 7.0. ~regards, Aashish
participants (5)
-
aashish -
David Abrahams -
Jonathan Brandmeyer -
Mike Rovner -
Raoul Gough