-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-83791: Raise TypeError for len(memoryview_0d) #18463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-83791: Raise TypeError for len(memoryview_0d) #18463
Conversation
530d5f3
to
5200b72
Compare
Lib/ctypes/test/test_pep3118.py
Outdated
if v.shape: | ||
n = 1 | ||
for dim in v.shape: | ||
n = n * dim | ||
self.assertEqual(n * v.itemsize, len(v.tobytes())) | ||
n = 1 | ||
for dim in v.shape: | ||
n = n * dim | ||
self.assertEqual(n * v.itemsize, len(v.tobytes())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if
was a pointless special case
Lib/ctypes/test/test_pep3118.py
Outdated
if v.shape: | ||
n = 1 | ||
for dim in v.shape: | ||
n = n * dim | ||
self.assertEqual(n, len(v)) | ||
n = 1 | ||
for dim in v.shape: | ||
n = n * dim | ||
self.assertEqual(n * v.itemsize, len(v.tobytes())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This if
always evaluated to False
, so the garbage code within it never ran. Fixed to be identical to the above.
5200b72
to
b897e68
Compare
This makes `memoryview.__len__` consistent with `memoryview.__getitem__`. Also activates and fixes a bug in dead code in the `test_endian` test, which was only being run on 0d arrays.
b897e68
to
c210029
Compare
Codecov Report
@@ Coverage Diff @@
## master #18463 +/- ##
==========================================
+ Coverage 82.11% 82.13% +0.02%
==========================================
Files 1955 1955
Lines 588958 584775 -4183
Branches 44428 44488 +60
==========================================
- Hits 483632 480330 -3302
+ Misses 95677 94794 -883
- Partials 9649 9651 +2
Continue to review full report at Codecov.
|
the length is equal to the length of the nested list representation of | ||
the view. The :class:`~memoryview.itemsize` attribute will give you the | ||
number of bytes in a single element. | ||
``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the documented behavior was changed, it needs a versionchanged
directive and an entry in What's New.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I put this in the 3.9 what's new? This sounds like a recipe for merge conflicts, until the rest of the patch has general approval.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checking in on this - what's the procedure for adding a what's new entry if I have no idea which python version this will end up being merged into?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use version 3.10
. It cannot go into earlier versions since it's a behavior change. And we have ample time for deliberation on how the documented behavior emerged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've update it to say 3.11
, since it's been two years since I changed it to say 3.10
. Let me know if it should be 3.12
instead.
@@ -0,0 +1,8 @@ | |||
0d ``memoryview`` objects no longer have a ``len``:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK there are issues with multi-paragraph NEWS entry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you prefer me to keep just the first line here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure that the meaning of words "have a len()" is clear.
Maybe something like "len() for 0-dimensional memoryview objects raises now a TypeError"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed to your proposed wording.
34d362d
to
dbad24a
Compare
``len()`` for 0-dimensional ``memoryview`` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a ``TypeError``. | ||
Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` raising an ``IndexError``. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably there should be a :class:
or :type:
or :exc:
in here somewhere; can a reviewer advise what the convention is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@mdickinson: any chance you're willing to review one more buffer-related PR? This one isn't quite as old as the other two of mine you rescued, but it's getting close! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change LGTM in principle, and code looks fine, too.
Question: did you consider using ValueError
instead of TypeError
? Given that len
works for most memoryview
objects, the failure is arguably due to value rather than to type. It doesn't seem clear cut: I know NumPy raises TypeError
for len(np.array(some_scalar))
, and it would be annoying to be inconsistent with that.
I'll leave this open for a few days in case anyone else previously involved in the discussion wants to chip in, and then merge. (@eric-wieser Feel free to ping me if this remains unmerged by April 22nd. The beta 1 cutoff is May 8th.)
I'm afraid I don't remember what I considered at the time (which is obviously a lesson in writing better commit messages). I'll see if I can come up with an argument either way. |
I suspect consistency with numpy was the main argument; along with consistency with >>> import numpy as np
>>> arr_0d = np.array(42)
>>> mem_0d = memoryview(arr_0d)
>>> len(arr_0d)
TypeError: len() of unsized object
>>> len(mem_0d.tolist())
TypeError: object of type 'int' has no len()
>>> len(mem_0d)
TypeError: 0-dim memory has no length # with this PR |
This makes
memoryview.__len__
consistent withmemoryview.__getitem__
.https://bugs.python.org/issue39610
(#83791)