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 all commits
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
83 changes: 81 additions & 2 deletions fiscalyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,73 @@
START_DAY = 1


def _check_only_start_or_end_present(start_month, start_day,
end_month, end_day):
"""Checks that only start_* or end_* are present.

:param start_month: The first month of the fiscal year
:param start_day: The first day of the first month of the fiscal year
:param end_month: The last month of the fiscal year
:param end_day: The last day of the last month of the fiscal year
:raises ValueError: If ``start_month`` and/or ``start_day`` is passed
along with ``end_month`` and/or ``end_day``
"""
start_present = start_month is not None or start_day is not None
end_present = end_month is not None or end_day is not None
if start_present and end_present:
emsg = "invalid combination of " + \
"start_month, start_day, end_month, end_day; " + \
"pass either start_* or end_*"
raise ValueError(emsg)


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 +120,9 @@ 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.

:param start_year: Relationship between the start of the fiscal year and
the calendar year. Possible values: ``'previous'`` or ``'same'``.
Expand All @@ -63,13 +131,24 @@ 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
:raises ValueError: If ``start_month`` and/or ``start_day`` is passed
along with ``end_month`` and/or ``end_day``
"""
global START_YEAR, START_MONTH, START_DAY

_check_only_start_or_end_present(start_month, start_day, end_month, end_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
153 changes: 153 additions & 0 deletions test_fiscalyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,124 @@ def test_valid_input(self, arguments):
fiscalyear._validate_fiscal_calendar_params(**arguments)


class TestCheckOnlyStartOrEndPresent(object):
@pytest.mark.parametrize(
"arguments, exception",
[
(dict(start_month=None, start_day=1, end_month=12, end_day=31),
ValueError),
(dict(start_month=1, start_day=None, end_month=12, end_day=31),
ValueError),
(dict(start_month=1, start_day=1, end_month=None, end_day=31),
ValueError),
(dict(start_month=1, start_day=1, end_month=12, end_day=None),
ValueError),
(dict(start_month=None, start_day=1, end_month=None, end_day=31),
ValueError),
(dict(start_month=1, start_day=None, end_month=None, end_day=31),
ValueError),
(dict(start_month=None, start_day=1, end_month=12, end_day=None),
ValueError),
(dict(start_month=1, start_day=None, end_month=12, end_day=None),
ValueError),
],
)
def test_invalid_input(self, arguments, exception):
with pytest.raises(exception):
fiscalyear._check_only_start_or_end_present(**arguments)

@pytest.mark.parametrize(
"arguments",
[
dict(start_month=None, start_day=None, end_month=12, end_day=31),
dict(start_month=None, start_day=None, end_month=4, end_day=30),
dict(start_month=None, start_day=None, end_month='12', end_day='31'),
dict(start_month=None, start_day=None, end_month='4', end_day='30'),
dict(start_month=1, start_day=1, end_month=None, end_day=None),
dict(start_month=6, start_day=15, end_month=None, end_day=None),
dict(start_month='1', start_day='1', end_month=None, end_day=None),
dict(start_month='6', start_day='15', end_month=None, end_day=None),
dict(start_month=None, start_day=None, end_month=None, end_day=None),
],
)
def test_valid_input(self, arguments):
fiscalyear._check_only_start_or_end_present(**arguments)


class TestStartDayFromEndParams(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 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 +293,41 @@ 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_complex(self):
# Test defaults
day = fiscalyear.FiscalDate(2017, 12, 1)
Expand Down