fictive.patterns.types module

Common patterns for working with types

Functions

auto_merge

Create a subclass of bases with a single merged metaclass

synthesized_type

Synthesize a type from one or more instance objects

Classes

class_property

Like the property decorator, but for class variables

metaclass

decorators for controlling metaclass attributes

fictive.patterns.types.synthesized_type(name, instances, dict_)[source]

Synthesize a type from one or more instance objects

The method resolution order of the new type will be based on the left-to-right order of instances. E.g.:

import pprint
from fictive.patterns.types import synthesized_type

class FirstClass(object):
    def report(self):
        return ('FirstClass', )

class SecondClass(object):
    def report(self):
        return ('SecondClass', ) + super(SecondClass, self).report()

first = FirstClass()
second = SecondClass()
synth = synthesized_type(
    'synth', (second, first), {'ATTRIBUTE': 'foo'})
>>> synth().report()
('SecondClass', 'FirstClass')
>>> pprint.pprint(synth.mro())
[<class 'fictive.patterns.types.synth'>,
 <class 'SecondClass'>,
 <class 'FirstClass'>,
 <class 'object'>]
>>> synth.ATTRIBUTE
'foo'
>>> issubclass(synth, type(first))
True
>>> issubclass(synth, type(second))
True
Parameters
  • name – the __name__ for the new type

  • instances – any number of objects that should be instances of the new type

  • dict – any additional keyword arguments that will be used as attributes for the new type

fictive.patterns.types.auto_merge(*bases, metaclass=None, **dict_)[source]

Create a subclass of bases with a single merged metaclass

This function can be used to avoid TypeError: metaclass conflict when subclassing from ancestors that do not share a related metaclass. E.g.:

import pprint
from fictive.patterns.types import auto_merge

class FirstMeta(type):
    pass

class FirstClass(object, metaclass=FirstMeta):
    pass

class SecondMeta(type):
    pass

class SecondClass(object, metaclass=SecondMeta):
    pass

class ThirdMeta(type):
    pass

class Combined(auto_merge(SecondClass, FirstClass, metaclass=ThirdMeta)):
    pass
>>> pprint.pprint(Combined.mro())
[<class 'Combined'>,
 <class 'fictive.patterns.types.AutoMergedSubclass'>,
 <class 'SecondClass'>,
 <class 'FirstClass'>,
 <class 'object'>]
>>> pprint.pprint(type(Combined).__mro__)
(<class 'fictive.patterns.types.AutoMergedMetaclass'>,
 <class 'ThirdMeta'>,
 <class 'SecondMeta'>,
 <class 'FirstMeta'>,
 <class 'type'>,
 <class 'object'>)
Parameters
  • bases – any number of bases classes that will be ancestors of the new class

  • metaclass (type) – an optional additional metaclass to be incorporated into the new class

  • dict – any additional keyword arguments that should be used as class attributes for the new class

class fictive.patterns.types.metaclass[source]

Bases: object

decorators for controlling metaclass attributes

Python’s type system allows modification of class behaviors by modifying the class’s metaclass. While this system is powerful and flexible, explicitly defining and assigning a custom metaclass for small modifications to the class’s behavior can be overly verbose and error prone.

As an alternative to explicitly defining and invoking a custom metaclass, this group of decorators can be used to create an “ad hoc” metaclass based on the decorated methods and attributes of the class. E.g.:

from fictive.patterns.types import metaclass

@metaclass.auto
class MyClass(object):

    @metaclass.mark
    def __getattribute__(cls, name):
        '''
        obfuscate class attribute access

        '''
        _cls_ = super(type(MyClass), cls).__getattribute__
        reversed_name = name[::-1]
        if name == 'hidden' or reversed_name == 'hidden':
            return _cls_(reversed_name)
        return _cls_(name)

    @classmethod
    def public(cls):
        print(f"running {cls.__name__}.public()")

    @classmethod
    def hidden(cls):
        print(f"running {cls.__name__}.hidden()")
        return 'The Magic Words are Squeamish Ossifrage'

    def __init__(self, value):
        self.hidden = value
>>> MyClass.public()
running MyClass_auto.public()
>>> hasattr(MyClass, 'hidden')
False
>>> hasattr(MyClass, 'neddih')
True
>>> MyClass.neddih()
running MyClass_auto.hidden()
'The Magic Words are Squeamish Ossifrage'

Note, the class’s own __getattribute__ method (used for instance attribute access) is unaffected:

>>> instance = MyClass('open sesame')
>>> instance.hidden
'open sesame'
>>> hasattr(instance, 'neddih')
False
>>> del instance.hidden
>>> hasattr(instance, 'neddih')
False
>>> hasattr(instance, 'hidden')
True
>>> instance.hidden()
running MyClass_auto.hidden()
'The Magic Words are Squeamish Ossifrage'
class MARK_WRAPPER[source]

Bases: ObjectProxy

wrapper used to mark an attribute for the metaclass

move_to_metaclass(name, class_attrs, meta_attrs)[source]

moves the wrapped object to the metaclass

This method should define the behavior for moving an attribute from the class’s __dict__ to the dict that will be used to create a new metaclass

Parameters
  • class_attrs – the class’s __dict__

  • meta_attrs – the dictionary that will be passed to the new:term:metaclass’s constructor

classmethod auto(*args, **kwargs)[source]

synthesize a metaclass for the decorated class

Can be used without paramaters, or in a parameterized form specfiying which attributes of the new class that should not be copied from the original class. The default set of attributes to not copy is (__dict__ and __weakref__).

classmethod mark(*args, **kwargs)[source]

mark an attribute as belonging to the metaclass

Can be used as a method decorator or an object wrapper (e.g., for class variables). Can be used without paramaters, or in a parameterized form specfiying a custom wrapper object. E.g.:

from fictive.patterns.types import metaclass

class MyWrapper(metaclass.MARK_WRAPPER):

    def move_to_metaclass(self, name, class_attrs, meta_attrs):
        super(MyWrapper, self).move_to_metaclass(
            name, class_attrs, meta_attrs)
        reversed_name = name[::-1]
        meta_attrs[reversed_name] = meta_attrs.pop(name)


class MyClass(object):

    DEFAULT = metaclass.mark('default')

    CUSTOM = metaclass.mark(mark_wrapper=MyWrapper)('custom')

    @metaclass.mark
    def default(cls):
        return 'default'

    @metaclass.mark(mark_wrapper=MyWrapper)
    def custom(cls):
        return 'custom'
>>> type(MyClass.DEFAULT)
<class 'fictive.patterns.types.metaclass.MARK_WRAPPER'>
>>> type(MyClass.CUSTOM)
<class 'MyWrapper'>
>>> type(MyClass.default)
<class 'fictive.patterns.types.metaclass.MARK_WRAPPER'>
>>> type(MyClass.CUSTOM)
<class 'MyWrapper'>

When the class is decorated with metaclass.auto, the marked attributes will be moved to the metaclass using the mark_wrapper’s move_to_metaclass():

>>> MyClass = metaclass.auto(MyClass)
>>> MyClass.DEFAULT
'default'
>>> MyClass.MOTSUC
'custom'
>>> MyClass.default()
'default'
>>> MyClass.motsuc()
'custom'
class fictive.patterns.types.class_property[source]

Bases: property

Like the property decorator, but for class variables

from fictive.patterns.types import metaclass, class_property

@metaclass.auto
class MyClass(object):

    @class_property
    def class_attribute(cls):
        return cls._ATTRIBUTE

    @class_attribute.setter
    def class_attribute(cls, value):
        cls._ATTRIBUTE = value[::-1]

    @class_attribute.deleter
    def class_attribute(cls):
        del cls._ATTRIBUTE
>>> hasattr(MyClass, 'class_attribute')
False
>>> MyClass.class_attribute = 'class attribute'
>>> MyClass.class_attribute
'etubirtta ssalc'

As with other class variables, instance variables exist in a separate namespace to the class_property:

>>> instance = MyClass()
>>> instance.class_attribute = 'instance attribute'
>>> instance.class_attribute
'instance attribute'
>>> MyClass.class_attribute
'etubirtta ssalc'

If the instance has no matching attribute in its own namespace, it will read from the class’s namespace:

>>> del instance.class_attribute
>>> instance.class_attribute
'etubirtta ssalc'

NB: because “data descriptors” take precedence over instance variables (and property objects are data descriptors), a class_property will take precedence over class variables defined in subclasses. If a subclass needs to override a class_property, it must declare that override in its own metaclass.

class MARK_WRAPPER[source]

Bases: fictive.patterns.types.metaclass.MARK_WRAPPER

wrapper used to mark a property for the metaclass

Leaves a “trampoline” in the class’s __dict__

move_to_metaclass(name, class_attrs, meta_attrs)[source]

moves the wrapped object to the metaclass

This method should define the behavior for moving an attribute from the class’s __dict__ to the dict that will be used to create a new metaclass

Parameters
  • class_attrs – the class’s __dict__

  • meta_attrs – the dictionary that will be passed to the new:term:metaclass’s constructor

class MetaclassDescriptorReference(name)[source]

Bases: object

a “trampoline” to read the class attribute from an instance

__init__(name)[source]

Initialize self. See help(type(self)) for accurate signature.