Repository: Pylons/pyramid

Issue:
Restore the Registry(*args, **kw) API
In the course of #2891, the Registry API was changed in a backwards-incompatible way. While the author of the change (PR 2893) couldn't imagine anyone using the keywords API, I immediately ran into the incompatibility with a number of customer projects. Since the change back to the old API shouldn't introduce another backwards incompatibility, I suggest reverting that change as soon as possible.


Discussion:
How were you using the API?
It looks like you can configure the registry to delegate lookup to another registry (probably the global one). I will patch this for 1.8.1. I should have done more research on what the `bases` argument was prior to removing it.

https://github.com/zopefoundation/zope.interface/blob/b8a36f1b6aa2c4d4470c08b84bb6f5031e33ab30/src/zope/interface/registry.py#L180

https://docs.zope.org/zope.component/api/utility.html#delegated-utility-lookup
I'm using code like this to make Pyramid use the global ZCA registry:
```
        registry = pyramid.registry.Registry(
            bases=(zope.component.getGlobalSiteManager(),))
        config = pyramid.config.Configurator(
            settings=self.settings,
            registry=registry)
        config.setup_registry(settings=self.settings)
```
There are documented ways to do something similiar without using the `bases` parameter, but I'm not aware of another way to have Pyramid use a registry that delegates, but is not identical, to the same ZCA global registry that has been in use during process start-up before Pyramid came into play, while being a full `pyramid.registry.Registry` (as opposed to a `zope.interface.registry.Component`, which the Pyramid registry expands upon).

In addition to this technical reason for wanting the `bases` parameter back, I consider it a matter of principle that a backwards-incompatible change like this should not go into a release without some research (and without even being documented in the change log). I'm happy to see that we agree on that, so I'd like to reinforce my suggestion to just restore the old `*arg, **kw` API in 1.8.1 and bring up simplification as a feature for a future release, so it may be discussed by the users of the API.

Resolving patch:
diff --git a/pyramid/registry.py b/pyramid/registry.py
--- a/pyramid/registry.py
+++ b/pyramid/registry.py
@@ -56,7 +56,7 @@ class Registry(Components, dict):
 
     _settings = None
 
-    def __init__(self, package_name=CALLER_PACKAGE):
+    def __init__(self, package_name=CALLER_PACKAGE, *args, **kw):
         # add a registry-instance-specific lock, which is used when the lookup
         # cache is mutated
         self._lock = threading.Lock()
@@ -64,7 +64,7 @@ def __init__(self, package_name=CALLER_PACKAGE):
         self._clear_view_lookup_cache()
         if package_name is CALLER_PACKAGE:
             package_name = caller_package().__name__
-        Components.__init__(self, package_name)
+        Components.__init__(self, package_name, *args, **kw)
         dict.__init__(self)
 
     def _clear_view_lookup_cache(self):


Test patch:
diff --git a/pyramid/tests/test_registry.py b/pyramid/tests/test_registry.py
--- a/pyramid/tests/test_registry.py
+++ b/pyramid/tests/test_registry.py
@@ -5,8 +5,8 @@ def _getTargetClass(self):
         from pyramid.registry import Registry
         return Registry
     
-    def _makeOne(self):
-        return self._getTargetClass()()
+    def _makeOne(self, *args, **kw):
+        return self._getTargetClass()(*args, **kw)
 
     def test___nonzero__(self):
         registry = self._makeOne()
@@ -24,11 +24,11 @@ def test_clear_view_cache_lookup(self):
 
     def test_package_name(self):
         package_name = 'testing'
-        registry = self._getTargetClass()(package_name)
+        registry = self._makeOne(package_name)
         self.assertEqual(registry.package_name, package_name)
 
     def test_default_package_name(self):
-        registry = self._getTargetClass()()
+        registry = self._makeOne()
         self.assertEqual(registry.package_name, 'pyramid.tests')
 
     def test_registerHandler_and_notify(self):
@@ -61,6 +61,25 @@ def test__set_settings(self):
         registry.settings = 'foo'
         self.assertEqual(registry._settings, 'foo')
 
+    def test_init_forwards_args(self):
+        from zope.interface import Interface
+        from zope.interface.registry import Components
+        dummy = object()
+        c = Components()
+        c.registerUtility(dummy, Interface)
+        registry = self._makeOne('foo', (c,))
+        self.assertEqual(registry.__name__, 'foo')
+        self.assertEqual(registry.getUtility(Interface), dummy)
+
+    def test_init_forwards_kw(self):
+        from zope.interface import Interface
+        from zope.interface.registry import Components
+        dummy = object()
+        c = Components()
+        c.registerUtility(dummy, Interface)
+        registry = self._makeOne(bases=(c,))
+        self.assertEqual(registry.getUtility(Interface), dummy)
+
 class TestIntrospector(unittest.TestCase):
     def _getTargetClass(slf):
         from pyramid.registry import Introspector