linked-data-python 0.6.0__tar.gz → 0.6.2__tar.gz
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.
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/PKG-INFO +1 -1
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/islanddoc.py +10 -6
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/transpiler/core.py +48 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/PKG-INFO +1 -1
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/SOURCES.txt +1 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/pyproject.toml +1 -1
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_docs.py +21 -1
- linked_data_python-0.6.2/tests/test_lexing.py +53 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_sparql_island.py +48 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/LICENSE.md +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/README.md +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/__init__.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/__main__.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/backend.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/build.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/console.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/debug.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/formatter.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/importer.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/__init__.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/__main__.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/backend.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/hover.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/rpc.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/server.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/lsp/translate.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/pygments_lexer.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/runtime.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/sparql.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/transpiler/__init__.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/transpiler/errors.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/ldpy/transpiler/linemap.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/dependency_links.txt +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/entry_points.txt +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/requires.txt +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/top_level.txt +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/setup.cfg +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_bench.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_bindings.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_build.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_call_suffix.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_charsets.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_coercion.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_console.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_current_graph.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_debug.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_debug_stepping.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_disambiguation.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_docstrings.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_examples.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_formatter.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_generator.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_graphs.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_hover_parts.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_identity.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_import_hook.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_islanddoc.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_islands_terms.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_linemap.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_lsp_rpc.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_lsp_server.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_lsp_translate.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_match_island.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_micropython_subset.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_prefix_import.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_prefix_scoping.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_pygments_lexer.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_scope_modifiers.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_semantics.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_sourcemap_v3.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_sparql_expr.py +0 -0
- {linked_data_python-0.6.0 → linked_data_python-0.6.2}/tests/test_target_micropython.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linked-data-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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
|
|
@@ -134,7 +134,9 @@ ISLANDS = {
|
|
|
134
134
|
"A SPARQL query or update, parsed when the file is transpiled rather "
|
|
135
135
|
"than at run time. `{expr}` in term position becomes an initial "
|
|
136
136
|
"binding — never string pasting, so nothing here can be injected. "
|
|
137
|
-
"
|
|
137
|
+
"Calling it on a graph gives a LAZY query; `.execute()` is what "
|
|
138
|
+
"forces it — for an update, and for any query whose rdflib `Result` "
|
|
139
|
+
"you then call a method on.",
|
|
138
140
|
_QUERY, "s-a-sparql-query"),
|
|
139
141
|
|
|
140
142
|
# -- terms --------------------------------------------------------------
|
|
@@ -169,10 +171,10 @@ ISLANDS = {
|
|
|
169
171
|
|
|
170
172
|
"firi": IslandDoc(
|
|
171
173
|
"(term) f<...{expr}...> -> URIRef",
|
|
172
|
-
"A formatted IRI: the braces interpolate as in an f-string, the "
|
|
173
|
-
"result is
|
|
174
|
-
"
|
|
175
|
-
"
|
|
174
|
+
"A formatted IRI: the braces interpolate as in an f-string, and the "
|
|
175
|
+
"result is resolved against `@base` if it is relative. It does NOT "
|
|
176
|
+
"percent-encode — the shape of the IRI is yours. To mint one from "
|
|
177
|
+
"data that may hold a space or a slash, use `e<...>`, which encodes.",
|
|
176
178
|
_TERMS, "formatted-iris-f"),
|
|
177
179
|
|
|
178
180
|
"fnode": IslandDoc(
|
|
@@ -202,7 +204,9 @@ ISLANDS = {
|
|
|
202
204
|
"eiri": IslandDoc(
|
|
203
205
|
"(expression) e<...{?var}...> -> Expr",
|
|
204
206
|
"A deferred IRI: `f<...>`'s interpolation, except that the holes are "
|
|
205
|
-
"SPARQL expressions re-evaluated for each set of bindings
|
|
207
|
+
"SPARQL expressions re-evaluated for each set of bindings — and that "
|
|
208
|
+
"it percent-encodes what it interpolates. This is the form for "
|
|
209
|
+
"minting an IRI from a data column.",
|
|
206
210
|
_SPARQL_EXPR, "deferred-iris-e"),
|
|
207
211
|
}
|
|
208
212
|
|
|
@@ -592,6 +592,40 @@ class Transpiler:
|
|
|
592
592
|
# chaînes et littéraux RDF
|
|
593
593
|
# ------------------------------------------------------------------
|
|
594
594
|
|
|
595
|
+
# Island sigils that open with a brace or a chevron. A hole beginning
|
|
596
|
+
# with one of these is an island the scanner will never reach.
|
|
597
|
+
_HOLE_ISLANDS = ("_:{", "g{", "m{", "s{", "e{", "e<", "f{", "f<", "?{")
|
|
598
|
+
|
|
599
|
+
def _island_in_fstring_hole(self, tok_start, end):
|
|
600
|
+
"""The island opener written inside an f-string hole, or None.
|
|
601
|
+
|
|
602
|
+
The scanner does not descend into f-string interpolation holes: an
|
|
603
|
+
island written there would be copied verbatim into the generated
|
|
604
|
+
Python, which then fails with a message from CPython's f-string
|
|
605
|
+
parser that names nothing (record ldpy/012). Refusing it here, by
|
|
606
|
+
name, costs one scan of the token and turns a baffling failure into
|
|
607
|
+
an actionable one.
|
|
608
|
+
"""
|
|
609
|
+
tok = self.text[tok_start:end]
|
|
610
|
+
if "f" not in tok[:3].lower() or "{" not in tok:
|
|
611
|
+
return None
|
|
612
|
+
i, n = 0, len(tok)
|
|
613
|
+
while i < n:
|
|
614
|
+
if tok[i] != "{":
|
|
615
|
+
i += 1
|
|
616
|
+
continue
|
|
617
|
+
if tok[i + 1:i + 2] == "{": # '{{' is an escaped brace
|
|
618
|
+
i += 2
|
|
619
|
+
continue
|
|
620
|
+
j = i + 1
|
|
621
|
+
while j < n and tok[j] in " \t":
|
|
622
|
+
j += 1
|
|
623
|
+
for opener in self._HOLE_ISLANDS:
|
|
624
|
+
if tok.startswith(opener, j):
|
|
625
|
+
return opener
|
|
626
|
+
i += 1
|
|
627
|
+
return None
|
|
628
|
+
|
|
595
629
|
def _handle_string(self, start, prefix_start=None):
|
|
596
630
|
"""start : indice du guillemet. prefix_start : indice du préfixe de
|
|
597
631
|
chaîne (r/b/f/u) déjà repéré, sinon None."""
|
|
@@ -607,6 +641,12 @@ class Transpiler:
|
|
|
607
641
|
if suffix is None and t[end:end + 2] == "^^":
|
|
608
642
|
suffix = ("datatype", None, end + 2)
|
|
609
643
|
if suffix is None:
|
|
644
|
+
opener = self._island_in_fstring_hole(tok_start, end)
|
|
645
|
+
if opener is not None:
|
|
646
|
+
self._error(
|
|
647
|
+
"îlot '%s' dans un trou d'f-string : le scanner n'y "
|
|
648
|
+
"descend pas. Sortez la lecture dans une variable "
|
|
649
|
+
"au-dessus de l'f-string." % opener)
|
|
610
650
|
self._copy(end - self.i)
|
|
611
651
|
self.operand = False
|
|
612
652
|
self.stmt_start = False
|
|
@@ -2124,6 +2164,14 @@ class Transpiler:
|
|
|
2124
2164
|
elif c in "\"'":
|
|
2125
2165
|
end = self._string_end(self.i)
|
|
2126
2166
|
pieces.append(self._take(end - self.i))
|
|
2167
|
+
elif c == "<" and self._iriref_end(self.i) is not None:
|
|
2168
|
+
# A full IRI is a token, not punctuation: its '#' is part of
|
|
2169
|
+
# the IRI, not a comment. Without this the fragment of
|
|
2170
|
+
# <http://example.org/ns#X> — the most ordinary shape an IRI
|
|
2171
|
+
# takes in RDF — swallowed the rest of the line, closing
|
|
2172
|
+
# brace included. `<` that does NOT open an IRI is SPARQL's
|
|
2173
|
+
# less-than, and falls through to the single-character case.
|
|
2174
|
+
pieces.append(self._take(self._iriref_end(self.i) - self.i))
|
|
2127
2175
|
elif c == "#":
|
|
2128
2176
|
j = t.find("\n", self.i)
|
|
2129
2177
|
pieces.append(self._take((j if j != -1 else self.n) - self.i))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: linked-data-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
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
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "linked-data-python"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.2"
|
|
8
8
|
description = "Python extended with Semantic Web primitives: IRIs, RDF literals and Turtle-notation graphs as expressions, transpiled by island parsing."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -20,13 +20,21 @@ def blocks(lang):
|
|
|
20
20
|
for path in DOCS:
|
|
21
21
|
text = open(path, encoding="utf-8").read()
|
|
22
22
|
for i, m in enumerate(FENCE.finditer(text)):
|
|
23
|
-
if m.group(1) == lang:
|
|
23
|
+
if m.group(1) == lang and not _is_snippet(m.group(2)):
|
|
24
24
|
out.append(pytest.param(
|
|
25
25
|
m.group(2),
|
|
26
26
|
id="%s#%d" % (os.path.relpath(path, REPO), i)))
|
|
27
27
|
return out
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def _is_snippet(code):
|
|
31
|
+
"""A block that only includes a file (``--8<-- "..."``) has no code of its
|
|
32
|
+
own: mkdocs substitutes the file at build time, and that file is tested
|
|
33
|
+
where it lives — see ``test_the_tour_runs``."""
|
|
34
|
+
return all(line.strip().startswith("--8<--") or not line.strip()
|
|
35
|
+
for line in code.split("\n"))
|
|
36
|
+
|
|
37
|
+
|
|
30
38
|
def test_docs_exist_and_cover_diataxis():
|
|
31
39
|
rels = {os.path.relpath(p, os.path.join(REPO, "docs")) for p in DOCS}
|
|
32
40
|
assert "README.md" in rels
|
|
@@ -46,6 +54,18 @@ def test_python_snippets_run(code):
|
|
|
46
54
|
exec(compile(code, "<docs>", "exec"), {"__name__": "docs"})
|
|
47
55
|
|
|
48
56
|
|
|
57
|
+
def test_the_tour_runs():
|
|
58
|
+
"""``docs/tutorials/tour.ldpy`` is a tutorial in the shape of a program:
|
|
59
|
+
its comments teach, and each section asserts what it claims. Running it is
|
|
60
|
+
therefore the whole check — and the page that shows it includes this very
|
|
61
|
+
file, so the two cannot drift."""
|
|
62
|
+
from ldpy.transpiler import transpile
|
|
63
|
+
path = os.path.join(REPO, "docs", "tutorials", "tour.ldpy")
|
|
64
|
+
source = open(path, encoding="utf-8").read()
|
|
65
|
+
exec(compile(transpile(source, path).code, path, "exec"),
|
|
66
|
+
{"__name__": "tour"})
|
|
67
|
+
|
|
68
|
+
|
|
49
69
|
# --------------------------------------------------------------------------
|
|
50
70
|
# The same snippets, typed into the interactive console.
|
|
51
71
|
#
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Lexical guards on the boundary between Python and the islands.
|
|
2
|
+
|
|
3
|
+
What is pinned here is not what the transpiler produces but what it REFUSES,
|
|
4
|
+
and how: a construct the scanner cannot see must fail by name, not by leaving
|
|
5
|
+
CPython to complain about something else.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from ldpy.transpiler import transpile, LdpySyntaxError
|
|
11
|
+
|
|
12
|
+
# CPython then rejected with a message naming nothing. Found by the corpus
|
|
13
|
+
# study; refused by name since 0.5.1.
|
|
14
|
+
|
|
15
|
+
def test_an_island_in_an_fstring_hole_is_refused_by_name():
|
|
16
|
+
src = ('@prefix ex: <http://example.org/> .\n'
|
|
17
|
+
'@graph as g\n'
|
|
18
|
+
't = f"{m{ ?s ex:p ?o }.first()}"\n')
|
|
19
|
+
with pytest.raises(LdpySyntaxError) as e:
|
|
20
|
+
transpile(src, "t.ldpy")
|
|
21
|
+
assert "f-string" in e.value.msg and "m{" in e.value.msg
|
|
22
|
+
assert e.value.line == 2 # 0-based: the third line
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.parametrize("hole", ["g{ ex:a ex:b 1 }", "s{ SELECT ?s WHERE {} }",
|
|
26
|
+
"e{ ?a }", "f<a/{x}>", "_:{1}", "?{1}"])
|
|
27
|
+
def test_every_brace_island_is_caught_in_a_hole(hole):
|
|
28
|
+
src = ('@prefix ex: <http://example.org/> .\n'
|
|
29
|
+
'@graph as g\n'
|
|
30
|
+
't = f"{%s}"\n' % hole)
|
|
31
|
+
with pytest.raises(LdpySyntaxError):
|
|
32
|
+
transpile(src, "t.ldpy")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_an_ordinary_fstring_is_untouched():
|
|
36
|
+
"""The guard must not cost a plain f-string, nor an escaped brace, nor a
|
|
37
|
+
dict display inside a hole."""
|
|
38
|
+
src = ('xs = [1, 2]\n'
|
|
39
|
+
'a = f"{len(xs)} results"\n'
|
|
40
|
+
'b = f"{{literal braces}}"\n'
|
|
41
|
+
'c = f"{ {k: v for k, v in []} }"\n'
|
|
42
|
+
'd = f"{xs!r:>10}"\n')
|
|
43
|
+
code = transpile(src, "t.ldpy").code
|
|
44
|
+
assert 'f"{len(xs)} results"' in code
|
|
45
|
+
assert 'f"{{literal braces}}"' in code
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_an_island_outside_a_hole_still_works():
|
|
49
|
+
"""A comprehension over an island is fine — only the hole is blind."""
|
|
50
|
+
src = ('@prefix ex: <http://example.org/> .\n'
|
|
51
|
+
'@graph as g\n'
|
|
52
|
+
'xs = [s for s in m{ ?s ex:p ?o }]\n')
|
|
53
|
+
assert "_ldpy_.match(" in transpile(src, "t.ldpy").code
|
|
@@ -159,3 +159,51 @@ def test_update_par_execute_public(run):
|
|
|
159
159
|
g, _ = run(DATA + "s{ INSERT { ?s ex:seen 1 } WHERE { ?s a ex:Sensor } }"
|
|
160
160
|
".execute()\n")
|
|
161
161
|
assert len(g["g"]) > 2
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# --------------------------------------------------------------- record 012
|
|
165
|
+
# A '#' inside a full IRI was read as the start of a comment, so the rest of
|
|
166
|
+
# the line — closing brace included — was swallowed. The most ordinary shape
|
|
167
|
+
# an IRI takes in RDF, and only `s{ }` had the defect: `m{ }` and `g{ }`
|
|
168
|
+
# parse IRIs as terms and never saw it. Found by the corpus study.
|
|
169
|
+
|
|
170
|
+
def test_a_hash_inside_a_full_iri_is_not_a_comment():
|
|
171
|
+
src = ("@graph as g\n"
|
|
172
|
+
"q = s{ SELECT ?s WHERE { ?s <http://example.org/ns#X> ?o } }\n")
|
|
173
|
+
code = transpile(src, "t.ldpy").code
|
|
174
|
+
assert "http://example.org/ns#X" in code
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_the_same_iri_in_the_other_islands_never_broke():
|
|
178
|
+
"""The regression guard is on `s{ }`, but pin the siblings too: the fix
|
|
179
|
+
must not have been needed there, and must not change them."""
|
|
180
|
+
src = ("@graph as g\n"
|
|
181
|
+
"m1 = m{ ?s <http://example.org/ns#X> ?o }\n"
|
|
182
|
+
"g1 = g{ <http://example.org/ns#A> <http://example.org/ns#p> 1 }\n")
|
|
183
|
+
code = transpile(src, "t.ldpy").code
|
|
184
|
+
assert code.count("http://example.org/ns#") == 3
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_a_real_comment_is_still_a_comment():
|
|
188
|
+
src = ("@prefix ex: <http://example.org/ns#> .\n"
|
|
189
|
+
"@graph as g\n"
|
|
190
|
+
"q = s{ SELECT ?s WHERE { ?s ex:v ?v } # a real comment\n"
|
|
191
|
+
" }\n")
|
|
192
|
+
assert "a real comment" in transpile(src, "t.ldpy").code
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def test_less_than_is_still_an_operator():
|
|
196
|
+
"""`<` that does not open an IRI is SPARQL's less-than. The fix keys on
|
|
197
|
+
`_iriref_end`, so it must leave FILTER(?v < 5) alone."""
|
|
198
|
+
src = ("@prefix ex: <http://example.org/ns#> .\n"
|
|
199
|
+
"@graph as g\n"
|
|
200
|
+
"q = s{ SELECT ?s WHERE { ?s ex:v ?v . FILTER(?v < 5 && ?v > 1) } }\n")
|
|
201
|
+
code = transpile(src, "t.ldpy").code
|
|
202
|
+
assert "?v < 5 && ?v > 1" in code
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def test_a_hash_inside_a_string_is_not_a_comment_either():
|
|
206
|
+
src = ("@prefix ex: <http://example.org/ns#> .\n"
|
|
207
|
+
"@graph as g\n"
|
|
208
|
+
'q = s{ SELECT ?s WHERE { ?s ex:v "a#b" } }\n')
|
|
209
|
+
assert 'a#b' in transpile(src, "t.ldpy").code
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{linked_data_python-0.6.0 → linked_data_python-0.6.2}/linked_data_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|