Exemple #1
0
def _imports_for_strategy(strategy):
    # If we have a lazy from_type strategy, because unwrapping it gives us an
    # error or invalid syntax, import that type and we're done.
    if isinstance(strategy, LazyStrategy) and strategy.function is st.from_type:
        return _imports_for_object(strategy._LazyStrategy__args[0])

    imports = set()
    strategy = unwrap_strategies(strategy)

    # Get imports for s.map(f), s.filter(f), s.flatmap(f), including both s and f
    if isinstance(strategy, MappedSearchStrategy):
        imports |= _imports_for_strategy(strategy.mapped_strategy)
        imports |= _imports_for_object(strategy.pack)
    if isinstance(strategy, FilteredStrategy):
        imports |= _imports_for_strategy(strategy.filtered_strategy)
        for f in strategy.flat_conditions:
            imports |= _imports_for_object(f)
    if isinstance(strategy, FlatMapStrategy):
        imports |= _imports_for_strategy(strategy.flatmapped_strategy)
        imports |= _imports_for_object(strategy.expand)

    # recurse through one_of to handle e.g. from_type(Optional[Foo])
    if isinstance(strategy, OneOfStrategy):
        for s in strategy.element_strategies:
            imports |= _imports_for_strategy(s)

    # get imports for the target of builds(), and recurse into the argument strategies
    if isinstance(strategy, BuildsStrategy):
        imports |= _imports_for_object(strategy.target)
        for s in strategy.args:
            imports |= _imports_for_strategy(s)
        for s in strategy.kwargs.values():
            imports |= _imports_for_strategy(s)

    return imports
Exemple #2
0
def resolve_TypeVar(thing):
    type_var_key = f"typevar={thing!r}"

    if getattr(thing, "__bound__", None) is not None:
        bound = thing.__bound__
        if isinstance(bound, ForwardRef):
            bound = _try_import_forward_ref(thing, bound)
        strat = unwrap_strategies(st.from_type(bound))
        if not isinstance(strat, OneOfStrategy):
            return strat
        # The bound was a union, or we resolved it as a union of subtypes,
        # so we need to unpack the strategy to ensure consistency across uses.
        # This incantation runs a sampled_from over the strategies inferred for
        # each part of the union, wraps that in shared so that we only generate
        # from one type per testcase, and flatmaps that back to instances.
        return st.shared(st.sampled_from(strat.original_strategies),
                         key=type_var_key).flatmap(lambda s: s)

    builtin_scalar_types = [type(None), bool, int, float, str, bytes]
    return st.shared(
        st.sampled_from(
            # Constraints may be None or () on various Python versions.
            getattr(thing, "__constraints__", None) or builtin_scalar_types, ),
        key=type_var_key,
    ).flatmap(st.from_type)
def test_sequence_filter_rewriting(strategy, predicate):
    s = unwrap_strategies(strategy)
    fs = s.filter(predicate)
    assert not isinstance(fs, FilteredStrategy)
    if s.min_size > 0:
        assert fs is s
    else:
        assert fs.min_size == 1
Exemple #4
0
def from_typing_type(thing):
    # We start with special-case support for Union and Tuple - the latter
    # isn't actually a generic type. Then we handle Literal since it doesn't
    # support `isinstance`. Support for Callable may be added to this section
    # later.
    # We then explicitly error on non-Generic types, which don't carry enough
    # information to sensibly resolve to strategies at runtime.
    # Finally, we run a variation of the subclass lookup in st.from_type
    # among generic types in the lookup.
    #
    # Under 3.6 Union is handled directly in st.from_type, as the argument is
    # not an instance of `type`. However, under Python 3.5 Union *is* a type
    # and we have to handle it here, including failing if it has no parameters.
    if hasattr(thing, "__union_params__"):  # pragma: no cover
        args = sorted(thing.__union_params__ or (), key=type_sorting_key)
        if not args:
            raise ResolutionFailed("Cannot resolve Union of no types.")
        return st.one_of([st.from_type(t) for t in args])
    if getattr(thing, "__origin__", None) == tuple or isinstance(
            thing, getattr(typing, "TupleMeta", ())):
        elem_types = getattr(thing, "__tuple_params__", None) or ()
        elem_types += getattr(thing, "__args__", None) or ()
        if (getattr(thing, "__tuple_use_ellipsis__", False)
                or len(elem_types) == 2 and elem_types[-1] is Ellipsis):
            return st.lists(st.from_type(elem_types[0])).map(tuple)
        elif len(elem_types) == 1 and elem_types[0] == ():
            return st.tuples()  # Empty tuple; see issue #1583
        return st.tuples(*map(st.from_type, elem_types))
    if (hasattr(typing, "Final") and getattr(thing, "__origin__", None)
            == typing.Final):  # pragma: no cover  # new in Python 3.8
        return st.one_of([st.from_type(t) for t in thing.__args__])
    if is_typing_literal(thing):  # pragma: no cover  # new in Python 3.8
        args_dfs_stack = list(thing.__args__)
        literals = []
        while args_dfs_stack:
            arg = args_dfs_stack.pop()
            if is_typing_literal(arg):
                args_dfs_stack.extend(reversed(arg.__args__))
            else:
                literals.append(arg)
        return st.sampled_from(literals)
    if isinstance(thing, typing.TypeVar):
        if getattr(thing, "__bound__", None) is not None:
            strat = unwrap_strategies(st.from_type(thing.__bound__))
            if not isinstance(strat, OneOfStrategy):
                return strat
            # The bound was a union, or we resolved it as a union of subtypes,
            # so we need to unpack the strategy to ensure consistency across uses.
            # This incantation runs a sampled_from over the strategies inferred for
            # each part of the union, wraps that in shared so that we only generate
            # from one type per testcase, and flatmaps that back to instances.
            return st.shared(st.sampled_from(strat.original_strategies),
                             key="typevar=%r" % (thing, )).flatmap(lambda s: s)
        if getattr(thing, "__constraints__", None):
            return st.shared(st.sampled_from(thing.__constraints__),
                             key="typevar=%r" % (thing, )).flatmap(
                                 st.from_type)
        # Constraints may be None or () on various Python versions.
        return st.text()  # An arbitrary type for the typevar
    # Now, confirm that we're dealing with a generic type as we expected
    if not isinstance(thing, typing_root_type):  # pragma: no cover
        raise ResolutionFailed("Cannot resolve %s to a strategy" % (thing, ))

    # Some "generic" classes are not generic *in* anything - for example both
    # Hashable and Sized have `__args__ == ()` on Python 3.7 or later.
    # (In 3.6 they're just aliases for the collections.abc classes)
    origin = getattr(thing, "__origin__", thing)
    if (typing.Hashable is not collections.abc.Hashable
            and origin in vars(collections.abc).values()
            and len(getattr(thing, "__args__", None) or []) == 0
        ):  # pragma: no cover  # impossible on 3.6 where we measure coverage.
        return st.from_type(origin)

    # Parametrised generic types have their __origin__ attribute set to the
    # un-parametrised version, which we need to use in the subclass checks.
    # e.g.:     typing.List[int].__origin__ == typing.List
    mapping = {
        k: v
        for k, v in _global_type_lookup.items()
        if isinstance(k, typing_root_type) and try_issubclass(k, thing)
    }
    if typing.Dict in mapping:
        # The subtype relationships between generic and concrete View types
        # are sometimes inconsistent under Python 3.5, so we pop them out to
        # preserve our invariant that all examples of from_type(T) are
        # instances of type T - and simplify the strategy for abstract types
        # such as Container
        for t in (typing.KeysView, typing.ValuesView, typing.ItemsView):
            mapping.pop(t, None)
    if len(mapping) > 1:
        # issubclass treats bytestring as a kind of sequence, which it is,
        # but treating it as such breaks everything else when it is presumed
        # to be a generic sequence or container that could hold any item.
        # Except for sequences of integers, or unions which include integer!
        # See https://github.com/HypothesisWorks/hypothesis/issues/2257
        #
        # This block drops ByteString from the types that can be generated
        # if there is more than one allowed type, and the element type is
        # not either `int` or a Union with `int` as one of its elements.
        elem_type = (getattr(thing, "__args__", None) or ["not int"])[0]
        if getattr(elem_type, "__origin__", None) is typing.Union:
            union_elems = elem_type.__args__
        elif hasattr(elem_type, "__union_params__"):  # pragma: no cover
            union_elems = elem_type.__union_params__  # python 3.5 only
        else:
            union_elems = ()
        if not any(
                isinstance(T, type) and issubclass(int, T)
                for T in list(union_elems) + [elem_type]):
            mapping.pop(typing.ByteString, None)
    strategies = [
        v if isinstance(v, st.SearchStrategy) else v(thing)
        for k, v in mapping.items() if sum(
            try_issubclass(k, T) for T in mapping) == 1
    ]
    empty = ", ".join(repr(s) for s in strategies if s.is_empty)
    if empty or not strategies:  # pragma: no cover
        raise ResolutionFailed(
            "Could not resolve %s to a strategy; consider using "
            "register_type_strategy" % (empty or thing, ))
    return st.one_of(strategies)
Exemple #5
0
def test_identity_map_is_noop():
    s = unwrap_strategies(st.integers())
    assert s.map(lambda x: x) is s
def test_bumps_min_size_and_filters_for_content_str_methods(method):
    s = unwrap_strategies(st.text())
    fs = s.filter(method)
    assert fs.filtered_strategy.min_size == 1
    assert fs.flat_conditions == (method, )
def test_warns_on_suspicious_string_methods(method):
    s = unwrap_strategies(st.text())
    with pytest.warns(HypothesisWarning,
                      match="this allows all nonempty strings!  Did you mean"):
        fs = s.filter(method)
    assert fs.min_size == 1