term.py 89 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517
  1. """
  2. This module defines the different types of terms. Terms are the kinds of
  3. objects that can appear in a quoted/asserted triple. This includes those
  4. that are core to RDF:
  5. * [Blank Nodes][rdflib.term.BNode] - Blank Nodes
  6. * [URI References][rdflib.term.URIRef] - URI References
  7. * [Literals][rdflib.term.Literal] - Literals (which consist of a literal value, datatype and language tag)
  8. Those that extend the RDF model into N3:
  9. * [`QuotedGraph`][rdflib.graph.QuotedGraph] - Formulae
  10. * [`Variable`][rdflib.term.Variable] - Universal Quantifications (Variables)
  11. And those that are primarily for matching against 'Nodes' in the
  12. underlying Graph:
  13. * REGEX Expressions
  14. * Date Ranges
  15. * Numerical Ranges
  16. """
  17. from __future__ import annotations
  18. import abc
  19. import re
  20. from fractions import Fraction
  21. __all__ = [
  22. "bind",
  23. "_is_valid_uri",
  24. "Node",
  25. "IdentifiedNode",
  26. "Identifier",
  27. "URIRef",
  28. "BNode",
  29. "Literal",
  30. "Variable",
  31. ]
  32. import logging
  33. import math
  34. import warnings
  35. import xml.dom.minidom
  36. from base64 import b64decode, b64encode
  37. from binascii import hexlify, unhexlify
  38. from collections import defaultdict
  39. from datetime import date, datetime, time, timedelta
  40. from decimal import Decimal
  41. from re import compile, sub
  42. from types import GeneratorType
  43. from typing import (
  44. TYPE_CHECKING,
  45. Any,
  46. Callable,
  47. Dict,
  48. Generator,
  49. List,
  50. Optional,
  51. Tuple,
  52. Type,
  53. TypeVar,
  54. Union,
  55. )
  56. from urllib.parse import urldefrag, urljoin, urlparse
  57. from uuid import uuid4
  58. import rdflib
  59. import rdflib.util
  60. from rdflib.compat import long_type
  61. from .xsd_datetime import ( # type: ignore[attr-defined]
  62. Duration,
  63. duration_isoformat,
  64. parse_datetime,
  65. parse_time,
  66. parse_xsd_date,
  67. parse_xsd_duration,
  68. )
  69. if TYPE_CHECKING:
  70. from .namespace import NamespaceManager
  71. from .paths import AlternativePath, InvPath, NegatedPath, Path, SequencePath
  72. _HAS_HTML5RDF = False
  73. try:
  74. import html5rdf
  75. _HAS_HTML5RDF = True
  76. except ImportError:
  77. html5rdf = None
  78. _SKOLEM_DEFAULT_AUTHORITY = "https://rdflib.github.io"
  79. logger = logging.getLogger(__name__)
  80. skolem_genid = "/.well-known/genid/"
  81. rdflib_skolem_genid = "/.well-known/genid/rdflib/"
  82. skolems: Dict[str, BNode] = {}
  83. _invalid_uri_chars = '<>" {}|\\^`'
  84. def _is_valid_uri(uri: str) -> bool:
  85. for c in _invalid_uri_chars:
  86. if c in uri:
  87. return False
  88. return True
  89. _lang_tag_regex = compile("^[a-zA-Z]+(?:-[a-zA-Z0-9]+)*$")
  90. def _is_valid_langtag(tag: str) -> bool:
  91. return bool(_lang_tag_regex.match(tag))
  92. def _is_valid_unicode(value: Union[str, bytes]) -> bool:
  93. """
  94. Verify that the provided value can be converted into a Python
  95. unicode object.
  96. """
  97. if isinstance(value, bytes):
  98. coding_func, param = getattr(value, "decode"), "utf-8"
  99. else:
  100. coding_func, param = str, value
  101. # try to convert value into unicode
  102. try:
  103. coding_func(param)
  104. except UnicodeError:
  105. return False
  106. return True
  107. class Node(abc.ABC):
  108. """A Node in the Graph."""
  109. __slots__ = ()
  110. @abc.abstractmethod
  111. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: ...
  112. class Identifier(Node, str): # allow Identifiers to be Nodes in the Graph
  113. """See http://www.w3.org/2002/07/rdf-identifer-terminology/
  114. regarding choice of terminology."""
  115. __slots__ = ()
  116. def __new__(cls, value: str):
  117. return str.__new__(cls, value)
  118. def eq(self, other: Any) -> bool:
  119. """A "semantic"/interpreted equality function,
  120. by default, same as __eq__"""
  121. return self.__eq__(other)
  122. def neq(self, other: Any) -> bool:
  123. """A "semantic"/interpreted not equal function,
  124. by default, same as __ne__"""
  125. return self.__ne__(other)
  126. def __ne__(self, other: Any) -> bool:
  127. return not self.__eq__(other)
  128. def __eq__(self, other: Any) -> bool:
  129. """Equality for Nodes.
  130. ```python
  131. >>> BNode("foo")==None
  132. False
  133. >>> BNode("foo")==URIRef("foo")
  134. False
  135. >>> URIRef("foo")==BNode("foo")
  136. False
  137. >>> BNode("foo")!=URIRef("foo")
  138. True
  139. >>> URIRef("foo")!=BNode("foo")
  140. True
  141. >>> Variable('a')!=URIRef('a')
  142. True
  143. >>> Variable('a')!=Variable('a')
  144. False
  145. ```
  146. """
  147. if type(self) is type(other):
  148. return str(self) == str(other)
  149. else:
  150. return False
  151. def __gt__(self, other: Any) -> bool:
  152. """This implements ordering for Nodes.
  153. This tries to implement this:
  154. http://www.w3.org/TR/sparql11-query/#modOrderBy
  155. Variables are not included in the SPARQL list, but
  156. they are greater than BNodes and smaller than everything else
  157. """
  158. if other is None:
  159. return True # everything bigger than None
  160. elif type(self) is type(other):
  161. return str(self) > str(other)
  162. elif isinstance(other, Node):
  163. return _ORDERING[type(self)] > _ORDERING[type(other)]
  164. return NotImplemented
  165. def __lt__(self, other: Any) -> bool:
  166. if other is None:
  167. return False # Nothing is less than None
  168. elif type(self) is type(other):
  169. return str(self) < str(other)
  170. elif isinstance(other, Node):
  171. return _ORDERING[type(self)] < _ORDERING[type(other)]
  172. return NotImplemented
  173. def __le__(self, other: Any) -> bool:
  174. r = self.__lt__(other)
  175. if r:
  176. return True
  177. return self == other
  178. def __ge__(self, other: Any) -> bool:
  179. r = self.__gt__(other)
  180. if r:
  181. return True
  182. return self == other
  183. # type error: Argument 1 of "startswith" is incompatible with supertype "str"; supertype defines the argument type as "Union[str, Tuple[str, ...]]"
  184. # FIXME: this does not accommodate prefix of type Tuple[str, ...] which is a
  185. # valid for str.startswith
  186. def startswith(self, prefix: str, start=..., end=...) -> bool: # type: ignore[override] # FIXME
  187. return str(self).startswith(str(prefix))
  188. # use parent's hash for efficiency reasons
  189. # clashes of 'foo', URIRef('foo') and Literal('foo') are typically so rare
  190. # that they don't justify additional overhead. Notice that even in case of
  191. # clash __eq__ is still the fallback and very quick in those cases.
  192. __hash__ = str.__hash__
  193. class IdentifiedNode(Identifier):
  194. """
  195. An abstract class, primarily defined to identify Nodes that are not Literals.
  196. The name "Identified Node" is not explicitly defined in the RDF specification, but can be drawn from this section: https://www.w3.org/TR/rdf-concepts/#section-URI-Vocabulary
  197. """
  198. __slots__ = ()
  199. def __getnewargs__(self) -> Tuple[str]:
  200. return (str(self),)
  201. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
  202. raise NotImplementedError()
  203. def toPython(self) -> str: # noqa: N802
  204. return str(self)
  205. class URIRef(IdentifiedNode):
  206. """[RDF 1.1's IRI Section](https://www.w3.org/TR/rdf11-concepts/#section-IRIs)
  207. !!! info "Terminology"
  208. Documentation on RDF outside of RDFLib uses the term IRI or URI whereas this class is called URIRef. This is because it was made when the first version of the RDF specification was current, and it used the term *URIRef*, see [RDF 1.0 URIRef](http://www.w3.org/TR/rdf-concepts/#section-Graph-URIref)
  209. An IRI (Internationalized Resource Identifier) within an RDF graph is a Unicode string that conforms to the syntax defined in RFC 3987.
  210. IRIs in the RDF abstract syntax MUST be absolute, and MAY contain a fragment identifier.
  211. IRIs are a generalization of URIs [RFC3986] that permits a wider range of Unicode characters.
  212. """
  213. __slots__ = ()
  214. __or__: Callable[[URIRef, Union[URIRef, Path]], AlternativePath]
  215. __invert__: Callable[[URIRef], InvPath]
  216. __neg__: Callable[[URIRef], NegatedPath]
  217. __truediv__: Callable[[URIRef, Union[URIRef, Path]], SequencePath]
  218. def __new__(cls, value: str, base: Optional[str] = None):
  219. if base is not None:
  220. ends_in_hash = value.endswith("#")
  221. # type error: Argument "allow_fragments" to "urljoin" has incompatible type "int"; expected "bool"
  222. value = urljoin(base, value, allow_fragments=1) # type: ignore[arg-type]
  223. if ends_in_hash:
  224. if not value.endswith("#"):
  225. value += "#"
  226. if not _is_valid_uri(value):
  227. logger.warning(
  228. f"{value} does not look like a valid URI, trying to serialize this will break."
  229. )
  230. try:
  231. rt = str.__new__(cls, value)
  232. except UnicodeDecodeError:
  233. # type error: No overload variant of "__new__" of "str" matches argument types "Type[URIRef]", "str", "str"
  234. rt = str.__new__(cls, value, "utf-8") # type: ignore[call-overload]
  235. return rt
  236. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
  237. """This will do a limited check for valid URIs,
  238. essentially just making sure that the string includes no illegal
  239. characters (`<, >, ", {, }, |, \\, `, ^`)
  240. Args:
  241. namespace_manager: if not None, will be used to make up a prefixed name
  242. """
  243. if not _is_valid_uri(self):
  244. raise Exception(
  245. f'"{self}" does not look like a valid URI, I cannot serialize this as N3/Turtle. Perhaps you wanted to urlencode it?'
  246. )
  247. if namespace_manager:
  248. return namespace_manager.normalizeUri(self)
  249. else:
  250. return f"<{self}>"
  251. def defrag(self) -> URIRef:
  252. if "#" in self:
  253. url, frag = urldefrag(self)
  254. return URIRef(url)
  255. else:
  256. return self
  257. @property
  258. def fragment(self) -> str:
  259. """Return the URL Fragment
  260. ```python
  261. >>> URIRef("http://example.com/some/path/#some-fragment").fragment
  262. 'some-fragment'
  263. >>> URIRef("http://example.com/some/path/").fragment
  264. ''
  265. ```
  266. """
  267. return urlparse(self).fragment
  268. def __reduce__(self) -> Tuple[Type[URIRef], Tuple[str]]:
  269. return (URIRef, (str(self),))
  270. def __repr__(self) -> str:
  271. if self.__class__ is URIRef:
  272. clsName = "rdflib.term.URIRef" # noqa: N806
  273. else:
  274. clsName = self.__class__.__name__ # noqa: N806
  275. return f"{clsName}({str.__repr__(self)})"
  276. def __add__(self, other) -> URIRef:
  277. return self.__class__(str(self) + other)
  278. def __radd__(self, other) -> URIRef:
  279. return self.__class__(other + str(self))
  280. def __mod__(self, other) -> URIRef:
  281. return self.__class__(str(self) % other)
  282. def de_skolemize(self) -> BNode:
  283. """Create a Blank Node from a skolem URI, in accordance
  284. with http://www.w3.org/TR/rdf11-concepts/#section-skolemization.
  285. This function accepts only rdflib type skolemization, to provide
  286. a round-tripping within the system.
  287. Added in version 4.0
  288. """
  289. if isinstance(self, RDFLibGenid):
  290. parsed_uri = urlparse(f"{self}")
  291. return BNode(value=parsed_uri.path[len(rdflib_skolem_genid) :])
  292. elif isinstance(self, Genid):
  293. bnode_id = f"{self}"
  294. if bnode_id in skolems:
  295. return skolems[bnode_id]
  296. else:
  297. retval = BNode()
  298. skolems[bnode_id] = retval
  299. return retval
  300. else:
  301. raise Exception(f"<{self}> is not a skolem URI")
  302. class Genid(URIRef):
  303. __slots__ = ()
  304. @staticmethod
  305. def _is_external_skolem(uri: Any) -> bool:
  306. if not isinstance(uri, str):
  307. uri = str(uri)
  308. parsed_uri = urlparse(uri)
  309. gen_id = parsed_uri.path.rfind(skolem_genid)
  310. if gen_id != 0:
  311. return False
  312. return True
  313. class RDFLibGenid(Genid):
  314. __slots__ = ()
  315. @staticmethod
  316. def _is_rdflib_skolem(uri: Any) -> bool:
  317. if not isinstance(uri, str):
  318. uri = str(uri)
  319. parsed_uri = urlparse(uri)
  320. if (
  321. parsed_uri.params != ""
  322. or parsed_uri.query != ""
  323. or parsed_uri.fragment != ""
  324. ):
  325. return False
  326. gen_id = parsed_uri.path.rfind(rdflib_skolem_genid)
  327. if gen_id != 0:
  328. return False
  329. return True
  330. def _unique_id() -> str:
  331. # Used to read: """Create a (hopefully) unique prefix"""
  332. # now retained merely to leave internal API unchanged.
  333. # From BNode.__new__() below ...
  334. #
  335. # acceptable bnode value range for RDF/XML needs to be
  336. # something that can be serialzed as a nodeID for N3
  337. #
  338. # BNode identifiers must be valid NCNames" _:[A-Za-z][A-Za-z0-9]*
  339. # http://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#nodeID
  340. return "N" # ensure that id starts with a letter
  341. class BNode(IdentifiedNode):
  342. """
  343. RDF 1.1's Blank Nodes Section: https://www.w3.org/TR/rdf11-concepts/#section-blank-nodes
  344. Blank Nodes are local identifiers for unnamed nodes in RDF graphs that are used in
  345. some concrete RDF syntaxes or RDF store implementations. They are always locally
  346. scoped to the file or RDF store, and are not persistent or portable identifiers for
  347. blank nodes. The identifiers for Blank Nodes are not part of the RDF abstract
  348. syntax, but are entirely dependent on particular concrete syntax or implementation
  349. (such as Turtle, JSON-LD).
  350. ---
  351. RDFLib's `BNode` class makes unique IDs for all the Blank Nodes in a Graph but you
  352. should *never* expect, or reply on, BNodes' IDs to match across graphs, or even for
  353. multiple copies of the same graph, if they are regenerated from some non-RDFLib
  354. source, such as loading from RDF data.
  355. """
  356. __slots__ = ()
  357. def __new__(
  358. cls,
  359. value: Optional[str] = None,
  360. _sn_gen: Optional[Union[Callable[[], str], Generator]] = None,
  361. _prefix: str = _unique_id(),
  362. ):
  363. """
  364. # only store implementations should pass in a value
  365. """
  366. if value is None:
  367. # so that BNode values do not collide with ones created with
  368. # a different instance of this module at some other time.
  369. if _sn_gen is not None:
  370. if callable(_sn_gen):
  371. sn_result: Union[str, Generator] = _sn_gen()
  372. else:
  373. sn_result = _sn_gen
  374. if isinstance(sn_result, GeneratorType):
  375. node_id = next(sn_result)
  376. else:
  377. node_id = sn_result
  378. else:
  379. node_id = uuid4().hex
  380. # note, for two (and only two) string variables,
  381. # concat with + is faster than f"{x}{y}"
  382. value = _prefix + f"{node_id}"
  383. else:
  384. # TODO: check that value falls within acceptable bnode value range
  385. # for RDF/XML needs to be something that can be serialized
  386. # as a nodeID for N3 ?? Unless we require these
  387. # constraints be enforced elsewhere?
  388. pass # assert is_ncname(str(value)), "BNode identifiers
  389. # must be valid NCNames" _:[A-Za-z][A-Za-z0-9]*
  390. # http://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#nodeID
  391. # type error: Incompatible return value type (got "Identifier", expected "BNode")
  392. return Identifier.__new__(cls, value)
  393. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
  394. # note - for two strings, concat with + is faster than f"{x}{y}"
  395. return "_:" + self
  396. def __reduce__(self) -> Tuple[Type[BNode], Tuple[str]]:
  397. return (BNode, (str(self),))
  398. def __repr__(self) -> str:
  399. if self.__class__ is BNode:
  400. clsName = "rdflib.term.BNode" # noqa: N806
  401. else:
  402. clsName = self.__class__.__name__ # noqa: N806
  403. return f"{clsName}({str.__repr__(self)})"
  404. def skolemize(
  405. self, authority: Optional[str] = None, basepath: Optional[str] = None
  406. ) -> URIRef:
  407. """Create a URIRef "skolem" representation of the BNode, in accordance
  408. with http://www.w3.org/TR/rdf11-concepts/#section-skolemization
  409. Added in version 4.0
  410. """
  411. if authority is None:
  412. authority = _SKOLEM_DEFAULT_AUTHORITY
  413. if basepath is None:
  414. basepath = rdflib_skolem_genid
  415. skolem = basepath + str(self)
  416. return URIRef(urljoin(authority, skolem))
  417. class Literal(Identifier):
  418. """
  419. RDF 1.1's Literals Section: http://www.w3.org/TR/rdf-concepts/#section-Graph-Literal
  420. Literals are used for values such as strings, numbers, and dates.
  421. A literal in an RDF graph consists of two or three elements:
  422. * a lexical form, being a Unicode string, which SHOULD be in Normal Form C
  423. * a datatype IRI, being an IRI identifying a datatype that determines how the lexical form maps to a literal value, and
  424. * if and only if the datatype IRI is `http://www.w3.org/1999/02/22-rdf-syntax-ns#langString`, a non-empty language tag. The language tag MUST be well-formed according to section 2.2.9 of `Tags for identifying languages <http://tools.ietf.org/html/bcp47>`_.
  425. A literal is a language-tagged string if the third element is present. Lexical representations of language tags MAY be converted to lower case. The value space of language tags is always in lower case.
  426. ---
  427. For valid XSD datatypes, the lexical form is optionally normalized
  428. at construction time. Default behaviour is set by `rdflib.NORMALIZE_LITERALS`
  429. and can be overridden by the normalize parameter to `__new__`
  430. Equality and hashing of Literals are done based on the lexical form, i.e.:
  431. ```python
  432. >>> from rdflib.namespace import XSD
  433. >>> Literal('01') != Literal('1') # clear - strings differ
  434. True
  435. ```
  436. but with data-type they get normalized:
  437. ```python
  438. >>> Literal('01', datatype=XSD.integer) != Literal('1', datatype=XSD.integer)
  439. False
  440. ```
  441. unless disabled:
  442. ```python
  443. >>> Literal('01', datatype=XSD.integer, normalize=False) != Literal('1', datatype=XSD.integer)
  444. True
  445. ```
  446. Value based comparison is possible:
  447. ```python
  448. >>> Literal('01', datatype=XSD.integer).eq(Literal('1', datatype=XSD.float))
  449. True
  450. ```
  451. The eq method also provides limited support for basic python types:
  452. ```python
  453. >>> Literal(1).eq(1) # fine - int compatible with xsd:integer
  454. True
  455. >>> Literal('a').eq('b') # fine - str compatible with plain-lit
  456. False
  457. >>> Literal('a', datatype=XSD.string).eq('a') # fine - str compatible with xsd:string
  458. True
  459. >>> Literal('a').eq(1) # not fine, int incompatible with plain-lit
  460. NotImplemented
  461. ```
  462. Greater-than/less-than ordering comparisons are also done in value
  463. space, when compatible datatypes are used. Incompatible datatypes
  464. are ordered by DT, or by lang-tag. For other nodes the ordering
  465. is None < BNode < URIRef < Literal
  466. Any comparison with non-rdflib Node are "NotImplemented"
  467. In PY3 this is an error.
  468. ```python
  469. >>> from rdflib import Literal, XSD
  470. >>> lit2006 = Literal('2006-01-01',datatype=XSD.date)
  471. >>> lit2006.toPython()
  472. datetime.date(2006, 1, 1)
  473. >>> lit2006 < Literal('2007-01-01',datatype=XSD.date)
  474. True
  475. >>> Literal(datetime.utcnow()).datatype
  476. rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#dateTime')
  477. >>> Literal(1) > Literal(2) # by value
  478. False
  479. >>> Literal(1) > Literal(2.0) # by value
  480. False
  481. >>> Literal('1') > Literal(1) # by DT
  482. True
  483. >>> Literal('1') < Literal('1') # by lexical form
  484. False
  485. >>> Literal('a', lang='en') > Literal('a', lang='fr') # by lang-tag
  486. False
  487. >>> Literal(1) > URIRef('foo') # by node-type
  488. True
  489. ```
  490. The > < operators will eat this NotImplemented and throw a TypeError (py3k):
  491. ```python
  492. >>> Literal(1).__gt__(2.0)
  493. NotImplemented
  494. ```
  495. """
  496. _value: Any
  497. _language: Optional[str]
  498. # NOTE: _datatype should maybe be of type URIRef, and not optional.
  499. _datatype: Optional[URIRef]
  500. _ill_typed: Optional[bool]
  501. __slots__ = ("_language", "_datatype", "_value", "_ill_typed")
  502. def __new__(
  503. cls,
  504. lexical_or_value: Any,
  505. lang: Optional[str] = None,
  506. datatype: Optional[str] = None,
  507. normalize: Optional[bool] = None,
  508. ):
  509. """Create a new Literal instance."""
  510. if lang == "":
  511. lang = None # no empty lang-tags in RDF
  512. normalize = normalize if normalize is not None else rdflib.NORMALIZE_LITERALS
  513. if lang is not None and datatype is not None:
  514. raise TypeError(
  515. "A Literal can only have one of lang or datatype, "
  516. "per http://www.w3.org/TR/rdf-concepts/#section-Graph-Literal"
  517. )
  518. if lang is not None and not _is_valid_langtag(lang):
  519. raise ValueError(f"'{str(lang)}' is not a valid language tag!")
  520. if datatype is not None:
  521. datatype = URIRef(datatype)
  522. value = None
  523. ill_typed: Optional[bool] = None
  524. if isinstance(lexical_or_value, Literal):
  525. # create from another Literal instance
  526. lang = lang or lexical_or_value.language
  527. if datatype is not None:
  528. # override datatype
  529. value = _castLexicalToPython(lexical_or_value, datatype)
  530. else:
  531. datatype = lexical_or_value.datatype
  532. value = lexical_or_value.value
  533. elif isinstance(lexical_or_value, str) or isinstance(lexical_or_value, bytes):
  534. # passed a string
  535. # try parsing lexical form of datatyped literal
  536. value = _castLexicalToPython(lexical_or_value, datatype)
  537. if datatype is not None and datatype in _toPythonMapping:
  538. # datatype is a recognized datatype IRI:
  539. # https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris
  540. dt_uri: URIRef = URIRef(datatype)
  541. checker = _check_well_formed_types.get(dt_uri, _well_formed_by_value)
  542. well_formed = checker(lexical_or_value, value)
  543. ill_typed = ill_typed or (not well_formed)
  544. if value is not None and normalize:
  545. _value, _datatype = _castPythonToLiteral(value, datatype)
  546. if _value is not None and _is_valid_unicode(_value):
  547. lexical_or_value = _value
  548. else:
  549. # passed some python object
  550. value = lexical_or_value
  551. _value, _datatype = _castPythonToLiteral(lexical_or_value, datatype)
  552. _datatype = None if _datatype is None else URIRef(_datatype)
  553. datatype = rdflib.util._coalesce(datatype, _datatype)
  554. if _value is not None:
  555. lexical_or_value = _value
  556. if datatype is not None:
  557. lang = None
  558. if isinstance(lexical_or_value, bytes):
  559. lexical_or_value = lexical_or_value.decode("utf-8")
  560. if datatype in (_XSD_NORMALISED_STRING, _XSD_TOKEN):
  561. lexical_or_value = _normalise_XSD_STRING(lexical_or_value)
  562. if datatype in (_XSD_TOKEN,):
  563. lexical_or_value = _strip_and_collapse_whitespace(lexical_or_value)
  564. try:
  565. inst = str.__new__(cls, lexical_or_value)
  566. except UnicodeDecodeError:
  567. inst = str.__new__(cls, lexical_or_value, "utf-8")
  568. inst._language = lang
  569. inst._datatype = datatype
  570. inst._value = value
  571. inst._ill_typed = ill_typed
  572. return inst
  573. def normalize(self) -> Literal:
  574. """
  575. Returns a new literal with a normalised lexical representation
  576. of this literal
  577. ```python
  578. >>> from rdflib import XSD
  579. >>> Literal("01", datatype=XSD.integer, normalize=False).normalize()
  580. rdflib.term.Literal('1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  581. ```
  582. Illegal lexical forms for the datatype given are simply passed on
  583. ```python
  584. >>> Literal("a", datatype=XSD.integer, normalize=False)
  585. rdflib.term.Literal('a', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  586. ```
  587. """
  588. if self.value is not None:
  589. return Literal(self.value, datatype=self.datatype, lang=self.language)
  590. else:
  591. return self
  592. @property
  593. def ill_typed(self) -> Optional[bool]:
  594. """
  595. For `recognized datatype IRIs
  596. <https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris>`_,
  597. this value will be `True` if the literal is ill formed, otherwise it
  598. will be `False`. `Literal.value` (i.e. the `literal value <https://www.w3.org/TR/rdf11-concepts/#dfn-literal-value>`_) should always be defined if this property is `False`, but should not be considered reliable if this property is `True`.
  599. If the literal's datatype is `None` or not in the set of `recognized datatype IRIs
  600. <https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris>`_ this value will be `None`.
  601. """
  602. return self._ill_typed
  603. @property
  604. def value(self) -> Any:
  605. return self._value
  606. @property
  607. def language(self) -> Optional[str]:
  608. return self._language
  609. @property
  610. def datatype(self) -> Optional[URIRef]:
  611. return self._datatype
  612. def __reduce__(
  613. self,
  614. ) -> Tuple[Type[Literal], Tuple[str, Union[str, None], Union[str, None]]]:
  615. return (
  616. Literal,
  617. (str(self), self.language, self.datatype),
  618. )
  619. def __getstate__(self) -> Tuple[None, Dict[str, Union[str, None]]]:
  620. return (None, dict(language=self.language, datatype=self.datatype))
  621. def __setstate__(self, arg: Tuple[Any, Dict[str, Any]]) -> None:
  622. _, d = arg
  623. self._language = d["language"]
  624. self._datatype = d["datatype"]
  625. def __add__(self, val: Any) -> Literal:
  626. """
  627. ```python
  628. >>> from rdflib.namespace import XSD
  629. >>> Literal(1) + 1
  630. rdflib.term.Literal('2', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  631. >>> Literal("1") + "1"
  632. rdflib.term.Literal('11')
  633. # Handling dateTime/date/time based operations in Literals
  634. >>> a = Literal('2006-01-01T20:50:00', datatype=XSD.dateTime)
  635. >>> b = Literal('P31D', datatype=XSD.duration)
  636. >>> (a + b)
  637. rdflib.term.Literal('2006-02-01T20:50:00', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#dateTime'))
  638. >>> from rdflib.namespace import XSD
  639. >>> a = Literal('2006-07-01T20:52:00', datatype=XSD.dateTime)
  640. >>> b = Literal('P122DT15H58M', datatype=XSD.duration)
  641. >>> (a + b)
  642. rdflib.term.Literal('2006-11-01T12:50:00', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#dateTime'))
  643. ```
  644. """
  645. # if no val is supplied, return this Literal
  646. if val is None:
  647. return self
  648. # convert the val to a Literal, if it isn't already one
  649. if not isinstance(val, Literal):
  650. val = Literal(val)
  651. # if self is datetime based and value is duration
  652. if (
  653. self.datatype in (_XSD_DATETIME, _XSD_DATE)
  654. and val.datatype in _TIME_DELTA_TYPES
  655. ):
  656. date1: Union[datetime, date] = self.toPython()
  657. duration: Union[Duration, timedelta] = val.toPython()
  658. difference = date1 + duration
  659. return Literal(difference, datatype=self.datatype)
  660. # if self is time based and value is duration
  661. elif self.datatype == _XSD_TIME and val.datatype in _TIME_DELTA_TYPES:
  662. selfv: time = self.toPython()
  663. valv: Union[Duration, timedelta] = val.toPython()
  664. sdt = datetime.combine(date(2000, 1, 1), selfv) + valv
  665. return Literal(sdt.time(), datatype=self.datatype)
  666. # if self is datetime based and value is not or vice versa
  667. elif (
  668. (
  669. self.datatype in _ALL_DATE_AND_TIME_TYPES
  670. and val.datatype not in _ALL_DATE_AND_TIME_TYPES
  671. )
  672. or (
  673. self.datatype not in _ALL_DATE_AND_TIME_TYPES
  674. and val.datatype in _ALL_DATE_AND_TIME_TYPES
  675. )
  676. or (
  677. self.datatype in _TIME_DELTA_TYPES
  678. and (
  679. (val.datatype not in _TIME_DELTA_TYPES)
  680. or (self.datatype != val.datatype)
  681. )
  682. )
  683. ):
  684. raise TypeError(
  685. f"Cannot add a Literal of datatype {str(val.datatype)} to a Literal of datatype {str(self.datatype)}"
  686. )
  687. # if the datatypes are the same, just add the Python values and convert back
  688. if self.datatype == val.datatype:
  689. return Literal(
  690. self.toPython() + val.toPython(), self.language, datatype=self.datatype
  691. )
  692. # if the datatypes are not the same but are both numeric, add the Python values and strip off decimal junk
  693. # (i.e. tiny numbers (more than 17 decimal places) and trailing zeros) and return as a decimal
  694. elif (
  695. self.datatype in _NUMERIC_LITERAL_TYPES
  696. and val.datatype in _NUMERIC_LITERAL_TYPES
  697. ):
  698. return Literal(
  699. Decimal(
  700. f"{round(Decimal(self.toPython()) + Decimal(val.toPython()), 15):f}".rstrip(
  701. "0"
  702. ).rstrip(
  703. "."
  704. )
  705. ),
  706. datatype=_XSD_DECIMAL,
  707. )
  708. # in all other cases, perform string concatenation
  709. else:
  710. try:
  711. s = str.__add__(self, val)
  712. except TypeError:
  713. s = str(self.value) + str(val)
  714. # if the original datatype is string-like, use that
  715. if self.datatype in _STRING_LITERAL_TYPES:
  716. new_datatype = self.datatype
  717. # if not, use string
  718. else:
  719. new_datatype = _XSD_STRING
  720. return Literal(s, self.language, datatype=new_datatype)
  721. def __sub__(self, val: Any) -> Literal:
  722. """Implements subtraction between Literals or between a Literal and a Python object.
  723. Example:
  724. ```python
  725. from rdflib.namespace import XSD
  726. # Basic numeric subtraction
  727. Literal(2) - 1
  728. # rdflib.term.Literal('1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  729. Literal(1.1) - 1.0
  730. # rdflib.term.Literal('0.10000000000000009', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#double'))
  731. Literal(1.1) - 1
  732. # rdflib.term.Literal('0.1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#decimal'))
  733. Literal(1.1, datatype=XSD.float) - Literal(1.0, datatype=XSD.float)
  734. # rdflib.term.Literal('0.10000000000000009', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#float'))
  735. # This will raise a TypeError
  736. Literal("1.1") - 1.0
  737. # TypeError: Not a number; rdflib.term.Literal('1.1')
  738. Literal(1.1, datatype=XSD.integer) - Literal(1.0, datatype=XSD.integer)
  739. # rdflib.term.Literal('0.10000000000000009', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  740. # Handling dateTime/date/time based operations in Literals
  741. a = Literal('2006-01-01T20:50:00', datatype=XSD.dateTime)
  742. b = Literal('2006-02-01T20:50:00', datatype=XSD.dateTime)
  743. (b - a)
  744. # rdflib.term.Literal('P31D', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#duration'))
  745. a = Literal('2006-07-01T20:52:00', datatype=XSD.dateTime)
  746. b = Literal('2006-11-01T12:50:00', datatype=XSD.dateTime)
  747. (a - b)
  748. # rdflib.term.Literal('-P122DT15H58M', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#duration'))
  749. (b - a)
  750. # rdflib.term.Literal('P122DT15H58M', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#duration'))
  751. ```
  752. """
  753. # if no val is supplied, return this Literal
  754. if val is None:
  755. return self
  756. # convert the val to a Literal, if it isn't already one
  757. if not isinstance(val, Literal):
  758. val = Literal(val)
  759. if not getattr(self, "datatype"):
  760. raise TypeError(
  761. "Minuend Literal must have Numeric, Date, Datetime or Time datatype."
  762. )
  763. elif not getattr(val, "datatype"):
  764. raise TypeError(
  765. "Subtrahend Literal must have Numeric, Date, Datetime or Time datatype."
  766. )
  767. if (
  768. self.datatype in (_XSD_DATETIME, _XSD_DATE)
  769. and val.datatype in _TIME_DELTA_TYPES
  770. ):
  771. date1: Union[datetime, date] = self.toPython()
  772. duration: Union[Duration, timedelta] = val.toPython()
  773. difference = date1 - duration
  774. return Literal(difference, datatype=self.datatype)
  775. # if self is time based and value is duration
  776. elif self.datatype == _XSD_TIME and val.datatype in _TIME_DELTA_TYPES:
  777. selfv: time = self.toPython()
  778. valv: Union[Duration, timedelta] = val.toPython()
  779. sdt = datetime.combine(date(2000, 1, 1), selfv) - valv
  780. return Literal(sdt.time(), datatype=self.datatype)
  781. # if the datatypes are the same, just subtract the Python values and convert back
  782. if self.datatype == val.datatype:
  783. if self.datatype == _XSD_TIME:
  784. sdt = datetime.combine(date.today(), self.toPython())
  785. vdt = datetime.combine(date.today(), val.toPython())
  786. return Literal(sdt - vdt, datatype=_XSD_DURATION)
  787. else:
  788. return Literal(
  789. self.toPython() - val.toPython(),
  790. self.language,
  791. datatype=(
  792. _XSD_DURATION
  793. if self.datatype in (_XSD_DATETIME, _XSD_DATE, _XSD_TIME)
  794. else self.datatype
  795. ),
  796. )
  797. # if the datatypes are not the same but are both numeric, subtract the Python values and strip off decimal junk
  798. # (i.e. tiny numbers (more than 17 decimal places) and trailing zeros) and return as a decimal
  799. elif (
  800. self.datatype in _NUMERIC_LITERAL_TYPES
  801. and val.datatype in _NUMERIC_LITERAL_TYPES
  802. ):
  803. return Literal(
  804. Decimal(
  805. f"{round(Decimal(self.toPython()) - Decimal(val.toPython()), 15):f}".rstrip(
  806. "0"
  807. ).rstrip(
  808. "."
  809. )
  810. ),
  811. datatype=_XSD_DECIMAL,
  812. )
  813. # in all other cases, perform string concatenation
  814. else:
  815. raise TypeError(
  816. f"Cannot subtract a Literal of datatype {str(val.datatype)} from a Literal of datatype {str(self.datatype)}"
  817. )
  818. def __bool__(self) -> bool:
  819. """Determines the truth value of the Literal.
  820. Used for if statements, bool(literal), etc.
  821. """
  822. if self.value is not None:
  823. return bool(self.value)
  824. return len(self) != 0
  825. def __neg__(self) -> Literal:
  826. """Implements unary negation for Literals with numeric values.
  827. Example:
  828. ```python
  829. # Negating an integer Literal
  830. -Literal(1)
  831. # rdflib.term.Literal('-1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  832. # Negating a float Literal
  833. -Literal(10.5)
  834. # rdflib.term.Literal('-10.5', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#double'))
  835. # Using a string with a datatype
  836. from rdflib.namespace import XSD
  837. -Literal("1", datatype=XSD.integer)
  838. # rdflib.term.Literal('-1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  839. # This will raise a TypeError
  840. -Literal("1")
  841. # TypeError: Not a number; rdflib.term.Literal('1')
  842. ```
  843. """
  844. if isinstance(self.value, (int, long_type, float)):
  845. return Literal(self.value.__neg__())
  846. else:
  847. raise TypeError(f"Not a number; {self!r}")
  848. def __pos__(self) -> Literal:
  849. """Implements unary plus operation for Literals with numeric values.
  850. Example:
  851. ```python
  852. # Applying unary plus to an integer Literal
  853. +Literal(1)
  854. # rdflib.term.Literal('1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  855. # Applying unary plus to a negative integer Literal
  856. +Literal(-1)
  857. # rdflib.term.Literal('-1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  858. # Using a string with a datatype
  859. from rdflib.namespace import XSD
  860. +Literal("-1", datatype=XSD.integer)
  861. # rdflib.term.Literal('-1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  862. # This will raise a TypeError
  863. +Literal("1")
  864. # TypeError: Not a number; rdflib.term.Literal('1')
  865. ```
  866. """
  867. if isinstance(self.value, (int, long_type, float)):
  868. return Literal(self.value.__pos__())
  869. else:
  870. raise TypeError(f"Not a number; {self!r}")
  871. def __abs__(self) -> Literal:
  872. """Implements absolute value operation for Literals with numeric values.
  873. Example:
  874. ```python
  875. # Absolute value of a negative integer Literal
  876. abs(Literal(-1))
  877. # rdflib.term.Literal('1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  878. # Using a string with a datatype
  879. from rdflib.namespace import XSD
  880. abs(Literal("-1", datatype=XSD.integer))
  881. # rdflib.term.Literal('1', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  882. # This will raise a TypeError
  883. abs(Literal("1"))
  884. # TypeError: Not a number; rdflib.term.Literal('1')
  885. ```
  886. """
  887. if isinstance(self.value, (int, long_type, float)):
  888. return Literal(self.value.__abs__())
  889. else:
  890. raise TypeError(f"Not a number; {self!r}")
  891. def __invert__(self) -> Literal:
  892. """Implements bitwise NOT operation for Literals with numeric values.
  893. Example:
  894. ```python
  895. # Bitwise NOT of a negative integer Literal
  896. ~(Literal(-1))
  897. # rdflib.term.Literal('0', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  898. # Using a string with a datatype
  899. from rdflib.namespace import XSD
  900. ~(Literal("-1", datatype=XSD.integer))
  901. # rdflib.term.Literal('0', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer'))
  902. # This will raise a TypeError
  903. ~(Literal("1"))
  904. # TypeError: Not a number; rdflib.term.Literal('1')
  905. ```
  906. """
  907. if isinstance(self.value, (int, long_type, float)):
  908. # type error: Unsupported operand type for ~ ("float")
  909. return Literal(self.value.__invert__()) # type: ignore[operator] # FIXME
  910. else:
  911. raise TypeError(f"Not a number; {self!r}")
  912. def __gt__(self, other: Any) -> bool:
  913. """Implements the greater-than comparison for Literals.
  914. This is the base method for ordering comparisons - other comparison methods delegate here.
  915. Implements the ordering rules described in http://www.w3.org/TR/sparql11-query/#modOrderBy
  916. In summary:
  917. 1. Literals with compatible data-types are ordered in value space
  918. 2. Incompatible datatypes are ordered by their datatype URIs
  919. 3. Literals with language tags are ordered by their language tags
  920. 4. Plain literals come before xsd:string literals
  921. 5. In the node order: None < BNode < URIRef < Literal
  922. Example:
  923. ```python
  924. from rdflib import XSD
  925. from decimal import Decimal
  926. # Comparing numeric literals in value space
  927. Literal(1) > Literal(2) # int/int
  928. # False
  929. Literal(2.0) > Literal(1) # double/int
  930. # True
  931. Literal(Decimal("3.3")) > Literal(2.0) # decimal/double
  932. # True
  933. Literal(Decimal("3.3")) < Literal(4.0) # decimal/double
  934. # True
  935. # Comparing string literals
  936. Literal('b') > Literal('a') # plain lit/plain lit
  937. # True
  938. Literal('b') > Literal('a', datatype=XSD.string) # plain lit/xsd:str
  939. # True
  940. # Incompatible datatypes ordered by DT
  941. Literal(1) > Literal("2") # int>string
  942. # False
  943. # Langtagged literals ordered by lang tag
  944. Literal("a", lang="en") > Literal("a", lang="fr")
  945. # False
  946. ```
  947. """
  948. if other is None:
  949. return True # Everything is greater than None
  950. if isinstance(other, Literal):
  951. # Fast path for comparing numeric literals
  952. # that are not ill-typed and don't have a None value
  953. if (
  954. (
  955. self.datatype in _NUMERIC_LITERAL_TYPES
  956. and other.datatype in _NUMERIC_LITERAL_TYPES
  957. )
  958. and ((not self.ill_typed) and (not other.ill_typed))
  959. and (self.value is not None and other.value is not None)
  960. ):
  961. return self.value > other.value
  962. # plain-literals and xsd:string literals
  963. # are "the same"
  964. dtself = rdflib.util._coalesce(self.datatype, default=_XSD_STRING)
  965. dtother = rdflib.util._coalesce(other.datatype, default=_XSD_STRING)
  966. if dtself != dtother:
  967. if rdflib.DAWG_LITERAL_COLLATION:
  968. return NotImplemented
  969. else:
  970. return dtself > dtother
  971. if self.language != other.language:
  972. if not self.language:
  973. return False
  974. elif not other.language:
  975. return True
  976. else:
  977. return self.language > other.language
  978. if self.value is not None and other.value is not None:
  979. if type(self.value) in _TOTAL_ORDER_CASTERS:
  980. caster = _TOTAL_ORDER_CASTERS[type(self.value)]
  981. return caster(self.value) > caster(other.value)
  982. try:
  983. return self.value > other.value
  984. except TypeError:
  985. pass
  986. if str(self) != str(other):
  987. return str(self) > str(other)
  988. # same language, same lexical form, check real dt
  989. # plain-literals come before xsd:string!
  990. if self.datatype != other.datatype:
  991. if self.datatype is None:
  992. return False
  993. elif other.datatype is None:
  994. return True
  995. else:
  996. return self.datatype > other.datatype
  997. return False # they are the same
  998. elif isinstance(other, Node):
  999. return True # Literal are the greatest!
  1000. else:
  1001. return NotImplemented # we can only compare to nodes
  1002. def __lt__(self, other: Any) -> bool:
  1003. if other is None:
  1004. return False # Nothing is less than None
  1005. if isinstance(other, Literal):
  1006. try:
  1007. return not self.__gt__(other) and not self.eq(other)
  1008. except TypeError:
  1009. return NotImplemented
  1010. if isinstance(other, Node):
  1011. return False # all nodes are less-than Literals
  1012. return NotImplemented
  1013. def __le__(self, other: Any) -> bool:
  1014. """Less than or equal operator for Literals.
  1015. Example:
  1016. ```python
  1017. from rdflib.namespace import XSD
  1018. Literal('2007-01-01T10:00:00', datatype=XSD.dateTime) <= Literal('2007-01-01T10:00:00', datatype=XSD.dateTime)
  1019. # True
  1020. ```
  1021. """
  1022. r = self.__lt__(other)
  1023. if r:
  1024. return True
  1025. try:
  1026. return self.eq(other)
  1027. except TypeError:
  1028. return NotImplemented
  1029. def __ge__(self, other: Any) -> bool:
  1030. r = self.__gt__(other)
  1031. if r:
  1032. return True
  1033. try:
  1034. return self.eq(other)
  1035. except TypeError:
  1036. return NotImplemented
  1037. def _comparable_to(self, other: Any) -> bool:
  1038. """Helper method to decide which things are meaningful to rich-compare with this literal."""
  1039. if isinstance(other, Literal):
  1040. if self.datatype is not None and other.datatype is not None:
  1041. # two datatyped literals
  1042. if (
  1043. self.datatype not in XSDToPython
  1044. or other.datatype not in XSDToPython
  1045. ):
  1046. # non XSD DTs must match
  1047. if self.datatype != other.datatype:
  1048. return False
  1049. else:
  1050. # xsd:string may be compared with plain literals
  1051. if not (self.datatype == _XSD_STRING and not other.datatype) or (
  1052. other.datatype == _XSD_STRING and not self.datatype
  1053. ):
  1054. return False
  1055. # if given lang-tag has to be case insensitive equal
  1056. if (self.language or "").lower() != (other.language or "").lower():
  1057. return False
  1058. return True
  1059. # type error: Signature of "__hash__" incompatible with supertype "Identifier"
  1060. # Superclass: def __hash__(self: str) -> int
  1061. # Subclass: def __hash__(self) -> int
  1062. # NOTE for type ignore: This can possibly be fixed by changing how __hash__ is implemented in Identifier
  1063. def __hash__(self) -> int: # type: ignore[override]
  1064. """Hash function for Literals to enable their use as dictionary keys.
  1065. Example:
  1066. ```python
  1067. from rdflib.namespace import XSD
  1068. a = {Literal('1', datatype=XSD.integer):'one'}
  1069. Literal('1', datatype=XSD.double) in a
  1070. # False
  1071. ```
  1072. Notes:
  1073. "Called for the key object for dictionary operations,
  1074. and by the built-in function hash(). Should return
  1075. a 32-bit integer usable as a hash value for
  1076. dictionary operations. The only required property
  1077. is that objects which compare equal have the same
  1078. hash value; it is advised to somehow mix together
  1079. (e.g., using exclusive or) the hash values for the
  1080. components of the object that also play a part in
  1081. comparison of objects." -- 3.4.1 Basic customization (Python)
  1082. "Two literals are equal if and only if all of the following hold:
  1083. * The strings of the two lexical forms compare equal, character by character.
  1084. * Either both or neither have language tags.
  1085. * The language tags, if any, compare equal.
  1086. * Either both or neither have datatype URIs.
  1087. * The two datatype URIs, if any, compare equal, character by character."
  1088. -- 6.5.1 Literal Equality (RDF: Concepts and Abstract Syntax)
  1089. """
  1090. # don't use super()... for efficiency reasons, see Identifier.__hash__
  1091. res = str.__hash__(self)
  1092. # Directly accessing the member is faster than the property.
  1093. if self._language:
  1094. res ^= hash(self._language.lower())
  1095. if self._datatype is not None:
  1096. res ^= hash(self._datatype)
  1097. return res
  1098. def __eq__(self, other: Any) -> bool:
  1099. """Equality operator for Literals.
  1100. Literals are only equal to other literals.
  1101. Notes:
  1102. "Two literals are equal if and only if all of the following hold:
  1103. * The strings of the two lexical forms compare equal, character by character.
  1104. * Either both or neither have language tags.
  1105. * The language tags, if any, compare equal.
  1106. * Either both or neither have datatype URIs.
  1107. * The two datatype URIs, if any, compare equal, character by character."
  1108. -- 6.5.1 Literal Equality (RDF: Concepts and Abstract Syntax)
  1109. Example:
  1110. ```python
  1111. Literal("1", datatype=URIRef("foo")) == Literal("1", datatype=URIRef("foo"))
  1112. # True
  1113. Literal("1", datatype=URIRef("foo")) == Literal("1", datatype=URIRef("foo2"))
  1114. # False
  1115. Literal("1", datatype=URIRef("foo")) == Literal("2", datatype=URIRef("foo"))
  1116. # False
  1117. Literal("1", datatype=URIRef("foo")) == "asdf"
  1118. # False
  1119. from rdflib import XSD
  1120. Literal('2007-01-01', datatype=XSD.date) == Literal('2007-01-01', datatype=XSD.date)
  1121. # True
  1122. Literal('2007-01-01', datatype=XSD.date) == date(2007, 1, 1)
  1123. # False
  1124. Literal("one", lang="en") == Literal("one", lang="en")
  1125. # True
  1126. Literal("hast", lang='en') == Literal("hast", lang='de')
  1127. # False
  1128. Literal("1", datatype=XSD.integer) == Literal(1)
  1129. # True
  1130. Literal("1", datatype=XSD.integer) == Literal("01", datatype=XSD.integer)
  1131. # True
  1132. ```
  1133. """
  1134. if self is other:
  1135. return True
  1136. if other is None:
  1137. return False
  1138. # Directly accessing the member is faster than the property.
  1139. if isinstance(other, Literal):
  1140. return (
  1141. self._datatype == other._datatype
  1142. and (self._language.lower() if self._language else None)
  1143. == (other._language.lower() if other._language else None)
  1144. and str.__eq__(self, other)
  1145. )
  1146. return False
  1147. def eq(self, other: Any) -> bool:
  1148. """Compare the value of this literal with something else.
  1149. This comparison can be done in two ways:
  1150. 1. With the value of another literal - comparisons are then done in literal "value space"
  1151. according to the rules of XSD subtype-substitution/type-promotion
  1152. 2. With a Python object:
  1153. * string objects can be compared with plain-literals or those with datatype xsd:string
  1154. * bool objects with xsd:boolean
  1155. * int, long or float with numeric xsd types
  1156. * date, time, datetime objects with xsd:date, xsd:time, xsd:datetime
  1157. Any other operations returns NotImplemented.
  1158. """
  1159. if isinstance(other, Literal):
  1160. # Fast path for comparing numeric literals
  1161. # that are not ill-typed and don't have a None value
  1162. if (
  1163. (
  1164. self.datatype in _NUMERIC_LITERAL_TYPES
  1165. and other.datatype in _NUMERIC_LITERAL_TYPES
  1166. )
  1167. and ((not self.ill_typed) and (not other.ill_typed))
  1168. and (self.value is not None and other.value is not None)
  1169. ):
  1170. if self.value is not None and other.value is not None:
  1171. return self.value == other.value
  1172. else:
  1173. if str.__eq__(self, other):
  1174. return True
  1175. raise TypeError(
  1176. # TODO: Should this use repr strings in the error message?
  1177. "I cannot know that these two lexical forms do not map to the "
  1178. f"same value: {self} and {other}"
  1179. )
  1180. if (self.language or "").lower() != (other.language or "").lower():
  1181. return False
  1182. dtself = rdflib.util._coalesce(self.datatype, default=_XSD_STRING)
  1183. dtother = rdflib.util._coalesce(other.datatype, default=_XSD_STRING)
  1184. if dtself == _XSD_STRING and dtother == _XSD_STRING:
  1185. # string/plain literals, compare on lexical form
  1186. return str.__eq__(self, other)
  1187. # XML can be compared to HTML, only if html5rdf is enabled
  1188. if (
  1189. (dtself in _XML_COMPARABLE and dtother in _XML_COMPARABLE)
  1190. and
  1191. # Ill-typed can be None if unknown, but we don't want it to be True.
  1192. ((self.ill_typed is not True) and (other.ill_typed is not True))
  1193. and (self.value is not None and other.value is not None)
  1194. ):
  1195. return _isEqualXMLNode(self.value, other.value)
  1196. if dtself != dtother:
  1197. if rdflib.DAWG_LITERAL_COLLATION:
  1198. raise TypeError(
  1199. f"I don't know how to compare literals with datatypes {self.datatype} and {other.datatype}"
  1200. )
  1201. else:
  1202. return False
  1203. # matching non-string DTs now - do we compare values or
  1204. # lexical form first? comparing two ints is far quicker -
  1205. # maybe there are counter examples
  1206. if self.value is not None and other.value is not None:
  1207. return self.value == other.value
  1208. else:
  1209. if str.__eq__(self, other):
  1210. return True
  1211. if self.datatype == _XSD_STRING:
  1212. return False # string value space=lexical space
  1213. # matching DTs, but not matching, we cannot compare!
  1214. raise TypeError(
  1215. # TODO: Should this use repr strings in the error message?
  1216. "I cannot know that these two lexical forms do not map to the same "
  1217. f"value: {self} and {other}"
  1218. )
  1219. elif isinstance(other, Node):
  1220. return False # no non-Literal nodes are equal to a literal
  1221. elif isinstance(other, str):
  1222. # only plain-literals can be directly compared to strings
  1223. # TODO: Is "blah"@en eq "blah" ?
  1224. if self.language is not None:
  1225. return False
  1226. if self.datatype == _XSD_STRING or self.datatype is None:
  1227. return str(self) == other
  1228. elif isinstance(other, (int, long_type, float)):
  1229. if self.datatype in _NUMERIC_LITERAL_TYPES:
  1230. return self.value == other
  1231. elif isinstance(other, (date, datetime, time)):
  1232. if self.datatype in (_XSD_DATETIME, _XSD_DATE, _XSD_TIME):
  1233. return self.value == other
  1234. elif isinstance(other, (timedelta, Duration)):
  1235. if self.datatype in (
  1236. _XSD_DURATION,
  1237. _XSD_DAYTIMEDURATION,
  1238. _XSD_YEARMONTHDURATION,
  1239. ):
  1240. return self.value == other
  1241. # NOTE for type ignore: bool is a subclass of int so this won't ever run.
  1242. elif isinstance(other, bool): # type: ignore[unreachable, unused-ignore]
  1243. if self.datatype == _XSD_BOOLEAN:
  1244. return self.value == other
  1245. return NotImplemented
  1246. def neq(self, other: Any) -> bool:
  1247. return not self.eq(other)
  1248. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
  1249. r'''Returns a representation in the N3 format.
  1250. ```python
  1251. >>> Literal("foo").n3()
  1252. '"foo"'
  1253. ```
  1254. Strings with newlines or triple-quotes:
  1255. ```python
  1256. >>> Literal("foo\nbar").n3()
  1257. '"""foo\nbar"""'
  1258. >>> Literal("''\'").n3()
  1259. '"\'\'\'"'
  1260. >>> Literal('"""').n3()
  1261. '"\\"\\"\\""'
  1262. ```
  1263. Language:
  1264. ```python
  1265. >>> Literal("hello", lang="en").n3()
  1266. '"hello"@en'
  1267. ```
  1268. Datatypes:
  1269. ```python
  1270. >>> Literal(1).n3()
  1271. '"1"^^<http://www.w3.org/2001/XMLSchema#integer>'
  1272. >>> Literal(1.0).n3()
  1273. '"1.0"^^<http://www.w3.org/2001/XMLSchema#double>'
  1274. >>> Literal(True).n3()
  1275. '"true"^^<http://www.w3.org/2001/XMLSchema#boolean>'
  1276. ```
  1277. Datatype and language isn't allowed (datatype takes precedence):
  1278. ```python
  1279. >>> Literal(1, lang="en").n3()
  1280. '"1"^^<http://www.w3.org/2001/XMLSchema#integer>'
  1281. ```
  1282. Custom datatype:
  1283. ```python
  1284. >>> footype = URIRef("http://example.org/ns#foo")
  1285. >>> Literal("1", datatype=footype).n3()
  1286. '"1"^^<http://example.org/ns#foo>'
  1287. ```
  1288. Passing a namespace-manager will use it to abbreviate datatype URIs:
  1289. ```python
  1290. >>> from rdflib import Graph
  1291. >>> Literal(1).n3(Graph().namespace_manager)
  1292. '"1"^^xsd:integer'
  1293. ```
  1294. '''
  1295. if namespace_manager:
  1296. return self._literal_n3(qname_callback=namespace_manager.normalizeUri)
  1297. else:
  1298. return self._literal_n3()
  1299. def _literal_n3(
  1300. self,
  1301. use_plain: bool = False,
  1302. qname_callback: Optional[Callable[[URIRef], Optional[str]]] = None,
  1303. ) -> str:
  1304. """Internal method for N3 serialization with more options.
  1305. Args:
  1306. use_plain: Whether to use plain literal (shorthand) output
  1307. qname_callback: Function to convert URIs to prefixed names
  1308. Example:
  1309. Using plain literal (shorthand) output:
  1310. ```python
  1311. >>> from rdflib.namespace import XSD
  1312. >>> Literal(1)._literal_n3(use_plain=True)
  1313. '1'
  1314. >>> Literal(1.0)._literal_n3(use_plain=True)
  1315. '1e+00'
  1316. >>> Literal(1.0, datatype=XSD.decimal)._literal_n3(use_plain=True)
  1317. '1.0'
  1318. >>> Literal(1.0, datatype=XSD.float)._literal_n3(use_plain=True)
  1319. '"1.0"^^<http://www.w3.org/2001/XMLSchema#float>'
  1320. >>> Literal("foo", datatype=XSD.string)._literal_n3(use_plain=True)
  1321. '"foo"^^<http://www.w3.org/2001/XMLSchema#string>'
  1322. >>> Literal(True)._literal_n3(use_plain=True)
  1323. 'true'
  1324. >>> Literal(False)._literal_n3(use_plain=True)
  1325. 'false'
  1326. >>> Literal(1.91)._literal_n3(use_plain=True)
  1327. '1.91e+00'
  1328. ```
  1329. Only limited precision available for floats:
  1330. ```python
  1331. >>> Literal(0.123456789)._literal_n3(use_plain=True)
  1332. '1.234568e-01'
  1333. >>> Literal('0.123456789', datatype=XSD.decimal)._literal_n3(use_plain=True)
  1334. '0.123456789'
  1335. ```
  1336. Using callback for datatype QNames:
  1337. ```python
  1338. >>> Literal(1)._literal_n3(qname_callback=lambda uri: "xsd:integer")
  1339. '"1"^^xsd:integer'
  1340. ```
  1341. """
  1342. if use_plain and self.datatype in _PLAIN_LITERAL_TYPES:
  1343. if self.value is not None:
  1344. # If self is inf or NaN, we need a datatype
  1345. # (there is no plain representation)
  1346. if self.datatype in _NUMERIC_INF_NAN_LITERAL_TYPES:
  1347. try:
  1348. v = float(self)
  1349. if math.isinf(v) or math.isnan(v):
  1350. return self._literal_n3(False, qname_callback)
  1351. except ValueError:
  1352. return self._literal_n3(False, qname_callback)
  1353. # this is a bit of a mess -
  1354. # we try to produce "pretty" output
  1355. # that is compatible with n3 (turtle) notation
  1356. if self.datatype == _XSD_DOUBLE:
  1357. return sub("\\.?0*e", "e", f"{float(self):e}")
  1358. elif self.datatype == _XSD_DECIMAL:
  1359. s = f"{self}" # f"{self}" is faster than "%s" % self and str(self)
  1360. if "." not in s and "e" not in s and "E" not in s:
  1361. s += ".0"
  1362. return s
  1363. elif self.datatype == _XSD_BOOLEAN:
  1364. return f"{self}".lower()
  1365. else:
  1366. return f"{self}"
  1367. encoded: str = self._quote_encode()
  1368. datatype = self.datatype
  1369. quoted_dt = None
  1370. if datatype is not None:
  1371. if qname_callback:
  1372. quoted_dt = qname_callback(datatype)
  1373. if not quoted_dt:
  1374. quoted_dt = f"<{datatype}>"
  1375. if datatype in _NUMERIC_INF_NAN_LITERAL_TYPES:
  1376. try:
  1377. v = float(self)
  1378. if math.isinf(v):
  1379. # py string reps: float: 'inf', Decimal: 'Infinity"
  1380. # both need to become "INF" in xsd datatypes
  1381. encoded = encoded.replace("inf", "INF").replace(
  1382. "Infinity", "INF"
  1383. )
  1384. if math.isnan(v):
  1385. encoded = encoded.replace("nan", "NaN")
  1386. except ValueError:
  1387. # if we can't cast to float something is wrong, but we can
  1388. # still serialize. Warn user about it
  1389. warnings.warn(f"Serializing weird numerical {self!r}")
  1390. language = self.language
  1391. if language:
  1392. return f"{encoded}@{language}"
  1393. elif datatype:
  1394. return f"{encoded}^^{quoted_dt}"
  1395. else:
  1396. return encoded
  1397. def _quote_encode(self) -> str:
  1398. # This simpler encoding doesn't work; a newline gets encoded as "\\n",
  1399. # which is ok in sourcecode, but we want "\n".
  1400. # encoded = self.encode('unicode-escape').replace(
  1401. # '\\', '\\\\').replace('"','\\"')
  1402. # encoded = self.replace.replace('\\', '\\\\').replace('"','\\"')
  1403. # NOTE: Could in theory chose quotes based on quotes appearing in the
  1404. # string, i.e. '"' and "'", but N3/turtle doesn't allow "'"(?).
  1405. if "\n" in self:
  1406. # Triple quote this string.
  1407. encoded = self.replace("\\", "\\\\")
  1408. if '"""' in self:
  1409. # is this ok?
  1410. encoded = encoded.replace('"""', '\\"\\"\\"')
  1411. if encoded[-1] == '"' and encoded[-2] != "\\":
  1412. encoded = encoded[:-1] + "\\" + '"'
  1413. # TODO: Replace usage of %s here with fstrings
  1414. # when we have ability to escape \r and \n inside
  1415. # f-string inline function calls
  1416. return '"""%s"""' % encoded.replace("\r", "\\r")
  1417. else:
  1418. return '"%s"' % self.replace("\n", "\\n").replace("\\", "\\\\").replace(
  1419. '"', '\\"'
  1420. ).replace("\r", "\\r")
  1421. def __repr__(self) -> str:
  1422. args = [str.__repr__(self)]
  1423. if self.language is not None:
  1424. args.append("lang=" + repr(self.language))
  1425. if self.datatype is not None:
  1426. args.append("datatype=" + repr(self.datatype))
  1427. if self.__class__ == Literal:
  1428. clsName = "rdflib.term.Literal" # noqa: N806
  1429. else:
  1430. clsName = self.__class__.__name__ # noqa: N806
  1431. return f"{clsName}({', '.join(args)})"
  1432. def toPython(self) -> Any: # noqa: N802
  1433. """
  1434. Returns an appropriate python datatype derived from this RDF Literal
  1435. """
  1436. if self.value is not None:
  1437. return self.value
  1438. return self
  1439. def _parseXML(xmlstring: str) -> xml.dom.minidom.Document: # noqa: N802
  1440. retval = xml.dom.minidom.parseString(
  1441. f"<rdflibtoplevelelement>{xmlstring}</rdflibtoplevelelement>"
  1442. )
  1443. retval.normalize()
  1444. return retval
  1445. def _parse_html(lexical_form: str) -> xml.dom.minidom.DocumentFragment:
  1446. """
  1447. Parse the lexical form of an HTML literal into a document fragment
  1448. using the `dom` from html5rdf tree builder.
  1449. Args:
  1450. lexical_form: The lexical form of the HTML literal.
  1451. Returns:
  1452. A document fragment representing the HTML literal.
  1453. Raises:
  1454. html5rdf.html5parser.ParseError: If the lexical form is not valid HTML.
  1455. """
  1456. parser = html5rdf.HTMLParser(
  1457. tree=html5rdf.treebuilders.getTreeBuilder("dom"), strict=True
  1458. )
  1459. try:
  1460. result: xml.dom.minidom.DocumentFragment = parser.parseFragment(lexical_form)
  1461. except html5rdf.html5parser.ParseError as e:
  1462. logger.info(f"Failed to parse HTML: {e}")
  1463. raise e
  1464. result.normalize()
  1465. return result
  1466. def _write_html(value: xml.dom.minidom.DocumentFragment) -> bytes:
  1467. """
  1468. Serialize a document fragment representing an HTML literal into
  1469. its lexical form.
  1470. Args:
  1471. value: A document fragment representing an HTML literal.
  1472. Returns:
  1473. The lexical form of the HTML literal.
  1474. """
  1475. result = html5rdf.serialize(value, tree="dom")
  1476. return result
  1477. def _writeXML( # noqa: N802
  1478. xmlnode: Union[xml.dom.minidom.Document, xml.dom.minidom.DocumentFragment]
  1479. ) -> bytes:
  1480. if isinstance(xmlnode, xml.dom.minidom.DocumentFragment):
  1481. d = xml.dom.minidom.Document()
  1482. d.childNodes += xmlnode.childNodes
  1483. xmlnode = d
  1484. s = xmlnode.toxml("utf-8")
  1485. # for clean round-tripping, remove headers -- I have great and
  1486. # specific worries that this will blow up later, but this margin
  1487. # is too narrow to contain them
  1488. if s.startswith(b'<?xml version="1.0" encoding="utf-8"?>'):
  1489. s = s[38:]
  1490. if s.startswith(b"<rdflibtoplevelelement>"):
  1491. s = s[23:-24]
  1492. if s == b"<rdflibtoplevelelement/>":
  1493. s = b""
  1494. return s
  1495. def _unhexlify(value: Union[str, bytes, Literal]) -> bytes:
  1496. # In Python 3.2, unhexlify does not support str (only bytes)
  1497. if isinstance(value, str):
  1498. value = value.encode()
  1499. return unhexlify(value)
  1500. def _parseBoolean(value: Union[str, bytes]) -> bool: # noqa: N802
  1501. """
  1502. Boolean is a datatype with value space {true,false},
  1503. lexical space {"true", "false","1","0"} and
  1504. lexical-to-value mapping {"true"→true, "false"→false, "1"→true, "0"→false}.
  1505. """
  1506. true_accepted_values = ["1", "true", b"1", b"true"]
  1507. false_accepted_values = ["0", "false", b"0", b"false"]
  1508. new_value = value.lower()
  1509. if new_value in true_accepted_values:
  1510. return True
  1511. if new_value not in false_accepted_values:
  1512. warnings.warn(
  1513. f"Parsing weird boolean, {value!r} does not map to True or False",
  1514. category=UserWarning,
  1515. )
  1516. return False
  1517. def _well_formed_by_value(lexical: Union[str, bytes], value: Any) -> bool:
  1518. """
  1519. This function is used as the fallback for detecting ill-typed/ill-formed
  1520. literals and operates on the asumption that if a value (i.e.
  1521. `Literal.value`) could be determined for a Literal then it is not
  1522. ill-typed/ill-formed.
  1523. This function will be called with `Literal.lexical` and `Literal.value` as arguments.
  1524. """
  1525. return value is not None
  1526. def _well_formed_unsignedlong(lexical: Union[str, bytes], value: Any) -> bool:
  1527. """
  1528. xsd:unsignedInteger and xsd:unsignedLong must not be negative
  1529. """
  1530. return len(lexical) > 0 and isinstance(value, long_type) and value >= 0
  1531. def _well_formed_boolean(lexical: Union[str, bytes], value: Any) -> bool:
  1532. """
  1533. Boolean is a datatype with value space {true,false},
  1534. lexical space {"true", "false","1","0"} and
  1535. lexical-to-value mapping {"true"→true, "false"→false, "1"→true, "0"→false}.
  1536. """
  1537. return lexical in ("true", b"true", "false", b"false", "1", b"1", "0", b"0")
  1538. def _well_formed_int(lexical: Union[str, bytes], value: Any) -> bool:
  1539. """
  1540. The value space of xs:int is the set of common single size integers (32 bits),
  1541. i.e., the integers between -2147483648 and 2147483647,
  1542. its lexical space allows any number of insignificant leading zeros.
  1543. """
  1544. return (
  1545. len(lexical) > 0
  1546. and isinstance(value, int)
  1547. and (-2147483648 <= value <= 2147483647)
  1548. )
  1549. def _well_formed_unsignedint(lexical: Union[str, bytes], value: Any) -> bool:
  1550. """
  1551. xsd:unsignedInt has a 32bit value of between 0 and 4294967295
  1552. """
  1553. return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 4294967295)
  1554. def _well_formed_short(lexical: Union[str, bytes], value: Any) -> bool:
  1555. """
  1556. The value space of xs:short is the set of common short integers (16 bits),
  1557. i.e., the integers between -32768 and 32767,
  1558. its lexical space allows any number of insignificant leading zeros.
  1559. """
  1560. return len(lexical) > 0 and isinstance(value, int) and (-32768 <= value <= 32767)
  1561. def _well_formed_unsignedshort(lexical: Union[str, bytes], value: Any) -> bool:
  1562. """
  1563. xsd:unsignedShort has a 16bit value of between 0 and 65535
  1564. """
  1565. return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 65535)
  1566. def _well_formed_byte(lexical: Union[str, bytes], value: Any) -> bool:
  1567. """
  1568. The value space of xs:byte is the set of common single byte integers (8 bits),
  1569. i.e., the integers between -128 and 127,
  1570. its lexical space allows any number of insignificant leading zeros.
  1571. """
  1572. return len(lexical) > 0 and isinstance(value, int) and (-128 <= value <= 127)
  1573. def _well_formed_unsignedbyte(lexical: Union[str, bytes], value: Any) -> bool:
  1574. """
  1575. xsd:unsignedByte has a 8bit value of between 0 and 255
  1576. """
  1577. return len(lexical) > 0 and isinstance(value, int) and (0 <= value <= 255)
  1578. def _well_formed_non_negative_integer(lexical: Union[str, bytes], value: Any) -> bool:
  1579. return isinstance(value, int) and value >= 0
  1580. def _well_formed_positive_integer(lexical: Union[str, bytes], value: Any) -> bool:
  1581. return isinstance(value, int) and value > 0
  1582. def _well_formed_non_positive_integer(lexical: Union[str, bytes], value: Any) -> bool:
  1583. return isinstance(value, int) and value <= 0
  1584. def _well_formed_negative_integer(lexical: Union[str, bytes], value: Any) -> bool:
  1585. return isinstance(value, int) and value < 0
  1586. # Cannot import Namespace/XSD because of circular dependencies
  1587. _XSD_PFX = "http://www.w3.org/2001/XMLSchema#"
  1588. _RDF_PFX = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  1589. _RDF_XMLLITERAL = URIRef(_RDF_PFX + "XMLLiteral")
  1590. _RDF_HTMLLITERAL = URIRef(_RDF_PFX + "HTML")
  1591. _XSD_STRING = URIRef(_XSD_PFX + "string")
  1592. _XSD_NORMALISED_STRING = URIRef(_XSD_PFX + "normalizedString")
  1593. _XSD_TOKEN = URIRef(_XSD_PFX + "token")
  1594. _XSD_FLOAT = URIRef(_XSD_PFX + "float")
  1595. _XSD_DOUBLE = URIRef(_XSD_PFX + "double")
  1596. _XSD_DECIMAL = URIRef(_XSD_PFX + "decimal")
  1597. _XSD_INTEGER = URIRef(_XSD_PFX + "integer")
  1598. _XSD_BOOLEAN = URIRef(_XSD_PFX + "boolean")
  1599. _XSD_DATETIME = URIRef(_XSD_PFX + "dateTime")
  1600. _XSD_DATE = URIRef(_XSD_PFX + "date")
  1601. _XSD_TIME = URIRef(_XSD_PFX + "time")
  1602. _XSD_DURATION = URIRef(_XSD_PFX + "duration")
  1603. _XSD_DAYTIMEDURATION = URIRef(_XSD_PFX + "dayTimeDuration")
  1604. _XSD_YEARMONTHDURATION = URIRef(_XSD_PFX + "yearMonthDuration")
  1605. _OWL_RATIONAL = URIRef("http://www.w3.org/2002/07/owl#rational")
  1606. _XSD_B64BINARY = URIRef(_XSD_PFX + "base64Binary")
  1607. _XSD_HEXBINARY = URIRef(_XSD_PFX + "hexBinary")
  1608. _XSD_GYEAR = URIRef(_XSD_PFX + "gYear")
  1609. _XSD_GYEARMONTH = URIRef(_XSD_PFX + "gYearMonth")
  1610. # TODO: gMonthDay, gDay, gMonth
  1611. _NUMERIC_LITERAL_TYPES: Tuple[URIRef, ...] = (
  1612. _XSD_INTEGER,
  1613. _XSD_DECIMAL,
  1614. _XSD_DOUBLE,
  1615. URIRef(_XSD_PFX + "float"),
  1616. URIRef(_XSD_PFX + "byte"),
  1617. URIRef(_XSD_PFX + "int"),
  1618. URIRef(_XSD_PFX + "long"),
  1619. URIRef(_XSD_PFX + "negativeInteger"),
  1620. URIRef(_XSD_PFX + "nonNegativeInteger"),
  1621. URIRef(_XSD_PFX + "nonPositiveInteger"),
  1622. URIRef(_XSD_PFX + "positiveInteger"),
  1623. URIRef(_XSD_PFX + "short"),
  1624. URIRef(_XSD_PFX + "unsignedByte"),
  1625. URIRef(_XSD_PFX + "unsignedInt"),
  1626. URIRef(_XSD_PFX + "unsignedLong"),
  1627. URIRef(_XSD_PFX + "unsignedShort"),
  1628. )
  1629. # these have "native" syntax in N3/SPARQL
  1630. _PLAIN_LITERAL_TYPES: Tuple[URIRef, ...] = (
  1631. _XSD_INTEGER,
  1632. _XSD_BOOLEAN,
  1633. _XSD_DOUBLE,
  1634. _XSD_DECIMAL,
  1635. _OWL_RATIONAL,
  1636. )
  1637. # these have special INF and NaN XSD representations
  1638. _NUMERIC_INF_NAN_LITERAL_TYPES: Tuple[URIRef, ...] = (
  1639. URIRef(_XSD_PFX + "float"),
  1640. _XSD_DOUBLE,
  1641. _XSD_DECIMAL,
  1642. )
  1643. # these need dedicated operators
  1644. _DATE_AND_TIME_TYPES: Tuple[URIRef, ...] = (
  1645. _XSD_DATETIME,
  1646. _XSD_DATE,
  1647. _XSD_TIME,
  1648. )
  1649. # These are recognized datatype IRIs
  1650. # (https://www.w3.org/TR/rdf11-concepts/#dfn-recognized-datatype-iris) that
  1651. # represents durations.
  1652. _TIME_DELTA_TYPES: Tuple[URIRef, ...] = (
  1653. _XSD_DURATION,
  1654. _XSD_DAYTIMEDURATION,
  1655. )
  1656. _ALL_DATE_AND_TIME_TYPES: Tuple[URIRef, ...] = _DATE_AND_TIME_TYPES + _TIME_DELTA_TYPES
  1657. # the following types need special treatment for reasonable sorting because
  1658. # certain instances can't be compared to each other. We treat this by
  1659. # partitioning and then sorting within those partitions.
  1660. _TOTAL_ORDER_CASTERS: Dict[Type[Any], Callable[[Any], Any]] = {
  1661. datetime: lambda value: (
  1662. # naive vs. aware
  1663. value.tzinfo is not None and value.tzinfo.utcoffset(value) is not None,
  1664. value,
  1665. ),
  1666. time: lambda value: (
  1667. # naive vs. aware
  1668. value.tzinfo is not None and value.tzinfo.utcoffset(None) is not None,
  1669. value,
  1670. ),
  1671. xml.dom.minidom.Document: lambda value: value.toxml(),
  1672. }
  1673. _STRING_LITERAL_TYPES: Tuple[URIRef, ...] = (
  1674. _XSD_STRING,
  1675. _RDF_XMLLITERAL,
  1676. _RDF_HTMLLITERAL,
  1677. URIRef(_XSD_PFX + "normalizedString"),
  1678. URIRef(_XSD_PFX + "token"),
  1679. )
  1680. _StrT = TypeVar("_StrT", bound=str)
  1681. def _py2literal(
  1682. obj: Any,
  1683. pType: Any, # noqa: N803
  1684. castFunc: Optional[Callable[[Any], Any]], # noqa: N803
  1685. dType: Optional[_StrT], # noqa: N803
  1686. ) -> Tuple[Any, Optional[_StrT]]:
  1687. if castFunc is not None:
  1688. return castFunc(obj), dType
  1689. elif dType is not None:
  1690. return obj, dType
  1691. else:
  1692. return obj, None
  1693. def _castPythonToLiteral( # noqa: N802
  1694. obj: Any, datatype: Optional[str]
  1695. ) -> Tuple[Any, Optional[str]]:
  1696. """
  1697. Casts a tuple of a python type and a special datatype URI to a tuple of the lexical value and a
  1698. datatype URI (or None)
  1699. """
  1700. castFunc: Optional[Callable[[Any], Union[str, bytes]]] # noqa: N806
  1701. dType: Optional[str] # noqa: N806
  1702. for (pType, dType), castFunc in _SpecificPythonToXSDRules: # noqa: N806
  1703. if isinstance(obj, pType) and dType == datatype:
  1704. return _py2literal(obj, pType, castFunc, dType)
  1705. for pType, (castFunc, dType) in _GenericPythonToXSDRules: # noqa: N806
  1706. if isinstance(obj, pType):
  1707. return _py2literal(obj, pType, castFunc, dType)
  1708. return obj, None # TODO: is this right for the fall through case?
  1709. # Mappings from Python types to XSD datatypes and back (borrowed from sparta)
  1710. # datetime instances are also instances of date... so we need to order these.
  1711. # SPARQL/Turtle/N3 has shortcuts for integer, double, decimal
  1712. # python has only float - to be in tune with sparql/n3/turtle
  1713. # we default to XSD.double for float literals
  1714. # python ints are promoted to longs when overflowing
  1715. # python longs have no limit
  1716. # both map to the abstract integer type,
  1717. # rather than some concrete bit-limited datatype
  1718. _GenericPythonToXSDRules: List[
  1719. Tuple[Type[Any], Tuple[Optional[Callable[[Any], Union[str, bytes]]], Optional[str]]]
  1720. ] = [
  1721. (str, (None, None)),
  1722. (float, (None, _XSD_DOUBLE)),
  1723. (bool, (lambda i: str(i).lower(), _XSD_BOOLEAN)),
  1724. (int, (None, _XSD_INTEGER)),
  1725. (long_type, (None, _XSD_INTEGER)),
  1726. (Decimal, (lambda i: f"{i:f}", _XSD_DECIMAL)),
  1727. (datetime, (lambda i: i.isoformat(), _XSD_DATETIME)),
  1728. (date, (lambda i: i.isoformat(), _XSD_DATE)),
  1729. (time, (lambda i: i.isoformat(), _XSD_TIME)),
  1730. (Duration, (lambda i: duration_isoformat(i), _XSD_DURATION)),
  1731. (timedelta, (lambda i: duration_isoformat(i), _XSD_DAYTIMEDURATION)),
  1732. (xml.dom.minidom.Document, (_writeXML, _RDF_XMLLITERAL)),
  1733. (Fraction, (None, _OWL_RATIONAL)),
  1734. ]
  1735. if html5rdf is not None:
  1736. # This is a bit dirty, by accident the html5rdf parser produces
  1737. # DocumentFragments, and the xml parser Documents, letting this
  1738. # decide what datatype to use makes roundtripping easier, but its a
  1739. # bit random.
  1740. # This must happen before _GenericPythonToXSDRules is assigned to
  1741. # _OriginalGenericPythonToXSDRules.
  1742. _GenericPythonToXSDRules.append(
  1743. (xml.dom.minidom.DocumentFragment, (_write_html, _RDF_HTMLLITERAL))
  1744. )
  1745. _OriginalGenericPythonToXSDRules = list(_GenericPythonToXSDRules)
  1746. _SpecificPythonToXSDRules: List[
  1747. Tuple[Tuple[Type[Any], str], Optional[Callable[[Any], Union[str, bytes]]]]
  1748. ] = [
  1749. ((date, _XSD_GYEAR), lambda val: val.strftime("%Y").zfill(4)),
  1750. ((date, _XSD_GYEARMONTH), lambda val: val.strftime("%Y-%m").zfill(7)),
  1751. ((str, _XSD_HEXBINARY), hexlify),
  1752. ((bytes, _XSD_HEXBINARY), hexlify),
  1753. ((str, _XSD_B64BINARY), b64encode),
  1754. ((bytes, _XSD_B64BINARY), b64encode),
  1755. ]
  1756. _OriginalSpecificPythonToXSDRules = list(_SpecificPythonToXSDRules)
  1757. XSDToPython: Dict[Optional[str], Optional[Callable[[str], Any]]] = {
  1758. None: None, # plain literals map directly to value space
  1759. URIRef(_XSD_PFX + "time"): parse_time,
  1760. URIRef(_XSD_PFX + "date"): parse_xsd_date,
  1761. URIRef(_XSD_PFX + "dateTime"): parse_datetime,
  1762. URIRef(_XSD_PFX + "duration"): parse_xsd_duration,
  1763. URIRef(_XSD_PFX + "dayTimeDuration"): parse_xsd_duration,
  1764. URIRef(_XSD_PFX + "yearMonthDuration"): parse_xsd_duration,
  1765. URIRef(_XSD_PFX + "hexBinary"): _unhexlify,
  1766. URIRef(_XSD_PFX + "string"): None,
  1767. URIRef(_XSD_PFX + "normalizedString"): None,
  1768. URIRef(_XSD_PFX + "token"): None,
  1769. URIRef(_XSD_PFX + "language"): None,
  1770. URIRef(_XSD_PFX + "boolean"): _parseBoolean,
  1771. URIRef(_XSD_PFX + "decimal"): Decimal,
  1772. URIRef(_XSD_PFX + "integer"): long_type,
  1773. URIRef(_XSD_PFX + "nonPositiveInteger"): long_type,
  1774. URIRef(_XSD_PFX + "long"): long_type,
  1775. URIRef(_XSD_PFX + "nonNegativeInteger"): long_type,
  1776. URIRef(_XSD_PFX + "negativeInteger"): long_type,
  1777. URIRef(_XSD_PFX + "int"): int,
  1778. URIRef(_XSD_PFX + "unsignedLong"): long_type,
  1779. URIRef(_XSD_PFX + "positiveInteger"): long_type,
  1780. URIRef(_XSD_PFX + "short"): int,
  1781. URIRef(_XSD_PFX + "unsignedInt"): int,
  1782. URIRef(_XSD_PFX + "byte"): int,
  1783. URIRef(_XSD_PFX + "unsignedShort"): int,
  1784. URIRef(_XSD_PFX + "unsignedByte"): int,
  1785. URIRef(_XSD_PFX + "float"): float,
  1786. URIRef(_XSD_PFX + "double"): float,
  1787. URIRef(_XSD_PFX + "base64Binary"): b64decode,
  1788. URIRef(_XSD_PFX + "anyURI"): None,
  1789. _RDF_XMLLITERAL: _parseXML,
  1790. }
  1791. if html5rdf is not None:
  1792. # It is probably best to keep this close to the definition of
  1793. # _GenericPythonToXSDRules so nobody misses it.
  1794. XSDToPython[_RDF_HTMLLITERAL] = _parse_html
  1795. _XML_COMPARABLE: Tuple[URIRef, ...] = (_RDF_XMLLITERAL, _RDF_HTMLLITERAL)
  1796. else:
  1797. _XML_COMPARABLE = (_RDF_XMLLITERAL,)
  1798. _check_well_formed_types: Dict[URIRef, Callable[[Union[str, bytes], Any], bool]] = {
  1799. URIRef(_XSD_PFX + "boolean"): _well_formed_boolean,
  1800. URIRef(_XSD_PFX + "nonPositiveInteger"): _well_formed_non_positive_integer,
  1801. URIRef(_XSD_PFX + "nonNegativeInteger"): _well_formed_non_negative_integer,
  1802. URIRef(_XSD_PFX + "negativeInteger"): _well_formed_negative_integer,
  1803. URIRef(_XSD_PFX + "positiveInteger"): _well_formed_positive_integer,
  1804. URIRef(_XSD_PFX + "int"): _well_formed_int,
  1805. URIRef(_XSD_PFX + "short"): _well_formed_short,
  1806. URIRef(_XSD_PFX + "byte"): _well_formed_byte,
  1807. URIRef(_XSD_PFX + "unsignedInt"): _well_formed_unsignedint,
  1808. URIRef(_XSD_PFX + "unsignedLong"): _well_formed_unsignedlong,
  1809. URIRef(_XSD_PFX + "unsignedShort"): _well_formed_unsignedshort,
  1810. URIRef(_XSD_PFX + "unsignedByte"): _well_formed_unsignedbyte,
  1811. }
  1812. _toPythonMapping: Dict[Optional[str], Optional[Callable[[str], Any]]] = {} # noqa: N816
  1813. _toPythonMapping.update(XSDToPython)
  1814. def _reset_bindings() -> None:
  1815. """Reset lexical<->value space binding for `Literal`."""
  1816. _toPythonMapping.clear()
  1817. _toPythonMapping.update(XSDToPython)
  1818. _GenericPythonToXSDRules.clear()
  1819. _GenericPythonToXSDRules.extend(_OriginalGenericPythonToXSDRules)
  1820. _SpecificPythonToXSDRules.clear()
  1821. _SpecificPythonToXSDRules.extend(_OriginalSpecificPythonToXSDRules)
  1822. def _castLexicalToPython( # noqa: N802
  1823. lexical: Union[str, bytes], datatype: Optional[URIRef]
  1824. ) -> Any:
  1825. """Map a lexical form to the value-space for the given datatype.
  1826. Returns:
  1827. A python object for the value or `None`
  1828. """
  1829. try:
  1830. conv_func = _toPythonMapping[datatype]
  1831. except KeyError:
  1832. # no conv_func -> unknown data-type
  1833. return None
  1834. if conv_func is not None:
  1835. try:
  1836. # type error: Argument 1 has incompatible type "Union[str, bytes]"; expected "str"
  1837. # NOTE for type ignore: various functions in _toPythonMapping will
  1838. # only work for str, so there is some inconsistency here, the right
  1839. # approach may be to change lexical to be of str type but this will
  1840. # require runtime changes.
  1841. return conv_func(lexical) # type: ignore[arg-type]
  1842. except Exception:
  1843. logger.warning(
  1844. f"Failed to convert Literal lexical form to value. Datatype={datatype}, Converter={conv_func}",
  1845. exc_info=True,
  1846. )
  1847. # not a valid lexical representation for this dt
  1848. return None
  1849. else:
  1850. # no conv func means 1-1 lexical<->value-space mapping
  1851. try:
  1852. return str(lexical)
  1853. except UnicodeDecodeError:
  1854. # type error: Argument 1 to "str" has incompatible type "Union[str, bytes]"; expected "bytes"
  1855. # NOTE for type ignore: code assumes that lexical is of type bytes
  1856. # at this point.
  1857. return str(lexical, "utf-8") # type: ignore[arg-type]
  1858. _AnyT = TypeVar("_AnyT", bound=Any)
  1859. def _normalise_XSD_STRING(lexical_or_value: _AnyT) -> _AnyT: # noqa: N802
  1860. """Replaces \\t, \\n, \\r (#x9 (tab), #xA (linefeed), and #xD (carriage return)) with space without any whitespace collapsing."""
  1861. if isinstance(lexical_or_value, str):
  1862. # type error: Incompatible return value type (got "str", expected "_AnyT") [return-value]
  1863. # NOTE for type ignore: this is an issue with mypy: https://github.com/python/mypy/issues/10003
  1864. return lexical_or_value.replace("\t", " ").replace("\n", " ").replace("\r", " ") # type: ignore[return-value]
  1865. return lexical_or_value
  1866. def _strip_and_collapse_whitespace(lexical_or_value: _AnyT) -> _AnyT:
  1867. if isinstance(lexical_or_value, str):
  1868. # Use regex to substitute contiguous whitespace into a single whitespace. Strip trailing whitespace.
  1869. # type error: Incompatible return value type (got "str", expected "_AnyT") [return-value]
  1870. # NOTE for type ignore: this is an issue with mypy: https://github.com/python/mypy/issues/10003
  1871. return re.sub(" +", " ", lexical_or_value.strip()) # type: ignore[return-value]
  1872. return lexical_or_value
  1873. def bind(
  1874. datatype: str,
  1875. pythontype: Type[Any],
  1876. constructor: Optional[Callable[[str], Any]] = None,
  1877. lexicalizer: Optional[Callable[[Any], Union[str, bytes]]] = None,
  1878. datatype_specific: bool = False,
  1879. ) -> None:
  1880. """
  1881. register a new datatype<->pythontype binding
  1882. Args:
  1883. constructor: An optional function for converting lexical forms
  1884. into a Python instances, if not given the pythontype
  1885. is used directly
  1886. lexicalizer: An optional function for converting python objects to
  1887. lexical form, if not given object.__str__ is used
  1888. datatype_specific: Makes the lexicalizer function be accessible
  1889. from the pair (pythontype, datatype) if set to True
  1890. or from the pythontype otherwise. False by default
  1891. """
  1892. if datatype_specific and datatype is None:
  1893. raise Exception("No datatype given for a datatype-specific binding")
  1894. if datatype in _toPythonMapping:
  1895. logger.warning(f"datatype '{datatype}' was already bound. Rebinding.")
  1896. if constructor is None:
  1897. constructor = pythontype
  1898. _toPythonMapping[datatype] = constructor
  1899. if datatype_specific:
  1900. _SpecificPythonToXSDRules.append(((pythontype, datatype), lexicalizer))
  1901. else:
  1902. _GenericPythonToXSDRules.append((pythontype, (lexicalizer, datatype)))
  1903. class Variable(Identifier):
  1904. """
  1905. A Variable - this is used for querying, or in Formula aware
  1906. graphs, where Variables can be stored
  1907. """
  1908. __slots__ = ()
  1909. def __new__(cls, value: str):
  1910. if len(value) == 0:
  1911. raise Exception("Attempted to create variable with empty string as name!")
  1912. if value[0] == "?":
  1913. value = value[1:]
  1914. return str.__new__(cls, value)
  1915. def __repr__(self) -> str:
  1916. if self.__class__ is Variable:
  1917. clsName = "rdflib.term.Variable" # noqa: N806
  1918. else:
  1919. clsName = self.__class__.__name__ # noqa: N806
  1920. return f"{clsName}({str.__repr__(self)})"
  1921. def toPython(self) -> str: # noqa: N802
  1922. return "?" + self
  1923. def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str:
  1924. return "?" + self
  1925. def __reduce__(self) -> Tuple[Type[Variable], Tuple[str]]:
  1926. return (Variable, (str(self),))
  1927. # Nodes are ordered like this
  1928. # See http://www.w3.org/TR/sparql11-query/#modOrderBy
  1929. # we leave "space" for more subclasses of Node elsewhere
  1930. # default-dict to grazefully fail for new subclasses
  1931. _ORDERING: Dict[Type[Node], int] = defaultdict(int)
  1932. _ORDERING.update({BNode: 10, Variable: 20, URIRef: 30, Literal: 40})
  1933. def _isEqualXMLNode( # noqa: N802
  1934. node: Union[
  1935. None,
  1936. xml.dom.minidom.Attr,
  1937. xml.dom.minidom.Comment,
  1938. xml.dom.minidom.Document,
  1939. xml.dom.minidom.DocumentFragment,
  1940. xml.dom.minidom.DocumentType,
  1941. xml.dom.minidom.Element,
  1942. xml.dom.minidom.Entity,
  1943. xml.dom.minidom.Notation,
  1944. xml.dom.minidom.ProcessingInstruction,
  1945. xml.dom.minidom.Text,
  1946. ],
  1947. other: Union[
  1948. None,
  1949. xml.dom.minidom.Attr,
  1950. xml.dom.minidom.Comment,
  1951. xml.dom.minidom.Document,
  1952. xml.dom.minidom.DocumentFragment,
  1953. xml.dom.minidom.DocumentType,
  1954. xml.dom.minidom.Element,
  1955. xml.dom.minidom.Entity,
  1956. xml.dom.minidom.Notation,
  1957. xml.dom.minidom.ProcessingInstruction,
  1958. xml.dom.minidom.Text,
  1959. ],
  1960. ) -> bool:
  1961. # importing xml.dom.minidom.Node as XMLNode to avoid confusion with
  1962. # rdflib.term.Node
  1963. from xml.dom.minidom import Node as XMLNode
  1964. def recurse():
  1965. # Recursion through the children
  1966. # In Python2, the semantics of 'map' is such that the check on
  1967. # length would be unnecessary. In Python 3,
  1968. # the semantics of map has changed (why, oh why???) and the check
  1969. # for the length becomes necessary...
  1970. # type error: Item "None" of "Union[None, Attr, Comment, Document, DocumentFragment, DocumentType, Element, Entity, Notation, ProcessingInstruction, Text]" has no attribute "childNodes"
  1971. if len(node.childNodes) != len(other.childNodes): # type: ignore[union-attr]
  1972. return False
  1973. # type error: Item "None" of "Union[None, Attr, Comment, Document, DocumentFragment, DocumentType, Element, Entity, Notation, ProcessingInstruction, Text]" has no attribute "childNodes"
  1974. for nc, oc in map(lambda x, y: (x, y), node.childNodes, other.childNodes): # type: ignore[union-attr]
  1975. if not _isEqualXMLNode(nc, oc):
  1976. return False
  1977. # if we got here then everything is fine:
  1978. return True
  1979. if node is None or other is None:
  1980. return False
  1981. if node.nodeType != other.nodeType:
  1982. return False
  1983. if node.nodeType in [XMLNode.DOCUMENT_NODE, XMLNode.DOCUMENT_FRAGMENT_NODE]:
  1984. return recurse()
  1985. elif node.nodeType == XMLNode.ELEMENT_NODE:
  1986. if TYPE_CHECKING:
  1987. assert isinstance(node, xml.dom.minidom.Element)
  1988. assert isinstance(other, xml.dom.minidom.Element)
  1989. # Get the basics right
  1990. if not (
  1991. node.tagName == other.tagName and node.namespaceURI == other.namespaceURI
  1992. ):
  1993. return False
  1994. # Handle the (namespaced) attributes; the namespace setting key
  1995. # should be ignored, though
  1996. # Note that the minidom orders the keys already, so we do not have
  1997. # to worry about that, which is a bonus...
  1998. n_keys = [
  1999. k
  2000. for k in node.attributes.keysNS()
  2001. if k[0] != "http://www.w3.org/2000/xmlns/"
  2002. ]
  2003. o_keys = [
  2004. k
  2005. for k in other.attributes.keysNS()
  2006. if k[0] != "http://www.w3.org/2000/xmlns/"
  2007. ]
  2008. if len(n_keys) != len(o_keys):
  2009. return False
  2010. for k in n_keys:
  2011. if not (
  2012. k in o_keys
  2013. and node.getAttributeNS(k[0], k[1]) == other.getAttributeNS(k[0], k[1])
  2014. ):
  2015. return False
  2016. # if we got here, the attributes are all right, we can go down
  2017. # the tree recursively
  2018. return recurse()
  2019. elif node.nodeType in [
  2020. XMLNode.TEXT_NODE,
  2021. XMLNode.COMMENT_NODE,
  2022. XMLNode.CDATA_SECTION_NODE,
  2023. XMLNode.NOTATION_NODE,
  2024. ]:
  2025. if TYPE_CHECKING:
  2026. assert isinstance(
  2027. node,
  2028. (
  2029. xml.dom.minidom.Text,
  2030. xml.dom.minidom.Comment,
  2031. xml.dom.minidom.CDATASection,
  2032. xml.dom.minidom.Notation,
  2033. ),
  2034. )
  2035. assert isinstance(
  2036. other,
  2037. (
  2038. xml.dom.minidom.Text,
  2039. xml.dom.minidom.Comment,
  2040. xml.dom.minidom.CDATASection,
  2041. xml.dom.minidom.Notation,
  2042. ),
  2043. )
  2044. # type error: Item "Notation" of "Union[Comment, Document, Notation, Text]" has no attribute "data"
  2045. return node.data == other.data # type: ignore[union-attr] # FIXME
  2046. elif node.nodeType == XMLNode.PROCESSING_INSTRUCTION_NODE:
  2047. if TYPE_CHECKING:
  2048. assert isinstance(node, xml.dom.minidom.ProcessingInstruction)
  2049. assert isinstance(other, xml.dom.minidom.ProcessingInstruction)
  2050. return node.data == other.data and node.target == other.target
  2051. elif node.nodeType == XMLNode.ENTITY_NODE:
  2052. return node.nodeValue == other.nodeValue
  2053. elif node.nodeType == XMLNode.DOCUMENT_TYPE_NODE:
  2054. if TYPE_CHECKING:
  2055. assert isinstance(node, xml.dom.minidom.DocumentType)
  2056. assert isinstance(other, xml.dom.minidom.DocumentType)
  2057. return node.publicId == other.publicId and node.systemId == other.systemId
  2058. else:
  2059. # should not happen, in fact
  2060. raise Exception(f"I dont know how to compare XML Node type: {node.nodeType}")