Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add special handling for gYear and gYearMonth #1315

Merged
merged 1 commit into from
Jun 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions rdflib/term.py
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,8 @@ def _parseBoolean(value):
_OWL_RATIONAL = URIRef("http://www.w3.org/2002/07/owl#rational")
_XSD_B64BINARY = URIRef(_XSD_PFX + "base64Binary")
_XSD_HEXBINARY = URIRef(_XSD_PFX + "hexBinary")
_XSD_GYEAR = URIRef(_XSD_PFX + "gYear")
_XSD_GYEARMONTH = URIRef(_XSD_PFX + "gYearMonth")
# TODO: gYearMonth, gYear, gMonthDay, gDay, gMonth

_NUMERIC_LITERAL_TYPES = (
Expand Down Expand Up @@ -1558,6 +1560,8 @@ def _castPythonToLiteral(obj, datatype):
]

_SpecificPythonToXSDRules = [
((date, _XSD_GYEAR), lambda val: val.strftime("%04Y")),
((date, _XSD_GYEARMONTH), lambda val: val.strftime("%04Y-%02m")),
((str, _XSD_HEXBINARY), hexlify),
((bytes, _XSD_HEXBINARY), hexlify),
((str, _XSD_B64BINARY), b64encode),
Expand Down
76 changes: 76 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,79 @@ 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),
("NOT A VALID HEX STRING", XSD.hexBinary, None),
("NOT A VALID BASE64 STRING", XSD.base64Binary, 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),
("abcdef0123", XSD.hexBinary, bytes),
("", XSD.hexBinary, bytes),
("UkRGTGli", XSD.base64Binary, bytes),
("", XSD.base64Binary, bytes),
]
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()