File: test_subscripts.py

package info (click to toggle)
python-multimethod 2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 164 kB
  • sloc: python: 731; makefile: 13
file content (151 lines) | stat: -rw-r--r-- 4,048 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import asyncio
import inspect
import sys
import typing
import pytest
from array import array
from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import Generic, Literal, Type, TypeVar, Union
from multimethod import multimethod, parametric, subtype, DispatchError


def test_literals():
    assert issubclass(subtype(Literal['a', 'b']), str)
    assert not issubclass(subtype(Literal['a']), subtype(list[int]))
    assert issubclass(Literal[[0]], subtype(Iterable[int]))
    tp = subtype(Literal['a', 0])
    assert isinstance('a', tp)
    assert isinstance(0, tp)
    assert not issubclass(Literal['a', 0.0], tp)
    assert not issubclass(tuple[str, int], tp)
    assert issubclass(tp, subtype(Union[str, int]))

    @multimethod
    def func(arg: Literal['a', 0]):
        return arg

    assert func(0) == 0
    with pytest.raises(DispatchError):
        func(1)
    with pytest.raises(DispatchError):
        func(0.0)


@pytest.mark.skipif(sys.version_info < (3, 10), reason="Union syntax added in 3.10")
def test_union():
    assert issubclass(int, subtype(int | float))
    assert issubclass(subtype(int | float), subtype(int | float | None))
    assert subtype(Iterable | Mapping | Sequence) is Iterable


@pytest.mark.skipif(sys.version_info < (3, 12), reason="Type aliases added in 3.12")
def test_type_alias():
    Point = typing.TypeAliasType(name='Point', value=tuple[int, int])
    assert isinstance((0, 0), subtype(Point))


def test_type():
    @multimethod
    def func(arg: Type[int]):
        return arg

    assert isinstance(int, subtype(Type[int]))
    assert func(int) is int
    assert func(bool) is bool
    with pytest.raises(DispatchError):
        func(float)
    with pytest.raises(DispatchError):
        func(0)


def test_generic():
    class cls(Generic[TypeVar('T')]):
        pass

    @multimethod
    def func(x: cls[int]):
        pass

    obj = cls[int]()
    assert isinstance(obj, subtype(cls[int]))
    assert func(obj) is None


def test_empty():
    @multimethod
    def func(arg: list[int]):
        return int

    @func.register
    def _(arg: list[bool]):
        return bool

    assert func[list[int],]
    assert func([0]) is int
    assert func([False]) is func([]) is bool


def test_callable():
    def f(arg: bool) -> int: ...

    def g(arg: int) -> bool: ...

    def h(arg) -> bool: ...

    @multimethod
    def func(arg: Callable[[bool], bool]):
        return arg.__name__

    @func.register
    def _(arg: Callable[..., bool]):
        return ...

    @func.register
    def _(arg: int):
        return 'int'

    @func.register
    def _(arg: Sequence[Callable[[bool], bool]]):
        return arg[0].__name__ + "0"

    with pytest.raises(DispatchError):
        func(f)
    assert func(g) == 'g'
    assert func([g]) == 'g0'
    assert func(h) is ...


def test_final():
    tp = subtype(Iterable[str])
    d = {'': 0}
    assert isinstance(d, subtype(Mapping[str, int]))
    assert isinstance(d.keys(), tp)


def test_args():
    tp = type('', (), {'__args__': None})
    assert subtype(tp) is tp
    assert not issubclass(tp, subtype(list[int]))
    assert subtype(typing.Callable) is Callable


@pytest.mark.benchmark
def test_parametric():
    coro = parametric(Callable, inspect.iscoroutinefunction)
    assert issubclass(coro, Callable)
    assert not issubclass(Callable, coro)
    assert not issubclass(parametric(object, inspect.iscoroutinefunction), coro)
    assert isinstance(asyncio.sleep, coro)
    assert not isinstance(lambda: None, coro)
    assert list(subtype.origins(coro)) == [Callable]

    ints = parametric(array, typecode='i')
    assert issubclass(ints, array)
    assert not issubclass(array, ints)
    sized = parametric(array, itemsize=4)
    assert issubclass(sized & ints, ints)
    assert not issubclass(ints, sized & ints)
    assert not issubclass(parametric(object, typecode='i'), array)
    assert isinstance(array('i'), ints)
    assert not isinstance(array('l'), ints)
    assert list(subtype.origins(ints)) == [array]