Repository navigation
Literal equality fails for datatypes None and XSD.string #2123
Copy link
Copy link
Open
Labels
accepting PRPRs for this issue will be considered.PRs for this issue will be considered.breaking changeThis involves or proposes breaking RDFLib's public API.This involves or proposes breaking RDFLib's public API.bugSomething isn't workingSomething isn't workingconcept: RDF Literalconcept: datatypeRelates to the RDF literal datatype concept.Relates to the RDF literal datatype concept.coreRelates to core functionality of RDFLib, i.e. `rdflib.{graph,store,term}`Relates to core functionality of RDFLib, i.e. `rdflib.{graph,store,term}`feedback wantedFeedback from RDFLib users and contributors is wanted.Feedback from RDFLib users and contributors is wanted.needs discussionThis issue needs further discussion to find an optimal way to resolve it.This issue needs further discussion to find an optimal way to resolve it.parsingRelated to a parsing.Related to a parsing.
Description
Example:
>>> from rdflib import Literal
>>> from rdflib.namespace import XSD
>>> Literal('foo') == Literal('foo', datatype=XSD.string)
FalseAccording to https://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal, every literal has a datatype (and a simple literal without a datatype should be considered syntactic sugar for literals of datatype http://www.w3.org/2001/XMLSchema#string).
The implementation in rdflib seems to follow the original RDF (not RDF 1.1), which allowed missing datatypes.
Related issues:
- Literal should always have a datatype #1326 proposes to always set a datatype (which would work, but might break things).
PS:
A similar problem would presumably occur with RDF.langString, except that setting both lang and datatype results in an error (which might also be an issue).
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
accepting PRPRs for this issue will be considered.PRs for this issue will be considered.breaking changeThis involves or proposes breaking RDFLib's public API.This involves or proposes breaking RDFLib's public API.bugSomething isn't workingSomething isn't workingconcept: RDF Literalconcept: datatypeRelates to the RDF literal datatype concept.Relates to the RDF literal datatype concept.coreRelates to core functionality of RDFLib, i.e. `rdflib.{graph,store,term}`Relates to core functionality of RDFLib, i.e. `rdflib.{graph,store,term}`feedback wantedFeedback from RDFLib users and contributors is wanted.Feedback from RDFLib users and contributors is wanted.needs discussionThis issue needs further discussion to find an optimal way to resolve it.This issue needs further discussion to find an optimal way to resolve it.parsingRelated to a parsing.Related to a parsing.
Activity
aucampia commentedon Mar 20, 2023
This is a bug, but fixing it without a major version bump may be somewhat controversial.
aucampia commentedon Jun 9, 2023
One option to solve this is to enforce that
rdflib.terms.Literalalways has a datatype, but then we won't be able to support RDF 1.0 anymore. I'm somewhat okay with this, I think it would be nice to be able to support 1.0 and 1.1 - but I think 1.1. support is more important.aucampia commentedon Jun 9, 2023
I think the best option is to just not allow null literals.
4 remaining items
aucampia commentedon Jun 9, 2023
The alternative is to maybe create a Literal abstract class which has optional data type and then have Literal with mandatory Datatype but also RDF10Literal with optional datatype, but I think that is going to be too much work.
Tpt commentedon Jun 10, 2023
An other option: allow
Nonedatatype but for__eq__and__hash__useself.datatype or XSD.stringto get the datatype. This should ensure proper equality support while keeping the "plain literal" information.It might be nice to tweak the constructor to fail only if datatype is not
RDF.langString.aucampia commentedon Jun 10, 2023
This may be quite unexpected if someone is not familiar with RDF, and even for me, I would expect that the property has a stable value and that value is used during equality and hashing.
I think eliminating the possibility of None datatypes is simpler for users to understand.
For the constructor, I'm thinking of having 3 overloads:
def __new__(value: str, datatype: str = XSD.string)-> Created withlang=Nonedef __new__(value: str, lang: str)-> Created withdatatype=XSD.langStringdef __new__(value: str, lang: str, datatype: str)-> Create with the supplied datatype and lang, potentially with some validation.One obvious problem with validation is that it sometimes it may be undesirable, but I think we can maybe in future add a static variable on the Literal class to control its strictness (e.g.
Literal.strict), even though that is not the nicest thing.I think at some point we should look at making factories that can control strictness in a way that does not involve global state, but right now, being overly strict may be best as it is easier to make it more lax later, I think.
aucampia commentedon Jun 10, 2023
Another related issue:
Tpt commentedon Jun 10, 2023
Indeed. It makes perfect sense.
This variant seems dangerous because it indeed requires some validation. What about only allowing the first two overloads, making sure that
datatypecan not be set at the same time withlang? This way no validation would be needed.aucampia commentedon Jun 10, 2023
The only potential use may be if we have a stream of data where we get Literals as
value,datatypeandlanguage, a bit similar to data from HexT, but I will try to avoid adding this overload as I agree it is best to not have it if we don't need it, and if we really do need it we can add it later.aucampia commentedon Jun 20, 2023
One problem is that SPARQL 1.1 defines Simple Literal:
I check RDF4J and Jena, Jena's Literal does support null datatypes:
https://www.javadoc.io/doc/org.apache.jena/jena-core/latest/org.apache.jena.core/org/apache/jena/rdf/model/impl/LiteralImpl.html
RDF4J on the other hand defaults to xsd:string for datatype as the RDF 1.1 standard defines.
Probably on balance still right to use the RDF 1.1 spec, but worth highlighting this caveat.
aucampia commentedon Jun 20, 2023
I guess the right option is to just defer to the RDF 1.1 spec.
aucampia commentedon Jun 20, 2023
What we can also do is have a
simpleattribute on Literal which is true if the Literal is initialized with a null datatype 🤔But we can maybe add that later also.
aucampia commentedon Jun 20, 2023
This would complicate equality about as much as having
datatype=Nonebeing equal todatatype=XSD.stringaucampia commentedon Jun 20, 2023
I made a draft PR (#2460) that still has some work left, I think some tests will fail, but one thing which is quite apparent is that there are cases where passing datatype=None and having it be interpreted as
xsd:stringis helpful, mainly because there is quite often cases where the passed parameter is of typeOptional[str].