Endless Database with pyyaml and pymongo
Project description
EndlessDB
EndlessDB is a lightweight Python wrapper around MongoDB that lets you work with databases, collections, and documents as dynamic Python objects.
It is a developer tool for scripts, prototypes, fixtures, notebooks, and debugger-friendly workflows. It is not a full ODM and does not try to hide PyMongo.
It keeps MongoDB as the source of truth while making common document access feel natural:
from endlessdb import EndlessConfiguration, EndlessDatabase
class LocalConfiguration(EndlessConfiguration):
def override(self):
self.MONGO_URI = "mongodb://root:root@localhost:27017/"
self.MONGO_DATABASE = "example"
LocalConfiguration.apply()
db = EndlessDatabase()
employees = db.Employee
employees["john"] = {"Name": "John", "Age": 25}
employees["john"].Age = 26
print(employees["john"].Name)
print(employees["john"]().to_dict())
Features
- Dynamic wrappers for MongoDB databases, collections, and documents.
- Attribute and item access for collections and document fields.
- Dot-path writes for nested document values.
- Lazy document wrappers for paths that do not exist until written.
- Strict mode for typo-safe attribute access when you do not want virtual paths.
- Mongo-backed updates for collection items and document properties.
- Explicit patch, replace, unset, and delete operations.
- Query helpers for filters, sorting, limits, offsets, counts, existence checks, and raw PyMongo access.
- Document references stored as DBRef-compatible values.
- Dictionary, JSON, and YAML serialization helpers.
- YAML-based default documents.
- Access to the underlying PyMongo database and collection objects when needed.
- Debugger-friendly string representations for VS Code and other Python debuggers.
Installation
EndlessDB requires Python 3.11 or newer and a reachable MongoDB server.
Install the package from PyPI:
python -m pip install endlessdb
For local examples, you can start MongoDB with Docker Compose from this repository:
docker compose -f samples/docker-compose.yml up -d
Quick Start
Configure the MongoDB connection before creating EndlessDatabase:
from endlessdb import EndlessConfiguration, EndlessDatabase
class AppConfiguration(EndlessConfiguration):
def override(self):
self.MONGO_URI = "mongodb://root:root@localhost:27017/"
self.MONGO_DATABASE = "app"
AppConfiguration.apply()
db = EndlessDatabase()
Collections are available through attributes or item access:
employees = db.Employee
same_collection = db["Employee"]
Documents are addressed by MongoDB _id:
employees["john"] = {"Name": "John", "Age": 25}
john = employees["john"]
Fields can be read and written through attributes or item paths:
john.Age = 26
john["Profile.City"] = "New York"
assert john.Age == 26
assert john.Profile.City == "New York"
Object Model
EndlessDB exposes public wrappers for everyday use:
EndlessDatabaserepresents a MongoDB database.EndlessCollectionrepresents a MongoDB collection.EndlessDocumentrepresents a MongoDB document or nested document path.
Calling a wrapper returns its logic container. Logic containers expose metadata, lower-level Mongo objects, serialization, reload, and delete operations:
db = EndlessDatabase()
collection = db.Employee
document = collection["john"]
print(collection().key())
print(document().path(True))
print(document().mongo())
This split keeps application code compact while still making lower-level operations available when you need them.
Configuration
EndlessConfiguration controls the default MongoDB connection, database name, config collection, and YAML defaults file.
class AppConfiguration(EndlessConfiguration):
def override(self):
self.CONFIG_YML = "config.yml"
self.CONFIG_COLLECTION = "config"
self.MONGO_URI = "mongodb://root:root@localhost:27017/"
self.MONGO_DATABASE = "app"
You can also pass connection values directly when creating a database:
db = EndlessDatabase(
url="mongodb://root:root@localhost:27017/",
database="app",
)
Use strict mode when missing collections, documents, or fields should raise PropertyNotFoundError instead of creating virtual wrappers:
db = EndlessDatabase(
url="mongodb://root:root@localhost:27017/app",
strict=True,
)
References
Assigning one EndlessDocument to another document field stores a reference-like value in MongoDB. When the document is loaded again, EndlessDB resolves it back to an EndlessDocument wrapper.
departments = db.Department
departments["it"] = {"Name": "IT"}
employees["john"].Department = departments["it"]
assert employees["john"].Department == departments["it"]
Querying
Use find_one() and find() from the collection logic container for Mongo-style filters:
employees["john"] = {"Name": "John", "Age": 26}
employees["jane"] = {"Name": "Jane", "Age": 31}
match = employees().find_one({"Name": "Jane"})
matches = list(
employees().find(
{"Age": {"$gte": 25}},
sort=[("Age", -1)],
limit=10,
)
)
find() returns an iterator of EndlessDocument objects. The collection logic also exposes count(), exists(), first(), and raw() for direct PyMongo collection access.
Updating And Deleting
Item assignment keeps patch-compatible $set behavior:
employees["john"] = {"Name": "John", "Age": 25}
employees["john"] = {"Age": 26}
Use explicit methods when the difference matters:
employees().patch("john", {"Role": "developer"})
employees().replace("john", {"Name": "John", "Status": "active"})
employees["john"]().unset("Profile.City")
employees["john"].Profile().delete()
Root document deletion remains explicit:
employees["john"]().delete()
Serialization
Logic containers can export data to dictionaries, JSON, or YAML. Use iter_items() when you need lazy key/value traversal.
data = employees["john"]().to_dict()
items = list(employees["john"]().iter_items())
json_text = employees["john"]().to_json()
yaml_text = employees().to_yml()
Bytes are base64 encoded for JSON. date and datetime values are encoded in ISO format.
YAML Defaults
EndlessDB can load default collections and documents from YAML. This is useful for sample data, local application defaults, and repeatable test fixtures.
Employee:
john:
Name: John
Age: 25
Set CONFIG_YML in your configuration class, then create EndlessDatabase() as usual.
Samples
The samples directory contains runnable examples for the main workflows:
- quickstart collection and document writes;
- nested dot-path updates;
- document references;
- JSON, base64 JSON, and YAML serialization;
- YAML defaults loading;
- debugger-friendly representations;
- strict mode;
- query helpers;
- patch, replace, unset, and delete behavior.
Run a sample from the repository root:
docker compose -f samples/docker-compose.yml up -d
python -m pip install -e .
python samples\01_quickstart.py
Project Status
EndlessDB 0.5.x is focused on making the dynamic MongoDB facade safer and clearer while keeping it small. The current API includes strict mode, dictionary-returning serialization, query helpers, explicit patch/replace semantics, field unset/delete helpers, runnable samples, CI, Ruff checks, and coverage reporting.
Future improvements are intentionally narrow: formatter/type-checking workflow, more negative-path coverage, and better public type hints where they help without hiding the dynamic API.
Development
Create a local virtual environment and install development dependencies:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
Start the integration MongoDB instance:
docker compose -f tests/docker-compose.yml up -d
Run the test suite:
.\.venv\Scripts\python.exe -m pytest tests
Run lint checks:
.\.venv\Scripts\python.exe -m ruff check src tests samples
Pytest writes a terminal coverage summary and coverage.xml through pytest-cov; the current baseline gate is 70%.
Build the package locally:
.\.venv\Scripts\python.exe -m build
GitHub Actions runs tests against Python 3.11, 3.12, and 3.13 with a MongoDB service container, then builds and checks the package distributions.
To create a GitHub Release, commit the version change first, then create and push a v<version> tag. The release workflow verifies that the tag matches pyproject.toml, runs tests, builds the wheel and source distribution, checks them with Twine, and attaches the artifacts to the GitHub Release:
.\scripts\create-github-release-tag.ps1
License
EndlessDB is licensed under the Apache License 2.0. See LICENSE.txt 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 endlessdb-0.5.1.tar.gz.
File metadata
- Download URL: endlessdb-0.5.1.tar.gz
- Upload date:
- Size: 26.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c91b55453caea5aa51ef2ac6f657793d2eeb44977205befa311cac00109341c7
|
|
| MD5 |
87ebdf1b9ce84a69cb81ef4e5c0feaca
|
|
| BLAKE2b-256 |
ee364c37b89fb215c9a404b088ecdd0d41692ddb5bed7edbeb1dbe63af78eaec
|
File details
Details for the file endlessdb-0.5.1-py3-none-any.whl.
File metadata
- Download URL: endlessdb-0.5.1-py3-none-any.whl
- Upload date:
- Size: 22.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05f61f22566efa0c06126e5e1f1ca4cb800bbce659960196dc0959e43a604c1f
|
|
| MD5 |
218376d916f55ed67d9b5882be3a3d6b
|
|
| BLAKE2b-256 |
0469876bf0f04229a3b17ddc8b7c75855bc5b721c7d99cd871f1ba4fb3e39b50
|