Skip to content

Commit a167a86

Browse files
authored
PYTHON-5917 Fix document_class generic alias check on PyPy (mongodb#2917)
1 parent c224067 commit a167a86

2 files changed

Lines changed: 16 additions & 12 deletions

File tree

bson/codec_options.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,14 +377,16 @@ def __new__(
377377
datetime_conversion: Optional[DatetimeConversion] = DatetimeConversion.DATETIME,
378378
) -> CodecOptions:
379379
doc_class = document_class or dict
380-
# issubclass can raise TypeError for generic aliases like SON[str, Any].
381-
# In that case we can use the base class for the comparison.
382-
is_mapping = False
380+
# Generic aliases like SON[str, Any] or dict[str, Any] aren't classes, so
381+
# resolve to their origin before the subclass check. Whether issubclass()
382+
# raises TypeError or just returns False for such aliases is inconsistent
383+
# across Python implementations (e.g. PyPy vs CPython), so check the
384+
# origin proactively instead of relying on catching the error.
385+
check_class = getattr(doc_class, "__origin__", doc_class)
383386
try:
384-
is_mapping = issubclass(doc_class, _MutableMapping)
387+
is_mapping = issubclass(check_class, _MutableMapping)
385388
except TypeError:
386-
if hasattr(doc_class, "__origin__"):
387-
is_mapping = issubclass(doc_class.__origin__, _MutableMapping)
389+
is_mapping = False
388390
if not (is_mapping or _raw_document_class(doc_class)):
389391
raise TypeError(
390392
"document_class must be dict, bson.son.SON, "

pymongo/common.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -482,14 +482,16 @@ def validate_document_class(
482482
option: str, value: Any
483483
) -> Union[type[MutableMapping[str, Any]], type[RawBSONDocument]]:
484484
"""Validate the document_class option."""
485-
# issubclass can raise TypeError for generic aliases like SON[str, Any].
486-
# In that case we can use the base class for the comparison.
487-
is_mapping = False
485+
# Generic aliases like SON[str, Any] or dict[str, Any] aren't classes, so
486+
# resolve to their origin before the subclass check. Whether issubclass()
487+
# raises TypeError or just returns False for such aliases is inconsistent
488+
# across Python implementations (e.g. PyPy vs CPython), so check the
489+
# origin proactively instead of relying on catching the error.
490+
check_class = getattr(value, "__origin__", value)
488491
try:
489-
is_mapping = issubclass(value, abc.MutableMapping)
492+
is_mapping = issubclass(check_class, abc.MutableMapping)
490493
except TypeError:
491-
if hasattr(value, "__origin__"):
492-
is_mapping = issubclass(value.__origin__, abc.MutableMapping)
494+
is_mapping = False
493495
if not is_mapping and not issubclass(value, RawBSONDocument):
494496
raise TypeError(
495497
f"{option} must be dict, bson.son.SON, "

0 commit comments

Comments
 (0)