msg181884 - (view) |
Author: Chris Withers (cjw296) *  |
Date: 2013-02-11 08:26 |
>>> from types import new_class >>> from datetime import datetime >>> new_class('tdatetime', (datetime, ), kwds={'foo':'bar'}) Traceback (most recent call last): File "", line 1, in File "/src/Python-3.Lib/types.py", line 52, in new_class return meta(name, bases, ns, **kwds) TypeError: type() takes 1 or 3 arguments I'm guessing ns and kwds should be combined before being passed through to meta? (meta is 'type' in this case) |
|
|
msg182064 - (view) |
Author: Chris Withers (cjw296) *  |
Date: 2013-02-13 23:16 |
Eric, surely this is a bugfix candidate for 3.3.1? |
|
|
msg182065 - (view) |
Author: Éric Araujo (eric.araujo) *  |
Date: 2013-02-13 23:17 |
> I'm guessing ns and kwds should be combined before being passed through to meta? Possibly; can you try that? > surely this is a bugfix candidate for 3.3.1? If we get a patch with a test in time, otherwise 3.3.2. |
|
|
msg182118 - (view) |
Author: Daniel Urban (daniel.urban) *  |
Date: 2013-02-14 19:26 |
I don't think this is a bug: >>> from datetime import datetime >>> class tdatetime(datetime, foo='bar'): ... pass ... Traceback (most recent call last): File "", line 1, in TypeError: type() takes 1 or 3 arguments >>> |
|
|
msg182142 - (view) |
Author: Ramchandra Apte (Ramchandra Apte) * |
Date: 2013-02-15 13:23 |
@Daniel Urban Me too. |
|
|
msg182175 - (view) |
Author: Terry J. Reedy (terry.reedy) *  |
Date: 2013-02-15 21:09 |
As far as I know, currently, the only valid 'keyword' argument for a class statement is 'metaclass' and that is so advanced that it is not mentioned in *8.7. Class definitions* but only in the linked section *3.3.3. Customizing class creation*. The types.newclass doc also only mentions 'metaclass' as a possible keyword. (Maybe it should currently say that that is the only possibility, but perhaps the window was being left open for possible additions in the future.) So I agree that passing anything else is a bug and should raise. If so, this issue should be closed. |
|
|
msg182211 - (view) |
Author: Alyssa Coghlan (ncoghlan) *  |
Date: 2013-02-16 05:05 |
The types.new_class docs are quite clear that the supplied keyword arguments are equivalent to those provided in the type header (if you want to pre-populate the namespace, that's what exec_body is for). The problem here is that the dual signature of type (retrieving the type of an existing object, or creating a new one), and the fact that type.__prepare__ ignores all arguments, means the error message is thoroughly misleading when you pass an unknown keyword argument: >>> type.__prepare__(foo=1) {} >>> type("Example", (), {}, foo=1) Traceback (most recent call last): File "", line 1, in TypeError: type() takes 1 or 3 arguments >>> class Example(foo=1): pass ... Traceback (most recent call last): File "", line 1, in TypeError: type() takes 1 or 3 arguments >>> import types >>> types.new_class("Example", (), dict(foo=1)) Traceback (most recent call last): File "", line 1, in File "/home/ncoghlan/devel/py3k/Lib/types.py", line 52, in new_class return meta(name, bases, ns, **kwds) TypeError: type() takes 1 or 3 arguments The reason type.__prepare__ ignores its arguments is to make it easy for people to use type to anchor a custom metaclass hierarchy and call super().__prepare__(name, bases, **kwds) without needing to worry much about filtering the keyword arguments. (The class machinery intercepts the metaclass hint and never passes it to __prepare__ or the metaclass constructor). That means the real change needed here is to update type's error message for bad arguments to properly report unknown keyword errors when using the PEP 3115 metaclass API. |
|
|
msg182304 - (view) |
Author: Chris Withers (cjw296) *  |
Date: 2013-02-18 08:14 |
Some background: I hit this problem when adding Python 3 compatibility to one of my libraries, where I had the following code: from types import ClassType ... class_ = ClassType(n, (sometype, ), dict(class_attr1='foo', class_attr2='bar') It wasn't at all clear how to port this to Python 3, given that ClassType was gone. types.new_class looks fair game, but the help is not exactly helpful: new_class(name, bases=(), kwds=None, exec_body=None) Create a class object dynamically using the appropriate metaclass. No indication there as to what type should be passed for kwds or exec_body. I guessed and, by the sound of it, guessed wrong. I'd certainly agree that the error message is very misleading. cheers, Chris |
|
|
msg182310 - (view) |
Author: Alyssa Coghlan (ncoghlan) *  |
Date: 2013-02-18 09:53 |
For the simple case where you don't need to provide a metaclass hint, the simplest conversion is actually directly to the 3-argument form of type(). As far as the docstring goes, I don't want to make it as long as the full docs, but it could probably stand to be longer than it is. |
|
|
msg406936 - (view) |
Author: Irit Katriel (iritkatriel) *  |
Date: 2021-11-24 16:23 |
This seems to have been fixed by now. I get this on 3.11: >>> from types import new_class >>> from datetime import datetime >>> new_class('tdatetime', (datetime, ), kwds={'foo':'bar'}) Traceback (most recent call last): File "", line 1, in File "/Users/iritkatriel/src/cpython-1/Lib/types.py", line 77, in new_class return meta(name, resolved_bases, ns, **kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: tdatetime.__init_subclass__() takes no keyword arguments |
|
|