pyling-n3 0.1.0__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.
- pyling_n3-0.1.0/LICENSE +21 -0
- pyling_n3-0.1.0/PKG-INFO +562 -0
- pyling_n3-0.1.0/README.md +524 -0
- pyling_n3-0.1.0/pyling/__init__.py +86 -0
- pyling_n3-0.1.0/pyling/builtins.py +1325 -0
- pyling_n3-0.1.0/pyling/cli.py +94 -0
- pyling_n3-0.1.0/pyling/engine.py +1365 -0
- pyling_n3-0.1.0/pyling/parser.py +551 -0
- pyling_n3-0.1.0/pyling/printing.py +112 -0
- pyling_n3-0.1.0/pyling/rdf.py +924 -0
- pyling_n3-0.1.0/pyling/store.py +91 -0
- pyling_n3-0.1.0/pyling/terms.py +449 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/PKG-INFO +562 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/SOURCES.txt +21 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/dependency_links.txt +1 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/entry_points.txt +2 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/requires.txt +15 -0
- pyling_n3-0.1.0/pyling_n3.egg-info/top_level.txt +1 -0
- pyling_n3-0.1.0/pyproject.toml +47 -0
- pyling_n3-0.1.0/setup.cfg +4 -0
- pyling_n3-0.1.0/tests/test_conformance_hooks.py +45 -0
- pyling_n3-0.1.0/tests/test_rdf_compat.py +191 -0
- pyling_n3-0.1.0/tests/test_reasoning.py +430 -0
pyling_n3-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pyling_n3-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyling-n3
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python implementation of the Eyeling Notation3 reasoner
|
|
5
|
+
Author: Eyereasoner contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/eyereasoner/pyling
|
|
8
|
+
Project-URL: Repository, https://github.com/eyereasoner/pyling
|
|
9
|
+
Project-URL: Issues, https://github.com/eyereasoner/pyling/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/eyereasoner/pyling/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: Notation3,N3,reasoner,RDF,RDF 1.2,RDF Message,RDFLib
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: rdflib>=7.0
|
|
27
|
+
Provides-Extra: test
|
|
28
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
29
|
+
Provides-Extra: conformance
|
|
30
|
+
Requires-Dist: pytest>=7; extra == "conformance"
|
|
31
|
+
Provides-Extra: docs
|
|
32
|
+
Requires-Dist: jupyter>=1; extra == "docs"
|
|
33
|
+
Requires-Dist: nbconvert>=7; extra == "docs"
|
|
34
|
+
Provides-Extra: build
|
|
35
|
+
Requires-Dist: build>=1; extra == "build"
|
|
36
|
+
Requires-Dist: twine>=5; extra == "build"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# pyling
|
|
40
|
+
|
|
41
|
+
A Python port of the Eyeling Notation3 reasoner.
|
|
42
|
+
|
|
43
|
+
RDF/Turtle/TriG compatibility through `rdflib`, RDF 1.2 surface-syntax checks, and RDF Message Log parsing/streaming.
|
|
44
|
+
|
|
45
|
+
The [Eyeling](https://github.com/eyereasoner/eyeling) repositories remains the main implementation.
|
|
46
|
+
|
|
47
|
+
## Requirements
|
|
48
|
+
|
|
49
|
+
- Python 3.10 or newer
|
|
50
|
+
- `pip`
|
|
51
|
+
- `rdflib` is installed automatically from `pyproject.toml`
|
|
52
|
+
- `pytest` is needed only for the test suite
|
|
53
|
+
|
|
54
|
+
## Install in your project
|
|
55
|
+
|
|
56
|
+
After pyling is published to PyPI as `pyling-n3`, install it with Python's
|
|
57
|
+
standard package installer:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m pip install pyling-n3
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
With project-oriented package managers:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv add pyling-n3
|
|
67
|
+
poetry add pyling-n3
|
|
68
|
+
pdm add pyling-n3
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The distribution package is named `pyling-n3`; the Python import package and
|
|
72
|
+
CLI command remain `pyling`.
|
|
73
|
+
|
|
74
|
+
Until the package is published on PyPI, install directly from GitHub:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python -m pip install "pyling-n3 @ git+https://github.com/eyereasoner/pyling.git"
|
|
78
|
+
uv add "pyling-n3 @ git+https://github.com/eyereasoner/pyling.git"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Install from a checkout
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cd pyling
|
|
85
|
+
python -m venv .venv
|
|
86
|
+
. .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
87
|
+
python -m pip install --upgrade pip
|
|
88
|
+
python -m pip install -e ".[test]"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Verify the install:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pyling --help
|
|
95
|
+
python -m pytest -q
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Command-line usage
|
|
99
|
+
|
|
100
|
+
Run a simple N3 rule program from standard input:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cat > example.n3 <<'EOF'
|
|
104
|
+
@prefix : <http://example.org/> .
|
|
105
|
+
|
|
106
|
+
:Socrates a :Man .
|
|
107
|
+
{ ?x a :Man } => { ?x a :Mortal } .
|
|
108
|
+
EOF
|
|
109
|
+
|
|
110
|
+
pyling example.n3
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Expected derived output:
|
|
114
|
+
|
|
115
|
+
```n3
|
|
116
|
+
@prefix : <http://example.org/> .
|
|
117
|
+
|
|
118
|
+
:Socrates a :Mortal .
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Include explicit input facts in the rendered closure:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pyling --include-input-facts example.n3
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Read multiple sources, such as facts plus rules:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pyling facts.n3 rules.n3
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Enable RDF/Turtle/TriG/RDF Message compatibility mode:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
pyling --rdf data.trig rules.n3
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Force a line format:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pyling --rdf --input-format nt data.nt
|
|
143
|
+
|
|
144
|
+
pyling --rdf --input-format nquads data.nq
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Python API
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from pyling import reason, reason_stream, run_async
|
|
151
|
+
|
|
152
|
+
program = """
|
|
153
|
+
@prefix : <http://example.org/> .
|
|
154
|
+
:a :p :b .
|
|
155
|
+
{ ?s :p ?o } => { ?s :q ?o } .
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
print(reason(program))
|
|
159
|
+
|
|
160
|
+
result = reason_stream(program, include_input_facts_in_closure=True)
|
|
161
|
+
print(result.closure_n3)
|
|
162
|
+
print(result.derived)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Multi-source input mirrors Eyeling’s source-list style:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from pyling import reason
|
|
169
|
+
|
|
170
|
+
out = reason({
|
|
171
|
+
"sources": [
|
|
172
|
+
"@prefix : <http://example.org/> .\n:Socrates a :Man .\n",
|
|
173
|
+
"@prefix : <http://example.org/> .\n{ ?x a :Man } => { ?x a :Mortal } .\n",
|
|
174
|
+
]
|
|
175
|
+
})
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The main exported term classes are `Iri`, `Literal`, `Var`, `Blank`, `ListTerm`, `GraphTerm`, `Triple`, `Rule`, and `PrefixEnv`.
|
|
179
|
+
|
|
180
|
+
## Notebook examples
|
|
181
|
+
|
|
182
|
+
Publishable notebooks live in `docs/notebooks/`:
|
|
183
|
+
|
|
184
|
+
- `01-rdflib-reasoning.ipynb` shows RDFLib graph input and RDFLib graph output.
|
|
185
|
+
- `02-owl-style-rules.ipynb` shows runtime-loaded OWL-style N3 rules.
|
|
186
|
+
- `03-neuro-symbolic-validation.ipynb` shows symbolic validation over facts
|
|
187
|
+
extracted by a neural model.
|
|
188
|
+
|
|
189
|
+
Run them locally with:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python -m pip install -e ".[docs]"
|
|
193
|
+
jupyter lab docs/notebooks
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
GitHub Actions executes the notebooks and converts them to HTML in the
|
|
197
|
+
`Notebook docs` workflow. Pull requests upload the generated `notebook-site`
|
|
198
|
+
artifact; pushes to `main` also publish the same `site/` output through GitHub
|
|
199
|
+
Pages when Pages is enabled for GitHub Actions.
|
|
200
|
+
|
|
201
|
+
## RDF and RDF 1.2 compatibility
|
|
202
|
+
|
|
203
|
+
RDF mode is selected with `--rdf` on the CLI or `{"rdf": True}` in the API. It routes ordinary RDF syntax through `rdflib` instead of the N3 rule parser:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from pyling import reason
|
|
207
|
+
|
|
208
|
+
rdf = """
|
|
209
|
+
PREFIX : <http://example.org/>
|
|
210
|
+
:a :p :b .
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
print(reason(rdf, rdf=True, include_input_facts_in_closure=True))
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
RDFLib graphs can also be passed directly:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
from rdflib import Graph, Namespace
|
|
220
|
+
from pyling import reason_graph
|
|
221
|
+
|
|
222
|
+
ex = Namespace("http://example.org/")
|
|
223
|
+
g = Graph()
|
|
224
|
+
g.bind("", ex)
|
|
225
|
+
g.add((ex.a, ex.p, ex.b))
|
|
226
|
+
|
|
227
|
+
closure = reason_graph(g, include_input_facts_in_closure=True)
|
|
228
|
+
print(closure.serialize(format="turtle"))
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Supported compatibility inputs include:
|
|
232
|
+
|
|
233
|
+
- Turtle / `.ttl`
|
|
234
|
+
- TriG / `.trig`
|
|
235
|
+
- N-Triples / `.nt`
|
|
236
|
+
- N-Quads / `.nq`
|
|
237
|
+
- uppercase `PREFIX`, `BASE`, and RDF 1.2 `VERSION` surface forms
|
|
238
|
+
- simple RDF 1.2 annotation syntax, preserving the asserted triple
|
|
239
|
+
- RDF Message Logs using `VERSION "1.2-messages"` and `MESSAGE`
|
|
240
|
+
|
|
241
|
+
The RDF 1.2 layer includes strict surface checks for common negative conformance cases such as surrogate numeric escapes, invalid RDF 1.2 language tags in line syntaxes, relative IRIREFs in N-Triples/N-Quads, and annotation syntax in line syntaxes.
|
|
242
|
+
|
|
243
|
+
Run the bundled offline RDF 1.2 smoke suite:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
python tools/run_rdf12_w3c.py
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Run the W3C RDF 1.2 syntax compliance manifests (requires Node.js and network
|
|
250
|
+
access on the first run):
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
npm ci
|
|
254
|
+
npm run spec
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The W3C runner caches downloaded manifests and fixtures in
|
|
258
|
+
`.rdf-test-suite-cache/`. All RDF 1.2 syntax cases in the configured N-Triples,
|
|
259
|
+
N-Quads, Turtle, and TriG manifests are enabled.
|
|
260
|
+
|
|
261
|
+
## Performance comparisons
|
|
262
|
+
|
|
263
|
+
The comparison harness in `tools/compare_reasoners.py` benchmarks pyling and
|
|
264
|
+
optional FuXi installations over shared N3 fixtures. FuXi is not installed in
|
|
265
|
+
the main project environment. When the `fuxi` reasoner is selected for a
|
|
266
|
+
benchmark run, the harness lazily creates `.cache/fuxi-venv` with Python 3.13
|
|
267
|
+
and installs the `fuxi` package there. The default benchmark suite discovers
|
|
268
|
+
selected `.n3` files from this repo's `examples/` directory. `--list` never
|
|
269
|
+
installs dependencies.
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
npm run perf -- --list
|
|
273
|
+
npm run perf -- --case=socrates --reasoner=pyling --iterations=5 --warmup=2
|
|
274
|
+
npm run perf -- --case=socrates --reasoner=pyling,fuxi --json
|
|
275
|
+
npm run perf -- --csv > perf-results.csv
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
OWL 2 RL support can be benchmarked with the MobiBench OWL2RL archive. pyling
|
|
279
|
+
loads the RDFJS inference engine's OWL2RL N3 rules from
|
|
280
|
+
`https://raw.githubusercontent.com/pietercolpaert/rdfjs-inference-engine/refs/heads/main/rules/owl2rl/owl2rl-eyeling.n3`.
|
|
281
|
+
For the same MobiBench cases, FuXi uses its built-in OWL/DLP setup instead of
|
|
282
|
+
that Eyeling-specific N3 ruleset. This keeps each reasoner on its intended OWL
|
|
283
|
+
path: pyling exercises runtime-loaded N3 rules, while FuXi exercises the OWL
|
|
284
|
+
rule generation shipped with FuXi.
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
npm run perf -- --suite=owl-mobibench --mobibench-limit=5 --reasoner=pyling
|
|
288
|
+
npm run perf:mobibench
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Latest local MobiBench OWL2RL run, measured with one iteration and no warmup on
|
|
292
|
+
2026-07-22:
|
|
293
|
+
|
|
294
|
+
| Reasoner | Cases | Failures | Median ms/case | Cases deriving facts | Total derived facts |
|
|
295
|
+
|---|---:|---:|---:|---:|---:|
|
|
296
|
+
| pyling | 273 | 0 | 85.88 | 273 | 33,402 |
|
|
297
|
+
| FuXi | 273 | 0 | 95.93 | 43 | 221 |
|
|
298
|
+
|
|
299
|
+
Interpret these numbers as a profile of each configured reasoning path, not as
|
|
300
|
+
a strict semantic equivalence result. pyling materializes with the runtime-loaded
|
|
301
|
+
OWL2RL N3 rules, which include broad datatype and RDF-based entailment rules.
|
|
302
|
+
FuXi runs its built-in OWL/DLP translation, which is fast and useful for many
|
|
303
|
+
structural OWL cases but derives no facts for many datatype-heavy MobiBench
|
|
304
|
+
cases. For example, `rdfbased-sem-rdfs-subclass-trans` derives facts in both
|
|
305
|
+
engines, while the early `rdfbased-dat-*` cases mostly derive only in pyling.
|
|
306
|
+
|
|
307
|
+
The GitHub Actions performance workflow runs both `pyling` and `fuxi` for the
|
|
308
|
+
examples suite only. Full MobiBench is intentionally local-only through
|
|
309
|
+
`npm run perf:mobibench`, because it is larger and less suitable for normal pull
|
|
310
|
+
request feedback. Both paths write JSON, CSV, and Markdown reports to
|
|
311
|
+
`performance-reports`.
|
|
312
|
+
|
|
313
|
+
The slowest pyling cases in the latest completed full run were concentrated in
|
|
314
|
+
a small set of RDF-based OWL patterns:
|
|
315
|
+
|
|
316
|
+
| Case | pyling median ms | Derived facts |
|
|
317
|
+
|---|---:|---:|
|
|
318
|
+
| `mobibench-rdfbased-xtr-reflection-subclasses` | 133,292.61 | 290 |
|
|
319
|
+
| `mobibench-rdfbased-sem-bool-intersection-inst-comp` | 31,885.76 | 105 |
|
|
320
|
+
| `mobibench-rdfbased-sem-bool-intersection-inst-expr` | 31,301.35 | 106 |
|
|
321
|
+
| `mobibench-rdfbased-sem-bool-intersection-term` | 30,417.15 | 104 |
|
|
322
|
+
| `mobibench-rdfbased-sem-key-def` | 3,042.21 | 116 |
|
|
323
|
+
|
|
324
|
+
An interrupted full rerun stopped inside `pyling.engine.Engine.solve`, after
|
|
325
|
+
recursive goal solving had already entered a deep multi-premise OWL rule. That
|
|
326
|
+
matches the profile from the completed report: pyling is not uniformly slow,
|
|
327
|
+
but the current generic N3 fixpoint solver can spend disproportionate time on
|
|
328
|
+
rules with broad joins over RDF lists, subclass reflection, intersections, and
|
|
329
|
+
keys. The next performance work should focus on predicate indexing for rule
|
|
330
|
+
bodies, join ordering based on bound variables and candidate counts, and
|
|
331
|
+
deduplication of equivalent substitutions before recursive goal expansion.
|
|
332
|
+
|
|
333
|
+
The examples suite is useful for implementation regressions. After the
|
|
334
|
+
memoized Fibonacci fix, pyling completes `examples/fibonacci.n3` and derives
|
|
335
|
+
the expected query formula containing `F(0)`, `F(1)`, `F(10)`, `F(100)`,
|
|
336
|
+
`F(1000)`, and `F(10000)`. FuXi's generic N3 rule loader does not currently run
|
|
337
|
+
that file because it rejects the literal-subject rule shape used by the example.
|
|
338
|
+
|
|
339
|
+
Disable lazy installation, or supply a dedicated Python executable or checkout
|
|
340
|
+
path:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
npm run perf -- --reasoner=fuxi --no-install-fuxi
|
|
344
|
+
FUXI_PYTHON=/path/to/venv/bin/python npm run perf -- --reasoner=fuxi
|
|
345
|
+
FUXI_PYTHONPATH=/path/to/FuXi-reincarnate/lib npm run perf -- --reasoner=fuxi
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
FuXi currently requires Python 3.13 or newer. If your system `python3` is older,
|
|
349
|
+
install a 3.13 interpreter and let the benchmark harness create
|
|
350
|
+
`.cache/fuxi-venv` from it. Two practical options:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# uv-managed Python, no system Python upgrade needed
|
|
354
|
+
uv python install 3.13
|
|
355
|
+
FUXI_PYTHON="$(uv python find 3.13)" npm run perf -- --reasoner=fuxi --case=socrates
|
|
356
|
+
|
|
357
|
+
# pyenv-managed Python
|
|
358
|
+
pyenv install 3.13
|
|
359
|
+
FUXI_PYTHON="$(pyenv prefix 3.13)/bin/python" npm run perf -- --reasoner=fuxi --case=socrates
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
After Python 3.13 is available, `npm run perf -- --reasoner=fuxi ...` installs
|
|
363
|
+
the `fuxi` package lazily into `.cache/fuxi-venv` and reuses that environment on
|
|
364
|
+
later benchmark runs.
|
|
365
|
+
|
|
366
|
+
Additional fixtures can be added without editing the script:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
npm run perf -- --fixture=my-case=../eyeling/examples/deep-taxonomy-100.n3
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## RDF Message Logs
|
|
373
|
+
|
|
374
|
+
Whole-log replay:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
cat > messages.trig <<'EOF'
|
|
378
|
+
VERSION "1.2-messages"
|
|
379
|
+
PREFIX : <http://example.org/>
|
|
380
|
+
|
|
381
|
+
:a :value 21 .
|
|
382
|
+
|
|
383
|
+
MESSAGE
|
|
384
|
+
|
|
385
|
+
# Empty heartbeat message.
|
|
386
|
+
|
|
387
|
+
MESSAGE
|
|
388
|
+
|
|
389
|
+
:b :value 22 .
|
|
390
|
+
EOF
|
|
391
|
+
|
|
392
|
+
pyling --rdf --include-input-facts messages.trig
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Streaming replay, one message envelope at a time:
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
pyling --rdf --stream-messages rules.n3 messages.trig
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Python streaming API:
|
|
402
|
+
|
|
403
|
+
```python
|
|
404
|
+
from pyling import reason_message_stream
|
|
405
|
+
|
|
406
|
+
for result in reason_message_stream({"sources": [rules_n3, messages_trig]}, {"rdf": True}):
|
|
407
|
+
print(result.closure_n3)
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
The replay vocabulary uses:
|
|
411
|
+
|
|
412
|
+
```n3
|
|
413
|
+
@prefix eymsg: <https://eyereasoner.github.io/eyeling/vocab/message#> .
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
It materializes stream/envelope metadata, `eymsg:orderedEnvelopes`, `eymsg:messageCount`, `eymsg:payloadKind`, and payload formula links through `log:nameOf`. Rules can inspect each payload graph with `log:includes`.
|
|
417
|
+
|
|
418
|
+
## Built-ins
|
|
419
|
+
|
|
420
|
+
The package includes the built-in registry API:
|
|
421
|
+
|
|
422
|
+
```python
|
|
423
|
+
from pyling import register_builtin, unregister_builtin, list_builtin_iris
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Built-in coverage includes common predicates in these namespaces:
|
|
427
|
+
|
|
428
|
+
- `math:` numeric comparison and arithmetic, plus common trig functions
|
|
429
|
+
- `string:` contains/matches/replace/format/length/comparison helpers
|
|
430
|
+
- `list:` first/rest/member/append/reverse/sort and related helpers
|
|
431
|
+
- `log:` includes/notIncludes/semantics/conjunction/skolem/uri and equality helpers
|
|
432
|
+
- `dt:` datatype inspection, validation, value comparison, canonicalization
|
|
433
|
+
- `crypto:` md5/sha/sha256/sha512
|
|
434
|
+
- `time:` year/month/day/hour/minute/second/timeZone/localTime
|
|
435
|
+
|
|
436
|
+
Registering a custom built-in:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
from pyling import Literal, XSD_NS, register_builtin
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def hello(ctx):
|
|
443
|
+
return [ctx.unify_term(ctx.goal.o, Literal("world", XSD_NS + "string"), ctx.subst)]
|
|
444
|
+
|
|
445
|
+
register_builtin("http://example.org/custom#hello", hello)
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Stores
|
|
449
|
+
|
|
450
|
+
The synchronous API uses in-memory reasoning. `run_async(..., {"store": ...})` can persist explicit and inferred triples through the included JSON-backed persistent store.
|
|
451
|
+
|
|
452
|
+
```python
|
|
453
|
+
import asyncio
|
|
454
|
+
from pyling import run_async
|
|
455
|
+
|
|
456
|
+
async def main():
|
|
457
|
+
result = await run_async(program, {"store": {"name": "demo", "path": ".eyeling-store", "clear": True}})
|
|
458
|
+
await result.store.close()
|
|
459
|
+
|
|
460
|
+
asyncio.run(main())
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Tests
|
|
464
|
+
|
|
465
|
+
Run the package tests:
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
python -m pytest -q
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Run the offline RDF 1.2 compatibility smoke suite:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
python tools/run_rdf12_w3c.py
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Run the W3C RDF 1.2 compliance tests:
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
npm ci
|
|
481
|
+
npm run spec
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Run the external `phochste/notation3tests` suite when you have network access or an existing checkout:
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
# Existing checkout
|
|
488
|
+
python tools/run_notation3tests.py /path/to/notation3tests
|
|
489
|
+
|
|
490
|
+
# Or let the runner clone and install the public suite at https://codeberg.org/phochste/notation3tests
|
|
491
|
+
python tools/run_notation3tests.py --clone
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
The runner defaults to `NETWORKING=0`, because this native port does not
|
|
495
|
+
dereference Web resources. It removes stale `.out` files for the 19 skipped
|
|
496
|
+
network fixtures so the reported score covers only tests actually executed.
|
|
497
|
+
|
|
498
|
+
You can also have `pytest` run the external suite by setting:
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
NOTATION3TESTS_DIR=/path/to/notation3tests python -m pytest -q
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
## Packaging and release
|
|
505
|
+
|
|
506
|
+
The package metadata lives in `pyproject.toml`; releases are tracked in
|
|
507
|
+
`CHANGELOG.md`. PyPI is the Python package index, `pip` is the default installer
|
|
508
|
+
users will normally run, and `build` plus `twine` are the local maintainer tools
|
|
509
|
+
used to create and upload distributions. The `Package build` GitHub Actions
|
|
510
|
+
workflow builds the wheel and sdist, runs `twine check`, and uploads the
|
|
511
|
+
generated distributions as an artifact.
|
|
512
|
+
|
|
513
|
+
Build and inspect a release locally:
|
|
514
|
+
|
|
515
|
+
```bash
|
|
516
|
+
python -m pip install -e ".[build,test]"
|
|
517
|
+
python -m pytest -q
|
|
518
|
+
python -m build
|
|
519
|
+
twine check dist/pyling_n3-*
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Publish first to TestPyPI:
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
twine upload --repository testpypi dist/pyling_n3-*
|
|
526
|
+
python -m pip install \
|
|
527
|
+
--index-url https://test.pypi.org/simple/ \
|
|
528
|
+
--extra-index-url https://pypi.org/simple/ \
|
|
529
|
+
pyling-n3
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
If that install works in a fresh environment, publish the same checked
|
|
533
|
+
distributions to PyPI:
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
twine upload dist/pyling_n3-*
|
|
537
|
+
python -m pip install pyling-n3
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
For GitHub Actions releases, prefer PyPI Trusted Publishing over storing a
|
|
541
|
+
long-lived API token in repository secrets. Configure a PyPI trusted publisher
|
|
542
|
+
for the `eyereasoner/pyling` repository and the release workflow file, then use
|
|
543
|
+
`pypa/gh-action-pypi-publish` with `id-token: write` permissions.
|
|
544
|
+
|
|
545
|
+
Release checklist:
|
|
546
|
+
|
|
547
|
+
1. Update `CHANGELOG.md` and move the relevant entries from `Unreleased` to the
|
|
548
|
+
new version.
|
|
549
|
+
2. Update `version` in `pyproject.toml`.
|
|
550
|
+
3. Run tests, conformance checks, notebook build, and package build locally or
|
|
551
|
+
in GitHub Actions.
|
|
552
|
+
4. Confirm the published package name, ownership, license metadata, and long
|
|
553
|
+
README rendering on TestPyPI.
|
|
554
|
+
5. Create a signed git tag, for example `v0.1.0`.
|
|
555
|
+
6. Upload to TestPyPI and install from TestPyPI in a fresh environment.
|
|
556
|
+
7. Upload the same checked distributions to PyPI.
|
|
557
|
+
8. Create a GitHub release from the tag and include the changelog notes.
|
|
558
|
+
|
|
559
|
+
## Development notes
|
|
560
|
+
|
|
561
|
+
- `rdflib` is used only for RDF/Turtle/TriG/N-Triples/N-Quads parsing. N3 rules and formulas are parsed by the local parser.
|
|
562
|
+
- RDF Message Logs are split and replayed before reasoning so message boundaries, empty heartbeat messages, and per-message blank-node scope are preserved.
|