classification
Title: Have type(n,b,d) check for type(b[i]) is module
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.10, Python 3.9
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: eric.araujo, rhettinger, serhiy.storchaka, terry.reedy, ysj.ray
Priority: normal Keywords: newcomer friendly

Created on 2011-03-19 02:13 by terry.reedy, last changed 2020-11-17 06:27 by terry.reedy. This issue is now closed.

Messages (7)
msg131381 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2011-03-19 02:13
People occasionally ask on python-list about the following error message when trying to create a class:

> TypeError: Error when calling the metaclass bases
> module.__init__() takes at most 2 arguments (3 given)

It is a bit cryptic. It is also accidental: if module.__init__ happened to take 3 args instead of 2, the exception would be delayed until ???

The cause is using a module as a superclass, as in

import UserDict
class MyDict(UserDict): pass

This seems to happen mostly because of duplicate (or only case-different) module/class names.
 
Suggestion: insert a specific module type check for bases in type_new() in typeobject.c. In Python:
  if basetype is module: # where 'module' is the module class
    raise TypeError('Cannot subclass module')

I see 2 possible places to put the check:

1. for all bases - after
        tmp = PyTuple_GET_ITEM(bases, i);
        tmptype = Py_TYPE(tmp);

Advantage: can add (name of) tmp to the error message.

2. Before the return call in
    if (winner != metatype) {
        if (winner->tp_new != type_new) /* Pass it to the winner */
            return winner->tp_new(winner, args, kwds);

Advantage: only add extra check when module is the winner and are about to call it as a metaclass, which raises the current error.

Any test would be CPython specific and would require checking something about the message text.

I am only suggesting a check for module because the is the only mistake I remember anyone reporting. Passing a number as a base class gives a similar message, but no one does that. And as far as I know, there is no way in general to detect whether a callable works as a metaclass except by calling it with name, bases, and dict.
msg131397 - (view) Author: ysj.ray (ysj.ray) Date: 2011-03-19 06:22
> I am only suggesting a check for module because the is the only mistake > I remember anyone reporting. Passing a number as a base class gives a > > similar message, but no one does that. And as far as I know, there is > no way in general to detect whether a callable works as a metaclass > except by calling it with name, bases, and dict.


Since 3.x all the module names became lower-case and can be easily differ from class names, so I don't think this problem will present much in 3.x, right?
msg131493 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-03-20 13:34
> raise TypeError('Cannot subclass module')
It is possible to subclass module.

Ray: right, but 2.x still has a long life ahead of it, so we still want to improve its doc.
msg131522 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2011-03-20 17:46
Whoops. That should be 'Cannot subclass a module' or 'Cannot subclass module %s' % modulename.  Types.ModuleType can indeed by subclassed.

I agree that this is not a pressing issue, but it will at least provide an answer to anyone searching the tracker for the current message.
msg140268 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-07-13 15:18
I don’t know if this should be left to lint tools or addressed by CPython itself.  Raymond, do you have an opinion?
msg381160 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2020-11-16 21:27
Special cases aren't special enough to break the rules.

I think this issue should be closed. This is not common user error, especially in Python 3. I can even imagine that you can subclass module, if it is an instance of special ModuleType subclass. It is a feature of Python that you can subclass any objects, not only classes, if they provide the particular interface.
msg381208 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2020-11-17 06:27
I cannot anymore remember seeing this. So closing.
History
Date User Action Args
2020-11-17 06:27:44terry.reedysetstatus: pending -> closed
resolution: out of date
messages: + msg381208

stage: test needed -> resolved
2020-11-16 21:27:23serhiy.storchakasetstatus: open -> pending
nosy: + serhiy.storchaka
messages: + msg381160

2020-11-16 20:00:11iritkatrielsetkeywords: + newcomer friendly
versions: + Python 3.9, Python 3.10, - Python 3.3
2011-07-13 15:18:39eric.araujosetnosy: + rhettinger
messages: + msg140268
2011-03-20 17:46:32terry.reedysetnosy: terry.reedy, eric.araujo, ysj.ray
messages: + msg131522
2011-03-20 13:34:16eric.araujosetnosy: + eric.araujo
messages: + msg131493
2011-03-19 06:22:29ysj.raysetnosy: + ysj.ray
messages: + msg131397
2011-03-19 02:13:57terry.reedycreate