linkyndy
linkyndy

Reputation: 17900

Extra arguments in Metaclass

I wrote the following metaclass:

class FieldHandlerBase(type):
    def __new__(cls, name, bases, dct, model):
        ...
        return super(FieldHandlerBase, cls).__new__(cls, name, bases, dct)

Now, I try to dynamically create a class using the above metaclass:

FieldHandlerBase(
    '%sFieldHandler' % name,
    (FieldHandler,),
    {rel_type: dct.setdefault(rel_type, ()) for rel_type in REL_TYPES},
    model=name)

But it throws me this error:

>           model=name)
E       TypeError: Error when calling the metaclass bases
E           type.__init__() takes no keyword arguments

I don't understand why, since I call the metaclass base (type here, from within FieldHandlerBase) with the correct number of arguments. How can I fix this? I need to pass an extra argument to FieldHandlerBase and I don't want to include it into the dct argument, since I need it only at metaclass level.

Upvotes: 1

Views: 1103

Answers (1)

Dunes
Dunes

Reputation: 40713

You need to write an __init__ method as well as a __new__ method. Otherwise, python will call type.__init__ for your new class, which does not take any additional arguments.

eg.

class FieldHandlerBase(type):

    def __init__(cls, name, bases, attrs, model):
        type.__init__(cls, name, bases, attrs)
        cls.model = model

    def __new__(metacls, name, bases, attrs, model):
        ...
        return type.__new__(metacls, name, bases, attrs)

class ExampleFieldHandler(FieldHandler, metaclass=FieldHandlerBase, 
        model="Example"):
    clsvar = "var"

# or 
ExampleFieldHandler = FieldHandlerBase(
    "ExampleFieldHandler",
    (FieldHandler,),
    {"clsvar": "var"},
    model="Example"
)

assert ExampleFieldHandler.model == "Example"

Upvotes: 2

Related Questions