A Python package to manipulate dictionaries like databases.
Project description
DictDB is an in-memory, dictionary-based database for Python with SQL-like CRUD operations, optional schemas, fast lookups via indexes, and a fluent query DSL.
Perfect for prototyping, testing, and lightweight relational workflows without a full database engine.
Features
- SQL-like CRUD —
INSERT,SELECT,UPDATE,DELETEwith familiar semantics - Fluent Query DSL — Build conditions with Python operators:
table.age >= 18 - Indexes — Hash indexes for O(1) equality lookups, sorted indexes for range queries
- Optional Schemas — Type validation when you need it, flexibility when you don't
- Persistence — Save/load to JSON or Pickle
- Thread-Safe — Reader-writer locks for concurrent access
- Zero Config — No server, no setup, just Python
Installation
pip install dctdb
from dictdb import DictDB, Condition
Note: The PyPI package is
dctdb, but the import name isdictdb.
Development Setup
git clone https://github.com/mhbxyz/dictdb.git
cd dictdb
make setup
Quickstart
Basic CRUD
from dictdb import DictDB, Condition
# Create database and table
db = DictDB()
db.create_table("employees", primary_key="emp_id")
employees = db.get_table("employees")
# Insert records (auto-assigns emp_id if missing)
employees.insert({"emp_id": 101, "name": "Alice", "department": "IT", "salary": 75000})
employees.insert({"name": "Bob", "department": "HR", "salary": 65000})
employees.insert({"name": "Charlie", "department": "IT", "salary": 85000})
employees.insert({"name": "Diana", "department": "Sales", "salary": 70000})
# Select all
all_employees = employees.select()
# Update records
employees.update({"salary": 68000}, where=Condition(employees.name == "Bob"))
# Delete records
employees.delete(where=Condition(employees.name == "Diana"))
Query DSL
# Comparison operators: ==, !=, <, <=, >, >=
seniors = employees.select(where=Condition(employees.salary >= 80000))
# Logical AND
it_seniors = employees.select(
where=Condition((employees.department == "IT") & (employees.salary >= 80000))
)
# Logical OR
it_or_hr = employees.select(
where=Condition((employees.department == "IT") | (employees.department == "HR"))
)
# IN operator
tech_teams = employees.select(
where=Condition(employees.department.is_in(["IT", "Engineering", "Data"]))
)
# String matching
employees.select(where=Condition(employees.name.startswith("A")))
employees.select(where=Condition(employees.name.contains("li")))
Sorting & Pagination
# Order by salary descending
top_earners = employees.select(order_by="-salary")
# Multi-field sort: department asc, then salary desc
sorted_employees = employees.select(order_by=["department", "-salary"])
# Pagination
page_size = 10
page = 2
paginated = employees.select(
order_by="name",
limit=page_size,
offset=(page - 1) * page_size
)
Column Projection
# Select specific columns
names = employees.select(columns=["name", "department"])
# [{"name": "Alice", "department": "IT"}, ...]
# Column aliasing
aliased = employees.select(columns={"employee": "name", "team": "department"})
# [{"employee": "Alice", "team": "IT"}, ...]
Schema Validation
# Define schema for type enforcement
schema = {"emp_id": int, "name": str, "department": str, "salary": int}
db.create_table("staff", primary_key="emp_id", schema=schema)
staff = db.get_table("staff")
staff.insert({"emp_id": 1, "name": "Alice", "department": "IT", "salary": 75000}) # OK
staff.insert({"emp_id": 2, "name": "Bob", "department": "HR", "salary": "high"}) # Raises SchemaValidationError
Indexes
# Hash index for O(1) equality lookups
employees.create_index("department", index_type="hash")
employees.select(where=Condition(employees.department == "IT")) # Fast
# Sorted index for range queries
employees.create_index("salary", index_type="sorted")
employees.select(where=Condition(employees.salary > 70000)) # Fast
employees.select(where=Condition(employees.salary <= 80000)) # Fast
# Check indexes
employees.indexed_fields() # ["department", "salary"]
employees.has_index("salary") # True
Persistence
# Save to JSON (human-readable)
db.save("employees.json", file_format="json")
# Save to Pickle (faster, binary)
db.save("employees.pkl", file_format="pickle")
# Load from disk
db2 = DictDB.load("employees.json", file_format="json")
# Async I/O for non-blocking operations
import asyncio
asyncio.run(db.async_save("employees.json", file_format="json"))
Introspection
# Table metadata
employees.columns() # ["emp_id", "name", "department", "salary"]
employees.count() # 3
employees.primary_key_name() # "emp_id"
# Database metadata
db.list_tables() # ["employees", "staff"]
Documentation
Full documentation available at mhbxyz.github.io/dictdb
| Section | Description |
|---|---|
| Getting Started | Installation and first steps |
| Query DSL | Build conditions with Python operators |
| Indexes | Speed up queries |
| Schemas | Type validation |
| Persistence | Save and load databases |
| API Reference | Complete API documentation |
Development
# Setup environment
make setup
make hooks-install
# Run all checks (format, lint, types, tests)
make check
# Run tests with coverage
make coverage
# Run benchmarks
make benchmark
License
Apache License 2.0 — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dctdb-1.0.0.tar.gz.
File metadata
- Download URL: dctdb-1.0.0.tar.gz
- Upload date:
- Size: 185.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96b0836d4856e42c83020abc7c1b2710b6a988c6ecbbc4f861d7bf24c08a886f
|
|
| MD5 |
80854023babbd04400a9cdb1f84dc998
|
|
| BLAKE2b-256 |
585dcdf6b542362a5b47b11dd6e11b091e201ae196426f1c6dbde0d8fabde1c3
|
Provenance
The following attestation bundles were made for dctdb-1.0.0.tar.gz:
Publisher:
publish.yml on mhbxyz/dictdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dctdb-1.0.0.tar.gz -
Subject digest:
96b0836d4856e42c83020abc7c1b2710b6a988c6ecbbc4f861d7bf24c08a886f - Sigstore transparency entry: 834257042
- Sigstore integration time:
-
Permalink:
mhbxyz/dictdb@06c9107731a10fdb150ad02777af22adebf134fc -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mhbxyz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@06c9107731a10fdb150ad02777af22adebf134fc -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file dctdb-1.0.0-py3-none-any.whl.
File metadata
- Download URL: dctdb-1.0.0-py3-none-any.whl
- Upload date:
- Size: 36.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6985a32e307aa25f84d8585cf178e006d2e0ff47eac50771ea2f70b7a7f24321
|
|
| MD5 |
ec509d51fc721ef1d97c094a68c4c97e
|
|
| BLAKE2b-256 |
4d55b4961c9e56739c407fd819aa7cc2d78c9b4393e531db10c2a2e4e7c7841d
|
Provenance
The following attestation bundles were made for dctdb-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on mhbxyz/dictdb
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dctdb-1.0.0-py3-none-any.whl -
Subject digest:
6985a32e307aa25f84d8585cf178e006d2e0ff47eac50771ea2f70b7a7f24321 - Sigstore transparency entry: 834257045
- Sigstore integration time:
-
Permalink:
mhbxyz/dictdb@06c9107731a10fdb150ad02777af22adebf134fc -
Branch / Tag:
refs/heads/main - Owner: https://github.com/mhbxyz
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@06c9107731a10fdb150ad02777af22adebf134fc -
Trigger Event:
workflow_dispatch
-
Statement type: