Skip to content

Commit

Permalink
roles: implement required attributes
Browse files Browse the repository at this point in the history
Implement required attributes for roles via the ``__require__``
attribute.
  • Loading branch information
frasertweedale committed Aug 11, 2013
1 parent b41b4f7 commit c0adddf
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
2 changes: 0 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,5 @@
- inner and augment

- roles
- required attributes
- required methods
- method exclusion and aliasing
- apply role to instance?
13 changes: 13 additions & 0 deletions elk/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def __new__(mcs, name, bases, dict):

cls = type.__new__(mcs, name, bases, dict)

# check role requirements
for role in roles:
ElkRoleMeta.check_requirements(cls, role)

# apply method modifiers
modifiers = sorted(
v for v in dict.viewvalues()
Expand Down Expand Up @@ -132,6 +136,15 @@ def apply_to_class_dict(mcs, dict, role):
if k not in dict:
dict[k] = v

@classmethod
def check_requirements(mcs, cls, role):
requires = getattr(role, '__require__', ())
if isinstance(requires, str):
requires = (requires,)
for require in requires:
if not hasattr(cls, require):
raise TypeError('{} requires {}'.format(role, require))


class Elk(object):
__metaclass__ = ElkMeta
Expand Down
35 changes: 35 additions & 0 deletions elk/test_roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,38 @@ def test_car(self):
car.break_()
self.assertTrue(car.is_broken)
self.assertTrue(isinstance(car, Breakable))


class SingleRequireRole(elk.ElkRole):
__require__ = 'x'


class MultiRequireRole(elk.ElkRole):
__require__ = 'y', 'z'


class RequiresTestCase(unittest.TestCase):
def test_missing_requirement_raises_TypeError(self):
with self.assertRaises(TypeError):
class A(elk.Elk):
__with__ = SingleRequireRole

with self.assertRaises(TypeError):
class B(elk.Elk):
y = elk.ElkAttribute()
__with__ = MultiRequireRole

with self.assertRaises(TypeError):
class C(elk.Elk):
z = elk.ElkAttribute()
__with__ = MultiRequireRole

def test_satisfied_requirement_allows_composition(self):
class A(elk.Elk):
__with__ = SingleRequireRole, MultiRequireRole
x = elk.ElkAttribute()
y = elk.ElkAttribute()
z = elk.ElkAttribute()

self.assertTrue(issubclass(A, SingleRequireRole))
self.assertTrue(issubclass(A, MultiRequireRole))

0 comments on commit c0adddf

Please sign in to comment.