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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
from inspect import getdoc
import pytest
from returns.curry import curry
def test_docstring():
"""Ensures that we preserve docstrings from curried function."""
@curry
def factory(arg: int, other: int) -> None:
"""Some docstring."""
assert getdoc(factory) == 'Some docstring.'
def test_immutable():
"""Check that arguments from previous calls are immutable."""
@curry
def factory(arg: int, other: int) -> tuple[int, int]:
return (arg, other)
cached = factory(arg=1)
assert cached(other=2) == (1, 2)
assert cached(other=3) == (1, 3)
def test_no_args():
"""Ensures that it is possible to curry a function with empty args."""
@curry
def factory() -> int:
return 1
assert factory() == 1
def test_one_arg():
"""Ensures that it is possible to curry a function with one arg."""
@curry
def factory(arg: int) -> int:
return arg
assert factory(1) == 1
assert factory(arg=1) == 1
with pytest.raises(TypeError):
factory(other=2) # type: ignore
with pytest.raises(TypeError):
factory(1, 2) # type: ignore
with pytest.raises(TypeError):
factory(1)(2) # type: ignore
def test_two_args():
"""Ensures that it is possible to curry a function with two args."""
@curry
def factory(arg: int, other: int) -> tuple[int, int]:
return (arg, other)
assert factory(1)(2) == (1, 2)
assert factory(1, 2) == (1, 2)
assert factory(2, other=3) == (2, 3)
assert factory(arg=2, other=3) == (2, 3)
assert factory(other=3, arg=2) == (2, 3)
assert factory(arg=0)(other=5) == (0, 5)
assert factory(0)(other=5) == (0, 5)
with pytest.raises(TypeError):
factory(1, 2, 3) # type: ignore
with pytest.raises(TypeError):
factory(1, c=2) # type: ignore
with pytest.raises(TypeError):
factory(1)(c=2) # type: ignore
with pytest.raises(TypeError):
factory(1)(2)(3) # type: ignore
def test_star_args():
"""Ensures that it is possible to curry a function with ``*args``."""
@curry
def factory(*args: int) -> int:
return sum(args)
assert factory() == 0
assert factory(1) == 1
assert factory(1, 2) == 3
assert factory(1, 2, 3) == 6
with pytest.raises(TypeError):
factory(arg=1)
with pytest.raises(TypeError):
factory(1, other=2)
with pytest.raises(TypeError):
factory(1)(2)
def test_arg_and_star_args():
"""Ensures that it is possible to curry a function with ``*args``."""
@curry
def factory(arg: int, *args: int) -> int:
return arg + sum(args)
assert factory(1) == 1
assert factory(1, 2) == 3
assert factory(1, 2, 3) == 6
with pytest.raises(TypeError):
assert factory(1)(2, 3) == 6
def test_star_kwargs():
"""Ensures that it is possible to curry a function with ``**kwargs``."""
@curry
def factory(**kwargs: int) -> list[tuple[str, int]]:
return sorted(kwargs.items())
assert not factory()
assert factory(arg=1) == [('arg', 1)]
assert factory(
arg=1,
other=2,
) == [('arg', 1), ('other', 2)]
with pytest.raises(TypeError):
factory(1)
with pytest.raises(TypeError):
factory(1, other=2)
def test_arg_star_kwargs():
"""The decorator should work with ``kwargs``."""
@curry
def factory(first: int, **kwargs: int) -> list[tuple[str, int]]:
return [('first', first), *sorted(kwargs.items())]
assert factory(1) == [('first', 1)]
assert factory(1, arg=2) == [('first', 1), ('arg', 2)]
assert factory(
first=1,
arg=2,
) == [('first', 1), ('arg', 2)]
assert factory(1, arg=2, other=3) == [
('first', 1),
('arg', 2),
('other', 3),
]
with pytest.raises(TypeError):
factory(1, 2)
with pytest.raises(TypeError):
factory(1, first=2)
with pytest.raises(TypeError):
factory(1, 2, c=2)
def test_kwonly():
"""The decorator should work with kw-only args."""
@curry
def factory(*args: int, by: int) -> tuple[int, ...]:
return (*args, by)
assert factory(
1,
2,
3,
)(by=10) == (1, 2, 3, 10)
assert factory(by=10) == (10,)
def test_raises():
"""Exception raised from the function must not be intercepted."""
@curry
def factory(arg: int, other: int) -> None:
msg = "f() missing 2 required positional arguments: 'a' and 'b'"
raise TypeError(msg)
with pytest.raises(TypeError):
factory(1)(2)
with pytest.raises(TypeError):
factory(1, 2)
with pytest.raises(TypeError):
factory(1, 2, 3) # type: ignore
|