]> granicus.if.org Git - python/commitdiff
Add custom initializer argument to multiprocess.Manager*, courtesy of lekma
authorJesse Noller <jnoller@gmail.com>
Thu, 2 Apr 2009 05:17:26 +0000 (05:17 +0000)
committerJesse Noller <jnoller@gmail.com>
Thu, 2 Apr 2009 05:17:26 +0000 (05:17 +0000)
Doc/library/multiprocessing.rst
Lib/multiprocessing/managers.py
Lib/multiprocessing/pool.py
Lib/test/test_multiprocessing.py
Misc/NEWS

index 18e81a793858b01b2a14ed04d27ae6818cc9f685..a36836e5267032570501822953a3a455830c94f7 100644 (file)
@@ -1130,9 +1130,10 @@ their parent process exits.  The manager classes are defined in the
    ``current_process().authkey``.  Otherwise *authkey* is used and it
    must be a string.
 
-   .. method:: start()
+   .. method:: start([initializer[, initargs]])
 
-      Start a subprocess to start the manager.
+      Start a subprocess to start the manager.  If *initializer* is not ``None``
+      then the subprocess will call ``initializer(*initargs)`` when it starts.
 
    .. method:: serve_forever()
 
index 02e96b969b46087acc15161df81bbcb847d06a61..fde0e40d373a2c4845d2f57d48ff6c6e00fac59c 100644 (file)
@@ -475,12 +475,15 @@ class BaseManager(object):
         dispatch(conn, None, 'dummy')
         self._state.value = State.STARTED
 
-    def start(self):
+    def start(self, initializer=None, initargs=()):
         '''
         Spawn a server process for this manager object
         '''
         assert self._state.value == State.INITIAL
 
+        if initializer is not None and not hasattr(initializer, '__call__'):
+            raise TypeError('initializer must be a callable')
+
         # pipe over which we will retrieve address of server
         reader, writer = connection.Pipe(duplex=False)
 
@@ -488,7 +491,7 @@ class BaseManager(object):
         self._process = Process(
             target=type(self)._run_server,
             args=(self._registry, self._address, self._authkey,
-                  self._serializer, writer),
+                  self._serializer, writer, initializer, initargs),
             )
         ident = ':'.join(str(i) for i in self._process._identity)
         self._process.name = type(self).__name__  + '-' + ident
@@ -509,10 +512,14 @@ class BaseManager(object):
             )
 
     @classmethod
-    def _run_server(cls, registry, address, authkey, serializer, writer):
+    def _run_server(cls, registry, address, authkey, serializer, writer,
+                    initializer=None, initargs=()):
         '''
         Create a server, report its address and run it
         '''
+        if initializer is not None:
+            initializer(*initargs)
+
         # create server
         server = cls._Server(registry, address, authkey, serializer)
 
index 9da27d48edfff5d35bb8acc9c00ebf36ee4c8fc1..bc7e8f1712e86d420f1412cb39b5d1c41a66a478 100644 (file)
@@ -92,6 +92,9 @@ class Pool(object):
             except NotImplementedError:
                 processes = 1
 
+        if initializer is not None and not hasattr(initializer, '__call__'):
+            raise TypeError('initializer must be a callable')
+
         self._pool = []
         for i in range(processes):
             w = self.Process(
index 8ef2e2fc7b99dba8c5c2fba7a42d55aa36509b82..cbcb63022d2ec66191b03f981ae119dbbee97567 100644 (file)
@@ -1831,7 +1831,37 @@ class OtherTest(unittest.TestCase):
                           multiprocessing.connection.answer_challenge,
                           _FakeConnection(), b'abc')
 
-testcases_other = [OtherTest, TestInvalidHandle]
+#
+# Test Manager.start()/Pool.__init__() initializer feature - see issue 5585
+#
+
+def initializer(ns):
+    ns.test += 1
+
+class TestInitializers(unittest.TestCase):
+    def setUp(self):
+        self.mgr = multiprocessing.Manager()
+        self.ns = self.mgr.Namespace()
+        self.ns.test = 0
+
+    def tearDown(self):
+        self.mgr.shutdown()
+
+    def test_manager_initializer(self):
+        m = multiprocessing.managers.SyncManager()
+        self.assertRaises(TypeError, m.start, 1)
+        m.start(initializer, (self.ns,))
+        self.assertEqual(self.ns.test, 1)
+        m.shutdown()
+
+    def test_pool_initializer(self):
+        self.assertRaises(TypeError, multiprocessing.Pool, initializer=1)
+        p = multiprocessing.Pool(1, initializer, (self.ns,))
+        p.close()
+        p.join()
+        self.assertEqual(self.ns.test, 1)
+
+testcases_other = [OtherTest, TestInvalidHandle, TestInitializers]
 
 #
 #
index 8a500597db9daef50bc8ee2d21930847fea4330c..7de7b8aee706a1625dcba06ca3a6691af5def724 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -202,6 +202,9 @@ Core and Builtins
 Library
 -------
 
+- Issue 5585: Add the ability to call an initializer to mulitiprocessing.manager
+  so that users can install custonm handlers/etc.
+
 - Issue 3551: Patch multiprocessing to raise a proper exception if the size of the
   object when writefile is called causes a ERROR_NO_SYSTEM_RESOURCES. Added docs
   to note the limitation