mongospec


Namemongospec JSON
Version 0.1.5 PyPI version JSON
download
home_pageNone
SummaryAsync MongoDB ODM with msgspec integration and automatic collection binding
upload_time2025-08-02 15:53:40
maintainerNone
docs_urlNone
authorNone
requires_python>=3.13
licenseNone
keywords mongodb odm async database asyncio msgspec mongojet
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <p align="center">
  <img src="assets/logo.svg" width="35%" alt="mongospec"/>
</p>

[![PyPI](https://img.shields.io/pypi/v/mongospec?color=blue&label=PyPI%20package)](https://pypi.org/project/mongospec/)
[![Python](https://img.shields.io/badge/python-3.13%2B-blue)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)

Minimal **async** MongoDB ODM built for *speed* and *simplicity*, featuring automatic collection binding,
[msgspec](https://github.com/jcrist/msgspec) integration, and first-class asyncio support.

---

## Table of Contents

1. [Installation](#installation)  
2. [Quick Start](#quick-start)  
3. [Examples](#examples)  
4. [Key Features](#key-features)  
5. [Core Concepts](#core-concepts)  
   - [Document Models](#document-models)  
   - [Connection Management](#connection-management)  
   - [Collection Binding](#collection-binding)  
   - [CRUD Operations](#crud-operations)  
   - [Indexes](#indexes)  
6. [Contributing](#contributing)  
7. [License](#license)

---

## Installation

```bash
pip install mongospec
```

Requires **Python 3.13+** and a running MongoDB 6.0+ server.

---

## Quick Start

```python
import asyncio
from datetime import datetime
from typing import ClassVar, Sequence

import mongojet
import msgspec

import mongospec
from mongospec import MongoDocument
from mongojet import IndexModel


class User(MongoDocument):
    __collection_name__ = "users"
    __indexes__: ClassVar[Sequence[IndexModel]] = [
        IndexModel(keys=[("email", 1)], options={"unique": True})
    ]

    name: str
    email: str
    created_at: datetime = msgspec.field(default_factory=datetime.now)


async def main() -> None:
    client = await mongojet.create_client("mongodb://localhost:27017")
    await mongospec.init(client.get_database("example_db"), document_types=[User])

    user = User(name="Alice", email="alice@example.com")
    await user.insert()
    print("Inserted:", user)

    fetched = await User.find_one({"email": "alice@example.com"})
    print("Fetched:", fetched)

    await fetched.delete()
    await mongospec.close()


if __name__ == "__main__":
    asyncio.run(main())
```

---

## Examples

All other usage examples have been moved to standalone scripts in the
[`examples/`](./examples) directory.
Each file is self-contained and can be executed directly:

| Script                     | What it covers                               |
|----------------------------|----------------------------------------------|
| `quick_start.py`           | End-to-end “hello world”                     |
| `document_models.py`       | Defining typed models & indexes              |
| `connection_management.py` | Initialising the ODM and binding collections |
| `collection_binding.py`    | Using models immediately after init          |
| `index_creation.py`        | Unique, compound & text indexes              |
| `create_documents.py`      | Single & bulk inserts, conditional insert    |
| `read_documents.py`        | Queries, cursors, projections                |
| `update_documents.py`      | Field updates, atomic & versioned updates    |
| `delete_documents.py`      | Single & batch deletes                       |
| `count_documents.py`       | Fast counts & estimated counts               |
| `working_with_cursors.py`  | Batch processing large result sets           |
| `batch_operations.py`      | Bulk insert / update / delete                |
| `atomic_updates.py`        | Optimistic-locking with version field        |
| `upsert_operations.py`     | Upsert via `save` and `update_one`           |
| `projection_example.py`    | Field selection for performance              |

---

## Key Features

* **Zero-boilerplate models** – automatic collection resolution & binding.
* **Async first** – built on `mongojet`, fully `await`-able API.
* **Typed & fast** – data classes powered by `msgspec` for
  ultra-fast (de)serialization.
* **Declarative indexes** – define indexes right on the model with
  familiar `pymongo`/`mongojet` `IndexModel`s.
* **Batteries included** – helpers for common CRUD patterns, bulk and
  atomic operations, cursors, projections, upserts and more.

---

## Core Concepts

### Document Models

Define your schema by subclassing **`MongoDocument`**
and adding typed attributes.
See **[`examples/document_models.py`](./examples/document_models.py)**.

### Connection Management

Initialise once with `mongospec.init(...)`, passing a
`mongojet.Database` and the list of models to bind.
See **[`examples/connection_management.py`](./examples/connection_management.py)**.

### Collection Binding

After initialisation every model knows its collection and can be used
immediately – no manual wiring required.
See **[`examples/collection_binding.py`](./examples/collection_binding.py)**.

### CRUD Operations

The `MongoDocument` class (and its mixins) exposes a rich async CRUD API:
`insert`, `find`, `update`, `delete`, `count`, cursors, bulk helpers,
atomic `find_one_and_update`, upserts, etc.
See scripts in `examples/` grouped by operation type.

### Indexes

Declare indexes in `__indexes__` as a `Sequence[IndexModel]`
(unique, compound, text, …).
Indexes are created automatically at init time.
See **[`examples/index_creation.py`](./examples/index_creation.py)**.

### Automatic Discovery of Document Models

In addition to manually listing document classes when calling `mongospec.init(...)`, you can use the utility function `collect_document_types(...)` to automatically discover all models in a package:

```python
from mongospec.utils import collect_document_types

document_types = collect_document_types("myapp.db.models")
await mongospec.init(db, document_types=document_types)

```

This function supports:

* Recursive import of all submodules in the target package
* Filtering by base class (default: `MongoDocument`)
* Optional exclusion of abstract or re-exported classes
* Regex or callable-based module filtering
* Graceful handling of import errors

**Usage Example:**

```python
from mongospec.utils import collect_document_types

# Collect all document models in `myapp.db.models` and its submodules
models = collect_document_types(
    "myapp.db.models",
    ignore_abstract=True,
    local_only=True,
    on_error="warn",
)

await mongospec.init(db, document_types=models)
```

**Advanced options include:**

* `predicate=...` to filter only specific model types
* `return_map=True` to get a `{qualified_name: class}` dict
* `module_filter=".*models.*"` to restrict traversal

See the full function signature in [`mongospec/utils.py`](./mongospec/utils.py).

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mongospec",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.13",
    "maintainer_email": null,
    "keywords": "mongodb, odm, async, database, asyncio, msgspec, mongojet",
    "author": null,
    "author_email": "Diprog <diprog991@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/1a/45/274ea5082d1487996bf38c5973bdbbb70b289cd60f96329f03d24a27d538/mongospec-0.1.5.tar.gz",
    "platform": null,
    "description": "<p align=\"center\">\r\n  <img src=\"assets/logo.svg\" width=\"35%\" alt=\"mongospec\"/>\r\n</p>\r\n\r\n[![PyPI](https://img.shields.io/pypi/v/mongospec?color=blue&label=PyPI%20package)](https://pypi.org/project/mongospec/)\r\n[![Python](https://img.shields.io/badge/python-3.13%2B-blue)](https://www.python.org/downloads/)\r\n[![License](https://img.shields.io/badge/license-MIT-green)](https://opensource.org/licenses/MIT)\r\n\r\nMinimal **async** MongoDB ODM built for *speed* and *simplicity*, featuring automatic collection binding,\r\n[msgspec](https://github.com/jcrist/msgspec) integration, and first-class asyncio support.\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n1. [Installation](#installation)  \r\n2. [Quick Start](#quick-start)  \r\n3. [Examples](#examples)  \r\n4. [Key Features](#key-features)  \r\n5. [Core Concepts](#core-concepts)  \r\n   - [Document Models](#document-models)  \r\n   - [Connection Management](#connection-management)  \r\n   - [Collection Binding](#collection-binding)  \r\n   - [CRUD Operations](#crud-operations)  \r\n   - [Indexes](#indexes)  \r\n6. [Contributing](#contributing)  \r\n7. [License](#license)\r\n\r\n---\r\n\r\n## Installation\r\n\r\n```bash\r\npip install mongospec\r\n```\r\n\r\nRequires **Python 3.13+** and a running MongoDB 6.0+ server.\r\n\r\n---\r\n\r\n## Quick Start\r\n\r\n```python\r\nimport asyncio\r\nfrom datetime import datetime\r\nfrom typing import ClassVar, Sequence\r\n\r\nimport mongojet\r\nimport msgspec\r\n\r\nimport mongospec\r\nfrom mongospec import MongoDocument\r\nfrom mongojet import IndexModel\r\n\r\n\r\nclass User(MongoDocument):\r\n    __collection_name__ = \"users\"\r\n    __indexes__: ClassVar[Sequence[IndexModel]] = [\r\n        IndexModel(keys=[(\"email\", 1)], options={\"unique\": True})\r\n    ]\r\n\r\n    name: str\r\n    email: str\r\n    created_at: datetime = msgspec.field(default_factory=datetime.now)\r\n\r\n\r\nasync def main() -> None:\r\n    client = await mongojet.create_client(\"mongodb://localhost:27017\")\r\n    await mongospec.init(client.get_database(\"example_db\"), document_types=[User])\r\n\r\n    user = User(name=\"Alice\", email=\"alice@example.com\")\r\n    await user.insert()\r\n    print(\"Inserted:\", user)\r\n\r\n    fetched = await User.find_one({\"email\": \"alice@example.com\"})\r\n    print(\"Fetched:\", fetched)\r\n\r\n    await fetched.delete()\r\n    await mongospec.close()\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    asyncio.run(main())\r\n```\r\n\r\n---\r\n\r\n## Examples\r\n\r\nAll other usage examples have been moved to standalone scripts in the\r\n[`examples/`](./examples) directory.\r\nEach file is self-contained and can be executed directly:\r\n\r\n| Script                     | What it covers                               |\r\n|----------------------------|----------------------------------------------|\r\n| `quick_start.py`           | End-to-end \u201chello world\u201d                     |\r\n| `document_models.py`       | Defining typed models & indexes              |\r\n| `connection_management.py` | Initialising the ODM and binding collections |\r\n| `collection_binding.py`    | Using models immediately after init          |\r\n| `index_creation.py`        | Unique, compound & text indexes              |\r\n| `create_documents.py`      | Single & bulk inserts, conditional insert    |\r\n| `read_documents.py`        | Queries, cursors, projections                |\r\n| `update_documents.py`      | Field updates, atomic & versioned updates    |\r\n| `delete_documents.py`      | Single & batch deletes                       |\r\n| `count_documents.py`       | Fast counts & estimated counts               |\r\n| `working_with_cursors.py`  | Batch processing large result sets           |\r\n| `batch_operations.py`      | Bulk insert / update / delete                |\r\n| `atomic_updates.py`        | Optimistic-locking with version field        |\r\n| `upsert_operations.py`     | Upsert via `save` and `update_one`           |\r\n| `projection_example.py`    | Field selection for performance              |\r\n\r\n---\r\n\r\n## Key Features\r\n\r\n* **Zero-boilerplate models** \u2013 automatic collection resolution & binding.\r\n* **Async first** \u2013 built on `mongojet`, fully `await`-able API.\r\n* **Typed & fast** \u2013 data classes powered by `msgspec` for\r\n  ultra-fast (de)serialization.\r\n* **Declarative indexes** \u2013 define indexes right on the model with\r\n  familiar `pymongo`/`mongojet` `IndexModel`s.\r\n* **Batteries included** \u2013 helpers for common CRUD patterns, bulk and\r\n  atomic operations, cursors, projections, upserts and more.\r\n\r\n---\r\n\r\n## Core Concepts\r\n\r\n### Document Models\r\n\r\nDefine your schema by subclassing **`MongoDocument`**\r\nand adding typed attributes.\r\nSee **[`examples/document_models.py`](./examples/document_models.py)**.\r\n\r\n### Connection Management\r\n\r\nInitialise once with `mongospec.init(...)`, passing a\r\n`mongojet.Database` and the list of models to bind.\r\nSee **[`examples/connection_management.py`](./examples/connection_management.py)**.\r\n\r\n### Collection Binding\r\n\r\nAfter initialisation every model knows its collection and can be used\r\nimmediately \u2013 no manual wiring required.\r\nSee **[`examples/collection_binding.py`](./examples/collection_binding.py)**.\r\n\r\n### CRUD Operations\r\n\r\nThe `MongoDocument` class (and its mixins) exposes a rich async CRUD API:\r\n`insert`, `find`, `update`, `delete`, `count`, cursors, bulk helpers,\r\natomic `find_one_and_update`, upserts, etc.\r\nSee scripts in `examples/` grouped by operation type.\r\n\r\n### Indexes\r\n\r\nDeclare indexes in `__indexes__` as a `Sequence[IndexModel]`\r\n(unique, compound, text, \u2026).\r\nIndexes are created automatically at init time.\r\nSee **[`examples/index_creation.py`](./examples/index_creation.py)**.\r\n\r\n### Automatic Discovery of Document Models\r\n\r\nIn addition to manually listing document classes when calling `mongospec.init(...)`, you can use the utility function `collect_document_types(...)` to automatically discover all models in a package:\r\n\r\n```python\r\nfrom mongospec.utils import collect_document_types\r\n\r\ndocument_types = collect_document_types(\"myapp.db.models\")\r\nawait mongospec.init(db, document_types=document_types)\r\n\r\n```\r\n\r\nThis function supports:\r\n\r\n* Recursive import of all submodules in the target package\r\n* Filtering by base class (default: `MongoDocument`)\r\n* Optional exclusion of abstract or re-exported classes\r\n* Regex or callable-based module filtering\r\n* Graceful handling of import errors\r\n\r\n**Usage Example:**\r\n\r\n```python\r\nfrom mongospec.utils import collect_document_types\r\n\r\n# Collect all document models in `myapp.db.models` and its submodules\r\nmodels = collect_document_types(\r\n    \"myapp.db.models\",\r\n    ignore_abstract=True,\r\n    local_only=True,\r\n    on_error=\"warn\",\r\n)\r\n\r\nawait mongospec.init(db, document_types=models)\r\n```\r\n\r\n**Advanced options include:**\r\n\r\n* `predicate=...` to filter only specific model types\r\n* `return_map=True` to get a `{qualified_name: class}` dict\r\n* `module_filter=\".*models.*\"` to restrict traversal\r\n\r\nSee the full function signature in [`mongospec/utils.py`](./mongospec/utils.py).\r\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Async MongoDB ODM with msgspec integration and automatic collection binding",
    "version": "0.1.5",
    "project_urls": {
        "Bug Tracker": "https://github.com/diprog/mongospec/issues",
        "Documentation": "https://github.com/diprog/mongospec#readme",
        "Repository": "https://github.com/diprog/mongospec"
    },
    "split_keywords": [
        "mongodb",
        " odm",
        " async",
        " database",
        " asyncio",
        " msgspec",
        " mongojet"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7fd127a9094790d4277ef122f620c466880fb1e88382fbbfaa9d949684ed8d2e",
                "md5": "5e5859d408d325a975c6f5380cefaaae",
                "sha256": "2b740ec5f4ce169778d03eaf7f5b1d3353312bd74451db14639d8e332a40a2eb"
            },
            "downloads": -1,
            "filename": "mongospec-0.1.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5e5859d408d325a975c6f5380cefaaae",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.13",
            "size": 32755,
            "upload_time": "2025-08-02T15:53:39",
            "upload_time_iso_8601": "2025-08-02T15:53:39.635178Z",
            "url": "https://files.pythonhosted.org/packages/7f/d1/27a9094790d4277ef122f620c466880fb1e88382fbbfaa9d949684ed8d2e/mongospec-0.1.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1a45274ea5082d1487996bf38c5973bdbbb70b289cd60f96329f03d24a27d538",
                "md5": "2762618e4e278921383665246e914093",
                "sha256": "e4fe1f7ed1162a79a739d96b92c95772660dbd7b2337a1f29b0564a7355e1bf2"
            },
            "downloads": -1,
            "filename": "mongospec-0.1.5.tar.gz",
            "has_sig": false,
            "md5_digest": "2762618e4e278921383665246e914093",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.13",
            "size": 22852,
            "upload_time": "2025-08-02T15:53:40",
            "upload_time_iso_8601": "2025-08-02T15:53:40.958860Z",
            "url": "https://files.pythonhosted.org/packages/1a/45/274ea5082d1487996bf38c5973bdbbb70b289cd60f96329f03d24a27d538/mongospec-0.1.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-02 15:53:40",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "diprog",
    "github_project": "mongospec",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "mongospec"
}
        
Elapsed time: 0.81641s