Porting Ruby's Forwardable module to Python
Python
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
forwardable
.gitignore
.travis.yml
CHANGELOG.rst
LICENSE
MANIFEST.in
README.rst
setup.py
tox.ini

README.rst

Forwardable

Utility for easy object composition via delegation. Roughly ported from Ruby's forwardable standard library.

Requirements

Python 2.7 or 3.3 w/ standard library. Might work on other version of Python, too.

Installation

$ pip install forwardable

Usage

Most Common Use Case

The @forwardable.forwardable() decorator enables you to use def_delegator() and def_delegators() in a class definition block.

Use def_delegators() to define multiple attr forwarding:

from forwardable import forwardable

@forwardable() # Note the () here, which is required.
class Foo(object):
    def_delegators('bar', 'add, __len__')

    def __init__(self):
        self.bar = set()

foo = Foo()
foo.add(1) # Delegates to foo.bar.add()
assert len(foo) == 1 # Magic methods works, too

Easy, heh?

Define a Single Forwarding

In case you only need to delegate one method to a delegatee, just use def_delegator:

from forwardable import forwardable

@forwardable()
class Foo(object):
    def_delegator('bar', '__len__')

    def __init__(self):
        self.bar = set()

assert len(Foo()) == 0

And it should work just fine. Actually, def_delegators() calls def_delegator() under the hood.

Plucking

from forwardable import forwardable

@forwardable()
class MyDict(object):
    def_delegator('dct.get', '__call__')
    def __init__(self):
        self.dct = {'foo', 42}

d = MyDict()
# Equivlant to d.dct.get('foo')
assert d('foo') == 42

Less Magical Usage

The @forwardable() decorator injects def_delegator{,s} into the module scope temorarily, which is why you don't have to import them explicitly. This is admittedly magical but discourages the usage of import *. And it's always nice to type less characters whenever unnecessary.

If you hesitate to utilize this injection magic, just explicitly say from forwardable import def_delegator, def_delegators, use them in a class definition and you'll be fine.

Links

License

MIT license.