Skip to content

Commit b2a6f9a

Browse files
Refactor datetime handling
1 parent a16c293 commit b2a6f9a

File tree

3 files changed

+45
-27
lines changed

3 files changed

+45
-27
lines changed

src/country_workspace/datasources/rdi.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
from country_workspace.models import AsyncJob, Batch, Household
1515
from country_workspace.utils.config import BatchNameConfig, FailIfAlienConfig
1616
from country_workspace.utils.fields import Record, clean_field_names
17+
from country_workspace.utils.functional import compose
1718
from country_workspace.validators.beneficiaries import validate_beneficiaries
18-
from country_workspace.datasources.utils import strip_time_iso
19+
from country_workspace.datasources.utils import datetime_to_date, date_to_iso_string
1920

2021

2122
RDI = str | io.BytesIO
@@ -156,7 +157,8 @@ def merge_images(sheet: Sheet, sheet_images: Mapping[int, Mapping[int, str]]) ->
156157

157158

158159
def read_sheets(config: Config, filepath: str, *sheet_indices: int) -> Generator[Sheet, None, None]:
159-
sheets = open_xls_multi(filepath, sheets=list(sheet_indices), value_mapper=strip_time_iso)
160+
cell_mapper = compose(datetime_to_date, date_to_iso_string)
161+
sheets = open_xls_multi(filepath, sheets=list(sheet_indices), value_mapper=cell_mapper)
160162
sheet_images = extract_images(filepath, *sheet_indices)
161163
for (_, sheet), images in zip(sheets, sheet_images, strict=False):
162164
sheet_with_images = merge_images(sheet, images)
Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from typing import Any
2-
from datetime import date
3-
4-
5-
def strip_time_iso(v: Any) -> Any:
6-
if not isinstance(v, str):
7-
return v
8-
date_part = v.split(" ", 1)[0]
9-
try:
10-
d = date.fromisoformat(date_part)
11-
return d.isoformat()
12-
except ValueError:
13-
return v
2+
from datetime import date, datetime
3+
4+
5+
def datetime_to_date(v: Any) -> Any:
6+
if isinstance(v, datetime):
7+
return v.date()
8+
return v
9+
10+
11+
def date_to_iso_string(v: Any) -> Any:
12+
if isinstance(v, date):
13+
return v.isoformat()
14+
return v

tests/datasources/test_rdi.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections.abc import Mapping
2-
from datetime import datetime, date
2+
from datetime import datetime, date, timezone
3+
from typing import Any
34
from unittest.mock import Mock, call, MagicMock
45

56
import pytest
@@ -24,7 +25,7 @@
2425
read_sheets,
2526
full_name_column,
2627
)
27-
from country_workspace.datasources.utils import strip_time_iso
28+
from country_workspace.datasources.utils import datetime_to_date, date_to_iso_string
2829
from country_workspace.models import Household
2930
from country_workspace.workspaces.exceptions import BeneficiaryValidationError
3031
from country_workspace.validators.beneficiaries import validate_beneficiaries
@@ -293,7 +294,9 @@ def test_merge_images() -> None:
293294

294295
def test_read_sheets(mocker: MockerFixture) -> None:
295296
fake_sheets = ((Mock(), sheet := Mock()),)
296-
strip_time_iso_mock = mocker.patch("country_workspace.datasources.rdi.strip_time_iso")
297+
compose_mock = mocker.patch("country_workspace.datasources.rdi.compose")
298+
datetime_to_date_mock = mocker.patch("country_workspace.datasources.rdi.datetime_to_date")
299+
date_to_iso_string_mock = mocker.patch("country_workspace.datasources.rdi.date_to_iso_string")
297300
open_xls_multi_mock = mocker.patch("country_workspace.datasources.rdi.open_xls_multi")
298301
open_xls_multi_mock.return_value = fake_sheets
299302
extract_images_mock = mocker.patch("country_workspace.datasources.rdi.extract_images")
@@ -305,7 +308,8 @@ def test_read_sheets(mocker: MockerFixture) -> None:
305308
result = list(read_sheets(config_mock, filepath := "test", sheet_index := 0))
306309

307310
assert result == [filter_rows_with_household_pk_mock.return_value]
308-
open_xls_multi_mock.assert_called_once_with(filepath, sheets=[sheet_index], value_mapper=strip_time_iso_mock)
311+
compose_mock.assert_called_once_with(datetime_to_date_mock, date_to_iso_string_mock)
312+
open_xls_multi_mock.assert_called_once_with(filepath, sheets=[sheet_index], value_mapper=compose_mock.return_value)
309313
extract_images_mock.assert_called_once_with(filepath, sheet_index)
310314
merge_images_mock.assert_called_once_with(sheet, images)
311315
filter_rows_with_household_pk_mock.assert_called_once_with(config_mock, merge_images_mock.return_value)
@@ -326,14 +330,25 @@ def test_full_name_column(record: Record, expected: str | None) -> None:
326330
@pytest.mark.parametrize(
327331
("inp", "expected"),
328332
[
329-
("2025-05-15 12:34:56", "2025-05-15"),
330-
("2025-05-15", "2025-05-15"),
331-
("foo bar", "foo bar"),
332-
(123, 123),
333-
(datetime.fromisoformat("2025-05-15 00:00:00"), datetime.fromisoformat("2025-05-15 00:00:00")),
334-
(date(2020, 1, 1), date(2020, 1, 1)),
333+
(s := "foo", s),
334+
(i := 123, i),
335+
(d := date(2020, 1, 1), d),
336+
(dt := datetime(2020, 1, 1, 1, 1, 1, tzinfo=timezone.utc), dt.date()),
335337
],
336-
ids=["str_with_time", "str_date_only", "str_non_date", "numeric", "datetime_obj", "date_obj"],
338+
ids=["string", "integer", "date", "datetime"],
337339
)
338-
def test_strip_time_iso(inp, expected):
339-
assert strip_time_iso(inp) == expected
340+
def test_datetime_to_date(inp: Any, expected: Any) -> None:
341+
assert datetime_to_date(inp) == expected
342+
343+
344+
@pytest.mark.parametrize(
345+
("inp", "expected"),
346+
[
347+
(s := "foo", s),
348+
(i := 123, i),
349+
(d := date(2020, 1, 1), d.isoformat()),
350+
],
351+
ids=["string", "integer", "date"],
352+
)
353+
def test_date_to_iso_string(inp: Any, expected: Any) -> None:
354+
assert date_to_iso_string(inp) == expected

0 commit comments

Comments
 (0)