Pyro5 5.15__tar.gz → 5.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. {Pyro5-5.15 → pyro5-5.17}/PKG-INFO +11 -7
  2. {Pyro5-5.15 → pyro5-5.17}/Pyro5/__init__.py +1 -1
  3. {Pyro5-5.15 → pyro5-5.17}/Pyro5/client.py +14 -7
  4. {Pyro5-5.15 → pyro5-5.17}/Pyro5/configure.py +2 -0
  5. {Pyro5-5.15 → pyro5-5.17}/Pyro5/core.py +38 -26
  6. {Pyro5-5.15 → pyro5-5.17}/Pyro5/errors.py +1 -1
  7. {Pyro5-5.15 → pyro5-5.17}/Pyro5/nameserver.py +23 -18
  8. {Pyro5-5.15 → pyro5-5.17}/Pyro5/protocol.py +9 -6
  9. {Pyro5-5.15 → pyro5-5.17}/Pyro5/serializers.py +2 -2
  10. {Pyro5-5.15 → pyro5-5.17}/Pyro5/server.py +35 -21
  11. {Pyro5-5.15 → pyro5-5.17}/Pyro5/socketutil.py +10 -4
  12. {Pyro5-5.15 → pyro5-5.17}/Pyro5/svr_existingconn.py +2 -2
  13. {Pyro5-5.15 → pyro5-5.17}/Pyro5/svr_multiplex.py +2 -2
  14. {Pyro5-5.15 → pyro5-5.17}/Pyro5/svr_threads.py +7 -9
  15. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/PKG-INFO +11 -7
  16. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/SOURCES.txt +0 -46
  17. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/entry_points.txt +0 -1
  18. {Pyro5-5.15 → pyro5-5.17}/Readme.rst +7 -1
  19. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing3/Readme.txt +1 -1
  20. {Pyro5-5.15 → pyro5-5.17}/examples/exceptions/Readme.txt +1 -1
  21. {Pyro5-5.15 → pyro5-5.17}/examples/streaming/client.py +4 -0
  22. {Pyro5-5.15 → pyro5-5.17}/examples/streaming/server.py +8 -0
  23. {Pyro5-5.15 → pyro5-5.17}/setup.cfg +0 -1
  24. {Pyro5-5.15 → pyro5-5.17}/tests/test_core.py +15 -0
  25. {Pyro5-5.15 → pyro5-5.17}/tests/test_daemon.py +144 -3
  26. {Pyro5-5.15 → pyro5-5.17}/tests/test_naming.py +31 -0
  27. {Pyro5-5.15 → pyro5-5.17}/tests/test_serialize.py +51 -0
  28. {Pyro5-5.15 → pyro5-5.17}/tests/test_server.py +10 -2
  29. {Pyro5-5.15 → pyro5-5.17}/tests/test_socketutil.py +9 -4
  30. Pyro5-5.15/.gitattributes +0 -7
  31. Pyro5-5.15/.github/workflows/main-ci.yml +0 -40
  32. Pyro5-5.15/Makefile +0 -42
  33. Pyro5-5.15/docs/Makefile +0 -130
  34. Pyro5-5.15/docs/make.bat +0 -170
  35. Pyro5-5.15/docs/source/_static/css/customize.css +0 -14
  36. Pyro5-5.15/docs/source/_static/flammable.png +0 -0
  37. Pyro5-5.15/docs/source/_static/pyro-large.png +0 -0
  38. Pyro5-5.15/docs/source/_static/pyro.png +0 -0
  39. Pyro5-5.15/docs/source/_static/tf_pyrotaunt.png +0 -0
  40. Pyro5-5.15/docs/source/api/api.rst +0 -6
  41. Pyro5-5.15/docs/source/api/callcontext.rst +0 -5
  42. Pyro5-5.15/docs/source/api/client.rst +0 -5
  43. Pyro5-5.15/docs/source/api/compatibility.rst +0 -5
  44. Pyro5-5.15/docs/source/api/config.rst +0 -14
  45. Pyro5-5.15/docs/source/api/core.rst +0 -5
  46. Pyro5-5.15/docs/source/api/echoserver.rst +0 -5
  47. Pyro5-5.15/docs/source/api/errors.rst +0 -24
  48. Pyro5-5.15/docs/source/api/httpgateway.rst +0 -5
  49. Pyro5-5.15/docs/source/api/nameserver.rst +0 -9
  50. Pyro5-5.15/docs/source/api/protocol.rst +0 -13
  51. Pyro5-5.15/docs/source/api/server.rst +0 -6
  52. Pyro5-5.15/docs/source/api/socketserver.rst +0 -60
  53. Pyro5-5.15/docs/source/api/socketutil.rst +0 -5
  54. Pyro5-5.15/docs/source/api.rst +0 -24
  55. Pyro5-5.15/docs/source/changelog.rst +0 -158
  56. Pyro5-5.15/docs/source/clientcode.rst +0 -531
  57. Pyro5-5.15/docs/source/commandline.rst +0 -77
  58. Pyro5-5.15/docs/source/conf.py +0 -236
  59. Pyro5-5.15/docs/source/config.rst +0 -140
  60. Pyro5-5.15/docs/source/docutils.conf +0 -2
  61. Pyro5-5.15/docs/source/errors.rst +0 -138
  62. Pyro5-5.15/docs/source/index.rst +0 -61
  63. Pyro5-5.15/docs/source/install.rst +0 -64
  64. Pyro5-5.15/docs/source/intro.rst +0 -310
  65. Pyro5-5.15/docs/source/license.rst +0 -37
  66. Pyro5-5.15/docs/source/nameserver.rst +0 -629
  67. Pyro5-5.15/docs/source/pyrolite.rst +0 -15
  68. Pyro5-5.15/docs/source/security.rst +0 -126
  69. Pyro5-5.15/docs/source/servercode.rst +0 -821
  70. Pyro5-5.15/docs/source/tipstricks.rst +0 -733
  71. Pyro5-5.15/docs/source/tutorials.rst +0 -198
  72. Pyro5-5.15/mypy.ini +0 -10
  73. Pyro5-5.15/requirements.txt +0 -1
  74. Pyro5-5.15/test-requirements.txt +0 -3
  75. Pyro5-5.15/tox.ini +0 -14
  76. {Pyro5-5.15 → pyro5-5.17}/LICENSE +0 -0
  77. {Pyro5-5.15 → pyro5-5.17}/MANIFEST.in +0 -0
  78. {Pyro5-5.15 → pyro5-5.17}/Pyro5/api.py +0 -0
  79. {Pyro5-5.15 → pyro5-5.17}/Pyro5/callcontext.py +0 -0
  80. {Pyro5-5.15 → pyro5-5.17}/Pyro5/compatibility/Pyro4.py +0 -0
  81. {Pyro5-5.15 → pyro5-5.17}/Pyro5/compatibility/__init__.py +0 -0
  82. {Pyro5-5.15 → pyro5-5.17}/Pyro5/nsc.py +0 -0
  83. {Pyro5-5.15 → pyro5-5.17}/Pyro5/utils/__init__.py +0 -0
  84. {Pyro5-5.15 → pyro5-5.17}/Pyro5/utils/echoserver.py +0 -0
  85. {Pyro5-5.15 → pyro5-5.17}/Pyro5/utils/httpgateway.py +0 -0
  86. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/dependency_links.txt +0 -0
  87. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/requires.txt +0 -0
  88. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/top_level.txt +0 -0
  89. {Pyro5-5.15 → pyro5-5.17}/Pyro5.egg-info/zip-safe +0 -0
  90. {Pyro5-5.15 → pyro5-5.17}/certs/client_cert.pem +0 -0
  91. {Pyro5-5.15 → pyro5-5.17}/certs/client_key.pem +0 -0
  92. {Pyro5-5.15 → pyro5-5.17}/certs/readme.txt +0 -0
  93. {Pyro5-5.15 → pyro5-5.17}/certs/server_cert.pem +0 -0
  94. {Pyro5-5.15 → pyro5-5.17}/certs/server_key.pem +0 -0
  95. {Pyro5-5.15 → pyro5-5.17}/examples/attributes/Readme.txt +0 -0
  96. {Pyro5-5.15 → pyro5-5.17}/examples/attributes/client.py +0 -0
  97. {Pyro5-5.15 → pyro5-5.17}/examples/attributes/server.py +0 -0
  98. {Pyro5-5.15 → pyro5-5.17}/examples/autoproxy/Readme.txt +0 -0
  99. {Pyro5-5.15 → pyro5-5.17}/examples/autoproxy/client.py +0 -0
  100. {Pyro5-5.15 → pyro5-5.17}/examples/autoproxy/server.py +0 -0
  101. {Pyro5-5.15 → pyro5-5.17}/examples/autoproxy/thingy.py +0 -0
  102. {Pyro5-5.15 → pyro5-5.17}/examples/autoreconnect/Readme.txt +0 -0
  103. {Pyro5-5.15 → pyro5-5.17}/examples/autoreconnect/client.py +0 -0
  104. {Pyro5-5.15 → pyro5-5.17}/examples/autoreconnect/clientNS.py +0 -0
  105. {Pyro5-5.15 → pyro5-5.17}/examples/autoreconnect/server.py +0 -0
  106. {Pyro5-5.15 → pyro5-5.17}/examples/autoreconnect/serverNS.py +0 -0
  107. {Pyro5-5.15 → pyro5-5.17}/examples/autoretry/Readme.txt +0 -0
  108. {Pyro5-5.15 → pyro5-5.17}/examples/autoretry/client.py +0 -0
  109. {Pyro5-5.15 → pyro5-5.17}/examples/autoretry/server.py +0 -0
  110. {Pyro5-5.15 → pyro5-5.17}/examples/banks/Readme.txt +0 -0
  111. {Pyro5-5.15 → pyro5-5.17}/examples/banks/banks.py +0 -0
  112. {Pyro5-5.15 → pyro5-5.17}/examples/banks/client.py +0 -0
  113. {Pyro5-5.15 → pyro5-5.17}/examples/banks/server.py +0 -0
  114. {Pyro5-5.15 → pyro5-5.17}/examples/batchedcalls/Readme.txt +0 -0
  115. {Pyro5-5.15 → pyro5-5.17}/examples/batchedcalls/client.py +0 -0
  116. {Pyro5-5.15 → pyro5-5.17}/examples/batchedcalls/server.py +0 -0
  117. {Pyro5-5.15 → pyro5-5.17}/examples/benchmark/Readme.txt +0 -0
  118. {Pyro5-5.15 → pyro5-5.17}/examples/benchmark/bench.py +0 -0
  119. {Pyro5-5.15 → pyro5-5.17}/examples/benchmark/client.py +0 -0
  120. {Pyro5-5.15 → pyro5-5.17}/examples/benchmark/connections.py +0 -0
  121. {Pyro5-5.15 → pyro5-5.17}/examples/benchmark/server.py +0 -0
  122. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/Readme.txt +0 -0
  123. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/client/client.py +0 -0
  124. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/client/customdata.py +0 -0
  125. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/dispatcher/dispatcher.py +0 -0
  126. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/listeners/customdata.py +0 -0
  127. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/listeners/listener.py +0 -0
  128. {Pyro5-5.15 → pyro5-5.17}/examples/blob-dispatch/listeners/main.py +0 -0
  129. {Pyro5-5.15 → pyro5-5.17}/examples/callback/Readme.txt +0 -0
  130. {Pyro5-5.15 → pyro5-5.17}/examples/callback/client.py +0 -0
  131. {Pyro5-5.15 → pyro5-5.17}/examples/callback/client2.py +0 -0
  132. {Pyro5-5.15 → pyro5-5.17}/examples/callback/server.py +0 -0
  133. {Pyro5-5.15 → pyro5-5.17}/examples/callback/server2.py +0 -0
  134. {Pyro5-5.15 → pyro5-5.17}/examples/callcontext/Readme.txt +0 -0
  135. {Pyro5-5.15 → pyro5-5.17}/examples/callcontext/client.py +0 -0
  136. {Pyro5-5.15 → pyro5-5.17}/examples/callcontext/server.py +0 -0
  137. {Pyro5-5.15 → pyro5-5.17}/examples/chatbox/Readme.txt +0 -0
  138. {Pyro5-5.15 → pyro5-5.17}/examples/chatbox/client.py +0 -0
  139. {Pyro5-5.15 → pyro5-5.17}/examples/chatbox/server.py +0 -0
  140. {Pyro5-5.15 → pyro5-5.17}/examples/circular/Readme.txt +0 -0
  141. {Pyro5-5.15 → pyro5-5.17}/examples/circular/chain.py +0 -0
  142. {Pyro5-5.15 → pyro5-5.17}/examples/circular/client.py +0 -0
  143. {Pyro5-5.15 → pyro5-5.17}/examples/circular/servA.py +0 -0
  144. {Pyro5-5.15 → pyro5-5.17}/examples/circular/servB.py +0 -0
  145. {Pyro5-5.15 → pyro5-5.17}/examples/circular/servC.py +0 -0
  146. {Pyro5-5.15 → pyro5-5.17}/examples/custom-serialization/Readme.txt +0 -0
  147. {Pyro5-5.15 → pyro5-5.17}/examples/custom-serialization/client.py +0 -0
  148. {Pyro5-5.15 → pyro5-5.17}/examples/custom-serialization/mycustomclasses.py +0 -0
  149. {Pyro5-5.15 → pyro5-5.17}/examples/custom-serialization/server.py +0 -0
  150. {Pyro5-5.15 → pyro5-5.17}/examples/diffie-hellman/Readme.txt +0 -0
  151. {Pyro5-5.15 → pyro5-5.17}/examples/diffie-hellman/client.py +0 -0
  152. {Pyro5-5.15 → pyro5-5.17}/examples/diffie-hellman/diffiehellman.py +0 -0
  153. {Pyro5-5.15 → pyro5-5.17}/examples/diffie-hellman/server.py +0 -0
  154. {Pyro5-5.15 → pyro5-5.17}/examples/disconnects/Readme.txt +0 -0
  155. {Pyro5-5.15 → pyro5-5.17}/examples/disconnects/client.py +0 -0
  156. {Pyro5-5.15 → pyro5-5.17}/examples/disconnects/server.py +0 -0
  157. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing/Readme.txt +0 -0
  158. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing/client.py +0 -0
  159. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing/dispatcher.py +0 -0
  160. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing/worker.py +0 -0
  161. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing/workitem.py +0 -0
  162. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing2/Readme.txt +0 -0
  163. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing2/alice.zip +0 -0
  164. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing2/client.py +0 -0
  165. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing2/servers.py +0 -0
  166. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing3/client.py +0 -0
  167. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-computing3/worker.py +0 -0
  168. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/Readme.txt +0 -0
  169. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/client_asciizoom.py +0 -0
  170. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/client_graphics.py +0 -0
  171. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/launch_servers.sh +0 -0
  172. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/normal.py +0 -0
  173. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/normal_graphics.py +0 -0
  174. {Pyro5-5.15 → pyro5-5.17}/examples/distributed-mandelbrot/server.py +0 -0
  175. {Pyro5-5.15 → pyro5-5.17}/examples/echoserver/Readme.txt +0 -0
  176. {Pyro5-5.15 → pyro5-5.17}/examples/echoserver/client.py +0 -0
  177. {Pyro5-5.15 → pyro5-5.17}/examples/eventloop/Readme.txt +0 -0
  178. {Pyro5-5.15 → pyro5-5.17}/examples/eventloop/client.py +0 -0
  179. {Pyro5-5.15 → pyro5-5.17}/examples/eventloop/server_multiplexed.py +0 -0
  180. {Pyro5-5.15 → pyro5-5.17}/examples/eventloop/server_threads.py +0 -0
  181. {Pyro5-5.15 → pyro5-5.17}/examples/exceptions/client.py +0 -0
  182. {Pyro5-5.15 → pyro5-5.17}/examples/exceptions/excep.py +0 -0
  183. {Pyro5-5.15 → pyro5-5.17}/examples/exceptions/server.py +0 -0
  184. {Pyro5-5.15 → pyro5-5.17}/examples/filetransfer/Readme.txt +0 -0
  185. {Pyro5-5.15 → pyro5-5.17}/examples/filetransfer/client.py +0 -0
  186. {Pyro5-5.15 → pyro5-5.17}/examples/filetransfer/server.py +0 -0
  187. {Pyro5-5.15 → pyro5-5.17}/examples/gui_eventloop/Readme.txt +0 -0
  188. {Pyro5-5.15 → pyro5-5.17}/examples/gui_eventloop/client.py +0 -0
  189. {Pyro5-5.15 → pyro5-5.17}/examples/gui_eventloop/gui_nothreads.py +0 -0
  190. {Pyro5-5.15 → pyro5-5.17}/examples/gui_eventloop/gui_threads.py +0 -0
  191. {Pyro5-5.15 → pyro5-5.17}/examples/handshake/Readme.txt +0 -0
  192. {Pyro5-5.15 → pyro5-5.17}/examples/handshake/client.py +0 -0
  193. {Pyro5-5.15 → pyro5-5.17}/examples/handshake/server.py +0 -0
  194. {Pyro5-5.15 → pyro5-5.17}/examples/http/Readme.txt +0 -0
  195. {Pyro5-5.15 → pyro5-5.17}/examples/http/client.js +0 -0
  196. {Pyro5-5.15 → pyro5-5.17}/examples/http/client.py +0 -0
  197. {Pyro5-5.15 → pyro5-5.17}/examples/hugetransfer/Readme.txt +0 -0
  198. {Pyro5-5.15 → pyro5-5.17}/examples/hugetransfer/client.py +0 -0
  199. {Pyro5-5.15 → pyro5-5.17}/examples/hugetransfer/server.py +0 -0
  200. {Pyro5-5.15 → pyro5-5.17}/examples/instancemode/Readme.txt +0 -0
  201. {Pyro5-5.15 → pyro5-5.17}/examples/instancemode/client.py +0 -0
  202. {Pyro5-5.15 → pyro5-5.17}/examples/instancemode/server.py +0 -0
  203. {Pyro5-5.15 → pyro5-5.17}/examples/maxsize/Readme.txt +0 -0
  204. {Pyro5-5.15 → pyro5-5.17}/examples/maxsize/client.py +0 -0
  205. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/Readme.txt +0 -0
  206. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/manytopics_publisher.py +0 -0
  207. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/manytopics_subscriber.py +0 -0
  208. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/messagebus/__init__.py +0 -0
  209. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/messagebus/messagebus.py +0 -0
  210. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/messagebus/server.py +0 -0
  211. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/publisher.py +0 -0
  212. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/subscriber.py +0 -0
  213. {Pyro5-5.15 → pyro5-5.17}/examples/messagebus/subscriber_manual_consume.py +0 -0
  214. {Pyro5-5.15 → pyro5-5.17}/examples/nameserverstress/Readme.txt +0 -0
  215. {Pyro5-5.15 → pyro5-5.17}/examples/nameserverstress/stress.py +0 -0
  216. {Pyro5-5.15 → pyro5-5.17}/examples/nonameserver/Readme.txt +0 -0
  217. {Pyro5-5.15 → pyro5-5.17}/examples/nonameserver/client.py +0 -0
  218. {Pyro5-5.15 → pyro5-5.17}/examples/nonameserver/server.py +0 -0
  219. {Pyro5-5.15 → pyro5-5.17}/examples/ns-metadata/Readme.txt +0 -0
  220. {Pyro5-5.15 → pyro5-5.17}/examples/ns-metadata/example.py +0 -0
  221. {Pyro5-5.15 → pyro5-5.17}/examples/ns-metadata/resources.py +0 -0
  222. {Pyro5-5.15 → pyro5-5.17}/examples/oneway/Readme.txt +0 -0
  223. {Pyro5-5.15 → pyro5-5.17}/examples/oneway/client.py +0 -0
  224. {Pyro5-5.15 → pyro5-5.17}/examples/oneway/client2.py +0 -0
  225. {Pyro5-5.15 → pyro5-5.17}/examples/oneway/server.py +0 -0
  226. {Pyro5-5.15 → pyro5-5.17}/examples/oneway/server2.py +0 -0
  227. {Pyro5-5.15 → pyro5-5.17}/examples/privilege-separation/Readme.txt +0 -0
  228. {Pyro5-5.15 → pyro5-5.17}/examples/privilege-separation/drop_privs_client.py +0 -0
  229. {Pyro5-5.15 → pyro5-5.17}/examples/privilege-separation/drop_privs_server.py +0 -0
  230. {Pyro5-5.15 → pyro5-5.17}/examples/privilege-separation/elevated_client.py +0 -0
  231. {Pyro5-5.15 → pyro5-5.17}/examples/privilege-separation/elevated_server.py +0 -0
  232. {Pyro5-5.15 → pyro5-5.17}/examples/resourcetracking/Readme.txt +0 -0
  233. {Pyro5-5.15 → pyro5-5.17}/examples/resourcetracking/client.py +0 -0
  234. {Pyro5-5.15 → pyro5-5.17}/examples/resourcetracking/server.py +0 -0
  235. {Pyro5-5.15 → pyro5-5.17}/examples/robots/Readme.txt +0 -0
  236. {Pyro5-5.15 → pyro5-5.17}/examples/robots/client.py +0 -0
  237. {Pyro5-5.15 → pyro5-5.17}/examples/robots/gameserver.py +0 -0
  238. {Pyro5-5.15 → pyro5-5.17}/examples/robots/remote.py +0 -0
  239. {Pyro5-5.15 → pyro5-5.17}/examples/robots/robot.py +0 -0
  240. {Pyro5-5.15 → pyro5-5.17}/examples/servertypes/Readme.txt +0 -0
  241. {Pyro5-5.15 → pyro5-5.17}/examples/servertypes/client.py +0 -0
  242. {Pyro5-5.15 → pyro5-5.17}/examples/servertypes/server.py +0 -0
  243. {Pyro5-5.15 → pyro5-5.17}/examples/shoppingcart/Readme.txt +0 -0
  244. {Pyro5-5.15 → pyro5-5.17}/examples/shoppingcart/clients.py +0 -0
  245. {Pyro5-5.15 → pyro5-5.17}/examples/shoppingcart/shoppingcart.py +0 -0
  246. {Pyro5-5.15 → pyro5-5.17}/examples/shoppingcart/shopserver.py +0 -0
  247. {Pyro5-5.15 → pyro5-5.17}/examples/socketpair/pair-fork.py +0 -0
  248. {Pyro5-5.15 → pyro5-5.17}/examples/socketpair/pair-thread.py +0 -0
  249. {Pyro5-5.15 → pyro5-5.17}/examples/socketpair/readme.txt +0 -0
  250. {Pyro5-5.15 → pyro5-5.17}/examples/ssl/Readme.txt +0 -0
  251. {Pyro5-5.15 → pyro5-5.17}/examples/ssl/client.py +0 -0
  252. {Pyro5-5.15 → pyro5-5.17}/examples/ssl/server.py +0 -0
  253. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/Readme.txt +0 -0
  254. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase1/stockmarket.py +0 -0
  255. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase1/viewer.py +0 -0
  256. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase2/stockmarket.py +0 -0
  257. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase2/viewer.py +0 -0
  258. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase3/stockmarket.py +0 -0
  259. {Pyro5-5.15 → pyro5-5.17}/examples/stockquotes/phase3/viewer.py +0 -0
  260. {Pyro5-5.15 → pyro5-5.17}/examples/streaming/Readme.txt +0 -0
  261. {Pyro5-5.15 → pyro5-5.17}/examples/thirdpartylib/Readme.txt +0 -0
  262. {Pyro5-5.15 → pyro5-5.17}/examples/thirdpartylib/awesome_thirdparty_library.py +0 -0
  263. {Pyro5-5.15 → pyro5-5.17}/examples/thirdpartylib/client.py +0 -0
  264. {Pyro5-5.15 → pyro5-5.17}/examples/thirdpartylib/server.py +0 -0
  265. {Pyro5-5.15 → pyro5-5.17}/examples/thirdpartylib/server2.py +0 -0
  266. {Pyro5-5.15 → pyro5-5.17}/examples/threadproxysharing/Readme.txt +0 -0
  267. {Pyro5-5.15 → pyro5-5.17}/examples/threadproxysharing/client.py +0 -0
  268. {Pyro5-5.15 → pyro5-5.17}/examples/timeout/Readme.txt +0 -0
  269. {Pyro5-5.15 → pyro5-5.17}/examples/timeout/client.py +0 -0
  270. {Pyro5-5.15 → pyro5-5.17}/examples/timeout/server.py +0 -0
  271. {Pyro5-5.15 → pyro5-5.17}/examples/timezones/Readme.txt +0 -0
  272. {Pyro5-5.15 → pyro5-5.17}/examples/timezones/client.py +0 -0
  273. {Pyro5-5.15 → pyro5-5.17}/examples/timezones/server.py +0 -0
  274. {Pyro5-5.15 → pyro5-5.17}/examples/unixdomainsock/Readme.txt +0 -0
  275. {Pyro5-5.15 → pyro5-5.17}/examples/unixdomainsock/abstract_namespace_server.py +0 -0
  276. {Pyro5-5.15 → pyro5-5.17}/examples/unixdomainsock/client.py +0 -0
  277. {Pyro5-5.15 → pyro5-5.17}/examples/unixdomainsock/server.py +0 -0
  278. {Pyro5-5.15 → pyro5-5.17}/examples/usersession/Readme.txt +0 -0
  279. {Pyro5-5.15 → pyro5-5.17}/examples/usersession/client.py +0 -0
  280. {Pyro5-5.15 → pyro5-5.17}/examples/usersession/database.py +0 -0
  281. {Pyro5-5.15 → pyro5-5.17}/examples/usersession/server.py +0 -0
  282. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/Readme.txt +0 -0
  283. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase1/person.py +0 -0
  284. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase1/visit.py +0 -0
  285. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase1/warehouse.py +0 -0
  286. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase2/person.py +0 -0
  287. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase2/visit.py +0 -0
  288. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase2/warehouse.py +0 -0
  289. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase3/person.py +0 -0
  290. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase3/visit.py +0 -0
  291. {Pyro5-5.15 → pyro5-5.17}/examples/warehouse/phase3/warehouse.py +0 -0
  292. {Pyro5-5.15 → pyro5-5.17}/setup.py +0 -0
  293. {Pyro5-5.15 → pyro5-5.17}/tests/support.py +0 -0
  294. {Pyro5-5.15 → pyro5-5.17}/tests/test_api.py +0 -0
  295. {Pyro5-5.15 → pyro5-5.17}/tests/test_client.py +0 -0
  296. {Pyro5-5.15 → pyro5-5.17}/tests/test_echoserver.py +0 -0
  297. {Pyro5-5.15 → pyro5-5.17}/tests/test_errors.py +0 -0
  298. {Pyro5-5.15 → pyro5-5.17}/tests/test_httpgateway.py +0 -0
  299. {Pyro5-5.15 → pyro5-5.17}/tests/test_protocol.py +0 -0
  300. {Pyro5-5.15 → pyro5-5.17}/tests/test_pyro4compat.py +0 -0
  301. {Pyro5-5.15 → pyro5-5.17}/tests/test_server_timeout.py +0 -0
  302. {Pyro5-5.15 → pyro5-5.17}/tests/test_threadpool.py +0 -0
@@ -1,16 +1,14 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: Pyro5
3
- Version: 5.15
3
+ Version: 5.17
4
4
  Summary: Remote object communication library, fifth major version
5
5
  Home-page: https://github.com/irmen/Pyro5
6
6
  Author: Irmen de Jong
7
7
  Author-email: irmen@razorvine.net
8
8
  License: MIT
9
9
  Keywords: distributed objects,RPC,remote method call,IPC
10
- Platform: UNKNOWN
11
10
  Classifier: Development Status :: 5 - Production/Stable
12
11
  Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
12
  Classifier: Natural Language :: English
15
13
  Classifier: Natural Language :: Dutch
16
14
  Classifier: Operating System :: OS Independent
@@ -22,6 +20,8 @@ Classifier: Topic :: System :: Networking
22
20
  Requires-Python: >=3.7
23
21
  Description-Content-Type: text/x-rst
24
22
  License-File: LICENSE
23
+ Requires-Dist: serpent>=1.41
24
+ Dynamic: license-file
25
25
 
26
26
  Pyro5
27
27
  =====
@@ -34,6 +34,8 @@ Pyro5
34
34
  .. image:: https://anaconda.org/conda-forge/pyro5/badges/version.svg
35
35
  :target: https://anaconda.org/conda-forge/pyro5
36
36
 
37
+ **Project status: super low maintenance mode. Not really worked on anymore, only reported bugs will be looked at.**
38
+
37
39
 
38
40
  Info
39
41
  ----
@@ -60,7 +62,7 @@ New code should use Pyro5 if at all possible.
60
62
  Features
61
63
  --------
62
64
 
63
- - written in 100% Python so extremely portable, supported on Python 3.8 and newer, and Pypy3
65
+ - written in 100% Python so extremely portable, supported on CPython 3 and Pypy 3
64
66
  - works between different system architectures and operating systems.
65
67
  - able to communicate between different Python versions transparently.
66
68
  - defaults to a safe serializer (`serpent <https://pypi.python.org/pypi/serpent>`_) that supports many Python data types.
@@ -79,6 +81,10 @@ Features
79
81
  - you can define timeouts on network communications to prevent a call blocking forever if there's something wrong.
80
82
  - remote exceptions will be raised in the caller, as if they were local. You can extract detailed remote traceback information.
81
83
  - http gateway available for clients wanting to use http+json (such as browser scripts).
84
+ - custom handshake data can be exchanged during connection setup.
85
+ - message annotations support attaching custom metadata to every call.
86
+ - correlation ids on every call for end-to-end request tracing.
87
+ - SerializedBlob for efficient transfer of large serialized data blobs.
82
88
  - stable network communication code that has worked reliably on many platforms for over a decade.
83
89
  - can hook onto existing sockets created for instance with socketpair() to communicate efficiently between threads or sub-processes.
84
90
  - possibility to integrate Pyro's event loop into your own (or third party) event loop.
@@ -87,5 +93,3 @@ Features
87
93
  - large amount of unit tests and high test coverage.
88
94
  - reliable and established: built upon more than 20 years of existing Pyro history, with ongoing support and development.
89
95
 
90
-
91
-
@@ -4,7 +4,7 @@ Pyro package. Some generic init stuff to set up logging etc.
4
4
  Pyro - Python Remote Objects. Copyright by Irmen de Jong (irmen@razorvine.net).
5
5
  """
6
6
 
7
- __version__ = "5.15"
7
+ __version__ = "5.17"
8
8
  __author__ = "Irmen de Jong"
9
9
 
10
10
 
@@ -88,7 +88,7 @@ class Proxy(object):
88
88
  def __del__(self):
89
89
  if hasattr(self, "_pyroConnection"):
90
90
  try:
91
- self._pyroRelease()
91
+ self._pyroConnection.close()
92
92
  except Exception:
93
93
  pass
94
94
 
@@ -272,7 +272,10 @@ class Proxy(object):
272
272
  raise errors.ProtocolError("result of call is an iterator, but the server is not configured to allow streaming")
273
273
  return _StreamResultIterator(streamId, self)
274
274
  if msg.flags & protocol.FLAGS_EXCEPTION:
275
- raise data # if you see this in your traceback, you should probably inspect the remote traceback as well
275
+ try:
276
+ raise data # if you see this in your traceback, you should probably inspect the remote traceback as well
277
+ finally:
278
+ del data
276
279
  else:
277
280
  return data
278
281
  except (errors.CommunicationError, KeyboardInterrupt):
@@ -296,7 +299,8 @@ class Proxy(object):
296
299
  Connects this proxy to the remote Pyro daemon. Does connection handshake.
297
300
  Returns true if a new connection was made, false if an existing one was already present.
298
301
  """
299
- def connect_and_handshake(conn):
302
+ def connect_and_handshake():
303
+ conn = None
300
304
  try:
301
305
  if self._pyroConnection is not None:
302
306
  return False # already connected
@@ -312,7 +316,11 @@ class Proxy(object):
312
316
  timeout=self.__pyroTimeout,
313
317
  nodelay=config.SOCK_NODELAY,
314
318
  sslContext=sslContext)
315
- conn = socketutil.SocketConnection(sock, uri.object)
319
+ try:
320
+ conn = socketutil.SocketConnection(sock, uri.object)
321
+ except Exception:
322
+ sock.close()
323
+ raise
316
324
  # Do handshake.
317
325
  serializer = serializers.serializers[self._pyroSerializer or config.SERIALIZER]
318
326
  data = {"handshake": self._pyroHandshake, "object": uri.object}
@@ -366,14 +374,13 @@ class Proxy(object):
366
374
  return False # already connected
367
375
  uri = core.resolve(self._pyroUri)
368
376
  # socket connection (normal or Unix domain socket)
369
- conn = None
370
377
  log.debug("connecting to %s", uri)
371
378
  connect_location = uri.sockname or (uri.host, uri.port)
372
379
  if connected_socket:
373
380
  self._pyroConnection = socketutil.SocketConnection(connected_socket, uri.object, True)
374
381
  self._pyroLocalSocket = connected_socket.getsockname()
375
382
  else:
376
- connect_and_handshake(conn)
383
+ connect_and_handshake()
377
384
  # obtain metadata if this feature is enabled, and the metadata is not known yet
378
385
  if not self._pyroMethods and not self._pyroAttrs:
379
386
  self._pyroGetMetadata(uri.object)
@@ -413,7 +420,7 @@ class Proxy(object):
413
420
  log.debug("from meta: methods=%s, oneway methods=%s, attributes=%s",
414
421
  sorted(self._pyroMethods), sorted(self._pyroOneway), sorted(self._pyroAttrs))
415
422
  if not self._pyroMethods and not self._pyroAttrs:
416
- raise errors.PyroError("remote object doesn't expose any methods or attributes. Did you forget setting @expose on them?")
423
+ raise errors.PyroError("remote object '%s' doesn't expose any methods or attributes. Did you forget setting @expose on them?" % self._pyroUri)
417
424
 
418
425
  def _pyroReconnect(self, tries=100000000):
419
426
  """
@@ -93,6 +93,8 @@ class Configuration:
93
93
  envvalue = True
94
94
  else:
95
95
  raise ValueError("invalid boolean value: %s%s=%s" % (prefix, item, envvalue))
96
+ elif valuetype is type(None):
97
+ envvalue = str(envvalue)
96
98
  else:
97
99
  try:
98
100
  envvalue = valuetype(envvalue)
@@ -10,6 +10,7 @@ import contextlib
10
10
  import ipaddress
11
11
  import socket
12
12
  import random
13
+ import platform
13
14
  import serpent
14
15
  from typing import Union, Optional
15
16
  from . import config, errors, socketutil, serializers
@@ -152,7 +153,13 @@ class _ExceptionWrapper(object):
152
153
  self.exception = exception
153
154
 
154
155
  def raiseIt(self):
155
- raise self.exception
156
+ try:
157
+ err = self.exception.__class__(*self.exception.args)
158
+ if hasattr(self.exception, '_pyroTraceback'):
159
+ err._pyroTraceback = self.exception._pyroTraceback
160
+ raise err
161
+ finally:
162
+ del err
156
163
 
157
164
  def __serialized_dict__(self):
158
165
  """serialized form as a dictionary"""
@@ -215,11 +222,15 @@ def locate_ns(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] = "
215
222
  else:
216
223
  # Some systems have 127.0.1.1 in the hosts file assigned to the hostname,
217
224
  # so try this too (only if it's actually used as a valid ip address)
218
- try:
219
- socket.gethostbyaddr("127.0.1.1")
220
- hosts = [config.NS_HOST] if config.NS_HOST == "127.0.1.1" else [config.NS_HOST, "127.0.1.1"]
221
- except socket.error:
225
+ # Skip this check on Windows to avoid slow DNS lookup timeout (5+ seconds)
226
+ if platform.system() == "Windows":
222
227
  hosts = [config.NS_HOST]
228
+ else:
229
+ try:
230
+ socket.gethostbyaddr("127.0.1.1")
231
+ hosts = [config.NS_HOST] if config.NS_HOST == "127.0.1.1" else [config.NS_HOST, "127.0.1.1"]
232
+ except socket.error:
233
+ hosts = [config.NS_HOST]
223
234
  for host in hosts:
224
235
  uristring = "PYRO:%s@%s:%d" % (NAMESERVER_NAME, host, port or config.NS_PORT)
225
236
  log.debug("locating the NS: %s", uristring)
@@ -236,27 +247,28 @@ def locate_ns(host: Union[str, ipaddress.IPv4Address, ipaddress.IPv6Address] = "
236
247
  port = config.NS_BCPORT
237
248
  log.debug("broadcast locate")
238
249
  sock = socketutil.create_bc_socket(reuseaddr=config.SOCK_REUSE, timeout=0.7)
239
- for _ in range(3):
240
- try:
241
- for bcaddr in config.BROADCAST_ADDRS:
242
- try:
243
- sock.sendto(b"GET_NSURI", 0, (bcaddr, port))
244
- except socket.error as x:
245
- err = getattr(x, "errno", x.args[0])
246
- # handle some errno's that some platforms like to throw:
247
- if err not in socketutil.ERRNO_EADDRNOTAVAIL and err not in socketutil.ERRNO_EADDRINUSE:
248
- raise
249
- data, _ = sock.recvfrom(100)
250
- sock.close()
251
- text = data.decode("iso-8859-1")
252
- log.debug("located NS: %s", text)
253
- proxy = client.Proxy(text)
254
- return proxy
255
- except socket.timeout:
256
- continue
257
- with contextlib.suppress(OSError, socket.error):
258
- sock.shutdown(socket.SHUT_RDWR)
259
- sock.close()
250
+ try:
251
+ for _ in range(3):
252
+ try:
253
+ for bcaddr in config.BROADCAST_ADDRS:
254
+ try:
255
+ sock.sendto(b"GET_NSURI", 0, (bcaddr, port))
256
+ except socket.error as x:
257
+ err = getattr(x, "errno", x.args[0])
258
+ # handle some errno's that some platforms like to throw:
259
+ if err not in socketutil.ERRNO_EADDRNOTAVAIL and err not in socketutil.ERRNO_EADDRINUSE:
260
+ raise
261
+ data, _ = sock.recvfrom(100)
262
+ text = data.decode("iso-8859-1")
263
+ log.debug("located NS: %s", text)
264
+ proxy = client.Proxy(text)
265
+ return proxy
266
+ except socket.timeout:
267
+ continue
268
+ finally:
269
+ with contextlib.suppress(OSError, socket.error):
270
+ sock.shutdown(socket.SHUT_RDWR)
271
+ sock.close()
260
272
  log.debug("broadcast locate failed, try direct connection on NS_HOST")
261
273
  else:
262
274
  log.debug("skipping broadcast lookup")
@@ -70,7 +70,7 @@ def get_pyro_traceback(ex_type=None, ex_value=None, ex_tb=None):
70
70
  you do not supply the objects yourself."""
71
71
 
72
72
  def formatRemoteTraceback(remote_tb_lines):
73
- result = [" +--- This exception occured remotely (Pyro) - Remote traceback:"]
73
+ result = [" +--- This exception occurred remotely (Pyro) - Remote traceback:"]
74
74
  for line in remote_tb_lines:
75
75
  if line.endswith("\n"):
76
76
  line = line[:-1]
@@ -37,7 +37,7 @@ class MemoryStorage(dict):
37
37
 
38
38
  def __setitem__(self, key, value):
39
39
  uri, metadata = value
40
- super(MemoryStorage, self).__setitem__(key, (uri, metadata or frozenset()))
40
+ super(MemoryStorage, self).__setitem__(key, (uri, metadata if metadata is not None else frozenset()))
41
41
 
42
42
  def optimized_prefix_list(self, prefix, return_metadata=False):
43
43
  return None
@@ -315,7 +315,7 @@ class NameServer(object):
315
315
  with self.lock:
316
316
  if safe and name in self.storage:
317
317
  raise NamingError("name already registered: " + name)
318
- self.storage[name] = uri, set(metadata) if metadata else None
318
+ self.storage[name] = uri, set(metadata) if metadata is not None else None
319
319
 
320
320
  def set_metadata(self, name, metadata):
321
321
  """update the metadata for an existing registration"""
@@ -327,28 +327,32 @@ class NameServer(object):
327
327
  with self.lock:
328
328
  try:
329
329
  uri, old_meta = self.storage[name]
330
- self.storage[name] = uri, set(metadata) if metadata else None
330
+ self.storage[name] = uri, set(metadata) if metadata is not None else None
331
331
  except KeyError:
332
332
  raise NamingError("unknown name: " + name)
333
333
 
334
334
  def remove(self, name=None, prefix=None, regex=None):
335
335
  """Remove a registration. returns the number of items removed."""
336
- if name and name in self.storage and name != core.NAMESERVER_NAME:
336
+ if name and name != core.NAMESERVER_NAME:
337
337
  with self.lock:
338
- del self.storage[name]
339
- return 1
338
+ if name in self.storage:
339
+ del self.storage[name]
340
+ return 1
341
+ return 0
340
342
  if prefix:
341
- items = list(self.list(prefix=prefix).keys())
342
- if core.NAMESERVER_NAME in items:
343
- items.remove(core.NAMESERVER_NAME)
344
- self.storage.remove_items(items)
345
- return len(items)
343
+ with self.lock:
344
+ items = list(self.list(prefix=prefix).keys())
345
+ if core.NAMESERVER_NAME in items:
346
+ items.remove(core.NAMESERVER_NAME)
347
+ self.storage.remove_items(items)
348
+ return len(items)
346
349
  if regex:
347
- items = list(self.list(regex=regex).keys())
348
- if core.NAMESERVER_NAME in items:
349
- items.remove(core.NAMESERVER_NAME)
350
- self.storage.remove_items(items)
351
- return len(items)
350
+ with self.lock:
351
+ items = list(self.list(regex=regex).keys())
352
+ if core.NAMESERVER_NAME in items:
353
+ items.remove(core.NAMESERVER_NAME)
354
+ self.storage.remove_items(items)
355
+ return len(items)
352
356
  return 0
353
357
 
354
358
  # noinspection PyNoneFunctionAssignment
@@ -645,7 +649,8 @@ class BroadcastServer(object):
645
649
 
646
650
 
647
651
  def start_ns_loop(host=None, port=None, enableBroadcast=True, bchost=None, bcport=None,
648
- unixsocket=None, nathost=None, natport=None, storage=None):
652
+ unixsocket=None, nathost=None, natport=None, storage=None,
653
+ loopCondition=lambda: True):
649
654
  """utility function that starts a new Name server and enters its requestloop."""
650
655
  daemon = NameServerDaemon(host, port, unixsocket, nathost=nathost, natport=natport, storage=storage)
651
656
  nsUri = daemon.uriFor(daemon.nameserver)
@@ -681,7 +686,7 @@ def start_ns_loop(host=None, port=None, enableBroadcast=True, bchost=None, bcpor
681
686
  print("URI = %s" % nsUri)
682
687
  sys.stdout.flush()
683
688
  try:
684
- daemon.requestLoop()
689
+ daemon.requestLoop(loopCondition=loopCondition)
685
690
  finally:
686
691
  daemon.close()
687
692
  if bcserver is not None:
@@ -75,12 +75,11 @@ class SendingMessage:
75
75
  self.seq = seq
76
76
  self.serializer_id = serializer_id
77
77
  annotations = annotations or {}
78
- annotations_size = sum([8 + len(v) for v in annotations.values()])
78
+ annotations_size = sum(8 + len(v) for v in annotations.values())
79
79
  flags &= ~FLAGS_COMPRESSED
80
80
  if config.COMPRESSION and len(payload) > 100:
81
81
  payload = zlib.compress(payload, 4)
82
82
  flags |= FLAGS_COMPRESSED
83
- self.flags = flags
84
83
  total_size = len(payload) + annotations_size
85
84
  if total_size > config.MAX_MESSAGE_SIZE:
86
85
  raise errors.ProtocolError("message too large ({:d}, max={:d})".format(total_size, config.MAX_MESSAGE_SIZE))
@@ -89,7 +88,8 @@ class SendingMessage:
89
88
  self.corr_id = current_context.correlation_id.bytes
90
89
  else:
91
90
  self.corr_id = _empty_correlation_id
92
- header_data = struct.pack(_header_format, b"PYRO", PROTOCOL_VERSION, msgtype, serializer_id, flags, seq,
91
+ self.flags = flags
92
+ header_data = struct.pack(_header_format, b"PYRO", PROTOCOL_VERSION, msgtype, serializer_id, self.flags, seq,
93
93
  len(payload), annotations_size, self.corr_id, 0, _magic_number)
94
94
  annotation_data = []
95
95
  for k, v in annotations.items():
@@ -158,9 +158,12 @@ class ReceivingMessage:
158
158
  while i < self.annotations_size:
159
159
  annotation_id = bytes(payload[i:i+4]).decode("ascii")
160
160
  length = int.from_bytes(payload[i+4:i+8], "big")
161
+ if length < 0 or i + 8 + length > self.annotations_size:
162
+ raise errors.ProtocolError("annotation chunk length exceeds remaining data")
161
163
  self.annotations[annotation_id] = payload[i+8:i+8+length] # note: it stores a memoryview!
162
164
  i += 8 + length
163
- assert i == self.annotations_size
165
+ if i != self.annotations_size:
166
+ raise errors.ProtocolError("annotation parsing did not consume all annotation data")
164
167
  self.data = payload[self.annotations_size:]
165
168
  else:
166
169
  self.data = payload
@@ -175,8 +178,8 @@ def log_wiredata(logger, text, msg):
175
178
  num_anns = len(msg.annotations) if hasattr(msg, "annotations") else 0
176
179
  corr_bytes = bytes(msg.corr_id) if hasattr(msg, "corr_id") else _empty_correlation_id
177
180
  corr_id = uuid.UUID(bytes=corr_bytes)
178
- logger.debug("%s: msgtype=%d flags=0x%x ser=%d seq=%d num_annotations=%s corr_id=%s\ndata=%r" %
179
- (text, msg.type, msg.flags, msg.serializer_id, msg.seq, num_anns, corr_id, bytes(msg.data)))
181
+ logger.debug("%s: msgtype=%d flags=0x%x ser=%d seq=%d num_annotations=%s corr_id=%s\ndata=%r",
182
+ text, msg.type, msg.flags, msg.serializer_id, msg.seq, num_anns, corr_id, bytes(msg.data))
180
183
 
181
184
 
182
185
  def recv_stub(connection, accepted_msgtypes=None):
@@ -231,7 +231,7 @@ class SerializerBase(object):
231
231
  exceptiontype = getattr(sqlite3, short_classname)
232
232
  if issubclass(exceptiontype, BaseException):
233
233
  return SerializerBase.make_exception(exceptiontype, data)
234
- log.warning("unsupported serialized class: " + classname)
234
+ log.warning("unsupported serialized class: %s", classname)
235
235
  raise errors.SerializeError("unsupported serialized class: " + classname)
236
236
 
237
237
  @staticmethod
@@ -422,7 +422,7 @@ class MsgpackSerializer(SerializerBase):
422
422
  return msgpack.packb(data, use_bin_type=True, default=self.default)
423
423
 
424
424
  def loadsCall(self, data):
425
- return msgpack.unpackb(self._convertToBytes(data), raw=False, object_hook=self.object_hook)
425
+ return msgpack.unpackb(self._convertToBytes(data), raw=False, object_hook=self.object_hook, ext_hook=self.ext_hook)
426
426
 
427
427
  def loads(self, data):
428
428
  return msgpack.unpackb(self._convertToBytes(data), raw=False, object_hook=self.object_hook, ext_hook=self.ext_hook)
@@ -168,7 +168,7 @@ class DaemonObject(object):
168
168
  metadata = _get_exposed_members(obj)
169
169
  if not metadata["methods"] and not metadata["attrs"]:
170
170
  # Something seems wrong: nothing is remotely exposed.
171
- warnings.warn("Class %r doesn't expose any methods or attributes. Did you forget setting @expose on them?" % type(obj))
171
+ warnings.warn("Class %s doesn't expose any methods or attributes. Did you forget setting @expose on them?" % repr(obj))
172
172
  return metadata
173
173
  else:
174
174
  log.debug("unknown object requested: %s", objectId)
@@ -241,7 +241,7 @@ class Daemon(object):
241
241
  natport_for_loc = natport
242
242
  if natport == 0:
243
243
  # expose internal port number as NAT port as well. (don't use port because it could be 0 and will be chosen by the OS)
244
- natport_for_loc = int(self.locationStr.split(":")[1])
244
+ natport_for_loc = int(self.locationStr.rsplit(":", 1)[1])
245
245
  # The NAT-location (str of the form ``nathost:natportnumber``) on which the Daemon is exposed for use with NAT-routing
246
246
  self.natLocationStr = "%s:%d" % (nathost, natport_for_loc) if nathost else None
247
247
  if self.natLocationStr:
@@ -250,10 +250,11 @@ class Daemon(object):
250
250
  pyroObject._pyroId = core.DAEMON_NAME
251
251
  # Dictionary from Pyro object id to the actual Pyro object registered by this id
252
252
  self.objectsById = {pyroObject._pyroId: pyroObject}
253
- log.debug("pyro protocol version: %d" % protocol.PROTOCOL_VERSION)
253
+ log.debug("pyro protocol version: %d", protocol.PROTOCOL_VERSION)
254
254
  self._pyroInstances = {} # pyro objects for instance_mode=single (singletons, just one per daemon)
255
255
  self.streaming_responses = {} # stream_id -> (client, creation_timestamp, linger_timestamp, stream)
256
256
  self.housekeeper_lock = threading.Lock()
257
+ self._disconnect_lock = threading.Lock()
257
258
  self.create_single_instance_lock = threading.Lock()
258
259
  self.__mustshutdown.clear()
259
260
  self.methodcall_error_handler = _default_methodcall_error_handler
@@ -456,6 +457,16 @@ class Daemon(object):
456
457
  if method == "__getattr__":
457
458
  # special case for direct attribute access (only exposed @properties are accessible)
458
459
  data = _get_exposed_property_value(obj, vargs[0])
460
+ if not request_flags & protocol.FLAGS_ONEWAY:
461
+ isStream, data = self._streamResponse(data, conn)
462
+ if isStream:
463
+ # throw an exception as well as setting message flags
464
+ # this way, it is backwards compatible with older pyro versions.
465
+ exc = errors.ProtocolError("result of call is an iterator")
466
+ ann = {"STRM": data.encode()} if data else {}
467
+ self._sendExceptionResponse(conn, request_seq, serializer.serializer_id, exc, None,
468
+ annotations=ann, flags=protocol.FLAGS_ITEMSTREAMRESULT)
469
+ return
459
470
  elif method == "__setattr__":
460
471
  # special case for direct attribute access (only exposed @properties are accessible)
461
472
  data = _set_exposed_property_value(obj, vargs[0], vargs[1])
@@ -514,19 +525,20 @@ class Daemon(object):
514
525
  raise # re-raise if flagged as callback, communication or security error.
515
526
 
516
527
  def _clientDisconnect(self, conn):
517
- if config.ITER_STREAM_LINGER > 0:
518
- # client goes away, keep streams around for a bit longer (allow reconnect)
519
- for streamId in list(self.streaming_responses):
520
- info = self.streaming_responses.get(streamId, None)
521
- if info and info[0] is conn:
522
- _, timestamp, _, stream = info
523
- self.streaming_responses[streamId] = (None, timestamp, time.time(), stream)
524
- else:
525
- # client goes away, close any streams it had open as well
526
- for streamId in list(self.streaming_responses):
527
- info = self.streaming_responses.get(streamId, None)
528
- if info and info[0] is conn:
529
- del self.streaming_responses[streamId]
528
+ with self._disconnect_lock:
529
+ if config.ITER_STREAM_LINGER > 0:
530
+ # client goes away, keep streams around for a bit longer (allow reconnect)
531
+ for streamId in list(self.streaming_responses):
532
+ info = self.streaming_responses.get(streamId, None)
533
+ if info and info[0] is conn:
534
+ _, timestamp, _, stream = info
535
+ self.streaming_responses[streamId] = (None, timestamp, time.time(), stream)
536
+ else:
537
+ # client goes away, close any streams it had open as well
538
+ for streamId in list(self.streaming_responses):
539
+ info = self.streaming_responses.get(streamId, None)
540
+ if info and info[0] is conn:
541
+ del self.streaming_responses[streamId]
530
542
  self.clientDisconnect(conn) # user overridable hook
531
543
 
532
544
  def _housekeeping(self):
@@ -650,12 +662,14 @@ class Daemon(object):
650
662
  obj_or_class._pyroInstancing = ("session", None)
651
663
  if not force:
652
664
  if hasattr(obj_or_class, "_pyroId") and obj_or_class._pyroId != "": # check for empty string is needed for Cython
653
- raise errors.DaemonError("object or class already has a Pyro id")
665
+ pyro_id = obj_or_class._pyroId
666
+ if pyro_id and self.objectsById.get(pyro_id) is obj_or_class:
667
+ raise errors.DaemonError("object or class already has a Pyro id")
654
668
  if objectId in self.objectsById:
655
669
  raise errors.DaemonError("an object or class is already registered with that id")
656
670
  # set some pyro attributes
657
671
  obj_or_class._pyroId = objectId
658
- obj_or_class._pyroDaemon = self
672
+ obj_or_class._pyroDaemon = weakref.proxy(self)
659
673
  # register a custom serializer for the type to automatically return proxies
660
674
  # we need to do this for all known serializers
661
675
  for ser in serializers.serializers.values():
@@ -664,7 +678,7 @@ class Daemon(object):
664
678
  else:
665
679
  ser.register_type_replacement(type(obj_or_class), _pyro_obj_to_auto_proxy)
666
680
  # register the object/class in the mapping
667
- self.objectsById[obj_or_class._pyroId] = (obj_or_class if not weak else weakref.ref(obj_or_class))
681
+ self.objectsById[obj_or_class._pyroId] = obj_or_class if not weak else weakref.ref(obj_or_class)
668
682
  if weak: weakref.finalize(obj_or_class,self.unregister,objectId)
669
683
  return self.uriFor(objectId)
670
684
 
@@ -847,8 +861,8 @@ def _default_methodcall_error_handler(daemon: Daemon, client_sock: socketutil.So
847
861
  method: Callable, vargs: Sequence[Any], kwargs: Dict[str, Any],
848
862
  exception: Exception) -> None:
849
863
  """The default routine called to process a exception raised in the user code of a method call"""
850
- log.debug("exception occurred in method call user code: client={} method={} exception={}"
851
- .format(client_sock, method.__qualname__, repr(exception)))
864
+ log.debug("exception occurred in method call user code: client=%s method=%s exception=%r",
865
+ client_sock, method.__qualname__, exception)
852
866
 
853
867
 
854
868
  # register the special serializers for the pyro objects
@@ -79,7 +79,10 @@ def get_ip_address(hostname: str, workaround127: bool = False, version: int = No
79
79
  raise ValueError("unknown value for argument ipVersion.")
80
80
  ip = socket.getaddrinfo(hostname or socket.gethostname(), 80, family, socket.SOCK_STREAM, socket.SOL_TCP)[0][4][0]
81
81
  if workaround127 and (ip.startswith("127.") or ip == "0.0.0.0"):
82
- return get_interface("4.2.2.2").ip
82
+ try:
83
+ return get_interface("4.2.2.2").ip
84
+ except OSError:
85
+ pass # network unreachable, fall through to return loopback address
83
86
  return ipaddress.ip_address(ip)
84
87
 
85
88
  try:
@@ -154,9 +157,12 @@ def receive_data(sock: socket.socket, size: int) -> bytes:
154
157
  data.extend(chunk)
155
158
  msglen += len(chunk)
156
159
  if len(data) != size:
157
- err = ConnectionClosedError("receiving: not enough data")
158
- err.partialData = data # store the message that was received until now
159
- raise err
160
+ try:
161
+ err = ConnectionClosedError("receiving: not enough data")
162
+ err.partialData = data # store the message that was received until now
163
+ raise err
164
+ finally:
165
+ del err
160
166
  return data # yay, complete
161
167
  except socket.timeout:
162
168
  raise TimeoutError("receiving: timeout")
@@ -24,7 +24,7 @@ class SocketServer_ExistingConnection(object):
24
24
  raise socket.error("SSL configured for Pyro but existing socket is not a SSL socket")
25
25
  self.daemon = daemon
26
26
  self.sock = connected_socket
27
- log.info("starting server on user-supplied connected socket " + str(connected_socket))
27
+ log.info("starting server on user-supplied connected socket %s", connected_socket)
28
28
  sn = connected_socket.getsockname()
29
29
  if hasattr(socket, "AF_UNIX") and connected_socket.family == socket.AF_UNIX:
30
30
  self.locationStr = "./u:" + (sn or "<<not-bound>>")
@@ -86,7 +86,7 @@ class SocketServer_ExistingConnection(object):
86
86
  return False
87
87
  except errors.TimeoutError as x:
88
88
  # for timeout errors we're not really interested in detailed traceback info
89
- log.warning("error during handleRequest: %s" % x)
89
+ log.warning("error during handleRequest: %s", x)
90
90
  return False
91
91
  except Exception:
92
92
  # other error occurred, close the connection, but also log a warning
@@ -87,7 +87,7 @@ class SocketServer_Multiplex(object):
87
87
  try:
88
88
  self.daemon._clientDisconnect(s)
89
89
  except Exception as x:
90
- log.warning("Error in clientDisconnect: " + str(x))
90
+ log.warning("Error in clientDisconnect: %s", x)
91
91
  self.selector.unregister(s)
92
92
  s.close()
93
93
  self.daemon._housekeeping()
@@ -174,7 +174,7 @@ class SocketServer_Multiplex(object):
174
174
  return False
175
175
  except errors.TimeoutError as x:
176
176
  # for timeout errors we're not really interested in detailed traceback info
177
- log.warning("error during handleRequest: %s" % x)
177
+ log.warning("error during handleRequest: %s", x)
178
178
  return False
179
179
  except Exception:
180
180
  # other error occurred, close the connection, but also log a warning
@@ -17,7 +17,6 @@ import contextlib
17
17
  from . import config, socketutil, errors
18
18
 
19
19
  log = logging.getLogger("Pyro5.threadpoolserver")
20
- _client_disconnect_lock = threading.Lock()
21
20
 
22
21
 
23
22
  class ClientConnectionJob(object):
@@ -46,7 +45,7 @@ class ClientConnectionJob(object):
46
45
  break
47
46
  except errors.TimeoutError as x:
48
47
  # for timeout errors we're not really interested in detailed traceback info
49
- log.warning("error during handleRequest: %s" % x)
48
+ log.warning("error during handleRequest: %s", x)
50
49
  break
51
50
  except Exception:
52
51
  # other errors log a warning, break this loop and close the client connection
@@ -56,11 +55,10 @@ class ClientConnectionJob(object):
56
55
  log.warning(msg)
57
56
  break
58
57
  finally:
59
- with _client_disconnect_lock:
60
- try:
61
- self.daemon._clientDisconnect(self.csock)
62
- except Exception as x:
63
- log.warning("Error in clientDisconnect: " + str(x))
58
+ try:
59
+ self.daemon._clientDisconnect(self.csock)
60
+ except Exception as x:
61
+ log.warning("Error in clientDisconnect: %s", x)
64
62
  self.csock.close()
65
63
 
66
64
  def handleConnection(self):
@@ -77,7 +75,7 @@ class ClientConnectionJob(object):
77
75
  return False
78
76
 
79
77
  def denyConnection(self, reason):
80
- log.warning("client connection was denied: " + reason)
78
+ log.warning("client connection was denied: %s", reason)
81
79
  # return failed handshake
82
80
  self.daemon._handshake(self.csock, denied_reason=reason)
83
81
  self.csock.close()
@@ -308,11 +306,11 @@ class Pool(object):
308
306
  def close(self):
309
307
  if not self.closed:
310
308
  log.debug("closing down")
309
+ self.closed = True
311
310
  for w in list(self.busy):
312
311
  w.process(None)
313
312
  for w in list(self.idle):
314
313
  w.process(None)
315
- self.closed = True
316
314
  time.sleep(0.1)
317
315
  idle, self.idle = self.idle, set()
318
316
  busy, self.busy = self.busy, set()