# steptools

`steptools.range` is as a drop-in replacement for `range`, adding with support for anything that behaves reasonably like a number, including floats, `datetime.datetime`, `datetime.date`, `fractions.Fraction`, and `decimal.Decimal`.

if `stop is None`, `start` will be used as `stop` and `start` will be “zero” created with `type(start)()`.

Similar to `range`, generated items are EXCLUSIVE of `stop`. `inclusive=True` allows stop to be returned, assuming it’s a multiple of step.

`type(step)()` should construct a “zero” version of `step` which has no result if added to `start`. If this does not work, set `zero_step` explicitly.

## Examples

`steptools.range` can act as a drop-in replacement for `range` to iterate over ints. `range` is probably faster!

```>>> list(range(3))
[0, 1, 2]
>>> list(range(3, inclusive=True))
[0, 1, 2, 3]
>>> list(range(5, -3, -2))
[5, 3, 1, -1]
>>> list(range(1.1, 1.5, .2))
[1.1, 1.3]
```

`steptools.range` can iterate over over `datetime.datetime` and `datetime.date` objects using a `datetime.timedelta` as the step.

```>>> from datetime import datetime, timedelta
>>> list(range(datetime(2000, 1, 1), datetime(1999,12,30),
...     timedelta(days=-1)))
[datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(1999, 12, 31, 0, 0)]
```

`steptools.range` can iterate over over `fractions.Fraction`

```>>> from fractions import Fraction
>>> list(range(Fraction(1,3), Fraction(2,3), Fraction(1,6)))
[Fraction(1, 3), Fraction(1, 2)]
>>> list(range(Fraction(1,3), Fraction(5,3)))
[Fraction(1, 3), Fraction(4, 3)]
```

`steptools.range` can iterate over over `decimal.Decimal`

```>>> from decimal import Decimal
>>> list(range(Decimal("1.33"), Decimal("1.66"), Decimal("0.11")))
[Decimal('1.33'), Decimal('1.44'), Decimal('1.55')]
```

## Requirements

steptools does not depend on any non-core libraries, however the values you pass in for start, stop, step, and zero_step must have certain behavior. The following should all work reasonably without raising exception. The comparisons (< and ==) should return a bool.:

```if zero_step is None:
type(step)() # must be logically "zero"

step == zero_step

if step < zero_step:
stop < start
stop < (start+step)
else:
start < stop
(start+step) < stop
if inclusive:
start == stop
(start+step) == stop
if stop is none:
type(start)() # must be logically "zero"
```