Skip to content

Commit

Permalink
Added @named(name) declaration.
Browse files Browse the repository at this point in the history
The decorator specifies the component name, so it does not have to be
passed in during registration. This in turn allows developers to define
component names once globally and use it everywhere, especially when
using ZCML where the name had to be specified a second time.
  • Loading branch information
strichter committed Feb 5, 2014
1 parent ffcf288 commit 79a2662
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 11 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
``zope.interface Changelog``
============================

4.0.6 (unreleased)
4.1.0 (unreleased)
------------------

- Updated ``boostrap.py`` to version 2.2.

- Added ``@named(name)`` declaration, that specifies the component name, so it
does not have to be passed in during registration.


4.0.5 (2013-02-28)
------------------
Expand Down
1 change: 1 addition & 0 deletions src/zope/interface/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def meth(arg1, arg2):
_wire()
del _wire

from zope.interface.declarations import named
from zope.interface.declarations import Declaration
from zope.interface.declarations import alsoProvides
from zope.interface.declarations import classImplements
Expand Down
9 changes: 9 additions & 0 deletions src/zope/interface/declarations.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ class implements (that instances of the class provides).
_ADVICE_WARNING = ('The %s API is deprecated, and will not work in Python3 '
'Use the @%s class decorator instead.')

class named(object):

def __init__(self, name):
self.name = name

def __call__(self, ob):
ob.__component_name__ = self.name
return ob

class Declaration(Specification):
"""Interface declarations"""

Expand Down
17 changes: 14 additions & 3 deletions src/zope/interface/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def _setBases(self, bases):
lambda self, bases: self._setBases(bases),
)

def registerUtility(self, component=None, provided=None, name=_u(''),
def registerUtility(self, component=None, provided=None, name=_u(''),
info=_u(''), event=True, factory=None):
if factory:
if component:
Expand All @@ -89,6 +89,9 @@ def registerUtility(self, component=None, provided=None, name=_u(''),
if provided is None:
provided = _getUtilityProvided(component)

if name == _u(''):
name = _getName(component)

reg = self._utility_registrations.get((provided, name))
if reg is not None:
if reg[:2] == (component, info):
Expand Down Expand Up @@ -176,11 +179,13 @@ def getUtilitiesFor(self, interface):
def getAllUtilitiesRegisteredFor(self, interface):
return self.utilities.subscriptions((), interface)

def registerAdapter(self, factory, required=None, provided=None,
def registerAdapter(self, factory, required=None, provided=None,
name=_u(''), info=_u(''), event=True):
if provided is None:
provided = _getAdapterProvided(factory)
required = _getAdapterRequired(factory, required)
if name == _u(''):
name = _getName(factory)
self._adapter_registrations[(required, provided, name)
] = factory, info
self.adapters.register(required, provided, name, factory)
Expand Down Expand Up @@ -234,7 +239,7 @@ def getAdapter(self, object, interface, name=_u('')):
raise ComponentLookupError(object, interface, name)
return adapter

def queryMultiAdapter(self, objects, interface, name=_u(''),
def queryMultiAdapter(self, objects, interface, name=_u(''),
default=None):
return self.adapters.queryMultiAdapter(
objects, interface, name, default)
Expand Down Expand Up @@ -381,6 +386,12 @@ def handle(self, *objects):
self.adapters.subscribers(objects, None)


def _getName(component):
try:
return component.__component_name__
except AttributeError:
return _u('')

def _getUtilityProvided(component):
provided = list(providedBy(component))
if len(provided) == 1:
Expand Down
45 changes: 38 additions & 7 deletions src/zope/interface/tests/test_declarations.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"""
import unittest

from zope.interface._compat import _skip_under_py3k
from zope.interface._compat import _skip_under_py3k, _u


class _SilencePy3Deprecations(unittest.TestCase):
Expand Down Expand Up @@ -51,7 +51,38 @@ def _run_generated_code(self, code, globs, locs,
else:
if fails_under_py3k:
self.fail("Didn't raise TypeError")



class NamedTests(unittest.TestCase):

def test_class(self):
from zope.interface.declarations import named

@named(_u('foo'))
class Foo(object):
pass

self.assertEqual(Foo.__component_name__, _u('foo'))

def test_function(self):
from zope.interface.declarations import named

@named(_u('foo'))
def doFoo(object):
pass

self.assertEqual(doFoo.__component_name__, _u('foo'))

def test_instance(self):
from zope.interface.declarations import named

class Foo(object):
pass
foo = Foo()
named(_u('foo'))(foo)

self.assertEqual(foo.__component_name__, _u('foo'))


class DeclarationTests(_SilencePy3Deprecations):

Expand All @@ -61,7 +92,7 @@ def _getTargetClass(self):

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor_no_bases(self):
decl = self._makeOne()
self.assertEqual(list(decl.__bases__), [])
Expand Down Expand Up @@ -217,7 +248,7 @@ def test___add___related_interface(self):
other = self._makeOne(IBar, IBaz)
after = before + other
self.assertEqual(list(after), [IFoo, IBar, IBaz])


class ImplementsTests(_SilencePy3Deprecations):

Expand All @@ -227,19 +258,19 @@ def _getTargetClass(self):

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

def test_ctor_no_bases(self):
impl = self._makeOne()
self.assertEqual(impl.inherit, None)
self.assertEqual(impl.declared, ())
self.assertEqual(impl.__name__, '?')
self.assertEqual(list(impl.__bases__), [])

def test___repr__(self):
impl = self._makeOne()
impl.__name__ = 'Testing'
self.assertEqual(repr(impl), '<implementedBy Testing>')

def test___reduce__(self):
from zope.interface.declarations import implementedBy
impl = self._makeOne()
Expand Down
41 changes: 41 additions & 0 deletions src/zope/interface/tests/test_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ def test_assign_to___bases__(self):
self.assertEqual(comp.utilities.__bases__,
(base1.utilities, base2.utilities))

def test_registerUtility_with_component_name(self):
from zope.interface.declarations import named, InterfaceClass
from zope.interface._compat import _u

class IFoo(InterfaceClass):
pass
ifoo = IFoo('IFoo')

@named(_u('foo'))
class Foo(object):
pass
foo = Foo()
_info = _u('info')

comp = self._makeOne()
comp.registerUtility(foo, ifoo, info=_info)
self.assertEqual(
comp._utility_registrations[ifoo, _u('foo')],
(foo, _info, None))

def test_registerUtility_both_factory_and_component(self):
def _factory():
pass
Expand Down Expand Up @@ -591,6 +611,27 @@ class IFoo(InterfaceClass):
self.assertEqual(list(comp.getAllUtilitiesRegisteredFor(ifoo)),
[_to_reg])

def test_registerAdapter_with_component_name(self):
from zope.interface.declarations import named, InterfaceClass
from zope.interface._compat import _u

class IFoo(InterfaceClass):
pass
ifoo = IFoo('IFoo')
ibar = IFoo('IBar')

@named(_u('foo'))
class Foo(object):
pass
_info = _u('info')

comp = self._makeOne()
comp.registerAdapter(Foo, (ibar,), ifoo, info=_info)

self.assertEqual(
comp._adapter_registrations[(ibar,), ifoo, _u('foo')],
(Foo, _info))

def test_registerAdapter_w_explicit_provided_and_required(self):
from zope.interface.declarations import InterfaceClass
from zope.interface.interfaces import Registered
Expand Down

0 comments on commit 79a2662

Please sign in to comment.