Welcome to metaframe’s documentation!¶
Contents:
Introduction¶
metaframe
is a MetaClass infrastructure to intercept instance
creation/initialization enabling modification of args/kwargs and instance.
Features:¶
MetaFrame
metaclass to apply to any object - With embedded staticmethod with_metaclass to enable inheritanceMetaFrameBase
class from which classes can inherit- 3 hooks (classmethods)
_new_pre
: called before object creation_new_do
: called for object creation_init_pre
: called after object creation / before object initialization_init_do
: called fo object initialization_init_post
: called after object initialization
Installation¶
metaframe
is self-contained with no external dependencies
From pypi:
pip install metaframe
From source:
- Place the metaframe directory found in the sources inside your project
Usage¶
metaframe
allows placing hooks into the creation/initializaion of objects,
enabling use cases like:
- Modification of args/kwargs on the fly
- Instance scanning/modification
Direct Inheritance¶
The package offers an already metaclassed base class supporting the infrastructure.
MetaFrameBase
Intercepting Object Creation¶
An example from one of the tests included in the sources.
import metaframe as mf
class FrameTest(mf.MetaFrameBase):
_KEY = 'ft'
_VAL = True
def __init__(self, *args, **kwargs):
self._val = kwargs.get(self._KEY, False)
def check_val(self):
return self._val == self._VAL
@classmethod
def _new_pre(cls, *args, **kwargs):
# Insert a kwarg
kwargs[cls._KEY] = cls._VAL
return cls, args, kwargs
Doing something with it:
ft = FrameTest()
print('ft.check_val:', ft.check_val())
Yields the following output:
ft.check_val: True
From the example:
No kwargs were passed to
FrameTest
for instantiationDuring init
self._KEY
(‘ft’) was extracted from kwargs and assigned toself._val
The
kwargs
were actually modified in theclassmethod()
whereself._VAL
was added with key ``self._KEY’‘And the modified
kwargs
were returned to be fed to object creation/initializationHence
check_val()
returningTrue
Before initialization¶
The previous example can be extended to undo the effect achieved during object creation.
Let’s add a hook before init
@classmethod
def _init_pre(cls, obj, *args, **kwargs):
# Remove the kwarg
kwargs.pop(cls._KEY)
return obj, args, kwargs
Doing something with it:
ft = FrameTest()
print('ft.check_val:', ft.check_val())
Yields the following output:
ft.check_val: False
The new code in _init_pre()
removes the key self._KEY
from the passed
kwargs
and returns them for object initialization.
After initialization¶
Redoing the effect by directly operating on the instance can be done after initialization.
The hook after __init__
@classmethod
def _init_post(cls, obj, *args, **kwargs):
# change self._val ... to the expected value
obj._val = obj._VAL
return obj, args, kwargs
Repeating execution:
ft = FrameTest()
print('ft.check_val:', ft.check_val())
Yields the following output:
ft.check_val: True
In this case the post initialization hook has directly changed the value of
attribute _val
after object init.
Applying the metaclass¶
Instead of inheriting from MetaFrameBase
a derived metaclass for your class
can be created:
import metaframe as mf
class MyMetaClass(mf.MetaFrame):
def _new_pre(cls, *args, **kwargs):
# Insert a kwarg
kwargs[cls._KEY] = cls._VAL
return cls, args, kwargs
def _init_pre(cls, obj, *args, **kwargs):
# Remove the kwarg
kwargs.pop(cls._KEY)
return obj, args, kwargs
def _init_post(cls, obj, *args, **kwargs):
# change self._val ... to the expected value
obj._val = obj._VAL
return obj, args, kwargs
Now there is no need to declare the 3 hoods as classmethods
because they are
already being declared in the MetaClass.
The FrameTest
class would now look like this:
class FrameTest(MyMetaClass.as_metaclass(object)):
_KEY = 'ft'
_VAL = True
def __init__(self, *args, **kwargs):
self._val = kwargs.get(self._KEY, False)
def check_val(self):
return self._val == self._VAL
The execution examples remain unchanged.
Alternatively, you can directly MetaFrame-enable a class applying MetaFrame
as metaclass and defining the methods in the class as @classmethods
:
class FrameTest(mf.MetaFrame.as_metaclass(object)):
_KEY = 'ft'
_VAL = True
@classmethod
def _new_pre(cls, *args, **kwargs):
# Insert a kwarg
kwargs[cls._KEY] = cls._VAL
return cls, args, kwargs
@classmethod
def _init_pre(cls, obj, *args, **kwargs):
# Remove the kwarg
kwargs.pop(cls._KEY)
return obj, args, kwargs
@classmethod
def _init_post(cls, obj, *args, **kwargs):
# change self._val ... to the expected value
obj._val = obj._VAL
return obj, args, kwargs
def __init__(self, *args, **kwargs):
self._val = kwargs.get(self._KEY, False)
def check_val(self):
return self._val == self._VAL
Reference¶
-
class
metaframe.
MetaFrame
¶ This Metaclass intercepts instance creation/initialization enabling use cases like modification of args, kwargs and/or scanning of the object post init
-
_new_pre
(*args, **kwargs)¶ Called before the object is created.
Parameters: - cls (automatic) – The class which is going to be instantiated
- args – To be passed to
__new__
for class instantiation - kwargs – To be passed to
__new__
for class instantiation
Returns: cls, args, kwargs as a tuple
The return values need not be the same that were passed
-
_new_do
(*args, **kwargs)¶ Called for object creation
Parameters: - cls (automatic) – The class which is going to be instantiated
- args – To be passed to
__new__
for class instantiation - kwargs – To be passed to
__new__
for class instantiation
Returns: obj, args, kwargs as a tuple
Note that in this method the 1st return value is no the 1st passed argument (unlike in the rest of methods) It is the created instance and not the passed class
The return values need not be the same that were passed
-
_init_pre
(obj, *args, **kwargs)¶ Called after object creation and before the object is init’ed
Parameters: - cls (-) – The class which has been instantiated
- obj (-) – The class instance which has been created
- args (-) – To be passed to
__init__
for object initialization - kwargs (-) – To be passed to
__init__
for object initialization
Returns: obj, args, kwargs as a tuple
The return values need not be the same that were passed
-
_init_do
(obj, *args, **kwargs)¶ Called for object initialization
Parameters: - cls (-) – The class which has been instantiated
- obj (-) – The class instance which has been created
- args (-) – To be passed to
__init__
for object initialization - kwargs (-) – To be passed to
__init__
for object initialization
Returns: obj, args, kwargs as a tuple
The return values need not be the same that were passed
-
_init_post
(obj, *args, **kwargs)¶ Called after object initialization
Parameters: - cls (-) – The class which has been instantiated
- obj (-) – The class instance which has been created
- args (-) – Which were passed to
__init__
for object initialization - kwargs (-) – Which were passed to
__init__
for object initialization
Returns: obj, args, kwargs as a tuple
The return values need not be the same that were passed. But modifying
args
and/orkwargs
no longer plays a role because the object has already been created and initialized
-
__call__
(*args, **kwargs)¶ Creates an initializes an instance of cls calling the pre-new, pre-init/post-init hooks with the passed/returned
args
/kwargs
-
classmethod
as_metaclass
(meta, *bases)¶ Create a base class with “this metaclass” as metaclass
Meant to be used in the definition of classes for Py2/3 syntax equality
Parameters: bases – a list of base classes to apply (object if none given)
-
-
class
metaframe.
MetaFrameBase
¶ Enables a class to MetaFrame-enabled through inheritance without having to specify/declare a metaclass