Skip to main content

Statically typed asynchronous MongoDB collections with Pydantic models and Motor engine.

Project description

PyMotyc

Statically typed asynchronous MongoDB collections with Pydantic models and Motor engine.

Motyc stands for MOngodb TYped Collections, and also is diminutive for the word 'motocycle' in Russian, which, of course, also has a motor!

Main idea of the library is to use Pydantic models to statically type MongoDB collections to automate parsing documents from collection to models instances (and vise versa) and also enable static type checking for saved and retrieved objects, which brings handy IDE support for attributes access etc.

Documentation

See README.md on GitHub.

Example

import asyncio

from motor.motor_asyncio import AsyncIOMotorClient
from pydantic import BaseModel

import pymotyc


class Employee(BaseModel):
    name: str
    age: int


class Warehouse:
    employees: pymotyc.Collection[Employee]


async def main():
    motor = AsyncIOMotorClient("mongodb://127.0.0.1:27017")
    await pymotyc.Engine().bind(motor=motor, databases=[Warehouse])

    await Warehouse.employees.collection.drop()

    vasya = await Warehouse.employees.save(Employee(name='Vasya Pupkin', age=42)) 
    # IDE already knows there, that vasya is of Employee type

    assert isinstance(vasya, Employee) 

    employees = await Warehouse.employees.find()
    assert employees == [Employee(name='Vasya Pupkin', age=42)]


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

Features

  • Declarative MongoDB databases with statically typed (by Pydantic models) collections with save, find, find_one, update, delete_one built-in methods and a bunch of utility methods to deal with raw Motor collections.

  • One collection can be typed with Discriminated Union to hold different documents corresponded to several models. Retrieved documents will be converted to correct model classes instances thanks to Pydantic.

  • Automation of routine procedures for collections management, like indexes creation.

  • Flexible identity management of documents in the collection:

    • MongoDB's _id field injection to model, even if it has no one (detached id),
    • id field of type bson.ObjectId (with alias='_id', limitation of Pydantic), which represents MongoDB's _id field (the model should be properly configured or inherited from pymotyc.WithId trait),
    • auto-generation of identity with callable provided (uuid in str representation by default, actually this is the most convenient method),
    • client-managed identity field, index is created to guaranty identity uniques.
  • pymotyc.MotycModel base class (and pymotyc.WithId trait) to hold relation of the model instance with collection it was retrieved from, this allows to modify model instance and call save directly on instance itself.

  • Direct access to Motor's collection, which allows to rely on original MongoDB API and then use typed collection utility methods to parse retrieved documents to model instances.

Experimental

Another part of PyMotyc is so-called refactorable queries. The idea is when you type the query like

await collection.find({'foo': 'bar'})

you have no relation between key 'foo' in the dict and model's (with which collection is typed) field foo, so when you rename field IDE have no idea, in which queries this field is used.

PyMotyc allows to use model's fields as keys in queries in built-in typed collection methods.

To enable this feature one should use inject_motyc_fields=True in Engine.bind method, so query in example above can be re-written like this:

    ...
    await pymotyc.Engine().bind(motor=motor, databases=[Warehouse], inject_motyc_fields=True)
    ...
    employees = await Warehouse.employees.find({Employee.age: 42})
    assert employees == [Employee(name='Vasya Pupkin', age=42)]

Now one can rename model's field age with refactor feature of the IDE and IDE automatically will rename keys in correspondent queries! Also, one can click on age field and see all usages in queries.

For this feature PyMotyc uses dirty trick, that's why feature should be considered as experimental.

Using the fact, that Pydantic already initialized all its internal structures during model class creation, PyMotyc replaces model's class attributes with pymotyc.MotycField class instances, which holds all necessary field's info like name alias etc, and then parses queries, searching for MotycField in them.

PyMotyc also have simple query builder. One can use MotycFields in logical expressions, as well as use methods like regexp directly on them. This will form MotycQuery as result, which then will be converted to MongoDB query by PyMotyc. To use models fields with injected MotycFields in logical expression they should be cast to MotycField explicitly to calm down the IDE. One can use pymotyc.M helper for this.

    employees = await Warehouse.employees.find(M(Employee.name).regex('Vasya') & M(Employee.age) == 42)
    assert employees == [Employee(name='Vasya Pupkin', age=42)]

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

pymotyc-0.9.0.tar.gz (15.6 kB view details)

Uploaded Source

Built Distribution

pymotyc-0.9.0-py3-none-any.whl (14.6 kB view details)

Uploaded Python 3

File details

Details for the file pymotyc-0.9.0.tar.gz.

File metadata

  • Download URL: pymotyc-0.9.0.tar.gz
  • Upload date:
  • Size: 15.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.7.6

File hashes

Hashes for pymotyc-0.9.0.tar.gz
Algorithm Hash digest
SHA256 f0f0c28a70be049f618a3c967f35c74c7badf140eec02cae63c50d903bfd06eb
MD5 320fd60586d9b6e84f23258dfdb9ebe5
BLAKE2b-256 3b10d5f929b720b5b49054ad5ba02667f633a6788ef536530f5eda089311fef2

See more details on using hashes here.

File details

Details for the file pymotyc-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: pymotyc-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 14.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.0.1 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.59.0 CPython/3.7.6

File hashes

Hashes for pymotyc-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 62c1fe0d04ccbbe33551b4f0b0fee0c2fcdfe8bcbcd1a4d22fbb8cdafcdd8931
MD5 66abccd5c8a2131ea007e04038fb14d6
BLAKE2b-256 42d2cb55a46102c96e48c7f4320ebc77d0127f6589e24c5b9bdcf37073f65b0a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page