linked-data-python 0.6.4__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 +48 -0
- {linked_data_python-0.6.4.dist-info → linked_data_python-0.6.5.dist-info}/METADATA +1 -1
- {linked_data_python-0.6.4.dist-info → linked_data_python-0.6.5.dist-info}/RECORD +9 -9
- {linked_data_python-0.6.4.dist-info → linked_data_python-0.6.5.dist-info}/WHEEL +0 -0
- {linked_data_python-0.6.4.dist-info → linked_data_python-0.6.5.dist-info}/entry_points.txt +0 -0
- {linked_data_python-0.6.4.dist-info → linked_data_python-0.6.5.dist-info}/licenses/LICENSE.md +0 -0
- {linked_data_python-0.6.4.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
|
|
|
@@ -1441,6 +1457,7 @@ class Transpiler:
|
|
|
1441
1457
|
if scope_mode:
|
|
1442
1458
|
names = var if not as_name else "%s, %s" % (var, as_name)
|
|
1443
1459
|
gen = "%s %s; %s" % (scope_mode, names, gen)
|
|
1460
|
+
gen = self._bind_on_current_graph(gen, prefix)
|
|
1444
1461
|
self._end_island("prefix", mark, gen)
|
|
1445
1462
|
return True
|
|
1446
1463
|
|
|
@@ -1980,10 +1997,36 @@ class Transpiler:
|
|
|
1980
1997
|
if not m:
|
|
1981
1998
|
self._error("nom de variable attendu après '%s'" % sigil)
|
|
1982
1999
|
name = self._take(len(m.group(0)))
|
|
2000
|
+
self._refuse_suffix_on_variable(sigil, name)
|
|
1983
2001
|
if self._match_vars is not None and name not in self._match_vars:
|
|
1984
2002
|
self._match_vars.append(name)
|
|
1985
2003
|
return "%s.Variable(%r)" % (RUNTIME_ALIAS, name)
|
|
1986
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
|
+
|
|
1987
2030
|
def _g_node(self, triples, gctx):
|
|
1988
2031
|
"""Records the term as a `part` of the island, then parses it.
|
|
1989
2032
|
|
|
@@ -2335,6 +2378,11 @@ class Transpiler:
|
|
|
2335
2378
|
"STRBEFORE", "STRAFTER", "REPLACE", "REGEX", "ABS", "ROUND", "CEIL",
|
|
2336
2379
|
"FLOOR", "SAMETERM", "ISIRI", "ISURI", "ISBLANK", "ISLITERAL",
|
|
2337
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",
|
|
2338
2386
|
))
|
|
2339
2387
|
|
|
2340
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.4.dist-info → linked_data_python-0.6.5.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|