Search code examples
pythonmongodbpython-attrs

Is there a way to access a class field as a property in python?


I've been trying to craft a small "mongodb orm" on top of pymongo with attrs. For this I've found that there's not a way for me to keep a consistent structure through the whole app since pymongo is very permissive by default. Trying to build what I think would add consistency I found a wall that I'm eager to break but don't think is a trivial task at first glance.

Let's say I have define this class:

from attrs import define

@define(slots=True)
class User:

    @define()
    class UserDetails:
        status: UserStatus = UserStatus.ALIVE
        address: str = None

    user_id: CustomTypeId = None
    details: UserDetails = UserDetails()

And this class works great for handling defaults in my app. But when I want to do a query, instead of making:

db[UserCollection].find({'user_id': 'newid', 'details.status': 'ALIVE'})

I want to make

db[UserCollection].find({User.user_id: 'newid', User.details.status: 'ALIVE' })
# or from a class method
db[UserCollection].find({cls.user_id: 'newid', cls.details.status: 'ALIVE' })

However accessing this properties in the class level hasn't been trivial and it gets ugly real fast using external methods. With all of this being said, If I'm breaking a fundamental design of pymongo/python and there's a way to turn this around using a more conventional path, more glad to hear it. Thanks for reading and for your help!


Solution

  • I' the author of cattrs and an attrs maintainer, and I've previously built a Mongo library using these libraries and Pymongo (not open source though) so I can share some tips.

    You can use attrs.fields(User).user_id instead of User.user_id. (You can do from attrs import fields as f to keep it less verbose.) Due to recent changes in Mypy, this approach can have much better static type safety, if done right.