| 1162 | if not TYPE_CHECKING: |
| 1163 | |
| 1164 | def __eq__(self, other: Any) -> bool: |
| 1165 | if isinstance(other, BaseModel): |
| 1166 | # When comparing instances of generic types for equality, as long as all field values are equal, |
| 1167 | # only require their generic origin types to be equal, rather than exact type equality. |
| 1168 | # This prevents headaches like MyGeneric(x=1) != MyGeneric[Any](x=1). |
| 1169 | self_type = self.__pydantic_generic_metadata__['origin'] or self.__class__ |
| 1170 | other_type = other.__pydantic_generic_metadata__['origin'] or other.__class__ |
| 1171 | |
| 1172 | # Perform common checks first |
| 1173 | if not ( |
| 1174 | self_type is other_type |
| 1175 | and getattr(self, '__pydantic_private__', None) == getattr(other, '__pydantic_private__', None) |
| 1176 | # We need to assume `None` and `{}` are equivalent, because extra behavior |
| 1177 | # can be controlled at validation time: |
| 1178 | and (self.__pydantic_extra__ or {}) == (other.__pydantic_extra__ or {}) |
| 1179 | ): |
| 1180 | return False |
| 1181 | |
| 1182 | # We only want to compare pydantic fields but ignoring fields is costly. |
| 1183 | # We'll perform a fast check first, and fallback only when needed |
| 1184 | # See GH-7444 and GH-7825 for rationale and a performance benchmark |
| 1185 | |
| 1186 | # First, do the fast (and sometimes faulty) __dict__ comparison |
| 1187 | if self.__dict__ == other.__dict__: |
| 1188 | # If the check above passes, then pydantic fields are equal, we can return early |
| 1189 | return True |
| 1190 | |
| 1191 | # We don't want to trigger unnecessary costly filtering of __dict__ on all unequal objects, so we return |
| 1192 | # early if there are no keys to ignore (we would just return False later on anyway) |
| 1193 | model_fields = type(self).__pydantic_fields__.keys() |
| 1194 | if self.__dict__.keys() <= model_fields and other.__dict__.keys() <= model_fields: |
| 1195 | return False |
| 1196 | |
| 1197 | # If we reach here, there are non-pydantic-fields keys, mapped to unequal values, that we need to ignore |
| 1198 | # Resort to costly filtering of the __dict__ objects |
| 1199 | # We use operator.itemgetter because it is much faster than dict comprehensions |
| 1200 | # NOTE: Contrary to standard python class and instances, when the Model class has a default value for an |
| 1201 | # attribute and the model instance doesn't have a corresponding attribute, accessing the missing attribute |
| 1202 | # raises an error in BaseModel.__getattr__ instead of returning the class attribute |
| 1203 | # So we can use operator.itemgetter() instead of operator.attrgetter() |
| 1204 | getter = operator.itemgetter(*model_fields) if model_fields else lambda _: _utils._SENTINEL |
| 1205 | try: |
| 1206 | return getter(self.__dict__) == getter(other.__dict__) |
| 1207 | except KeyError: |
| 1208 | # In rare cases (such as when using the deprecated BaseModel.copy() method), |
| 1209 | # the __dict__ may not contain all model fields, which is how we can get here. |
| 1210 | # getter(self.__dict__) is much faster than any 'safe' method that accounts |
| 1211 | # for missing keys, and wrapping it in a `try` doesn't slow things down much |
| 1212 | # in the common case. |
| 1213 | self_fields_proxy = _utils.SafeGetItemProxy(self.__dict__) |
| 1214 | other_fields_proxy = _utils.SafeGetItemProxy(other.__dict__) |
| 1215 | return getter(self_fields_proxy) == getter(other_fields_proxy) |
| 1216 | |
| 1217 | # other instance is not a BaseModel |
| 1218 | else: |
| 1219 | return NotImplemented # delegate to the other item in the comparison |
| 1220 | |
| 1221 | if TYPE_CHECKING: |