Example #1
0
def indices(
    shape: Shape,
    *,
    min_dims: int = 0,
    max_dims: Optional[int] = None,
    allow_ellipsis: bool = True,
) -> st.SearchStrategy[BasicIndex]:
    """Return a strategy for :xp-ref:`valid indices <indexing.html>` of
    arrays with the specified shape, which may include dimensions of size zero.

    It generates tuples containing some mix of integers, :obj:`python:slice`
    objects, and ``...`` (an ``Ellipsis``). When a length-one tuple would be
    generated, this strategy may instead return the element which will index the
    first axis, e.g. ``5`` instead of ``(5,)``.

    * ``shape`` is the shape of the array that will be indexed, as a tuple of
      integers >= 0. This must be at least two-dimensional for a tuple to be a
      valid index;  for one-dimensional arrays use
      :func:`~hypothesis.strategies.slices` instead.
    * ``min_dims`` is the minimum dimensionality of the resulting array from use
      of the generated index.
    * ``max_dims`` is the the maximum dimensionality of the resulting array,
      defaulting to ``len(shape)``.
    * ``allow_ellipsis`` specifies whether ``...`` is allowed in the index.
    """
    check_type(tuple, shape, "shape")
    check_argument(
        all(isinstance(x, int) and x >= 0 for x in shape),
        f"shape={shape!r}, but all dimensions must be non-negative integers.",
    )
    check_type(bool, allow_ellipsis, "allow_ellipsis")
    check_type(int, min_dims, "min_dims")
    check_argument(
        min_dims <= len(shape),
        f"min_dims={min_dims} is larger than len(shape)={len(shape)}, "
        "but it is impossible for an indexing operation to add dimensions.",
    )
    check_valid_dims(min_dims, "min_dims")

    if max_dims is None:
        max_dims = min(len(shape), NDIM_MAX)
    check_type(int, max_dims, "max_dims")
    assert isinstance(max_dims, int)
    check_argument(
        max_dims <= len(shape),
        f"max_dims={max_dims} is larger than len(shape)={len(shape)}, "
        "but it is impossible for an indexing operation to add dimensions.",
    )
    check_valid_dims(max_dims, "max_dims")

    order_check("dims", 0, min_dims, max_dims)

    return BasicIndexStrategy(
        shape,
        min_dims=min_dims,
        max_dims=max_dims,
        allow_ellipsis=allow_ellipsis,
        allow_newaxis=False,
        allow_fewer_indices_than_dims=False,
    )
Example #2
0
def array_dtypes(
    subtype_strategy: st.SearchStrategy[np.dtype] = scalar_dtypes(),
    *,
    min_size: int = 1,
    max_size: int = 5,
    allow_subarrays: bool = False,
) -> st.SearchStrategy[np.dtype]:
    """Return a strategy for generating array (compound) dtypes, with members
    drawn from the given subtype strategy."""
    order_check("size", 0, min_size, max_size)
    # The empty string is replaced by f{idx}; see #1963 for details.  Much easier to
    # insist that field names be unique and just boost f{idx} strings manually.
    field_names = st.integers(0, 127).map("f{}".format) | st.text(min_size=1)
    name_titles = st.one_of(
        field_names,
        st.tuples(field_names, field_names).filter(lambda ns: ns[0] != ns[1]),
    )
    elements = st.tuples(name_titles, subtype_strategy)
    if allow_subarrays:
        elements |= st.tuples(name_titles, subtype_strategy,
                              array_shapes(max_dims=2, max_side=2))
    return st.lists(
        elements=elements,
        min_size=min_size,
        max_size=max_size,
        unique_by=(
            # Deduplicate by both name and title for efficiency before filtering.
            # (Field names must be unique, as must titles, and no intersections)
            lambda d: d[0] if isinstance(d[0], str) else d[0][0],
            lambda d: d[0] if isinstance(d[0], str) else d[0][1],
        ),
    ).filter(_no_title_is_name_of_a_titled_field)
Example #3
0
def unicode_string_dtypes(
    *, endianness: str = "?", min_len: int = 1, max_len: int = 16
) -> st.SearchStrategy[np.dtype]:
    """Return a strategy for generating unicode string dtypes, of various
    lengths and byteorder.

    While Hypothesis' string strategies can generate empty strings, string
    dtypes with length 0 indicate that size is still to be determined, so
    the minimum length for string dtypes is 1.
    """
    order_check("len", 1, min_len, max_len)
    return dtype_factory("U", list(range(min_len, max_len + 1)), None, endianness)
Example #4
0
def basic_indices(
    shape: Shape,
    *,
    min_dims: int = 0,
    max_dims: Optional[int] = None,
    allow_newaxis: bool = False,
    allow_ellipsis: bool = True,
) -> st.SearchStrategy[BasicIndex]:
    """Return a strategy for :doc:`basic indexes <numpy:reference/arrays.indexing>` of
    arrays with the specified shape, which may include dimensions of size zero.

    It generates tuples containing some mix of integers, :obj:`python:slice`
    objects, ``...`` (an ``Ellipsis``), and ``None``. When a length-one tuple
    would be generated, this strategy may instead return the element which will
    index the first axis, e.g. ``5`` instead of ``(5,)``.

    * ``shape`` is the shape of the array that will be indexed, as a tuple of
      positive integers. This must be at least two-dimensional for a tuple to be
      a valid index; for one-dimensional arrays use
      :func:`~hypothesis.strategies.slices` instead.
    * ``min_dims`` is the minimum dimensionality of the resulting array from use
      of the generated index. When ``min_dims == 0``, scalars and zero-dimensional
      arrays are both allowed.
    * ``max_dims`` is the the maximum dimensionality of the resulting array,
      defaulting to ``len(shape) if not allow_newaxis else
      max(len(shape), min_dims) + 2``.
    * ``allow_newaxis`` specifies whether ``None`` is allowed in the index.
    * ``allow_ellipsis`` specifies whether ``...`` is allowed in the index.
    """
    # Arguments to exclude scalars, zero-dim arrays, and dims of size zero were
    # all considered and rejected.  We want users to explicitly consider those
    # cases if they're dealing in general indexers, and while it's fiddly we can
    # back-compatibly add them later (hence using kwonlyargs).
    check_type(tuple, shape, "shape")
    check_argument(
        all(isinstance(x, int) and x >= 0 for x in shape),
        f"shape={shape!r}, but all dimensions must be non-negative integers.",
    )
    check_type(bool, allow_ellipsis, "allow_ellipsis")
    check_type(bool, allow_newaxis, "allow_newaxis")
    check_type(int, min_dims, "min_dims")
    if min_dims > len(shape) and not allow_newaxis:
        note_deprecation(
            f"min_dims={min_dims} is larger than len(shape)={len(shape)}, "
            "but allow_newaxis=False makes it impossible for an indexing "
            "operation to add dimensions.",
            since="2021-09-15",
            has_codemod=False,
        )
    check_valid_dims(min_dims, "min_dims")

    if max_dims is None:
        if allow_newaxis:
            max_dims = min(max(len(shape), min_dims) + 2, NDIM_MAX)
        else:
            max_dims = min(len(shape), NDIM_MAX)
    else:
        check_type(int, max_dims, "max_dims")
        if max_dims > len(shape) and not allow_newaxis:
            note_deprecation(
                f"max_dims={max_dims} is larger than len(shape)={len(shape)}, "
                "but allow_newaxis=False makes it impossible for an indexing "
                "operation to add dimensions.",
                since="2021-09-15",
                has_codemod=False,
            )
    check_valid_dims(max_dims, "max_dims")

    order_check("dims", 0, min_dims, max_dims)

    return BasicIndexStrategy(
        shape,
        min_dims=min_dims,
        max_dims=max_dims,
        allow_ellipsis=allow_ellipsis,
        allow_newaxis=allow_newaxis,
        allow_fewer_indices_than_dims=True,
    )