Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add end_month and end_day feature to setup_fiscal_calendar #21

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions fiscalyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,53 @@
START_DAY = 1


def _start_day_from_end(end_month, end_day):
"""Returns start day from end month and day.

:param end_month: The last month of the fiscal year
:type end_month: int or str
:param end_day: The last day of the last month of the fiscal year
:type end_day: int or str
:raises ValueError: If ``end_month`` or ``end_day`` is not an int or
int-like string
:raises ValueError: If ``end_month`` or ``end_day`` is out of range
"""
day = _check_day(end_month, end_day) + 1
max_day = calendar.monthrange(2001, end_month)[1]
start_day = 1 if day > max_day else day
return start_day


def _start_month_day_from_end(end_month, end_day):
"""Returns start month and day from end month and day.

:param end_month: The last month of the fiscal year
:type end_month: int or str
:param end_day: The last day of the last month of the fiscal year
:type end_day: int or str
:raises ValueError: If ``end_month`` or ``end_day`` is not an int or
int-like string
:raises ValueError: If ``end_month`` or ``end_day`` is out of range
"""
if end_month is None and end_day is None:
start_day = None
start_month = None
elif end_month is None:
month = 12 if START_MONTH == 1 else START_MONTH - 1
start_day = _start_day_from_end(month, end_day)
start_month = None
elif end_day is None:
start_day = None
start_month = _check_month(end_month) % 12 + 1
else:
day = _check_day(end_month, end_day)
month = _check_month(end_month)
start_day = _start_day_from_end(month, day)
start_month = month if start_day > day else month % 12 + 1

return start_month, start_day


def _validate_fiscal_calendar_params(start_year, start_month, start_day):
"""Raise an Exception if the calendar parameters are invalid.

Expand All @@ -53,8 +100,12 @@ def _validate_fiscal_calendar_params(start_year, start_month, start_day):
_check_day(start_month, start_day)


def setup_fiscal_calendar(start_year=None, start_month=None, start_day=None):
"""Modify the start of the fiscal calendar.
def setup_fiscal_calendar(start_year=None, start_month=None, start_day=None,
end_month=None, end_day=None):
"""Modify the fiscal calendar.

If either of ``start_month`` or ``start_day`` are present, ``end_month``
and ``end_day`` are ignored.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be surprising behavior. I think it would be preferable to throw an error when invalid combinations of arguments are supplied


:param start_year: Relationship between the start of the fiscal year and
the calendar year. Possible values: ``'previous'`` or ``'same'``.
Expand All @@ -63,13 +114,20 @@ def setup_fiscal_calendar(start_year=None, start_month=None, start_day=None):
:type start_month: int or str
:param start_day: The first day of the first month of the fiscal year
:type start_day: int or str
:param end_month: The last month of the fiscal year
:type end_month: int or str
:param end_day: The last day of the last month of the fiscal year
:type end_day: int or str
:raises ValueError: If ``start_year`` is not ``'previous'`` or ``'same'``
:raises TypeError: If ``start_month`` or ``start_day`` is not an int or
int-like string
:raises ValueError: If ``start_month`` or ``start_day`` is out of range
"""
global START_YEAR, START_MONTH, START_DAY

if start_month is None and start_day is None:
start_month, start_day = _start_month_day_from_end(end_month, end_day)

# If arguments are omitted, use the currently active values.
start_year = START_YEAR if start_year is None else start_year
start_month = START_MONTH if start_month is None else start_month
Expand Down
88 changes: 88 additions & 0 deletions test_fiscalyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,43 @@ def test_valid_input(self, arguments):
fiscalyear._validate_fiscal_calendar_params(**arguments)


class TestStartMonthDayFromEndParams(object):
@pytest.mark.parametrize(
"arguments, exception",
[
(dict(end_month="asdf", end_day=1), TypeError),
(dict(end_month=float(12), end_day=1), TypeError),
(dict(end_month=object(), end_day=1), TypeError),
(dict(end_month=-1, end_day=1), ValueError),
(dict(end_month=0, end_day=1), ValueError),
(dict(end_month=13, end_day=1), ValueError),
(dict(end_month=12, end_day="asdf"), TypeError),
(dict(end_month=12, end_day=float(1)), TypeError),
(dict(end_month=12, end_day=object()), TypeError),
(dict(end_month=12, end_day=0), ValueError),
(dict(end_month=12, end_day=-1), ValueError),
(dict(end_month=12, end_day=32), ValueError),
],
)
def test_invalid_input(self, arguments, exception):
with pytest.raises(exception):
fiscalyear._start_month_day_from_end(**arguments)

@pytest.mark.parametrize(
"arguments",
[
dict(end_month=1, end_day=1),
dict(end_month=1, end_day=31),
dict(end_month=12, end_day=1),
dict(end_month=1, end_day=1),
dict(end_month=1, end_day=31),
dict(end_month=12, end_day=1),
],
)
def test_valid_input(self, arguments):
fiscalyear._start_month_day_from_end(**arguments)


class TestSetupFiscalCalendar(object):
def test_start_year(self):
assert fiscalyear.START_YEAR == "previous"
Expand Down Expand Up @@ -175,6 +212,57 @@ def test_start_day(self):

assert fiscalyear.START_DAY == 1

def test_end_month(self):
assert fiscalyear.START_MONTH == 10

fiscalyear.setup_fiscal_calendar(end_month=4)
assert fiscalyear.START_MONTH == 5
fiscalyear.setup_fiscal_calendar(end_month=12)
assert fiscalyear.START_MONTH == 1
fiscalyear.setup_fiscal_calendar(end_month=9)

assert fiscalyear.START_MONTH == 10

def test_end_day(self):
assert fiscalyear.START_DAY == 1

fiscalyear.setup_fiscal_calendar(end_day=6)
assert fiscalyear.START_DAY == 7
fiscalyear.setup_fiscal_calendar(end_day=30)

assert fiscalyear.START_DAY == 1

def test_end_month_day(self):
assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1

fiscalyear.setup_fiscal_calendar(end_month=4, end_day=15)
assert fiscalyear.START_MONTH == 4
assert fiscalyear.START_DAY == 16
fiscalyear.setup_fiscal_calendar(end_month=2, end_day=28)
assert fiscalyear.START_MONTH == 3
assert fiscalyear.START_DAY == 1
fiscalyear.setup_fiscal_calendar(end_month=9, end_day=30)

assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1

def test_end_ignored(self):
assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1

fiscalyear.setup_fiscal_calendar(start_month=10, end_month=2, end_day=28)
assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1
fiscalyear.setup_fiscal_calendar(start_day=1, end_month=2, end_day=28)
assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1
fiscalyear.setup_fiscal_calendar(start_month=10, start_day=1,
end_month=2, end_day=28)

assert fiscalyear.START_MONTH == 10
assert fiscalyear.START_DAY == 1

def test_complex(self):
# Test defaults
day = fiscalyear.FiscalDate(2017, 12, 1)
Expand Down