Skip to content
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

Merged
merged 8 commits into from
Apr 22, 2023

Conversation

eric-wieser
Copy link
Contributor

@eric-wieser eric-wieser commented Feb 11, 2020

This makes memoryview.__len__ consistent with memoryview.__getitem__.

https://bugs.python.org/issue39610

(#83791)

Comment on lines 42 to 45
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()))
Copy link
Contributor Author

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

Comment on lines 70 to 72
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()))
Copy link
Contributor Author

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.

@eric-wieser eric-wieser force-pushed the fix-memorview-__len__-issue39610 branch from 5200b72 to b897e68 Compare February 11, 2020 17:15
@pitrou pitrou requested a review from skrah February 26, 2020 23:46
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.
@eric-wieser eric-wieser force-pushed the fix-memorview-__len__-issue39610 branch from b897e68 to c210029 Compare March 2, 2020 11:26
@codecov
Copy link

codecov bot commented Mar 2, 2020

Codecov Report

Merging #18463 into master will increase coverage by 0.02%.
The diff coverage is n/a.

Impacted file tree graph

@@            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     
Impacted Files Coverage Δ
Lib/distutils/tests/test_bdist_rpm.py 30.00% <0.00%> (-65.00%) ⬇️
Lib/distutils/command/bdist_rpm.py 7.63% <0.00%> (-56.88%) ⬇️
Modules/_decimal/libmpdec/umodarith.h 80.76% <0.00%> (-19.24%) ⬇️
Lib/test/test_urllib2net.py 76.92% <0.00%> (-13.85%) ⬇️
Lib/test/test_smtpnet.py 78.57% <0.00%> (-7.15%) ⬇️
Lib/ftplib.py 63.85% <0.00%> (-6.06%) ⬇️
Lib/test/test_ftplib.py 87.11% <0.00%> (-4.72%) ⬇️
Tools/scripts/db2pickle.py 17.82% <0.00%> (-3.97%) ⬇️
Tools/scripts/pickle2db.py 16.98% <0.00%> (-3.78%) ⬇️
Lib/test/test_socket.py 71.94% <0.00%> (-3.77%) ⬇️
... and 399 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f3e7ea5...c210029. Read the comment docs.

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
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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``::
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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"?

Copy link
Contributor Author

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.

@cpython-cla-bot
Copy link

cpython-cla-bot bot commented Jul 7, 2022

All commit authors signed the Contributor License Agreement.
CLA signed

@eric-wieser eric-wieser force-pushed the fix-memorview-__len__-issue39610 branch from 34d362d to dbad24a Compare July 7, 2022 22:32
@eric-wieser eric-wieser requested review from serhiy-storchaka and removed request for skrah August 15, 2022 22:54
Doc/library/stdtypes.rst Outdated Show resolved Hide resolved
@arhadthedev arhadthedev changed the title bpo-39610: Raise TypeError for len(memoryview_0d) gh-83791: Raise TypeError for len(memoryview_0d) Feb 21, 2023
@arhadthedev arhadthedev added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label Feb 21, 2023
Comment on lines 1 to 2
``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``.
Copy link
Contributor Author

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@eric-wieser
Copy link
Contributor Author

@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!

Copy link
Member

@mdickinson mdickinson left a 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.)

@eric-wieser
Copy link
Contributor Author

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.

@eric-wieser
Copy link
Contributor Author

eric-wieser commented Apr 19, 2023

I suspect consistency with numpy was the main argument; along with consistency with to_list:

>>> 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants