Skip to content

Replace shape assignment with reshape calls#1106

Merged
rapids-bot[bot] merged 8 commits into
rapidsai:mainfrom
jakirkham:use_reshape
Jun 25, 2026
Merged

Replace shape assignment with reshape calls#1106
rapids-bot[bot] merged 8 commits into
rapidsai:mainfrom
jakirkham:use_reshape

Conversation

@jakirkham

Copy link
Copy Markdown
Member

NumPy is deprecating direct shape assignment. The underlying code path simply goes through reshape. So just switch to reshape to eliminate the deprecation warning and future proof the code.

ref: https://github.com/numpy/numpy/blob/2a674fc909ef47631e4f6550e25817731534987f/numpy/_core/src/multiarray/getset.c#L64

NumPy is deprecating direct `shape` assignment. The underlying code path
simply goes through `reshape`. So just switch to `reshape` to eliminate
the deprecation warning and future proof the code.

ref: https://github.com/numpy/numpy/blob/2a674fc909ef47631e4f6550e25817731534987f/numpy/_core/src/multiarray/getset.c#L64
@jakirkham jakirkham requested a review from a team as a code owner June 24, 2026 18:05
@jakirkham jakirkham added bug Something isn't working non-breaking Introduces a non-breaking change labels Jun 24, 2026
if not hasattr(data, "__cuda_array_interface__"):
data = np.frombuffer(data, np.uint8)
data.shape = tile_shape
data = data.reshape(tile_shape, copy=False)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current behavior of .shape assignment is to call reshape and error if a copy occurs. Equivalent behavior can be implemented by calling .reshape(...) with the copy keyword argument as False

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the discussion below, all of these were dropped because CuPy's reshape doesn't support the copy keyword argument and they were either unneeded in that context or the intended behavior could be captured other ways.

@grlee77 grlee77 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @jakirkham this changes to avoid shape assignment look good to me

@seberg seberg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, looks all better and safe. Not sure if the last can see NumPy arrays but it hardly matters.
(The first feels like it might be a latent fix, but probably not in practice.)

Comment on lines 411 to 412
x_view = x.reshape((ndim, 2), copy=False)
return x_view.tolist()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given we call .tolist(...) here, avoiding a copy probably doesn't matter much. After all this is an array that is already created as C-contiguous above, so the copy shouldn't happen anyways.

This would better match the same upstream change: cupy/cupy#10037

Suggested change
x_view = x.reshape((ndim, 2), copy=False)
return x_view.tolist()
x_view = x.reshape((ndim, 2))
return x_view.tolist()

@jakirkham jakirkham Jun 24, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included in commit: 9c75cbb

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Reshapes are always no-copy by default if possible, so unless any of these could error it doesn't matter.
(But yes, it adds the guarantee, which may makes sense for the other cases)

This array is constructed so that copying shouldn't happen and it is a
small array (extents). Plus `the `.tolist()` call will copy it in the
end anyways. So drop the `copy=False` keyword argument.

Co-authored-by: jakirkham <jakirkham@gmail.com>
if not hasattr(data, "__cuda_array_interface__"):
data = np.frombuffer(data, np.uint8)
data.shape = tile_shape
data = data.reshape(tile_shape, copy=False)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, this one could be a problem, though? Because cupy doesn't have copy=False (should probably add that).
And the hasattr() above looks like the input may or may not be a CuPy array?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Looking at CuPy's reshape logic it appears to behave similar to NumPy's copy=None. Besides the NumPy case is already starting from a 1-D contiguous array so shouldn't copy anyways. So perhaps we can just drop this keyword argument

Suggested change
data = data.reshape(tile_shape, copy=False)
data = data.reshape(tile_shape)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included in commit: bfb7cd0

@jakirkham jakirkham requested a review from a team as a code owner June 24, 2026 20:06
@jakirkham jakirkham requested a review from jameslamb June 24, 2026 20:06
Comment on lines +151 to +154
# https://github.com/cupy/cupy/blob/v14.1.1/cupy/_padding/pad.py#L408
"ignore:Setting the shape on a NumPy array:DeprecationWarning:cupy",
# https://github.com/scikit-image/scikit-image/blob/v0.26.0/skimage/measure/_marching_cubes_lewiner.py#L237
"ignore:Setting the shape on a NumPy array:DeprecationWarning:skimage",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have picked up @bdice fixes from PR: #1105

Was still seeing some test failures without them. Hoping by combining them we can get a clean CI run

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the warnings in CuPy are being fixed by @seberg in PR: cupy/cupy#10037

The warnings in scikit-image will be fixed in 0.27 with PR: scikit-image/scikit-image#8020

Comment thread python/cucim/src/cucim/skimage/util/_map_array.py Outdated
Co-authored-by: jakirkham <jakirkham@gmail.com>
Comment on lines +88 to +89
out_view = out.view()
out_view.shape = (-1,) # no-copy reshape/ravel

@jakirkham jakirkham Jun 24, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have reverted to the original syntax here as CuPy's reshape doesn't support the copy keyword argument and we really must avoid a copy here. So the best way to do this with CuPy is to assign to .shape. This is unfortunate, but it should work as intended.

Edit - Filed an upstream request to add the copy keyword argument to reshape: cupy/cupy#10039

@bdice bdice left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

@jakirkham

Copy link
Copy Markdown
Member Author

Thanks all! 🙏

@jakirkham

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot rapids-bot Bot merged commit b4ad404 into rapidsai:main Jun 25, 2026
68 checks passed
@jakirkham jakirkham deleted the use_reshape branch June 25, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working non-breaking Introduces a non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants