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.2.tar.gz (286.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.2-cp311-abi3-win_amd64.whl (2.5 MB view details)

Uploaded CPython 3.11+Windows x86-64

fastdbf-0.5.2-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.2-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.2-cp311-abi3-macosx_11_0_arm64.whl (2.1 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

fastdbf-0.5.2-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.2.tar.gz.

File metadata

  • Download URL: fastdbf-0.5.2.tar.gz
  • Upload date:
  • Size: 286.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.2.tar.gz
Algorithm Hash digest
SHA256 c42666782d792a5a6dbfde2fe27420b94e776c8d4fe513756fb3c5fd324b042b
MD5 1237128601e014f55709e8052b57635e
BLAKE2b-256 e6dc9eabef8738c8f692054091fd97098a92dce749567327e3b04c9678b7f1fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2.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.2-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: fastdbf-0.5.2-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.2-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 72458d490dacf375619da3a7f13d53ea468a8659b9dbb0118005337d4032f7f5
MD5 80e91e4d772c614b4303da13ab4c94c6
BLAKE2b-256 7760c940268315a4cfe03d858f01c16a82ada8cd8ef0bba759a51516865c3a76

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2-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.2-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.2-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 ed50d67cb1eb1dc1b3da5e2cbbadf2d3575f28ce9a3cfa3011e12aec128e4876
MD5 75465140969a204550f3ff082baf7726
BLAKE2b-256 11508513b71df56a4e49eb802de78f6a342bcc49f52e6f0e2605329324025346

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2-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.2-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.2-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 efea2ace9c4c2aa48c47950c6081258e9d592bab6340e83a5a5ea4aa3cac2a5b
MD5 938bdf9bdbce6c8a714a4877eec8ffdd
BLAKE2b-256 a66ddc688b16943baf040ad6c4d9cc191f35c077c7ed6f309a650ea10450dd20

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2-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.2-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.2-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f31d7fc00f9b8da76c11ba70c39780a4b0f983f67f9e3211cd5cc3daf663a6a1
MD5 c8f4ace7f99499dc4d39942bc1c3466f
BLAKE2b-256 e8486cb6fda428e32da37b2cceb3ffcfce552f7942cac518381e8093685f186b

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2-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.2-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for fastdbf-0.5.2-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1766d901488c40fb04e33540951fc1eb047153d191d15ad5d23e2dbe971dbd62
MD5 653921cbc134b675f18347e3280a5238
BLAKE2b-256 a3fe8c4dd4afd3e2dd25cd61420afe63959e2a9288abfe924fac62bfd12d2154

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastdbf-0.5.2-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