Skip to content

This release adds 2 notable features for engineering teams evaluating rollout.

✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

compound-file deterministic excel file-format macro-extraction ms-cfb
+13 more
ms-ovba office-automation openxml pure-python python roundtrip vba vba-macros xlam xls xlsb xlsm zero-dependencies

Summary

AI summary

Class modules from exported .cls files now compile correctly in Excel and other hosts.

Full changelog

Fixed

  • Class modules built from VBE-exported .cls sources now compile in
    the host
    (GitHub issue #1). add_module(kind=VBAModuleKind.other),
    set_module, and push_modules normalize class sources from
    file-export form to stream form via the new
    pyopenvba.vba.normalize_class_source(): a leading
    VERSION 1.0 CLASS / BEGIN / END preamble is stripped, and
    Attribute VB_Base is inserted after VB_Name when missing. On
    replacement of an existing module the prior header's VB_Base line is
    preserved, so document-module host CLSIDs are never overwritten.
    Previously a supplied header was written into the stream verbatim: a
    missing VB_Base made Excel raise "Invalid procedure call or
    argument" at the first New site, and a VERSION preamble in the
    stream raised "Compile error: Expected: end of statement" (both
    verified against live Excel, as is the fix). Supersedes the 2.0.1
    guidance that callers must supply the VB_Base line themselves.
  • pyopenvba.__version__ reported 2.0.0 while PyPI shipped 3.0.x. A
    new test pins it to the installed package metadata so the two sources
    cannot drift again.
  • CFB get_stream_in_storage / write_stream_in_storage /
    list_streams_in_storage now operate on the named storage's own
    child subtree instead of linear-scanning the whole directory. The
    old scan could read or overwrite a same-named stream in a different
    storage (two UserForms both carry o / f streams) and reported
    root-level streams as members of every storage. The host facades now
    address PROJECTwm at the project root, where [MS-OVBA] 2.2.1 puts
    it. Byte output for well-formed files is unchanged (verified by
    hashing a 25-case save matrix across all live fixtures).
  • python -m pyopenvba pull / push / ls now route Word and PowerPoint
    files by extension instead of assuming Excel; legacy .xls / .doc
    / .ppt are accepted everywhere the modern extensions are. disasm
    no longer advertises .xltm / .ppam, which no facade accepts.
  • python -m pyopenvba access-pull delegates to
    AccessReader.pull_modules, so Access class modules export as
    .cls (previously everything was written as .bas).
  • README support section named the wrong project; roadmap.md's link to
    the feature-gate matrix pointed outside docs/.

Changed

  • The MS-OVBA compressor's LZ encoder uses a 3-gram position index
    instead of re-scanning the whole window at every position: about 60x
    faster on the 17 KB large-module fixture (0.44 s to 0.007 s) and
    0.4 s on a 1 MB input. Output is byte-for-byte unchanged -- Access
    validates OVBA cache blobs against exact compressor output -- pinned
    by new naive-oracle equivalence tests across random, repetitive, and
    boundary inputs.
  • AccessReader.pull_modules walks the database's LVAL rows once
    instead of four times per call.
  • save() emits pending module additions and deletions in sorted
    order, making multi-add saves byte-deterministic across processes
    (Python randomizes set iteration per process via string hashing).
  • ExcelFile, WordFile, and PowerPointFile are now thin subclasses
    of a single shared implementation
    (pyopenvba._host.VBAHostFile), removing three hand-synchronized
    copies of the read/edit/pull/push/save pipeline (~900 duplicated
    lines). The public API is unchanged and the refactor was verified
    byte-identical against the previous implementation on every live
    fixture and save operation.

Added

  • Live Excel compile-and-run gate (tests/test_live_excel_gate.py
    plus tools/live_excel/): builds a workbook with an export-form
    class module, runs its macro in desktop Excel under a popup-aware
    bounded harness (VBE modals are dismissed, captured, and reported
    instead of deadlocking the run), and requires a clean run plus the
    macro's sentinel output. Opt-in via RUN_LIVE_EXCEL=1 on Windows;
    skipped in CI. Issue #1 shipped because "opens without a repair
    prompt" was the strongest live verification; this gate closes that
    gap.
  • CI matrix now tests Python 3.14 (the classifiers already claimed it).

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track WilliamSmithEdward/pyOpenVBA

Get notified when new releases ship.

Sign up free

About WilliamSmithEdward/pyOpenVBA

All releases →

Related context

Earlier breaking changes

  • v3.0.0 Renamed the `AccessFile` class to `AccessReader`.
  • v3.0.0 Renamed `pyopenvba.access` module to `pyopenvba.access_read`.
  • v1.1.1 `add_module(kind=other)` now requires an explicit attribute header; automatic synthesis is disabled.

Beta — feedback welcome: [email protected]