Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Setting the metaclass for all files in a folder

I wrote a metaclass that I'm using for logging purposes in my python project. It makes every class automatically log all activity. The only issue is that I don't want to go into every file and have to add in:

__metaclass__ = myMeta

Is there a way to set the metaclass in the top level folder so that all the files underneath use that metaclass?

like image 752
amustafa Avatar asked Apr 23 '13 20:04

amustafa


2 Answers

No, you can only specify the metaclass per class or per module. You cannot set it for the whole package.

In Python 3.1 and onwards, you can intercept the builtins.__build_class__ hook and insert a metaclass programatically, see Overriding the default type() metaclass before Python runs.

In Python 2.7, you could replace __builtins__.object with a subclass that uses your metaclass. Like the builtins.__build_class__ hook, this is advanced hackery and break your code as much as getting your metaclass in everwhere.

Do so by replacing the object reference on the __builtin__ module:

import __builtin__


class MetaClass(type):
    def __new__(mcls, name, *args):
        # do something in the metaclass
        return super(MetaClass, mcls).__new__(mcls, name, *args)


orig_object = __builtin__.orig_object


class metaobject(orig_object):
    __metaclass__ = MetaClass


def enable():
    # *replace* object with one that uses your metaclass
    __builtin__.object = metaobject

def disable():
    __builtin__.object = orig_object

Run enable() this before importing your package and all new-style classes (those that can support a metaclass) will have your metaclass. Note that this behaviour now will propagate to all Python code not already loaded, including the standard library, as your package imports code. You probably want to use:

enable()
import package
disable()

to limit the effects.

like image 85
Martijn Pieters Avatar answered Oct 21 '22 15:10

Martijn Pieters


Here's a simple technique. Just subclass the class itself with __metaclass__ attribute in the subclass. This process can be automated.

util.py

class A(object):
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def __str__(self):
        return '{} {}'.format(self.first, self.second)

main.py

from datetime import datetime
from util import A

def meta(*args):
    cls = type(*args)
    setattr(cls, 'created', datetime.now().ctime())
    return cls

try:
    print(A.created)
except AttributeError as e:
    print(e)

class A(A):
    __metaclass__ = meta

print(A.created, str(A('Michael', 'Jackson')))

Test;

$ python main.py 
type object 'A' has no attribute 'created'
('Wed Mar  9 22:58:16 2016', 'Michael Jackson')
like image 40
Nizam Mohamed Avatar answered Oct 21 '22 14:10

Nizam Mohamed