You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1112 lines
36 KiB

Merged revisions 74779-74786,74793,74795,74811,74860-74861,74863,74876,74886,74896,74901,74903,74908,74912,74930,74933,74943,74946,74952-74955,75015,75019,75032,75068,75076,75095,75098,75102,75129,75139,75230 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r74779 | michael.foord | 2009-09-13 11:13:36 -0500 (Sun, 13 Sep 2009) | 1 line Change to tutorial wording for reading text / binary files on Windows. Issue #6301. ........ r74780 | michael.foord | 2009-09-13 11:40:02 -0500 (Sun, 13 Sep 2009) | 1 line Objects that compare equal automatically pass or fail assertAlmostEqual and assertNotAlmostEqual tests on unittest.TestCase. Issue 6567. ........ r74781 | michael.foord | 2009-09-13 11:46:19 -0500 (Sun, 13 Sep 2009) | 1 line Note that sys._getframe is not guaranteed to exist in all implementations of Python, and a corresponding note in inspect.currentframe. Issue 6712. ........ r74782 | michael.foord | 2009-09-13 12:07:46 -0500 (Sun, 13 Sep 2009) | 1 line Tutorial tweaks. Issue 6849. ........ r74783 | michael.foord | 2009-09-13 12:28:35 -0500 (Sun, 13 Sep 2009) | 1 line unittest.TestLoader.loadTestsFromName honors the loader suiteClass attribute. Issue 6866. ........ r74784 | georg.brandl | 2009-09-13 13:15:07 -0500 (Sun, 13 Sep 2009) | 1 line Typo fix. ........ r74785 | michael.foord | 2009-09-13 14:07:03 -0500 (Sun, 13 Sep 2009) | 1 line Test discovery in unittest will only attempt to import modules that are importable; i.e. their names are valid Python identifiers. If an import fails during discovery this will be recorded as an error and test discovery will continue. Issue 6568. ........ r74786 | michael.foord | 2009-09-13 14:08:18 -0500 (Sun, 13 Sep 2009) | 1 line Remove an extraneous space in unittest documentation. ........ r74793 | georg.brandl | 2009-09-14 09:50:47 -0500 (Mon, 14 Sep 2009) | 1 line #6908: fix association of hashlib hash attributes. ........ r74795 | benjamin.peterson | 2009-09-14 22:36:26 -0500 (Mon, 14 Sep 2009) | 1 line Py_SetPythonHome uses static storage #6913 ........ r74811 | georg.brandl | 2009-09-15 15:26:59 -0500 (Tue, 15 Sep 2009) | 1 line Add Armin Ronacher. ........ r74860 | benjamin.peterson | 2009-09-16 21:46:54 -0500 (Wed, 16 Sep 2009) | 1 line kill bare except ........ r74861 | benjamin.peterson | 2009-09-16 22:18:28 -0500 (Wed, 16 Sep 2009) | 1 line pep 8 defaults ........ r74863 | benjamin.peterson | 2009-09-16 22:27:33 -0500 (Wed, 16 Sep 2009) | 1 line rationalize a bit ........ r74876 | georg.brandl | 2009-09-17 11:15:53 -0500 (Thu, 17 Sep 2009) | 1 line #6932: remove paragraph that advises relying on __del__ being called. ........ r74886 | benjamin.peterson | 2009-09-17 16:33:46 -0500 (Thu, 17 Sep 2009) | 1 line use macros ........ r74896 | georg.brandl | 2009-09-18 02:22:41 -0500 (Fri, 18 Sep 2009) | 1 line #6936: for interactive use, quit() is just fine. ........ r74901 | georg.brandl | 2009-09-18 04:14:52 -0500 (Fri, 18 Sep 2009) | 1 line #6905: use better exception messages in inspect when the argument is of the wrong type. ........ r74903 | georg.brandl | 2009-09-18 04:18:27 -0500 (Fri, 18 Sep 2009) | 1 line #6938: "ident" is always a string, so use a format code which works. ........ r74908 | georg.brandl | 2009-09-18 08:57:11 -0500 (Fri, 18 Sep 2009) | 1 line Use str.format() to fix beginner's mistake with %-style string formatting. ........ r74912 | georg.brandl | 2009-09-18 11:19:56 -0500 (Fri, 18 Sep 2009) | 1 line Optimize optimization and fix method name in docstring. ........ r74930 | georg.brandl | 2009-09-18 16:21:41 -0500 (Fri, 18 Sep 2009) | 1 line #6925: rewrite docs for locals() and vars() a bit. ........ r74933 | georg.brandl | 2009-09-18 16:35:59 -0500 (Fri, 18 Sep 2009) | 1 line #6930: clarify description about byteorder handling in UTF decoder routines. ........ r74943 | georg.brandl | 2009-09-19 02:35:07 -0500 (Sat, 19 Sep 2009) | 1 line #6944: the argument to PyArg_ParseTuple should be a tuple, otherwise a SystemError is set. Also clean up another usage of PyArg_ParseTuple. ........ r74946 | georg.brandl | 2009-09-19 03:43:16 -0500 (Sat, 19 Sep 2009) | 1 line Update bug tracker reference. ........ r74952 | georg.brandl | 2009-09-19 05:42:34 -0500 (Sat, 19 Sep 2009) | 1 line #6946: fix duplicate index entries for datetime classes. ........ r74953 | georg.brandl | 2009-09-19 07:04:16 -0500 (Sat, 19 Sep 2009) | 1 line Fix references to threading.enumerate(). ........ r74954 | georg.brandl | 2009-09-19 08:13:56 -0500 (Sat, 19 Sep 2009) | 1 line Add Doug. ........ r74955 | georg.brandl | 2009-09-19 08:20:49 -0500 (Sat, 19 Sep 2009) | 1 line Add Mark Summerfield. ........ r75015 | georg.brandl | 2009-09-22 05:55:08 -0500 (Tue, 22 Sep 2009) | 1 line Fix encoding name. ........ r75019 | vinay.sajip | 2009-09-22 12:23:41 -0500 (Tue, 22 Sep 2009) | 1 line Fixed a typo, and added sections on optimization and using arbitrary objects as messages. ........ r75032 | benjamin.peterson | 2009-09-22 17:15:28 -0500 (Tue, 22 Sep 2009) | 1 line fix typos/rephrase ........ r75068 | benjamin.peterson | 2009-09-25 21:57:59 -0500 (Fri, 25 Sep 2009) | 1 line comment out ugly xxx ........ r75076 | vinay.sajip | 2009-09-26 09:53:32 -0500 (Sat, 26 Sep 2009) | 1 line Tidied up name of parameter in StreamHandler ........ r75095 | michael.foord | 2009-09-27 14:15:41 -0500 (Sun, 27 Sep 2009) | 1 line Test creation moved from TestProgram.parseArgs to TestProgram.createTests exclusively. Issue 6956. ........ r75098 | michael.foord | 2009-09-27 15:08:23 -0500 (Sun, 27 Sep 2009) | 1 line Documentation improvement for load_tests protocol in unittest. Issue 6515. ........ r75102 | skip.montanaro | 2009-09-27 21:12:27 -0500 (Sun, 27 Sep 2009) | 3 lines Patch from Thomas Barr so that csv.Sniffer will set doublequote property. Closes issue 6606. ........ r75129 | vinay.sajip | 2009-09-29 02:08:54 -0500 (Tue, 29 Sep 2009) | 1 line Issue #7014: logging: Improved IronPython 2.6 compatibility. ........ r75139 | raymond.hettinger | 2009-09-29 13:53:24 -0500 (Tue, 29 Sep 2009) | 3 lines Issue 7008: Better document str.title and show how to work around the apostrophe problem. ........ r75230 | benjamin.peterson | 2009-10-04 08:38:38 -0500 (Sun, 04 Oct 2009) | 1 line test logging ........
17 years ago
Merged revisions 70912,70944,70968,71033,71041,71208,71263,71286,71395-71396,71405-71406,71485,71492,71494 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70912 | georg.brandl | 2009-03-31 17:35:46 -0500 (Tue, 31 Mar 2009) | 1 line #5617: add a handy function to print a unicode string to gdbinit. ........ r70944 | georg.brandl | 2009-03-31 23:32:39 -0500 (Tue, 31 Mar 2009) | 1 line #5631: add upload to list of possible commands, which is presented in --help-commands. ........ r70968 | michael.foord | 2009-04-01 13:25:38 -0500 (Wed, 01 Apr 2009) | 1 line Adding Wing project file ........ r71033 | brett.cannon | 2009-04-01 22:34:53 -0500 (Wed, 01 Apr 2009) | 3 lines Fix two issues introduced by issue #71031 by changing the signature of PyImport_AppendInittab() to take a const char *. ........ r71041 | jesse.noller | 2009-04-02 00:17:26 -0500 (Thu, 02 Apr 2009) | 1 line Add custom initializer argument to multiprocess.Manager*, courtesy of lekma ........ r71208 | michael.foord | 2009-04-04 20:15:01 -0500 (Sat, 04 Apr 2009) | 4 lines Change the way unittest.TestSuite use their tests to always access them through iteration. Non behavior changing, this allows you to create custom subclasses that override __iter__. Issue #5693 ........ r71263 | michael.foord | 2009-04-05 14:19:28 -0500 (Sun, 05 Apr 2009) | 4 lines Adding assertIs and assertIsNot methods to unittest.TestCase Issue #2578 ........ r71286 | tarek.ziade | 2009-04-05 17:04:38 -0500 (Sun, 05 Apr 2009) | 1 line added a simplest test to distutils.spawn._nt_quote_args ........ r71395 | benjamin.peterson | 2009-04-08 08:27:29 -0500 (Wed, 08 Apr 2009) | 1 line these must be installed to correctly run tests ........ r71396 | benjamin.peterson | 2009-04-08 08:29:41 -0500 (Wed, 08 Apr 2009) | 1 line fix syntax ........ r71405 | andrew.kuchling | 2009-04-09 06:22:47 -0500 (Thu, 09 Apr 2009) | 1 line Add items ........ r71406 | andrew.kuchling | 2009-04-09 06:23:36 -0500 (Thu, 09 Apr 2009) | 1 line Typo fixes ........ r71485 | andrew.kuchling | 2009-04-11 11:12:23 -0500 (Sat, 11 Apr 2009) | 1 line Add various items ........ r71492 | georg.brandl | 2009-04-11 13:19:27 -0500 (Sat, 11 Apr 2009) | 1 line Take credit for a patch of mine. ........ r71494 | benjamin.peterson | 2009-04-11 14:31:00 -0500 (Sat, 11 Apr 2009) | 1 line ignore py3_test_grammar when compiling the library ........
17 years ago
Merged revisions 70912,70944,70968,71033,71041,71208,71263,71286,71395-71396,71405-71406,71485,71492,71494 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70912 | georg.brandl | 2009-03-31 17:35:46 -0500 (Tue, 31 Mar 2009) | 1 line #5617: add a handy function to print a unicode string to gdbinit. ........ r70944 | georg.brandl | 2009-03-31 23:32:39 -0500 (Tue, 31 Mar 2009) | 1 line #5631: add upload to list of possible commands, which is presented in --help-commands. ........ r70968 | michael.foord | 2009-04-01 13:25:38 -0500 (Wed, 01 Apr 2009) | 1 line Adding Wing project file ........ r71033 | brett.cannon | 2009-04-01 22:34:53 -0500 (Wed, 01 Apr 2009) | 3 lines Fix two issues introduced by issue #71031 by changing the signature of PyImport_AppendInittab() to take a const char *. ........ r71041 | jesse.noller | 2009-04-02 00:17:26 -0500 (Thu, 02 Apr 2009) | 1 line Add custom initializer argument to multiprocess.Manager*, courtesy of lekma ........ r71208 | michael.foord | 2009-04-04 20:15:01 -0500 (Sat, 04 Apr 2009) | 4 lines Change the way unittest.TestSuite use their tests to always access them through iteration. Non behavior changing, this allows you to create custom subclasses that override __iter__. Issue #5693 ........ r71263 | michael.foord | 2009-04-05 14:19:28 -0500 (Sun, 05 Apr 2009) | 4 lines Adding assertIs and assertIsNot methods to unittest.TestCase Issue #2578 ........ r71286 | tarek.ziade | 2009-04-05 17:04:38 -0500 (Sun, 05 Apr 2009) | 1 line added a simplest test to distutils.spawn._nt_quote_args ........ r71395 | benjamin.peterson | 2009-04-08 08:27:29 -0500 (Wed, 08 Apr 2009) | 1 line these must be installed to correctly run tests ........ r71396 | benjamin.peterson | 2009-04-08 08:29:41 -0500 (Wed, 08 Apr 2009) | 1 line fix syntax ........ r71405 | andrew.kuchling | 2009-04-09 06:22:47 -0500 (Thu, 09 Apr 2009) | 1 line Add items ........ r71406 | andrew.kuchling | 2009-04-09 06:23:36 -0500 (Thu, 09 Apr 2009) | 1 line Typo fixes ........ r71485 | andrew.kuchling | 2009-04-11 11:12:23 -0500 (Sat, 11 Apr 2009) | 1 line Add various items ........ r71492 | georg.brandl | 2009-04-11 13:19:27 -0500 (Sat, 11 Apr 2009) | 1 line Take credit for a patch of mine. ........ r71494 | benjamin.peterson | 2009-04-11 14:31:00 -0500 (Sat, 11 Apr 2009) | 1 line ignore py3_test_grammar when compiling the library ........
17 years ago
Merged revisions 70912,70944,70968,71033,71041,71208,71263,71286,71395-71396,71405-71406,71485,71492,71494 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70912 | georg.brandl | 2009-03-31 17:35:46 -0500 (Tue, 31 Mar 2009) | 1 line #5617: add a handy function to print a unicode string to gdbinit. ........ r70944 | georg.brandl | 2009-03-31 23:32:39 -0500 (Tue, 31 Mar 2009) | 1 line #5631: add upload to list of possible commands, which is presented in --help-commands. ........ r70968 | michael.foord | 2009-04-01 13:25:38 -0500 (Wed, 01 Apr 2009) | 1 line Adding Wing project file ........ r71033 | brett.cannon | 2009-04-01 22:34:53 -0500 (Wed, 01 Apr 2009) | 3 lines Fix two issues introduced by issue #71031 by changing the signature of PyImport_AppendInittab() to take a const char *. ........ r71041 | jesse.noller | 2009-04-02 00:17:26 -0500 (Thu, 02 Apr 2009) | 1 line Add custom initializer argument to multiprocess.Manager*, courtesy of lekma ........ r71208 | michael.foord | 2009-04-04 20:15:01 -0500 (Sat, 04 Apr 2009) | 4 lines Change the way unittest.TestSuite use their tests to always access them through iteration. Non behavior changing, this allows you to create custom subclasses that override __iter__. Issue #5693 ........ r71263 | michael.foord | 2009-04-05 14:19:28 -0500 (Sun, 05 Apr 2009) | 4 lines Adding assertIs and assertIsNot methods to unittest.TestCase Issue #2578 ........ r71286 | tarek.ziade | 2009-04-05 17:04:38 -0500 (Sun, 05 Apr 2009) | 1 line added a simplest test to distutils.spawn._nt_quote_args ........ r71395 | benjamin.peterson | 2009-04-08 08:27:29 -0500 (Wed, 08 Apr 2009) | 1 line these must be installed to correctly run tests ........ r71396 | benjamin.peterson | 2009-04-08 08:29:41 -0500 (Wed, 08 Apr 2009) | 1 line fix syntax ........ r71405 | andrew.kuchling | 2009-04-09 06:22:47 -0500 (Thu, 09 Apr 2009) | 1 line Add items ........ r71406 | andrew.kuchling | 2009-04-09 06:23:36 -0500 (Thu, 09 Apr 2009) | 1 line Typo fixes ........ r71485 | andrew.kuchling | 2009-04-11 11:12:23 -0500 (Sat, 11 Apr 2009) | 1 line Add various items ........ r71492 | georg.brandl | 2009-04-11 13:19:27 -0500 (Sat, 11 Apr 2009) | 1 line Take credit for a patch of mine. ........ r71494 | benjamin.peterson | 2009-04-11 14:31:00 -0500 (Sat, 11 Apr 2009) | 1 line ignore py3_test_grammar when compiling the library ........
17 years ago
Merged revisions 70912,70944,70968,71033,71041,71208,71263,71286,71395-71396,71405-71406,71485,71492,71494 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70912 | georg.brandl | 2009-03-31 17:35:46 -0500 (Tue, 31 Mar 2009) | 1 line #5617: add a handy function to print a unicode string to gdbinit. ........ r70944 | georg.brandl | 2009-03-31 23:32:39 -0500 (Tue, 31 Mar 2009) | 1 line #5631: add upload to list of possible commands, which is presented in --help-commands. ........ r70968 | michael.foord | 2009-04-01 13:25:38 -0500 (Wed, 01 Apr 2009) | 1 line Adding Wing project file ........ r71033 | brett.cannon | 2009-04-01 22:34:53 -0500 (Wed, 01 Apr 2009) | 3 lines Fix two issues introduced by issue #71031 by changing the signature of PyImport_AppendInittab() to take a const char *. ........ r71041 | jesse.noller | 2009-04-02 00:17:26 -0500 (Thu, 02 Apr 2009) | 1 line Add custom initializer argument to multiprocess.Manager*, courtesy of lekma ........ r71208 | michael.foord | 2009-04-04 20:15:01 -0500 (Sat, 04 Apr 2009) | 4 lines Change the way unittest.TestSuite use their tests to always access them through iteration. Non behavior changing, this allows you to create custom subclasses that override __iter__. Issue #5693 ........ r71263 | michael.foord | 2009-04-05 14:19:28 -0500 (Sun, 05 Apr 2009) | 4 lines Adding assertIs and assertIsNot methods to unittest.TestCase Issue #2578 ........ r71286 | tarek.ziade | 2009-04-05 17:04:38 -0500 (Sun, 05 Apr 2009) | 1 line added a simplest test to distutils.spawn._nt_quote_args ........ r71395 | benjamin.peterson | 2009-04-08 08:27:29 -0500 (Wed, 08 Apr 2009) | 1 line these must be installed to correctly run tests ........ r71396 | benjamin.peterson | 2009-04-08 08:29:41 -0500 (Wed, 08 Apr 2009) | 1 line fix syntax ........ r71405 | andrew.kuchling | 2009-04-09 06:22:47 -0500 (Thu, 09 Apr 2009) | 1 line Add items ........ r71406 | andrew.kuchling | 2009-04-09 06:23:36 -0500 (Thu, 09 Apr 2009) | 1 line Typo fixes ........ r71485 | andrew.kuchling | 2009-04-11 11:12:23 -0500 (Sat, 11 Apr 2009) | 1 line Add various items ........ r71492 | georg.brandl | 2009-04-11 13:19:27 -0500 (Sat, 11 Apr 2009) | 1 line Take credit for a patch of mine. ........ r71494 | benjamin.peterson | 2009-04-11 14:31:00 -0500 (Sat, 11 Apr 2009) | 1 line ignore py3_test_grammar when compiling the library ........
17 years ago
Merged revisions 70912,70944,70968,71033,71041,71208,71263,71286,71395-71396,71405-71406,71485,71492,71494 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r70912 | georg.brandl | 2009-03-31 17:35:46 -0500 (Tue, 31 Mar 2009) | 1 line #5617: add a handy function to print a unicode string to gdbinit. ........ r70944 | georg.brandl | 2009-03-31 23:32:39 -0500 (Tue, 31 Mar 2009) | 1 line #5631: add upload to list of possible commands, which is presented in --help-commands. ........ r70968 | michael.foord | 2009-04-01 13:25:38 -0500 (Wed, 01 Apr 2009) | 1 line Adding Wing project file ........ r71033 | brett.cannon | 2009-04-01 22:34:53 -0500 (Wed, 01 Apr 2009) | 3 lines Fix two issues introduced by issue #71031 by changing the signature of PyImport_AppendInittab() to take a const char *. ........ r71041 | jesse.noller | 2009-04-02 00:17:26 -0500 (Thu, 02 Apr 2009) | 1 line Add custom initializer argument to multiprocess.Manager*, courtesy of lekma ........ r71208 | michael.foord | 2009-04-04 20:15:01 -0500 (Sat, 04 Apr 2009) | 4 lines Change the way unittest.TestSuite use their tests to always access them through iteration. Non behavior changing, this allows you to create custom subclasses that override __iter__. Issue #5693 ........ r71263 | michael.foord | 2009-04-05 14:19:28 -0500 (Sun, 05 Apr 2009) | 4 lines Adding assertIs and assertIsNot methods to unittest.TestCase Issue #2578 ........ r71286 | tarek.ziade | 2009-04-05 17:04:38 -0500 (Sun, 05 Apr 2009) | 1 line added a simplest test to distutils.spawn._nt_quote_args ........ r71395 | benjamin.peterson | 2009-04-08 08:27:29 -0500 (Wed, 08 Apr 2009) | 1 line these must be installed to correctly run tests ........ r71396 | benjamin.peterson | 2009-04-08 08:29:41 -0500 (Wed, 08 Apr 2009) | 1 line fix syntax ........ r71405 | andrew.kuchling | 2009-04-09 06:22:47 -0500 (Thu, 09 Apr 2009) | 1 line Add items ........ r71406 | andrew.kuchling | 2009-04-09 06:23:36 -0500 (Thu, 09 Apr 2009) | 1 line Typo fixes ........ r71485 | andrew.kuchling | 2009-04-11 11:12:23 -0500 (Sat, 11 Apr 2009) | 1 line Add various items ........ r71492 | georg.brandl | 2009-04-11 13:19:27 -0500 (Sat, 11 Apr 2009) | 1 line Take credit for a patch of mine. ........ r71494 | benjamin.peterson | 2009-04-11 14:31:00 -0500 (Sat, 11 Apr 2009) | 1 line ignore py3_test_grammar when compiling the library ........
17 years ago
  1. #
  2. # Module providing the `SyncManager` class for dealing
  3. # with shared objects
  4. #
  5. # multiprocessing/managers.py
  6. #
  7. # Copyright (c) 2006-2008, R Oudkerk
  8. # All rights reserved.
  9. #
  10. # Redistribution and use in source and binary forms, with or without
  11. # modification, are permitted provided that the following conditions
  12. # are met:
  13. #
  14. # 1. Redistributions of source code must retain the above copyright
  15. # notice, this list of conditions and the following disclaimer.
  16. # 2. Redistributions in binary form must reproduce the above copyright
  17. # notice, this list of conditions and the following disclaimer in the
  18. # documentation and/or other materials provided with the distribution.
  19. # 3. Neither the name of author nor the names of any contributors may be
  20. # used to endorse or promote products derived from this software
  21. # without specific prior written permission.
  22. #
  23. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
  24. # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26. # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  27. # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28. # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29. # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30. # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32. # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33. # SUCH DAMAGE.
  34. #
  35. __all__ = [ 'BaseManager', 'SyncManager', 'BaseProxy', 'Token' ]
  36. #
  37. # Imports
  38. #
  39. import sys
  40. import threading
  41. import array
  42. import queue
  43. from traceback import format_exc
  44. from multiprocessing import Process, current_process, active_children, Pool, util, connection
  45. from multiprocessing.process import AuthenticationString
  46. from multiprocessing.forking import exit, Popen, ForkingPickler
  47. #
  48. # Register some things for pickling
  49. #
  50. def reduce_array(a):
  51. return array.array, (a.typecode, a.tobytes())
  52. ForkingPickler.register(array.array, reduce_array)
  53. view_types = [type(getattr({}, name)()) for name in ('items','keys','values')]
  54. if view_types[0] is not list: # only needed in Py3.0
  55. def rebuild_as_list(obj):
  56. return list, (list(obj),)
  57. for view_type in view_types:
  58. ForkingPickler.register(view_type, rebuild_as_list)
  59. import copyreg
  60. copyreg.pickle(view_type, rebuild_as_list)
  61. #
  62. # Type for identifying shared objects
  63. #
  64. class Token(object):
  65. '''
  66. Type to uniquely indentify a shared object
  67. '''
  68. __slots__ = ('typeid', 'address', 'id')
  69. def __init__(self, typeid, address, id):
  70. (self.typeid, self.address, self.id) = (typeid, address, id)
  71. def __getstate__(self):
  72. return (self.typeid, self.address, self.id)
  73. def __setstate__(self, state):
  74. (self.typeid, self.address, self.id) = state
  75. def __repr__(self):
  76. return 'Token(typeid=%r, address=%r, id=%r)' % \
  77. (self.typeid, self.address, self.id)
  78. #
  79. # Function for communication with a manager's server process
  80. #
  81. def dispatch(c, id, methodname, args=(), kwds={}):
  82. '''
  83. Send a message to manager using connection `c` and return response
  84. '''
  85. c.send((id, methodname, args, kwds))
  86. kind, result = c.recv()
  87. if kind == '#RETURN':
  88. return result
  89. raise convert_to_error(kind, result)
  90. def convert_to_error(kind, result):
  91. if kind == '#ERROR':
  92. return result
  93. elif kind == '#TRACEBACK':
  94. assert type(result) is str
  95. return RemoteError(result)
  96. elif kind == '#UNSERIALIZABLE':
  97. assert type(result) is str
  98. return RemoteError('Unserializable message: %s\n' % result)
  99. else:
  100. return ValueError('Unrecognized message type')
  101. class RemoteError(Exception):
  102. def __str__(self):
  103. return ('\n' + '-'*75 + '\n' + str(self.args[0]) + '-'*75)
  104. #
  105. # Functions for finding the method names of an object
  106. #
  107. def all_methods(obj):
  108. '''
  109. Return a list of names of methods of `obj`
  110. '''
  111. temp = []
  112. for name in dir(obj):
  113. func = getattr(obj, name)
  114. if callable(func):
  115. temp.append(name)
  116. return temp
  117. def public_methods(obj):
  118. '''
  119. Return a list of names of methods of `obj` which do not start with '_'
  120. '''
  121. return [name for name in all_methods(obj) if name[0] != '_']
  122. #
  123. # Server which is run in a process controlled by a manager
  124. #
  125. class Server(object):
  126. '''
  127. Server class which runs in a process controlled by a manager object
  128. '''
  129. public = ['shutdown', 'create', 'accept_connection', 'get_methods',
  130. 'debug_info', 'number_of_objects', 'dummy', 'incref', 'decref']
  131. def __init__(self, registry, address, authkey, serializer):
  132. assert isinstance(authkey, bytes)
  133. self.registry = registry
  134. self.authkey = AuthenticationString(authkey)
  135. Listener, Client = listener_client[serializer]
  136. # do authentication later
  137. self.listener = Listener(address=address, backlog=16)
  138. self.address = self.listener.address
  139. self.id_to_obj = {'0': (None, ())}
  140. self.id_to_refcount = {}
  141. self.mutex = threading.RLock()
  142. self.stop = 0
  143. def serve_forever(self):
  144. '''
  145. Run the server forever
  146. '''
  147. current_process()._manager_server = self
  148. try:
  149. try:
  150. while 1:
  151. try:
  152. c = self.listener.accept()
  153. except (OSError, IOError):
  154. continue
  155. t = threading.Thread(target=self.handle_request, args=(c,))
  156. t.daemon = True
  157. t.start()
  158. except (KeyboardInterrupt, SystemExit):
  159. pass
  160. finally:
  161. self.stop = 999
  162. self.listener.close()
  163. def handle_request(self, c):
  164. '''
  165. Handle a new connection
  166. '''
  167. funcname = result = request = None
  168. try:
  169. connection.deliver_challenge(c, self.authkey)
  170. connection.answer_challenge(c, self.authkey)
  171. request = c.recv()
  172. ignore, funcname, args, kwds = request
  173. assert funcname in self.public, '%r unrecognized' % funcname
  174. func = getattr(self, funcname)
  175. except Exception:
  176. msg = ('#TRACEBACK', format_exc())
  177. else:
  178. try:
  179. result = func(c, *args, **kwds)
  180. except Exception:
  181. msg = ('#TRACEBACK', format_exc())
  182. else:
  183. msg = ('#RETURN', result)
  184. try:
  185. c.send(msg)
  186. except Exception as e:
  187. try:
  188. c.send(('#TRACEBACK', format_exc()))
  189. except Exception:
  190. pass
  191. util.info('Failure to send message: %r', msg)
  192. util.info(' ... request was %r', request)
  193. util.info(' ... exception was %r', e)
  194. c.close()
  195. def serve_client(self, conn):
  196. '''
  197. Handle requests from the proxies in a particular process/thread
  198. '''
  199. util.debug('starting server thread to service %r',
  200. threading.current_thread().name)
  201. recv = conn.recv
  202. send = conn.send
  203. id_to_obj = self.id_to_obj
  204. while not self.stop:
  205. try:
  206. methodname = obj = None
  207. request = recv()
  208. ident, methodname, args, kwds = request
  209. obj, exposed, gettypeid = id_to_obj[ident]
  210. if methodname not in exposed:
  211. raise AttributeError(
  212. 'method %r of %r object is not in exposed=%r' %
  213. (methodname, type(obj), exposed)
  214. )
  215. function = getattr(obj, methodname)
  216. try:
  217. res = function(*args, **kwds)
  218. except Exception as e:
  219. msg = ('#ERROR', e)
  220. else:
  221. typeid = gettypeid and gettypeid.get(methodname, None)
  222. if typeid:
  223. rident, rexposed = self.create(conn, typeid, res)
  224. token = Token(typeid, self.address, rident)
  225. msg = ('#PROXY', (rexposed, token))
  226. else:
  227. msg = ('#RETURN', res)
  228. except AttributeError:
  229. if methodname is None:
  230. msg = ('#TRACEBACK', format_exc())
  231. else:
  232. try:
  233. fallback_func = self.fallback_mapping[methodname]
  234. result = fallback_func(
  235. self, conn, ident, obj, *args, **kwds
  236. )
  237. msg = ('#RETURN', result)
  238. except Exception:
  239. msg = ('#TRACEBACK', format_exc())
  240. except EOFError:
  241. util.debug('got EOF -- exiting thread serving %r',
  242. threading.current_thread().name)
  243. sys.exit(0)
  244. except Exception:
  245. msg = ('#TRACEBACK', format_exc())
  246. try:
  247. try:
  248. send(msg)
  249. except Exception as e:
  250. send(('#UNSERIALIZABLE', repr(msg)))
  251. except Exception as e:
  252. util.info('exception in thread serving %r',
  253. threading.current_thread().name)
  254. util.info(' ... message was %r', msg)
  255. util.info(' ... exception was %r', e)
  256. conn.close()
  257. sys.exit(1)
  258. def fallback_getvalue(self, conn, ident, obj):
  259. return obj
  260. def fallback_str(self, conn, ident, obj):
  261. return str(obj)
  262. def fallback_repr(self, conn, ident, obj):
  263. return repr(obj)
  264. fallback_mapping = {
  265. '__str__':fallback_str,
  266. '__repr__':fallback_repr,
  267. '#GETVALUE':fallback_getvalue
  268. }
  269. def dummy(self, c):
  270. pass
  271. def debug_info(self, c):
  272. '''
  273. Return some info --- useful to spot problems with refcounting
  274. '''
  275. self.mutex.acquire()
  276. try:
  277. result = []
  278. keys = list(self.id_to_obj.keys())
  279. keys.sort()
  280. for ident in keys:
  281. if ident != '0':
  282. result.append(' %s: refcount=%s\n %s' %
  283. (ident, self.id_to_refcount[ident],
  284. str(self.id_to_obj[ident][0])[:75]))
  285. return '\n'.join(result)
  286. finally:
  287. self.mutex.release()
  288. def number_of_objects(self, c):
  289. '''
  290. Number of shared objects
  291. '''
  292. return len(self.id_to_obj) - 1 # don't count ident='0'
  293. def shutdown(self, c):
  294. '''
  295. Shutdown this process
  296. '''
  297. try:
  298. try:
  299. util.debug('manager received shutdown message')
  300. c.send(('#RETURN', None))
  301. if sys.stdout != sys.__stdout__:
  302. util.debug('resetting stdout, stderr')
  303. sys.stdout = sys.__stdout__
  304. sys.stderr = sys.__stderr__
  305. util._run_finalizers(0)
  306. for p in active_children():
  307. util.debug('terminating a child process of manager')
  308. p.terminate()
  309. for p in active_children():
  310. util.debug('terminating a child process of manager')
  311. p.join()
  312. util._run_finalizers()
  313. util.info('manager exiting with exitcode 0')
  314. except:
  315. import traceback
  316. traceback.print_exc()
  317. finally:
  318. exit(0)
  319. def create(self, c, typeid, *args, **kwds):
  320. '''
  321. Create a new shared object and return its id
  322. '''
  323. self.mutex.acquire()
  324. try:
  325. callable, exposed, method_to_typeid, proxytype = \
  326. self.registry[typeid]
  327. if callable is None:
  328. assert len(args) == 1 and not kwds
  329. obj = args[0]
  330. else:
  331. obj = callable(*args, **kwds)
  332. if exposed is None:
  333. exposed = public_methods(obj)
  334. if method_to_typeid is not None:
  335. assert type(method_to_typeid) is dict
  336. exposed = list(exposed) + list(method_to_typeid)
  337. ident = '%x' % id(obj) # convert to string because xmlrpclib
  338. # only has 32 bit signed integers
  339. util.debug('%r callable returned object with id %r', typeid, ident)
  340. self.id_to_obj[ident] = (obj, set(exposed), method_to_typeid)
  341. if ident not in self.id_to_refcount:
  342. self.id_to_refcount[ident] = 0
  343. # increment the reference count immediately, to avoid
  344. # this object being garbage collected before a Proxy
  345. # object for it can be created. The caller of create()
  346. # is responsible for doing a decref once the Proxy object
  347. # has been created.
  348. self.incref(c, ident)
  349. return ident, tuple(exposed)
  350. finally:
  351. self.mutex.release()
  352. def get_methods(self, c, token):
  353. '''
  354. Return the methods of the shared object indicated by token
  355. '''
  356. return tuple(self.id_to_obj[token.id][1])
  357. def accept_connection(self, c, name):
  358. '''
  359. Spawn a new thread to serve this connection
  360. '''
  361. threading.current_thread().name = name
  362. c.send(('#RETURN', None))
  363. self.serve_client(c)
  364. def incref(self, c, ident):
  365. self.mutex.acquire()
  366. try:
  367. self.id_to_refcount[ident] += 1
  368. finally:
  369. self.mutex.release()
  370. def decref(self, c, ident):
  371. self.mutex.acquire()
  372. try:
  373. assert self.id_to_refcount[ident] >= 1
  374. self.id_to_refcount[ident] -= 1
  375. if self.id_to_refcount[ident] == 0:
  376. del self.id_to_obj[ident], self.id_to_refcount[ident]
  377. util.debug('disposing of obj with id %r', ident)
  378. finally:
  379. self.mutex.release()
  380. #
  381. # Class to represent state of a manager
  382. #
  383. class State(object):
  384. __slots__ = ['value']
  385. INITIAL = 0
  386. STARTED = 1
  387. SHUTDOWN = 2
  388. #
  389. # Mapping from serializer name to Listener and Client types
  390. #
  391. listener_client = {
  392. 'pickle' : (connection.Listener, connection.Client),
  393. 'xmlrpclib' : (connection.XmlListener, connection.XmlClient)
  394. }
  395. #
  396. # Definition of BaseManager
  397. #
  398. class BaseManager(object):
  399. '''
  400. Base class for managers
  401. '''
  402. _registry = {}
  403. _Server = Server
  404. def __init__(self, address=None, authkey=None, serializer='pickle'):
  405. if authkey is None:
  406. authkey = current_process().authkey
  407. self._address = address # XXX not final address if eg ('', 0)
  408. self._authkey = AuthenticationString(authkey)
  409. self._state = State()
  410. self._state.value = State.INITIAL
  411. self._serializer = serializer
  412. self._Listener, self._Client = listener_client[serializer]
  413. def __reduce__(self):
  414. return type(self).from_address, \
  415. (self._address, self._authkey, self._serializer)
  416. def get_server(self):
  417. '''
  418. Return server object with serve_forever() method and address attribute
  419. '''
  420. assert self._state.value == State.INITIAL
  421. return Server(self._registry, self._address,
  422. self._authkey, self._serializer)
  423. def connect(self):
  424. '''
  425. Connect manager object to the server process
  426. '''
  427. Listener, Client = listener_client[self._serializer]
  428. conn = Client(self._address, authkey=self._authkey)
  429. dispatch(conn, None, 'dummy')
  430. self._state.value = State.STARTED
  431. def start(self, initializer=None, initargs=()):
  432. '''
  433. Spawn a server process for this manager object
  434. '''
  435. assert self._state.value == State.INITIAL
  436. if initializer is not None and not callable(initializer):
  437. raise TypeError('initializer must be a callable')
  438. # pipe over which we will retrieve address of server
  439. reader, writer = connection.Pipe(duplex=False)
  440. # spawn process which runs a server
  441. self._process = Process(
  442. target=type(self)._run_server,
  443. args=(self._registry, self._address, self._authkey,
  444. self._serializer, writer, initializer, initargs),
  445. )
  446. ident = ':'.join(str(i) for i in self._process._identity)
  447. self._process.name = type(self).__name__ + '-' + ident
  448. self._process.start()
  449. # get address of server
  450. writer.close()
  451. self._address = reader.recv()
  452. reader.close()
  453. # register a finalizer
  454. self._state.value = State.STARTED
  455. self.shutdown = util.Finalize(
  456. self, type(self)._finalize_manager,
  457. args=(self._process, self._address, self._authkey,
  458. self._state, self._Client),
  459. exitpriority=0
  460. )
  461. @classmethod
  462. def _run_server(cls, registry, address, authkey, serializer, writer,
  463. initializer=None, initargs=()):
  464. '''
  465. Create a server, report its address and run it
  466. '''
  467. if initializer is not None:
  468. initializer(*initargs)
  469. # create server
  470. server = cls._Server(registry, address, authkey, serializer)
  471. # inform parent process of the server's address
  472. writer.send(server.address)
  473. writer.close()
  474. # run the manager
  475. util.info('manager serving at %r', server.address)
  476. server.serve_forever()
  477. def _create(self, typeid, *args, **kwds):
  478. '''
  479. Create a new shared object; return the token and exposed tuple
  480. '''
  481. assert self._state.value == State.STARTED, 'server not yet started'
  482. conn = self._Client(self._address, authkey=self._authkey)
  483. try:
  484. id, exposed = dispatch(conn, None, 'create', (typeid,)+args, kwds)
  485. finally:
  486. conn.close()
  487. return Token(typeid, self._address, id), exposed
  488. def join(self, timeout=None):
  489. '''
  490. Join the manager process (if it has been spawned)
  491. '''
  492. self._process.join(timeout)
  493. def _debug_info(self):
  494. '''
  495. Return some info about the servers shared objects and connections
  496. '''
  497. conn = self._Client(self._address, authkey=self._authkey)
  498. try:
  499. return dispatch(conn, None, 'debug_info')
  500. finally:
  501. conn.close()
  502. def _number_of_objects(self):
  503. '''
  504. Return the number of shared objects
  505. '''
  506. conn = self._Client(self._address, authkey=self._authkey)
  507. try:
  508. return dispatch(conn, None, 'number_of_objects')
  509. finally:
  510. conn.close()
  511. def __enter__(self):
  512. return self
  513. def __exit__(self, exc_type, exc_val, exc_tb):
  514. self.shutdown()
  515. @staticmethod
  516. def _finalize_manager(process, address, authkey, state, _Client):
  517. '''
  518. Shutdown the manager process; will be registered as a finalizer
  519. '''
  520. if process.is_alive():
  521. util.info('sending shutdown message to manager')
  522. try:
  523. conn = _Client(address, authkey=authkey)
  524. try:
  525. dispatch(conn, None, 'shutdown')
  526. finally:
  527. conn.close()
  528. except Exception:
  529. pass
  530. process.join(timeout=0.2)
  531. if process.is_alive():
  532. util.info('manager still alive')
  533. if hasattr(process, 'terminate'):
  534. util.info('trying to `terminate()` manager process')
  535. process.terminate()
  536. process.join(timeout=0.1)
  537. if process.is_alive():
  538. util.info('manager still alive after terminate')
  539. state.value = State.SHUTDOWN
  540. try:
  541. del BaseProxy._address_to_local[address]
  542. except KeyError:
  543. pass
  544. address = property(lambda self: self._address)
  545. @classmethod
  546. def register(cls, typeid, callable=None, proxytype=None, exposed=None,
  547. method_to_typeid=None, create_method=True):
  548. '''
  549. Register a typeid with the manager type
  550. '''
  551. if '_registry' not in cls.__dict__:
  552. cls._registry = cls._registry.copy()
  553. if proxytype is None:
  554. proxytype = AutoProxy
  555. exposed = exposed or getattr(proxytype, '_exposed_', None)
  556. method_to_typeid = method_to_typeid or \
  557. getattr(proxytype, '_method_to_typeid_', None)
  558. if method_to_typeid:
  559. for key, value in list(method_to_typeid.items()):
  560. assert type(key) is str, '%r is not a string' % key
  561. assert type(value) is str, '%r is not a string' % value
  562. cls._registry[typeid] = (
  563. callable, exposed, method_to_typeid, proxytype
  564. )
  565. if create_method:
  566. def temp(self, *args, **kwds):
  567. util.debug('requesting creation of a shared %r object', typeid)
  568. token, exp = self._create(typeid, *args, **kwds)
  569. proxy = proxytype(
  570. token, self._serializer, manager=self,
  571. authkey=self._authkey, exposed=exp
  572. )
  573. conn = self._Client(token.address, authkey=self._authkey)
  574. dispatch(conn, None, 'decref', (token.id,))
  575. return proxy
  576. temp.__name__ = typeid
  577. setattr(cls, typeid, temp)
  578. #
  579. # Subclass of set which get cleared after a fork
  580. #
  581. class ProcessLocalSet(set):
  582. def __init__(self):
  583. util.register_after_fork(self, lambda obj: obj.clear())
  584. def __reduce__(self):
  585. return type(self), ()
  586. #
  587. # Definition of BaseProxy
  588. #
  589. class BaseProxy(object):
  590. '''
  591. A base for proxies of shared objects
  592. '''
  593. _address_to_local = {}
  594. _mutex = util.ForkAwareThreadLock()
  595. def __init__(self, token, serializer, manager=None,
  596. authkey=None, exposed=None, incref=True):
  597. BaseProxy._mutex.acquire()
  598. try:
  599. tls_idset = BaseProxy._address_to_local.get(token.address, None)
  600. if tls_idset is None:
  601. tls_idset = util.ForkAwareLocal(), ProcessLocalSet()
  602. BaseProxy._address_to_local[token.address] = tls_idset
  603. finally:
  604. BaseProxy._mutex.release()
  605. # self._tls is used to record the connection used by this
  606. # thread to communicate with the manager at token.address
  607. self._tls = tls_idset[0]
  608. # self._idset is used to record the identities of all shared
  609. # objects for which the current process owns references and
  610. # which are in the manager at token.address
  611. self._idset = tls_idset[1]
  612. self._token = token
  613. self._id = self._token.id
  614. self._manager = manager
  615. self._serializer = serializer
  616. self._Client = listener_client[serializer][1]
  617. if authkey is not None:
  618. self._authkey = AuthenticationString(authkey)
  619. elif self._manager is not None:
  620. self._authkey = self._manager._authkey
  621. else:
  622. self._authkey = current_process().authkey
  623. if incref:
  624. self._incref()
  625. util.register_after_fork(self, BaseProxy._after_fork)
  626. def _connect(self):
  627. util.debug('making connection to manager')
  628. name = current_process().name
  629. if threading.current_thread().name != 'MainThread':
  630. name += '|' + threading.current_thread().name
  631. conn = self._Client(self._token.address, authkey=self._authkey)
  632. dispatch(conn, None, 'accept_connection', (name,))
  633. self._tls.connection = conn
  634. def _callmethod(self, methodname, args=(), kwds={}):
  635. '''
  636. Try to call a method of the referrent and return a copy of the result
  637. '''
  638. try:
  639. conn = self._tls.connection
  640. except AttributeError:
  641. util.debug('thread %r does not own a connection',
  642. threading.current_thread().name)
  643. self._connect()
  644. conn = self._tls.connection
  645. conn.send((self._id, methodname, args, kwds))
  646. kind, result = conn.recv()
  647. if kind == '#RETURN':
  648. return result
  649. elif kind == '#PROXY':
  650. exposed, token = result
  651. proxytype = self._manager._registry[token.typeid][-1]
  652. proxy = proxytype(
  653. token, self._serializer, manager=self._manager,
  654. authkey=self._authkey, exposed=exposed
  655. )
  656. conn = self._Client(token.address, authkey=self._authkey)
  657. dispatch(conn, None, 'decref', (token.id,))
  658. return proxy
  659. raise convert_to_error(kind, result)
  660. def _getvalue(self):
  661. '''
  662. Get a copy of the value of the referent
  663. '''
  664. return self._callmethod('#GETVALUE')
  665. def _incref(self):
  666. conn = self._Client(self._token.address, authkey=self._authkey)
  667. dispatch(conn, None, 'incref', (self._id,))
  668. util.debug('INCREF %r', self._token.id)
  669. self._idset.add(self._id)
  670. state = self._manager and self._manager._state
  671. self._close = util.Finalize(
  672. self, BaseProxy._decref,
  673. args=(self._token, self._authkey, state,
  674. self._tls, self._idset, self._Client),
  675. exitpriority=10
  676. )
  677. @staticmethod
  678. def _decref(token, authkey, state, tls, idset, _Client):
  679. idset.discard(token.id)
  680. # check whether manager is still alive
  681. if state is None or state.value == State.STARTED:
  682. # tell manager this process no longer cares about referent
  683. try:
  684. util.debug('DECREF %r', token.id)
  685. conn = _Client(token.address, authkey=authkey)
  686. dispatch(conn, None, 'decref', (token.id,))
  687. except Exception as e:
  688. util.debug('... decref failed %s', e)
  689. else:
  690. util.debug('DECREF %r -- manager already shutdown', token.id)
  691. # check whether we can close this thread's connection because
  692. # the process owns no more references to objects for this manager
  693. if not idset and hasattr(tls, 'connection'):
  694. util.debug('thread %r has no more proxies so closing conn',
  695. threading.current_thread().name)
  696. tls.connection.close()
  697. del tls.connection
  698. def _after_fork(self):
  699. self._manager = None
  700. try:
  701. self._incref()
  702. except Exception as e:
  703. # the proxy may just be for a manager which has shutdown
  704. util.info('incref failed: %s' % e)
  705. def __reduce__(self):
  706. kwds = {}
  707. if Popen.thread_is_spawning():
  708. kwds['authkey'] = self._authkey
  709. if getattr(self, '_isauto', False):
  710. kwds['exposed'] = self._exposed_
  711. return (RebuildProxy,
  712. (AutoProxy, self._token, self._serializer, kwds))
  713. else:
  714. return (RebuildProxy,
  715. (type(self), self._token, self._serializer, kwds))
  716. def __deepcopy__(self, memo):
  717. return self._getvalue()
  718. def __repr__(self):
  719. return '<%s object, typeid %r at %s>' % \
  720. (type(self).__name__, self._token.typeid, '0x%x' % id(self))
  721. def __str__(self):
  722. '''
  723. Return representation of the referent (or a fall-back if that fails)
  724. '''
  725. try:
  726. return self._callmethod('__repr__')
  727. except Exception:
  728. return repr(self)[:-1] + "; '__str__()' failed>"
  729. #
  730. # Function used for unpickling
  731. #
  732. def RebuildProxy(func, token, serializer, kwds):
  733. '''
  734. Function used for unpickling proxy objects.
  735. If possible the shared object is returned, or otherwise a proxy for it.
  736. '''
  737. server = getattr(current_process(), '_manager_server', None)
  738. if server and server.address == token.address:
  739. return server.id_to_obj[token.id][0]
  740. else:
  741. incref = (
  742. kwds.pop('incref', True) and
  743. not getattr(current_process(), '_inheriting', False)
  744. )
  745. return func(token, serializer, incref=incref, **kwds)
  746. #
  747. # Functions to create proxies and proxy types
  748. #
  749. def MakeProxyType(name, exposed, _cache={}):
  750. '''
  751. Return an proxy type whose methods are given by `exposed`
  752. '''
  753. exposed = tuple(exposed)
  754. try:
  755. return _cache[(name, exposed)]
  756. except KeyError:
  757. pass
  758. dic = {}
  759. for meth in exposed:
  760. exec('''def %s(self, *args, **kwds):
  761. return self._callmethod(%r, args, kwds)''' % (meth, meth), dic)
  762. ProxyType = type(name, (BaseProxy,), dic)
  763. ProxyType._exposed_ = exposed
  764. _cache[(name, exposed)] = ProxyType
  765. return ProxyType
  766. def AutoProxy(token, serializer, manager=None, authkey=None,
  767. exposed=None, incref=True):
  768. '''
  769. Return an auto-proxy for `token`
  770. '''
  771. _Client = listener_client[serializer][1]
  772. if exposed is None:
  773. conn = _Client(token.address, authkey=authkey)
  774. try:
  775. exposed = dispatch(conn, None, 'get_methods', (token,))
  776. finally:
  777. conn.close()
  778. if authkey is None and manager is not None:
  779. authkey = manager._authkey
  780. if authkey is None:
  781. authkey = current_process().authkey
  782. ProxyType = MakeProxyType('AutoProxy[%s]' % token.typeid, exposed)
  783. proxy = ProxyType(token, serializer, manager=manager, authkey=authkey,
  784. incref=incref)
  785. proxy._isauto = True
  786. return proxy
  787. #
  788. # Types/callables which we will register with SyncManager
  789. #
  790. class Namespace(object):
  791. def __init__(self, **kwds):
  792. self.__dict__.update(kwds)
  793. def __repr__(self):
  794. items = list(self.__dict__.items())
  795. temp = []
  796. for name, value in items:
  797. if not name.startswith('_'):
  798. temp.append('%s=%r' % (name, value))
  799. temp.sort()
  800. return 'Namespace(%s)' % str.join(', ', temp)
  801. class Value(object):
  802. def __init__(self, typecode, value, lock=True):
  803. self._typecode = typecode
  804. self._value = value
  805. def get(self):
  806. return self._value
  807. def set(self, value):
  808. self._value = value
  809. def __repr__(self):
  810. return '%s(%r, %r)'%(type(self).__name__, self._typecode, self._value)
  811. value = property(get, set)
  812. def Array(typecode, sequence, lock=True):
  813. return array.array(typecode, sequence)
  814. #
  815. # Proxy types used by SyncManager
  816. #
  817. class IteratorProxy(BaseProxy):
  818. _exposed_ = ('__next__', 'send', 'throw', 'close')
  819. def __iter__(self):
  820. return self
  821. def __next__(self, *args):
  822. return self._callmethod('__next__', args)
  823. def send(self, *args):
  824. return self._callmethod('send', args)
  825. def throw(self, *args):
  826. return self._callmethod('throw', args)
  827. def close(self, *args):
  828. return self._callmethod('close', args)
  829. class AcquirerProxy(BaseProxy):
  830. _exposed_ = ('acquire', 'release')
  831. def acquire(self, blocking=True):
  832. return self._callmethod('acquire', (blocking,))
  833. def release(self):
  834. return self._callmethod('release')
  835. def __enter__(self):
  836. return self._callmethod('acquire')
  837. def __exit__(self, exc_type, exc_val, exc_tb):
  838. return self._callmethod('release')
  839. class ConditionProxy(AcquirerProxy):
  840. _exposed_ = ('acquire', 'release', 'wait', 'notify', 'notify_all')
  841. def wait(self, timeout=None):
  842. return self._callmethod('wait', (timeout,))
  843. def notify(self):
  844. return self._callmethod('notify')
  845. def notify_all(self):
  846. return self._callmethod('notify_all')
  847. class EventProxy(BaseProxy):
  848. _exposed_ = ('is_set', 'set', 'clear', 'wait')
  849. def is_set(self):
  850. return self._callmethod('is_set')
  851. def set(self):
  852. return self._callmethod('set')
  853. def clear(self):
  854. return self._callmethod('clear')
  855. def wait(self, timeout=None):
  856. return self._callmethod('wait', (timeout,))
  857. class NamespaceProxy(BaseProxy):
  858. _exposed_ = ('__getattribute__', '__setattr__', '__delattr__')
  859. def __getattr__(self, key):
  860. if key[0] == '_':
  861. return object.__getattribute__(self, key)
  862. callmethod = object.__getattribute__(self, '_callmethod')
  863. return callmethod('__getattribute__', (key,))
  864. def __setattr__(self, key, value):
  865. if key[0] == '_':
  866. return object.__setattr__(self, key, value)
  867. callmethod = object.__getattribute__(self, '_callmethod')
  868. return callmethod('__setattr__', (key, value))
  869. def __delattr__(self, key):
  870. if key[0] == '_':
  871. return object.__delattr__(self, key)
  872. callmethod = object.__getattribute__(self, '_callmethod')
  873. return callmethod('__delattr__', (key,))
  874. class ValueProxy(BaseProxy):
  875. _exposed_ = ('get', 'set')
  876. def get(self):
  877. return self._callmethod('get')
  878. def set(self, value):
  879. return self._callmethod('set', (value,))
  880. value = property(get, set)
  881. BaseListProxy = MakeProxyType('BaseListProxy', (
  882. '__add__', '__contains__', '__delitem__', '__delslice__',
  883. '__getitem__', '__getslice__', '__len__', '__mul__',
  884. '__reversed__', '__rmul__', '__setitem__', '__setslice__',
  885. 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove',
  886. 'reverse', 'sort', '__imul__'
  887. )) # XXX __getslice__ and __setslice__ unneeded in Py3.0
  888. class ListProxy(BaseListProxy):
  889. def __iadd__(self, value):
  890. self._callmethod('extend', (value,))
  891. return self
  892. def __imul__(self, value):
  893. self._callmethod('__imul__', (value,))
  894. return self
  895. DictProxy = MakeProxyType('DictProxy', (
  896. '__contains__', '__delitem__', '__getitem__', '__len__',
  897. '__setitem__', 'clear', 'copy', 'get', 'has_key', 'items',
  898. 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values'
  899. ))
  900. ArrayProxy = MakeProxyType('ArrayProxy', (
  901. '__len__', '__getitem__', '__setitem__', '__getslice__', '__setslice__'
  902. )) # XXX __getslice__ and __setslice__ unneeded in Py3.0
  903. PoolProxy = MakeProxyType('PoolProxy', (
  904. 'apply', 'apply_async', 'close', 'imap', 'imap_unordered', 'join',
  905. 'map', 'map_async', 'starmap', 'starmap_async', 'terminate'
  906. ))
  907. PoolProxy._method_to_typeid_ = {
  908. 'apply_async': 'AsyncResult',
  909. 'map_async': 'AsyncResult',
  910. 'starmap_async': 'AsyncResult',
  911. 'imap': 'Iterator',
  912. 'imap_unordered': 'Iterator'
  913. }
  914. #
  915. # Definition of SyncManager
  916. #
  917. class SyncManager(BaseManager):
  918. '''
  919. Subclass of `BaseManager` which supports a number of shared object types.
  920. The types registered are those intended for the synchronization
  921. of threads, plus `dict`, `list` and `Namespace`.
  922. The `multiprocessing.Manager()` function creates started instances of
  923. this class.
  924. '''
  925. SyncManager.register('Queue', queue.Queue)
  926. SyncManager.register('JoinableQueue', queue.Queue)
  927. SyncManager.register('Event', threading.Event, EventProxy)
  928. SyncManager.register('Lock', threading.Lock, AcquirerProxy)
  929. SyncManager.register('RLock', threading.RLock, AcquirerProxy)
  930. SyncManager.register('Semaphore', threading.Semaphore, AcquirerProxy)
  931. SyncManager.register('BoundedSemaphore', threading.BoundedSemaphore,
  932. AcquirerProxy)
  933. SyncManager.register('Condition', threading.Condition, ConditionProxy)
  934. SyncManager.register('Pool', Pool, PoolProxy)
  935. SyncManager.register('list', list, ListProxy)
  936. SyncManager.register('dict', dict, DictProxy)
  937. SyncManager.register('Value', Value, ValueProxy)
  938. SyncManager.register('Array', Array, ArrayProxy)
  939. SyncManager.register('Namespace', Namespace, NamespaceProxy)
  940. # types returned by methods of PoolProxy
  941. SyncManager.register('Iterator', proxytype=IteratorProxy, create_method=False)
  942. SyncManager.register('AsyncResult', create_method=False)