File: test_inference.py

package info (click to toggle)
python-hypothesis 6.148.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 15,408 kB
  • sloc: python: 63,888; ruby: 1,107; sh: 266; makefile: 42; javascript: 6
file content (135 lines) | stat: -rw-r--r-- 4,164 bytes parent folder | download | duplicates (2)
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
# This file is part of Hypothesis, which may be found at
# https://github.com/HypothesisWorks/hypothesis/
#
# Copyright the Hypothesis Authors.
# Individual contributors are listed in AUTHORS.rst and the git log.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.

import typing

import attr
import pytest

from hypothesis import given, strategies as st
from hypothesis.errors import ResolutionFailed

from tests.common.debug import check_can_generate_examples

# Union[A, B] is not equivalent to A | B until 3.14. We'll continue to test both
# until then.
# ruff: noqa: UP045, UP007


@attr.s
class Inferrables:
    type_ = attr.ib(type=int)
    type_converter = attr.ib(converter=bool)
    validator_type = attr.ib(validator=attr.validators.instance_of(str))
    validator_type_tuple = attr.ib(validator=attr.validators.instance_of((str, int)))
    validator_type_multiple = attr.ib(
        validator=[
            attr.validators.instance_of(str),
            attr.validators.instance_of((str, int, bool)),
        ]
    )
    validator_type_has_overlap = attr.ib(
        validator=[
            attr.validators.instance_of(str),
            attr.validators.instance_of((str, list)),
            attr.validators.instance_of(object),
        ]
    )
    validator_optional = attr.ib(
        validator=attr.validators.optional(lambda inst, atrib, val: float(val))
    )
    validator_in = attr.ib(validator=attr.validators.in_([1, 2, 3]))
    validator_in_multiple = attr.ib(
        validator=[attr.validators.in_(list(range(100))), attr.validators.in_([1, -1])]
    )
    validator_in_multiple_strings = attr.ib(
        validator=[attr.validators.in_("abcd"), attr.validators.in_(["ab", "cd"])]
    )

    typing_list = attr.ib(type=list[int])
    typing_list_of_list = attr.ib(type=list[list[int]])
    typing_dict = attr.ib(type=dict[str, int])
    typing_optional = attr.ib(type=typing.Optional[bool])
    typing_optional_new = attr.ib(type=bool | None)
    typing_union = attr.ib(type=typing.Union[str, int])
    typing_union_new = attr.ib(type=str | int)

    has_default = attr.ib(default=0)
    has_default_factory = attr.ib(default=attr.Factory(list))
    has_default_factory_takes_self = attr.ib(  # uninferrable but has default
        default=attr.Factory(lambda _: [], takes_self=True)
    )


@attr.s
class Required:
    a = attr.ib()


@attr.s
class UnhelpfulConverter:
    a = attr.ib(converter=lambda x: x)


@given(st.builds(Inferrables, has_default=..., has_default_factory=...))
def test_attrs_inference_builds(c):
    pass


@given(st.from_type(Inferrables))
def test_attrs_inference_from_type(c):
    pass


@pytest.mark.parametrize("c", [Required, UnhelpfulConverter])
def test_cannot_infer(c):
    with pytest.raises(ResolutionFailed):
        check_can_generate_examples(st.builds(c))


def test_cannot_infer_takes_self():
    with pytest.raises(ResolutionFailed):
        check_can_generate_examples(
            st.builds(Inferrables, has_default_factory_takes_self=...)
        )


@attr.s
class HasPrivateAttribute:
    _x: int = attr.ib()


@pytest.mark.parametrize("s", [st.just(42)])
def test_private_attribute(s):
    check_can_generate_examples(st.builds(HasPrivateAttribute, x=s))


def test_private_attribute_underscore_fails():
    with pytest.raises(TypeError, match="unexpected keyword argument '_x'"):
        check_can_generate_examples(st.builds(HasPrivateAttribute, _x=st.just(42)))


def test_private_attribute_underscore_infer_fails():
    # this has a slightly different failure case, because it goes through
    # attrs-specific resolution logic.
    with pytest.raises(
        TypeError, match="Unexpected keyword argument _x for attrs class"
    ):
        check_can_generate_examples(st.builds(HasPrivateAttribute, _x=...))


@attr.s
class HasAliasedAttribute:
    x: int = attr.ib(alias="crazyname")


@pytest.mark.parametrize("s", [st.just(42)])
def test_aliased_attribute(s):
    check_can_generate_examples(st.builds(HasAliasedAttribute, crazyname=s))