-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatch_reason_sandbox.py
More file actions
78 lines (72 loc) · 2.94 KB
/
Copy pathpatch_reason_sandbox.py
File metadata and controls
78 lines (72 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
"""Monkey-patch cogitarelink.reason.sandbox.reason_over to support N3/EYE rules."""
import json
import subprocess
import tempfile
from pathlib import Path
from rdflib import Graph
import cogitarelink.reason.sandbox as sandbox
# Preserve original JSON-LD loader to catch HTTP errors when parsing contexts
_orig_to_graph = sandbox._to_graph
def _patched_to_graph(data: str | dict, fmt: str = "json-ld"):
"""Attempt to parse JSON-LD, stripping remote @context on failure to avoid HTTP errors."""
try:
return _orig_to_graph(data, fmt)
except Exception as e:
# Fallback: remove @context to prevent remote fetch
try:
obj = data if isinstance(data, dict) else json.loads(data)
except Exception:
raise e
if isinstance(obj, dict) and "@context" in obj:
obj.pop("@context", None)
try:
return _orig_to_graph(obj, fmt)
except Exception:
pass
# Reraise if fallback fails
raise e
# Apply patched loader
sandbox._to_graph = _patched_to_graph
from cogitarelink.reason.prov import wrap_patch_with_prov
# Preserve the original reason_over function
_original_reason_over = sandbox.reason_over
def _eye_run(data_ttl: str, rules_n3: str) -> Graph:
workdir = Path(tempfile.mkdtemp(prefix="eyejs_"))
data_f = workdir / "data.ttl"
rules_f = workdir / "rules.n3"
data_f.write_text(data_ttl, encoding="utf8")
rules_f.write_text(rules_n3, encoding="utf8")
payload = {
"dataPath": str(data_f),
"rulesPath": str(rules_f),
"queryPath": None
}
out = subprocess.check_output(
["node", "js/eye-runner.mjs"],
input=json.dumps(payload),
text=True
)
derived = Graph().parse(data=out, format="n3")
return derived
def patched_reason_over(jsonld: str, shapes_turtle=None, query=None, n3_rules=None, *args, **kwargs):
if n3_rules is not None:
# If input looks like Turtle, use it directly; otherwise parse JSON-LD to Turtle
if jsonld.strip().startswith('@prefix'):
data_ttl = jsonld
else:
# Parse JSON-LD using patched loader to avoid remote context fetch
ds = sandbox._to_graph(jsonld)
data_ttl = ds.default_context.serialize(format="turtle")
# Run EYE reasoning
derived_graph = _eye_run(data_ttl, n3_rules)
# Compute the delta
original_graph = Graph().parse(data=data_ttl, format="turtle")
patch_graph = derived_graph - original_graph
# Wrap with provenance and return
summary = f"💡 EYE derived {len(patch_graph)} triples via n3_rules"
prov_patch = wrap_patch_with_prov(patch_graph)
return prov_patch.serialize(format="json-ld"), summary
# Fallback to original
return _original_reason_over(jsonld=jsonld, shapes_turtle=shapes_turtle, query=query, *args, **kwargs)
# Apply the monkey-patch
sandbox.reason_over = patched_reason_over