[issue24659] dict() built-in fails on iterators with a keys attribute

2015-07-18 Thread Christian Barcenas

Christian Barcenas added the comment:

Should have clarified that the specific issue that is outlined in #5945 is that 
PyMapping_Check returns 1 on sequences (e.g. lists), which would mean something 
like x = [('one', 1), ('two', 2)]; dict(x) would fail in 3.x because x would be 
incorrectly evaluated as a mapping rather than as an iterable.

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue24659
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue24659] dict() built-in fails on iterators with a keys attribute

2015-07-18 Thread Christian Barcenas

New submission from Christian Barcenas:

I noticed an inconsistency today between the dict() documentation vs. 
implementation.

The documentation for the dict() built-in [1] states that the function accepts 
an optional positional argument that is either a mapping object [2] or an 
iterable object [3]. 

Consider the following:

import collections.abc

class MyIterable(object):
def __init__(self):
self._data = [('one', 1), ('two', 2)]

def __iter__(self):
return iter(self._data)

class MyIterableWithKeysMethod(MyIterable):
def keys(self):
return And now for something completely different

class MyIterableWithKeysAttribute(MyIterable):
keys = It's just a flesh wound!

assert issubclass(MyIterable, collections.abc.Iterable)
assert issubclass(MyIterableWithKeysMethod, collections.abc.Iterable)
assert issubclass(MyIterableWithKeysAttribute, collections.abc.Iterable)
assert not issubclass(MyIterable, collections.abc.Mapping)
assert not issubclass(MyIterableWithKeysMethod, collections.abc.Mapping)
assert not issubclass(MyIterableWithKeysAttribute, collections.abc.Mapping)

# OK
assert dict(MyIterable()) == {'one': 1, 'two': 2}

# Traceback (most recent call last):
#   File stdin, line 1, in module
# TypeError: 'MyIterableWithKeysMethod' object is not subscriptable
assert dict(MyIterableWithKeysMethod()) == {'one': 1, 'two': 2}

# Traceback (most recent call last):
# File stdin, line 1, in module
# TypeError: attribute of type 'str' is not callable
assert dict(MyIterableWithKeysAttribute()) == {'one': 1, 'two': 2}

The last two assertions should not fail, and it appears that the offending code 
can be found in Objects/dictobject.c's dict_update_common:

else if (arg != NULL) {
_Py_IDENTIFIER(keys);
if (_PyObject_HasAttrId(arg, PyId_keys))
result = PyDict_Merge(self, arg, 1);
else
result = PyDict_MergeFromSeq2(self, arg, 1);
}

PyDict_Merge is used to merge key-value pairs if the optional parameter is a 
mapping, and PyDict_MergeFromSeq2 is used if the parameter is an iterable.

My immediate thought was to substitute the _PyObject_HasAttrId call with 
PyMapping_Check which I believe would work in 2.7, but due to #5945 I don't 
think this fix would work in 3.x.

Thoughts?

[1] https://docs.python.org/3.6/library/stdtypes.html#dict
[2] https://docs.python.org/3.6/glossary.html#term-mapping
[3] https://docs.python.org/3.6/glossary.html#term-iterable

--
assignee: docs@python
components: Documentation, Interpreter Core
messages: 246890
nosy: christian.barcenas, docs@python
priority: normal
severity: normal
status: open
title: dict() built-in fails on iterators with a keys attribute
type: behavior
versions: Python 2.7, Python 3.2, Python 3.3, Python 3.4, Python 3.5, Python 3.6

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue24659
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue24659] dict() built-in fails on iterators with a keys attribute

2015-07-18 Thread Christian Barcenas

Christian Barcenas added the comment:

I'm aware of duck typing but I don't think this is the right place for it. 
(Although ABCs are ostensibly a kind of duck typing, as they do not require 
implementing classes to inherit from the ABC.)

As Martin noticed, the glossary directly defines a mapping as a class that 
implements the Mapping ABC, and likewise the definition of an iterable under 
the glossary would satisfy the Iterable ABC.

I think this is not just a documentation issue: the quack of a mapping has 
been well-defined and consistent since Python 2.7. Same for iterables.

(It is worth noting that 2.6's definition of mapping was indeed just any object 
with a __getitem__ method 
https://docs.python.org/2.7/glossary.html#term-mapping)

 I think the documentation for the dict() constructor should say how to ensure 
 the iterable and mapping modes are triggered.

Doesn't it do this already by referencing the definitions of iterable and 
mapping? These ABCs are used in other built-ins such as any() and eval().

--

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue24659
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue5945] PyMapping_Check returns 1 for lists

2015-07-17 Thread Christian Barcenas

Changes by Christian Barcenas christ...@cbarcenas.com:


--
versions: +Python 3.6

___
Python tracker rep...@bugs.python.org
http://bugs.python.org/issue5945
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com