Skip to content

Commit

Permalink
Add special handling for gYear and gYearMonth in _SpecificPythonToXSD…
Browse files Browse the repository at this point in the history
…Rules

This should solve various issues that occur with hanlding of xsd:gYear
and xsd:gYearMonth values.
  • Loading branch information
aucampia committed May 15, 2021
1 parent 8d592a2 commit fc1cece
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
4 changes: 4 additions & 0 deletions rdflib/term.py
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,8 @@ def _parseBoolean(value):

_OWL_RATIONAL = URIRef("http://www.w3.org/2002/07/owl#rational")
_XSD_HEXBINARY = URIRef(_XSD_PFX + "hexBinary")
_XSD_YEAR = URIRef(_XSD_PFX + "gYear")
_XSD_YEARMONTH = URIRef(_XSD_PFX + "gYearMonth")
# TODO: gYearMonth, gYear, gMonthDay, gDay, gMonth

_NUMERIC_LITERAL_TYPES = (
Expand Down Expand Up @@ -1559,6 +1561,8 @@ def _castPythonToLiteral(obj, datatype):
_SpecificPythonToXSDRules = [
((str, _XSD_HEXBINARY), hexlify),
((bytes, _XSD_HEXBINARY), hexlify),
((date, _XSD_YEAR), lambda val: val.strftime("%04Y")),
((date, _XSD_YEARMONTH), lambda val: val.strftime("%04Y-%02m")),
]

XSDToPython = {
Expand Down
70 changes: 70 additions & 0 deletions test/test_literal.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import unittest
import datetime

import rdflib # needed for eval(repr(...)) below
from rdflib.term import Literal, URIRef, _XSD_DOUBLE, bind, _XSD_BOOLEAN
from rdflib.namespace import XSD


def uformat(s):
Expand Down Expand Up @@ -188,5 +190,73 @@ def unlexify(s):
self.assertEqual(specific_l.datatype, datatype)


class TestXsdLiterals(unittest.TestCase):
def test_make_literals(self):
"""
Tests literal construction.
"""
inputs = [
# these literals do not get conerted to python types
("ABCD", XSD.integer, None),
("ABCD", XSD.gYear, None),
("-10000", XSD.gYear, None),
("-1921-00", XSD.gYearMonth, None),
("1921-00", XSD.gMonthDay, None),
("1921-13", XSD.gMonthDay, None),
("-1921-00", XSD.gMonthDay, None),
("10", XSD.gDay, None),
("-1", XSD.gDay, None),
("0000", XSD.gYear, None),
("0000-00-00", XSD.date, None),
# these literals get converted to python types
("1921-05-01", XSD.date, datetime.date),
("1921-05-01T00:00:00", XSD.dateTime, datetime.datetime),
("1921-05", XSD.gYearMonth, datetime.date),
("0001-01", XSD.gYearMonth, datetime.date),
("0001-12", XSD.gYearMonth, datetime.date),
("2002-01", XSD.gYearMonth, datetime.date),
("9999-01", XSD.gYearMonth, datetime.date),
("9999-12", XSD.gYearMonth, datetime.date),
("1921", XSD.gYear, datetime.date),
("2000", XSD.gYear, datetime.date),
("0001", XSD.gYear, datetime.date),
("9999", XSD.gYear, datetime.date),
("1982", XSD.gYear, datetime.date),
("2002", XSD.gYear, datetime.date),
("1921-05-01T00:00:00+00:30", XSD.dateTime, datetime.datetime),
("1921-05-01T00:00:00-00:30", XSD.dateTime, datetime.datetime),
]
self.check_make_literals(inputs)

@unittest.expectedFailure
def test_make_literals_ki(self):
"""
Known issues with literal construction.
"""
inputs = [
("1921-01Z", XSD.gYearMonth, datetime.date),
("1921Z", XSD.gYear, datetime.date),
("1921-00", XSD.gYearMonth, datetime.date),
("1921-05-01Z", XSD.date, datetime.date),
("1921-05-01+00:30", XSD.date, datetime.date),
("1921-05-01+00:30", XSD.date, datetime.date),
("1921-05-01+00:00", XSD.date, datetime.date),
("1921-05-01+00:00", XSD.date, datetime.date),
("1921-05-01T00:00:00Z", XSD.dateTime, datetime.datetime),
]
self.check_make_literals(inputs)

def check_make_literals(self, inputs):
for literal_pair in inputs:
(lexical, type, value_cls) = literal_pair
with self.subTest(f"tesing {literal_pair}"):
literal = Literal(lexical, datatype=type)
if value_cls is not None:
self.assertIsInstance(literal.value, value_cls)
else:
self.assertIsNone(literal.value)
self.assertEqual(lexical, f"{literal}")


if __name__ == "__main__":
unittest.main()
42 changes: 42 additions & 0 deletions test/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,47 @@ def testNoPathWithHash(self):
self.assertEqual(type, RDFS.Class)


class TestGitHubIssues(unittest.TestCase):
def test_issue_1228_a(self):
data = """
PREFIX sdo: <https://schema.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
<x:> sdo:startDate "1982"^^xsd:gYear .
"""

g = Graph().parse(data=data, format="ttl")
self.assertNotIn("1982-01-01", data)
self.assertNotIn("1982-01-01", g.serialize(format="ttl"))

def test_issue_1228_b(self):
data = """\
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:sdo="https://schema.org/"
>
<rdf:Description rdf:about="x:">
<sdo:startDate
rdf:datatype="http://www.w3.org/2001/XMLSchema#gYear">1982</sdo:startDate>
</rdf:Description>
</rdf:RDF>"""

g = Graph().parse(data=data, format="xml")
self.assertNotIn("1982-01-01", data)
self.assertNotIn("1982-01-01", g.serialize(format="xml"))

def test_issue_806(self):
data = (
"<http://dbpedia.org/resource/Australian_Labor_Party> "
"<http://dbpedia.org/ontology/formationYear> "
'"1891"^^<http://www.w3.org/2001/XMLSchema#gYear> .'
)
g = Graph()
g.parse(data=data, format="nt")
for _, _, o in g:
self.assertNotIn("1891-01-01", o.n3())


if __name__ == "__main__":
unittest.main()

0 comments on commit fc1cece

Please sign in to comment.