Skip to main content

pyRegTab: pattern-based extraction of recordsets from tables (RTL / ATP / ITM)

Project description

pyRegTab

RegTab: pattern-driven data extraction from document tables with regular structure — the Python port of jRegTab with a native Rust core.

pyRegTab compiles RTL (Regular Table Language) patterns into abstract table patterns (ATP), matches them against a table's syntactic layer (ITM), and interprets the match into a relational recordset:

TableSyntax → RtlCompiler/TablePattern → AtpMatcher → TableInterpreter → Recordset

pyRegTab 0.1.x ≙ jRegTab 0.4.0 (same API, same semantics, same test corpus). 0.2.0 adds the embedded RTL DSL (pyregtab.dsl), mirroring jRegTab's ru.icc.regtab.dsl.

Installation

pip install pyregtab

Binary wheels are published for Windows, Linux and macOS (x86-64 / arm64), CPython ≥ 3.10 (one abi3 wheel per platform). Building from the sdist requires a Rust toolchain.

Example

from pyregtab import TableSyntax, RtlCompiler, AtpMatcher, TableInterpreter

syntax = TableSyntax(3, 3)
syntax.cell(0, 1).set_text("CA");  syntax.cell(0, 2).set_text("HU")
syntax.cell(1, 0).set_text("IKT"); syntax.cell(1, 1).set_text("0 Jan"); syntax.cell(1, 2).set_text("8 Feb")
syntax.cell(2, 0).set_text("SVO"); syntax.cell(2, 1).set_text("31 Jan"); syntax.cell(2, 2).set_text("40 Feb")

pattern = RtlCompiler.compile("""
    [ [] [VAL : 'AIRLINE'->AVP]+ ]
    [ [VAL : 'AIRPORT'->AVP]
      [VAL : (COL, ROW, CL)->REC, 'ND'->AVP " " VAL : 'MON'->AVP]+ ]+
""")

itm = AtpMatcher.match(pattern, syntax)     # InterpretableTable | None
rs = TableInterpreter().interpret(itm)      # Recordset
rs.schema.attributes                        # ['ND', 'AIRLINE', 'AIRPORT', 'MON']
rs[0]["ND"]                                 # '0'
df = rs.to_pandas()                         # extras: pip install pyregtab[pandas]

Patterns can also be built without RTL, via the fluent spec API (TablePattern.of(SubtablePattern.of(...)) — same factories as in Java, snake_case method names), and serialized back to RTL with AtpToRtlSerializer.serialize(pattern).

For a terser, RTL-like way to build patterns in code, use the embedded RTL DSL (pyregtab.dsl) — see Embedded RTL below.

Named Python predicates are attached to RTL via EXT('name'):

from pyregtab import Bindings

p = RtlCompiler.compile(
    "{ [ [EXT('isTotal') ? VAL : ST*->REC] []+ ] }+",
    Bindings.of().cell("isTotal", lambda cell: cell.text.startswith("Total")),
)

Embedded RTL

The pyregtab.dsl module is a fluent DSL that reads almost like RTL but is ordinary Python — with IDE completion, structural typing, pattern composition via plain variables, and Python callables as escape-hatch constraints. It builds the same TablePattern objects as the compiler (verified byte-for-byte against RtlCompiler.compile for a representative set of tasks in tests/test_dsl.py).

from pyregtab.dsl import *

# RTL: { [ [VAL : ST*->REC] [VAL]{2} []+ ]
#        [ []               [VAL]{4} []+ ] }+
p = table(
    subtable(
        row(cell(VAL, rec(ST.unbounded())), cell(VAL).exactly(2), skip().one_or_more()),
        row(skip(),                         cell(VAL).exactly(4), skip().one_or_more()),
    ).one_or_more())

Method names are snake_case (.one_or_more(), .and_(), .split_by()); the vocabulary constants (VAL, ST, COL, C(n), …) match RTL. See the Embedded RTL guide for the full mapping and the where(...) escape hatch.

API mapping (Java → Python)

Java Python
RtlCompiler.compile(String) RtlCompiler.compile(str) / pyregtab.compile(...)
AtpMatcher.match(p, s)Optional<InterpretableTable> AtpMatcher.match(p, s)InterpretableTable | None
Quantifier.oneOrMore() Quantifier.one_or_more()
new TableInterpreter().withStrategy(s).interpret(itm) TableInterpreter().with_strategy(s).interpret(itm)
rs.records().get(0).get("Name") rs[0]["Name"], rs.records, record.get("Name")
cell.text() / cell.setText(t) property cell.text (get/set); cell.set_text(t) also works
RtlCompileException RtlCompileError

Architecture

Everything after the Python call boundary runs in a native core written in Rust (pyregtab._core, built with PyO3 and maturin); the Python layer is a thin re-export.

  • grammar/RTL.g4 — the normative specification of the RTL language (a verbatim copy from jRegTab; the upstream commit and the grammar's SHA-256 are recorded in grammar/UPSTREAM). The core's parser is a hand-written lexer + recursive descent that structurally follows the grammar rules. A CI job (tools/check_grammar_sync.py) fails the build if the copy drifts from the pinned hash, and — when a jRegTab read token is available — cross-checks it byte-for-byte against the upstream commit.
  • conformance/ — the shared RTL conformance corpus (also pinned from jRegTab, see conformance/UPSTREAM and conformance/README.md). Both implementations must compile every positive case to the same canonical form and reject every negative case; the corpus runs in CI of both projects. Any RTL language change flows: RTL.g4 in jregtab → corpus extension → both parsers → green corpus in both CIs.
  • Regular expressions in RTL constraints are executed by the Rust regex crate (linear-time). The reference fixture corpus uses no lookaround/backreferences (audited), so the dialect is compatible with java.util.regex on this corpus. Documented divergences from Java: \d/\s/\w are Unicode-aware in regex (ASCII in Java), and SUBSTR indices count code points (UTF-16 units in Java) — identical behavior on the entire reference corpus.

Testing

pytest tests runs (1 904 tests):

  • the full benchmark suite — tasks 001–150 (Foofah, RegTab, Baikal), every fixture variant, both via RTL patterns and via ATP patterns built with the Python spec API (1 500 task variants in total; fixtures are copied verbatim from jRegTab into tests/fixtures/tasks, ATP builders are mechanically translated from the Java tests by tools/translate_atp.py);
  • embedded RTL DSL parity — 26 representative tasks/constructs built with pyregtab.dsl produce byte-identical ATP to RtlCompiler.compile (tests/test_dsl.py);
  • the RTL conformance corpus (positive canonical forms, fixed points, negative rejections);
  • RTL↔ATP round-trip for tasks 001–050;
  • API unit tests (syntax layer, extractors, EXT bindings, custom predicates, transformations, interpreter options, GIL-released batch matching from a thread pool).

cargo test additionally runs the conformance corpus and an end-to-end smoke test against the native core alone. Differential testing against the Java reference (tools/differential.py + tools/RecordsetDumpMain.java) compares recordsets cell-by-cell on all 750 task variants — zero mismatches against jRegTab v0.4.0.

IDE support

ide/vscode/ is a VS Code extension (and IntelliJ/PyCharm TextMate bundle) that highlights .rtl files and RTL embedded in Python strings passed to RtlCompiler.compile(...). See ide/README.md. RTL is also validated at compile time: RtlCompiler.compile(...) raises RtlCompileError with a line:col position on an invalid pattern.

Development

python -m venv .venv && . .venv/bin/activate   # or .venv\Scripts\activate
pip install maturin pytest
maturin develop --release
pytest tests -q

License

MIT

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

pyregtab-0.2.0-cp310-abi3-win_amd64.whl (1.2 MB view details)

Uploaded CPython 3.10+Windows x86-64

pyregtab-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

pyregtab-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.3 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ ARM64

pyregtab-0.2.0-cp310-abi3-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

pyregtab-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl (1.3 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file pyregtab-0.2.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: pyregtab-0.2.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for pyregtab-0.2.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ab68393227eb36fd761bc0564a7b3bd6d6507fb4a7a368da802fbf6dc4d25979
MD5 e1a2b41b044823ed613a19ea2f9b50d0
BLAKE2b-256 d06baec4c6adc317c75dcbb35b58f5ed185e757fc00ab08acc66d1b8a7f6e603

See more details on using hashes here.

File details

Details for the file pyregtab-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyregtab-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 632d630ea4635a991b35362802b57caa72cb4e972cc1dbc867299a81d7b7ea8b
MD5 dd57e94bb4e99b8c5174b686ffaba547
BLAKE2b-256 7c163408249dcec97c3e9f0370a6bb9f2da3fb0c230689ca401ac3d9d33a019d

See more details on using hashes here.

File details

Details for the file pyregtab-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyregtab-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 1c9202aa66d1bd88991a79899187b4b22ded21ee3c3feeb901ac3568731cf617
MD5 8251e262a18c0c94db3b0a5b03c3d80f
BLAKE2b-256 664db4c00a66de50422eead90bbf445cb3bf59192138dd888e27a8f1970ff4c4

See more details on using hashes here.

File details

Details for the file pyregtab-0.2.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyregtab-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9f5b0503b2b002bc61c4d8a4f6b9241b9e0fac0695aba4c648a80530be9256f1
MD5 c9d1f163103f60779c63c3bc4f41a07e
BLAKE2b-256 27b06c4de7d680ab85450666ce417c31c1e9f72cc02c075e4fbd83d65d1d67c5

See more details on using hashes here.

File details

Details for the file pyregtab-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pyregtab-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 3805135077e650c27a5e5ab09aa8f9b329b6a7cf69c28eabcb3c2af111f25834
MD5 3ece60ae4eae8c0f46f50bee58a0822a
BLAKE2b-256 9f7d4792c1cef821607a45ddb078877a4e38a5b2f9afb5f3054fb1fc2684c5ac

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