aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Lemon <matt@matthewlemon.com>2021-05-16 16:53:13 +0100
committerMatthew Lemon <matt@matthewlemon.com>2021-05-16 16:53:13 +0100
commit4dff45ad4f5459e62fde51071bb03b7fbde12954 (patch)
tree3411e22c6d4714e4d373b3c4bf144ad5d32e736a
parentupdated version number (diff)
working on Month class
-rw-r--r--datamaps/api/__init__.py1
-rw-r--r--datamaps/api/api.py24
-rw-r--r--datamaps/core/temporal.py90
-rw-r--r--datamaps/plugins/dft/master.py8
-rw-r--r--datamaps/tests/test_api.py37
5 files changed, 137 insertions, 23 deletions
diff --git a/datamaps/api/__init__.py b/datamaps/api/__init__.py
index 3f6a35c..947f8a6 100644
--- a/datamaps/api/__init__.py
+++ b/datamaps/api/__init__.py
@@ -1 +1,2 @@
from .api import project_data_from_master_api as project_data_from_master
+from .api import project_data_from_master_month_api as project_data_from_master_month
diff --git a/datamaps/api/api.py b/datamaps/api/api.py
index 6cc6f4e..c9f9a64 100644
--- a/datamaps/api/api.py
+++ b/datamaps/api/api.py
@@ -13,3 +13,27 @@ def project_data_from_master_api(master_file: str, quarter: int, year: int):
"""
m = Master(Quarter(quarter, year), master_file)
return m
+
+def project_data_from_master_month_api(master_file: str, month: int, year: int):
+ """Create a Master object directly without the need to explicitly pass
+ a Month object.
+
+ Args:
+ master_file (str): the path to a master file
+ month (int): an integer representing the month
+ year (int): an integer representing the year
+ """
+ # we need to work out what Quarter we are dealing with from the month
+ if month in [1, 2, 3]:
+ quarter = 4
+ elif month in [4, 5, 6]:
+ quarter = 1
+ elif month in [7, 8, 9]:
+ quarter = 2
+ elif month in [10, 11, 12]:
+ quarter = 3
+ else:
+ pass
+ # TODO: raise exception here
+ m = Master(Quarter(quarter, year), master_file)
+ return m
diff --git a/datamaps/core/temporal.py b/datamaps/core/temporal.py
index ddb7004..d368f6a 100644
--- a/datamaps/core/temporal.py
+++ b/datamaps/core/temporal.py
@@ -1,4 +1,56 @@
import datetime
+import calendar
+
+
+class Month:
+ """An object representing a calendar Month."""
+
+ _end_ints = {
+ 1: 31,
+ 2: 28,
+ 3: 31,
+ 4: 30,
+ 5: 31,
+ 6: 30,
+ 7: 31,
+ 8: 31,
+ 9: 30,
+ 10: 31,
+ 11: 30,
+ 12: 31,
+ }
+
+ def __init__(self, month: int, year: int):
+ self._month = month
+ self.year = year
+
+ @property
+ def start_date(self):
+ return datetime.date(self.year, self._month, 1)
+
+ @property
+ def end_date(self):
+ if self._month == 2 and calendar.isleap(self.year):
+ return datetime.date(self.year, self._month, Month._end_ints[self._month] + 1)
+ else:
+ return datetime.date(self.year, self._month, Month._end_ints[self._month])
+
+ @property
+ def month(self):
+ return [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ ][self._month - 1]
class FinancialYear:
@@ -27,26 +79,22 @@ class FinancialYear:
@property
def q1(self) -> datetime.date:
- """Quarter 1 as a :py:class:`datetime.date` object
- """
+ """Quarter 1 as a :py:class:`datetime.date` object"""
return self._q1
@property
def q2(self):
- """Quarter 2 as a :py:class:`datetime.date` object
- """
+ """Quarter 2 as a :py:class:`datetime.date` object"""
return self._q2
@property
def q3(self):
- """Quarter 3 as a :py:class:`datetime.date` object
- """
+ """Quarter 3 as a :py:class:`datetime.date` object"""
return self._q3
@property
def q4(self):
- """Quarter 4 as a :py:class:`datetime.date` object
- """
+ """Quarter 4 as a :py:class:`datetime.date` object"""
return self._q4
def __str__(self):
@@ -55,7 +103,6 @@ class FinancialYear:
def _generate_quarters(self):
self.quarters = [Quarter(x, self.year) for x in range(1, 5)]
-
def __repr__(self):
return f"FinancialYear({self.year})"
@@ -68,21 +115,21 @@ class Quarter:
quarter (int): e.g.1, 2, 3 or 4
year (int): e.g. 2013
"""
+
_start_months = {
- 1: (4, 'April'),
- 2: (7, 'July'),
- 3: (10, 'October'),
- 4: (1, 'January')
+ 1: (4, "April"),
+ 2: (7, "July"),
+ 3: (10, "October"),
+ 4: (1, "January"),
}
_end_months = {
- 1: (6, 'June', 30),
- 2: (9, 'September', 30),
- 3: (12, 'December', 31),
- 4: (3, 'March', 31),
+ 1: (6, "June", 30),
+ 2: (9, "September", 30),
+ 3: (12, "December", 31),
+ 4: (3, "March", 31),
}
-
def __init__(self, quarter: int, year: int) -> None:
if isinstance(quarter, int) and (quarter >= 1 and quarter <= 4):
@@ -93,7 +140,9 @@ class Quarter:
if isinstance(year, int) and (year in range(1950, 2100)):
self.year = year
else:
- raise ValueError("Year must be between 1950 and 2100 - surely that will do?")
+ raise ValueError(
+ "Year must be between 1950 and 2100 - surely that will do?"
+ )
self.start_date = self._start_date(self.quarter, self.year)
self.end_date = self._end_date(self.quarter, self.year)
@@ -116,6 +165,5 @@ class Quarter:
@property
def fy(self):
- """Return a :py:class:`core.temporal.FinancialYear` object.
- """
+ """Return a :py:class:`core.temporal.FinancialYear` object."""
return FinancialYear(self.year)
diff --git a/datamaps/plugins/dft/master.py b/datamaps/plugins/dft/master.py
index 744cc27..c3e6c3b 100644
--- a/datamaps/plugins/dft/master.py
+++ b/datamaps/plugins/dft/master.py
@@ -158,6 +158,14 @@ class Master:
return self._quarter
@property
+ def month(self):
+ """
+ Returns the ``Month`` object associated with the ``Master``.
+ """
+ pass
+
+
+ @property
def filename(self):
"""The filename of the master xlsx file, e.g. ``master_1_2017.xlsx``.
"""
diff --git a/datamaps/tests/test_api.py b/datamaps/tests/test_api.py
index 273f984..21ab4d1 100644
--- a/datamaps/tests/test_api.py
+++ b/datamaps/tests/test_api.py
@@ -1,10 +1,43 @@
import datetime
-from ..api import project_data_from_master
+from ..api import project_data_from_master, project_data_from_master_month
+from ..core.temporal import Quarter, Month
def test_get_project_data(master):
master = project_data_from_master(master, 1, 2019)
- assert master["Chutney Bridge.xlsm"]["Project/Programme Name"] == "Chutney Bridge Ltd"
+ assert (
+ master["Chutney Bridge.xlsm"]["Project/Programme Name"] == "Chutney Bridge Ltd"
+ )
assert master.quarter.quarter == 1
assert master.quarter.end_date == datetime.date(2019, 6, 30)
+
+
+def test_get_project_data_using_month(master):
+ master = project_data_from_master_month(master, 7, 2021)
+ assert (
+ master["Chutney Bridge.xlsm"]["Project/Programme Name"] == "Chutney Bridge Ltd"
+ )
+ assert master.month == "July"
+ assert master.quarter.quarter == 2
+ assert master.quarter.end_date == datetime.date(2021, 9, 30)
+
+
+def test_quarter_objects_have_months():
+ q = Quarter(1, 2021)
+ assert q.months[0].start_date == datetime.date(2021, 4, 1)
+
+
+def test_month():
+ m1 = Month(1, 2021)
+ assert m1.month == "January"
+ m2 = Month(9, 2021)
+ assert m2.month == "September"
+ assert m2.start_date == datetime.date(2021, 9, 1)
+ assert m2.end_date == datetime.date(2021, 9, 30)
+ # test leap year
+ m3 = Month(2, 2024)
+ m4 = Month(2, 2028)
+ assert m3.end_date == datetime.date(2024, 2, 29)
+ assert m4.end_date == datetime.date(2028, 2, 29)
+