structile 6.0.2__tar.gz → 6.1.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.
- {structile-6.0.2/structile.egg-info → structile-6.1.2}/PKG-INFO +1 -1
- structile-6.1.2/VERSION +1 -0
- {structile-6.0.2 → structile-6.1.2}/structile/__init__.py +133 -122
- {structile-6.0.2 → structile-6.1.2}/structile/_paths.py +3 -2
- {structile-6.0.2 → structile-6.1.2}/structile/_plugins.py +10 -6
- {structile-6.0.2 → structile-6.1.2}/structile/convert.py +24 -22
- {structile-6.0.2 → structile-6.1.2}/structile/interpreters.py +8 -6
- structile-6.1.2/structile/static/structile.prod.html +183 -0
- {structile-6.0.2 → structile-6.1.2/structile.egg-info}/PKG-INFO +1 -1
- structile-6.0.2/VERSION +0 -1
- structile-6.0.2/structile/static/structile.prod.html +0 -199
- {structile-6.0.2 → structile-6.1.2}/LICENSE +0 -0
- {structile-6.0.2 → structile-6.1.2}/MANIFEST.in +0 -0
- {structile-6.0.2 → structile-6.1.2}/README.pypi.md +0 -0
- {structile-6.0.2 → structile-6.1.2}/pyproject.toml +0 -0
- {structile-6.0.2 → structile-6.1.2}/setup.cfg +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/__main__.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/_dom_lite.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/_log.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/config.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/dom_lite.js +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/render.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/serialize.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/static/widget.js +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile/widget.py +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile.egg-info/SOURCES.txt +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile.egg-info/dependency_links.txt +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile.egg-info/requires.txt +0 -0
- {structile-6.0.2 → structile-6.1.2}/structile.egg-info/top_level.txt +0 -0
structile-6.1.2/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6.1.2
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
`open()` renders through whichever renderer is active — an inline
|
|
8
8
|
Jupyter widget, a browser tab, a written HTML file, a terminal summary, or
|
|
9
|
-
nothing at all — matplotlib-backend style (see `render.py`). See
|
|
10
|
-
for the full
|
|
11
|
-
limitations)
|
|
9
|
+
nothing at all — matplotlib-backend style (see `render.py`). See
|
|
10
|
+
https://danieltuzes.github.io/structile/python-library/ for the full
|
|
11
|
+
picture (renderers, install steps, supported types, current limitations)
|
|
12
|
+
— no repo checkout needed to read it.
|
|
12
13
|
"""
|
|
13
14
|
from __future__ import annotations
|
|
14
15
|
|
|
@@ -227,105 +228,107 @@ def open(
|
|
|
227
228
|
the last expression in a Jupyter cell, or pass it to
|
|
228
229
|
`IPython.display.display`, and it renders itself richly there too.
|
|
229
230
|
|
|
230
|
-
See
|
|
231
|
-
full picture — this is a parameter reference, not a
|
|
231
|
+
See https://danieltuzes.github.io/structile/python-library/ for
|
|
232
|
+
examples and the full picture — this is a parameter reference, not a
|
|
233
|
+
tutorial. Shadows
|
|
232
234
|
the `open` builtin — always call this namespace-qualified
|
|
233
235
|
(`structile.open(...)`), never `from structile import open`.
|
|
234
236
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
`
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
237
|
+
Args:
|
|
238
|
+
obj: the value to display — any mix of dict/list/tuple/set/None/bool/
|
|
239
|
+
int (any size)/float/str/numpy scalar — or a `pathlib.Path`/`str`
|
|
240
|
+
naming an existing file to load it from (JSON, falling back to
|
|
241
|
+
plain text). When loaded from a path whose content IS valid JSON,
|
|
242
|
+
the file's own literal bytes (not a re-serialization) are what the
|
|
243
|
+
viewer's source pane shows/edits/saves — so original formatting
|
|
244
|
+
(whitespace, key order, ...) survives untouched until an edit
|
|
245
|
+
actually touches it. There's no such "original text" for an
|
|
246
|
+
in-memory `obj` (no path) or for a path that falls back to plain
|
|
247
|
+
text (below) — both show a freshly-serialized JSON view instead, as
|
|
248
|
+
they always have. A path whose extension is markup-like (`.xml`,
|
|
249
|
+
`.html`/`.htm` — see `interpreters.MARKUP_FORMATS`), or has an
|
|
250
|
+
interpreter attached to it (`interpreter=`, or something already
|
|
251
|
+
registered via `register_interpreter`), or `format=` set explicitly
|
|
252
|
+
to anything other than `"json"`/`"python"`, switches to interpreter
|
|
253
|
+
mode: `obj` (or a literal string, with `format=` then required) is
|
|
254
|
+
handed to an interpreter instead of being read as a Python value —
|
|
255
|
+
see `interpreter=` below. `.xml`/`.html` use the DOM-based
|
|
256
|
+
`interpretXML(xmlDocument)` contract; any other format (`.ini`,
|
|
257
|
+
`.toml`, ...) uses the raw-text `interpretText(text)` contract — see
|
|
258
|
+
interpreters/generic_xml.js vs interpreters/generic_ini.js.
|
|
259
|
+
name: display name. Defaults to the loaded file's stem, else "data".
|
|
260
|
+
height: iframe height in px (`widget` renderer only).
|
|
261
|
+
config: viewer settings for this call — an `Options` instance, or a
|
|
262
|
+
plain dict of the same keys (`config={"gap": 8, "forNull": "N/A"}`),
|
|
263
|
+
whichever's more convenient; a dict is just turned into an `Options`
|
|
264
|
+
internally (see `options_from_dict`).
|
|
265
|
+
**settings: individual viewer settings for this call — the numeric
|
|
266
|
+
layout knobs (`gap`, `n`, `m`, `N`, `M`, `nameMax`, `valMax`,
|
|
267
|
+
`headerLabelMax`, `detCols`, `detRows`, `dwellMs`, `kvRows`,
|
|
268
|
+
`kvCols`, `maxWidthFrac`), `theme`, the "Special values" display
|
|
269
|
+
overrides the viewer's Settings panel edits under that name —
|
|
270
|
+
`forNull`/`forEmpty` (strings shown in place of `None`/`""`) and
|
|
271
|
+
`values` (a `{exact_string: replacement}` table) — cosmetic only,
|
|
272
|
+
never changes the underlying data; and `linkOpen`/`linkClose`, the
|
|
273
|
+
viewer's cross-reference-value marker — a dict value/table cell
|
|
274
|
+
wrapped between them, verbatim (delimiters included), that names
|
|
275
|
+
another dict/table anywhere in the document becomes a clickable
|
|
276
|
+
link that jumps to it (see `Options`). `config=` and
|
|
277
|
+
`**settings` both take precedence over `structile.options` /
|
|
278
|
+
`set_option(...)`; anything left unset everywhere falls back to the
|
|
279
|
+
viewer's default. There's no Settings panel in embedded (widget)
|
|
280
|
+
mode, so this is the only way to reach these from Python there —
|
|
281
|
+
e.g. `structile.open(data, forNull="N/A")` to show `None` as `"N/A"`
|
|
282
|
+
everywhere it appears, including nested inside dicts/lists, or
|
|
283
|
+
`structile.open(data, linkOpen="<link.id", linkClose=">")` so a value
|
|
284
|
+
like `"<link.id.20>"` links to a same-named dict/table.
|
|
285
|
+
interpreter: a path to a `.js` interpreter script, raw JS source
|
|
286
|
+
(`interpretXML(xmlDocument)` + optional `serializeXML(value)` for
|
|
287
|
+
markup; `interpretText(text)` + optional `serializeText(value)` for
|
|
288
|
+
any other text format — see interpreters/generic_xml.js,
|
|
289
|
+
interpreters/html.js, interpreters/generic_ini.js), or an
|
|
290
|
+
`InterpreterSource` (source text supplied directly rather than read
|
|
291
|
+
from a path — what an installed plugin package hands
|
|
292
|
+
`register_interpreter`; see `structile.plugins()`); a list mixing
|
|
293
|
+
any of the above; or a dict keyed by file extension (`{".xml": [...],
|
|
294
|
+
".html": [...]}`) — only the entry matching the actual file/format
|
|
295
|
+
is tried, never another extension's candidates (see
|
|
296
|
+
`resolve_candidates`). Multiple candidates are never disambiguated
|
|
297
|
+
in Python — the source(s) are forwarded as-is to whichever renderer
|
|
298
|
+
is active, which tries each one itself (`tryInterpreterCandidates`
|
|
299
|
+
in structile.html) and reports which one worked. This
|
|
300
|
+
needs no Node.js, for any renderer including `widget`. Not required
|
|
301
|
+
if something's already registered for the extension
|
|
302
|
+
(`register_interpreter`, set up once at import time) — this only
|
|
303
|
+
overrides that for one call.
|
|
304
|
+
format: `"xml"` | `"html"` | any other string (e.g. `"ini"`) —
|
|
305
|
+
required alongside `interpreter=`/a registered interpreter when
|
|
306
|
+
`obj` isn't a path (no extension to infer it from) — *unless*
|
|
307
|
+
`interpreter=` is a dict spanning more than one extension, in which
|
|
308
|
+
case omitting `format=` forwards every entry (each under its own
|
|
309
|
+
extension's format) to the renderer, which determines the format
|
|
310
|
+
itself the same no-Node way (`tryInterpreterCandidatesAnyFormat`) —
|
|
311
|
+
Python never has to run anything just to decide which format
|
|
312
|
+
applies, or which contract (DOM vs. raw-text) it uses. Any format
|
|
313
|
+
other than `"xml"`/`"html"` runs through the raw-text
|
|
314
|
+
`interpretText(text)` contract instead of DOM parsing.
|
|
315
|
+
path: save destination, overriding `obj`'s own source path (if any) —
|
|
316
|
+
`widget` renderer only (the other renderers never write back to a
|
|
317
|
+
source file; see the `browser`/`file`/`none`/`text` docs).
|
|
318
|
+
renderer: `"widget"` | `"browser"` | `"file"` | `"none"` | `"text"` —
|
|
319
|
+
overrides resolution for this call only. Otherwise resolved via
|
|
320
|
+
`STRUCTILE_RENDERER` -> `config`/`structile.options.renderer`
|
|
321
|
+
(`set_option`/`use`) -> auto-detect (see `render.detect_renderer`).
|
|
322
|
+
out: also write the standalone HTML snapshot here (any renderer).
|
|
323
|
+
auto_open: set `False` to suppress the `browser` renderer's automatic
|
|
324
|
+
`webbrowser.open()` (it still writes the file; call `.open()` later
|
|
325
|
+
to open it manually).
|
|
326
|
+
default: called on any value that isn't one of `obj`'s own supported
|
|
327
|
+
types (see above); its return value is normalized in its place,
|
|
328
|
+
same escape hatch as `json.dumps(..., default=...)` — e.g.
|
|
329
|
+
`default=str` displays an otherwise-unsupported object as whatever
|
|
330
|
+
`str()` shows for it, instead of raising `TypeError`. See
|
|
331
|
+
`structile.normalize`.
|
|
329
332
|
"""
|
|
330
333
|
if isinstance(config, dict):
|
|
331
334
|
config = options_from_dict(config)
|
|
@@ -482,8 +485,8 @@ def diff(
|
|
|
482
485
|
`.left_payload`/`.right_payload`, `.left_value`/`.right_value`,
|
|
483
486
|
`.open()`, `.to_html()`, `.save(path)`.
|
|
484
487
|
|
|
485
|
-
See
|
|
486
|
-
Deliberately narrower than `open()`: no per-side viewer
|
|
488
|
+
See https://danieltuzes.github.io/structile/python-library/#comparing-two-files-structilediff
|
|
489
|
+
for examples. Deliberately narrower than `open()`: no per-side viewer
|
|
487
490
|
`config=`/`**settings`, and the diff graph itself is always read-only
|
|
488
491
|
for every renderer (including `widget`) — only each side's own source
|
|
489
492
|
pane can be independently edited/saved (see `.left_value`/
|
|
@@ -491,27 +494,35 @@ def diff(
|
|
|
491
494
|
for the `widget` renderer, same as `RenderHandle.value` does for
|
|
492
495
|
`open()`).
|
|
493
496
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
497
|
+
Args:
|
|
498
|
+
left: each independently accepts anything `open()`'s
|
|
499
|
+
`obj` does — a Python value, a path, or (with `interpreter=`/
|
|
500
|
+
`format=`) a raw XML string.
|
|
501
|
+
right: same contract as `left`, independently — the two sides don't
|
|
502
|
+
have to be the same format or schema.
|
|
503
|
+
interpreter: a single value applies to BOTH sides (the common
|
|
504
|
+
case: two files in the same format/schema); a `(left, right)`
|
|
505
|
+
2-tuple gives each side its own — this is what lets `left` and
|
|
506
|
+
`right` be two genuinely different, mutually-incompatible XML
|
|
507
|
+
schemas, each with its own interpreter. See `open()`'s
|
|
508
|
+
`interpreter=` docs for what a single value can be.
|
|
509
|
+
format: same single-value-or-`(left, right)`-tuple convention as
|
|
510
|
+
`interpreter=`. See `open()`'s `format=` docs for what a single
|
|
511
|
+
value can be.
|
|
512
|
+
name: `(left_name, right_name)` — defaults to each side's own inferred
|
|
513
|
+
name (its file stem, or "left"/"right" for a raw string/value).
|
|
514
|
+
view: `"unified"` | `"split"`.
|
|
515
|
+
key_columns: table key-column overrides — same shape the standalone
|
|
516
|
+
viewer's own diff header accepts.
|
|
517
|
+
height: iframe height in px (`widget` renderer only).
|
|
518
|
+
renderer: same as `open()`.
|
|
519
|
+
out: same as `open()`.
|
|
520
|
+
auto_open: same as `open()`.
|
|
521
|
+
default: same escape hatch as `open()`'s `default=`, for
|
|
522
|
+
whichever side(s) are plain Python values (a markup/interpreter-mode
|
|
523
|
+
side never reaches `normalize()`, so this has no effect there) — a
|
|
524
|
+
single value applies to both sides; a `(left, right)` 2-tuple gives
|
|
525
|
+
each side its own, same convention as `interpreter=`/`format=`.
|
|
515
526
|
"""
|
|
516
527
|
resolved_renderer = resolve_renderer(renderer, None) or _detect_renderer()
|
|
517
528
|
left_interp, right_interp = interpreter if isinstance(interpreter, tuple) else (interpreter, interpreter)
|
|
@@ -61,8 +61,9 @@ class InterpreterSource:
|
|
|
61
61
|
"""Interpreter JS source text supplied directly, rather than read from a
|
|
62
62
|
file path — for an interpreter that lives inside an installed package
|
|
63
63
|
(e.g. loaded via `importlib.resources.files()` from an entry-point
|
|
64
|
-
plugin — see
|
|
65
|
-
|
|
64
|
+
plugin — see
|
|
65
|
+
https://danieltuzes.github.io/structile/advanced-usage/#distributing-interpreters-as-a-package
|
|
66
|
+
and `structile.load_plugins`) instead of at a stable filesystem
|
|
66
67
|
path.
|
|
67
68
|
|
|
68
69
|
Accepted anywhere a path is accepted: the `interpreter=` argument of
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"""Entry-point-based interpreter plugin discovery — lets an organisation
|
|
2
2
|
distribute its own interpreter(s) as an ordinary, `pip install`-able Python
|
|
3
3
|
package that `structile` picks up with no import of the plugin package, no
|
|
4
|
-
registration call, and no wrapper API. See
|
|
5
|
-
interpreters
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
registration call, and no wrapper API. See
|
|
5
|
+
https://danieltuzes.github.io/structile/advanced-usage/#distributing-interpreters-as-a-package
|
|
6
|
+
for the full mechanics (precedence,
|
|
7
|
+
discovery timing/caching, the `STRUCTILE_DISABLE_PLUGINS` escape hatch,
|
|
8
|
+
repo-only, contributor-facing) and
|
|
9
|
+
https://danieltuzes.github.io/structile/interpreters/#python-an-installable-plugin
|
|
10
|
+
for the end-user-facing walkthrough (public, no repo checkout needed);
|
|
11
|
+
`tests/fixtures/structile_demo_plugin/` is a working, copyable template.
|
|
9
12
|
|
|
10
13
|
Plugin contract (public and stable — external packages pin against this):
|
|
11
14
|
|
|
@@ -92,7 +95,8 @@ class _RegistryFacade:
|
|
|
92
95
|
plugin could reach into or break.
|
|
93
96
|
|
|
94
97
|
Enforces the "a plugin registration never beats a real, direct
|
|
95
|
-
`register_interpreter()` call" precedence rule (see
|
|
98
|
+
`register_interpreter()` call" precedence rule (see
|
|
99
|
+
https://danieltuzes.github.io/structile/advanced-usage/#distributing-interpreters-as-a-package's
|
|
96
100
|
precedence table) and tracks which extensions THIS plugin registered,
|
|
97
101
|
for `structile.plugins()`. If two plugins register the same extension,
|
|
98
102
|
the last one loaded wins and a WARNING names both distributions —
|
|
@@ -66,28 +66,30 @@ def convert(
|
|
|
66
66
|
) -> str:
|
|
67
67
|
"""Convert data from one of the viewer's formats to another, entirely
|
|
68
68
|
outside the widget/notebook — parse `src`, then serialize the result as
|
|
69
|
-
`dst_format`, returning the converted text. See
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
69
|
+
`dst_format`, returning the converted text. See
|
|
70
|
+
https://danieltuzes.github.io/structile/python-library/#converting-between-formats
|
|
71
|
+
for the built-in-vs-JS-runtime boundary and examples.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
src: a path (format inferred from its extension: .json/.py/.xml/.html —
|
|
75
|
+
or, once an interpreter is attached to it, any other extension too,
|
|
76
|
+
e.g. .ini) or a literal string of source text (sniffed: JSON, else
|
|
77
|
+
Python-repr, else XML if it looks like markup — there's no
|
|
78
|
+
`src_format=` parameter, so a literal string for any OTHER format
|
|
79
|
+
needs a `.` path instead, since there's no reliable way to sniff an
|
|
80
|
+
arbitrary text format from content alone the way XML's leading `<`
|
|
81
|
+
works).
|
|
82
|
+
dst_format: `"json"` | `"python"` | `"xml"` | `"html"` | any other
|
|
83
|
+
string an interpreter is registered/provided for (e.g. `"ini"`).
|
|
84
|
+
interpreter: a path to a `.js` interpreter script, raw JS source, or a
|
|
85
|
+
list of candidates tried in order (same contract as
|
|
86
|
+
`structile.open(..., interpreter=...)` — see `select_interpreter`) —
|
|
87
|
+
required whenever `src` or `dst_format` isn't `"json"`/`"python"`
|
|
88
|
+
and nothing is registered for the relevant extension (see
|
|
89
|
+
`register_interpreter`); needs the optional `mini-racer` package
|
|
90
|
+
(`pip install mini-racer`) to run it — no Node.js, no jsdom, no
|
|
91
|
+
system install (see interpreters.run_interpreter_source). Converting
|
|
92
|
+
purely between "json" and "python" needs nothing extra at all.
|
|
91
93
|
"""
|
|
92
94
|
text, src_format, src_ext = _infer_source(src, interpreter)
|
|
93
95
|
value = _parse_by_format(text, src_format, interpreter, src_ext)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"""Interpreter registry + selection — markup (XML, HTML included) and any
|
|
2
|
-
other text format alike — see
|
|
3
|
-
|
|
2
|
+
other text format alike — see
|
|
3
|
+
https://danieltuzes.github.io/structile/interpreters/ (the public guide;
|
|
4
|
+
no repo checkout needed) and
|
|
5
|
+
https://danieltuzes.github.io/structile/advanced-usage/#interpreter-selection
|
|
4
6
|
for the full picture.
|
|
5
7
|
|
|
6
8
|
An interpreter is caller-supplied JS: `interpretXML(xmlDocument)` (optionally
|
|
@@ -222,8 +224,8 @@ def run_interpreter_source(
|
|
|
222
224
|
raise RuntimeError(
|
|
223
225
|
"structile: this needs the 'mini-racer' package (run `pip install "
|
|
224
226
|
"mini-racer`) — an optional capability, not a hard dependency of "
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
"structile itself. See "
|
|
228
|
+
"https://danieltuzes.github.io/structile/interpreters/"
|
|
227
229
|
)
|
|
228
230
|
from py_mini_racer import JSEvalException, MiniRacer
|
|
229
231
|
|
|
@@ -348,8 +350,8 @@ def select_interpreter(
|
|
|
348
350
|
raise RuntimeError(
|
|
349
351
|
f"structile: {reason} for {fmt!r} data needs the 'mini-racer' package "
|
|
350
352
|
"(run `pip install mini-racer`) — an optional capability, not a hard "
|
|
351
|
-
|
|
352
|
-
|
|
353
|
+
"dependency of structile itself. See "
|
|
354
|
+
"https://danieltuzes.github.io/structile/interpreters/"
|
|
353
355
|
)
|
|
354
356
|
if len(candidates) > 1:
|
|
355
357
|
logger.debug("structile: %d interpreter candidates for %r, trying each in order", len(candidates), fmt)
|