Skip to content
Prev Previous commit
Next Next commit
Split up tests
  • Loading branch information
smheidrich committed Dec 30, 2022
commit eb23d0561ca169d5454d1f0fe28af2ea31077bae
30 changes: 24 additions & 6 deletions Lib/test/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2926,6 +2926,13 @@ def _(arg):
def _(arg):
return "type[bytes]"

self.assertEqual(f(int), "type[int]")
self.assertEqual(f(float), "type[float]")
self.assertEqual(f(str), "type[str]")
self.assertEqual(f(bytes), "type[bytes]")
self.assertEqual(f(2), "default")

def test_type_argument_mro(self):
class A:
pass

Expand All @@ -2935,6 +2942,10 @@ class B(A):
class C:
pass

@functools.singledispatch
def f(arg):
return "default"

@f.register
def _(arg: type[A]):
return "type[A]"
Expand All @@ -2943,6 +2954,14 @@ def _(arg: type[A]):
def _(arg: B):
return "B"

self.assertEqual(f(B), "type[A]")
self.assertEqual(f(C), "default")

def test_type_argument_unions(self):
@functools.singledispatch
def f(arg):
return "default"

@f.register
def _(arg: type[list|dict]):
return "type[list|dict]"
Expand All @@ -2951,15 +2970,14 @@ def _(arg: type[list|dict]):
def _(arg: type[set]|typing.Type[type(None)]):
return "type[set]|type[NoneType]"

self.assertEqual(f(int), "type[int]")
self.assertEqual(f(float), "type[float]")
self.assertEqual(f(str), "type[str]")
self.assertEqual(f(bytes), "type[bytes]")
self.assertEqual(f(B), "type[A]")
self.assertEqual(f(C), "default")
self.assertEqual(f(list), "type[list|dict]")
self.assertEqual(f(type(None)), "type[set]|type[NoneType]")
Comment on lines +2965 to +2974
Copy link
Copy Markdown
Contributor Author

@smheidrich smheidrich Dec 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if treating type[a|b] and type[a]|type[b] the same actually makes sense and even if so, whether union types should be supported for type[...] arguments at all:

E.g. if we have a single-dispatch function with an implementation for type[a|b|c], wouldn't people expect to be able to pass e.g. a|b to it and have it dispatch to that implementation? That would be much harder to implement than my current naive implementation of just splitting up unions into their individual constituent types, especially considering issubclass(a|b, a|b|c) isn't even possible.

So maybe unions of type[...]s and type[...]s of unions should just not be allowed for now, deferring them to when (if ever) issubclass supports these kinds of checks (or Python gets another issubtype function).

OTOH, it's unlikely that introducing support for dispatching to type[a|b|c] given a|b later on would be much of a breaking change... If only dispatching on single types is supported for now then that is all people will use, nobody will rely on the fact that a|b dispatches to the default implementation, they'll just never pass a|b to a single-dispatch function in the first place I should think. So it might be fine to implement it like this for now and leave only the "proper" handling for later.


def test_type_argument_invalid_types(self):
@functools.singledispatch
def f(arg):
return "default"

with self.assertRaisesRegex(TypeError, "Invalid annotation for 'arg'"):
@f.register
def _(arg: type[2]):
Expand Down