forked from PrefectHQ/prefect
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_exceptions.py
119 lines (97 loc) · 4.02 KB
/
test_exceptions.py
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
from typing import List
import cloudpickle
import pytest
from pydantic import BaseModel, TypeAdapter, ValidationError
from prefect.exceptions import (
ParameterBindError,
ParameterTypeError,
SignatureMismatchError,
)
class Foo(BaseModel):
num: int
string: str
class TestParameterTypeError:
def test_construction_from_single_validation_error(self):
with pytest.raises(
ValidationError, match=r"validation error.*\s+num\s+.*integer"
):
Foo(**{"num": "not an int", "string": "a string"})
def test_construction_from_two_validation_errors(self):
with pytest.raises(
ValidationError,
match=r"2 validation errors.*\s+num\s+.*integer.*\s+string\s+.*str",
):
Foo(**{"num": "not an int", "string": [1, 2]})
def test_construction_with_list_of_model_type_inputs(self):
"""regression test for https://github.com/PrefectHQ/prefect/issues/14406"""
errored = False
class HelloParams(BaseModel):
name: str
try:
TypeAdapter(List[HelloParams]).validate_python([{"name": "rodrigo"}, {}])
except ValidationError as exc:
errored = True
assert len(exc.errors()) == 1
parameter_type_error = ParameterTypeError.from_validation_error(exc)
assert "1.name" in str(parameter_type_error)
assert "Field required" in str(parameter_type_error)
assert errored
def test_pickle_roundtrip_single_error(self):
try:
Foo(**{"num": "not an int", "string": "a string"})
except Exception as exc:
pte = ParameterTypeError.from_validation_error(exc)
pickled = cloudpickle.dumps(pte)
unpickled = cloudpickle.loads(pickled)
assert str(pte) == str(unpickled)
assert pte.args == unpickled.args
def test_pickle_roundtrip_two_errors(self):
try:
Foo(**{"num": "not an int", "string": [1, 2]})
except Exception as exc:
pte = ParameterTypeError.from_validation_error(exc)
pickled = cloudpickle.dumps(pte)
unpickled = cloudpickle.loads(pickled)
assert str(pte) == str(unpickled)
assert pte.args == unpickled.args
class TestParameterBindError:
def test_construction_from_bind_error(self):
def fn(a: int, b: str):
pass
type_error = TypeError("Demo TypeError")
expected_str = (
"Error binding parameters for function 'fn': Demo TypeError.\nFunction 'fn'"
" has signature 'a: int, b: str' but received args: () and kwargs: ['c',"
" 'd']."
)
pbe = ParameterBindError.from_bind_failure(
fn, type_error, (), {"c": 3, "d": "test"}
)
assert str(pbe) == expected_str
assert pbe.args == ParameterBindError(expected_str).args
def test_pickle_roundtrip(self):
def test_construction_from_bind_error(self):
def fn(a: int, b: str):
pass
type_error = TypeError("Demo TypeError")
pbe = ParameterBindError.from_bind_failure(
fn, type_error, (), {"c": 3, "d": "test"}
)
pickled = cloudpickle.dumps(pbe)
unpickled = cloudpickle.loads(pickled)
assert str(pbe) == str(unpickled)
assert pbe.args == unpickled.args
class TestSignatureMismatchError:
def test_from_bad_params(self):
expected = (
"Function expects parameters ['dog', 'cat'] but was provided with"
" parameters ['puppy', 'kitty']"
)
sme = SignatureMismatchError.from_bad_params(["dog", "cat"], ["puppy", "kitty"])
assert str(sme) == expected
def test_pickle_roundtrip(self):
sme = SignatureMismatchError.from_bad_params(["dog", "cat"], ["puppy", "kitty"])
pickled = cloudpickle.dumps(sme)
unpickled = cloudpickle.loads(pickled)
assert str(sme) == str(unpickled)
assert sme.args == unpickled.args