Skip to main content

Read and write VBA macros inside Excel workbooks (.xlsm, .xlsb, .xlam, .xls) in pure Python, no dependencies.

Project description

pyOpenVBA

Read and write the VBA macros inside Excel workbooks, in pure Python.

No external dependencies. No Excel install required. Works on Windows, macOS, and Linux. Python 3.10 or newer.

Supports .xlsm, .xlsb, .xlam, and legacy .xls.


Why use this?

Several excellent Python tools already exist for reading VBA out of Excel files (oletools, olefile, and friends), and they remain the right choice for forensics, malware analysis, and audit use-cases. pyOpenVBA focuses on the next step: safely writing changes back so the workbook still opens cleanly in Excel.

The write path is the whole point of the library:

  • Replace a module's source in place.
  • Add a new standard module, class module, or document/UserForm code-behind.
  • Rename any module (the CFB stream, dir record, PROJECT declaration, PROJECTwm name map, and Attribute VB_Name are all updated in lockstep).
  • Delete a module cleanly.
  • Save the workbook and have it reopen in Excel with no "we found a problem with some content" repair dialog. Every supported format (.xlsm, .xlsb, .xlam, .xls) is verified against live Excel.
  • Safely refuse to corrupt password-protected or digitally signed projects unless you explicitly opt in.

That makes it a good fit for:

  • Version-controlling your VBA in git like normal source code, then pushing edits back without ever opening Excel.
  • Diffing two workbooks to see what changed in Module1.
  • Generating or updating macros from a script without scripting Excel through COM automation.
  • Reading and writing macros on a server (Linux / CI) where Excel is not installed.

pyOpenVBA is a complete read-and-write library, so it covers the full lifecycle of a VBA project in one place: extract, edit, version, write back, and verify. If you only ever need to read, the existing tools remain a solid choice; if you might ever need to write, start here and you will not have to switch later.

Installation

pip install pyOpenVBA

Or from source:

git clone https://github.com/WilliamSmithEdward/pyOpenVBA
cd pyOpenVBA
pip install -e .

That's it. There are no other dependencies.


30-second tour

from pyopenvba import ExcelFile

with ExcelFile("workbook.xlsm") as wb:
    # 1. List all VBA modules in the workbook.
    print(wb.module_names())
    # ['ThisWorkbook', 'Sheet1', 'Module1']

    # 2. Read a module's source as a string.
    source = wb.get_module("Module1")
    print(source)

    # 3. Edit a module and save the workbook.
    wb.set_module("Module1", 'Sub Hello()\r\n    MsgBox "hi"\r\nEnd Sub\r\n')
    wb.save()                       # overwrites the original file
    # wb.save("edited.xlsm")        # ...or save to a new file

That is the entire core API. Three methods.


Add, rename, or delete a module

from pyopenvba import ExcelFile, VBAModuleKind

with ExcelFile("workbook.xlsm") as wb:
    project = wb.vba_project()

    project.add_module(
        "NewModule",
        "Sub Hi()\r\n    MsgBox \"hi\"\r\nEnd Sub\r\n",
        kind=VBAModuleKind.standard,
    )
    project.rename_module("OldName", "NewName")
    project.delete_module("Obsolete")

    wb.save("out.xlsm")

Edit your macros as files on disk (recommended workflow)

This is the easiest way to manage VBA in a git repo. Export every module to a folder, edit the files in any text editor, then push the changes back into the workbook.

From the command line:

# 1. Pull every module out of the workbook into ./vba/
python -m pyopenvba pull workbook.xlsm ./vba

# 2. ...edit ./vba/Module1.bas in your editor of choice...

# 3. Push your edits back into the workbook
python -m pyopenvba push ./vba workbook.xlsm

# Bonus: list modules without extracting anything
python -m pyopenvba ls workbook.xlsm

From Python:

from pyopenvba import pull, push

pull("workbook.xlsm", "./vba")
# ...edit files...
push("./vba", "workbook.xlsm")                       # in place
push("./vba", "workbook.xlsm", out="edited.xlsm")    # to a new file

Module files use the extensions VBA already uses: .bas for standard modules, .cls for class modules, .frm for UserForm code-behind.


Supported formats

Extension What it is Read Write
.xlsm Macro-enabled workbook yes yes
.xlsb Binary workbook yes yes
.xlam Macro-enabled add-in yes yes
.xls Legacy (Excel 97-2003) yes yes

Every save is verified to reopen in Excel without the "we found a problem with some content" repair dialog.


Safety guards

save() refuses to silently produce a broken workbook.

Password-protected projects

If the VBA project is password-protected, any mutation will raise VBAProjectError unless you explicitly opt in:

wb.save(allow_protected=True)

The library never tries to decrypt or change the password - it just preserves the existing protection bytes verbatim. The resulting workbook still requires the original password to open the VBE.

Digitally-signed projects

A digital signature is invalidated by any change to the macros. On mutation, the library drops the stale signature streams and emits a UserWarning so you know trust has been removed:

import warnings
warnings.filterwarnings("error", category=UserWarning)   # treat as fatal

# ...or silence the warning if you accept the consequence:
wb.save(allow_invalidate_signature=True)

What's out of scope

This library is intentionally focused on module source code. The following are preserved byte-for-byte but not interpreted:

  • UserForm layout (controls, properties, positions). Editing the code-behind of a UserForm works fine; editing the design surface does not.
  • VBA project password decryption / re-encryption.
  • Re-signing digitally signed projects.
  • ActiveX license editing.

See docs/roadmap.md for the full feature matrix.


Architecture

src/pyopenvba/
  __init__.py     public API (ExcelFile, pull, push, exceptions)
  excel.py        ExcelFile facade (ZIP / CFB dispatch, pull/push helpers)
  vba.py          VBA project parser + MS-OVBA codec
  cfb.py          MS-CFB (Compound File Binary) parser/writer
  exceptions.py   custom exception hierarchy
  __main__.py     `python -m pyopenvba {pull,push,ls}` CLI

For deeper documentation:


Contributing

Bug reports, weird workbooks that break the library, and PRs are all welcome. Please include the workbook (or a minimal redacted version) when filing a parsing bug.

Run the test suite:

pip install pytest pyright
pytest
pyright src tests

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 Distribution

pyopenvba-1.0.0.tar.gz (55.8 kB view details)

Uploaded Source

Built Distribution

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

pyopenvba-1.0.0-py3-none-any.whl (37.9 kB view details)

Uploaded Python 3

File details

Details for the file pyopenvba-1.0.0.tar.gz.

File metadata

  • Download URL: pyopenvba-1.0.0.tar.gz
  • Upload date:
  • Size: 55.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pyopenvba-1.0.0.tar.gz
Algorithm Hash digest
SHA256 a146ace5912f3a3caf57e8a76c552012fceb3822d9e3f027922f44238bb1b803
MD5 104f74c694aa7649c005cefcf9e45172
BLAKE2b-256 7fa480b47d045ebf5e1c00bcc462664d18a1421fb6e2849abc71d463339ee633

See more details on using hashes here.

File details

Details for the file pyopenvba-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pyopenvba-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 37.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pyopenvba-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0e3ae8a6035ad3b82e0182755d56d16fd88f1ce7603f70d8790664464325301c
MD5 d9ab846102c801deda3769a7e3795f4c
BLAKE2b-256 a6c15be458cb313c1d77edced7600fe7adb781b0c425b16889ba2c2f11649e17

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