comparison planemo/lib/python3.7/site-packages/rdflib/plugins/sparql/operators.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 """
2 This contains evaluation functions for expressions
3
4 They get bound as instances-methods to the CompValue objects from parserutils
5 using setEvalFn
6
7 """
8
9 import sys
10 import re
11 import math
12 import random
13 import uuid
14 import hashlib
15 import urllib.request, urllib.error, urllib.parse
16
17 from decimal import Decimal, ROUND_HALF_UP, InvalidOperation
18
19 import operator as pyop # python operators
20
21 import isodate
22
23 from rdflib.plugins.sparql.parserutils import CompValue, Expr
24 from rdflib.plugins.sparql.datatypes import XSD_DTs, type_promotion
25 from rdflib import URIRef, BNode, Variable, Literal, XSD, RDF
26 from rdflib.term import Node
27
28 from pyparsing import ParseResults
29
30 from rdflib.plugins.sparql.sparql import SPARQLError, SPARQLTypeError
31 from functools import reduce
32
33
34 # closed namespace, langString isn't in it
35 RDF_langString = URIRef(RDF.uri + "langString")
36
37
38 def Builtin_IRI(expr, ctx):
39 """
40 http://www.w3.org/TR/sparql11-query/#func-iri
41 """
42
43 a = expr.arg
44
45 if isinstance(a, URIRef):
46 return a
47 if isinstance(a, Literal):
48 return ctx.prologue.absolutize(URIRef(a))
49
50 raise SPARQLError('IRI function only accepts URIRefs or Literals/Strings!')
51
52
53 def Builtin_isBLANK(expr, ctx):
54 return Literal(isinstance(expr.arg, BNode))
55
56
57 def Builtin_isLITERAL(expr, ctx):
58 return Literal(isinstance(expr.arg, Literal))
59
60
61 def Builtin_isIRI(expr, ctx):
62 return Literal(isinstance(expr.arg, URIRef))
63
64
65 def Builtin_isNUMERIC(expr, ctx):
66 try:
67 numeric(expr.arg)
68 return Literal(True)
69 except:
70 return Literal(False)
71
72
73 def Builtin_BNODE(expr, ctx):
74 """
75 http://www.w3.org/TR/sparql11-query/#func-bnode
76 """
77
78 a = expr.arg
79
80 if a is None:
81 return BNode()
82
83 if isinstance(a, Literal):
84 return ctx.bnodes[a] # defaultdict does the right thing
85
86 raise SPARQLError(
87 'BNode function only accepts no argument or literal/string')
88
89
90 def Builtin_ABS(expr, ctx):
91 """
92 http://www.w3.org/TR/sparql11-query/#func-abs
93 """
94
95 return Literal(abs(numeric(expr.arg)))
96
97
98 def Builtin_IF(expr, ctx):
99 """
100 http://www.w3.org/TR/sparql11-query/#func-if
101 """
102
103 return expr.arg2 if EBV(expr.arg1) else expr.arg3
104
105
106 def Builtin_RAND(expr, ctx):
107 """
108 http://www.w3.org/TR/sparql11-query/#idp2133952
109 """
110
111 return Literal(random.random())
112
113
114 def Builtin_UUID(expr, ctx):
115 """
116 http://www.w3.org/TR/sparql11-query/#func-strdt
117 """
118
119 return URIRef(uuid.uuid4().urn)
120
121
122 def Builtin_STRUUID(expr, ctx):
123 """
124 http://www.w3.org/TR/sparql11-query/#func-strdt
125 """
126
127 return Literal(str(uuid.uuid4()))
128
129
130 def Builtin_MD5(expr, ctx):
131 s = string(expr.arg).encode("utf-8")
132 return Literal(hashlib.md5(s).hexdigest())
133
134
135 def Builtin_SHA1(expr, ctx):
136 s = string(expr.arg).encode("utf-8")
137 return Literal(hashlib.sha1(s).hexdigest())
138
139
140 def Builtin_SHA256(expr, ctx):
141 s = string(expr.arg).encode("utf-8")
142 return Literal(hashlib.sha256(s).hexdigest())
143
144
145 def Builtin_SHA384(expr, ctx):
146 s = string(expr.arg).encode("utf-8")
147 return Literal(hashlib.sha384(s).hexdigest())
148
149
150 def Builtin_SHA512(expr, ctx):
151 s = string(expr.arg).encode("utf-8")
152 return Literal(hashlib.sha512(s).hexdigest())
153
154
155 def Builtin_COALESCE(expr, ctx):
156 """
157 http://www.w3.org/TR/sparql11-query/#func-coalesce
158 """
159 for x in expr.get('arg', variables=True):
160 if x is not None and not isinstance(x, (SPARQLError, Variable)):
161 return x
162 raise SPARQLError(
163 "COALESCE got no arguments that did not evaluate to an error")
164
165
166 def Builtin_CEIL(expr, ctx):
167 """
168 http://www.w3.org/TR/sparql11-query/#func-ceil
169 """
170
171 l = expr.arg
172 return Literal(int(math.ceil(numeric(l))), datatype=l.datatype)
173
174
175 def Builtin_FLOOR(expr, ctx):
176 """
177 http://www.w3.org/TR/sparql11-query/#func-floor
178 """
179 l = expr.arg
180 return Literal(int(math.floor(numeric(l))), datatype=l.datatype)
181
182
183 def Builtin_ROUND(expr, ctx):
184 """
185 http://www.w3.org/TR/sparql11-query/#func-round
186 """
187
188 # This used to be just math.bound
189 # but in py3k bound was changed to
190 # "round-to-even" behaviour
191 # this is an ugly work-around
192 l = expr.arg
193 v = numeric(l)
194 v = int(Decimal(v).quantize(1, ROUND_HALF_UP))
195 return Literal(v, datatype=l.datatype)
196
197
198 def Builtin_REGEX(expr, ctx):
199 """
200 http://www.w3.org/TR/sparql11-query/#func-regex
201 Invokes the XPath fn:matches function to match text against a regular
202 expression pattern.
203 The regular expression language is defined in XQuery 1.0 and XPath 2.0
204 Functions and Operators section 7.6.1 Regular Expression Syntax
205 """
206
207 text = string(expr.text)
208 pattern = string(expr.pattern)
209 flags = expr.flags
210
211 cFlag = 0
212 if flags:
213 # Maps XPath REGEX flags (http://www.w3.org/TR/xpath-functions/#flags)
214 # to Python's re flags
215 flagMap = dict(
216 [('i', re.IGNORECASE), ('s', re.DOTALL), ('m', re.MULTILINE)])
217 cFlag = reduce(pyop.or_, [flagMap.get(f, 0) for f in flags])
218
219 return Literal(bool(re.search(str(pattern), text, cFlag)))
220
221
222 def Builtin_REPLACE(expr, ctx):
223 """
224 http://www.w3.org/TR/sparql11-query/#func-substr
225 """
226 text = string(expr.arg)
227 pattern = string(expr.pattern)
228 replacement = string(expr.replacement)
229 flags = expr.flags
230
231 # python uses \1, xpath/sparql uses $1
232 replacement = re.sub('\\$([0-9]*)', r'\\\1', replacement)
233
234 def _r(m):
235
236 # Now this is ugly.
237 # Python has a "feature" where unmatched groups return None
238 # then re.sub chokes on this.
239 # see http://bugs.python.org/issue1519638 , fixed and errs in py3.5
240
241 # this works around and hooks into the internal of the re module...
242
243 # the match object is replaced with a wrapper that
244 # returns "" instead of None for unmatched groups
245
246 class _m():
247 def __init__(self, m):
248 self.m = m
249 self.string = m.string
250
251 def group(self, n):
252 return m.group(n) or ""
253
254 return re._expand(pattern, _m(m), replacement)
255
256 cFlag = 0
257 if flags:
258 # Maps XPath REGEX flags (http://www.w3.org/TR/xpath-functions/#flags)
259 # to Python's re flags
260 flagMap = dict(
261 [('i', re.IGNORECASE), ('s', re.DOTALL), ('m', re.MULTILINE)])
262 cFlag = reduce(pyop.or_, [flagMap.get(f, 0) for f in flags])
263
264 # @@FIXME@@ either datatype OR lang, NOT both
265
266 # this is necessary due to different treatment of unmatched groups in
267 # python versions. see comments above in _r(m).
268 compat_r = str(replacement) if sys.version_info[:2] >= (3, 5) else _r
269
270 return Literal(re.sub(str(pattern), compat_r, text, cFlag),
271 datatype=text.datatype, lang=text.language)
272
273
274 def Builtin_STRDT(expr, ctx):
275 """
276 http://www.w3.org/TR/sparql11-query/#func-strdt
277 """
278
279 return Literal(str(expr.arg1), datatype=expr.arg2)
280
281
282 def Builtin_STRLANG(expr, ctx):
283 """
284 http://www.w3.org/TR/sparql11-query/#func-strlang
285 """
286
287 s = string(expr.arg1)
288 if s.language or s.datatype:
289 raise SPARQLError('STRLANG expects a simple literal')
290
291 # TODO: normalisation of lang tag to lower-case
292 # should probably happen in literal __init__
293 return Literal(str(s), lang=str(expr.arg2).lower())
294
295
296 def Builtin_CONCAT(expr, ctx):
297 """
298 http://www.w3.org/TR/sparql11-query/#func-concat
299 """
300
301 # dt/lang passed on only if they all match
302
303 dt = set(x.datatype for x in expr.arg)
304 dt = dt.pop() if len(dt) == 1 else None
305
306 lang = set(x.language for x in expr.arg)
307 lang = lang.pop() if len(lang) == 1 else None
308
309 return Literal("".join(string(x)
310 for x in expr.arg), datatype=dt, lang=lang)
311
312
313 def _compatibleStrings(a, b):
314 string(a)
315 string(b)
316
317 if b.language and a.language != b.language:
318 raise SPARQLError('incompatible arguments to str functions')
319
320
321 def Builtin_STRSTARTS(expr, ctx):
322 """
323 http://www.w3.org/TR/sparql11-query/#func-strstarts
324 """
325
326 a = expr.arg1
327 b = expr.arg2
328 _compatibleStrings(a, b)
329
330 return Literal(a.startswith(b))
331
332
333 def Builtin_STRENDS(expr, ctx):
334 """
335 http://www.w3.org/TR/sparql11-query/#func-strends
336 """
337 a = expr.arg1
338 b = expr.arg2
339
340 _compatibleStrings(a, b)
341
342 return Literal(a.endswith(b))
343
344
345 def Builtin_STRBEFORE(expr, ctx):
346 """
347 http://www.w3.org/TR/sparql11-query/#func-strbefore
348 """
349
350 a = expr.arg1
351 b = expr.arg2
352 _compatibleStrings(a, b)
353
354 i = a.find(b)
355 if i == -1:
356 return Literal("")
357 else:
358 return Literal(a[:i], lang=a.language, datatype=a.datatype)
359
360
361 def Builtin_STRAFTER(expr, ctx):
362 """
363 http://www.w3.org/TR/sparql11-query/#func-strafter
364 """
365
366 a = expr.arg1
367 b = expr.arg2
368 _compatibleStrings(a, b)
369
370 i = a.find(b)
371 if i == -1:
372 return Literal("")
373 else:
374 return Literal(a[i + len(b):], lang=a.language, datatype=a.datatype)
375
376
377 def Builtin_CONTAINS(expr, ctx):
378 """
379 http://www.w3.org/TR/sparql11-query/#func-strcontains
380 """
381
382 a = expr.arg1
383 b = expr.arg2
384 _compatibleStrings(a, b)
385
386 return Literal(b in a)
387
388
389 def Builtin_ENCODE_FOR_URI(expr, ctx):
390 return Literal(urllib.parse.quote(string(expr.arg).encode("utf-8")))
391
392
393 def Builtin_SUBSTR(expr, ctx):
394 """
395 http://www.w3.org/TR/sparql11-query/#func-substr
396 """
397
398 a = string(expr.arg)
399
400 start = numeric(expr.start) - 1
401
402 length = expr.length
403 if length is not None:
404 length = numeric(length) + start
405
406 return Literal(a[start:length], lang=a.language, datatype=a.datatype)
407
408
409 def Builtin_STRLEN(e, ctx):
410 l = string(e.arg)
411
412 return Literal(len(l))
413
414
415 def Builtin_STR(e, ctx):
416 arg = e.arg
417 if isinstance(arg, SPARQLError):
418 raise arg
419 return Literal(str(arg)) # plain literal
420
421
422 def Builtin_LCASE(e, ctx):
423 l = string(e.arg)
424
425 return Literal(l.lower(), datatype=l.datatype, lang=l.language)
426
427
428 def Builtin_LANGMATCHES(e, ctx):
429 """
430 http://www.w3.org/TR/sparql11-query/#func-langMatches
431
432
433 """
434 langTag = string(e.arg1)
435 langRange = string(e.arg2)
436
437 if str(langTag) == "":
438 return Literal(False) # nothing matches empty!
439
440 return Literal(_lang_range_check(langRange, langTag))
441
442
443 def Builtin_NOW(e, ctx):
444 """
445 http://www.w3.org/TR/sparql11-query/#func-now
446 """
447 return Literal(ctx.now)
448
449
450 def Builtin_YEAR(e, ctx):
451 d = datetime(e.arg)
452 return Literal(d.year)
453
454
455 def Builtin_MONTH(e, ctx):
456 d = datetime(e.arg)
457 return Literal(d.month)
458
459
460 def Builtin_DAY(e, ctx):
461 d = datetime(e.arg)
462 return Literal(d.day)
463
464
465 def Builtin_HOURS(e, ctx):
466 d = datetime(e.arg)
467 return Literal(d.hour)
468
469
470 def Builtin_MINUTES(e, ctx):
471 d = datetime(e.arg)
472 return Literal(d.minute)
473
474
475 def Builtin_SECONDS(e, ctx):
476 """
477 http://www.w3.org/TR/sparql11-query/#func-seconds
478 """
479 d = datetime(e.arg)
480 return Literal(d.second, datatype=XSD.decimal)
481
482
483 def Builtin_TIMEZONE(e, ctx):
484 """
485 http://www.w3.org/TR/sparql11-query/#func-timezone
486
487 :returns: the timezone part of arg as an xsd:dayTimeDuration.
488 :raises: an error if there is no timezone.
489 """
490 dt = datetime(e.arg)
491 if not dt.tzinfo:
492 raise SPARQLError('datatime has no timezone: %r' % dt)
493
494 delta = dt.tzinfo.utcoffset(ctx.now)
495
496 d = delta.days
497 s = delta.seconds
498 neg = ""
499
500 if d < 0:
501 s = -24 * 60 * 60 * d - s
502 d = 0
503 neg = "-"
504
505 h = s / (60 * 60)
506 m = (s - h * 60 * 60) / 60
507 s = s - h * 60 * 60 - m * 60
508
509 tzdelta = "%sP%sT%s%s%s" % (neg,
510 "%dD" % d if d else "",
511 "%dH" % h if h else "",
512 "%dM" % m if m else "",
513 "%dS" % s if not d and not h and not m else "")
514
515 return Literal(tzdelta, datatype=XSD.dayTimeDuration)
516
517
518 def Builtin_TZ(e, ctx):
519 d = datetime(e.arg)
520 if not d.tzinfo:
521 return Literal("")
522 n = d.tzinfo.tzname(d)
523 if n == "UTC":
524 n = "Z"
525 return Literal(n)
526
527
528 def Builtin_UCASE(e, ctx):
529 l = string(e.arg)
530
531 return Literal(l.upper(), datatype=l.datatype, lang=l.language)
532
533
534 def Builtin_LANG(e, ctx):
535
536 """
537 http://www.w3.org/TR/sparql11-query/#func-lang
538
539 Returns the language tag of ltrl, if it has one. It returns "" if ltrl has
540 no language tag. Note that the RDF data model does not include literals
541 with an empty language tag.
542 """
543
544 l = literal(e.arg)
545 return Literal(l.language or "")
546
547
548 def Builtin_DATATYPE(e, ctx):
549 l = e.arg
550 if not isinstance(l, Literal):
551 raise SPARQLError('Can only get datatype of literal: %r' % l)
552 if l.language:
553 return RDF_langString
554 if not l.datatype and not l.language:
555 return XSD.string
556 return l.datatype
557
558
559 def Builtin_sameTerm(e, ctx):
560 a = e.arg1
561 b = e.arg2
562 return Literal(a == b)
563
564
565 def Builtin_BOUND(e, ctx):
566 """
567 http://www.w3.org/TR/sparql11-query/#func-bound
568 """
569 n = e.get('arg', variables=True)
570
571 return Literal(not isinstance(n, Variable))
572
573
574 def Builtin_EXISTS(e, ctx):
575 # damn...
576 from rdflib.plugins.sparql.evaluate import evalPart
577
578 exists = e.name == 'Builtin_EXISTS'
579
580 ctx = ctx.ctx.thaw(ctx) # hmm
581 for x in evalPart(ctx, e.graph):
582 return Literal(exists)
583 return Literal(not exists)
584
585
586 def Function(e, ctx):
587 """
588 Custom functions (and casts!)
589 """
590
591 if e.iri in XSD_DTs:
592 # a cast
593
594 if not e.expr:
595 raise SPARQLError("Nothing given to cast.")
596 if len(e.expr) > 1:
597 raise SPARQLError("Cannot cast more than one thing!")
598
599 x = e.expr[0]
600
601 if e.iri == XSD.string:
602
603 if isinstance(x, (URIRef, Literal)):
604 return Literal(x, datatype=XSD.string)
605 else:
606 raise SPARQLError(
607 "Cannot cast term %r of type %r" % (x, type(x)))
608
609 if not isinstance(x, Literal):
610 raise SPARQLError(
611 "Can only cast Literals to non-string data-types")
612
613 if x.datatype and not x.datatype in XSD_DTs:
614 raise SPARQLError(
615 "Cannot cast literal with unknown datatype: %r" % x.datatype)
616
617 if e.iri == XSD.dateTime:
618 if x.datatype and x.datatype not in (XSD.dateTime, XSD.string):
619 raise SPARQLError(
620 "Cannot cast %r to XSD:dateTime" % x.datatype)
621 try:
622 return Literal(isodate.parse_datetime(x), datatype=e.iri)
623 except:
624 raise SPARQLError("Cannot interpret '%r' as datetime" % x)
625
626 if x.datatype == XSD.dateTime:
627 raise SPARQLError("Cannot cast XSD.dateTime to %r" % e.iri)
628
629 if e.iri in (XSD.float, XSD.double):
630 try:
631 return Literal(float(x), datatype=e.iri)
632 except:
633 raise SPARQLError("Cannot interpret '%r' as float" % x)
634
635 elif e.iri == XSD.decimal:
636 if "e" in x or "E" in x: # SPARQL/XSD does not allow exponents in decimals
637 raise SPARQLError("Cannot interpret '%r' as decimal" % x)
638 try:
639 return Literal(Decimal(x), datatype=e.iri)
640 except:
641 raise SPARQLError("Cannot interpret '%r' as decimal" % x)
642
643 elif e.iri == XSD.integer:
644 try:
645 return Literal(int(x), datatype=XSD.integer)
646 except:
647 raise SPARQLError("Cannot interpret '%r' as int" % x)
648
649 elif e.iri == XSD.boolean:
650 # # I would argue that any number is True...
651 # try:
652 # return Literal(bool(int(x)), datatype=XSD.boolean)
653 # except:
654 if x.lower() in ("1", "true"):
655 return Literal(True)
656 if x.lower() in ("0", "false"):
657 return Literal(False)
658
659 raise SPARQLError("Cannot interpret '%r' as bool" % x)
660 else:
661 raise Exception("I do not know how to cast to %r" % e.iri)
662
663 else:
664 raise SPARQLError('Unknown function %r"%e.iri')
665
666 # TODO: Custom functions!
667
668
669 def UnaryNot(expr, ctx):
670 return Literal(not EBV(expr.expr))
671
672
673 def UnaryMinus(expr, ctx):
674 return Literal(-numeric(expr.expr))
675
676
677 def UnaryPlus(expr, ctx):
678 return Literal(+numeric(expr.expr))
679
680
681 def MultiplicativeExpression(e, ctx):
682
683 expr = e.expr
684 other = e.other
685
686 # because of the way the mul-expr production handled operator precedence
687 # we sometimes have nothing to do
688 if other is None:
689 return expr
690 try:
691 res = Decimal(numeric(expr))
692 for op, f in zip(e.op, other):
693 f = numeric(f)
694
695 if type(f) == float:
696 res = float(res)
697
698 if op == '*':
699 res *= f
700 else:
701 res /= f
702 except (InvalidOperation, ZeroDivisionError):
703 raise SPARQLError('divide by 0')
704
705 return Literal(res)
706
707
708 def AdditiveExpression(e, ctx):
709
710 expr = e.expr
711 other = e.other
712
713 # because of the way the add-expr production handled operator precedence
714 # we sometimes have nothing to do
715 if other is None:
716 return expr
717
718 res = numeric(expr)
719
720 dt = expr.datatype
721
722 for op, term in zip(e.op, other):
723 n = numeric(term)
724 if isinstance(n, Decimal) and isinstance(res, float):
725 n = float(n)
726 if isinstance(n, float) and isinstance(res, Decimal):
727 res = float(res)
728
729 dt = type_promotion(dt, term.datatype)
730
731 if op == '+':
732 res += n
733 else:
734 res -= n
735
736 return Literal(res, datatype=dt)
737
738
739 def RelationalExpression(e, ctx):
740
741 expr = e.expr
742 other = e.other
743 op = e.op
744
745 # because of the way the add-expr production handled operator precedence
746 # we sometimes have nothing to do
747 if other is None:
748 return expr
749
750 ops = dict([('>', lambda x, y: x.__gt__(y)),
751 ('<', lambda x, y: x.__lt__(y)),
752 ('=', lambda x, y: x.eq(y)),
753 ('!=', lambda x, y: x.neq(y)),
754 ('>=', lambda x, y: x.__ge__(y)),
755 ('<=', lambda x, y: x.__le__(y)),
756 ('IN', pyop.contains),
757 ('NOT IN', lambda x, y: not pyop.contains(x, y))])
758
759 if op in ('IN', 'NOT IN'):
760
761 res = (op == 'NOT IN')
762
763 error = False
764
765 if other == RDF.nil:
766 other = []
767
768 for x in other:
769 try:
770 if x == expr:
771 return Literal(True ^ res)
772 except SPARQLError as e:
773 error = e
774 if not error:
775 return Literal(False ^ res)
776 else:
777 raise error
778
779 if not op in ('=', '!=', 'IN', 'NOT IN'):
780 if not isinstance(expr, Literal):
781 raise SPARQLError(
782 "Compare other than =, != of non-literals is an error: %r" %
783 expr)
784 if not isinstance(other, Literal):
785 raise SPARQLError(
786 "Compare other than =, != of non-literals is an error: %r" %
787 other)
788 else:
789 if not isinstance(expr, Node):
790 raise SPARQLError('I cannot compare this non-node: %r' % expr)
791 if not isinstance(other, Node):
792 raise SPARQLError('I cannot compare this non-node: %r' % other)
793
794 if isinstance(expr, Literal) and isinstance(other, Literal):
795
796 if expr.datatype != None and expr.datatype not in XSD_DTs and other.datatype != None and other.datatype not in XSD_DTs:
797 # in SPARQL for non-XSD DT Literals we can only do =,!=
798 if op not in ('=', '!='):
799 raise SPARQLError(
800 'Can only do =,!= comparisons of non-XSD Literals')
801
802 try:
803 r = ops[op](expr, other)
804 if r == NotImplemented:
805 raise SPARQLError('Error when comparing')
806 except TypeError as te:
807 raise SPARQLError(*te.args)
808 return Literal(r)
809
810
811 def ConditionalAndExpression(e, ctx):
812
813 # TODO: handle returned errors
814
815 expr = e.expr
816 other = e.other
817
818 # because of the way the add-expr production handled operator precedence
819 # we sometimes have nothing to do
820 if other is None:
821 return expr
822
823 return Literal(all(EBV(x) for x in [expr] + other))
824
825
826 def ConditionalOrExpression(e, ctx):
827
828 # TODO: handle errors
829
830 expr = e.expr
831 other = e.other
832
833 # because of the way the add-expr production handled operator precedence
834 # we sometimes have nothing to do
835 if other is None:
836 return expr
837 # A logical-or that encounters an error on only one branch
838 # will return TRUE if the other branch is TRUE and an error
839 # if the other branch is FALSE.
840 error = None
841 for x in [expr] + other:
842 try:
843 if EBV(x):
844 return Literal(True)
845 except SPARQLError as e:
846 error = e
847 if error:
848 raise error
849 return Literal(False)
850
851
852 def not_(arg):
853 return Expr('UnaryNot', UnaryNot, expr=arg)
854
855
856 def and_(*args):
857 if len(args) == 1:
858 return args[0]
859
860 return Expr('ConditionalAndExpression', ConditionalAndExpression,
861 expr=args[0], other=list(args[1:]))
862
863 TrueFilter = Expr('TrueFilter', lambda _1, _2: Literal(True))
864
865
866 def simplify(expr):
867 if isinstance(expr, ParseResults) and len(expr) == 1:
868 return simplify(expr[0])
869
870 if isinstance(expr, (list, ParseResults)):
871 return list(map(simplify, expr))
872 if not isinstance(expr, CompValue):
873 return expr
874 if expr.name.endswith('Expression'):
875 if expr.other is None:
876 return simplify(expr.expr)
877
878 for k in list(expr.keys()):
879 expr[k] = simplify(expr[k])
880 # expr['expr']=simplify(expr.expr)
881 # expr['other']=simplify(expr.other)
882
883 return expr
884
885
886 def literal(s):
887 if not isinstance(s, Literal):
888 raise SPARQLError("Non-literal passed as string: %r" % s)
889 return s
890
891
892 def datetime(e):
893 if not isinstance(e, Literal):
894 raise SPARQLError("Non-literal passed as datetime: %r" % e)
895 if not e.datatype == XSD.dateTime:
896 raise SPARQLError(
897 "Literal with wrong datatype passed as datetime: %r" % e)
898 return e.toPython()
899
900
901 def string(s):
902 """
903 Make sure the passed thing is a string literal
904 i.e. plain literal, xsd:string literal or lang-tagged literal
905 """
906 if not isinstance(s, Literal):
907 raise SPARQLError("Non-literal passes as string: %r" % s)
908 if s.datatype and s.datatype != XSD.string:
909 raise SPARQLError(
910 "Non-string datatype-literal passes as string: %r" % s)
911 return s
912
913
914 def numeric(expr):
915 """
916 return a number from a literal
917 http://www.w3.org/TR/xpath20/#promotion
918
919 or TypeError
920 """
921
922 if not isinstance(expr, Literal):
923 raise SPARQLTypeError("%r is not a literal!" % expr)
924
925 if expr.datatype not in (XSD.float, XSD.double,
926 XSD.decimal, XSD.integer,
927 XSD.nonPositiveInteger, XSD.negativeInteger,
928 XSD.nonNegativeInteger, XSD.positiveInteger,
929 XSD.unsignedLong, XSD.unsignedInt,
930 XSD.unsignedShort, XSD.unsignedByte,
931 XSD.long, XSD.int, XSD.short, XSD.byte):
932 raise SPARQLTypeError("%r does not have a numeric datatype!" % expr)
933
934 return expr.toPython()
935
936
937 def EBV(rt):
938 """
939 * If the argument is a typed literal with a datatype of xsd:boolean,
940 the EBV is the value of that argument.
941 * If the argument is a plain literal or a typed literal with a
942 datatype of xsd:string, the EBV is false if the operand value
943 has zero length; otherwise the EBV is true.
944 * If the argument is a numeric type or a typed literal with a datatype
945 derived from a numeric type, the EBV is false if the operand value is
946 NaN or is numerically equal to zero; otherwise the EBV is true.
947 * All other arguments, including unbound arguments, produce a type error.
948
949 """
950
951 if isinstance(rt, Literal):
952
953 if rt.datatype == XSD.boolean:
954 return rt.toPython()
955
956 elif rt.datatype == XSD.string or rt.datatype is None:
957 return len(rt) > 0
958
959 else:
960 pyRT = rt.toPython()
961
962 if isinstance(pyRT, Literal):
963 # Type error, see: http://www.w3.org/TR/rdf-sparql-query/#ebv
964 raise SPARQLTypeError(
965 "http://www.w3.org/TR/rdf-sparql-query/#ebv - ' + \
966 'Could not determine the EBV for : %r" % rt)
967 else:
968 return bool(pyRT)
969
970 else:
971 raise SPARQLTypeError(
972 "http://www.w3.org/TR/rdf-sparql-query/#ebv - ' + \
973 'Only literals have Boolean values! %r" % rt)
974
975
976 def _lang_range_check(range, lang):
977 """
978 Implementation of the extended filtering algorithm, as defined in point
979 3.3.2, of U{RFC 4647<http://www.rfc-editor.org/rfc/rfc4647.txt>}, on
980 matching language ranges and language tags.
981 Needed to handle the C{rdf:PlainLiteral} datatype.
982 @param range: language range
983 @param lang: language tag
984 @rtype: boolean
985
986 @author: U{Ivan Herman<a href="http://www.w3.org/People/Ivan/">}
987
988 Taken from `RDFClosure/RestrictedDatatype.py`__
989
990 .. __:http://dev.w3.org/2004/PythonLib-IH/RDFClosure/RestrictedDatatype.py
991
992 """
993 def _match(r, l):
994 """
995 Matching of a range and language item: either range is a wildcard
996 or the two are equal
997 @param r: language range item
998 @param l: language tag item
999 @rtype: boolean
1000 """
1001 return r == '*' or r == l
1002
1003 rangeList = range.strip().lower().split('-')
1004 langList = lang.strip().lower().split('-')
1005 if not _match(rangeList[0], langList[0]):
1006 return False
1007 if len(rangeList) > len(langList):
1008 return False
1009
1010 return all(_match(*x) for x in zip(rangeList, langList))