Skip to main content

vsdxkit

CI Python 3.10–3.14 BSD-3-Clause Docs

Create, edit and analyse Microsoft Visio .vsdx files with Python. Visio is not required at runtime.

0.x API notice. 0.7 is the last release of the inherited API. 1.0 renames VisioFile to Document and Container to SwimlaneDiagram, splits Connect into an internal ConnectionRecord and a public Connector, and drops the context manager: opening closes the archive before it returns, and save() is the only write. The 1.0 design lists every change, and a migration guide lands at docs/migration-1.0.rst with the first breaking release. Once there is a release on PyPI again, pin vsdxkit<1 to stay on the 0.x names; see Installation for what the index holds today.

The distribution is named vsdxkit. The import remains vsdx, so existing code keeps working.

vsdxkit adds shape creation, Visio-faithful connectors, connector re-anchoring, cross-functional flowchart swimlanes, stricter package handling, current Python tooling and typed public APIs. It began as a fork of dave-howard/vsdx and is now developed as its own project; see Provenance and licence.

What it does

  • Opens, queries and edits existing .vsdx files without Microsoft Visio.
  • Finds shapes by ID, text, regular expression or Shape Data.
  • Creates common flowchart shapes from a bundled palette.
  • Creates dynamic or connection-point glue with straight, right-angle or curved routing.
  • Re-anchors either end of an existing connector.
  • Reads and extends Visio cross-functional flowchart swimlanes.
  • Copies shapes and pages while rewriting package-local IDs and importing masters.
  • Renders data into Visio templates with Jinja.
  • Saves to a new file or safely replaces the source file in place.

The implementation edits the XML parts inside the Open Packaging Convention archive. It does not drive the Visio user interface. Generated connector and swimlane files are checked against Microsoft Visio through COM before a connector or swimlane change is considered done. That check is manual; no workflow runs Visio. See When a change needs Visio.

Installation

As of 2026-09-13 there is no release on PyPI. The first release was withdrawn after a security defect was found in it and cannot be republished, so pip install vsdxkit finds no versions until the next one lands. The PyPI project page shows the current state.

Install from GitHub in the meantime:

python -m pip install "vsdxkit @ git+https://github.com/firmfooting/vsdxkit.git"

That tracks main, so pin a commit if you need a reproducible install. Once there is a release on the index, install it with pip install vsdxkit.

For development:

git clone https://github.com/firmfooting/vsdxkit.git
cd vsdxkit
uv sync --locked

Python 3.10–3.14 is supported on Linux, Windows and macOS. Add --group docs to that sync if you also want to build the documentation; Sphinx needs Python 3.12 or later.

Open, edit and save

Use the context manager to close the package cleanly. Saving is explicit.

from vsdx import VisioFile

with VisioFile("diagram.vsdx") as vis:
    page = vis.pages[0]
    shape = page.find_shape_by_text("Shape to remove")

    if shape is not None:
        shape.text = "Renamed shape"

    vis.save_vsdx("edited.vsdx")

Call save_vsdx() without a filename to replace the source file in place:

with VisioFile("diagram.vsdx") as vis:
    vis.pages[0].name = "Current state"
    vis.save_vsdx()

Create shapes and connectors

Shape coordinates are in Visio page units, normally inches. x and y identify the shape centre.

from vsdx import VisioFile

with VisioFile("diagram.vsdx") as vis:
    page = vis.pages[0]

    start = vis.create_shape(
        page, "PALETTE_START_END", 2.0, 6.0, text="Start"
    )
    work = vis.create_shape(
        page, "PALETTE_PROCESS", 6.0, 6.0, text="Do the thing"
    )
    decision = vis.create_shape(
        page, "PALETTE_DECISION", 10.0, 6.0, text="OK?"
    )

    page.connect_shapes(start, work)
    page.connect_shapes(work, decision, route="rightangle")
    vis.save_vsdx("flow.vsdx")

Bundled palette names are:

  • PALETTE_PROCESS
  • PALETTE_DECISION
  • PALETTE_START_END
  • PALETTE_PARALLELOGRAM
  • PALETTE_DATABASE

Connector route combines glue and routing behaviour:

Value Meaning
dynamic Dynamic shape glue. This is the default.
point Glue to zero-based connection points selected with from_cp and to_cp.
straight Dynamic glue with straight routing.
rightangle Dynamic glue with right-angle routing.
curved Dynamic glue with curved routing.
`point curved`

Re-anchor a connector

Pass only the end that should move. A None endpoint keeps the current shape.

connector = page.find_shape_by_id("9")
new_target = page.find_shape_by_text("Store")

if connector is not None and new_target is not None:
    page.reanchor_connector(connector, to_shape=new_target)

Deleting a shape through page.delete_shape(shape) also removes incident connectors and their Connect records.

Work with swimlanes

Swimlane operations require an existing Visio cross-functional flowchart (CFF) page. add_swimlane() clones the current top lane and updates the CFF container geometry.

with VisioFile("cross-functional-flow.vsdx") as vis:
    page = vis.pages[0]
    container = page.get_container()

    if container is None:
        raise ValueError("The page is not a Visio CFF diagram")

    review_lane = page.add_swimlane("Review")
    check = vis.create_shape(
        page, "PALETTE_PROCESS", 6.0, 2.0, text="Check"
    )
    page.add_shape_to_lane(check, review_lane)

    assert container.lane_of(check) is not None
    vis.save_vsdx("with-review-lane.vsdx")

Visio CFF membership is geometric. Shapes are associated with the lane whose vertical band contains their centre; there is no separate membership field to write.

Render a Jinja template

Jinja expressions can be stored in shape text and rendered into a new file:

with VisioFile("template.vsdx") as vis:
    vis.jinja_render_vsdx(
        context={"project": "Ward refurbishment", "owner": "Facilities"}
    )
    vis.save_vsdx("rendered.vsdx")

The package also supports its existing group-shape loop and showif conventions. See docs/templating.rst and the tests/test_jinja*.py cases for the exact template structure.

Limits

  • The library starts from an existing .vsdx; it does not create a complete Visio document package from nothing.
  • .vsdm files can be read and saved, but only back to a .vsdm destination. The package kind is decided by the content type of visio/document.xml, not by the filename, so save_vsdx() refuses a .vsdx destination for a macro-enabled package and a .vsdm destination for one that is not — either would produce a file whose extension and [Content_Types].xml disagree, which Visio reports as corrupt. Stripping macros to convert a .vsdm into a .vsdx is not supported. A destination with no extension, or with an unrelated one, gets the matching Visio extension appended.
  • Swimlane creation works on existing Visio CFF diagrams. It does not convert an ordinary page into a CFF diagram.
  • Visio may recalculate layout when a generated file opens. The library writes the glue and route cells but does not reproduce Visio's entire layout engine.
  • Loading enforces package expansion limits before any archive member is read: at most 512 members, 64 MiB per member, 256 MiB total uncompressed, and a 100:1 compression ratio, plus rejection of duplicate and path-unsafe member names. A hostile or accidental archive is refused with vsdx.PackageLimitError instead of exhausting process memory. The defaults suit documents from unknown sources; trusted callers can relax the caps with VisioFile(filename, limits=PackageLimits(...)) or limits_path="vsdx.limits.json" (same keys, JSON object).

Development and verification

uv run --no-sync python -m pytest tests -q
uv run --no-sync ruff check vsdx tests tools
uv run --no-sync ruff format --check vsdx tests tools
uv run --no-sync pyrefly check vsdx --min-severity warn --output-format min-text
uv run --no-sync sphinx-build -W --keep-going -b html docs docs/_build/html
uv run --no-sync python -m build

The package is held at pyrefly's strict preset. CI tests Python 3.10–3.14 on Linux and Windows, and 3.10 and 3.14 on macOS. Connector and swimlane changes also run through tools/visio_check.ps1, which opens generated files in an invisible Microsoft Visio instance and reports package repair or automation errors. That step is manual, on a maintainer's Windows machine; GitHub's runners have no Visio.

Documentation

The Sphinx source is in docs/. Build it locally with:

uv sync --locked --group docs
uv run --no-sync python -m sphinx -W --keep-going -b html docs docs/_build/html

Sphinx is pinned in the docs dependency group, which requires Python 3.12 or later. The library itself still supports 3.10, so run the docs build on a 3.12+ interpreter.

Provenance and licence

vsdxkit descends from dave-howard/vsdx, originally written by Dave Howard and released under the BSD 3-Clause licence. That work is the foundation this library is built on, and its copyright notice is retained in LICENSE alongside our own.

vsdxkit is now developed independently: it is not a downstream of that project and does not track it. The vsdx import namespace is kept so existing code continues to work, and the licence remains BSD 3-Clause.

Download files

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

Source Distribution

vsdxkit-0.7.1.tar.gz (613.8 kB view details)

Uploaded Source

Built Distribution

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

vsdxkit-0.7.1-py3-none-any.whl (98.8 kB view details)

Uploaded Python 3

File details

Details for the file vsdxkit-0.7.1.tar.gz.

File metadata

  • Download URL: vsdxkit-0.7.1.tar.gz
  • Upload date:
  • Size: 613.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vsdxkit-0.7.1.tar.gz
Algorithm Hash digest
SHA256 ff70ff50a204fb409c03761e4a81afbdae7ad6be78e31f63a30fd89cc1a74d40
MD5 b5f006ea5696b289e1b3605aac3c4654
BLAKE2b-256 21b97d484bcfa7d040aaf952d117ed8ba0d1819c725b7aac4d4db6ab913c79bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for vsdxkit-0.7.1.tar.gz:

Publisher: publish.yml on firmfooting/vsdxkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vsdxkit-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: vsdxkit-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 98.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for vsdxkit-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7b973d2241314867afd08ebc01b5be3411bdac499b51c3c8c3c0c4fd2d71a5f2
MD5 4f8a25524770b1679f6ea03ec5a748b4
BLAKE2b-256 1ae51472d0a635194e06c3ccb88c825e3ea5e03cc82ecbdb82b7dd58483663da

See more details on using hashes here.

Provenance

The following attestation bundles were made for vsdxkit-0.7.1-py3-none-any.whl:

Publisher: publish.yml on firmfooting/vsdxkit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.7.1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page