python / cpython

The Python programming language
https://www.python.org
Other
62.75k stars 30.08k forks source link

Set operations don't work for dictionary views #52651

Closed akuchling closed 14 years ago

akuchling commented 14 years ago
BPO 8404
Nosy @akuchling, @rhettinger, @abalkin, @ericvsmith, @avassalotti, @ezio-melotti
Files
  • fix_dictviews_set_operations.diff
  • issue8404_tests_py3k.diff: Patch against py3k revision 80615
  • 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: ```python assignee = 'https://github.com/avassalotti' closed_at = created_at = labels = ['type-bug', 'release-blocker'] title = "Set operations don't work for dictionary views" updated_at = user = 'https://github.com/akuchling' ``` bugs.python.org fields: ```python activity = actor = 'rhettinger' assignee = 'alexandre.vassalotti' closed = True closed_date = closer = 'alexandre.vassalotti' components = [] creation = creator = 'akuchling' dependencies = [] files = ['16966', '17127'] hgrepos = [] issue_num = 8404 keywords = ['patch'] message_count = 10.0 messages = ['103166', '103177', '103436', '104517', '104911', '105095', '105097', '105106', '105112', '105150'] nosy_count = 6.0 nosy_names = ['akuchling', 'rhettinger', 'belopolsky', 'eric.smith', 'alexandre.vassalotti', 'ezio.melotti'] pr_nums = [] priority = 'release blocker' resolution = 'accepted' stage = 'resolved' status = 'closed' superseder = None type = 'behavior' url = 'https://bugs.python.org/issue8404' versions = ['Python 2.7'] ```

    akuchling commented 14 years ago

    The examples of set operations in http://docs.python.org/dev/library/stdtypes#dictionary-view-objects don't work in the current 2.7 trunk:

    -> ./python.exe
    Python 2.7b1+ (trunk:80084:80085M, Apr 14 2010, 21:17:06) 
    [GCC 4.0.1 (Apple Inc. build 5465)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
    >>> keys = dishes.viewkeys()
    >>> keys & {'eggs', 'bacon', 'salad'}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for &: 'dict_keys' and 'set'
    >>> keys | {'eggs'}
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for |: 'dict_keys' and 'set'

    Is this a documentation bug, and set operations are only supported in 3.x? Or does the code need to be fixed?

    (Assigned to Alexandre, since he committed the backport patch; please feel free to reassign. Marking as release blocker; if it's a documentation bug, we can lower the priority.)

    avassalotti commented 14 years ago

    It is a bug.

    First, the dictviews_as_number is broken; the field for classic division was removed in 3.x, so everything is shifted by one. I included a patch to fix this.

    Unfortunately, this isn't enough to fix the issue. There seems to be some overly restrictive type checking going on in the method wrappers. However, I don't have the time to investigate this further today. I should be able to check this next weekend.

    avassalotti commented 14 years ago

    I found the issue. The view types didn't have Py_TPFLAGS_CHECKTYPES set, so the types were using the old-style binary operators.

    Here's a patch that fixes the issue. Please review.

    5579dc13-9f48-42d1-bb17-9c003ef6fa70 commented 14 years ago

    The patch looks fine. I verified that the new tests pass on trunk and py3k. I am attaching a patch for py3k with a forward port of set opereations and repr tests.

    avassalotti commented 14 years ago

    Committed in r80749 and r80751 (for py3k).

    Thank you!

    akuchling commented 14 years ago

    (commenting on a closed bug, because I'm not sure it should be re-opened)

    While coming up with examples, I found a weird inconsistency. Was it intentional for viewkeys() and viewitems() to support set operations, but not viewvalues()?

    >>> d1 = dict((i*10, chr(65+i)) for i in range(26))
    >>> d2 = dict((i**.5, i) for i in range(1000))
    >>> d1.viewkeys() | set('abc')
    set([0, 130, 10, 140, 20, 150, 30, 160, 40, 170, 50, 180, 60, 190, 70, 200, 80, 210, 90, 220, 'a', 'c', 'b', 100, 230, 110, 240, 120, 250])
    >>> d1.viewitems() | set('abc')
    set([(70, 'H'), (0, 'A'), ....)
    >>> d1.viewvalues() | set('abc')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for |: 'dict_values' and 'set' 
    >>> d1.viewvalues() | d2.viewvalues()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for |: 'dict_values' and 'dict_values'
    akuchling commented 14 years ago

    The fix is easy, I think; just add Py_TPFLAGS_CHECKTYPES to the PyDictValues_Type's definition.

    abalkin commented 14 years ago

    Why do you expect dict_values to support set operations? Dict values unlike keys are not sets, they are more like lists. Set operations of dict_values are not supported in 3.x either.

    akuchling commented 14 years ago

    Ah, of course! It didn't occur to me that .values() isn't necessarily a set.

    rhettinger commented 14 years ago

    FWIW, this agrees with the specs in _abcoll which show KeysView and ItemsView as sets but not ValuesView.