| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- # Test cases related to the functools.singledispatch decorator
- # Most of these tests are marked as xfails because mypyc doesn't support singledispatch yet
- # (These tests will be re-enabled when mypyc supports singledispatch)
- [case testSpecializedImplementationUsed]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register
- def fun_specialized(arg: str) -> bool:
- return True
- def test_specialize() -> None:
- assert fun('a')
- assert not fun(3)
- [case testSubclassesOfExpectedTypeUseSpecialized]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register
- def fun_specialized(arg: A) -> bool:
- return True
- def test_specialize() -> None:
- assert fun(B())
- assert fun(A())
- [case testSuperclassImplementationNotUsedWhenSubclassHasImplementation]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- @singledispatch
- def fun(arg) -> bool:
- # shouldn't be using this
- assert False
- @fun.register
- def fun_specialized(arg: A) -> bool:
- return False
- @fun.register
- def fun_specialized2(arg: B) -> bool:
- return True
- def test_specialize() -> None:
- assert fun(B())
- assert not fun(A())
- [case testMultipleUnderscoreFunctionsIsntError]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> str:
- return 'default'
- @fun.register
- def _(arg: str) -> str:
- return 'str'
- @fun.register
- def _(arg: int) -> str:
- return 'int'
- # extra function to make sure all 3 underscore functions aren't treated as one OverloadedFuncDef
- def a(b): pass
- @fun.register
- def _(arg: list) -> str:
- return 'list'
- def test_singledispatch() -> None:
- assert fun(0) == 'int'
- assert fun('a') == 'str'
- assert fun([1, 2]) == 'list'
- assert fun({'a': 'b'}) == 'default'
- [case testCanRegisterCompiledClasses]
- from functools import singledispatch
- class A: pass
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register
- def fun_specialized(arg: A) -> bool:
- return True
- def test_singledispatch() -> None:
- assert fun(A())
- assert not fun(1)
- [case testTypeUsedAsArgumentToRegister]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register(int)
- def fun_specialized(arg) -> bool:
- return True
- def test_singledispatch() -> None:
- assert fun(1)
- assert not fun('a')
- [case testUseRegisterAsAFunction]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- def fun_specialized_impl(arg) -> bool:
- return True
- fun.register(int, fun_specialized_impl)
- def test_singledispatch() -> None:
- assert fun(0)
- assert not fun('a')
- [case testRegisterDoesntChangeFunction]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register(int)
- def fun_specialized(arg) -> bool:
- return True
- def test_singledispatch() -> None:
- assert fun_specialized('a')
- # TODO: turn this into a mypy error
- [case testNoneIsntATypeWhenUsedAsArgumentToRegister]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- try:
- @fun.register
- def fun_specialized(arg: None) -> bool:
- return True
- except TypeError:
- pass
- [case testRegisteringTheSameFunctionSeveralTimes]
- from functools import singledispatch
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register(int)
- @fun.register(str)
- def fun_specialized(arg) -> bool:
- return True
- def test_singledispatch() -> None:
- assert fun(0)
- assert fun('a')
- assert not fun([1, 2])
- [case testTypeIsAnABC]
- from functools import singledispatch
- from collections.abc import Mapping
- @singledispatch
- def fun(arg) -> bool:
- return False
- @fun.register
- def fun_specialized(arg: Mapping) -> bool:
- return True
- def test_singledispatch() -> None:
- assert not fun(1)
- assert fun({'a': 'b'})
- [case testSingleDispatchMethod-xfail]
- from functools import singledispatchmethod
- class A:
- @singledispatchmethod
- def fun(self, arg) -> str:
- return 'default'
- @fun.register
- def fun_int(self, arg: int) -> str:
- return 'int'
- @fun.register
- def fun_str(self, arg: str) -> str:
- return 'str'
- def test_singledispatchmethod() -> None:
- x = A()
- assert x.fun(5) == 'int'
- assert x.fun('a') == 'str'
- assert x.fun([1, 2]) == 'default'
- [case testSingleDispatchMethodWithOtherDecorator-xfail]
- from functools import singledispatchmethod
- class A:
- @singledispatchmethod
- @staticmethod
- def fun(arg) -> str:
- return 'default'
- @fun.register
- @staticmethod
- def fun_int(arg: int) -> str:
- return 'int'
- @fun.register
- @staticmethod
- def fun_str(arg: str) -> str:
- return 'str'
- def test_singledispatchmethod() -> None:
- x = A()
- assert x.fun(5) == 'int'
- assert x.fun('a') == 'str'
- assert x.fun([1, 2]) == 'default'
- [case testSingledispatchTreeSumAndEqual]
- from functools import singledispatch
- class Tree:
- pass
- class Leaf(Tree):
- pass
- class Node(Tree):
- def __init__(self, value: int, left: Tree, right: Tree) -> None:
- self.value = value
- self.left = left
- self.right = right
- @singledispatch
- def calc_sum(x: Tree) -> int:
- raise TypeError('invalid type for x')
- @calc_sum.register
- def _(x: Leaf) -> int:
- return 0
- @calc_sum.register
- def _(x: Node) -> int:
- return x.value + calc_sum(x.left) + calc_sum(x.right)
- @singledispatch
- def equal(to_compare: Tree, known: Tree) -> bool:
- raise TypeError('invalid type for x')
- @equal.register
- def _(to_compare: Leaf, known: Tree) -> bool:
- return isinstance(known, Leaf)
- @equal.register
- def _(to_compare: Node, known: Tree) -> bool:
- if isinstance(known, Node):
- if to_compare.value != known.value:
- return False
- else:
- return equal(to_compare.left, known.left) and equal(to_compare.right, known.right)
- return False
- def build(n: int) -> Tree:
- if n == 0:
- return Leaf()
- return Node(n, build(n - 1), build(n - 1))
- def test_sum_and_equal():
- tree = build(5)
- tree2 = build(5)
- tree2.right.right.right.value = 10
- assert calc_sum(tree) == 57
- assert calc_sum(tree2) == 65
- assert equal(tree, tree)
- assert not equal(tree, tree2)
- tree3 = build(4)
- assert not equal(tree, tree3)
- [case testSimulateMypySingledispatch]
- from functools import singledispatch
- from mypy_extensions import trait
- from typing import Iterator, Union, TypeVar, Any, List, Type
- # based on use of singledispatch in stubtest.py
- class Error:
- def __init__(self, msg: str) -> None:
- self.msg = msg
- @trait
- class Node: pass
- class MypyFile(Node): pass
- class TypeInfo(Node): pass
- @trait
- class SymbolNode(Node): pass
- @trait
- class Expression(Node): pass
- class TypeVarLikeExpr(SymbolNode, Expression): pass
- class TypeVarExpr(TypeVarLikeExpr): pass
- class TypeAlias(SymbolNode): pass
- class Missing: pass
- MISSING = Missing()
- T = TypeVar("T")
- MaybeMissing = Union[T, Missing]
- @singledispatch
- def verify(stub: Node, a: MaybeMissing[Any], b: List[str]) -> Iterator[Error]:
- yield Error('unknown node type')
- @verify.register(MypyFile)
- def verify_mypyfile(stub: MypyFile, a: MaybeMissing[int], b: List[str]) -> Iterator[Error]:
- if isinstance(a, Missing):
- yield Error("shouldn't be missing")
- return
- if not isinstance(a, int):
- # this check should be unnecessary because of the type signature and the previous check,
- # but stubtest.py has this check
- yield Error("should be an int")
- return
- yield from verify(TypeInfo(), str, ['abc', 'def'])
- @verify.register(TypeInfo)
- def verify_typeinfo(stub: TypeInfo, a: MaybeMissing[Type[Any]], b: List[str]) -> Iterator[Error]:
- yield Error('in TypeInfo')
- yield Error('hello')
- @verify.register(TypeVarExpr)
- def verify_typevarexpr(stub: TypeVarExpr, a: MaybeMissing[Any], b: List[str]) -> Iterator[Error]:
- if False:
- yield None
- def verify_list(stub, a, b) -> List[str]:
- """Helper function that converts iterator of errors to list of messages"""
- return list(err.msg for err in verify(stub, a, b))
- def test_verify() -> None:
- assert verify_list(TypeAlias(), 'a', ['a', 'b']) == ['unknown node type']
- assert verify_list(MypyFile(), MISSING, ['a', 'b']) == ["shouldn't be missing"]
- assert verify_list(MypyFile(), 5, ['a', 'b']) == ['in TypeInfo', 'hello']
- assert verify_list(TypeInfo(), str, ['a', 'b']) == ['in TypeInfo', 'hello']
- assert verify_list(TypeVarExpr(), 'a', ['x', 'y']) == []
- [case testArgsInRegisteredImplNamedDifferentlyFromMainFunction]
- from functools import singledispatch
- @singledispatch
- def f(a) -> bool:
- return False
- @f.register
- def g(b: int) -> bool:
- return True
- def test_singledispatch():
- assert f(5)
- assert not f('a')
- [case testKeywordArguments]
- from functools import singledispatch
- @singledispatch
- def f(arg, *, kwarg: int = 0) -> int:
- return kwarg + 10
- @f.register
- def g(arg: int, *, kwarg: int = 5) -> int:
- return kwarg - 10
- def test_keywords():
- assert f('a') == 10
- assert f('a', kwarg=3) == 13
- assert f('a', kwarg=7) == 17
- assert f(1) == -5
- assert f(1, kwarg=4) == -6
- assert f(1, kwarg=6) == -4
- [case testGeneratorAndMultipleTypesOfIterable]
- from functools import singledispatch
- from typing import *
- @singledispatch
- def f(arg: Any) -> Iterable[int]:
- yield 1
- @f.register
- def g(arg: str) -> Iterable[int]:
- return [0]
- def test_iterables():
- assert f(1) != [1]
- assert list(f(1)) == [1]
- assert f('a') == [0]
- [case testRegisterUsedAtSameTimeAsOtherDecorators]
- from functools import singledispatch
- from typing import TypeVar
- class A: pass
- class B: pass
- T = TypeVar('T')
- def decorator(f: T) -> T:
- return f
- @singledispatch
- def f(arg) -> int:
- return 0
- @f.register
- @decorator
- def h(arg: str) -> int:
- return 2
- def test_singledispatch():
- assert f(1) == 0
- assert f('a') == 2
- [case testDecoratorModifiesFunction]
- from functools import singledispatch
- from typing import Callable, Any
- class A: pass
- def decorator(f: Callable[[Any], int]) -> Callable[[Any], int]:
- def wrapper(x) -> int:
- return f(x) * 7
- return wrapper
- @singledispatch
- def f(arg) -> int:
- return 10
- @f.register
- @decorator
- def h(arg: str) -> int:
- return 5
- def test_singledispatch():
- assert f('a') == 35
- assert f(A()) == 10
- [case testMoreSpecificTypeBeforeLessSpecificType]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- @singledispatch
- def f(arg) -> str:
- return 'default'
- @f.register
- def g(arg: B) -> str:
- return 'b'
- @f.register
- def h(arg: A) -> str:
- return 'a'
- def test_singledispatch():
- assert f(B()) == 'b'
- assert f(A()) == 'a'
- assert f(5) == 'default'
- [case testMultipleRelatedClassesBeingRegistered]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- class C(B): pass
- @singledispatch
- def f(arg) -> str: return 'default'
- @f.register
- def _(arg: A) -> str: return 'a'
- @f.register
- def _(arg: C) -> str: return 'c'
- @f.register
- def _(arg: B) -> str: return 'b'
- def test_singledispatch():
- assert f(A()) == 'a'
- assert f(B()) == 'b'
- assert f(C()) == 'c'
- assert f(1) == 'default'
- [case testRegisteredImplementationsInDifferentFiles]
- from other_a import f, A, B, C
- @f.register
- def a(arg: A) -> int:
- return 2
- @f.register
- def _(arg: C) -> int:
- return 3
- def test_singledispatch():
- assert f(B()) == 1
- assert f(A()) == 2
- assert f(C()) == 3
- assert f(1) == 0
- [file other_a.py]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- class C(B): pass
- @singledispatch
- def f(arg) -> int:
- return 0
- @f.register
- def g(arg: B) -> int:
- return 1
- [case testOrderCanOnlyBeDeterminedFromMRONotIsinstanceChecks]
- from mypy_extensions import trait
- from functools import singledispatch
- @trait
- class A: pass
- @trait
- class B: pass
- class AB(A, B): pass
- class BA(B, A): pass
- @singledispatch
- def f(arg) -> str:
- return "default"
- pass
- @f.register
- def fa(arg: A) -> str:
- return "a"
- @f.register
- def fb(arg: B) -> str:
- return "b"
- def test_singledispatch():
- assert f(AB()) == "a"
- assert f(BA()) == "b"
- [case testCallingFunctionBeforeAllImplementationsRegistered]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- @singledispatch
- def f(arg) -> str:
- return 'default'
- assert f(A()) == 'default'
- assert f(B()) == 'default'
- assert f(1) == 'default'
- @f.register
- def g(arg: A) -> str:
- return 'a'
- assert f(A()) == 'a'
- assert f(B()) == 'a'
- assert f(1) == 'default'
- @f.register
- def _(arg: B) -> str:
- return 'b'
- assert f(A()) == 'a'
- assert f(B()) == 'b'
- assert f(1) == 'default'
- [case testDynamicallyRegisteringFunctionFromInterpretedCode]
- from functools import singledispatch
- class A: pass
- class B(A): pass
- class C(B): pass
- class D(C): pass
- @singledispatch
- def f(arg) -> str:
- return "default"
- @f.register
- def _(arg: B) -> str:
- return 'b'
- [file register_impl.py]
- from native import f, A, B, C
- @f.register(A)
- def a(arg) -> str:
- return 'a'
- @f.register
- def c(arg: C) -> str:
- return 'c'
- [file driver.py]
- from native import f, A, B, C
- from register_impl import a, c
- # We need a custom driver here because register_impl has to be run before we test this (so that the
- # additional implementations are registered)
- assert f(C()) == 'c'
- assert f(A()) == 'a'
- assert f(B()) == 'b'
- assert a(C()) == 'a'
- assert c(A()) == 'c'
- [case testMalformedDynamicRegisterCall]
- from functools import singledispatch
- @singledispatch
- def f(arg) -> None:
- pass
- [file register.py]
- from native import f
- from testutil import assertRaises
- with assertRaises(TypeError, 'Invalid first argument to `register()`'):
- @f.register
- def _():
- pass
- [file driver.py]
- import register
- [case testCacheClearedWhenNewFunctionRegistered]
- from functools import singledispatch
- @singledispatch
- def f(arg) -> str:
- return 'default'
- [file register.py]
- from native import f
- class A: pass
- class B: pass
- class C: pass
- # annotated function
- assert f(A()) == 'default'
- @f.register
- def _(arg: A) -> str:
- return 'a'
- assert f(A()) == 'a'
- # type passed as argument
- assert f(B()) == 'default'
- @f.register(B)
- def _(arg: B) -> str:
- return 'b'
- assert f(B()) == 'b'
- # 2 argument form
- assert f(C()) == 'default'
- def c(arg) -> str:
- return 'c'
- f.register(C, c)
- assert f(C()) == 'c'
- [file driver.py]
- import register
|