Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8c8b1dd
Unify UnionType and Union
JelleZijlstra Jun 8, 2023
aba63eb
test_typing succeeds
JelleZijlstra Jun 8, 2023
f2f23a0
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Jun 8, 2023
e75282f
blurb
JelleZijlstra Jun 8, 2023
540b04b
Fix test_types
JelleZijlstra Jun 8, 2023
ae8fa62
Documentation
JelleZijlstra Jun 8, 2023
7569c48
stray f
JelleZijlstra Jun 8, 2023
8bcb930
Fix tests
JelleZijlstra Jun 8, 2023
291953e
No more typing._make_union
JelleZijlstra Jun 8, 2023
f7ca8d4
Add tp_new
JelleZijlstra Jun 9, 2023
0f1ab18
fix a refleak
JelleZijlstra Jun 9, 2023
eb47a0b
Fix test
JelleZijlstra Jun 9, 2023
eaa4e79
Update Lib/test/test_typing.py
JelleZijlstra Jun 9, 2023
4a0235f
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Jun 13, 2023
c71e8c3
Add back _UnionGenericAlias
JelleZijlstra Jun 13, 2023
0475415
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Jun 16, 2023
bb50899
Remove unnecessary NewRef
JelleZijlstra Jun 16, 2023
c564672
Make typing.Union the canonical name
JelleZijlstra Jun 16, 2023
9f58421
docs
JelleZijlstra Jun 16, 2023
8884a94
fix test_pydoc
JelleZijlstra Jun 16, 2023
bcc2e6a
Update Objects/unionobject.c
JelleZijlstra Jun 16, 2023
c4b217b
Update Doc/library/typing.rst
JelleZijlstra Jun 17, 2023
5eb2a0c
Update Doc/library/stdtypes.rst
JelleZijlstra Jun 17, 2023
64ac293
Update Doc/library/stdtypes.rst
JelleZijlstra Jun 17, 2023
0ba8551
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Jun 17, 2023
aacf2b0
Add __mro_entries__
JelleZijlstra Jun 17, 2023
f46c0c6
Improve docs, expose it in _typing
JelleZijlstra Jun 17, 2023
8c04441
Update Doc/library/functools.rst
JelleZijlstra Jun 20, 2023
04df4d0
Merge branch 'main' into unifyunion
JelleZijlstra Jun 20, 2023
c363de7
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Oct 11, 2023
98b634a
Post-merge cleanup
JelleZijlstra Oct 11, 2023
f2f961b
No need for tp_new
JelleZijlstra Oct 12, 2023
932f8e5
Merge branch 'main' into unifyunion
JelleZijlstra Oct 28, 2023
c3edd87
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Feb 18, 2024
9ae102d
Add back doctest
JelleZijlstra Feb 18, 2024
e0924c6
Merge branch 'main' into unifyunion
JelleZijlstra Feb 19, 2024
7086879
Merge branch 'main' into unifyunion
JelleZijlstra Feb 28, 2024
b0e057f
Merge branch 'main' into unifyunion
JelleZijlstra Mar 12, 2024
55d0c97
Merge branch 'main' into unifyunion
JelleZijlstra Apr 26, 2024
8a80fe0
Fix two issues
JelleZijlstra Apr 26, 2024
f910e88
in progress: hashable unions
JelleZijlstra Apr 26, 2024
cae36c7
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Sep 28, 2024
65da3f1
fixup
JelleZijlstra Sep 28, 2024
f500f5f
Make union support unhashable objects
JelleZijlstra Sep 28, 2024
5f9e599
simplify, extend docs
JelleZijlstra Sep 28, 2024
9927b38
fix more tests
JelleZijlstra Sep 28, 2024
eea6eca
another
JelleZijlstra Sep 28, 2024
0785951
change hash
JelleZijlstra Sep 29, 2024
1a39ded
Merge remote-tracking branch 'upstream/main' into unifyunion
JelleZijlstra Sep 29, 2024
eddbfde
Merge branch 'main' into unifyunion
JelleZijlstra Nov 5, 2024
3ec9271
Merge branch 'main' into unifyunion
JelleZijlstra Mar 3, 2025
cab69f0
tweak docs
JelleZijlstra Mar 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change hash
  • Loading branch information
JelleZijlstra committed Sep 29, 2024
commit 07859518929ec5a0ed686bc2d4e00597711086a1
31 changes: 30 additions & 1 deletion Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,10 +723,39 @@ class B(metaclass=UnhashableMeta): ...

self.assertEqual((A | B).__args__, (A, B))
union1 = A | B
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union1)

union2 = int | B
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union2)

union3 = A | int
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union3)

def test_unhashable_becomes_hashable(self):
is_hashable = False
class UnhashableMeta(type):
def __hash__(self):
if is_hashable:
return 1
else:
raise TypeError("not hashable")

class A(metaclass=UnhashableMeta): ...
class B(metaclass=UnhashableMeta): ...

union = A | B
self.assertEqual(union.__args__, (A, B))

with self.assertRaisesRegex(TypeError, "not hashable"):
hash(union)

is_hashable = True

self.assertEqual(len({union1, union2, union3}), 3)
with self.assertRaisesRegex(TypeError, "union contains 2 unhashable elements"):
hash(union)

def test_instancecheck_and_subclasscheck(self):
for x in (int | str, typing.Union[int, str]):
Expand Down
10 changes: 8 additions & 2 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2062,10 +2062,16 @@ class B(metaclass=UnhashableMeta): ...

self.assertEqual(Union[A, B].__args__, (A, B))
union1 = Union[A, B]
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union1)

union2 = Union[int, B]
union3 = Union[A, int]
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union2)

self.assertEqual(len({union1, union2, union3}), 3)
union3 = Union[A, int]
with self.assertRaisesRegex(TypeError, "unhashable type: 'UnhashableMeta'"):
hash(union3)

def test_repr(self):
u = Union[Employee, int]
Expand Down
25 changes: 12 additions & 13 deletions Objects/unionobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,25 @@ static Py_hash_t
union_hash(PyObject *self)
{
unionobject *alias = (unionobject *)self;
Py_hash_t hash;
if (alias->hashable_args) {
hash = PyObject_Hash(alias->hashable_args);
if (hash == -1) {
return -1;
}
}
else {
hash = 604;
}
// Mix in the ids of all the unhashable args.
// If there are any unhashable args, treat this union as unhashable.
// Otherwise, two unions might compare equal but have different hashes.
if (alias->unhashable_args) {
// Attempt to get an error from one of the values.
assert(PyTuple_CheckExact(alias->unhashable_args));
Py_ssize_t n = PyTuple_GET_SIZE(alias->unhashable_args);
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *arg = PyTuple_GET_ITEM(alias->unhashable_args, i);
hash ^= (Py_hash_t)arg;
Py_hash_t hash = PyObject_Hash(arg);
if (hash == -1) {
return -1;
}
}
// The unhashable values somehow became hashable again. Still raise
// an error.
PyErr_Format(PyExc_TypeError, "union contains %d unhashable elements", n);
return -1;
}
return hash;
return PyObject_Hash(alias->hashable_args);
}

static int
Expand Down