Skip to content

Commit b9f7d5e

Browse files
authored
Merge pull request #357 from dalito/issue2096-isodate-with-Z
Support isodate ending with Z
2 parents 8f2d867 + a1a6b48 commit b9f7d5e

File tree

4 files changed

+52
-36
lines changed

4 files changed

+52
-36
lines changed

.github/workflows/main.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
python-version: "3.8"
1919

2020
runs-on: ${{ matrix.os }}
21-
21+
2222
steps:
2323

2424
#----------------------------------------------

linkml_runtime/utils/metamodelcore.py

+39-26
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import re
44
from dataclasses import field
55
from decimal import Decimal
6+
import sys
67
from typing import Union, Optional, Tuple
78
from urllib.parse import urlparse
89

10+
import isodate
911
from rdflib import Literal, BNode, URIRef
1012
from rdflib.namespace import is_ncname
1113
from rdflib.term import Identifier as rdflib_Identifier
@@ -230,13 +232,10 @@ def __new__(cls, value: Union[str, datetime.time, datetime.datetime, Literal]) -
230232
if not isinstance(value, datetime.time):
231233
value = datetime.time.fromisoformat(value)
232234
return datetime.time.fromisoformat(str(value)).isoformat()
233-
except TypeError as e:
234-
pass
235-
except ValueError as e:
236-
pass
237-
if not is_strict():
238-
return str(value)
239-
raise e
235+
except (TypeError, ValueError) as e:
236+
if is_strict():
237+
raise e
238+
return str(value)
240239

241240
@classmethod
242241
def is_valid(cls, value: Union[str, datetime.time, datetime.datetime, Literal]) -> bool:
@@ -260,15 +259,15 @@ def __new__(cls, value: Union[str, datetime.date, Literal]) -> str:
260259
value = value.value
261260
try:
262261
if not isinstance(value, datetime.date):
263-
value = datetime.date.fromisoformat(str(value))
262+
if sys.version_info >= (3, 11):
263+
value = datetime.date.fromisoformat(str(value))
264+
else:
265+
value = isodate.parse_date(value)
264266
return value.isoformat()
265-
except TypeError as e:
266-
pass
267-
except ValueError as e:
268-
pass
269-
if not is_strict():
270-
return str(value)
271-
raise e
267+
except (TypeError, ValueError) as e:
268+
if is_strict():
269+
raise e
270+
return str(value)
272271

273272
@classmethod
274273
def is_valid(cls, value: Union[str, datetime.date, Literal]) -> bool:
@@ -279,7 +278,10 @@ def is_valid(cls, value: Union[str, datetime.date, Literal]) -> bool:
279278
if not re.match(r'^\d{4}-\d{2}-\d{2}$', value):
280279
return False
281280
try:
282-
datetime.date.fromisoformat(str(value))
281+
if sys.version_info >= (3, 11):
282+
datetime.date.fromisoformat(str(value))
283+
else:
284+
value = isodate.parse_date(value)
283285
except ValueError:
284286
return False
285287
return True
@@ -294,15 +296,18 @@ def __new__(cls, value: Union[str, datetime.datetime, Literal]) -> str:
294296
value = value.value
295297
try:
296298
if not isinstance(value, datetime.datetime):
297-
value = datetime.datetime.fromisoformat(value) # Note that this handles non 'T' format as well
299+
if sys.version_info >= (3, 11):
300+
value = datetime.datetime.fromisoformat(value) # Note that this handles non 'T' format as well
301+
else:
302+
if "T" in str(value):
303+
value = isodate.parse_datetime(value)
304+
else:
305+
value = isodate.parse_datetime("T".join(value.strip().split(' ', 1)))
298306
return value.isoformat()
299-
except TypeError as e:
300-
pass
301-
except ValueError as e:
302-
pass
303-
if not is_strict():
304-
return str(value)
305-
raise e
307+
except (TypeError, ValueError) as e:
308+
if is_strict():
309+
raise e
310+
return str(value)
306311

307312
@classmethod
308313
def is_valid(cls, value: Union[str, datetime.datetime, Literal]) -> bool:
@@ -311,8 +316,16 @@ def is_valid(cls, value: Union[str, datetime.datetime, Literal]) -> bool:
311316
if isinstance(value, datetime.datetime):
312317
value = value.isoformat()
313318
try:
314-
datetime.datetime.fromisoformat(value)
315-
except ValueError:
319+
if sys.version_info >= (3, 11):
320+
datetime.datetime.fromisoformat(value)
321+
else:
322+
if "T" in str(value):
323+
isodate.parse_datetime(value)
324+
elif " " in value.strip():
325+
isodate.parse_datetime("T".join(value.strip().split(' ', 1)))
326+
else:
327+
datetime.datetime.fromisoformat(value)
328+
except (ValueError, TypeError):
316329
return False
317330
return True
318331

tests/test_utils/test_metamodelcore.py

+5
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ def test_time(self):
153153
XSDDate(datetime.datetime.now())
154154
self.assertFalse(XSDTime.is_valid('Jan 12, 2019'))
155155
self.assertFalse(XSDTime.is_valid(datetime.datetime.now()))
156+
self.assertFalse(XSDTime.is_valid("2019-07-06T17:22:39Z"))
156157
self.assertTrue(XSDTime.is_valid(v))
157158

158159
def test_date(self):
@@ -168,6 +169,9 @@ def test_date(self):
168169
XSDDate('Jan 12, 2019')
169170
with self.assertRaises(ValueError):
170171
XSDDate(datetime.datetime.now())
172+
with self.assertRaises(ValueError):
173+
XSDDate("2019-07-06T17:22:39Z")
174+
171175
lax()
172176
bv = XSDDate('Jan 12, 2019')
173177
self.assertEqual('Jan 12, 2019', bv)
@@ -188,6 +192,7 @@ def test_datetime(self):
188192
vstr = str(Literal(v).value)
189193
self.assertEqual('2019-07-06 17:22:39.007300', vstr) # Note that this has no 'T'
190194
self.assertEqual('2019-07-06T17:22:39.007300', XSDDateTime(vstr))
195+
self.assertEqual('2019-07-06T17:22:39+00:00', XSDDateTime("2019-07-06T17:22:39Z"))
191196
with self.assertRaises(ValueError):
192197
XSDDateTime('Jan 12, 2019')
193198
lax()

tox.ini

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
[tox]
2-
envlist = py37, py38, py39, py310
3-
isolated_build = true
4-
skipsdist = true
5-
2+
envlist = py39, py310, py311, py312
63

74
[testenv]
8-
whitelist_externals = poetry
9-
commands=
10-
poetry install -v
11-
poetry run python -m unittest
12-
poetry run comparefiles --help
5+
skip_install = true
6+
allowlist_externals = poetry
7+
commands_pre =
8+
poetry install
9+
commands =
10+
poetry run pytest

0 commit comments

Comments
 (0)