admin管理员组

文章数量:1398782

In my situation I get a response from an API which follows the structure of MyGenericModel. After I parse the response using MyGenericModel, I want to check if it belongs to my set defined in MyEnum. If it does I want to continue with it, if not.. then we proceed further.

  • When I call MyGenericModel(value_one="a", value_two="b") in MyEnum I get a TypeError as response.

  • When I call MySpecificModel() in MyEnum I get a TypeError as response.

  • When I call MySpecificModel() == MyGenericModel(value_one="a", value_two="b") I get 'True' as response.

here is a small simplified example of my code:

from pydantic import BaseModel
from enum import Enum


class MyGenericModel(BaseModel):
    value_one: str
    value_two: str
    
    def __eq__(self, other):
        return self.model_dump() == other.model_dump()


class MySpecificModel(MyGenericModel):
    value_one: str = "a"
    value_two: str = "b"


class MyEnum(Enum):
    my_model = MySpecificModel()


# This is true
MyGenericModel(value_one="a", value_two="b")  == MySpecificModel()

# This fails - and I want to be true
MyGenericModel(value_one="a", value_two="b") in MyEnum

How to solve this issue?

In my situation I get a response from an API which follows the structure of MyGenericModel. After I parse the response using MyGenericModel, I want to check if it belongs to my set defined in MyEnum. If it does I want to continue with it, if not.. then we proceed further.

  • When I call MyGenericModel(value_one="a", value_two="b") in MyEnum I get a TypeError as response.

  • When I call MySpecificModel() in MyEnum I get a TypeError as response.

  • When I call MySpecificModel() == MyGenericModel(value_one="a", value_two="b") I get 'True' as response.

here is a small simplified example of my code:

from pydantic import BaseModel
from enum import Enum


class MyGenericModel(BaseModel):
    value_one: str
    value_two: str
    
    def __eq__(self, other):
        return self.model_dump() == other.model_dump()


class MySpecificModel(MyGenericModel):
    value_one: str = "a"
    value_two: str = "b"


class MyEnum(Enum):
    my_model = MySpecificModel()


# This is true
MyGenericModel(value_one="a", value_two="b")  == MySpecificModel()

# This fails - and I want to be true
MyGenericModel(value_one="a", value_two="b") in MyEnum

How to solve this issue?

Share edited Mar 17 at 13:12 zwep asked Mar 14 at 13:55 zwepzwep 1,3381 gold badge13 silver badges27 bronze badges 10
  • Small clarification: MyGenericModel(value_one=“a”, value_two=“c”) and MyGenericModel(value_one=“a”, value_two=“a”) both should throw a validation error, or is it acceptable MyGenericModel(value_one=“a”, value_two=“a”)? – Serhii Fomenko Commented Mar 14 at 14:53
  • Why would those first two examples throw a validation error? – zwep Commented Mar 14 at 15:26
  • Well, for example, I was thinking about this option: your application gets a response from API, and only writes data to the database if MyGenericModel(value_one=“a”, value_two=“b”), for this you could use validators on the pydantic model and check the model try -> MyGenericModel(...); doSomething() -> catch ValidationError -> continue. As I understand your question, is this what you want to do: value not in MyEnum -> then continue? If not, please provide an example of the usage in the question. – Serhii Fomenko Commented Mar 14 at 15:59
  • The error has nothing to do with pydantic and occurs when dealing with any non-hashable enum member (e.g. list). If you don't want to make your model hashable, you can first convert the value ( MyGenericModel ) to the MyEnum type, like this. I am not sure if this is a good practice though. – ken Commented Mar 14 at 16:21
  • 1 I mentioned that including the type of self in the hash calculation causes mismatches. Instead, I suggested calculating the hash using only the field values of self that determine equality. – ken Commented Mar 16 at 17:50
 |  Show 5 more comments

1 Answer 1

Reset to default 0

The problem here was that the 'in' operator was not properly defined in this situation.

The 'in' operator calls the '_contains_' magic method, but this should be defined in the class that creates the Enum class!
In order to do that, we need to use the EnumMeta class, inherit from that, and define a new class. This new class will be used as metaclass in MyEnum:

from enum import EnumMeta

class MetaEnum(EnumMeta):
    def __contains__(cls, item):
        return any([item == x.value for x in cls.__members__.values()])


class MyEnum(Enum, metaclass=MetaEnum):
    my_model = MySpecificModel()

Using this to redefine MyEnum allows us to check if a generic class is in the Enum, when that is initialized with attributes that make it essentially identical to the specific class:

# This is true
MyGenericModel(value_one="a", value_two="b")  == MySpecificModel()
# This is now also True
MyGenericModel(value_one="a", value_two="b") in MyEnum

I have learned a lot from this post about metaclasses:
What are metaclasses in Python?

本文标签: pythonIs an instance of my Pydantic model also in my EnumStack Overflow