Metadata-Version: 2.4
Name: pyOpenVBA
Version: 1.0.0
Summary: Read and write VBA macros inside Excel workbooks (.xlsm, .xlsb, .xlam, .xls) in pure Python, no dependencies.
Project-URL: Homepage, https://github.com/WilliamSmithEdward/pyOpenVBA
Project-URL: Repository, https://github.com/WilliamSmithEdward/pyOpenVBA
Project-URL: Issues, https://github.com/WilliamSmithEdward/pyOpenVBA/issues
Project-URL: Documentation, https://github.com/WilliamSmithEdward/pyOpenVBA#readme
Author-email: William Smith <williamsmithe@icloud.com>
License: MIT
License-File: LICENSE.md
Keywords: excel,macros,ms-cfb,ms-ovba,office,vba,xlam,xls,xlsb,xlsm
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# 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

```bash
pip install pyOpenVBA
```

Or from source:

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

That's it. There are no other dependencies.

---

## 30-second tour

```python
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

```python
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:

```bash
# 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:

```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:

```python
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:

```python
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](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:

- [docs/architecture.md](docs/architecture.md) - internal module layout.
- [docs/ms-ovba-implementation-guide_v2.md](docs/ms-ovba-implementation-guide_v2.md) -
  language-agnostic guide for re-implementing MS-OVBA in another
  language.
- [docs/roadmap.md](docs/roadmap.md) - per-feature implementation status.

---

## 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:

```bash
pip install pytest pyright
pytest
pyright src tests
```

---

## License

[MIT](LICENSE.md).
