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).

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).

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")),
)

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 878 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);
  • 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.1.1-cp310-abi3-win_amd64.whl (1.2 MB view details)

Uploaded CPython 3.10+Windows x86-64

pyregtab-0.1.1-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.1.1-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.1.1-cp310-abi3-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

pyregtab-0.1.1-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.1.1-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: pyregtab-0.1.1-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.1.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 02e0fefeef12183133209aea21a635ed48b97ac25661829622c001bd426dce06
MD5 a0660528b72760db87e621f8d7edfd9f
BLAKE2b-256 4b7ec43e667b0355610fd9b8c87d694d46601e047d3dd78fe51052307127edc8

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyregtab-0.1.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1a7a31529694d3542ed927d18bd06c492671718ee8e5fe95f8e86f7430060489
MD5 d2a2b21a70b331b4301f5a5d536011fd
BLAKE2b-256 9d2cb881719879eb31ae5d015c23722438892e361fa5862e91a3b52ffb790c7d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyregtab-0.1.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 d3bd188d470aa06948b4bbb2a3fda56f778a190d24305a3f22acaed4a26377bd
MD5 a326ed4e5a0c958d3e2cc9429986640c
BLAKE2b-256 828a36a6c573060377cdd0c06acdd331e32a93120018737cdbb760f87dcf5414

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyregtab-0.1.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f8529ae340edfbd8593bdf8b82af4ae85ba4ae113aa905afaebab459ad9be067
MD5 938191ae306c8da2ea3c1b23eb5d8877
BLAKE2b-256 a8faa2f8d5eb337eab015d2d07333f2d5ae05fc551001fb8baa4b7e4653f7ad6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pyregtab-0.1.1-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 67855d3bd046df885878e91ac768da9d87636a2306567eae95359ba587399132
MD5 45d1b8ffcb41a974e0d5d25373a65168
BLAKE2b-256 3cea0723981ea06804569aff654c8e7f80b8fe8c6707909bd209d9c6243fdc25

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