Skip to content

Commit eb090d9

Browse files
authored
Merge pull request #88 from OpenEnergyPlatform/release/v0.1.2
Release/v0.1.2
2 parents d053137 + 08bb59b commit eb090d9

File tree

8 files changed

+191
-47
lines changed

8 files changed

+191
-47
lines changed

CHANGELOG.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ Changelog
55
current (2022-XX-XX)
66
--------------------
77

8+
0.1.2 (2023-01-27)
9+
--------------------
10+
* Fix datetime parser (PR#87)
11+
812
0.1.1 (2022-11-29)
913
--------------------
1014
* update parser for v15 to handle former v13 key names, also update outdated License (data-)class in oem_v15 structure. (PR#77)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def read(*names, **kwargs):
2424

2525
setup(
2626
name="omi",
27-
version="0.1.1",
27+
version="0.1.2",
2828
license="AGPL-3.0",
2929
description="A library to process and translate open energy metadata.",
3030
long_description="%s\n%s"

src/omi/dialects/oep/compiler.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
import json
2-
from collections import OrderedDict
3-
from datetime import datetime
1+
import datetime
42

53
from omi import structure
64
from omi.dialects.base.compiler import Compiler
75
from omi.oem_structures import oem_v15
86

97

8+
def compile_date_or_none(x, format=None):
9+
if isinstance(x, (datetime.datetime, datetime.date)):
10+
if format:
11+
return x.strftime(format)
12+
else:
13+
return x.isoformat()
14+
else:
15+
return x
16+
17+
1018
class JSONCompiler(Compiler):
1119
__METADATA_VERSION = "OEP-1.4.0"
1220

13-
def _compile_date(self, date: datetime, format):
14-
if date:
15-
return date.strftime(format)
16-
else:
17-
return None
18-
1921
def _construct_dict(self, *args, omit_none=True, **kwargs):
2022
"""
2123
Accepts a list of arguments of shape (name: str, field: Compileable) and returns a dictionary that maps
@@ -61,7 +63,7 @@ def visit_contribution(self, contribution: structure.Contribution, *args, **kwar
6163
("email", contribution.contributor.email),
6264
("object", contribution.object),
6365
("comment", contribution.comment),
64-
("date", self._compile_date(contribution.date, "%Y-%m-%d")),
66+
("date", compile_date_or_none(contribution.date, "%Y-%m-%d")),
6567
)
6668

6769
def visit_language(self, language: structure.Language, *args, **kwargs):
@@ -90,11 +92,14 @@ def visit_temporal(self, temporal: structure.Temporal, *args, **kwargs):
9092
start = None
9193
end = None
9294
if temporal.ts_start is not None:
93-
start = self._compile_date(temporal.ts_start, "%Y-%m-%dT%H:%M%z")[:-2]
95+
start = compile_date_or_none(temporal.ts_start)
9496
if temporal.ts_end is not None:
95-
end = self._compile_date(temporal.ts_end, "%Y-%m-%dT%H:%M%z")[:-2]
97+
end = compile_date_or_none(temporal.ts_end)
9698
return self._construct_dict(
97-
("referenceDate", self._compile_date(temporal.reference_date, "%Y-%m-%d")),
99+
(
100+
"referenceDate",
101+
compile_date_or_none(temporal.reference_date, "%Y-%m-%d"),
102+
),
98103
timeseries=self._construct_dict(
99104
("start", start),
100105
("end", end),
@@ -202,7 +207,9 @@ def visit_meta_comment(self, comment: structure.MetaComment, *args, **kwargs):
202207
def visit_metadata(self, metadata: structure.OEPMetadata, *args, **kwargs):
203208
publication_date = None
204209
if metadata.publication_date is not None:
205-
publication_date = self._compile_date(metadata.publication_date, "%Y-%m-%d")
210+
publication_date = compile_date_or_none(
211+
metadata.publication_date, "%Y-%m-%d"
212+
)
206213
return self._construct_dict(
207214
("name", metadata.name),
208215
("title", metadata.title),
@@ -286,9 +293,9 @@ def visit_timeseries(self, timeseries: oem_v15.Timeseries, *args, **kwargs):
286293
start = None
287294
end = None
288295
if timeseries.ts_start is not None:
289-
start = self._compile_date(timeseries.ts_start, "%Y-%m-%dT%H:%M%z")[:-2]
296+
start = compile_date_or_none(timeseries.ts_start)
290297
if timeseries.ts_end is not None:
291-
end = self._compile_date(timeseries.ts_end, "%Y-%m-%dT%H:%M%z")[:-2]
298+
end = compile_date_or_none(timeseries.ts_end)
292299
return self._construct_dict(
293300
("start", start),
294301
("end", end),
@@ -299,10 +306,13 @@ def visit_timeseries(self, timeseries: oem_v15.Timeseries, *args, **kwargs):
299306

300307
def visit_temporal(self, temporal: oem_v15.Temporal, *args, **kwargs):
301308
return self._construct_dict(
302-
("referenceDate", self._compile_date(temporal.reference_date, "%Y-%m-%d")),
309+
(
310+
"referenceDate",
311+
compile_date_or_none(temporal.reference_date, "%Y-%m-%d"),
312+
),
303313
("timeseries", temporal.timeseries_collection),
304314
)
305-
315+
306316
def visit_license(self, lic: oem_v15.License, *args, **kwargs):
307317
return self._construct_dict(
308318
("name", lic.name),
@@ -347,7 +357,9 @@ def visit_meta_comment(self, comment: oem_v15.MetaComment, *args, **kwargs):
347357
def visit_metadata(self, metadata: oem_v15.OEPMetadata, *args, **kwargs):
348358
publication_date = None
349359
if metadata.publication_date is not None:
350-
publication_date = self._compile_date(metadata.publication_date, "%Y-%m-%d")
360+
publication_date = compile_date_or_none(
361+
metadata.publication_date, "%Y-%m-%d"
362+
)
351363
return self._construct_dict(
352364
("name", metadata.name),
353365
("title", metadata.title),

src/omi/dialects/oep/parser.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import json
55
import logging
66
import pathlib
7+
import re
78

9+
import dateutil
810
import jsonschema
9-
from dateutil.parser import parse as parse_date
1011
from jsonschema import ValidationError
1112
# oemetadata
1213
from metadata.latest.schema import OEMETADATA_LATEST_SCHEMA
@@ -31,15 +32,42 @@
3132
]
3233

3334

34-
def parse_date_or_none(x, *args, **kwargs):
35+
def parse_date_or_none(x):
3536
if x is None:
36-
return None
37+
pass
38+
elif type(x) == int:
39+
# e.g just a year or a unix timestamp
40+
# NOTE: isinstance(x, int) is also True for a bool,
41+
# which we dont want
42+
pass
43+
elif isinstance(x, str):
44+
# IMPORTANT NOTE: only use dateutil.parser if date part is complete
45+
# if you parse something like '2020' or '2020-01', it will silently
46+
# fill in the missing month/day from the current date!
47+
# in this case, we keep the string, if it is at least is the correct pattern
48+
49+
if re.match("^[123][0-9]{3}(|-[0-9]{1,2})$", x):
50+
# only year or year-month: keep string
51+
pass
52+
elif re.match("^[123][0-9]{3}-[0-9]{1,2}-[0-9]{1,2}", x):
53+
try:
54+
date_time = dateutil.parser.parse(x)
55+
except Exception:
56+
raise ParserException(f"invalid value for date: {x}")
57+
if re.match("^[123][0-9]{3}-[0-9]{1,2}-[0-9]{1,2}$", x):
58+
# date only
59+
x = date_time.date()
60+
else:
61+
x = date_time
62+
else:
63+
raise ParserException(f"invalid value for date: {x}")
3764
else:
38-
return parse_date(x, *args, **kwargs)
65+
raise ParserException(f"invalid type for date: {type(x)}")
66+
return x
3967

4068

4169
def create_report_json(
42-
error_data, # type list[dict]
70+
error_data, # type list[dict]
4371
save_at: pathlib.Path = "reports/",
4472
filename: str = "report.json",
4573
):
@@ -54,7 +82,6 @@ def create_report_json(
5482

5583

5684
class JSONParser(Parser):
57-
5885
def normalize_key_names_of_input(iput: dict):
5986
pass
6087

@@ -215,7 +242,6 @@ def is_valid(self, inp: dict, schema=OEMETADATA_V130_SCHEMA):
215242
except ValidationError:
216243
return False
217244

218-
219245
def parse(self, json_old, *args, **kwargs):
220246
# context section
221247
context = None
@@ -795,7 +821,10 @@ def parse_from_string(
795821
)
796822

797823
def get_any_value_not_none(
798-
self, element: dict, keys, get_return_default=None #keys: list[str] - reove as not support by py3.8
824+
self,
825+
element: dict,
826+
keys,
827+
get_return_default=None, # keys: list[str] - reove as not support by py3.8
799828
):
800829
"""
801830
Get the value for a key in a dict - but try multiple key names, in
@@ -1145,7 +1174,7 @@ def parse_licence_including_former_structure(licences_element):
11451174
primary_key=resource["schema"].get("primaryKey"),
11461175
foreign_keys=foreign_keys,
11471176
)
1148-
1177+
11491178
old_dialect = resource.get("dialect")
11501179
if old_dialect is None:
11511180
dialect = None

tests/data/metadata_v14.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
"temporal": {
3333
"referenceDate": "2016-01-01",
3434
"timeseries": {
35-
"start": "2017-01-01T00:00+01",
36-
"end": "2017-12-31T23:00+01",
35+
"start": "2017-01-01T00:00:00+01:00",
36+
"end": "2017-12-31T23:00:00+01:00",
3737
"resolution": "1 h",
3838
"alignment": "left",
3939
"aggregationType": "sum"

tests/data/metadata_v15.json

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@
4444
"referenceDate": "2016-01-01",
4545
"timeseries": [
4646
{
47-
"start": "2017-01-01T00:00+01",
48-
"end": "2017-12-31T23:00+01",
47+
"start": "2017-01-01T00:00:00+01:00",
48+
"end": "2017-12-31T23:00:00+01:00",
4949
"resolution": "1 h",
5050
"alignment": "left",
5151
"aggregationType": "sum"
5252
},
5353
{
54-
"start": "2018-01-01T00:00+01",
55-
"end": "2019-06-01T23:00+01",
54+
"start": "2018-01-01T00:00:00+01:00",
55+
"end": "2019-06-01T23:00:00+01:00",
5656
"resolution": "15 min",
5757
"alignment": "right",
5858
"aggregationType": "sum"
@@ -126,12 +126,10 @@
126126
"description": "Unique identifier",
127127
"type": "serial",
128128
"isAbout": [
129-
{
130-
}
129+
{}
131130
],
132131
"valueReference": [
133-
{
134-
}
132+
{}
135133
]
136134
},
137135
{
@@ -145,8 +143,7 @@
145143
}
146144
],
147145
"valueReference": [
148-
{
149-
}
146+
{}
150147
]
151148
},
152149
{
@@ -183,8 +180,7 @@
183180
}
184181
],
185182
"valueReference": [
186-
{
187-
}
183+
{}
188184
]
189185
},
190186
{
@@ -199,8 +195,7 @@
199195
}
200196
],
201197
"valueReference": [
202-
{
203-
}
198+
{}
204199
]
205200
},
206201
{
@@ -214,8 +209,7 @@
214209
}
215210
],
216211
"valueReference": [
217-
{
218-
}
212+
{}
219213
]
220214
}
221215
],

tests/test_dialects/test_oep/test_regression/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)