Skip to content

Commit

Permalink
Merge pull request #4 from dschenck/0.0.12
Browse files Browse the repository at this point in the history
0.0.12
  • Loading branch information
dschenck authored Dec 16, 2023
2 parents 9b83ffc + 23610f0 commit 1e0b013
Show file tree
Hide file tree
Showing 8 changed files with 195 additions and 7 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# This workflow will upload a Python Package using Twine when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Publish package to pypi on release

on:
release:
types: [published]
workflow_dispatch:

permissions:
contents: read

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
6 changes: 3 additions & 3 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python

name: doubledate
name: Install package, run tests and upload coverage

on:
push:
branches: [ "master" ]
branches: [ "*" ]
pull_request:
branches: [ "master" ]
branches: [ "main" ]

jobs:
build:
Expand Down
4 changes: 4 additions & 0 deletions docs/source/Calendar/doubledate.Calendar.join.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Calendar.join
============================================

.. automethod:: doubledate.Calendar.join
1 change: 1 addition & 0 deletions docs/source/Calendar/doubledate.Calendar.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Calendar
doubledate.Calendar.index.rst
doubledate.Calendar.intersection.rst
doubledate.Calendar.inverse.rst
doubledate.Calendar.join.rst
doubledate.Calendar.last.rst
doubledate.Calendar.lb.rst
doubledate.Calendar.offset.rst
Expand Down
3 changes: 2 additions & 1 deletion doubledate/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
__version__ = "0.0.12"

from datetime import MAXYEAR, MINYEAR
from datetime import date, datetime, time, timedelta, timezone, tzinfo

Expand Down Expand Up @@ -37,4 +39,3 @@
next,
datemap,
)

98 changes: 96 additions & 2 deletions doubledate/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import collections.abc
import datetime
import numbers
import dateutil.rrule
import warnings

import doubledate.utils as utils
import doubledate.constants as constants
Expand Down Expand Up @@ -137,6 +139,68 @@ def __hash__(self):
"""
return hash((date for date in self))

@classmethod
def create(
cls, *, freq=None, starting=None, ending=None, rrule=None, dtype=None, **kwargs
):
"""
Create a new calendar, wrapping :code:`dateutil.rrule`
Parameters
----------
freq : str, int
the calendar frequency; one of:
- 'Y' for yearly
- 'M' for monthly
- 'W' for weekly
- 'D' for daily
- 'H' for hourly
- 'MIN' for minutely
- 'S' for secondly
or any :code:`dateutil.rrule` constant (e.g. :code:`dateutil.rrule.MONTHLY`)
starting : datetime
the first date in the calendar
alias for :code:`dstart` in :code:`dateutil.rrule.rrule`
ending : datetime
the last date in the calendar
alias for :code:`until` in :code:`dateutil.rrule.rrule`
rrule : str, :code:`dateutil.rrule.rrule`
recurrence rule. If given a :code:`str`, this will be evaluated as a
:code:`dateutil.rrule.rrulestr` with the :code:`dstart`
dtype : None, type
the datetime type (e.g. pd.Timestamp)
**kwargs : dict
additional arguments to pass to :code:`dateutil.rrule.rrule`
"""
if rrule is not None:
if isinstance(rrule, str):
rrule = dateutil.rrule.rrulestr(rrule, dtstart=starting)
return cls([d if dtype is None else dtype(d) for d in rrule])

freqs = {
"Y": dateutil.rrule.YEARLY,
"M": dateutil.rrule.MONTHLY,
"W": dateutil.rrule.WEEKLY,
"D": dateutil.rrule.DAILY,
"H": dateutil.rrule.HOURLY,
"MIN": dateutil.rrule.MINUTELY,
"S": dateutil.rrule.SECONDLY,
}

return cls.create(
rrule=dateutil.rrule.rrule(
freqs.get(freq, freq),
**{"dtstart": starting, "until": ending, **kwargs},
)
)

@classmethod
def generate(cls, starting: datetime.date, ending: datetime.date):
"""
Expand Down Expand Up @@ -164,8 +228,8 @@ def generate(cls, starting: datetime.date, ending: datetime.date):
>>> import doubledate as dtwo
>>> calendar = dtwo.Calendar.generate(
... datetime.date(2021,1,1),
... datetime.date(2021,12,31)
... starting=datetime.date(2021,1,1),
... ending=datetime.date(2021,12,31)
... )
>>> len(calendar)
365
Expand All @@ -177,6 +241,11 @@ def generate(cls, starting: datetime.date, ending: datetime.date):
datetime.date(2021,12,31)
"""
warnings.warn(
"Calendar.generate is marked for deprecation and may be removed in future versions. Use Calendar.create instead",
DeprecationWarning,
)

if not all(isinstance(d, datetime.date) for d in (starting, ending)):
raise TypeError("Expected starting and ending dates to be datetime objects")

Expand Down Expand Up @@ -465,6 +534,31 @@ def intersection(self, *others):
"""
return Calendar(self.__dates__.intersection(*others))

def join(self, other, *, on=None):
"""
Returns a calendar containing all dates in self to (and
including the given :code:`on` date) and dates in other (from
and including the :code:`on` date).
In :code:`on` is not provided, defaults to the last date
in self.
Parameters
----------
other : iterable
Other calendar
on : datetime.date
date from which to join the two calendars together
Returns
-------
Calendar
"""
if on is None:
return self.union(Calendar(other)[self.end :])
return self[:on].union(Calendar(other)[on:])

def filter(
self,
func=None,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="doubledate",
version="0.0.11",
version="0.0.12",
author="david.schenck@outlook.com",
author_email="david.schenck@outlook.com",
description="A calendar wrapper",
Expand Down
49 changes: 49 additions & 0 deletions tests/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,52 @@ def test_resample_calendar_by_weekday(calendar):

dates = calendar.resample("W-TUE").first()
assert dates[-1] == datetime.date(2019, 11, 13) # Wednesday


def test_join():
cdr1 = dtwo.Calendar(
[
datetime.date(2019, 7, 13),
datetime.date(2019, 7, 29),
datetime.date(2019, 8, 15),
datetime.date(2019, 8, 16),
datetime.date(2019, 8, 19),
datetime.date(2019, 8, 20),
]
)

cdr2 = dtwo.Calendar(
[
datetime.date(2019, 7, 14),
datetime.date(2019, 7, 29),
datetime.date(2019, 8, 15),
datetime.date(2019, 8, 16),
datetime.date(2019, 8, 17),
datetime.date(2019, 8, 21),
datetime.date(2019, 8, 22),
datetime.date(2019, 8, 23),
]
)

join = cdr1.join(cdr2)

assert datetime.date(2019, 7, 13) in join
assert datetime.date(2019, 7, 14) not in join

assert datetime.date(2019, 8, 17) not in join
assert datetime.date(2019, 8, 23) in join

join = cdr1.join(cdr2, on=datetime.date(2019, 8, 1))

assert datetime.date(2019, 7, 13) in join
assert datetime.date(2019, 7, 14) not in join

assert datetime.date(2019, 8, 17) in join
assert datetime.date(2019, 8, 20) not in join


def test_create():
cdr = dtwo.Calendar.create(
freq="D", starting=datetime.date(2020, 1, 1), ending=datetime.date(2023, 12, 31)
)
assert len(cdr) == 4 * 365 + 1

0 comments on commit 1e0b013

Please sign in to comment.