Skip to main content

A basic framework for implementing an extension pattern

Project description

Object Extensions

A basic framework for implementing an extension pattern

Quickstart

Setup

Below is an example of an extendable class, and an example extension that can be applied to it.

from objectextensions import Extendable


class HashList(Extendable):
    def __init__(self, iterable=()):
        super().__init__()

        self.values = {}
        self.list = []

        for value in iterable:
            self.append(value)

    def append(self, item):
        self.list.append(item)
        self.values[item] = self.values.get(item, []) + [len(self.list) - 1]

    def index(self, item):
        """
        Returns all indexes containing the specified item.
        Much lower time complexity than a typical list due to dict lookup usage
        """

        if item not in self.values:
            raise ValueError("{0} is not in hashlist".format(item))

        return self.values[item]
from objectextensions import Extension


class Listener(Extension):
    @staticmethod
    def can_extend(target_cls):
        return issubclass(target_cls, HashList)

    @staticmethod
    def extend(target_cls):
        Extension._set(target_cls, "increment_append_count", Listener._increment_append_count)

        Extension._wrap(target_cls, "__init__", Listener._wrap_init)
        Extension._wrap(target_cls, 'append', Listener._wrap_append)

    def _increment_append_count(self):
        self.append_count += 1

    def _wrap_init(self, *args, **kwargs):
        Extension._set(self, "append_count", 0)
        yield

    def _wrap_append(self, *args, **kwargs):
        yield
        self.increment_append_count()

Instantiation

HashListWithListeners = HashList.with_extensions(Listener)
my_hashlist = HashListWithListeners(iterable=[5,2,4])

or, for shorthand:

my_hashlist = HashList.with_extensions(Listener)(iterable=[5,2,4])

Result

>>> my_hashlist.append_count  # Attribute that was added by the Listener extension
3
>>> my_hashlist.append(7)  # Listener has wrapped this to increment .append_count
>>> my_hashlist.append_count
4

Functionality

Properties

Extendable.extensions
    Returns a reference to a frozenset containing the applied extensions.
 

Methods

Extendable.with_extensions(cls, *extensions: Type[Extension])
    Returns a copy of the class with the provided extensions applied to it.
 

Extension.can_extend(target_cls: Type[Extendable])
    Abstract staticmethod which must be overridden.
    Should return a bool indicating whether this Extension can be applied to the target class.
 

Extension.extend(target_cls: Type[Extendable])
    Abstract staticmethod which can be overridden.
    Any modification of the target class should take place in this function.
 

Extension._wrap(target_cls: Type[Extendable], method_name: str,
                          gen_func: Callable[[Extendable, Any, Any], Generator[None, Any, None]])
    Used to wrap an existing method on the target class.
    Passes copies of the method parameters to the generator function provided.
    The generator function should yield once,
    with the yield statement receiving a copy of the result of executing the core method.
 

Extension._set(target: Union[Type[Extendable], Extendable], attribute_name: str, value: Any)
    Used to safely add new attributes to an extendable class or instance. In contrast with assigning them directly,
    this method will raise an error if the attribute already exists (for example, if another extension added it)
    to ensure compatibility issues are flagged and can be dealt with easily.
 

Additional Info

  • As extensions do not properly invoke name mangling, adding private members via extensions is discouraged; doing so may lead to unintended behaviour. Using protected members instead is encouraged, as name mangling does not come into play in this case.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

objectextensions-0.2.1.tar.gz (5.3 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page