Skip to main content

PyAccessKit

A modern, typed, Pythonic toolkit for building and modifying Microsoft Access databases (.accdb) and, progressively, whole Access applications without raw pywin32 calls, DAO magic numbers or orphaned MSACCESS.EXE processes.

from pyaccesskit import AccessDatabase, Column, Expr, Vba, cm

with AccessDatabase.create("crm.accdb") as db:
    db.tables.create(
        "Customers",
        columns=[
            Column.autonumber("CustomerID", primary_key=True),
            Column.text("CustomerName", length=200, required=True),
            Column.text("Email", length=255, unique=True),
            Column.date_time("CreatedAt", default=Expr("Now()")),
        ],
    )
    db.tables.create(
        "Orders",
        columns=[
            Column.autonumber("OrderID", primary_key=True),
            Column.number("CustomerID", required=True),  # Long Integer, as in Access
            Column.currency("Total", default=0),
        ],
    )
    db.relationships.create("Customers.CustomerID", "Orders.CustomerID", cascade_delete=True)
    db.queries.create("qryCustomers", "SELECT * FROM Customers ORDER BY CustomerName;")

    with db.forms.create("frmCustomers", record_source="Customers", caption="Customers") as form:
        form.textbox("CustomerName", label="Customer name", width=cm(8))
        form.textbox("Email")
        form.button("cmdClose", caption="Close", on_click=Vba("DoCmd.Close acForm, Me.Name"))

When the with block ends, the database file appears at crm.accdb, and any Access process PyAccessKit started is closed. If the block raises, no file is created and nothing is left running.

Status: alpha (0.1.0). The API may still change between 0.x releases.

Installation

pip install pyaccesskit

Requirements:

  • Windows 10 or 11 and CPython 3.11–3.14 (64- or 32-bit; free-threaded builds are not supported).
  • Microsoft Access 2016 or later, including Microsoft 365. Alternatively, the Microsoft 365 Access Runtime with a Python of the same bitness, for schema and data work only.

Check your machine with:

pyaccesskit doctor          # which engines work here, and why not
pyaccesskit doctor --probe  # also builds a scratch database end to end

The spec models (TableSpec, Column, FormSpec, units, layout…) are pure Python and also import on Linux and macOS, so you can validate specs in CI without Access.

What you can do in 0.1

Area Highlights Stability
Lifecycle Atomic create(), open() (read-only/shared, exclusive, password), guaranteed cleanup, db.raw escape hatch stable-track
Tables Every common column type, defaults as Python values or Expr, validation rules, captions, formats, input masks; indexes (composite, descending, unique, primary); add, drop and rename columns and indexes; to_spec() round-trips stable-track
Relationships Single and composite keys, referential integrity, cascades, join types, all checked before Access sees them stable-track
Queries & data Saved queries (select, action, union, crosstab, pass-through), parameters bound by name, execute() / fetch_all() stable-track
Forms Labels, text boxes, check boxes, combo boxes and buttons; stacked or tabular layout; VBA event procedures; atomic build-then-swap replacement provisional
Modules & text I/O Standard and class modules; SaveAsText/LoadFromText for forms, reports, macros, queries and modules, stored as UTF-8 provisional
Decimal columns Column.decimal(precision=…, scale=…) via ADO DDL provisional

Reports, linked tables, VBA references, and the declarative build/plan/apply workflow are planned (see the roadmap).

Engines

PyAccessKit reaches the database in one of three ways and picks one for you (engine="auto"):

Engine When Notes
In-process DAO Python and Office have the same bitness Fastest; never starts MSACCESS.EXE; enough for tables, relationships, queries and data
Access-hosted DAO Bitness differs, or engine="access" A hidden Access instance that PyAccessKit owns hosts DAO; the database is not opened in the Access UI, so no startup code runs
Design session First use of forms, modules or text I/O The database becomes Access's current database; handles such as db.tables["X"] keep working across the switch
Python Office In-process DAO Access transports
64-bit 64-bit ✅ ✅
32-bit 32-bit ✅ ✅
64-bit 32-bit (common with Microsoft 365) ❌ ✅
32-bit 64-bit ❌ ✅

pyaccesskit doctor explains what applies to your machine.

Safety guarantees

  • Never touches your own Access windows. PyAccessKit always starts a new Access instance (CoCreateInstanceEx, local server). It never attaches to a running Access (which Dispatch() does), so it can never close your work.
  • No orphaned MSACCESS.EXE. Every Access process it starts is identified by PID, creation time and image, and placed in a kill-on-close job object. If Python crashes, Windows ends the process. The process is also recorded in an ownership ledger: pyaccesskit cleanup ends leftovers from crashed sessions, and only when their Python owner is gone. Processes it did not start are never touched.
  • Exceptions clean up too. Closing runs every cleanup step even if one fails. Cleanup failures are attached as notes to the exception that caused the close, never masking it.
  • Atomic creation. AccessDatabase.create() builds in a hidden sibling file and moves it into place only on success. Tables are created all-or-nothing, and forms are built under a temporary name and swapped in.
  • No hangs on hidden dialogs. A watchdog watches the windows of our Access process. Unexpected dialogs are dismissed and reported as AccessDialogError with their text. Calls that exceed call_timeout end the owned process, and Ctrl+C works during long calls.
  • No startup code by default. Databases are opened with macros disabled. Read-only sessions never open the database in the Access UI, so AutoExec and startup forms do not run.

Errors you can act on

COM errors are translated into specific exceptions. Each one carries what PyAccessKit was doing, the object involved, and the original Access or DAO error:

from pyaccesskit import AccessDatabase, IntegrityViolationError

with AccessDatabase.open("crm.accdb") as db:
    try:
        db.execute("INSERT INTO Orders (CustomerID, Total) VALUES (999, 10)")
    except IntegrityViolationError as exc:
        print(exc)  # what failed, with Access's own explanation
        print(exc.details.number)  # 3201: there is no related record in Customers

Most mistakes are caught before Access is involved at all. A duplicate table name, an unknown column in a relationship, or incompatible key types each raise a precise ObjectExistsError, SpecError or RelationshipError.

Command line

pyaccesskit doctor [--json] [--probe]      # environment report (exit code 3 if nothing works)
pyaccesskit inspect DB [--json] [--counts] # tables, relationships, queries, objects; read-only
pyaccesskit cleanup [--dry-run] [--json]   # end orphaned Access processes started by PyAccessKit
pyaccesskit guide [--path]                 # the guide for AI coding agents
pyaccesskit schema [KIND]                  # JSON Schema of the specs

Exit codes: 0 success, 1 error, 2 usage error, 3 environment unusable.

Documentation

License

MIT. See LICENSE.

Release files for pyaccesskit 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyaccesskit 0.1.0
File Size Uploaded
pyaccesskit-0.1.0.tar.gz 246.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyaccesskit 0.1.0
File Interpreter ABI Platform
pyaccesskit-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 422.3 kB

Release files / pyaccesskit-0.1.0.tar.gz

Download URL pyaccesskit-0.1.0.tar.gz
Size 246.1 kB
Tags Source
SHA-256 checksum
How to use checksums
359b073fbe07e0a53025f0fb227aa99a223b0bcdb4ce732578478f5e8ff78391
BLAKE2b-256 checksum
How to use checksums
dd533208819c45febae66ab1a7b3d8ba174a3e7d35d28662dee93da7354a7a09
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release files / pyaccesskit-0.1.0-py3-none-any.whl

Download URL pyaccesskit-0.1.0-py3-none-any.whl
Size 176.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2d7bc6025327746b395f32f3b2f57ab1f96e51a4ae562cc76a51122a66f25c42
BLAKE2b-256 checksum
How to use checksums
909388e43ed1a71e91d04346ba7680e3a61f2e8d2201085eeddbaaf8909e1b62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release 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