Skip to main content

A Python package for reading and writing DBF files, powered by a Rust core

Project description

fastdbf

fastdbf is a high-performance Python package for reading and writing .dbf files.

Written in Rust (using PyO3), it provides standard Python bindings designed specifically for large datasets, where traditional pure-Python solutions (like the standard dbf package) suffer from significant performance bottlenecks.

Performance Time Performance Speedup

Status

fastdbf is fully production-ready for core data exchange workloads.

Supported Features

  • High-Performance I/O: Lightning fast reads and writes of standard .dbf files.
  • Zero-Copy Bulk Transfers: Native Apache Arrow integration (to_arrow(), extend_arrow()) for high-speed exchange with Pandas/Polars.
  • Visual FoxPro Support: Direct handling of VFP .dbf flavors, including mandatory null-flag layouts.
  • Memo Fields: Automatic management of companion .fpt memo files for unbounded strings.
  • Native Type Mapping: Correct Python/Arrow types for dates, datetimes, and integers — no manual casting needed.
  • Strict Typing: Clear data mappings with custom exception classes (DbfFormatError).

Not Implemented yet

  • In-place Schema Modification: Dynamic addition/removal of columns on pre-written tables (currently raises UnsupportedDbfTypeError).
  • Advanced Engine Tools: Indexing, cross-table relationships, or built-in query paradigms.

Installation

Create or sync the development environment with uv:

uv sync

Install into the current environment with uv:

uv pip install .

Editable install:

uv pip install -e .

Run tests:

uv run pytest

Build a wheel:

uv build

Quick Start

Read an existing DBF file:

import fastdbf

with fastdbf.Table("people.dbf").open("r") as table:
    print(table.kind)
    print(table.field_names)
    print(table.record_count)
    print(table.row(0))

    for field in table.fields():
        print(field["name"], field["type_code"], field["nullable"])

    for row in table:
        print(row)

Create and write a new DBF file:

import fastdbf
from datetime import date, datetime

specs = "name C(25) null; age N(3,0) null; birth D null; created T null; active L null"
with fastdbf.Table("people.dbf", specs, dbf_type="vfp") as table:
    table.append({
        "name": "Alice",       # case-insensitive keys
        "age": 30,
        "birth": date(1994, 5, 20),
        "created": datetime(2024, 1, 1, 12, 0),
        "active": True,
    })

    table.append({
        "NAME": None,
        "AGE": None,
        "BIRTH": None,
        "CREATED": None,
        "ACTIVE": None,
    })

Type Mapping

fastdbf maps DBF field types to native Python and Arrow types, so no manual casting is needed in either direction.

DBF → Python / Arrow

DBF Field DBF Type Code Python type Arrow type
Character C str Utf8
Numeric (integer) N(n,0) int Int64
Numeric (decimal) N(n,k) float Float64
Date D datetime.date Date32
DateTime T datetime.datetime Timestamp(ms)
Logical L bool Boolean
Integer I int Int32
Double B float Float64

Python / Pandas → DBF (writing)

append() and extend_arrow() both accept the types listed above, plus Pandas-native types without any manual casting:

Input type DBF field written
datetime.date D (Date)
datetime.datetime T (DateTime)
pandas.Timestamp T (DateTime)
numpy.int64 / int N(n,0) or I
numpy.float64 / float N(n,k) or B

Note: append(dict) is case-insensitive"name", "NAME", and "Name" all resolve to the same DBF field.

Field Types

Currently supported field types:

  • C Character
  • D Date
  • L Logical
  • N Numeric
  • F Float
  • I Integer
  • B Double
  • T / @ DateTime
  • Y Currency
  • M / G / P as reference values

Nullable fields are supported through null or nullable modifiers in the field specification:

"name C(25) null; amount N(10,2) nullable; created T null"

Nullable fields should be used with dbf_type="vfp" for Visual FoxPro-compatible null flags.

Pandas / Arrow Integration

Reading a DBF into Pandas (recommended)

Using the Arrow interface gives correct types directly — no extra dtype conversion needed:

import fastdbf
import pyarrow as pa

with fastdbf.Table("data.dbf").open("r") as table:
    df = pa.record_batch(table.to_arrow()).to_pandas()

# Result:
# - Date fields    → datetime64 (via object column of datetime.date)
# - DateTime fields → datetime64[ms]
# - Numeric(N,0)   → Int64 (no silent float coercion!)
# - Logical        → bool

Writing a Pandas DataFrame to DBF

Method A: Arrow (fastest, recommended for large DataFrames)

import fastdbf
import pyarrow as pa

batch = pa.RecordBatch.from_pandas(df)

with fastdbf.Table("output.dbf", field_specs="NAME C(20); AGE N(10,0); BIRTH D; CREATED T") as table:
    table.extend_arrow(batch)

Method B: Row-by-row append (no dependencies beyond fastdbf)

import fastdbf

with fastdbf.Table("output.dbf", field_specs="NAME C(20); AGE N(10,0); BIRTH D; CREATED T") as table:
    for _, row in df.iterrows():
        table.append(row.to_dict())   # pandas.Timestamp, numpy types accepted natively

The _deleted column

All read methods expose a _deleted: bool column. This reflects the DBF soft-delete flag — a standard DBF concept where records are logically marked as deleted (with a * marker byte) but remain physically in the file until a PACK operation removes them.

# Skip deleted records when reading:
df = df[~df["_deleted"]]

# Mark a record as deleted:
with table.record(0) as rec:
    rec.set_deleted(True)

# Physically remove all deleted records:
table.pack()

Performance & Columnar I/O (Arrow)

For maximum performance, especially with large datasets, fastdbf provides columnar read/write interfaces that avoid the high overhead of Python object allocation.

1. Apache Arrow Interface (Zero-Copy) — Fastest

Leverages the Arrow PyCapsule Interface to exchange data directly between Rust and Pandas / Polars / PyArrow without copying.

Read into Pandas via Arrow:

import fastdbf
import pyarrow as pa

with fastdbf.Table("data.dbf").open("r") as table:
    # Arrow Batch -> Pandas DataFrame
    df = pa.record_batch(table.to_arrow()).to_pandas()

Write from Pandas via Arrow:

import fastdbf
import pyarrow as pa

# Create Arrow batch from DataFrame
batch = pa.RecordBatch.from_pandas(df)

with fastdbf.Table("output.dbf", field_specs="NAME C(20); AGE N(10,2)") as table:
    table.extend_arrow(batch)

2. Columnar Interface (to_columns, extend_columns)

Reads/writes data as a dictionary of lists (one list per column). Faster than row-by-row processing but still bound by GIL limits.

Bulk Columnar Read:

import pandas as pd
import fastdbf

with fastdbf.Table("data.dbf").open("r") as table:
    cols = table.to_columns()
    df = pd.DataFrame(cols)

Bulk Columnar Write:

import pandas as pd
import fastdbf

# Drop internal meta-columns like '_deleted' if present
clean_data = {col: df[col].tolist() for col in df.columns if col != "_deleted"}

with fastdbf.Table("output.dbf", field_specs="NAME C(20); AGE N(10,2)") as table:
    table.extend_columns(clean_data)

Overview: Read/Write Methods compared

Method Implementation Pros
Row-by-Row table.row(), table.append() Easiest to use
Bulk Columnar to_columns(), extend_columns() No heavy dependencies
Zero-Copy Arrow to_arrow(), extend_arrow() Direct memory exchange

Documentation

Full Python API documentation:

Changelog:

Rust Example

use fastdbf::{Date, Table, Value};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut table = Table::new("name C(25); age N(3,0); birth D; qualified L")?;

    let mut record = table.new_record();
    record.insert(table.fields(), "name", Value::Character("Spunky".into()))?;
    record.insert(table.fields(), "age", Value::Numeric(23.0))?;
    record.insert(table.fields(), "birth", Value::Date(Some(Date::new(1989, 7, 23))))?;
    record.insert(table.fields(), "qualified", Value::Logical(Some(true)))?;
    table.push_record(record)?;

    table.write_to_path("example.dbf")?;
    Ok(())
}

License

This project is licensed under the Apache License 2.0.

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

fastdbf-0.5.0.tar.gz (285.6 kB view details)

Uploaded Source

Built Distributions

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

fastdbf-0.5.0-cp311-abi3-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.11+Windows x86-64

fastdbf-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

fastdbf-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ ARM64

fastdbf-0.5.0-cp311-abi3-macosx_11_0_arm64.whl (2.1 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

fastdbf-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl (2.4 MB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file fastdbf-0.5.0.tar.gz.

File metadata

  • Download URL: fastdbf-0.5.0.tar.gz
  • Upload date:
  • Size: 285.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastdbf-0.5.0.tar.gz
Algorithm Hash digest
SHA256 f3ae39a13f9f58600d7a243daef21274d96775bd1823b0e6e978c20ee9e51897
MD5 cb500235882ab5cfc071c519a7e8a19a
BLAKE2b-256 05f89ca0b4c3650383d9e1e6779a354531c427dbe9fff1bf852938ec2787b83f

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0.tar.gz:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

File details

Details for the file fastdbf-0.5.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: fastdbf-0.5.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fastdbf-0.5.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 24899baa7137384bc6141f3b9d2d8699f2befac9a1340179205ec34750d22c18
MD5 5bbfae4d6544d8f57eaa2cea31e92871
BLAKE2b-256 be8f4d082836fe3d3faa1a7778fe5850565588ec446f058109df833075107401

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0-cp311-abi3-win_amd64.whl:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

File details

Details for the file fastdbf-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fbc69df9177339d8ca20138906010e06d7ecc9ab3ea1b70f0b3ea0d57af436c1
MD5 6608690f7259dc52d52fb685015b50cd
BLAKE2b-256 38adacc3f30d7b637782f760d18884e3bdeecd20ca937c743f8fce82008ea7c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

File details

Details for the file fastdbf-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 8c7601f962fbe8710c405dc308aa0be0bb8537e6be3443d4bca83db140b4a49f
MD5 ebc77a5a4fc44c3dfd797584985cbce9
BLAKE2b-256 7f2e204595c2b06f6878a71cfc13f8fdaf4dc2c50b299e60f602633d58d74688

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

File details

Details for the file fastdbf-0.5.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 88a9f6905ea195e8955a0f17bb78dfe41e7f896d16cda3be37418ded59959d8b
MD5 b01d57a48dcd53b68f736c43244c6c24
BLAKE2b-256 35cc0de9dc0d32352a93250c80400d8671ff7eb0f41caea256d9f73545cd311e

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0-cp311-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

File details

Details for the file fastdbf-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 682f22aac3d08694f94e2b425ebbe4173429bb14a0ddb833928a72330ef93b9c
MD5 228d80f6a5e2289d727983a3a6c6c343
BLAKE2b-256 e94195045486b5db943338d171316b91a0f3953c02437e0c2087e6ce36f0984e

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on Jonas-Bruns/fastdbf

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

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