Skip to content

Commit

Permalink
Added PeriodRange class. Some restructuring
Browse files Browse the repository at this point in the history
  • Loading branch information
runfalk committed Mar 20, 2017
1 parent e7ab6c0 commit 79b1e61
Show file tree
Hide file tree
Showing 9 changed files with 521 additions and 57 deletions.
6 changes: 6 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ Date range
.. autoclass:: spans.types.daterange
:members: from_date

Typed date range
~~~~~~~~~~~~~~~~
.. autoclass:: spans.types.TypedDateRange
:members:

Datetime range
~~~~~~~~~~~~~~
.. autoclass:: spans.types.datetimerange
Expand All @@ -48,6 +53,7 @@ Timedelta range
~~~~~~~~~~~~~~~
.. autoclass:: spans.types.timedeltarange


Range sets
----------

Expand Down
15 changes: 15 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,26 @@ Version 0.4.0
-------------
Released on <unreleased>

- Added new argument to :meth:`~spans.types.daterange.from_date` for working
with different kinds of date intervals. The argument accepts a period of either
``"day"`` (default), ``"week"`` (ISO week), ``"american_week"`` (starts on
sunday), ``"month"``, ``"quarter"`` or ``"year"``.
- Added new methods to :class:`~spans.types.daterange` for working with different
kinds of date intervals:
:meth:`~spans.types.daterange.from_week`,
:meth:`~spans.types.daterange.from_month`,
:meth:`~spans.types.daterange.from_quarter` and
:meth:`~spans.types.daterange.from_year`.
- Added a new class :class:`~spans.types.PeriodRange` for working with periods
like weeks, months, quarters or years. It inherits all methods from
:class:`~spans.types.daterange` and is aware of its own period type. It
allows things like getting the previous or next week.
- Fixed :class:`~spans.types.daterange` not accepting subclasses of ``date``
(`bug #5 <https://github.com/runfalk/spans/issues/5>`_)
- Fixed some broken doctests
- Moved unit tests to `pytest <http://docs.pytest.org/en/latest/>`_
- Removed `Tox <https://tox.readthedocs.io/en/latest/>`_ config
- Minor documentation tweaks

Version 0.3.0
-------------
Expand Down
27 changes: 18 additions & 9 deletions spans/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,35 @@
import sys

__all__ = [
"python3",
"version",
"add_metaclass",
"is_python2",
"iter_range",
"bstr",
"ustr",
"uchr",
"add_metaclass"
"ustr",
"version",
]

version = tuple(map(int, sys.version.split(".")[0:2]))
python3 = False
version = sys.version_info[:2]

if version >= (3, 0):
python3 = True
is_python2 = False

if version < (3, 3):
raise ImportError("Module is only compatible with Python (<=2.7, >=3.3)")

bstr, ustr, uchr = bytes, str, chr
bstr = bytes
ustr = str
uchr = chr
iter_range = range
else:
bstr, ustr, uchr = str, unicode, unichr
is_python2 = True

bstr = str
ustr = unicode
uchr = unichr
iter_range = xrange


def add_metaclass(metaclass):
"""
Expand Down
28 changes: 27 additions & 1 deletion spans/_utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
"""Helper functions"""

from datetime import date, datetime, timedelta

from ._compat import *

__all__ = [
"date_from_iso_week",
"find_slots",
"PicklableSlotMixin"
"PicklableSlotMixin",
"sane_total_ordering",
]

def date_from_iso_week(year, week, day_of_week=None):
if day_of_week is None:
day_of_week = 1

if not 1 <= day_of_week <= 7:
raise ValueError(
"Day of week is not in range 1 through 7, got {!r}".format(day_of_week))

day = datetime.strptime(
"{:04d}-{:02d}-{:d}".format(year, week, day_of_week), "%Y-%W-%w")

# ISO week 1 is defined as the first week to have 4 or more days in January.
# Python's built-in date parsing considers the week that contain the first
# Monday of the year to be the first week.
if date(year, 1, 4).isoweekday() > 4:
day -= timedelta(days=7)

return day.date()


def find_slots(cls):
"""Return a set of all slots for a given class and its parents"""

Expand All @@ -23,6 +47,7 @@ def find_slots(cls):

return slots


class PicklableSlotMixin(object):
__slots__ = ()

Expand All @@ -33,6 +58,7 @@ def __setstate__(self, data):
for attr, value in data.items():
setattr(self, attr, value)


def sane_total_ordering(cls):
def __ge__(self, other):
lt = self.__lt__(other)
Expand Down
22 changes: 19 additions & 3 deletions spans/settypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
# Imports needed for doctests in date range sets
from datetime import *


__all__ = [
"intrangeset",
"floatrangeset",
"strrangeset",
"daterangeset",
"datetimerangeset",
"timedeltarangeset"
"timedeltarangeset",
]


class metarangeset(type):
"""
A meta class for rangesets. The purpose is to automatically add relevant
Expand All @@ -41,6 +43,15 @@ def __new__(cls, name, bases, attrs):
def add(cls, range_mixin, range_set_mixin):
cls.mixin_map[range_mixin] = range_set_mixin

@classmethod
def register(cls, range_mixin):
def decorator(range_set_mixin):
cls.add(range_mixin, range_set_mixin)
return range_set_mixin
return decorator


@metarangeset.register(discreterange)
class discreterangeset(object):
"""
Mixin that adds support for discrete range set operations. Automatically used
Expand All @@ -61,9 +72,9 @@ def values(self):
"""

return chain(*self)
metarangeset.add(discreterange, discreterangeset)


@metarangeset.register(offsetablerange)
class offsetablerangeset(object):
"""
Mixin that adds support for offsetable range set operations. Automatically used
Expand All @@ -88,7 +99,6 @@ def offset(self, offset):
"""

return self.__class__(r.offset(offset) for r in self)
metarangeset.add(offsetablerange, offsetablerangeset)


@sane_total_ordering
Expand Down Expand Up @@ -492,6 +502,7 @@ def intersection(self, *others):
# Python 3 support
__bool__ = __nonzero__


class intrangeset(rangeset):
"""
Range set that operates on intranges.
Expand All @@ -510,6 +521,7 @@ class intrangeset(rangeset):

type = intrange


class floatrangeset(rangeset):
"""
Range set that operates on floatranges.
Expand All @@ -528,6 +540,7 @@ class floatrangeset(rangeset):

type = floatrange


class strrangeset(rangeset):
"""
Range set that operates on strranges.
Expand All @@ -547,6 +560,7 @@ class strrangeset(rangeset):

type = strrange


class daterangeset(rangeset):
"""
Range set that operates on dateranges.
Expand All @@ -567,6 +581,7 @@ class daterangeset(rangeset):

type = daterange


class datetimerangeset(rangeset):
"""
Range set that operates on datetimeranges.
Expand All @@ -586,6 +601,7 @@ class datetimerangeset(rangeset):

type = datetimerange


class timedeltarangeset(rangeset):
"""
Range set that operates on timedeltaranges.
Expand Down

0 comments on commit 79b1e61

Please sign in to comment.