Hypothesis strategies for Array API

hypothesis_array.get_strategies_namespace(xp)

Creates a strategies namespace for the given array module.

  • xp is the Array API library to automatically pass to the namespaced methods.

A types.SimpleNamespace is returned which contains all the strategy methods in this module but without requiring the xp argument.

Creating and using a strategies namespace for NumPy’s Array API implemention would go like this:

>>> from numpy import array_api as xp
>>> xps = get_strategies_namespace(xp)
>>> x = xps.arrays(xp.int8, (2, 3)).example()
>>> x
Array([[-8,  6,  3],
       [-6,  4,  6]], dtype=int8)
>>> x.__array_namespace__() is xp
True
hypothesis_array.from_dtype(xp, dtype, *, min_value=None, max_value=None, allow_nan=None, allow_infinity=None, exclude_min=None, exclude_max=None)

Return a strategy for any value of the given dtype.

Values generated are of the Python scalar which is promotable to dtype, where the values do not exceed its bounds.

  • dtype may be a dtype object or the string name of a valid dtype.

Compatible **kwargs are passed to the inferred strategy function for integers and floats. This allows you to customise the min and max values, and exclude non-finite numbers. This is particularly useful when kwargs are passed through from arrays(), as it seamlessly handles the width or other representable bounds for you.

hypothesis_array.arrays(xp, dtype, shape, *, elements=None, fill=None, unique=False)

Returns a strategy for arrays.

  • dtype may be a valid dtype object or name, or a strategy that generates such values.

  • shape may be an integer >= 0, a tuple of such integers, or a strategy that generates such values.

  • elements is a strategy for values to put in the array. If None then a suitable value will be inferred based on the dtype, which may give any legal value (including e.g. NaN for floats). If a mapping, it will be passed as **kwargs to from_dtype() when inferring based on the dtype.

  • fill is a strategy that may be used to generate a single background value for the array. If None, a suitable default will be inferred based on the other arguments. If set to nothing() then filling behaviour will be disabled entirely and every element will be generated independently.

  • unique specifies if the elements of the array should all be distinct from one another. Note that in this case multiple NaN values may still be allowed. If fill is also set, the only valid values for fill to return are NaN values.

Arrays of specified dtype and shape are generated for example like this:

>>> from numpy import array_api as xp
>>> arrays(xp, xp.int8, (2, 3)).example()
Array([[-8,  6,  3],
       [-6,  4,  6]], dtype=int8)

Specifying element boundaries by a dict of the kwargs to pass to from_dtype() will ensure dtype bounds will be respected.

>>> arrays(xp, xp.int8, 3, elements={"min_value": 10}).example()
Array([125, 13, 79], dtype=int8)

Refer to What you can generate and how for passing your own elements strategy.

>>> arrays(xp, xp.float32, 3, elements=floats(0, 1, width=32)).example()
Array([ 0.88974794,  0.77387938,  0.1977879 ], dtype=float32)

Array values are generated in two parts:

  1. A single value is drawn from the fill strategy and is used to create a filled array.

  2. Some subset of the coordinates of the array are populated with a value drawn from the elements strategy (or its inferred form).

You can set fill to nothing() if you want to disable this behaviour and draw a value for every element.

By default arrays will attempt to infer the correct fill behaviour: if unique is also True, no filling will occur. Otherwise, if it looks safe to reuse the values of elements across multiple coordinates (this will be the case for any inferred strategy, and for most of the builtins, but is not the case for mutable values or strategies built with flatmap, map, composite, etc.) then it will use the elements strategy as the fill, else it will default to having no fill.

Having a fill helps Hypothesis craft high quality examples, but its main importance is when the array generated is large: Hypothesis is primarily designed around testing small examples. If you have arrays with hundreds or more elements, having a fill value is essential if you want your tests to run in reasonable time.

hypothesis_array.array_shapes(*, min_dims=1, max_dims=None, min_side=1, max_side=None)

Return a strategy for array shapes (tuples of int >= 1).

  • min_dims is the smallest length that the generated shape can possess.

  • max_dims is the largest length that the generated shape can possess, defaulting to min_dims + 2.

  • min_side is the smallest size that a dimension can possess.

  • max_side is the largest size that a dimension can possess, defaulting to min_side + 5.

hypothesis_array.scalar_dtypes(xp)

Return a strategy for all valid dtype objects.

hypothesis_array.numeric_dtypes(xp)

Return a strategy for all numeric dtype objects.

hypothesis_array.integer_dtypes(xp, *, sizes=(8, 16, 32, 64))

Return a strategy for signed integer dtype objects.

sizes contains the signed integer sizes in bits, defaulting to (8, 16, 32, 64) which covers all valid sizes.

hypothesis_array.unsigned_integer_dtypes(xp, *, sizes=(8, 16, 32, 64))

Return a strategy for unsigned integer dtype objects.

sizes contains the unsigned integer sizes in bits, defaulting to (8, 16, 32, 64) which covers all valid sizes.

hypothesis_array.floating_dtypes(xp, *, sizes=(32, 64))

Return a strategy for floating-point dtype objects.

sizes contains the floating-point sizes in bits, defaulting to (32, 64) which covers all valid sizes.

hypothesis_array.valid_tuple_axes(ndim, *, min_size=0, max_size=None)

Return a strategy for permissable tuple-values for the axis argument in Array API sequential methods e.g. sum, given the specified dimensionality.

All tuples will have a length >= min_size and <= max_size. The default value for max_size is ndim.

Examples from this strategy shrink towards an empty tuple, which render most sequential functions as no-ops.

The following are some examples drawn from this strategy.

>>> [valid_tuple_axes(3).example() for i in range(4)]
[(-3, 1), (0, 1, -1), (0, 2), (0, -2, 2)]

valid_tuple_axes can be joined with other strategies to generate any type of valid axis object, i.e. integers, tuples, and None:

any_axis_strategy = none() | integers(-ndim, ndim - 1) | valid_tuple_axes(ndim)
hypothesis_array.broadcastable_shapes(shape, *, min_dims=0, max_dims=None, min_side=1, max_side=None)

Return a strategy for shapes that are broadcast-compatible with the provided shape.

Examples from this strategy shrink towards a shape with length min_dims. The size of an aligned dimension shrinks towards size 1. The size of an unaligned dimension shrink towards min_side.

  • shape is a tuple of integers.

  • min_dims is the smallest length that the generated shape can possess.

  • max_dims is the largest length that the generated shape can possess, defaulting to min(32, max(len(shape), min_dims) + 2).

  • min_side is the smallest size that an unaligned dimension can possess.

  • max_side is the largest size that an unaligned dimension can possess, defaulting to 2 plus the size of the largest aligned dimension.

The following are some examples drawn from this strategy.

>>> [broadcastable_shapes(shape=(2, 3)).example() for i in range(5)]
[(1, 3), (), (2, 3), (2, 1), (4, 1, 3), (3, )]
hypothesis_array.mutually_broadcastable_shapes(num_shapes, *, base_shape=(), min_dims=0, max_dims=None, min_side=1, max_side=None)

Return a strategy for a specified number of shapes N that are mutually-broadcastable with one another and with the provided base shape.

  • num_shapes is the number of mutually broadcast-compatible shapes to generate.

  • base_shape is the shape against which all generated shapes can broadcast. The default shape is empty, which corresponds to a scalar and thus does not constrain broadcasting at all.

  • shape is a tuple of integers.

  • min_dims is the smallest length that the generated shape can possess.

  • max_dims is the largest length that the generated shape can possess, defaulting to min(32, max(len(shape), min_dims) + 2).

  • min_side is the smallest size that an unaligned dimension can possess.

  • max_side is the largest size that an unaligned dimension can possess, defaulting to 2 plus the size of the largest aligned dimension.

The strategy will generate a typing.NamedTuple containing:

  • input_shapes as a tuple of the N generated shapes.

  • result_shape as the resulting shape produced by broadcasting the N shapes with the base shape.

The following are some examples drawn from this strategy.

>>> # Draw three shapes where each shape is broadcast-compatible with (2, 3)
... strat = mutually_broadcastable_shapes(num_shapes=3, base_shape=(2, 3))
>>> for _ in range(5):
...     print(strat.example())
BroadcastableShapes(input_shapes=((3,), (1,), (2, 1)), result_shape=(2, 3))
BroadcastableShapes(input_shapes=((3,), (1, 3), (2, 3)), result_shape=(2, 3))
BroadcastableShapes(input_shapes=((), (), ()), result_shape=(2, 3))
BroadcastableShapes(input_shapes=((3,), (), (3,)), result_shape=(2, 3))
BroadcastableShapes(input_shapes=((1, 2, 3), (3,), ()), result_shape=(1, 2, 3))
hypothesis_array.indices(shape, *, min_dims=1, max_dims=None, allow_ellipsis=True, allow_none=False)

Return a strategy for valid indices of arrays with the specified shape.

It generates tuples containing some mix of integers, 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 integers >= 0. This must be at least two-dimensional for a tuple to be a valid index; for one-dimensional arrays use slices() instead.

  • min_dims is the minimum dimensionality of the resulting array from use of the generated index. If min_dims == 0, zero-dimensional arrays are allowed.

  • max_dims is the the maximum dimensionality of the resulting array, defaulting to max(len(shape), min_dims) + 2.

  • allow_ellipsis specifies whether ... is allowed in the index.

  • allow_none specifies whether None is allowed in the index.