summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2021-03-18 08:00:59 -0500
committerJason Madden <jamadden@gmail.com>2021-03-18 08:18:11 -0500
commitf81a7f8448225f45bad51ed8aa52b0f27640d625 (patch)
treef578e64bb47f54652cb67d55206acd6fd3dc5ef6
parent41cafd34b01555bc5c8bb7fe1b6181a7acf32fe7 (diff)
downloadzope-component-issue9.tar.gz
Fix the subscriber directive when a factory is given that implements an interface and no provides= attribute is specified.issue9
fixes #9
-rw-r--r--CHANGES.rst6
-rw-r--r--docs/zcml.rst3
-rw-r--r--src/zope/component/tests/test_zcml.py23
-rw-r--r--src/zope/component/zcml.py4
4 files changed, 34 insertions, 2 deletions
diff --git a/CHANGES.rst b/CHANGES.rst
index 84a0faa..62a294b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -10,6 +10,12 @@
- Add support for Python 3.9
+- Fix the ``<subscriber>`` ZCML directive to allow a missing
+ ``provides=`` attribute when a ``factory=`` is given and the Python
+ object has been decorated with ``@implementer`` and implements a
+ single interface. This has been documented, but hasn't worked
+ before. See `issue 9
+ <https://github.com/zopefoundation/zope.component/issues/9>`_.
4.6.2 (2020-07-03)
==================
diff --git a/docs/zcml.rst b/docs/zcml.rst
index 18afc81..6bcd786 100644
--- a/docs/zcml.rst
+++ b/docs/zcml.rst
@@ -690,13 +690,12 @@ subscriber should be registered for:
>>> clearZCML()
>>> runSnippet('''
... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
... factory="zope.component.testfiles.adapter.A3"
... />''')
>>> content = Content()
>>> a2 = A2()
- >>> subscribers = zope.component.subscribers((content, a1, a2), IS)
+ >>> subscribers = zope.component.subscribers((content, a1, a2), I3)
>>> a3 = subscribers[0]
>>> a3.__class__ is A3
diff --git a/src/zope/component/tests/test_zcml.py b/src/zope/component/tests/test_zcml.py
index bb92da4..0bf4591 100644
--- a/src/zope/component/tests/test_zcml.py
+++ b/src/zope/component/tests/test_zcml.py
@@ -598,6 +598,29 @@ class Test_subscriber(unittest.TestCase):
self.assertEqual(action['discriminator'], None)
self.assertEqual(action['args'], ('', Interface))
+ def test_no_for__no_provides_subscriber_adapts_subscriber_implements(self):
+ from zope.interface import Interface
+ from zope.interface import implementer
+ from zope.component._declaration import adapter
+ from zope.component.zcml import handler
+ class IFoo(Interface):
+ pass
+ @adapter(Interface)
+ @implementer(IFoo)
+ class _Factory(object):
+ def __init__(self, context):
+ self.context = context
+ _cfg_ctx = _makeConfigContext()
+ self._callFUT(_cfg_ctx, factory=_Factory)
+ self.assertEqual(len(_cfg_ctx._actions), 3)
+ self.assertEqual(_cfg_ctx._actions[0][0], ())
+ # Register the subscriber
+ action = _cfg_ctx._actions[0][1]
+ self.assertEqual(action['callable'], handler)
+ self.assertIsNone(action['discriminator'])
+ self.assertEqual(action['args'],
+ ('registerSubscriptionAdapter', _Factory, (Interface,), IFoo,
+ '', 'TESTING'))
class Test_utility(unittest.TestCase):
diff --git a/src/zope/component/zcml.py b/src/zope/component/zcml.py
index e3d040b..bc02c9f 100644
--- a/src/zope/component/zcml.py
+++ b/src/zope/component/zcml.py
@@ -304,6 +304,10 @@ def subscriber(_context, for_=None, factory=None, handler=None, provides=None,
if handler is not None:
raise TypeError("Cannot use handler with factory")
if provides is None:
+ p = list(implementedBy(factory))
+ if len(p) == 1:
+ provides = p[0]
+ if provides is None:
raise TypeError(
"You must specify a provided interface when registering "
"a factory")