Skip to main content

Scan and process embedded processing instructions in Text documents.

Project description

vyyhti

Tangle (Finnish: vyyhti) — scan and process embedded processing instructions in text documents.

Requires Python 3.11 or later.

Install

pip install vyyhti

Quickstart

Run vyyhti scan with a text file to list every detected embedding:

$ vyyhti scan doc.md
line_command:1:0: '\\newpage'
inline_code:9:22: '`$.document.notes[*].group_ids[*]`'
line_command:11:0: '\\columns=10%,,%30%'
block_pi:21:0: '```{.text} <!--json-path-list-->'

Print the version:

$ vyyhti version
vyyhti 2026.6.21
$ vyyhti -V
vyyhti 2026.6.21

For a dedicated feature walkthrough you can follow in minutes visit quickstart. A step-by-step build of a JSONPath expression linter for Markdown documents is provided in the tutorial.

Embedding kinds

Inline code

A single-backtick span on any non-fenced line:

The expression `$.notes[*].id` must yield at least one result.

Line command

A line whose only content is a backslash command (as used by liitos and LaTeX preprocessors):

\newpage
\columns=10%,,30%

Block processing instruction

A fenced code block whose info string contains an HTML processing instruction comment:

```{.text} <!--json-path-list-->
$.document.notes[*].group_ids[*]
$.vulnerabilities[*].flags[*].group_ids[*]
```

The PI name (json-path-list above) is extracted and available to handlers. The fence body is preserved verbatim.

Library API

scan(text, config=None)

Scans a text string and returns a list of Location objects — one per detected embedding.

from vyyhti import scan, LocationKind

locs = scan(open('doc.md').read())
for loc in locs:
    print(loc.kind, loc.line, loc.text)

Each Location is a frozen dataclass:

Field Type Meaning
kind LocationKind INLINE_CODE, LINE_COMMAND, or BLOCK_PI
line int 1-based line number of the embedding start
col int 1-based column for INLINE_CODE; 0 for whole-line kinds
text str Raw matched text (backtick span / command / opening fence line)
body str \ None For BLOCK_PI: fence body; None otherwise
pi str \ None For BLOCK_PI: content of <!--…-->; None otherwise

run(text, handlers, stages=None, config=None)

Scans the text and applies a list of handlers through the processing pipeline. Returns (embeddings, findings).

from vyyhti import run, Handler, LocationKind

class MyHandler(Handler):
    name = 'my-handler'

    def identify(self, location):
        return location.kind == LocationKind.INLINE_CODE

    def parse(self, location):
        return location.text[1:-1]   # strip backticks

    def verify(self, location, payload):
        return [] if payload.startswith('$') else ['not a JSONPath']

embeddings, findings = run(text, [MyHandler()])

Each matched Location becomes an Embedding (with handler name and payload set). Each problem becomes a Finding (with stage, message, and level).

Pass stages={'parse', 'verify'} to limit which pipeline stages execute. Pass a ScannerConfig to configure which embedding kinds are scanned.

ScannerConfig

Controls which embedding kinds are active and overrides the default match patterns. Pass an instance to scan() or run().

from vyyhti import scan, ScannerConfig

cfg = ScannerConfig(line_command=False)   # skip \commands
locs = scan(text, cfg)
Field Type Default Meaning
inline_code bool True Scan for inline-code spans
line_command bool True Scan for backslash line commands
block_pi bool True Scan for fenced-block PIs
block_pi_pi_pattern str <!--(.*?)--> Regex for PI comment in fence info string
line_command_pattern str ^\s*(\\...)$ Regex for line commands

Load from a YAML file (kebab-case keys) with load_scanner_config(path) from vyyhti._config.

Handler

An abstract base class. Subclass it and implement the methods you need.

Method Signature Required Default
name str class attribute yes
identify (location) -> bool yes
parse (location) -> Any no returns location.text
verify (location, payload) -> list[str] no returns []
validate (location, payload) -> list[str] no returns []
process (location, payload) -> Any no returns None

Finding

Field Type Meaning
location Location The embedding where the problem was found
stage str 'parse', 'verify', 'validate', 'process'
message str Human-readable description
level str 'error' (default), 'warning', or 'info'

Design

Handlers live in the tools that use vyyhti, not in the library itself. scan() finds all structural embedding locations; each handler decides what it claims via identify(). The pipeline then applies only the stages the handler cares about. Handlers for different embedding kinds can coexist in the same run() call.

Exit codes

  • 0 — success.
  • 1 — error: file not found, unreadable, or missing required argument.

See also

man vyyhti

Changes

See docs/changes.md for the release history.

Coverage

The test suite maintains 99% branch coverage. The HTML report (if generated) is in site/coverage/.

SBOM

Runtime dependency information is published in docs/sbom/ in SPDX 3.0 (JSON-LD) and CycloneDX 1.6 (JSON) formats. See docs/sbom/README.md for the component inventory and validation guide.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vyyhti-2026.6.21.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vyyhti-2026.6.21-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

Details for the file vyyhti-2026.6.21.tar.gz.

File metadata

  • Download URL: vyyhti-2026.6.21.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for vyyhti-2026.6.21.tar.gz
Algorithm Hash digest
SHA256 dd054bb497b152dcd1926b74be822c83a706ed51312eed97e844a0c5401fa791
MD5 0660793ce4812e1e1158c6fb81c68e09
BLAKE2b-256 3a6ef80160687f6edc2802fdb136f11fd349606d4169b76c76c336eb03666800

See more details on using hashes here.

File details

Details for the file vyyhti-2026.6.21-py3-none-any.whl.

File metadata

  • Download URL: vyyhti-2026.6.21-py3-none-any.whl
  • Upload date:
  • Size: 9.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for vyyhti-2026.6.21-py3-none-any.whl
Algorithm Hash digest
SHA256 c06405d91acd68ec2be6185df4e93203fbbff9a13750d7c6aeec722609a2afeb
MD5 b832451f1dcc55ec84af54b31ba9afcd
BLAKE2b-256 539084efa25a96a1d29f36fb846f47a549a3f497461399d969e83622068373ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page