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

SystemError on calling len() if __len__() doesn't return an int #47979

Closed
hagen mannequin opened this issue Aug 29, 2008 · 10 comments
Closed

SystemError on calling len() if __len__() doesn't return an int #47979

hagen mannequin opened this issue Aug 29, 2008 · 10 comments
Labels
type-bug An unexpected behavior, bug, or error

Comments

@hagen
Copy link
Mannequin

hagen mannequin commented Aug 29, 2008

BPO 3729
Nosy @birkenfeld, @amauryfa, @benjaminp
Files
  • len_check3.diff: patch fixing the SystemError and clipping to sys.maxsize, adds tests
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2009-02-10.12:52:53.722>
    created_at = <Date 2008-08-29.14:59:07.938>
    labels = ['type-bug']
    title = "SystemError on calling len() if __len__() doesn't return an int"
    updated_at = <Date 2009-02-10.12:52:53.716>
    user = 'https://bugs.python.org/hagen'

    bugs.python.org fields:

    activity = <Date 2009-02-10.12:52:53.716>
    actor = 'benjamin.peterson'
    assignee = 'none'
    closed = True
    closed_date = <Date 2009-02-10.12:52:53.722>
    closer = 'benjamin.peterson'
    components = []
    creation = <Date 2008-08-29.14:59:07.938>
    creator = 'hagen'
    dependencies = []
    files = ['11349']
    hgrepos = []
    issue_num = 3729
    keywords = ['patch']
    message_count = 10.0
    messages = ['72141', '72142', '72143', '72145', '72151', '72153', '72195', '72196', '72360', '81545']
    nosy_count = 4.0
    nosy_names = ['georg.brandl', 'amaury.forgeotdarc', 'benjamin.peterson', 'hagen']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = None
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue3729'
    versions = ['Python 2.6', 'Python 3.0']

    @hagen
    Copy link
    Mannequin Author

    hagen mannequin commented Aug 29, 2008

    On Python 3.0:

    >>> class C:
    ...     def __len__(self): return "foo"
    ...
    >>> len(C())
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    SystemError: Objects/longobject.c:433: bad argument to internal function

    On Python 2.6 the behaviour is different for old and new-style classes,
    with old-style classes giving the more informative error message and
    both accepting (and truncating) floats.

    I attached a patch for Python 3.0, which refuses everything but ints and
    gives an informative error message. Or does the float-truncating
    behaviour of Python 2.x need to be preserved?

    @hagen hagen mannequin added the type-bug An unexpected behavior, bug, or error label Aug 29, 2008
    @amauryfa
    Copy link
    Member

    What about using PyNumber_AsSsize_t? it uses PyNumber_Index to accept
    integral-like types, and refuses floats.

    @hagen
    Copy link
    Mannequin Author

    hagen mannequin commented Aug 29, 2008

    Sounds ok, but then you get a more generic "object cannot be interpreted
    as an integer" at the point where len() is called, instead of the
    clearer "__len__() should return an int". I'm not sure if this could be
    confusing.

    @hagen
    Copy link
    Mannequin Author

    hagen mannequin commented Aug 29, 2008

    Of course we can do both: Accept integral-like types and reset the
    exception text. The new patch does this and adds a test for the new
    behaviour.

    Review carefully - I'm a newbie! ;-)

    @amauryfa
    Copy link
    Member

    Not bad! some remarks though:

    • It's better to avoid the "expensive" call to PyErr_Occurred() when
      possible. Here, an exception is set if (and only if) len==-1.
      For example, it is enough to add these lines after the "__len__() should
      return >= 0" message:

    + else if (PyErr_ExceptionMatches(PyExc_TypeError))
    + PyErr_SetString(PyExc_TypeError,
    + "__len__() should return an int");

    • Please clarify (that is: add tests for) the case where __len__ returns
      1<<50 or -1<<50. If I remember correctly, PyNumber_AsSsize_t(res, NULL)
      clips the values to MAXINT. Is this wanted?

    @birkenfeld
    Copy link
    Member

    That is *not* wanted. We had a discussion on the list about changing the
    return value of the sq_length slot to allow larger lengths to be
    reported, and while I don't recall why this wasn't done, I do recall
    that the consensus was that if Py_ssize_t remains, len() should raise
    rather than lie for larger values-

    @hagen
    Copy link
    Mannequin Author

    hagen mannequin commented Aug 30, 2008

    In the latest list message I could find Guido wanted len() to lie:

    http://mail.python.org/pipermail/python-3000/2008-May/013387.html

    Has this been resolved in bpo-2723?

    @birkenfeld
    Copy link
    Member

    True. However, it's no pronouncement either. I suggest bringing it up on
    the list again; probably other people would want to voice their opinions
    too.

    @hagen
    Copy link
    Mannequin Author

    hagen mannequin commented Sep 2, 2008

    There seems to be a pronouncement now
    (http://mail.python.org/pipermail/python-3000/2008-September/014692.html),
    so I'm attaching a patch which clips to sys.maxsize and includes
    Amaury's suggestions.

    @benjaminp
    Copy link
    Contributor

    Fixed in bpo-5137.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants