linked-data-python 0.6.3__py3-none-any.whl → 0.6.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ldpy/runtime.py +42 -3
- ldpy/sparql.py +41 -0
- ldpy/transpiler/core.py +64 -1
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/METADATA +1 -1
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/RECORD +9 -9
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/WHEEL +0 -0
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/entry_points.txt +0 -0
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/licenses/LICENSE.md +0 -0
- {linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/top_level.txt +0 -0
ldpy/runtime.py
CHANGED
|
@@ -602,7 +602,21 @@ class Bindings(dict):
|
|
|
602
602
|
def as_bindings_iter(iterable):
|
|
603
603
|
"""'for @bindings in ...' (record ldpy/017): every element becomes the
|
|
604
604
|
current bindings of the body. An m{ ... } yields its solutions (anonymous
|
|
605
|
-
variables excluded); any other iterable must produce mappings
|
|
605
|
+
variables excluded); any other iterable must produce mappings or
|
|
606
|
+
namedtuple-like rows.
|
|
607
|
+
|
|
608
|
+
Two duck-typed shapes are accepted for a row, and both are needed because
|
|
609
|
+
CPython and MicroPython expose different halves of the namedtuple API:
|
|
610
|
+
|
|
611
|
+
- `_fields`, a sequence of names in value order — CPython's
|
|
612
|
+
`collections.namedtuple`, a `pandas.DataFrame.itertuples()` row, and
|
|
613
|
+
ldpy's own Row from `m{ }` (record ldpy/016);
|
|
614
|
+
- `_asdict()`, when `_fields` is absent — this is the ONLY one
|
|
615
|
+
MicroPython's `collections.namedtuple` exposes, and only when the
|
|
616
|
+
firmware was built with `MICROPY_PY_COLLECTIONS_NAMEDTUPLE__ASDICT`.
|
|
617
|
+
Keying off `_fields` alone would have left `for @bindings` broken on
|
|
618
|
+
device, in a file record ldpy/026 requires to emit the same code on
|
|
619
|
+
both backends."""
|
|
606
620
|
if isinstance(iterable, Match):
|
|
607
621
|
for sm in iterable.solutions():
|
|
608
622
|
b = Bindings()
|
|
@@ -617,10 +631,17 @@ def as_bindings_iter(iterable):
|
|
|
617
631
|
yield item
|
|
618
632
|
elif hasattr(item, "items"):
|
|
619
633
|
yield Bindings(item)
|
|
634
|
+
elif hasattr(item, "_fields"):
|
|
635
|
+
b = Bindings()
|
|
636
|
+
b.update(zip(item._fields, item))
|
|
637
|
+
yield b
|
|
638
|
+
elif hasattr(item, "_asdict"):
|
|
639
|
+
# MicroPython's namedtuple: no _fields, _asdict() instead.
|
|
640
|
+
yield Bindings(item._asdict())
|
|
620
641
|
else:
|
|
621
642
|
raise TypeError(
|
|
622
|
-
"for @bindings in ...: the iterable must produce mappings
|
|
623
|
-
"got %s" % type(item).__name__)
|
|
643
|
+
"for @bindings in ...: the iterable must produce mappings "
|
|
644
|
+
"or namedtuple-like rows, got %s" % type(item).__name__)
|
|
624
645
|
|
|
625
646
|
|
|
626
647
|
_EXPR_CLASS = None
|
|
@@ -732,6 +753,24 @@ def designate(namespaces, graph):
|
|
|
732
753
|
return graph
|
|
733
754
|
|
|
734
755
|
|
|
756
|
+
def bind_prefix(graph, prefix, ns):
|
|
757
|
+
"""'@prefix' declared while a graph is current — bind it there too.
|
|
758
|
+
|
|
759
|
+
:func:`designate` binds the prefixes in scope at the moment of
|
|
760
|
+
designation. A prefix declared AFTER, while that same graph is still the
|
|
761
|
+
current one, is in scope for it just as much: binding it here is what
|
|
762
|
+
makes the two orders serialise alike, instead of making the position of a
|
|
763
|
+
declaration a trap (record ldpy/027).
|
|
764
|
+
|
|
765
|
+
Same tolerance as :func:`designate`: anything that is not a graph, or a
|
|
766
|
+
backend without a namespace manager, passes through untouched.
|
|
767
|
+
"""
|
|
768
|
+
try:
|
|
769
|
+
_backend.bind_namespaces(graph, {prefix: ns})
|
|
770
|
+
except (AttributeError, TypeError):
|
|
771
|
+
pass # not a graph, or no binding support
|
|
772
|
+
|
|
773
|
+
|
|
735
774
|
def add_to(graph, *triples, bindings=None):
|
|
736
775
|
"""'+{ ... }': instantiate and add to the current graph (record ldpy/014).
|
|
737
776
|
A triple with a term still unbound is dropped — one cannot write an
|
ldpy/sparql.py
CHANGED
|
@@ -360,6 +360,47 @@ def DATATYPE(t):
|
|
|
360
360
|
return t.datatype or XSD.string
|
|
361
361
|
|
|
362
362
|
|
|
363
|
+
def STRLANG(t, lang):
|
|
364
|
+
"""STRLANG(lexical form, language tag).
|
|
365
|
+
|
|
366
|
+
The way to give a bound variable a language tag: `?v@en` is refused —
|
|
367
|
+
a variable is already bound to a COMPLETE term, so there is nothing to
|
|
368
|
+
interpret (record ldpy/027) — whereas STRLANG says explicitly to take
|
|
369
|
+
the lexical form and read it as a tagged literal.
|
|
370
|
+
|
|
371
|
+
SPARQL 1.1 wants a plain literal with no tag and no datatype, and gives
|
|
372
|
+
no result otherwise; here that is an error, which is what the rest of
|
|
373
|
+
this module does with an argument of the wrong shape.
|
|
374
|
+
"""
|
|
375
|
+
if not isinstance(t, Literal):
|
|
376
|
+
raise SparqlError("STRLANG wants a literal as its first argument")
|
|
377
|
+
if t.language or (t.datatype and t.datatype != XSD.string):
|
|
378
|
+
raise SparqlError(
|
|
379
|
+
"STRLANG wants a plain literal: %r already carries a %s"
|
|
380
|
+
% (str(t), "language tag" if t.language else "datatype"))
|
|
381
|
+
tag = str(lang)
|
|
382
|
+
if not tag:
|
|
383
|
+
raise SparqlError("STRLANG wants a non-empty language tag")
|
|
384
|
+
return Literal(str(t), lang=tag)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def STRDT(t, dt):
|
|
388
|
+
"""STRDT(lexical form, datatype IRI).
|
|
389
|
+
|
|
390
|
+
The counterpart of :func:`STRLANG` for `?v^^dt`, refused for the same
|
|
391
|
+
reason (record ldpy/027).
|
|
392
|
+
"""
|
|
393
|
+
if not isinstance(t, Literal):
|
|
394
|
+
raise SparqlError("STRDT wants a literal as its first argument")
|
|
395
|
+
if t.language or (t.datatype and t.datatype != XSD.string):
|
|
396
|
+
raise SparqlError(
|
|
397
|
+
"STRDT wants a plain literal: %r already carries a %s"
|
|
398
|
+
% (str(t), "language tag" if t.language else "datatype"))
|
|
399
|
+
if not isinstance(dt, URIRef):
|
|
400
|
+
raise SparqlError("STRDT wants an IRI as its datatype")
|
|
401
|
+
return Literal(str(t), datatype=dt)
|
|
402
|
+
|
|
403
|
+
|
|
363
404
|
def IRI(t, base=None):
|
|
364
405
|
"""IRI(str) — resolved against the lexical base of the call site."""
|
|
365
406
|
s = str(t)
|
ldpy/transpiler/core.py
CHANGED
|
@@ -1356,9 +1356,25 @@ class Transpiler:
|
|
|
1356
1356
|
prefix, as_name, RUNTIME_ALIAS, resolved)
|
|
1357
1357
|
if scope_mode:
|
|
1358
1358
|
gen = "%s %s; %s" % (scope_mode, as_name, gen)
|
|
1359
|
+
if kind == "prefix":
|
|
1360
|
+
gen = self._bind_on_current_graph(gen, prefix)
|
|
1359
1361
|
self._end_island(kind, mark, gen)
|
|
1360
1362
|
return True
|
|
1361
1363
|
|
|
1364
|
+
def _bind_on_current_graph(self, gen, prefix):
|
|
1365
|
+
"""Lie aussi le préfixe sur le graphe courant, s'il y en a un.
|
|
1366
|
+
|
|
1367
|
+
`@graph` lie les préfixes en portée au moment de la désignation. Un
|
|
1368
|
+
préfixe déclaré APRÈS, tant que ce graphe reste courant, est en
|
|
1369
|
+
portée pour lui tout autant : le lier ici est ce qui fait que les
|
|
1370
|
+
deux ordres d'écriture sérialisent pareil, au lieu de faire de la
|
|
1371
|
+
position d'une déclaration un piège (fiche 027).
|
|
1372
|
+
"""
|
|
1373
|
+
if not self._graph_var:
|
|
1374
|
+
return gen
|
|
1375
|
+
return gen + "; %s.bind_prefix(%s, %r, __namespaces__[%r])" % (
|
|
1376
|
+
RUNTIME_ALIAS, self._graph_var, prefix, prefix)
|
|
1377
|
+
|
|
1362
1378
|
def _prefix_as_clause(self, k):
|
|
1363
1379
|
"""`as NAME` before a @prefix declaration's closing '.', or nothing.
|
|
1364
1380
|
|
|
@@ -1392,6 +1408,10 @@ class Transpiler:
|
|
|
1392
1408
|
self._take(j - self.i) # '@prefix p:' + blancs
|
|
1393
1409
|
parts = self._take_firi_parts()
|
|
1394
1410
|
self._g_ws()
|
|
1411
|
+
as_name, k = self._prefix_as_clause(self.i)
|
|
1412
|
+
if as_name:
|
|
1413
|
+
self._take(k - self.i)
|
|
1414
|
+
self._g_ws()
|
|
1395
1415
|
if self._peek() != ".":
|
|
1396
1416
|
self._error("'.' attendu pour clore la déclaration @prefix")
|
|
1397
1417
|
self._take(1)
|
|
@@ -1411,6 +1431,11 @@ class Transpiler:
|
|
|
1411
1431
|
scope_mode)
|
|
1412
1432
|
gen = "__namespaces__[%r] = %s.Namespace(%r)" % (
|
|
1413
1433
|
prefix, RUNTIME_ALIAS, resolved)
|
|
1434
|
+
if as_name:
|
|
1435
|
+
gen = "__namespaces__[%r] = %s = %s.Namespace(%r)" % (
|
|
1436
|
+
prefix, as_name, RUNTIME_ALIAS, resolved)
|
|
1437
|
+
if scope_mode:
|
|
1438
|
+
gen = "%s %s; %s" % (scope_mode, as_name, gen)
|
|
1414
1439
|
else:
|
|
1415
1440
|
# global/nonlocal : réutiliser la variable de la liaison cible si
|
|
1416
1441
|
# elle est dynamique — c'est elle que les usages du dehors lisent
|
|
@@ -1424,8 +1449,15 @@ class Transpiler:
|
|
|
1424
1449
|
gen = "%s = %s.Namespace(%s.firi(%s)); __namespaces__[%r] = %s" % (
|
|
1425
1450
|
var, RUNTIME_ALIAS, RUNTIME_ALIAS,
|
|
1426
1451
|
self._firi_args(parts), prefix, var)
|
|
1452
|
+
if as_name:
|
|
1453
|
+
# `as EX` on a DYNAMIC prefix binds the Namespace built from
|
|
1454
|
+
# the IRI resolved at that point — the same object the
|
|
1455
|
+
# prefix itself uses, so the two can never disagree.
|
|
1456
|
+
gen += "; %s = %s" % (as_name, var)
|
|
1427
1457
|
if scope_mode:
|
|
1428
|
-
|
|
1458
|
+
names = var if not as_name else "%s, %s" % (var, as_name)
|
|
1459
|
+
gen = "%s %s; %s" % (scope_mode, names, gen)
|
|
1460
|
+
gen = self._bind_on_current_graph(gen, prefix)
|
|
1429
1461
|
self._end_island("prefix", mark, gen)
|
|
1430
1462
|
return True
|
|
1431
1463
|
|
|
@@ -1965,10 +1997,36 @@ class Transpiler:
|
|
|
1965
1997
|
if not m:
|
|
1966
1998
|
self._error("nom de variable attendu après '%s'" % sigil)
|
|
1967
1999
|
name = self._take(len(m.group(0)))
|
|
2000
|
+
self._refuse_suffix_on_variable(sigil, name)
|
|
1968
2001
|
if self._match_vars is not None and name not in self._match_vars:
|
|
1969
2002
|
self._match_vars.append(name)
|
|
1970
2003
|
return "%s.Variable(%r)" % (RUNTIME_ALIAS, name)
|
|
1971
2004
|
|
|
2005
|
+
def _refuse_suffix_on_variable(self, sigil, name):
|
|
2006
|
+
"""`?v@en` and `?v^^xsd:int` are refused, and say why.
|
|
2007
|
+
|
|
2008
|
+
Sticking an RDF suffix on an *interpolation* is meaningful — the
|
|
2009
|
+
Python value is the lexical form, and the suffix says how to read
|
|
2010
|
+
it. Sticking one on a variable is not: a variable is already bound
|
|
2011
|
+
to a complete term, and there is nothing left to interpret. Record
|
|
2012
|
+
027 closes the question — the language refuses rather than coerces
|
|
2013
|
+
— so the refusal has to name itself; before this, the parser only
|
|
2014
|
+
complained that the island's closing brace was missing."""
|
|
2015
|
+
c = self._peek()
|
|
2016
|
+
m = _LANGTAG_RE.match(self.text, self.i)
|
|
2017
|
+
if c == "@" and m:
|
|
2018
|
+
what, written, advice = "de langue", m.group(0), "@en"
|
|
2019
|
+
elif c == "^" and self._peek(1) == "^":
|
|
2020
|
+
what, written, advice = "de type", "^^...", "^^xsd:string"
|
|
2021
|
+
else:
|
|
2022
|
+
return
|
|
2023
|
+
self._error(
|
|
2024
|
+
"suffixe %s interdit sur une variable : '%s%s%s' — une variable "
|
|
2025
|
+
"est déjà liée à un terme complet, il n'y a rien à interpréter. "
|
|
2026
|
+
"Pour construire un littéral, coller le suffixe à une "
|
|
2027
|
+
"interpolation : '{expr}%s' (fiche 027)"
|
|
2028
|
+
% (what, sigil, name, written, advice))
|
|
2029
|
+
|
|
1972
2030
|
def _g_node(self, triples, gctx):
|
|
1973
2031
|
"""Records the term as a `part` of the island, then parses it.
|
|
1974
2032
|
|
|
@@ -2320,6 +2378,11 @@ class Transpiler:
|
|
|
2320
2378
|
"STRBEFORE", "STRAFTER", "REPLACE", "REGEX", "ABS", "ROUND", "CEIL",
|
|
2321
2379
|
"FLOOR", "SAMETERM", "ISIRI", "ISURI", "ISBLANK", "ISLITERAL",
|
|
2322
2380
|
"ISNUMERIC", "LANGMATCHES", "ENCODE_FOR_IRI",
|
|
2381
|
+
# STRLANG / STRDT : la façon de dire explicitement ce que `?v@en` et
|
|
2382
|
+
# `?v^^dt` ne disent pas — une variable est liée à un terme complet,
|
|
2383
|
+
# le suffixe est donc refusé (fiche 027) et ces deux-ci sont le
|
|
2384
|
+
# chemin propre, en SPARQL standard.
|
|
2385
|
+
"STRLANG", "STRDT",
|
|
2323
2386
|
))
|
|
2324
2387
|
|
|
2325
2388
|
def _take_enode(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linked-data-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.5
|
|
4
4
|
Summary: Python extended with Semantic Web primitives: IRIs, RDF literals and Turtle-notation graphs as expressions, transpiled by island parsing.
|
|
5
5
|
Author-email: Maxime Lefrançois <maxime.lefrancois@emse.fr>
|
|
6
6
|
License: MIT
|
|
@@ -7,8 +7,8 @@ ldpy/debug.py,sha256=JUuzeKc8ya4SG30AxaUVeihTEbzySo1cS0sU0s78Mv0,10493
|
|
|
7
7
|
ldpy/formatter.py,sha256=VaDPECxhivsMe8jnX_fOL7BUyLEu5r4xREdr4Hav-0c,12695
|
|
8
8
|
ldpy/importer.py,sha256=QXAhSujPN6rFMJSQuj0UsWyI4CajirKt1SOrykJ_fUw,3670
|
|
9
9
|
ldpy/pygments_lexer.py,sha256=fmqYytdnovqfXemuKE5lg4XG1iub-hui9otXERBWELw,26217
|
|
10
|
-
ldpy/runtime.py,sha256=
|
|
11
|
-
ldpy/sparql.py,sha256=
|
|
10
|
+
ldpy/runtime.py,sha256=6ZUkj33xvqvmNd0D3-a8py9DA58EKi88iByryZQ00G0,42586
|
|
11
|
+
ldpy/sparql.py,sha256=dIG72ieecoP_pm6m0SYR76HNXWgTK0AjMDcU7DovH0Y,16549
|
|
12
12
|
ldpy/lsp/__init__.py,sha256=rK5GYOITi9PN09-WVlJ2aPKodW8dWTpgI_X6dFbP1zA,542
|
|
13
13
|
ldpy/lsp/__main__.py,sha256=MIp4ktqaoWZCNIMfv14bSC9pqK86JBS5XVjd1Z3c24o,72
|
|
14
14
|
ldpy/lsp/backend.py,sha256=8DnSGaBk1dsIMOBo7D1WQxxF3MZjJbYd78jp4ucWORY,5375
|
|
@@ -18,12 +18,12 @@ ldpy/lsp/rpc.py,sha256=-TF_9U8dum23Pi4O1FZLogwoZgrGrt14J5BFB1OYVZw,3554
|
|
|
18
18
|
ldpy/lsp/server.py,sha256=PAMMookGUn00vAW_-a5BGy3qkVe9PoUdfzAzpdlvoF8,16359
|
|
19
19
|
ldpy/lsp/translate.py,sha256=HU9fBP_xWyYLih6QwQfSoyfF-MH-oInFcPX3o8Vc2GI,6116
|
|
20
20
|
ldpy/transpiler/__init__.py,sha256=9mQx0e47ixz0iMqSbCBbtGiwJ7PLxTcsVSIp6KNTMG4,504
|
|
21
|
-
ldpy/transpiler/core.py,sha256=
|
|
21
|
+
ldpy/transpiler/core.py,sha256=y2QfOLZCXjwLFb4uZNCWMPmHbBkTZ3MZXrkD3dnahP0,122190
|
|
22
22
|
ldpy/transpiler/errors.py,sha256=zEEwsNvC2Tawq8jIYls7hrbcWSvQtd7eo89k_SKp0k0,1142
|
|
23
23
|
ldpy/transpiler/linemap.py,sha256=ecLlCUkD4-6QQtUjGfAL28ql7LPITTS4fjLcDIbAwpQ,11386
|
|
24
|
-
linked_data_python-0.6.
|
|
25
|
-
linked_data_python-0.6.
|
|
26
|
-
linked_data_python-0.6.
|
|
27
|
-
linked_data_python-0.6.
|
|
28
|
-
linked_data_python-0.6.
|
|
29
|
-
linked_data_python-0.6.
|
|
24
|
+
linked_data_python-0.6.5.dist-info/licenses/LICENSE.md,sha256=R6KjQ098eAFd2k5mKaSRJqMH1LhY4o7xkHrKT5vjRfs,1074
|
|
25
|
+
linked_data_python-0.6.5.dist-info/METADATA,sha256=RM5C2uEatJaty4CIMyEVgPpS7e3q_Zt9iQoSDOAYH90,7974
|
|
26
|
+
linked_data_python-0.6.5.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
27
|
+
linked_data_python-0.6.5.dist-info/entry_points.txt,sha256=n8Vs52oH81BrKOe1DNUvdFLSOlEufRMpK2waPFa6aYk,224
|
|
28
|
+
linked_data_python-0.6.5.dist-info/top_level.txt,sha256=dkG_F4jYkh6CS6gdpQeV_gKW3yaJBvl1ukUu0zo2KA8,5
|
|
29
|
+
linked_data_python-0.6.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{linked_data_python-0.6.3.dist-info → linked_data_python-0.6.5.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|