From dc5e56d28521146f977f910cec3718dfd614de57 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 21 Mar 2023 18:20:29 +0000 Subject: [PATCH 1/2] Add a page on exceptions, and treat exceptions more consistently Closes gh-606 --- spec/draft/design_topics/exceptions.rst | 28 +++++++++++++++++++ spec/draft/design_topics/index.rst | 1 + .../_draft/manipulation_functions.py | 23 +++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 spec/draft/design_topics/exceptions.rst diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst new file mode 100644 index 000000000..0a176c302 --- /dev/null +++ b/spec/draft/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and use either +fitting builtin exception or warning types that are appropriate for the +situation, or custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not existing array library implementation already differ in their +choices and it may not be worth them breaking backwards compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/draft/design_topics/index.rst b/spec/draft/design_topics/index.rst index c8c5a0733..fa26359a7 100644 --- a/spec/draft/design_topics/index.rst +++ b/spec/draft/design_topics/index.rst @@ -11,6 +11,7 @@ Design topics & constraints device_support static_typing accuracy + exceptions complex_numbers C_API parallelism diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2d7179a8b..2a4b612f5 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -67,12 +67,17 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: x: array input array. axis: int - axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). Returns ------- out: array an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. """ @@ -125,12 +130,18 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - boolean indicating whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. """ @@ -169,12 +180,18 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: x: array input array. axis: Union[int, Tuple[int, ...]] - axis (or axes) to squeeze. If a specified axis has a size greater than one, a ``ValueError`` must be raised. + axis (or axes) to squeeze. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one, i.e. it is not a + singleton dimension, a ``ValueError`` should be raised. """ From 73c7fcb0793a0a1f7c603bf444fb7e0ccab281fe Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Apr 2023 00:37:35 -0700 Subject: [PATCH 2/2] Apply suggestions from code review --- spec/draft/design_topics/exceptions.rst | 12 ++++++------ src/array_api_stubs/_draft/manipulation_functions.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst index 0a176c302..570fe56e3 100644 --- a/spec/draft/design_topics/exceptions.rst +++ b/spec/draft/design_topics/exceptions.rst @@ -5,23 +5,23 @@ Exceptions This standard specifies expected syntax and semantics for a set of APIs. When inputs to an API do not match what is expected, libraries may emit warnings, -raise exceptions, or misbehave in unexpected ways. In general it is not +raise exceptions, or misbehave in unexpected ways. In general, it is not possible to foresee or specify all the ways in which unexpected or invalid inputs are provided. Therefore, this standard does not attempt to specify exception or warning types to the extent needed in order to do exception handling in a portable manner. In general, it is expected that array library implementers follow `the guidance given by the documentation of the Python -language `__, and use either -fitting builtin exception or warning types that are appropriate for the -situation, or custom exceptions or warnings that derive from those builtin +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin ones. In specific cases, it may be useful to provide guidance to array library authors regarding what an appropriate exception is. That guidance will be phrased as *should* rather than *must* (typically in a *Raises* section), because (a) there may be reasons for an implementer to deviate, and (b) more -often than not existing array library implementation already differ in their -choices and it may not be worth them breaking backwards compatibility in order +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order to comply with a "must" in this standard. In other cases, this standard will only specify that an exception should or diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2a4b612f5..99a40057a 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -130,7 +130,7 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. Returns ------- @@ -190,8 +190,8 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: Raises ------ ValueError - If a specified axis has a size greater than one, i.e. it is not a - singleton dimension, a ``ValueError`` should be raised. + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. """