init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
|
|
@ -0,0 +1,698 @@
|
|||
# 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue