Skip to content

Commit 297d624

Browse files
author
Mike
committed
Helper to set_last_modified directly
1 parent 4440f05 commit 297d624

7 files changed

Lines changed: 139 additions & 71 deletions

File tree

documentation/main.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,16 @@ resource, it is possible to supply the parameter `data_updated` eg.
922922

923923
resource.update_in_hdx(data_updated=True)
924924

925+
If you need to set a specific date for date of update (`last_modified`), you
926+
can call the following:
927+
928+
resource.set_date_data_updated(date)
929+
930+
`date` can be a datetime object or string. You can retrieve the date of update
931+
(`last_modified`) using the getter:
932+
933+
date = resource.get_date_data_updated()
934+
925935
If the method **set_file_to_upload** is used to supply a file, the resource
926936
`last_modified` field is set to now automatically regardless of the value of
927937
`data_updated` or whether **mark_data_updated** has been called.

src/hdx/data/dataset.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ def add_update_resource(
290290
updated_resource.set_file_to_upload(
291291
resource.get_file_to_upload()
292292
)
293-
if resource.is_data_updated():
293+
if resource.is_marked_data_updated():
294294
updated_resource.mark_data_updated()
295295

296296
def add_update_resources(
@@ -334,7 +334,7 @@ def add_update_resources(
334334
updated_resource.set_file_to_upload(
335335
resource.get_file_to_upload()
336336
)
337-
if resource.is_data_updated():
337+
if resource.is_marked_data_updated():
338338
updated_resource.mark_data_updated()
339339
for resource_index in updated_resource_no_matches:
340340
resource = resource_objects[resource_index]
@@ -1256,7 +1256,7 @@ def get_reference_period(
12561256
Returns:
12571257
Dict: Dictionary of date information
12581258
"""
1259-
return DateHelper.get_date_info(
1259+
return DateHelper.get_reference_period_info(
12601260
self.data.get("dataset_date"), date_format, today
12611261
)
12621262

@@ -1282,7 +1282,7 @@ def set_reference_period(
12821282
Returns:
12831283
None
12841284
"""
1285-
self.data["dataset_date"] = DateHelper.get_hdx_date(
1285+
self.data["dataset_date"] = DateHelper.get_hdx_reference_period(
12861286
startdate, enddate, ongoing, ignore_timeinfo
12871287
)
12881288

@@ -1300,7 +1300,10 @@ def set_reference_period_year_range(
13001300
Returns:
13011301
List[int]: The start and end year if supplied or sorted list of years
13021302
"""
1303-
self.data["dataset_date"], retval = DateHelper.get_hdx_date_from_years(
1303+
(
1304+
self.data["dataset_date"],
1305+
retval,
1306+
) = DateHelper.get_hdx_reference_period_from_years(
13041307
dataset_year, dataset_end_year
13051308
)
13061309
return retval

src/hdx/data/date_helper.py

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,74 @@
99

1010
class DateHelper:
1111
@staticmethod
12-
def get_date_info(
13-
hdx_date: Dict,
12+
def get_hdx_date(
13+
date: Union[datetime, str], ignore_timeinfo: bool, max=False
14+
):
15+
"""Get an HDX date as a string from a datetime.datetime object.
16+
17+
Args:
18+
date (Union[datetime, str]): Date as datetime or string
19+
ignore_timeinfo (bool): Ignore time and time zone of date. Defaults to True.
20+
21+
Returns:
22+
str: HDX date as a string
23+
"""
24+
if ignore_timeinfo:
25+
timezone_handling = 0
26+
else:
27+
timezone_handling = 3
28+
29+
if isinstance(date, str):
30+
date = parse_date(date, timezone_handling=timezone_handling)
31+
32+
if ignore_timeinfo:
33+
if max:
34+
date = date.replace(
35+
hour=23,
36+
minute=59,
37+
second=59,
38+
microsecond=0,
39+
tzinfo=None,
40+
)
41+
else:
42+
date = date.replace(
43+
hour=0, minute=0, second=0, microsecond=0, tzinfo=None
44+
)
45+
else:
46+
date = date.astimezone(timezone.utc).replace(
47+
microsecond=0, tzinfo=None
48+
)
49+
return date.isoformat()
50+
51+
@staticmethod
52+
def get_reference_period_info(
53+
hdx_reference_period: Dict,
1454
date_format: Optional[str] = None,
1555
today: datetime = now_utc(),
1656
) -> Dict:
17-
"""Get date as datetimes and strings in specified format. If no format is
18-
supplied, the ISO 8601 format is used. Returns a dictionary containing keys
19-
startdate (start date as datetime), enddate (end date as datetime),
20-
startdate_str (start date as string), enddate_str (end date as string) and
21-
ongoing (whether the end date is a rolls forward every day).
57+
"""Get reference period as datetimes and strings in specified format.
58+
If no format is supplied, the ISO 8601 format is used. Returns a
59+
dictionary containing keys startdate (start date as datetime), enddate
60+
(end date as datetime), startdate_str (start date as string),
61+
enddate_str (enddate as string) and ongoing (whether the end date rolls
62+
forward every day).
2263
2364
Args:
24-
hdx_date (str): Input date
65+
hdx_reference_period (str): Input reference period
2566
date_format (Optional[str]): Date format. None is taken to be ISO 8601. Defaults to None.
2667
today (datetime): Date to use for today. Defaults to now_utc().
2768
2869
Returns:
2970
Dict: Dictionary of date information
3071
"""
3172
result = dict()
32-
if hdx_date:
33-
if hdx_date[0] == "[" and hdx_date[-1] == "]":
34-
hdx_date = hdx_date[1:-1]
35-
dataset_dates = hdx_date.split(" TO ")
73+
if hdx_reference_period:
74+
if (
75+
hdx_reference_period[0] == "["
76+
and hdx_reference_period[-1] == "]"
77+
):
78+
hdx_reference_period = hdx_reference_period[1:-1]
79+
dataset_dates = hdx_reference_period.split(" TO ")
3680
startdate = parse_date(dataset_dates[0])
3781
enddate = dataset_dates[1]
3882
if enddate == "*":
@@ -59,15 +103,16 @@ def get_date_info(
59103
result["ongoing"] = ongoing
60104
return result
61105

62-
@staticmethod
63-
def get_hdx_date(
106+
@classmethod
107+
def get_hdx_reference_period(
108+
cls,
64109
startdate: Union[datetime, str],
65110
enddate: Union[datetime, str, None] = None,
66111
ongoing: bool = False,
67112
ignore_timeinfo: bool = True,
68113
) -> str:
69-
"""Get an HDX date from either datetime.datetime objects or strings with option
70-
to set ongoing.
114+
"""Get an HDX reference period from either datetime.datetime objects or
115+
strings with option to set ongoing.
71116
72117
Args:
73118
startdate (Union[datetime, str]): Dataset start date
@@ -76,65 +121,33 @@ def get_hdx_date(
76121
ignore_timeinfo (bool): Ignore time and time zone of date. Defaults to True.
77122
78123
Returns:
79-
str: HDX date
124+
str: HDX reference period
80125
"""
81-
if ignore_timeinfo:
82-
timezone_handling = 0
83-
else:
84-
timezone_handling = 3
85-
86-
def get_date_str(dt, max=False):
87-
if ignore_timeinfo:
88-
if max:
89-
dt = dt.replace(
90-
hour=23,
91-
minute=59,
92-
second=59,
93-
microsecond=0,
94-
tzinfo=None,
95-
)
96-
else:
97-
dt = dt.replace(
98-
hour=0, minute=0, second=0, microsecond=0, tzinfo=None
99-
)
100-
else:
101-
dt = dt.astimezone(timezone.utc).replace(
102-
microsecond=0, tzinfo=None
103-
)
104-
return dt.isoformat()
105-
106-
if isinstance(startdate, str):
107-
startdate = parse_date(
108-
startdate, timezone_handling=timezone_handling
109-
)
110-
startdate = get_date_str(startdate)
126+
startdate = cls.get_hdx_date(startdate, ignore_timeinfo)
111127
if ongoing:
112128
enddate = "*"
113129
else:
114130
if not enddate:
115131
enddate = startdate
116132
else:
117-
if isinstance(enddate, str):
118-
enddate = parse_date(
119-
enddate, timezone_handling=timezone_handling
120-
)
121-
enddate = get_date_str(enddate, max=True)
133+
enddate = cls.get_hdx_date(enddate, ignore_timeinfo, max=True)
122134
return f"[{startdate} TO {enddate}]"
123135

124136
@classmethod
125-
def get_hdx_date_from_years(
137+
def get_hdx_reference_period_from_years(
126138
cls,
127139
startyear: Union[str, int, Iterable],
128140
endyear: Union[str, int, None] = None,
129141
) -> Tuple[str, List[int]]:
130-
"""Get an HDX date from an iterable of years or a start and end year.
142+
"""Get an HDX reference period from an iterable of years or a start and
143+
end year.
131144
132145
Args:
133146
startyear (Union[str, int, Iterable]): Start year given as string or int or range in an iterable
134147
endyear (Union[str, int, None]): End year given as string or int
135148
136149
Returns:
137-
Tuple[str,List[int]]: (HDX date, the start and end year if supplied or sorted list of years)
150+
Tuple[str,List[int]]: (HDX reference period, the start and end year if supplied or sorted list of years)
138151
"""
139152
retval = list()
140153
if isinstance(startyear, str):
@@ -152,6 +165,8 @@ def get_hdx_date_from_years(
152165
startdate = datetime(startyear, 1, 1, tzinfo=timezone.utc)
153166
enddate = datetime(endyear, 12, 31, 23, 59, 59, tzinfo=timezone.utc)
154167
return (
155-
cls.get_hdx_date(startdate, enddate, ignore_timeinfo=False),
168+
cls.get_hdx_reference_period(
169+
startdate, enddate, ignore_timeinfo=False
170+
),
156171
retval,
157172
)

src/hdx/data/filestore_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def dataset_merge_filestore_resource(
9292
if file_to_upload:
9393
resource.set_file_to_upload(file_to_upload)
9494
filestore_resources[resource_index] = file_to_upload
95-
data_updated = updated_resource.is_data_updated()
95+
data_updated = updated_resource.is_marked_data_updated()
9696
merge_two_dictionaries(resource, updated_resource)
9797
cls.resource_check_required_fields(
9898
resource, check_upload=True, **kwargs

src/hdx/data/resource.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from hdx.data.date_helper import DateHelper
1212
from hdx.data.hdxobject import HDXError, HDXObject
1313
from hdx.data.resource_view import ResourceView
14-
from hdx.utilities.dateparse import now_utc
14+
from hdx.utilities.dateparse import now_utc, parse_date
1515
from hdx.utilities.downloader import Download
1616
from hdx.utilities.typehint import ListTuple
1717
from hdx.utilities.uuid import is_valid_uuid
@@ -122,7 +122,7 @@ def get_date_of_resource(
122122
Returns:
123123
Dict: Dictionary of date information
124124
"""
125-
return DateHelper.get_date_info(
125+
return DateHelper.get_reference_period_info(
126126
self.data.get("daterange_for_data"), date_format, today
127127
)
128128

@@ -146,7 +146,7 @@ def set_date_of_resource(
146146
Returns:
147147
None
148148
"""
149-
self.data["daterange_for_data"] = DateHelper.get_hdx_date(
149+
self.data["daterange_for_data"] = DateHelper.get_hdx_reference_period(
150150
startdate, enddate, ignore_timeinfo=ignore_timeinfo
151151
)
152152

@@ -389,6 +389,7 @@ def update_in_hdx(self, **kwargs: Any) -> None:
389389
**kwargs: See below
390390
operation (string): Operation to perform eg. patch. Defaults to update.
391391
data_updated (bool): If True, set last_modified to now. Defaults to False.
392+
date_data_updated (datetime): Date to use for last_modified. Default to None.
392393
393394
Returns:
394395
None
@@ -410,6 +411,7 @@ def create_in_hdx(self, **kwargs: Any) -> None:
410411
Args:
411412
**kwargs: See below
412413
data_updated (bool): If True, set last_modified to now. Defaults to False.
414+
date_data_updated (datetime): Date to use for last_modified. Default to None.
413415
414416
Returns:
415417
None
@@ -745,11 +747,11 @@ def mark_broken(self) -> None:
745747
else:
746748
logger.debug(result)
747749

748-
def is_data_updated(self) -> bool:
749-
"""Return if the resource's data is updated
750+
def is_marked_data_updated(self) -> bool:
751+
"""Return if the resource's data is marked to be updated
750752
751753
Returns:
752-
bool: Whether resource's data is updated
754+
bool: Whether resource's data is marked to be updated
753755
"""
754756
return self.data_updated
755757

@@ -760,3 +762,27 @@ def mark_data_updated(self) -> None:
760762
None
761763
"""
762764
self.data_updated = True
765+
766+
def get_date_data_updated(self) -> datetime:
767+
"""Get date resource data was updated
768+
769+
Returns:
770+
datetime: Date resource data was updated
771+
"""
772+
return parse_date(self.data["last_modified"])
773+
774+
def set_date_data_updated(
775+
self, date: Union[datetime, str], ignore_timeinfo: bool = True
776+
) -> None:
777+
"""Set date resource data was updated
778+
779+
Args:
780+
date (Union[datetime, str]): Date resource data was updated
781+
ignore_timeinfo (bool): Ignore time and time zone of date. Defaults to True.
782+
783+
Returns:
784+
None
785+
"""
786+
self.data["last_modified"] = DateHelper.get_hdx_date(
787+
date, ignore_timeinfo
788+
)

tests/hdx/data/test_dataset_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ def test_update_in_hdx(self, configuration, post_update, date_pattern):
713713
assert dataset["state"] == "active"
714714
assert len(dataset.resources) == 3
715715
resource = dataset.get_resource()
716-
assert resource.is_data_updated() is False
716+
assert resource.is_marked_data_updated() is False
717717
match = date_pattern.search(resource["last_modified"])
718718
assert match
719719

tests/hdx/data/test_resource.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from hdx.api.configuration import Configuration
1414
from hdx.data.hdxobject import HDXError
1515
from hdx.data.resource import Resource
16+
from hdx.utilities.dateparse import parse_date
1617
from hdx.utilities.dictandlist import merge_two_dictionaries
1718
from hdx.utilities.downloader import DownloadError
1819

@@ -845,9 +846,9 @@ def test_update_in_hdx(self, configuration, date_pattern, post_update):
845846
resource = Resource(resource_data)
846847
resource.mark_data_updated()
847848
assert resource.data_updated is True
848-
assert resource.is_data_updated() is True
849+
assert resource.is_marked_data_updated() is True
849850
resource.create_in_hdx()
850-
assert resource.is_data_updated() is False
851+
assert resource.is_marked_data_updated() is False
851852
assert resource["id"] == "74b74ae1-df0c-4716-829f-4f939a046811"
852853
assert resource.get_file_type() == "xlsx"
853854
assert resource["state"] == "active"
@@ -1010,3 +1011,16 @@ def test_mark_broken(self, configuration, post_broken):
10101011
assert resource["package_id"] == "6f36a41c-f126-4b18-aaaf-6c2ddfbc5d4d"
10111012
resource.mark_broken()
10121013
assert resource.is_broken() is True
1014+
1015+
def test_date_data_updated(self, configuration, read):
1016+
resource = Resource.read_from_hdx(
1017+
"74b74ae1-df0c-4716-829f-4f939a046811"
1018+
)
1019+
assert resource["id"] == "de6549d8-268b-4dfe-adaf-a4ae5c8510d5"
1020+
assert resource["name"] == "MyResource1"
1021+
assert resource["package_id"] == "6f36a41c-f126-4b18-aaaf-6c2ddfbc5d4d"
1022+
resource.set_date_data_updated("2020-03-02")
1023+
expected = "2020-03-02T00:00:00+00:00"
1024+
assert resource.get_date_data_updated().isoformat() == expected
1025+
resource.set_date_data_updated(parse_date("2020-03-02"))
1026+
assert resource.get_date_data_updated().isoformat() == expected

0 commit comments

Comments
 (0)