`isinstance(obj, Hashable)` raises `TypeError` when both `obj` and `type(obj)` are unhashable
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 77.2k
- Forks
- 35.9k
- PR merge metrics
- PR metrics pending
Description
Bug report
Bug description:
Assumption: isinstance(anything, any_type) should never raise.
The problem appears to be in _abc.c function _abc__abc_subclasscheck_impl (known at runtime as _abc._abc_subclasscheck()), which reads (in part):
/* 1. Check cache. */
incache = _in_weak_set(impl->_abc_cache, subclass);
The implementation assumes subclass is hashable. That's almost always true of classes, but not guaranteed.
Reproduction case:
from __future__ import annotations
from collections.abc import Hashable
class UnhashableMeta(type):
def __eq__(self, other: object) -> bool:
return super().__eq__(other)
class UnhashableClass(metaclass=UnhashableMeta):
def __eq__(self, other: object) -> bool:
return super().__eq__(other)
# any non-hashable instance of a non-hashable class
# ┌────────┴────────┐
isinstance(UnhashableClass(), Hashable)
Traceback for (cpython) Python 3.13.1:
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File ".../bug.py", line 14, in <module>
isinstance(UnhashableClass(), Hashable)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen abc>", line 119, in __instancecheck__
File "<frozen abc>", line 123, in __subclasscheck__
TypeError: unhashable type: 'UnhashableMeta'
Tracebacks are nearly identical with Python 3.8, 3.9, 3.10, 3.11, and 3.12, as well as Python 3.14.0a4.
CPython versions tested on:
3.13, 3.12, 3.11, 3.10, 3.9, 3.14
Operating systems tested on:
macOS
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Open Modules/_abc.c and start at _abc__abc_subclasscheck_impl, specifically the _in_weak_set call described in the issue. Run the provided UnhashableMeta and UnhashableClass reproduction on CPython, then verify that isinstance(UnhashableClass(), Hashable) no longer raises and that the regression is covered by an appropriate test.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100