Issue 17421: Drop restriction that meta.prepare() must return a dict (subclass) (original) (raw)

Created on 2013-03-14 20:20 by eric.snow, last changed 2022-04-11 14:57 by admin.

Messages (6)

msg184187 - (view)

Author: Eric Snow (eric.snow) * (Python committer)

Date: 2013-03-14 20:20

Currently type_new() in Objects/typeobject.c enforces a restriction that the namespace be a dict or dict subclass. It does this via the PyArg_ParseTupleAndKeywords() call there.

This means that valid mappings may not be used even though they should work just fine. A demonstration of the problem is below.

I've attached a patch that relaxes this restriction. Should we also add a note in the docs that type() will take anything for namespace that dict() will take?

Demonstration

class Meta(type): @classmethod def prepare(cls, name, bases, **kwargs): return ClassMapping()

from collections import MutableMapping class ClassMapping(MutableMapping): def init(self, *args, **kwargs): self._dict = dict(*args, **kwargs) def len(self): return len(self._dict) def iter(self): return iter(self._dict) def getitem(self, key): return self._dict[key] def setitem(self, key, value): self._dict[key] = value def delitem(self, key): del self._dict[key]

class X(metaclass=Meta): ... pass ... Traceback (most recent call last): File "", line 1, in TypeError: type() argument 3 must be dict, not ClassMapping

msg184203 - (view)

Author: Martin v. Löwis (loewis) * (Python committer)

Date: 2013-03-14 22:38

Are you sure that non-dicts work fine? ISTM that there is quite some code that relies on tp_dict being a dict-or-subdict instance, e.g. in typeobject.c:type_module,type_get_doc etc.

msg184206 - (view)

Author: Eric Snow (eric.snow) * (Python committer)

Date: 2013-03-14 23:16

Sorry I wasn't clear. Later in type.new() it copies that passed namespace into a new dict (see issue #17422). So as long as the namespace argument is a valid argument to dict(), it's going to work fine. We don't need the extra explicit check performed by PyArg_ParseTupleAndKeywords().

msg184309 - (view)

Author: Alyssa Coghlan (ncoghlan) * (Python committer)

Date: 2013-03-16 12:56

Eric and I discussed this, and I've come to the conclusion that the check doesn't serve much purpose at this point.

I initially thought it conveyed useful information about the runtime behavioural restriction, but it doesn't even do that correctly, as dict subclasses (like collections.OrderedDict) will pass the check but will also be copied into a vanilla dict instance.

However, we definitely shouldn't drop it until the copying behaviour is properly documented, so I've added #17422 as an explicit dependency.

msg303022 - (view)

Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer)

Date: 2017-09-26 07:50

Are you sure that non-dicts work fine?

They don't. See .

msg337814 - (view)

Author: Caleb Donovick (donovick) *

Date: 2019-03-12 22:17

In my mind this seems like a bug. PEP 3115 states: ''' prepare returns a dictionary-like object which is used to store the class member definitions during evaluation of the class body. In other words, the class body is evaluated as a function block (just like it is now), except that the local variables dictionary is replaced by the dictionary returned from prepare. This dictionary object can be a regular dictionary or a custom mapping type. '''

History

Date

User

Action

Args

2022-04-11 14:57:42

admin

set

github: 61623

2019-03-12 22:17:10

donovick

set

messages: +

2019-03-12 22:14:15

donovick

set

nosy: + donovick

2017-09-26 07:50:01

serhiy.storchaka

set

nosy: + serhiy.storchaka
dependencies: + SystemError in class creation in case of a metaclass with a bad __prepare__() method
messages: +

2016-09-09 20:09:19

eric.snow

set

assignee: eric.snow ->

2015-07-21 08:00:58

ethan.furman

set

nosy: - ethan.furman

2014-05-21 01:21:03

vstinner

set

nosy: + vstinner

2014-05-19 01:33:27

ethan.furman

set

nosy: + ethan.furman

2013-06-25 05:21:42

eric.snow

set

assignee: eric.snow

2013-03-16 12:56:01

ncoghlan

set

dependencies: + language reference should specify restrictions on class namespace
messages: +

2013-03-14 23:16:19

eric.snow

set

messages: +

2013-03-14 22:38:28

loewis

set

nosy: + loewis
messages: +

2013-03-14 21:57:58

daniel.urban

set

nosy: + daniel.urban

2013-03-14 20:20:27

eric.snow

create