Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

335
Views
Problem with initiating base with child class while working with python-attrs module

I'm trying to create Model class with attrs module. In my script CollectionModel class is inherited in User class. So logically all the attributes in the CollectionModel should be available in the User. But while trying to create a new instance of User from dictionary (it is possible with attrs) it shows that attributes of CollectionModel are not present in the User

My Script:

from bson import ObjectId
from attrs import asdict, define, field, validators, Factory
import time


@define
class CollectionModel:
    """ Base Class For All Collection Schema"""
    _id : str =   field(converter=str, default=Factory(ObjectId))
    _timestamp : float = field(default=Factory(time.time))

    def get_dict(self):
        return asdict(self)

    def update(self):
        self._timestamp = time.time()

@define
class User(CollectionModel):
    
    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))



user_object = User()
new_user_object = User(**asdict(user_object))

Here, I'm trying to create a new User object from the user_object. It shows the following error.

TypeError: User.__init__() got an unexpected keyword argument '_id'

I guessed that the parent class is not initiated at first. So I tried to initiate it with the super() function and according to attrs documentation it should be done with __attrs_pre_init__. From the documentation:

The sole reason for the existence of __attrs_pre_init__ is to give users the chance to call super().__init__(), because some subclassing-based APIs require that.

So the modified child class becomes like this.

@define
class User(CollectionModel):
    
    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))

    def __attrs_pre_init__(self):
        super().__init__()

But the problem still remains. Am I doing the OOP in the wrong way? Or is it just a bug of attrs module?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

I've solved that issue and there were two problems. The first one, in python, underscore before an attribute name makes it a private attribute. So while creating a new instance from dictionary _id is an unexpected key.

The second problem is, I indeed need an _id field as I'm working with MongoDB. In MongoDB document _id is reserved for using as a primary key.

Now the first problem can be solved by replacing _id to id_ (yes, underscore in the opposite side since id is literally a bad choice for a variable name in python).

For the second problem I've searched a lot to make an alias for id_ field. But it is not simply easy while working with attrs module. So I've modified the get_dict() method to get a perfect dictionary before throwing my data in MongoDB collection.

Here is the modified CollectionModel class and User class:

@define
class CollectionModel:
    """ Base Class For All Collection Schema"""
    id_: ObjectId =   field(default=Factory(ObjectId))
    timestamp : float = field(default=Factory(time.time))

    def get_dict(self):
        d = asdict(self)
        d["_id"] = d["id_"]
        del d["id_"]
        return d

    def update(self):
        self.timestamp = time.time()

@define
class User(CollectionModel):

    username : str = field(factory = str, validator=validators.instance_of(str)) 
    userType : str = field(factory = str, validator=validators.instance_of(str)) 
    password : str = field(factory = str, validator=validators.instance_of(str))

Now printing an instance:

user_object = User()
print(user_object.get_dict())

Output:

{'timestamp': 1645131182.421929, 'username': '', 'userType': '', 'password': '', '_id': ObjectId('620eb5ae10f27b87de5be3a9')}
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!