Skip to content

Commit 52eb2f4

Browse files
authored
Merge pull request #105 from planetlabs/add-iso-format-to-response
API: Add iso datetimes to datalake response sysval passing
2 parents f61854d + 81f9295 commit 52eb2f4

File tree

6 files changed

+69
-6
lines changed

6 files changed

+69
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,4 @@ target/
5858

5959
# build artifacts
6060
version.txt
61+
.claude/settings.local.json

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ IMAGE="$(REPO)/$(REPO_PATH):$(VERSION)"
77
docker: version
88
docker build --build-arg VERSION=$(VERSION) -t $(IMAGE) .
99

10-
.PHONY: devshell # Open a developer shell in the docker env
11-
devshell: docker
10+
.PHONY: dev # Open a developer shell in the docker env
11+
dev: docker
1212
docker run --rm -it -v $$PWD:/opt --entrypoint /bin/bash $(IMAGE)
1313

1414
test-client: docker

api/datalake_api/v0.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from flask import current_app as app
1919
import os
2020
import simplejson as json
21+
from datetime import datetime, timezone
22+
import decimal
2123
from .querier import ArchiveQuerier, Cursor, InvalidCursor, \
2224
DEFAULT_LOOKBACK_DAYS
2325
from .fetcher import ArchiveFileFetcher
@@ -29,6 +31,38 @@
2931

3032
_archive_querier = None
3133

34+
35+
def unix_ms_to_utc_iso(unix_ms):
36+
if unix_ms is None:
37+
return unix_ms
38+
unix_ms_to_iso = unix_ms
39+
if isinstance(unix_ms_to_iso, decimal.Decimal):
40+
unix_ms_to_iso = float(unix_ms_to_iso)
41+
iso = datetime.fromtimestamp(
42+
unix_ms_to_iso / 1000.0, tz=timezone.utc
43+
).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
44+
return iso
45+
46+
47+
def add_utc_metadata(metadata):
48+
"""Add ISO-8601 UTC timestamp fields to metadata dict
49+
50+
This function takes a metadata dict and adds start_iso and end_iso fields
51+
based on existing start and end epoch timestamps
52+
iso precision is set to milliseconds
53+
Can be expanded to add any api-level metadata
54+
"""
55+
if not metadata:
56+
return metadata
57+
58+
start_iso = unix_ms_to_utc_iso(metadata['start'])
59+
end_iso = unix_ms_to_utc_iso(metadata['end'])
60+
61+
metadata['start_iso'] = start_iso
62+
metadata['end_iso'] = end_iso
63+
return metadata
64+
65+
3266
def _get_aws_kwargs():
3367
kwargs = dict(
3468
region_name=app.config.get('AWS_REGION'),
@@ -305,6 +339,14 @@ def files_get():
305339
type: string
306340
description: 16-byte blake2 hash of the file
307341
content
342+
start_iso:
343+
type: string
344+
description: the start time of the file in ISO
345+
format UTC iso timezone
346+
end_iso:
347+
type: string
348+
description: the end time of the file in ISO
349+
format UTC iso timezone
308350
309351
next:
310352
type: string
@@ -349,7 +391,10 @@ def files_get():
349391
where=params.get('where'),
350392
cursor=params.get('cursor'))
351393

352-
[r.update(http_url=_get_canonical_http_url(r)) for r in results]
394+
for r in results:
395+
r.update(http_url=_get_canonical_http_url(r))
396+
r['metadata'] = add_utc_metadata(r['metadata'])
397+
353398
response = {
354399
'records': results,
355400
'next': _get_next_url(flask.request, results),
@@ -476,6 +521,7 @@ def file_get_metadata(file_id):
476521
id: DatalakeAPIError
477522
'''
478523
f = _get_file(file_id)
524+
f.metadata = add_utc_metadata(f.metadata)
479525
return Response(json.dumps(f.metadata), content_type='application/json')
480526

481527

@@ -542,6 +588,7 @@ def latest_get(what, where):
542588
params = _validate_latest_params(params)
543589
f = _get_latest(what, where, params.get('lookback', DEFAULT_LOOKBACK_DAYS))
544590
f.update(http_url=_get_canonical_http_url(f))
591+
f['metadata'] = add_utc_metadata(f['metadata'])
545592
return Response(json.dumps(f), content_type='application/json')
546593

547594

api/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def get_version_from_pyver():
3030
if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv:
3131
raise ImportError('You must install pyver to create a package')
3232
else:
33-
return 'noversion'
33+
return '0.0.0'
3434
version, version_info = pyver.get_version(pkg="datalake_api",
3535
public=True)
3636
return version

api/tests/test_metadata.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1212
# License for the specific language governing permissions and limitations under
1313
# the License.
14+
from datetime import datetime, timezone
15+
from decimal import Decimal
1416
import pytest
1517
import simplejson as json
1618

@@ -32,7 +34,20 @@ def test_get_metadata(metadata_getter, s3_file_maker, random_metadata):
3234
res = metadata_getter('12345')
3335
assert res.status_code == 200
3436
assert res.content_type == 'application/json'
35-
assert json.loads(res.data) == random_metadata
37+
res_data = json.loads(res.data)
38+
for k, v in res_data.items():
39+
if k == 'start_iso' or k == 'end_iso':
40+
k_epoch = k.replace('_iso','')
41+
v_epoch = res_data[k_epoch]
42+
if v is None:
43+
assert v == v_epoch
44+
45+
expected_v_iso = datetime.fromtimestamp(
46+
v_epoch / 1000.0, tz=timezone.utc
47+
).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
48+
assert v == expected_v_iso
49+
else:
50+
assert v == random_metadata[k]
3651

3752

3853
def test_no_such_metadata(s3_bucket_maker, metadata_getter):

ingester/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def get_version_from_pyver():
3030
if 'sdist' in sys.argv or 'bdist_wheel' in sys.argv:
3131
raise ImportError('You must install pyver to create a package')
3232
else:
33-
return 'noversion'
33+
return '0.0.0'
3434
version, version_info = pyver.get_version(pkg="datalake_ingester",
3535
public=True)
3636
return version

0 commit comments

Comments
 (0)