from __future__ import absolute_import
__author__ = "John Kirkham <kirkhamj@janelia.hhmi.org>"
__date__ = "$Dec 08, 2016 14:49:29 GMT-0500$"
import numbers
import math
import kenjutsu.format
[docs]class UnknownSliceLengthException(Exception):
"""
Raised if a slice does not have a known length.
"""
pass
[docs]def len_slice(a_slice, a_length=None):
"""
Determines how many elements a slice will contain.
Raises:
UnknownSliceLengthException: Will raise an exception if
a_slice.stop and a_length is None.
Args:
a_slice(slice): a slice to reformat.
a_length(int): a length to fill for stopping if not
provided.
Returns:
(slice): a new slice with as many values filled in as
possible.
Examples:
>>> len_slice(slice(2, None), 10)
8
>>> len_slice(slice(2, 6))
4
"""
if isinstance(a_slice, numbers.Integral):
raise TypeError(
"An integral index does not provide an object with a length."
)
new_slice = kenjutsu.format.reformat_slice(a_slice, a_length)
new_slice_size = 0
if isinstance(new_slice, slice):
if (new_slice.step > 0 and new_slice.start >= 0 and
(new_slice.stop is None or new_slice.stop < 0)):
raise UnknownSliceLengthException(
"Cannot determine slice length without a defined end"
" point. The reformatted slice was %s." % repr(new_slice)
)
elif (new_slice.step < 0 and new_slice.start < 0 and
(new_slice.stop is None or new_slice.stop >= 0)):
raise UnknownSliceLengthException(
"Cannot determine slice length without a defined start"
" point. The reformatted slice was %s." % repr(new_slice)
)
if new_slice.step < 0 and new_slice.stop is None:
new_slice = slice(new_slice.start, -1, new_slice.step)
new_slice_diff = float(new_slice.stop - new_slice.start)
new_slice_size = int(math.ceil(new_slice_diff / new_slice.step))
else:
new_slice_size = len(new_slice)
return(new_slice_size)
[docs]def len_slices(slices, lengths=None):
"""
Takes a tuple of slices and reformats them to fill in as many undefined
values as possible.
Args:
slices(tuple(slice)): a tuple of slices to reformat.
lengths(tuple(int)): a tuple of lengths to fill.
Returns:
(slice): a tuple of slices with all default
values filled if possible.
Examples:
>>> len_slices(
... (
... slice(None),
... slice(3, None),
... slice(None, 5),
... slice(None, None, 2)
... ),
... (10, 13, 15, 20)
... )
(10, 10, 5, 10)
"""
new_slices = kenjutsu.format.reformat_slices(slices, lengths)
lens = []
for each_slice in new_slices:
if not isinstance(each_slice, numbers.Integral):
lens.append(len_slice(each_slice))
lens = tuple(lens)
return(lens)