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

Uploaded CPython 3.11+Windows x86-64

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

Uploaded CPython 3.11+macOS 11.0+ ARM64

fastdbf-0.5.1-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.1.tar.gz.

File metadata

  • Download URL: fastdbf-0.5.1.tar.gz
  • Upload date:
  • Size: 286.3 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.1.tar.gz
Algorithm Hash digest
SHA256 580b5e7b7e27ae599364673967cff55f0725fc7ce3263d66438a27b51446455c
MD5 0d3c8169a1faa959b92352ad0a855d39
BLAKE2b-256 46c80a40fa721a36f18edc2be07b72f5e70e7143fe3e005904f1588e96de2fa4

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: fastdbf-0.5.1-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.1-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 647f0c1361d31fe20ec783e244a032e7e0a634257eb9320076ef3681a3de02b5
MD5 aeac50727e77212e8f653c57163278ee
BLAKE2b-256 221be9d51b8c31788e0b8d7353982f2203e2e6adac29e20ee4cbb9c95c353f4d

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for fastdbf-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e50a02e58b0ef117ac695a9ada64806e7624c6adf53f9981ec91f6c603c0f31a
MD5 610596b0d37ea7c5985f7f474604e63c
BLAKE2b-256 e9a34db226f7a3913610ae7d00de4b0643cfddd5b95d9c54c8a6951b3abaa7d3

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for fastdbf-0.5.1-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 0caa79427094cfda75fb8b69458fc3d5814f2eaaf6c479cef7a0cdf8c065dc95
MD5 2bb0537af848fcd603413d13c774ac72
BLAKE2b-256 09d249a93b306de49f0fea9baef55208ea5fccac4cd61f59e7b328ece43908f0

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for fastdbf-0.5.1-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 379360271854c9cbae490a0557549cb7e9100bea39ea2b3a8db198eb40687f8c
MD5 8aa3093793d4429f23a9cfe989b7f863
BLAKE2b-256 b12d6fa0286ca2a6d84b61cb9f6362590778a216440386ac3ebb2b3fbda11e0a

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for fastdbf-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 3d9ac94edffbee1cdffe67447e0da146f4b8b92d04f59c02e3e747ce196f734a
MD5 10da26e7ccbcf9f393f53358e508510e
BLAKE2b-256 ac167ba1a7ed995b42bc1bc41f148c902ebeb8dc475532da71e557373eb32f63

See more details on using hashes here.

Provenance

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