Skip to content

Commit 8f0ccd5

Browse files
Addressing PR comments
1 parent 159a730 commit 8f0ccd5

File tree

3 files changed

+78
-72
lines changed

3 files changed

+78
-72
lines changed

classes/subject.py

Lines changed: 18 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from classes.sdd_reason_for_change_type import SDDReasonForChangeType
1111
from classes.ss_reason_for_change_type import SSReasonForChangeType
1212
from classes.ssdd_reason_for_change_type import SSDDReasonForChangeType
13+
from utils.date_time_utils import DateTimeUtils
1314
import pandas as pd
1415

1516

@@ -1256,100 +1257,48 @@ def from_dataframe_row(row: pd.Series) -> "Subject":
12561257
"nhs_number": row.get("subject_nhs_number"),
12571258
"surname": row.get("person_family_name"),
12581259
"forename": row.get("person_given_name"),
1259-
"datestamp": Subject.parse_datetime(row.get("datestamp")),
1260+
"datestamp": DateTimeUtils.parse_datetime(row.get("datestamp")),
12601261
"screening_status_id": row.get("screening_status_id"),
12611262
"screening_status_change_reason_id": row.get("ss_reason_for_change_id"),
1262-
"screening_status_change_date": Subject.parse_date(
1263+
"screening_status_change_date": DateTimeUtils.parse_date(
12631264
row.get("screening_status_change_date")
12641265
),
1265-
"screening_due_date": Subject.parse_date(row.get("screening_due_date")),
1266+
"screening_due_date": DateTimeUtils.parse_date(
1267+
row.get("screening_due_date")
1268+
),
12661269
"screening_due_date_change_reason_id": row.get("sdd_reason_for_change_id"),
1267-
"screening_due_date_change_date": Subject.parse_date(
1270+
"screening_due_date_change_date": DateTimeUtils.parse_date(
12681271
row.get("sdd_change_date")
12691272
),
1270-
"calculated_screening_due_date": Subject.parse_date(
1273+
"calculated_screening_due_date": DateTimeUtils.parse_date(
12711274
row.get("calculated_sdd")
12721275
),
1273-
"surveillance_screening_due_date": Subject.parse_date(
1276+
"surveillance_screening_due_date": DateTimeUtils.parse_date(
12741277
row.get("surveillance_screen_due_date")
12751278
),
1276-
"calculated_surveillance_due_date": Subject.parse_date(
1279+
"calculated_surveillance_due_date": DateTimeUtils.parse_date(
12771280
row.get("calculated_ssdd")
12781281
),
12791282
"surveillance_due_date_change_reason_id": row.get(
12801283
"surveillance_sdd_rsn_change_id"
12811284
),
1282-
"surveillance_due_date_change_date": Subject.parse_date(
1285+
"surveillance_due_date_change_date": DateTimeUtils.parse_date(
12831286
row.get("surveillance_sdd_change_date")
12841287
),
1285-
"lynch_due_date": Subject.parse_date(row.get("lynch_screening_due_date")),
1288+
"lynch_due_date": DateTimeUtils.parse_date(
1289+
row.get("lynch_screening_due_date")
1290+
),
12861291
"lynch_due_date_change_reason_id": row.get(
12871292
"lynch_sdd_reason_for_change_id"
12881293
),
1289-
"lynch_due_date_change_date": Subject.parse_date(
1294+
"lynch_due_date_change_date": DateTimeUtils.parse_date(
12901295
row.get("lynch_sdd_change_date")
12911296
),
1292-
"calculated_lynch_due_date": Subject.parse_date(
1297+
"calculated_lynch_due_date": DateTimeUtils.parse_date(
12931298
row.get("lynch_calculated_sdd")
12941299
),
1295-
"date_of_birth": Subject.parse_date(row.get("date_of_birth")),
1296-
"date_of_death": Subject.parse_date(row.get("date_of_death")),
1300+
"date_of_birth": DateTimeUtils.parse_date(row.get("date_of_birth")),
1301+
"date_of_death": DateTimeUtils.parse_date(row.get("date_of_death")),
12971302
}
12981303

12991304
return Subject(**field_map)
1300-
1301-
@staticmethod
1302-
def parse_date(
1303-
val: Optional[Union[pd.Timestamp, str, datetime, date]],
1304-
) -> Optional[date]:
1305-
"""
1306-
Converts a value to a Python date object if possible.
1307-
1308-
Args:
1309-
val: The value to convert (can be pandas.Timestamp, string, datetime, date, or None).
1310-
1311-
Returns:
1312-
Optional[date]: The converted date object, or None if conversion fails.
1313-
"""
1314-
if pd.isnull(val):
1315-
return None
1316-
if isinstance(val, pd.Timestamp):
1317-
return val.to_pydatetime().date()
1318-
if isinstance(val, str):
1319-
try:
1320-
return datetime.strptime(val[:10], "%Y-%m-%d").date()
1321-
except Exception:
1322-
return None
1323-
if isinstance(val, datetime):
1324-
return val.date()
1325-
if isinstance(val, date):
1326-
return val
1327-
return None
1328-
1329-
@staticmethod
1330-
def parse_datetime(
1331-
val: Optional[Union[pd.Timestamp, str, datetime, date]],
1332-
) -> Optional[datetime]:
1333-
"""
1334-
Converts a value to a Python datetime object if possible.
1335-
1336-
Args:
1337-
val: The value to convert (can be pandas.Timestamp, string, datetime, or None).
1338-
1339-
Returns:
1340-
Optional[datetime]: The converted datetime object, or None if conversion fails.
1341-
"""
1342-
if pd.isnull(val):
1343-
return None
1344-
if isinstance(val, pd.Timestamp):
1345-
return val.to_pydatetime()
1346-
if isinstance(val, str):
1347-
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S"):
1348-
try:
1349-
return datetime.strptime(val[:19], fmt)
1350-
except Exception:
1351-
continue
1352-
return None
1353-
if isinstance(val, datetime):
1354-
return val
1355-
return None

docs/utility-guides/SubjectAssertion.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ If the subject does not match all criteria, the function will iteratively loop t
3636
## How It Works
3737

3838
1. The function first checks if the subject with the given NHS number matches all provided criteria.
39-
2. If not, it removes checks one criterion at a time and retries the assertion.
39+
2. If not, it checks one criterion at a time and retries the assertion.
4040
3. This process continues until all criteria have been checked.
4141
4. If a match is found only after removing criteria, the failed criteria are logged.
4242
5. The function returns `True` only if all criteria match on the first attempt; otherwise, it returns `False`.

utils/date_time_utils.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from datetime import datetime, timedelta
2-
from typing import Optional
1+
from datetime import datetime, timedelta, date
2+
from typing import Optional, Union
3+
import pandas as pd
34
import random
45

56

@@ -152,3 +153,59 @@ def generate_unique_weekday_date(start_year: int = 2025) -> str:
152153
base_date += timedelta(days=1)
153154

154155
return base_date.strftime("%d/%m/%Y")
156+
157+
@staticmethod
158+
def parse_date(
159+
val: Optional[Union[pd.Timestamp, str, datetime, date]],
160+
) -> Optional[date]:
161+
"""
162+
Converts a value to a Python date object if possible.
163+
164+
Args:
165+
val: The value to convert (can be pandas.Timestamp, string, datetime, date, or None).
166+
167+
Returns:
168+
Optional[date]: The converted date object, or None if conversion fails.
169+
"""
170+
if pd.isnull(val):
171+
return None
172+
if isinstance(val, pd.Timestamp):
173+
return val.to_pydatetime().date()
174+
if isinstance(val, str):
175+
try:
176+
return datetime.strptime(val[:10], "%Y-%m-%d").date()
177+
except Exception:
178+
return None
179+
if isinstance(val, datetime):
180+
return val.date()
181+
if isinstance(val, date):
182+
return val
183+
return None
184+
185+
@staticmethod
186+
def parse_datetime(
187+
val: Optional[Union[pd.Timestamp, str, datetime, date]],
188+
) -> Optional[datetime]:
189+
"""
190+
Converts a value to a Python datetime object if possible.
191+
192+
Args:
193+
val: The value to convert (can be pandas.Timestamp, string, datetime, or None).
194+
195+
Returns:
196+
Optional[datetime]: The converted datetime object, or None if conversion fails.
197+
"""
198+
if pd.isnull(val):
199+
return None
200+
if isinstance(val, pd.Timestamp):
201+
return val.to_pydatetime()
202+
if isinstance(val, str):
203+
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%dT%H:%M:%S"):
204+
try:
205+
return datetime.strptime(val[:19], fmt)
206+
except Exception:
207+
continue
208+
return None
209+
if isinstance(val, datetime):
210+
return val
211+
return None

0 commit comments

Comments
 (0)