0

i am trying to create an instance of a class using arguments, and the problem is my meta class needs some positional args to decide about the bases of class creation.

here is an example to clear it more:


Here are the childs which will be methods of the class (they will be chosen be the parent class object name)
import inspect
import sys

class ParentA:
    pass


class Child1(ParentA):
    def ch1_cmd(self):
        print('This is RAM Telnet IOS Cisco ')


class Child2(ParentA):
    def ch2_cmd(self):
        print('This is Time Telnet IOS Cisco ')

Here is my metaclass which accepts an additional argument CONNECTION_TYPE which is a dictionary, so metaclass will load proper childs according to this Dictionary

class MainMeta(type):
    def __new__(cls, clsname, bases, clsdict, CONNECTION_TYPE):
        if CONNECTION_TYPE != None:
            CONNECTION_TYPE['OBJ'] = getattr(
                sys.modules[__name__], CONNECTION_TYPE['OBJ'])
            if CONNECTION_TYPE['TYPE'] == 'CONDITION1':
                if CONNECTION_TYPE['CONNECTION_TYPE'] == 'CONDITION2':
                    bases = []
                    for name, obj in inspect.getmembers(sys.modules[__name__]):
                        if inspect.isclass(obj):
                            if CONNECTION_TYPE['OBJ'].__subclasscheck__(obj):
                                if CONNECTION_TYPE['OBJ'].__name__ != obj.__name__:
                                    bases.append(obj)
        bases = tuple(bases)
        print(clsname, bases, clsdict) # here Shows that bases are loaded CORRECTLY
        return super().__new__(cls, clsname, bases, clsdict)

this is the Dictionary which will be served to the meta class.

clsdic = {'TYPE': 'CONDITION1',
          'CONNECTION_TYPE': 'CONDITION2', 'OBJ': "ParentA", }

HERE IS The PROBLEM, I use exec to create my class dynamically with my desired CONNECTION_TYPE dictionary, code runs without Err but there are something missing in the created class, and those are __module__ and child classes.

def dev_creator(*args, **kwargs):
    print()
    myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n    pass\n"""
    return exec(myclass, globals())
dev = dev_creator(**clsdic)
print(dir(dev))

This is the output :|

MyMain (<class '__main__.Child1'>, <class '__main__.Child2'>) {'__module__': '__main__', '__qualname__': 'MyMain'}
['__bool__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

2 Answers 2

0

HUM, Solved. it was the global variable definition problem.

here is how we should call an exec and get a return from it.

dev = None
def dev_creator(*args, **kwargs):
    # print(kwargs)
    myclass = f"""class MyMain(metaclass=MainMeta, CONNECTION_TYPE={kwargs}):\n    pass\ndev = MyMain"""
    exec(myclass, globals(), dev)
    return dev
Sign up to request clarification or add additional context in comments.

Comments

0

You don't needand should not call exec at all.

Simply calling your metaclass passign the needed parameters (name, bases and namespace is enough in this case:

 myclass = metaclass("myclass", (), {}, CONNECTION_TYPE=kwargs)

will create you a new class. (the super() call atthe end of the metaclass __new__ does that).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.