Skip to content

Commit

Permalink
Merge pull request #173 from asmeurer/release
Browse files Browse the repository at this point in the history
1.8 release
  • Loading branch information
asmeurer authored Feb 16, 2024
2 parents 369331c + b6a5152 commit ff95123
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 92 deletions.
115 changes: 115 additions & 0 deletions .github/workflows/publish-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: publish distributions
on:
push:
branches:
- main
tags:
- '[0-9]+.[0-9]+'
- '[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches:
- main
release:
types: [published]
workflow_dispatch:
inputs:
publish:
type: choice
description: 'Publish to TestPyPI?'
options:
- false
- true

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
name: Build Python distribution
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install python-build and twine
run: |
python -m pip install --upgrade pip setuptools
python -m pip install build twine
python -m pip list
- name: Install dependencies
run: python -m pip install -r requirements-dev.txt

- name: Build a wheel and a sdist
run: |
CYTHONIZE_NDINDEX=0 PYTHONWARNINGS=error,default::DeprecationWarning python -m build .
- name: Verify the distribution
run: twine check --strict dist/*

- name: List contents of sdist
run: python -m tarfile --list dist/ndindex-*.tar.gz

- name: List contents of wheel
run: python -m zipfile --list dist/ndindex-*.whl

- name: Upload distribution artifact
uses: actions/upload-artifact@v4
with:
name: dist-artifact
path: dist

publish:
name: Publish Python distribution to (Test)PyPI
if: github.event_name != 'pull_request' && github.repository == 'Quansight-Labs/ndindex'
needs: build
runs-on: ubuntu-latest
# Mandatory for publishing with a trusted publisher
# c.f. https://docs.pypi.org/trusted-publishers/using-a-publisher/
permissions:
id-token: write
contents: write
# Restrict to the environment set for the trusted publisher
environment:
name: publish-package

steps:
- name: Download distribution artifact
uses: actions/download-artifact@v4
with:
name: dist-artifact
path: dist

- name: List all files
run: ls -lh dist

- name: Publish distribution 📦 to Test PyPI
# Publish to TestPyPI on tag events of if manually triggered
# Compare to 'true' string as booleans get turned into strings in the console
if: >-
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags'))
|| (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true')
uses: pypa/gh-action-pypi-publish@v1.8.11
with:
repository-url: https://test.pypi.org/legacy/
print-hash: true

- name: Create GitHub Release from a Tag
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: dist/*

- name: Publish distribution 📦 to PyPI
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@v1.8.11
with:
print-hash: true
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
pytest $PYTEST_FLAGS
./run_doctests
# Make sure it installs
python setup.py install
pip install .
# Coverage. This also sets the failing status if the
# coverage is not 100%. Travis sometimes cuts off the last command, which is
# why we print stuff at the end.
Expand Down
56 changes: 55 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,62 @@
# ndindex Changelog

## Version 1.8 (2024-02-15)

### Major Changes

- **Breaking** {func}`~.broadcast_shapes` no longer returns `None` in the
place of skipped axes. The result is now just the non-skipped axes
broadcasted together.

- The `skip_axes` flag to {func}`~.iter_indices` and
{func}`~.broadcast_shapes` can now be a list of tuples, of skipped axes,
which apply to each respective shape independently.

- Mixing negative and nonnegative `skip_axes` in {func}`~.iter_indices` and
{func}`~.broadcast_shapes` is now supported. The only restriction is that
skip axes must refer to unique dimensions for each shape.

- New index method [`selected_indices()`](Tuple.selected_indices), which
iterates indices corresponding to each element selected by the given index
on an array of a given `shape`.

- ndindex indices can now be constructed by slicing the {func}`~.ndindex`
constructor function, like `ndindex[0:10]`. This is generally preferred for
indices with explicit slices, as this allows using the usual `:` slice
syntax instead of requiring slices to be spelled out with the `slice`
function.

- Add a `negative_int` flag to [`reduce`](Integer.reduce), which makes it
normalize integer indices to negative integers when a shape is provided.

- {class}`~.Slice` objects now hash to the same hash value as their
corresponding raw `slice` in Python 3.12, which now allows [native `slice`
objects to be
hashed](https://docs.python.org/3/whatsnew/3.12.html#other-language-changes).

- Fix an incorrect result from {any}`ChunkSize.as_subchunks()` and
{any}`ChunkSize.num_subchunks()` when using multiple array indices or a
boolean array index with multiple dimensions.

### Minor Changes

- Drop support for Python 3.7.

- Fully support the upcoming NumPy 2.0 release. This mostly only relevant for
the ndindex test suite, although it does also mean that one ndindex error
message has been updated to match updated wording from NumPy.

- Specify Cython language_level, which leads to shorter code and gets rid of a
bunch of warnings. (@keszybz)

- Rename the default git branch from `master` to `main`.


### Minor Changes

## Version 1.7 (2023-04-20)

## Major Changes
### Major Changes

- **Breaking:** the `skip_axes` argument {func}`~.iter_indices` function now
applies the skipped axes *before* broadcasting, not after. This behavior is
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ linkify-it-py
myst-parser
sphinx
sphinx-copybutton
sphinx-autobuild
24 changes: 11 additions & 13 deletions ndindex/ndindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ class NDIndexConstructor:
(generally, the same error NumPy would raise if the index were used on an
array).
Indices are created by calling `ndindex` with getitem syntax:
Indices are created by calling the `ndindex` with raw index objects:
>>> from ndindex import ndindex
>>> ndindex[1]
Integer(1)
>>> ndindex[0:10, :]
Tuple(slice(0, 10, None), slice(None, None, None))
>>> ndindex(slice(0, 10))
Slice(0, 10, None)
>>> ndindex((slice(0, 10), 0))
Tuple(slice(0, 10, None), 0)
You can also create indices by calling `ndindex(idx)` like a function.
However, if you do this, you cannot use the `a:b` slice syntax, as it is
not syntactically valid:
Indices can also be created by calling `ndindex` with getitem syntax.
>>> ndindex[1]
Integer(1)
>>> ndindex[0:10]
Slice(0, 10, None)
>>> ndindex(0:10)
Expand All @@ -32,9 +32,10 @@ class NDIndexConstructor:
ndindex(0:10)
^
SyntaxError: invalid syntax
>>> ndindex(slice(0, 10))
Slice(0, 10, None)
The `ndindex[idx]` form should generally be preferred when creating an
index from a tuple or slice literal, since `ndindex(a:b)` is not
syntactically valid and must be typed as `ndindex(slice(a, b))`.
Additionally, the `ndindex[idx]` syntax does not require parentheses when
creating a tuple index:
Expand All @@ -47,9 +48,6 @@ class NDIndexConstructor:
>>> ndindex((0, 1))
Tuple(0, 1)
Therefore `ndindex[idx]` should generally be preferred when creating an
index from a tuple or slice literal.
"""
def __getitem__(self, obj):
if isinstance(obj, NDIndex):
Expand Down
38 changes: 23 additions & 15 deletions ndindex/shapetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ def broadcast_shapes(*shapes, skip_axes=()):
<numpy.broadcast_shapes>`, except is also supports skipping axes in the
shape with `skip_axes`.
`skip_axes` can be a tuple of integers which apply to all shapes, or a
list of tuples of integers, one for each shape, which apply to each
respective shape. The `skip_axes` argument works the same as in
:func:`iter_indices`. See its docstring for more details.
If the shapes are not broadcast compatible (excluding `skip_axes`),
:class:`BroadcastError` is raised.
Expand All @@ -66,11 +71,11 @@ def broadcast_shapes(*shapes, skip_axes=()):
Axes in `skip_axes` apply to each shape *before* being broadcasted. Each
shape will be broadcasted together with these axes removed. The dimensions
in skip_axes do not need to be equal or broadcast compatible with one
in `skip_axes` do not need to be equal or broadcast compatible with one
another. The final broadcasted shape be the result of broadcasting all the
non-skip axes.
>>> broadcast_shapes((10, 3, 2), (20, 2), skip_axes=(0,))
>>> broadcast_shapes((10, 3, 2), (2, 20), skip_axes=[(0,), (1,)])
(3, 2)
"""
Expand Down Expand Up @@ -126,16 +131,20 @@ def iter_indices(*shapes, skip_axes=(), _debug=False):
The remaining axes will be indexed one element at a time with integer
indices.
`skip_axes` should be a tuple of axes to skip. It can use negative
integers, e.g., `skip_axes=(-1,)` will skip the last axis (but note that
mixing negative and nonnegative skip axes is currently not supported). The
order of the axes in `skip_axes` does not matter. The axes in `skip_axes`
refer to the shapes *before* broadcasting (if you want to refer to the
axes after broadcasting, either broadcast the shapes and arrays first, or
refer to the axes using negative integers). For example,
`iter_indices((10, 2), (20, 1, 2), skip_axes=(0,))` will skip the size
`10` axis of `(10, 2)` and the size `20` axis of `(20, 1, 2)`. The result
is two sets of indices, one for each element of the non-skipped
`skip_axes` should be a tuple of axes to skip or a list of tuples of axes
to skip. If it is a single tuple, it applies to all shapes. Otherwise,
each tuple applies to each shape respectively. It can use negative
integers, e.g., `skip_axes=(-1,)` will skip the last axis. The order of
the axes in `skip_axes` does not matter. Mixing negative and nonnegative
skip axes is supported, but the skip axes must refer to unique dimensions
for each shape.
The axes in `skip_axes` refer to the shapes *before* broadcasting (if you
want to refer to the axes after broadcasting, either broadcast the shapes
and arrays first, or refer to the axes using negative integers). For
example, `iter_indices((10, 2), (20, 1, 2), skip_axes=(0,))` will skip the
size `10` axis of `(10, 2)` and the size `20` axis of `(20, 1, 2)`. The
result is two sets of indices, one for each element of the non-skipped
dimensions:
>>> from ndindex import iter_indices
Expand Down Expand Up @@ -194,9 +203,8 @@ def iter_indices(*shapes, skip_axes=(), _debug=False):
[110, 111, 112]])
To include an index into the final broadcasted array, you can simply
include the final broadcasted shape as one of the shapes (the NumPy
function :func:`np.broadcast_shapes() <numpy:numpy.broadcast_shapes>` is
useful here).
include the final broadcasted shape as one of the shapes (the function
:func:`broadcast_shapes` is useful here).
>>> np.broadcast_shapes((1, 3), (2, 1))
(2, 3)
Expand Down
1 change: 1 addition & 0 deletions ndindex/tests/test_booleanarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def test_booleanarray_reduce_no_shape_hypothesis(idx, shape, kwargs):

check_same(a, index.raw, ndindex_func=lambda a, x: a[x.reduce(**kwargs).raw])

@example(full((1, 9), True), 3, {})
@example(full((1, 9), True), (3, 3), {})
@example(full((1, 9), False), (3, 3), {})
@given(boolean_arrays, one_of(short_shapes, integers(0, 10)), reduce_kwargs)
Expand Down
1 change: 1 addition & 0 deletions ndindex/tests/test_chunking.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ def test_num_subchunks_error():
raises(ValueError, lambda: next(ChunkSize((1, 2)).num_subchunks(..., (1, 2, 3))))


@example((2, 2), (0, False), (5, 5))
@example((5,), [0, 7], (15,))
@example((5,), [], (15,))
@given(chunk_sizes(), ndindices, chunk_shapes)
Expand Down
1 change: 1 addition & 0 deletions ndindex/tests/test_shapetools.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ def test_asshape():
raises(TypeError, lambda: asshape(np.int64(1), allow_int=False))
raises(IndexError, lambda: asshape((2, 3), 3))

@example([(5,)], (10,))
@example([], [])
@example([()], [])
@example([(0, 1)], 0)
Expand Down
62 changes: 0 additions & 62 deletions rever.xsh

This file was deleted.

0 comments on commit ff95123

Please sign in to comment.