Procházet zdrojové kódy

[desktop] upgrade kazoo to 2.8.0 (#1278) (#1290)

Co-authored-by: zhangjiachao <zhangjiachao@ysten.com>
zhang-jc před 5 roky
rodič
revize
36126a0675
100 změnil soubory, kde provedl 4667 přidání a 3316 odebrání
  1. 0 548
      desktop/core/ext-py/kazoo-2.0/CHANGES.rst
  2. 0 81
      desktop/core/ext-py/kazoo-2.0/CONTRIBUTING.rst
  3. 0 604
      desktop/core/ext-py/kazoo-2.0/PKG-INFO
  4. 0 27
      desktop/core/ext-py/kazoo-2.0/README.rst
  5. 0 5
      desktop/core/ext-py/kazoo-2.0/debian/changelog
  6. 0 1
      desktop/core/ext-py/kazoo-2.0/debian/compat
  7. 0 50
      desktop/core/ext-py/kazoo-2.0/debian/control
  8. 0 13
      desktop/core/ext-py/kazoo-2.0/debian/copyright
  9. 0 1
      desktop/core/ext-py/kazoo-2.0/debian/docs
  10. 0 1
      desktop/core/ext-py/kazoo-2.0/debian/python-kazoo.install
  11. 0 18
      desktop/core/ext-py/kazoo-2.0/debian/rules
  12. 0 1
      desktop/core/ext-py/kazoo-2.0/debian/source/format
  13. 0 93
      desktop/core/ext-py/kazoo-2.0/kazoo/handlers/utils.py
  14. 0 26
      desktop/core/ext-py/kazoo-2.0/kazoo/hosts.py
  15. 0 2
      desktop/core/ext-py/kazoo-2.0/kazoo/loggingsupport.py
  16. 0 1
      desktop/core/ext-py/kazoo-2.0/kazoo/recipe/__init__.py
  17. 0 5
      desktop/core/ext-py/kazoo-2.0/kazoo/testing/__init__.py
  18. 0 180
      desktop/core/ext-py/kazoo-2.0/kazoo/testing/harness.py
  19. 0 29
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_build.py
  20. 0 35
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_counter.py
  21. 0 22
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_exceptions.py
  22. 0 517
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_lock.py
  23. 0 92
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_partitioner.py
  24. 0 98
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_paths.py
  25. 0 179
      desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_queue.py
  26. 0 3
      desktop/core/ext-py/kazoo-2.0/requirements.txt
  27. 0 1
      desktop/core/ext-py/kazoo-2.0/requirements_gevent.txt
  28. 0 4
      desktop/core/ext-py/kazoo-2.0/requirements_sphinx.txt
  29. 0 14
      desktop/core/ext-py/kazoo-2.0/setup.cfg
  30. 802 0
      desktop/core/ext-py/kazoo-2.8.0/CHANGES.md
  31. 167 0
      desktop/core/ext-py/kazoo-2.8.0/CONTRIBUTING.md
  32. 0 0
      desktop/core/ext-py/kazoo-2.8.0/LICENSE
  33. 4 4
      desktop/core/ext-py/kazoo-2.8.0/MANIFEST.in
  34. 861 0
      desktop/core/ext-py/kazoo-2.8.0/PKG-INFO
  35. 26 0
      desktop/core/ext-py/kazoo-2.8.0/README.md
  36. 22 21
      desktop/core/ext-py/kazoo-2.8.0/docs/Makefile
  37. 2 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api.rst
  38. 21 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/client.rst
  39. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/exceptions.rst
  40. 18 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/eventlet.rst
  41. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/gevent.rst
  42. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/threading.rst
  43. 18 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/utils.rst
  44. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/interfaces.rst
  45. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/protocol/states.rst
  46. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/barrier.rst
  47. 26 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/cache.rst
  48. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/counter.rst
  49. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/election.rst
  50. 19 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/lease.rst
  51. 12 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/lock.rst
  52. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/partitioner.rst
  53. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/party.rst
  54. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/queue.rst
  55. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/watchers.rst
  56. 23 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/retry.rst
  57. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/security.rst
  58. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/api/testing.rst
  59. 3 2
      desktop/core/ext-py/kazoo-2.8.0/docs/async_usage.rst
  60. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/basic_usage.rst
  61. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/changelog.rst
  62. 5 3
      desktop/core/ext-py/kazoo-2.8.0/docs/conf.py
  63. 1 0
      desktop/core/ext-py/kazoo-2.8.0/docs/contributing.rst
  64. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/glossary.rst
  65. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/implementation.rst
  66. 14 10
      desktop/core/ext-py/kazoo-2.8.0/docs/index.rst
  67. 1 1
      desktop/core/ext-py/kazoo-2.8.0/docs/install.rst
  68. 0 0
      desktop/core/ext-py/kazoo-2.8.0/docs/make.bat
  69. 1 1
      desktop/core/ext-py/kazoo-2.8.0/docs/testing.rst
  70. 1 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/__init__.py
  71. 424 135
      desktop/core/ext-py/kazoo-2.8.0/kazoo/client.py
  72. 15 7
      desktop/core/ext-py/kazoo-2.8.0/kazoo/exceptions.py
  73. 0 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/__init__.py
  74. 179 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/eventlet.py
  75. 31 22
      desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/gevent.py
  76. 123 119
      desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/threading.py
  77. 302 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/utils.py
  78. 30 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/hosts.py
  79. 0 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/interfaces.py
  80. 1 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/loggingsupport.py
  81. 0 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/__init__.py
  82. 238 114
      desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/connection.py
  83. 3 2
      desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/paths.py
  84. 51 12
      desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/serialization.py
  85. 9 3
      desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/states.py
  86. 69 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/python2atexit.py
  87. 0 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/__init__.py
  88. 3 4
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/barrier.py
  89. 427 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/cache.py
  90. 41 7
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/counter.py
  91. 1 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/election.py
  92. 147 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/lease.py
  93. 307 89
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/lock.py
  94. 105 55
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/partitioner.py
  95. 0 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/party.py
  96. 53 21
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/queue.py
  97. 21 10
      desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/watchers.py
  98. 24 20
      desktop/core/ext-py/kazoo-2.8.0/kazoo/retry.py
  99. 12 3
      desktop/core/ext-py/kazoo-2.8.0/kazoo/security.py
  100. 4 0
      desktop/core/ext-py/kazoo-2.8.0/kazoo/testing/__init__.py

+ 0 - 548
desktop/core/ext-py/kazoo-2.0/CHANGES.rst

@@ -1,548 +0,0 @@
-Changelog
-=========
-
-2.0 (2014-06-19)
-----------------
-
-Documentation
-*************
-
-- Extend support to Python 3.4, deprecating Python 3.2.
-- Issue #198: Mention Zake as a sophisticated kazoo mock testing library.
-- Issue #181: Add documentation on basic logging setup.
-
-2.0b1 (2014-04-24)
-------------------
-
-API Changes
-***********
-
-- Null or None data is no longer treated as "". Pull req #165, patch by
-  Raul Gutierrez S. This will affect how you should treat null data in a
-  znode vs. an empty string.
-- Passing acl=[] to create() now works properly instead of an InvalidACLError
-  as it returned before. Patch by Raul Gutierrez S in PR #164.
-- Removed the dependency on zope.interface. The classes in the interfaces
-  module are left for documentation purposes only (issue #131).
-
-Features
-********
-
-- Logging levels have been reduced.
-
-  - Logging previously at the ``logging.DEBUG`` level is now logged at
-    the ``kazoo.loggingsupport.BLATHER`` level (5).
-
-  - Some low-level logging previously at the ``logging.INFO`` level is
-    now logged at the ``logging.DEBUG`` level.
-
-- Issue #133: Introduce a new environment variable `ZOOKEEPER_PORT_OFFSET`
-  for the testing support, to run the testing cluster on a different range.
-
-Bug Handling
-************
-
-- When authenticating via add_auth() the auth data will be saved to ensure that
-  the authentication happens on reconnect (as is the case when feeding auth
-  data via KazooClient's constructor). PR #172, patch by Raul Gutierrez S.
-- Change gevent import to remove deprecation warning when newer gevent is
-  used. PR #191, patch by Hiroaki Kawai.
-- Lock recipe was failing to use the client's sleep_func causing issues with
-  gevent. Issue #150.
-- Calling a DataWatch or ChildrenWatch instance twice (decorator) now throws
-  an exception as only a single function can be associated with a single
-  watcher. Issue #154.
-- Another fix for atexit handling so that when disposing of connections the
-  atexit handler is removed. PR #190, patch by Devaev Maxim.
-- Fix atexit handling for kazoo threading handler, PR #183. Patch by
-  Brian Wickman.
-- Partitioner should handle a suspended connection properly and restore
-  an allocated state if it was allocated previously. Patch by Manish Tomar.
-- Issue #167: Closing a client that was never started throws a type error.
-  Patch by Joshua Harlow.
-- Passing dictionaries to KazooClient.__init__() wasn't actually working
-  properly. Patch by Ryan Uber.
-- Issue #119: Handler timeout takes the max of the random interval or
-  the read timeout to ensure a negative number isn't used for the read
-  timeout.
-- Fix ordering of exception catches in lock.acquire as it was capturing a
-  parent exception before the child. Patch by ReneSac.
-- Fix issue with client.stop() not always setting the client state to
-  KeeperState.CLOSED. Patch by Jyrki Pulliainen in PR #174.
-- Issue #169: Fixed pipes leaking into child processes.
-
-Documentation
-*************
-
-- Add section on contributing recipes, add maintainer/status information for
-  existing recipes.
-- Add note about alternate use of DataWatch.
-
-1.3.1 (2013-09-25)
-------------------
-
-Bug Handling
-************
-
-- #118, #125, #128: Fix unknown variable in KazooClient `command_retry`
-  argument handling.
-
-- #126: Fix `KazooRetry.copy` to correctly copy sleep function.
-
-- #118: Correct session/socket timeout conversion (int vs. float).
-
-Documentation
-*************
-
-- #121: Add a note about `kazoo.recipe.queue.LockingQueue` requiring a
-  Zookeeper 3.4+ server.
-
-
-1.3 (2013-09-05)
-----------------
-
-Features
-********
-
-- #115: Limit the backends we use for SLF4J during tests.
-
-- #112: Add IPv6 support. Patch by Dan Kruchinin.
-
-1.2.1 (2013-08-01)
-------------------
-
-Bug Handling
-************
-
-- Issue #108: Circular import fail when importing kazoo.recipe.watchers
-  directly has now been resolved. Watchers and partitioner properly import
-  the KazooState from kazoo.protocol.states rather than kazoo.client.
-- Issue #109: Partials not usable properly as a datawatch call can now be
-  used. All funcs will be called with 3 args and fall back to 2 args if
-  there's an argument error.
-- Issue #106, #107: `client.create_async` didn't strip change root from the
-  returned path.
-
-1.2 (2013-07-24)
-----------------
-
-Features
-********
-
-- KazooClient can now be stopped more reliably even if its in the middle
-  of a long retry sleep. This utilizes the new interrupt feature of
-  KazooRetry which lets the sleep be broken down into chunks and an
-  interrupt function called to determine if the retry should fail early.
-
-- Issue #62, #92, #89, #101, #102: Allow KazooRetry to have a
-  max deadline, transition properly when connection fails to LOST, and
-  setup separate connection retry behavior from client command retry
-  behavior. Patches by Mike Lundy.
-
-- Issue #100: Make it easier to see exception context in threading and
-  connection modules.
-
-- Issue #85: Increase information density of logs and don't prevent
-  dynamic reconfiguration of log levels at runtime.
-
-- Data-watchers for the same node are no longer 'stacked'. That is, if
-  a get and an exists call occur for the same node with the same watch
-  function, then it will be registered only once. This change results in
-  Kazoo behaving per Zookeeper client spec regarding repeat watch use.
-
-Bug Handling
-************
-
-- Issue #53: Throw a warning upon starting if the chroot path doesn't exist
-  so that it's more obvious when the chroot should be created before
-  performing more operations.
-
-- Kazoo previously would let the same function be registered as a data-watch
-  or child-watch multiple times, and then call it multiple times upon being
-  triggered. This was non-compliant Zookeeper client behavior, the same
-  watch can now only be registered once for the same znode path per Zookeeper
-  client documentation.
-
-- Issue #105: Avoid rare import lock problems by moving module imports in
-  client.py to the module scope.
-
-- Issue #103: Allow prefix-less sequential znodes.
-
-- Issue #98: Extend testing ZK harness to work with different file locations
-  on some versions of Debian/Ubuntu.
-
-- Issue #97: Update some docstrings to reflect current state of handlers.
-
-- Issue #62, #92, #89, #101, #102: Allow KazooRetry to have a
-  max deadline, transition properly when connection fails to LOST, and
-  setup separate connection retry behavior from client command retry
-  behavior. Patches by Mike Lundy.
-
-API Changes
-***********
-
-- The `kazoo.testing.harness.KazooTestHarness` class directly inherits from
-  `unittest.TestCase` and you need to ensure to call its `__init__` method.
-
-- DataWatch no longer takes any parameters besides for the optional function
-  during instantiation. The additional options are now implicitly True, with
-  the user being left to ignore events as they choose. See the DataWatch
-  API docs for more information.
-
-- Issue #99: Better exception raised when the writer fails to close. A
-  WriterNotClosedException that inherits from KazooException is now raised
-  when the writer fails to close in time.
-
-1.1 (2013-06-08)
-----------------
-
-Features
-********
-
-- Issue #93: Add timeout option to lock/semaphore acquire methods.
-
-- Issue #79 / #90: Add ability to pass the WatchedEvent to DataWatch and
-  ChildWatch functions.
-
-- Respect large client timeout values when closing the connection.
-
-- Add a `max_leases` consistency check to the semaphore recipe.
-
-- Issue #76: Extend testing helpers to allow customization of the Java
-  classpath by specifying the new `ZOOKEEPER_CLASSPATH` environment variable.
-
-- Issue #65: Allow non-blocking semaphore acquisition.
-
-Bug Handling
-************
-
-- Issue #96: Provide Windows compatibility in testing harness.
-
-- Issue #95: Handle errors deserializing connection response.
-
-- Issue #94: Clean up stray bytes in connection pipe.
-
-- Issue #87 / #88: Allow re-acquiring lock after cancel.
-
-- Issue #77: Use timeout in initial socket connection.
-
-- Issue #69: Only ensure path once in lock and semaphore recipes.
-
-- Issue #68: Closing the connection causes exceptions to be raised by watchers
-  which assume the connection won't be closed when running commands.
-
-- Issue #66: Require ping reply before sending another ping, otherwise the
-  connection will be considered dead and a ConnectionDropped will be raised
-  to trigger a reconnect.
-
-- Issue #63: Watchers weren't reset on lost connection.
-
-- Issue #58: DataWatcher failed to re-register for changes after non-existent
-  node was created then deleted.
-
-API Changes
-***********
-
-- KazooClient.create_async now supports the makepath argument.
-
-- KazooClient.ensure_path now has an async version, ensure_path_async.
-
-1.0 (2013-03-26)
-----------------
-
-Features
-********
-
-- Added a LockingQueue recipe. The queue first locks an item and removes it
-  from the queue only after the consume() method is called. This enables other
-  nodes to retake the item if an error occurs on the first node.
-
-Bug Handling
-************
-
-- Issue #50: Avoid problems with sleep function in mixed gevent/threading
-  setup.
-
-- Issue #56: Avoid issues with watch callbacks evaluating to false.
-
-1.0b1 (2013-02-24)
-------------------
-
-Features
-********
-
-- Refactored the internal connection handler to use a single thread. It now
-  uses a deque and pipe to signal the ZK thread that there's a new command to
-  send, so that the ZK thread can send it, or retrieve a response.
-  Processing ZK requests and responses serially in a single thread eliminates
-  the need for a bunch of the locking, the peekable queue and two threads
-  working on the same underlying socket.
-
-- Issue #48: Added documentation for the `retry` helper module.
-
-- Issue #55: Fix `os.pipe` file descriptor leak and introduce a
-  `KazooClient.close` method. The method is particular useful in tests, where
-  multiple KazooClients are created and closed in the same process.
-
-Bug Handling
-************
-
-- Issue #46: Avoid TypeError in GeneratorContextManager on process shutdown.
-
-- Issue #43: Let DataWatch return node data if allow_missing_node is used.
-
-0.9 (2013-01-07)
-----------------
-
-API Changes
-***********
-
-- When a retry operation ultimately fails, it now raises a
-  `kazoo.retry.RetryFailedError` exception, instead of a general `Exception`
-  instance. `RetryFailedError` also inherits from the base `KazooException`.
-
-Features
-********
-
-- Improvements to Debian packaging rules.
-
-Bug Handling
-************
-
-- Issue #39 / #41: Handle connection dropped errors during session writes.
-  Ensure client connection is re-established to a new ZK node if available.
-
-- Issue #38: Set `CLOEXEC` flag on all sockets when available.
-
-- Issue #37 / #40: Handle timeout errors during `select` calls on sockets.
-
-- Issue #36: Correctly set `ConnectionHandler.writer_stopped` even if an
-  exception is raised inside the writer, like a retry operation failing.
-
-0.8 (2012-10-26)
-----------------
-
-API Changes
-***********
-
-- The `KazooClient.__init__` took as `watcher` argument as its second keyword
-  argument. The argument had no effect anymore since version 0.5 and was
-  removed.
-
-Bug Handling
-************
-
-- Issue #35: `KazooClient.__init__` didn't pass on `retry_max_delay` to the
-  retry helper.
-
-- Issue #34: Be more careful while handling socket connection errors.
-
-0.7 (2012-10-15)
-----------------
-
-Features
-********
-
-- DataWatch now has a `allow_missing_node` setting that allows a watch to be
-  set on a node that doesn't exist when the DataWatch is created.
-- Add new Queue recipe, with optional priority support.
-- Add new Counter recipe.
-- Added debian packaging rules.
-
-Bug Handling
-************
-
-- Issue #31 fixed: Only catch KazooExceptions in catch-all calls.
-- Issue #15 fixed again: Force sleep delay to be a float to appease gevent.
-- Issue #29 fixed: DataWatch and ChildrenWatch properly re-register their
-  watches on server disconnect.
-
-0.6 (2012-09-27)
-----------------
-
-API Changes
-***********
-
-- Node paths are assumed to be Unicode objects. Under Python 2 pure-ascii
-  strings will also be accepted. Node values are considered bytes. The byte
-  type is an alias for `str` under Python 2.
-- New KeeperState.CONNECTED_RO state for Zookeeper servers connected in
-  read-only mode.
-- New NotReadOnlyCallError exception when issuing a write change against a
-  server thats currently read-only.
-
-Features
-********
-
-- Add support for Python 3.2, 3.3 and PyPy (only for the threading handler).
-- Handles connecting to Zookeeper 3.4+ read-only servers.
-- Automatic background scanning for a Read/Write server when connected to a
-  server in read-only mode.
-- Add new Semaphore recipe.
-- Add a new `retry_max_delay` argument to the client and by default limit the
-  retry delay to at most an hour regardless of exponential backoff settings.
-- Add new `randomize_hosts` argument to `KazooClient`, allowing one to disable
-  host randomization.
-
-Bug Handling
-************
-
-- Fix bug with locks not handling intermediary lock contenders disappearing.
-- Fix bug with set_data type check failing to catch unicode values.
-- Fix bug with gevent 0.13.x backport of peekable queue.
-- Fix PatientChildrenWatch to use handler specific sleep function.
-
-0.5 (2012-09-06)
-----------------
-
-Skipping a version to reflect the magnitude of the change. Kazoo is now a pure
-Python client with no C bindings. This release should run without a problem
-on alternate Python implementations such as PyPy and Jython. Porting to Python
-3 in the future should also be much easier.
-
-Documentation
-*************
-
-- Docs have been restructured to handle the new classes and locations of the
-  methods from the pure Python refactor.
-
-Bug Handling
-************
-
-This change may introduce new bugs, however there is no longer the possibility
-of a complete Python segfault due to errors in the C library and/or the C
-binding.
-
-- Possible segfaults from the C lib are gone.
-- Password mangling due to the C lib is gone.
-- The party recipes didn't set their participating flag to False after
-  leaving.
-
-Features
-********
-
-- New `client.command` and `client.server_version` API, exposing Zookeeper's
-  four letter commands and giving access to structured version information.
-- Added 'include_data' option for get_children to include the node's Stat
-  object.
-- Substantial increase in logging data with debug mode. All correspondence with
-  the Zookeeper server can now be seen to help in debugging.
-
-API Changes
-***********
-
-- The testing helpers have been moved from `testing.__init__` into a
-  `testing.harness` module. The official API's of `KazooTestCase` and
-  `KazooTestHarness` can still be directly imported from `testing`.
-- The kazoo.handlers.util module was removed.
-- Backwards compatible exception class aliases are provided for now in kazoo
-  exceptions for the prior C exception names.
-- Unicode strings now work fine for node names and are properly converted to
-  and from unicode objects.
-- The data value argument for the create and create_async methods of the
-  client was made optional and defaults to an empty byte string. The data
-  value must be a byte string. Unicode values are no longer allowed and
-  will raise a TypeError.
-
-
-0.3 (2012-08-23)
-----------------
-
-API Changes
-***********
-
-- Handler interface now has an rlock_object for use by recipes.
-
-Bug Handling
-************
-
-- Fixed password bug with updated zc-zookeeper-static release, which retains
-  null bytes in the password properly.
-- Fixed reconnect hammering, so that the reconnection follows retry jitter and
-  retry backoff's.
-- Fixed possible bug with using a threading.Condition in the set partitioner.
-  Set partitioner uses new rlock_object handler API to get an appropriate RLock
-  for gevent.
-- Issue #17 fixed: Wrap timeout exceptions with staticmethod so they can be
-  used directly as intended. Patch by Bob Van Zant.
-- Fixed bug with client reconnection looping indefinitely using an expired
-  session id.
-
-0.2 (2012-08-12)
-----------------
-
-Documentation
-*************
-
-- Fixed doc references to start_async using an AsyncResult object, it uses
-  an Event object.
-
-Bug Handling
-************
-
-- Issue #16 fixed: gevent zookeeper logging failed to handle a monkey patched
-  logging setup. Logging is now setup such that a greenlet is used for logging
-  messages under gevent, and the thread one is used otherwise.
-- Fixed bug similar to #14 for ChildrenWatch on the session listener.
-- Issue #14 fixed: DataWatch had inconsistent handling of the node it was
-  watching not existing. DataWatch also properly spawns its _get_data function
-  to avoid blocking session events.
-- Issue #15 fixed: sleep_func for SequentialGeventHandler was not set on the
-  class appropriately leading to additional arguments being passed to
-  gevent.sleep.
-- Issue #9 fixed: Threads/greenlets didn't gracefully shut down. Handler now
-  has a start/stop that is used by the client when calling start and stop that
-  shuts down the handler workers. This addresses errors and warnings that could
-  be emitted upon process shutdown regarding a clean exit of the workers.
-- Issue #12 fixed: gevent 0.13 doesn't use the same start_new_thread as gevent
-  1.0 which resulted in a fully monkey-patched environment halting due to the
-  wrong thread. Updated to use the older kazoo method of getting the real thread
-  module object.
-
-API Changes
-***********
-
-- The KazooClient handler is now officially exposed as KazooClient.handler
-  so that the appropriate sync objects can be used by end-users.
-- Refactored ChildrenWatcher used by SetPartitioner into a publicly exposed
-  PatientChildrenWatch under recipe.watchers.
-
-Deprecations
-************
-
-- connect/connect_async has been renamed to start/start_async to better match
-  the stop to indicate connection handling. The prior names are aliased for
-  the time being.
-
-Recipes
-*******
-
-- Added Barrier and DoubleBarrier implementation.
-
-0.2b1 (2012-07-27)
-------------------
-
-Bug Handling
-************
-
-- ZOOKEEPER-1318: SystemError is caught and rethrown as the proper invalid
-  state exception in older zookeeper python bindings where this issue is still
-  valid.
-- ZOOKEEPER-1431: Install the latest zc-zookeeper-static library or use the
-  packaged ubuntu one for ubuntu 12.04 or later.
-- ZOOKEEPER-553: State handling isn't checked via this method, we track it in
-  a simpler manner with the watcher to ensure we know the right state.
-
-Features
-********
-
-- Exponential backoff with jitter for retrying commands.
-- Gevent 0.13 and 1.0b support.
-- Lock, Party, SetPartitioner, and Election recipe implementations.
-- Data and Children watching API's.
-- State transition handling with listener registering to handle session state
-  changes (choose to fatal the app on session expiration, etc.)
-- Zookeeper logging stream redirected into Python logging channel under the
-  name 'Zookeeper'.
-- Base client library with handler support for threading and gevent async
-  environments.

+ 0 - 81
desktop/core/ext-py/kazoo-2.0/CONTRIBUTING.rst

@@ -1,81 +0,0 @@
-=================
-How to contribute
-=================
-
-We gladly accept outside contributions. We use our
-`Github issue tracker <https://github.com/python-zk/kazoo/issues>`_
-for both discussions and talking about new features or bugs. You can
-also fork the project and sent us a pull request. If you have a more
-general topic to discuss, the
-`user@zookeeper.apache.org <https://zookeeper.apache.org/lists.html>`_
-mailing list is a good place to do so. You can sometimes find us on
-IRC in the
-`#zookeeper channel on freenode <https://zookeeper.apache.org/irc.html>`_.
-
-
-Development
-===========
-
-If you want to work on the code and sent us a
-`pull request <https://help.github.com/articles/using-pull-requests>`_,
-first fork the repository on github to your own account. Then clone
-your new repository and run the build scripts::
-
-    git clone git@github.com:<username>/kazoo.git
-    cd kazoo
-    make
-    make zookeeper
-
-You need to have some supported version of Python installed and have
-it available as ``python`` in your shell. To run Zookeeper you also
-need a Java runtime (JRE or JDK) version 6 or 7.
-
-You can run all the tests by calling::
-
-    make test
-
-Or to run individual tests::
-
-    export ZOOKEEPER_PATH=/<path to current folder>/bin/zookeeper/
-    bin/nosetests -s -d kazoo.tests.test_client:TestClient.test_create
-
-The nose test runner allows you to filter by test module, class or
-individual test method.
-
-If you made changes to the documentation, you can build it locally::
-
-    make html
-
-And then open ``./docs/_build/html/index.html`` in a web browser to
-verify the correct rendering.
-
-
-Submitting changes
-==================
-
-We appreciate getting changes sent as pull requests via github. We have
-travis-ci set up, which will run all tests on all supported version
-combinations for submitted pull requests, which makes it easy to see
-if new code breaks tests on some weird version combination.
-
-If you introduce new functionality, please also add documentation and
-a short entry in the top-level ``CHANGES.rst`` file.
-
-
-Adding Recipes
-==============
-
-New recipes are welcome, however they should include the status/maintainer
-RST information so its clear who is maintaining the recipe. This does mean
-that if you submit a recipe for inclusion with Kazoo, you should be ready
-to support/maintain it, and address bugs that may be found.
-
-Ideally a recipe should have at least two maintainers.
-
-Legal
-=====
-
-Currently we don't have any legal contributor agreement, so code
-ownership stays with the original authors. The project is licensed
-under the
-`Apache License Version 2 <https://github.com/python-zk/kazoo/blob/master/LICENSE>`_.

+ 0 - 604
desktop/core/ext-py/kazoo-2.0/PKG-INFO

@@ -1,604 +0,0 @@
-Metadata-Version: 1.1
-Name: kazoo
-Version: 2.0
-Summary: Higher Level Zookeeper Client
-Home-page: https://kazoo.readthedocs.org
-Author: Kazoo team
-Author-email: python-zk@googlegroups.com
-License: Apache 2.0
-Description: =====
-        Kazoo
-        =====
-        
-        ``kazoo`` implements a higher level API to `Apache Zookeeper`_ for Python
-        clients.
-        
-        See `the full docs`_ for more information.
-        
-        License
-        =======
-        
-        ``kazoo`` is offered under the Apache License 2.0.
-        
-        Authors
-        =======
-        
-        ``kazoo`` started under the `Nimbus Project`_ and through collaboration with
-        the open-source community has been merged with code from `Mozilla`_ and the
-        `Zope Corporation`_. It has since gathered an active community of over two
-        dozen contributors.
-        
-        .. _Apache Zookeeper: http://zookeeper.apache.org/
-        .. _the full docs: http://kazoo.rtfd.org/
-        .. _Nimbus Project: http://www.nimbusproject.org/
-        .. _Zope Corporation: http://zope.com/
-        .. _Mozilla: http://www.mozilla.org/
-        
-        
-        Changelog
-        =========
-        
-        2.0 (2014-06-19)
-        ----------------
-        
-        Documentation
-        *************
-        
-        - Extend support to Python 3.4, deprecating Python 3.2.
-        - Issue #198: Mention Zake as a sophisticated kazoo mock testing library.
-        - Issue #181: Add documentation on basic logging setup.
-        
-        2.0b1 (2014-04-24)
-        ------------------
-        
-        API Changes
-        ***********
-        
-        - Null or None data is no longer treated as "". Pull req #165, patch by
-          Raul Gutierrez S. This will affect how you should treat null data in a
-          znode vs. an empty string.
-        - Passing acl=[] to create() now works properly instead of an InvalidACLError
-          as it returned before. Patch by Raul Gutierrez S in PR #164.
-        - Removed the dependency on zope.interface. The classes in the interfaces
-          module are left for documentation purposes only (issue #131).
-        
-        Features
-        ********
-        
-        - Logging levels have been reduced.
-        
-          - Logging previously at the ``logging.DEBUG`` level is now logged at
-            the ``kazoo.loggingsupport.BLATHER`` level (5).
-        
-          - Some low-level logging previously at the ``logging.INFO`` level is
-            now logged at the ``logging.DEBUG`` level.
-        
-        - Issue #133: Introduce a new environment variable `ZOOKEEPER_PORT_OFFSET`
-          for the testing support, to run the testing cluster on a different range.
-        
-        Bug Handling
-        ************
-        
-        - When authenticating via add_auth() the auth data will be saved to ensure that
-          the authentication happens on reconnect (as is the case when feeding auth
-          data via KazooClient's constructor). PR #172, patch by Raul Gutierrez S.
-        - Change gevent import to remove deprecation warning when newer gevent is
-          used. PR #191, patch by Hiroaki Kawai.
-        - Lock recipe was failing to use the client's sleep_func causing issues with
-          gevent. Issue #150.
-        - Calling a DataWatch or ChildrenWatch instance twice (decorator) now throws
-          an exception as only a single function can be associated with a single
-          watcher. Issue #154.
-        - Another fix for atexit handling so that when disposing of connections the
-          atexit handler is removed. PR #190, patch by Devaev Maxim.
-        - Fix atexit handling for kazoo threading handler, PR #183. Patch by
-          Brian Wickman.
-        - Partitioner should handle a suspended connection properly and restore
-          an allocated state if it was allocated previously. Patch by Manish Tomar.
-        - Issue #167: Closing a client that was never started throws a type error.
-          Patch by Joshua Harlow.
-        - Passing dictionaries to KazooClient.__init__() wasn't actually working
-          properly. Patch by Ryan Uber.
-        - Issue #119: Handler timeout takes the max of the random interval or
-          the read timeout to ensure a negative number isn't used for the read
-          timeout.
-        - Fix ordering of exception catches in lock.acquire as it was capturing a
-          parent exception before the child. Patch by ReneSac.
-        - Fix issue with client.stop() not always setting the client state to
-          KeeperState.CLOSED. Patch by Jyrki Pulliainen in PR #174.
-        - Issue #169: Fixed pipes leaking into child processes.
-        
-        Documentation
-        *************
-        
-        - Add section on contributing recipes, add maintainer/status information for
-          existing recipes.
-        - Add note about alternate use of DataWatch.
-        
-        1.3.1 (2013-09-25)
-        ------------------
-        
-        Bug Handling
-        ************
-        
-        - #118, #125, #128: Fix unknown variable in KazooClient `command_retry`
-          argument handling.
-        
-        - #126: Fix `KazooRetry.copy` to correctly copy sleep function.
-        
-        - #118: Correct session/socket timeout conversion (int vs. float).
-        
-        Documentation
-        *************
-        
-        - #121: Add a note about `kazoo.recipe.queue.LockingQueue` requiring a
-          Zookeeper 3.4+ server.
-        
-        
-        1.3 (2013-09-05)
-        ----------------
-        
-        Features
-        ********
-        
-        - #115: Limit the backends we use for SLF4J during tests.
-        
-        - #112: Add IPv6 support. Patch by Dan Kruchinin.
-        
-        1.2.1 (2013-08-01)
-        ------------------
-        
-        Bug Handling
-        ************
-        
-        - Issue #108: Circular import fail when importing kazoo.recipe.watchers
-          directly has now been resolved. Watchers and partitioner properly import
-          the KazooState from kazoo.protocol.states rather than kazoo.client.
-        - Issue #109: Partials not usable properly as a datawatch call can now be
-          used. All funcs will be called with 3 args and fall back to 2 args if
-          there's an argument error.
-        - Issue #106, #107: `client.create_async` didn't strip change root from the
-          returned path.
-        
-        1.2 (2013-07-24)
-        ----------------
-        
-        Features
-        ********
-        
-        - KazooClient can now be stopped more reliably even if its in the middle
-          of a long retry sleep. This utilizes the new interrupt feature of
-          KazooRetry which lets the sleep be broken down into chunks and an
-          interrupt function called to determine if the retry should fail early.
-        
-        - Issue #62, #92, #89, #101, #102: Allow KazooRetry to have a
-          max deadline, transition properly when connection fails to LOST, and
-          setup separate connection retry behavior from client command retry
-          behavior. Patches by Mike Lundy.
-        
-        - Issue #100: Make it easier to see exception context in threading and
-          connection modules.
-        
-        - Issue #85: Increase information density of logs and don't prevent
-          dynamic reconfiguration of log levels at runtime.
-        
-        - Data-watchers for the same node are no longer 'stacked'. That is, if
-          a get and an exists call occur for the same node with the same watch
-          function, then it will be registered only once. This change results in
-          Kazoo behaving per Zookeeper client spec regarding repeat watch use.
-        
-        Bug Handling
-        ************
-        
-        - Issue #53: Throw a warning upon starting if the chroot path doesn't exist
-          so that it's more obvious when the chroot should be created before
-          performing more operations.
-        
-        - Kazoo previously would let the same function be registered as a data-watch
-          or child-watch multiple times, and then call it multiple times upon being
-          triggered. This was non-compliant Zookeeper client behavior, the same
-          watch can now only be registered once for the same znode path per Zookeeper
-          client documentation.
-        
-        - Issue #105: Avoid rare import lock problems by moving module imports in
-          client.py to the module scope.
-        
-        - Issue #103: Allow prefix-less sequential znodes.
-        
-        - Issue #98: Extend testing ZK harness to work with different file locations
-          on some versions of Debian/Ubuntu.
-        
-        - Issue #97: Update some docstrings to reflect current state of handlers.
-        
-        - Issue #62, #92, #89, #101, #102: Allow KazooRetry to have a
-          max deadline, transition properly when connection fails to LOST, and
-          setup separate connection retry behavior from client command retry
-          behavior. Patches by Mike Lundy.
-        
-        API Changes
-        ***********
-        
-        - The `kazoo.testing.harness.KazooTestHarness` class directly inherits from
-          `unittest.TestCase` and you need to ensure to call its `__init__` method.
-        
-        - DataWatch no longer takes any parameters besides for the optional function
-          during instantiation. The additional options are now implicitly True, with
-          the user being left to ignore events as they choose. See the DataWatch
-          API docs for more information.
-        
-        - Issue #99: Better exception raised when the writer fails to close. A
-          WriterNotClosedException that inherits from KazooException is now raised
-          when the writer fails to close in time.
-        
-        1.1 (2013-06-08)
-        ----------------
-        
-        Features
-        ********
-        
-        - Issue #93: Add timeout option to lock/semaphore acquire methods.
-        
-        - Issue #79 / #90: Add ability to pass the WatchedEvent to DataWatch and
-          ChildWatch functions.
-        
-        - Respect large client timeout values when closing the connection.
-        
-        - Add a `max_leases` consistency check to the semaphore recipe.
-        
-        - Issue #76: Extend testing helpers to allow customization of the Java
-          classpath by specifying the new `ZOOKEEPER_CLASSPATH` environment variable.
-        
-        - Issue #65: Allow non-blocking semaphore acquisition.
-        
-        Bug Handling
-        ************
-        
-        - Issue #96: Provide Windows compatibility in testing harness.
-        
-        - Issue #95: Handle errors deserializing connection response.
-        
-        - Issue #94: Clean up stray bytes in connection pipe.
-        
-        - Issue #87 / #88: Allow re-acquiring lock after cancel.
-        
-        - Issue #77: Use timeout in initial socket connection.
-        
-        - Issue #69: Only ensure path once in lock and semaphore recipes.
-        
-        - Issue #68: Closing the connection causes exceptions to be raised by watchers
-          which assume the connection won't be closed when running commands.
-        
-        - Issue #66: Require ping reply before sending another ping, otherwise the
-          connection will be considered dead and a ConnectionDropped will be raised
-          to trigger a reconnect.
-        
-        - Issue #63: Watchers weren't reset on lost connection.
-        
-        - Issue #58: DataWatcher failed to re-register for changes after non-existent
-          node was created then deleted.
-        
-        API Changes
-        ***********
-        
-        - KazooClient.create_async now supports the makepath argument.
-        
-        - KazooClient.ensure_path now has an async version, ensure_path_async.
-        
-        1.0 (2013-03-26)
-        ----------------
-        
-        Features
-        ********
-        
-        - Added a LockingQueue recipe. The queue first locks an item and removes it
-          from the queue only after the consume() method is called. This enables other
-          nodes to retake the item if an error occurs on the first node.
-        
-        Bug Handling
-        ************
-        
-        - Issue #50: Avoid problems with sleep function in mixed gevent/threading
-          setup.
-        
-        - Issue #56: Avoid issues with watch callbacks evaluating to false.
-        
-        1.0b1 (2013-02-24)
-        ------------------
-        
-        Features
-        ********
-        
-        - Refactored the internal connection handler to use a single thread. It now
-          uses a deque and pipe to signal the ZK thread that there's a new command to
-          send, so that the ZK thread can send it, or retrieve a response.
-          Processing ZK requests and responses serially in a single thread eliminates
-          the need for a bunch of the locking, the peekable queue and two threads
-          working on the same underlying socket.
-        
-        - Issue #48: Added documentation for the `retry` helper module.
-        
-        - Issue #55: Fix `os.pipe` file descriptor leak and introduce a
-          `KazooClient.close` method. The method is particular useful in tests, where
-          multiple KazooClients are created and closed in the same process.
-        
-        Bug Handling
-        ************
-        
-        - Issue #46: Avoid TypeError in GeneratorContextManager on process shutdown.
-        
-        - Issue #43: Let DataWatch return node data if allow_missing_node is used.
-        
-        0.9 (2013-01-07)
-        ----------------
-        
-        API Changes
-        ***********
-        
-        - When a retry operation ultimately fails, it now raises a
-          `kazoo.retry.RetryFailedError` exception, instead of a general `Exception`
-          instance. `RetryFailedError` also inherits from the base `KazooException`.
-        
-        Features
-        ********
-        
-        - Improvements to Debian packaging rules.
-        
-        Bug Handling
-        ************
-        
-        - Issue #39 / #41: Handle connection dropped errors during session writes.
-          Ensure client connection is re-established to a new ZK node if available.
-        
-        - Issue #38: Set `CLOEXEC` flag on all sockets when available.
-        
-        - Issue #37 / #40: Handle timeout errors during `select` calls on sockets.
-        
-        - Issue #36: Correctly set `ConnectionHandler.writer_stopped` even if an
-          exception is raised inside the writer, like a retry operation failing.
-        
-        0.8 (2012-10-26)
-        ----------------
-        
-        API Changes
-        ***********
-        
-        - The `KazooClient.__init__` took as `watcher` argument as its second keyword
-          argument. The argument had no effect anymore since version 0.5 and was
-          removed.
-        
-        Bug Handling
-        ************
-        
-        - Issue #35: `KazooClient.__init__` didn't pass on `retry_max_delay` to the
-          retry helper.
-        
-        - Issue #34: Be more careful while handling socket connection errors.
-        
-        0.7 (2012-10-15)
-        ----------------
-        
-        Features
-        ********
-        
-        - DataWatch now has a `allow_missing_node` setting that allows a watch to be
-          set on a node that doesn't exist when the DataWatch is created.
-        - Add new Queue recipe, with optional priority support.
-        - Add new Counter recipe.
-        - Added debian packaging rules.
-        
-        Bug Handling
-        ************
-        
-        - Issue #31 fixed: Only catch KazooExceptions in catch-all calls.
-        - Issue #15 fixed again: Force sleep delay to be a float to appease gevent.
-        - Issue #29 fixed: DataWatch and ChildrenWatch properly re-register their
-          watches on server disconnect.
-        
-        0.6 (2012-09-27)
-        ----------------
-        
-        API Changes
-        ***********
-        
-        - Node paths are assumed to be Unicode objects. Under Python 2 pure-ascii
-          strings will also be accepted. Node values are considered bytes. The byte
-          type is an alias for `str` under Python 2.
-        - New KeeperState.CONNECTED_RO state for Zookeeper servers connected in
-          read-only mode.
-        - New NotReadOnlyCallError exception when issuing a write change against a
-          server thats currently read-only.
-        
-        Features
-        ********
-        
-        - Add support for Python 3.2, 3.3 and PyPy (only for the threading handler).
-        - Handles connecting to Zookeeper 3.4+ read-only servers.
-        - Automatic background scanning for a Read/Write server when connected to a
-          server in read-only mode.
-        - Add new Semaphore recipe.
-        - Add a new `retry_max_delay` argument to the client and by default limit the
-          retry delay to at most an hour regardless of exponential backoff settings.
-        - Add new `randomize_hosts` argument to `KazooClient`, allowing one to disable
-          host randomization.
-        
-        Bug Handling
-        ************
-        
-        - Fix bug with locks not handling intermediary lock contenders disappearing.
-        - Fix bug with set_data type check failing to catch unicode values.
-        - Fix bug with gevent 0.13.x backport of peekable queue.
-        - Fix PatientChildrenWatch to use handler specific sleep function.
-        
-        0.5 (2012-09-06)
-        ----------------
-        
-        Skipping a version to reflect the magnitude of the change. Kazoo is now a pure
-        Python client with no C bindings. This release should run without a problem
-        on alternate Python implementations such as PyPy and Jython. Porting to Python
-        3 in the future should also be much easier.
-        
-        Documentation
-        *************
-        
-        - Docs have been restructured to handle the new classes and locations of the
-          methods from the pure Python refactor.
-        
-        Bug Handling
-        ************
-        
-        This change may introduce new bugs, however there is no longer the possibility
-        of a complete Python segfault due to errors in the C library and/or the C
-        binding.
-        
-        - Possible segfaults from the C lib are gone.
-        - Password mangling due to the C lib is gone.
-        - The party recipes didn't set their participating flag to False after
-          leaving.
-        
-        Features
-        ********
-        
-        - New `client.command` and `client.server_version` API, exposing Zookeeper's
-          four letter commands and giving access to structured version information.
-        - Added 'include_data' option for get_children to include the node's Stat
-          object.
-        - Substantial increase in logging data with debug mode. All correspondence with
-          the Zookeeper server can now be seen to help in debugging.
-        
-        API Changes
-        ***********
-        
-        - The testing helpers have been moved from `testing.__init__` into a
-          `testing.harness` module. The official API's of `KazooTestCase` and
-          `KazooTestHarness` can still be directly imported from `testing`.
-        - The kazoo.handlers.util module was removed.
-        - Backwards compatible exception class aliases are provided for now in kazoo
-          exceptions for the prior C exception names.
-        - Unicode strings now work fine for node names and are properly converted to
-          and from unicode objects.
-        - The data value argument for the create and create_async methods of the
-          client was made optional and defaults to an empty byte string. The data
-          value must be a byte string. Unicode values are no longer allowed and
-          will raise a TypeError.
-        
-        
-        0.3 (2012-08-23)
-        ----------------
-        
-        API Changes
-        ***********
-        
-        - Handler interface now has an rlock_object for use by recipes.
-        
-        Bug Handling
-        ************
-        
-        - Fixed password bug with updated zc-zookeeper-static release, which retains
-          null bytes in the password properly.
-        - Fixed reconnect hammering, so that the reconnection follows retry jitter and
-          retry backoff's.
-        - Fixed possible bug with using a threading.Condition in the set partitioner.
-          Set partitioner uses new rlock_object handler API to get an appropriate RLock
-          for gevent.
-        - Issue #17 fixed: Wrap timeout exceptions with staticmethod so they can be
-          used directly as intended. Patch by Bob Van Zant.
-        - Fixed bug with client reconnection looping indefinitely using an expired
-          session id.
-        
-        0.2 (2012-08-12)
-        ----------------
-        
-        Documentation
-        *************
-        
-        - Fixed doc references to start_async using an AsyncResult object, it uses
-          an Event object.
-        
-        Bug Handling
-        ************
-        
-        - Issue #16 fixed: gevent zookeeper logging failed to handle a monkey patched
-          logging setup. Logging is now setup such that a greenlet is used for logging
-          messages under gevent, and the thread one is used otherwise.
-        - Fixed bug similar to #14 for ChildrenWatch on the session listener.
-        - Issue #14 fixed: DataWatch had inconsistent handling of the node it was
-          watching not existing. DataWatch also properly spawns its _get_data function
-          to avoid blocking session events.
-        - Issue #15 fixed: sleep_func for SequentialGeventHandler was not set on the
-          class appropriately leading to additional arguments being passed to
-          gevent.sleep.
-        - Issue #9 fixed: Threads/greenlets didn't gracefully shut down. Handler now
-          has a start/stop that is used by the client when calling start and stop that
-          shuts down the handler workers. This addresses errors and warnings that could
-          be emitted upon process shutdown regarding a clean exit of the workers.
-        - Issue #12 fixed: gevent 0.13 doesn't use the same start_new_thread as gevent
-          1.0 which resulted in a fully monkey-patched environment halting due to the
-          wrong thread. Updated to use the older kazoo method of getting the real thread
-          module object.
-        
-        API Changes
-        ***********
-        
-        - The KazooClient handler is now officially exposed as KazooClient.handler
-          so that the appropriate sync objects can be used by end-users.
-        - Refactored ChildrenWatcher used by SetPartitioner into a publicly exposed
-          PatientChildrenWatch under recipe.watchers.
-        
-        Deprecations
-        ************
-        
-        - connect/connect_async has been renamed to start/start_async to better match
-          the stop to indicate connection handling. The prior names are aliased for
-          the time being.
-        
-        Recipes
-        *******
-        
-        - Added Barrier and DoubleBarrier implementation.
-        
-        0.2b1 (2012-07-27)
-        ------------------
-        
-        Bug Handling
-        ************
-        
-        - ZOOKEEPER-1318: SystemError is caught and rethrown as the proper invalid
-          state exception in older zookeeper python bindings where this issue is still
-          valid.
-        - ZOOKEEPER-1431: Install the latest zc-zookeeper-static library or use the
-          packaged ubuntu one for ubuntu 12.04 or later.
-        - ZOOKEEPER-553: State handling isn't checked via this method, we track it in
-          a simpler manner with the watcher to ensure we know the right state.
-        
-        Features
-        ********
-        
-        - Exponential backoff with jitter for retrying commands.
-        - Gevent 0.13 and 1.0b support.
-        - Lock, Party, SetPartitioner, and Election recipe implementations.
-        - Data and Children watching API's.
-        - State transition handling with listener registering to handle session state
-          changes (choose to fatal the app on session expiration, etc.)
-        - Zookeeper logging stream redirected into Python logging channel under the
-          name 'Zookeeper'.
-        - Base client library with handler support for threading and gevent async
-          environments.
-        
-Keywords: zookeeper lock leader configuration
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Intended Audience :: Developers
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Communications
-Classifier: Topic :: System :: Distributed Computing
-Classifier: Topic :: System :: Networking

+ 0 - 27
desktop/core/ext-py/kazoo-2.0/README.rst

@@ -1,27 +0,0 @@
-=====
-Kazoo
-=====
-
-``kazoo`` implements a higher level API to `Apache Zookeeper`_ for Python
-clients.
-
-See `the full docs`_ for more information.
-
-License
-=======
-
-``kazoo`` is offered under the Apache License 2.0.
-
-Authors
-=======
-
-``kazoo`` started under the `Nimbus Project`_ and through collaboration with
-the open-source community has been merged with code from `Mozilla`_ and the
-`Zope Corporation`_. It has since gathered an active community of over two
-dozen contributors.
-
-.. _Apache Zookeeper: http://zookeeper.apache.org/
-.. _the full docs: http://kazoo.rtfd.org/
-.. _Nimbus Project: http://www.nimbusproject.org/
-.. _Zope Corporation: http://zope.com/
-.. _Mozilla: http://www.mozilla.org/

+ 0 - 5
desktop/core/ext-py/kazoo-2.0/debian/changelog

@@ -1,5 +0,0 @@
-kazoo (0+git20130102) unstable; urgency=low
-
-  * Initial package.
-
- -- Neil Williams <neil@spladug.net>  Fri, 02 Jan 2013 23:20:03 -0800

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/debian/compat

@@ -1 +0,0 @@
-8

+ 0 - 50
desktop/core/ext-py/kazoo-2.0/debian/control

@@ -1,50 +0,0 @@
-Source: kazoo
-Section: python
-Priority: optional
-Maintainer: Neil Williams <neil@spladug.net>
-Build-Depends: python-setuptools (>= 0.6b3),
-               python-all (>= 2.6.6-3),
-               debhelper (>= 8.0.0),
-               python-sphinx (>= 1.0.7+dfsg) | python3-sphinx,
-Standards-Version: 3.9.3
-Homepage: https://kazoo.readthedocs.org
-X-Python-Version: >= 2.6
-
-Package: python-kazoo
-Architecture: all
-Depends: ${python:Depends}, ${misc:Depends}
-Description: higher level API to Apache Zookeeper for Python clients
- Kazoo features:
- .
-  * Support for gevent 0.13 and gevent 1.0
-  * Unified asynchronous API for use with greenlets or threads
-  * Lock, Party, Election, and Partitioner recipe implementations (more
-    implementations are in development)
-  * Data and Children Watchers
-  * Integrated testing helpers for Zookeeper clusters
-  * Simplified Zookeeper connection state tracking
-  * Pure-Python based implementation of the wire protocol, avoiding all the
-    memory leaks, lacking features, and debugging madness of the C library
- .
- Kazoo is heavily inspired by Netflix Curator simplifications and helpers.
-
-Package: python-kazoo-doc
-Architecture: all
-Section: doc
-Depends: ${misc:Depends}, ${sphinxdoc:Depends}
-Description: API to Apache Zookeeper for Python clients. - API documentation
- Kazoo features:
- .
-  * Support for gevent 0.13 and gevent 1.0
-  * Unified asynchronous API for use with greenlets or threads
-  * Lock, Party, Election, and Partitioner recipe implementations (more
-    implementations are in development)
-  * Data and Children Watchers
-  * Integrated testing helpers for Zookeeper clusters
-  * Simplified Zookeeper connection state tracking
-  * Pure-Python based implementation of the wire protocol, avoiding all the
-    memory leaks, lacking features, and debugging madness of the C library
- .
- Kazoo is heavily inspired by Netflix Curator simplifications and helpers.
- .
- This package contains the API documentation.

+ 0 - 13
desktop/core/ext-py/kazoo-2.0/debian/copyright

@@ -1,13 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: kazoo
-Source: https://github.com/python-zk/kazoo
-
-Files: *
-Copyright: 2012 Kazoo Team
-License: Apache-2.0
- See /usr/share/common-licenses/Apache-2.0
-
-Files: debian/*
-Copyright: 2012 Neil Williams <neil@spladug.net>
-License: Apache-2.0
- See /usr/share/common-licenses/Apache-2.0

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/debian/docs

@@ -1 +0,0 @@
-README.rst

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/debian/python-kazoo.install

@@ -1 +0,0 @@
-usr/lib/python2*

+ 0 - 18
desktop/core/ext-py/kazoo-2.0/debian/rules

@@ -1,18 +0,0 @@
-#!/usr/bin/make -f
-
-%:
-	dh $@ --with python2,sphinxdoc --buildsystem=python_distutils
-
-.PHONY: override_dh_installchangelogs
-override_dh_installchangelogs:
-	dh_installchangelogs CHANGES.rst
-
-.PHONY: override_dh_auto_build
-override_dh_auto_build:
-	sphinx-build -b html docs build/html
-	dh_auto_build
-
-.PHONY: override_dh_clean
-override_dh_clean:
-	rm -rf build
-	dh_clean

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/debian/source/format

@@ -1 +0,0 @@
-3.0 (quilt)

+ 0 - 93
desktop/core/ext-py/kazoo-2.0/kazoo/handlers/utils.py

@@ -1,93 +0,0 @@
-"""Kazoo handler helpers"""
-
-HAS_FNCTL = True
-try:
-    import fcntl
-except ImportError:  # pragma: nocover
-    HAS_FNCTL = False
-import functools
-import os
-
-
-def _set_fd_cloexec(fd):
-    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
-    fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
-
-
-def _set_default_tcpsock_options(module, sock):
-    sock.setsockopt(module.IPPROTO_TCP, module.TCP_NODELAY, 1)
-    if HAS_FNCTL:
-        _set_fd_cloexec(sock)
-    return sock
-
-
-def create_pipe():
-    """Create a non-blocking read/write pipe.
-    """
-    r, w = os.pipe()
-    if HAS_FNCTL:
-        fcntl.fcntl(r, fcntl.F_SETFL, os.O_NONBLOCK)
-        fcntl.fcntl(w, fcntl.F_SETFL, os.O_NONBLOCK)
-        _set_fd_cloexec(r)
-        _set_fd_cloexec(w)
-    return r, w
-
-
-def create_tcp_socket(module):
-    """Create a TCP socket with the CLOEXEC flag set.
-    """
-    type_ = module.SOCK_STREAM
-    if hasattr(module, 'SOCK_CLOEXEC'):  # pragma: nocover
-        # if available, set cloexec flag during socket creation
-        type_ |= module.SOCK_CLOEXEC
-    sock = module.socket(module.AF_INET, type_)
-    _set_default_tcpsock_options(module, sock)
-    return sock
-
-
-def create_tcp_connection(module, address, timeout=None):
-    if timeout is None:
-        # thanks to create_connection() developers for
-        # this ugliness...
-        timeout = module._GLOBAL_DEFAULT_TIMEOUT
-
-    sock = module.create_connection(address, timeout)
-    _set_default_tcpsock_options(module, sock)
-    return sock
-
-
-def capture_exceptions(async_result):
-    """Return a new decorated function that propagates the exceptions of the
-    wrapped function to an async_result.
-
-    :param async_result: An async result implementing :class:`IAsyncResult`
-
-    """
-    def capture(function):
-        @functools.wraps(function)
-        def captured_function(*args, **kwargs):
-            try:
-                return function(*args, **kwargs)
-            except Exception as exc:
-                async_result.set_exception(exc)
-        return captured_function
-    return capture
-
-
-def wrap(async_result):
-    """Return a new decorated function that propagates the return value or
-    exception of wrapped function to an async_result.  NOTE: Only propagates a
-    non-None return value.
-
-    :param async_result: An async result implementing :class:`IAsyncResult`
-
-    """
-    def capture(function):
-        @capture_exceptions(async_result)
-        def captured_function(*args, **kwargs):
-            value = function(*args, **kwargs)
-            if value is not None:
-                async_result.set(value)
-            return value
-        return captured_function
-    return capture

+ 0 - 26
desktop/core/ext-py/kazoo-2.0/kazoo/hosts.py

@@ -1,26 +0,0 @@
-import random
-
-try:
-    from urlparse import urlsplit
-except ImportError:
-    # try python3 then
-    from urllib.parse import urlsplit
-
-def collect_hosts(hosts, randomize=True):
-    """Collect a set of hosts and an optional chroot from a string."""
-    host_ports, chroot = hosts.partition("/")[::2]
-    chroot = "/" + chroot if chroot else None
-
-    result = []
-    for host_port in host_ports.split(","):
-        # put all complexity of dealing with
-        # IPv4 & IPv6 address:port on the urlsplit
-        res = urlsplit("xxx://" + host_port)
-        host = res.hostname
-        port = int(res.port) if res.port else 2181
-        result.append((host.strip(), port))
-
-    if randomize:
-        random.shuffle(result)
-
-    return result, chroot

+ 0 - 2
desktop/core/ext-py/kazoo-2.0/kazoo/loggingsupport.py

@@ -1,2 +0,0 @@
-BLATHER = 5 # log level for low-level debugging
-

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/__init__.py

@@ -1 +0,0 @@
-#

+ 0 - 5
desktop/core/ext-py/kazoo-2.0/kazoo/testing/__init__.py

@@ -1,5 +0,0 @@
-from kazoo.testing.harness import KazooTestCase
-from kazoo.testing.harness import KazooTestHarness
-
-
-__all__ = ('KazooTestHarness', 'KazooTestCase', )

+ 0 - 180
desktop/core/ext-py/kazoo-2.0/kazoo/testing/harness.py

@@ -1,180 +0,0 @@
-"""Kazoo testing harnesses"""
-import atexit
-import logging
-import os
-import uuid
-import threading
-import unittest
-
-from kazoo.client import KazooClient
-from kazoo.exceptions import NotEmptyError
-from kazoo.protocol.states import (
-    KazooState
-)
-from kazoo.testing.common import ZookeeperCluster
-from kazoo.protocol.connection import _SESSION_EXPIRED
-
-log = logging.getLogger(__name__)
-
-CLUSTER = None
-
-
-def get_global_cluster():
-    global CLUSTER
-    if CLUSTER is None:
-        ZK_HOME = os.environ.get("ZOOKEEPER_PATH")
-        ZK_CLASSPATH = os.environ.get("ZOOKEEPER_CLASSPATH")
-        ZK_PORT_OFFSET = int(os.environ.get("ZOOKEEPER_PORT_OFFSET", 20000))
-
-        assert ZK_HOME or ZK_CLASSPATH, (
-            "either ZOOKEEPER_PATH or ZOOKEEPER_CLASSPATH environment variable "
-            "must be defined.\n"
-            "For deb package installations this is /usr/share/java")
-
-        CLUSTER = ZookeeperCluster(
-            install_path=ZK_HOME,
-            classpath=ZK_CLASSPATH,
-            port_offset=ZK_PORT_OFFSET,
-        )
-        atexit.register(lambda cluster: cluster.terminate(), CLUSTER)
-    return CLUSTER
-
-
-class KazooTestHarness(unittest.TestCase):
-    """Harness for testing code that uses Kazoo
-
-    This object can be used directly or as a mixin. It supports starting
-    and stopping a complete ZooKeeper cluster locally and provides an
-    API for simulating errors and expiring sessions.
-
-    Example::
-
-        class MyTestCase(KazooTestHarness):
-            def setUp(self):
-                self.setup_zookeeper()
-
-                # additional test setup
-
-            def tearDown(self):
-                self.teardown_zookeeper()
-
-            def test_something(self):
-                something_that_needs_a_kazoo_client(self.client)
-
-            def test_something_else(self):
-                something_that_needs_zk_servers(self.servers)
-
-    """
-
-    def __init__(self, *args, **kw):
-        super(KazooTestHarness, self).__init__(*args, **kw)
-        self.client = None
-        self._clients = []
-
-    @property
-    def cluster(self):
-        return get_global_cluster()
-
-    @property
-    def servers(self):
-        return ",".join([s.address for s in self.cluster])
-
-    def _get_nonchroot_client(self):
-        return KazooClient(self.servers)
-
-    def _get_client(self, **kwargs):
-        c = KazooClient(self.hosts, **kwargs)
-        try:
-            self._clients.append(c)
-        except AttributeError:
-            self._client = [c]
-        return c
-
-    def expire_session(self, client_id=None):
-        """Force ZK to expire a client session
-
-        :param client_id: id of client to expire. If unspecified, the id of
-                          self.client will be used.
-
-        """
-        client_id = client_id or self.client.client_id
-
-        lost = threading.Event()
-        safe = threading.Event()
-
-        def watch_loss(state):
-            if state == KazooState.LOST:
-                lost.set()
-            if lost.is_set() and state == KazooState.CONNECTED:
-                safe.set()
-                return True
-
-        self.client.add_listener(watch_loss)
-
-        self.client._call(_SESSION_EXPIRED, None)
-
-        lost.wait(5)
-        if not lost.isSet():
-            raise Exception("Failed to get notified of session loss")
-
-        # Wait for the reconnect now
-        safe.wait(15)
-        if not safe.isSet():
-            raise Exception("Failed to see client reconnect")
-        self.client.retry(self.client.get_async, '/')
-
-    def setup_zookeeper(self, **client_options):
-        """Create a ZK cluster and chrooted :class:`KazooClient`
-
-        The cluster will only be created on the first invocation and won't be
-        fully torn down until exit.
-        """
-        if not self.cluster[0].running:
-            self.cluster.start()
-        namespace = "/kazootests" + uuid.uuid4().hex
-        self.hosts = self.servers + namespace
-
-        if 'timeout' not in client_options:
-            client_options['timeout'] = 0.8
-        self.client = self._get_client(**client_options)
-        self.client.start()
-        self.client.ensure_path("/")
-
-    def teardown_zookeeper(self):
-        """Clean up any ZNodes created during the test
-        """
-        if not self.cluster[0].running:
-            self.cluster.start()
-
-        tries = 0
-        if self.client and self.client.connected:
-            while tries < 3:
-                try:
-                    self.client.retry(self.client.delete, '/', recursive=True)
-                    break
-                except NotEmptyError:
-                    pass
-                tries += 1
-            self.client.stop()
-            self.client.close()
-            del self.client
-        else:
-            client = self._get_client()
-            client.start()
-            client.retry(client.delete, '/', recursive=True)
-            client.stop()
-            client.close()
-            del client
-
-        for client in self._clients:
-            client.stop()
-            del client
-        self._clients = None
-
-
-class KazooTestCase(KazooTestHarness):
-    def setUp(self):
-        self.setup_zookeeper()
-
-    def tearDown(self):
-        self.teardown_zookeeper()

+ 0 - 29
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_build.py

@@ -1,29 +0,0 @@
-import os
-
-from nose import SkipTest
-
-from kazoo.testing import KazooTestCase
-
-
-class TestBuildEnvironment(KazooTestCase):
-
-    def setUp(self):
-        KazooTestCase.setUp(self)
-        if not os.environ.get('TRAVIS'):
-            raise SkipTest('Only run build config tests on Travis.')
-
-    def test_gevent_version(self):
-        try:
-            import gevent
-        except ImportError:
-            raise SkipTest('gevent not available.')
-        env_version = os.environ.get('GEVENT_VERSION')
-        if env_version:
-            self.assertEqual(env_version, gevent.__version__)
-
-    def test_zookeeper_version(self):
-        server_version = self.client.server_version()
-        server_version = '.'.join([str(i) for i in server_version])
-        env_version = os.environ.get('ZOOKEEPER_VERSION')
-        if env_version:
-            self.assertEqual(env_version, server_version)

+ 0 - 35
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_counter.py

@@ -1,35 +0,0 @@
-import uuid
-
-from nose.tools import eq_
-
-from kazoo.testing import KazooTestCase
-
-
-class KazooCounterTests(KazooTestCase):
-
-    def _makeOne(self, **kw):
-        path = "/" + uuid.uuid4().hex
-        return self.client.Counter(path, **kw)
-
-    def test_int_counter(self):
-        counter = self._makeOne()
-        eq_(counter.value, 0)
-        counter += 2
-        counter + 1
-        eq_(counter.value, 3)
-        counter -= 3
-        counter - 1
-        eq_(counter.value, -1)
-
-    def test_float_counter(self):
-        counter = self._makeOne(default=0.0)
-        eq_(counter.value, 0.0)
-        counter += 2.1
-        eq_(counter.value, 2.1)
-        counter -= 3.1
-        eq_(counter.value, -1.0)
-
-    def test_errors(self):
-        counter = self._makeOne()
-        self.assertRaises(TypeError, counter.__add__, 2.1)
-        self.assertRaises(TypeError, counter.__add__, b"a")

+ 0 - 22
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_exceptions.py

@@ -1,22 +0,0 @@
-from unittest import TestCase
-
-
-class ExceptionsTestCase(TestCase):
-
-    def _get(self):
-        from kazoo import exceptions
-        return exceptions
-
-    def test_backwards_alias(self):
-        module = self._get()
-        self.assertTrue(getattr(module, 'NoNodeException'))
-        self.assertTrue(module.NoNodeException, module.NoNodeError)
-
-    def test_exceptions_code(self):
-        module = self._get()
-        exc_8 = module.EXCEPTIONS[-8]
-        self.assertTrue(isinstance(exc_8(), module.BadArgumentsError))
-
-    def test_invalid_code(self):
-        module = self._get()
-        self.assertRaises(RuntimeError, module.EXCEPTIONS.__getitem__, 666)

+ 0 - 517
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_lock.py

@@ -1,517 +0,0 @@
-import uuid
-import threading
-
-from nose.tools import eq_, ok_
-
-from kazoo.exceptions import CancelledError
-from kazoo.exceptions import LockTimeout
-from kazoo.testing import KazooTestCase
-from kazoo.tests.util import wait
-
-
-class KazooLockTests(KazooTestCase):
-    def setUp(self):
-        super(KazooLockTests, self).setUp()
-        self.lockpath = "/" + uuid.uuid4().hex
-
-        self.condition = threading.Condition()
-        self.released = threading.Event()
-        self.active_thread = None
-        self.cancelled_threads = []
-
-    def _thread_lock_acquire_til_event(self, name, lock, event):
-        try:
-            with lock:
-                with self.condition:
-                    eq_(self.active_thread, None)
-                    self.active_thread = name
-                    self.condition.notify_all()
-
-                event.wait()
-
-                with self.condition:
-                    eq_(self.active_thread, name)
-                    self.active_thread = None
-                    self.condition.notify_all()
-            self.released.set()
-        except CancelledError:
-            with self.condition:
-                self.cancelled_threads.append(name)
-                self.condition.notify_all()
-
-    def test_lock_one(self):
-        lock_name = uuid.uuid4().hex
-        lock = self.client.Lock(self.lockpath, lock_name)
-        event = threading.Event()
-
-        thread = threading.Thread(target=self._thread_lock_acquire_til_event,
-            args=(lock_name, lock, event))
-        thread.start()
-
-        lock2_name = uuid.uuid4().hex
-        anotherlock = self.client.Lock(self.lockpath, lock2_name)
-
-        # wait for any contender to show up on the lock
-        wait(anotherlock.contenders)
-        eq_(anotherlock.contenders(), [lock_name])
-
-        with self.condition:
-            while self.active_thread != lock_name:
-                self.condition.wait()
-
-        # release the lock
-        event.set()
-
-        with self.condition:
-            while self.active_thread:
-                self.condition.wait()
-        self.released.wait()
-        thread.join()
-
-    def test_lock(self):
-        threads = []
-        names = ["contender" + str(i) for i in range(5)]
-
-        contender_bits = {}
-
-        for name in names:
-            e = threading.Event()
-
-            l = self.client.Lock(self.lockpath, name)
-            t = threading.Thread(target=self._thread_lock_acquire_til_event,
-                args=(name, l, e))
-            contender_bits[name] = (t, e)
-            threads.append(t)
-
-        # acquire the lock ourselves first to make the others line up
-        lock = self.client.Lock(self.lockpath, "test")
-        lock.acquire()
-
-        for t in threads:
-            t.start()
-
-        # wait for everyone to line up on the lock
-        wait(lambda: len(lock.contenders()) == 6)
-        contenders = lock.contenders()
-
-        eq_(contenders[0], "test")
-        contenders = contenders[1:]
-        remaining = list(contenders)
-
-        # release the lock and contenders should claim it in order
-        lock.release()
-
-        for contender in contenders:
-            thread, event = contender_bits[contender]
-
-            with self.condition:
-                while not self.active_thread:
-                    self.condition.wait()
-                eq_(self.active_thread, contender)
-
-            eq_(lock.contenders(), remaining)
-            remaining = remaining[1:]
-
-            event.set()
-
-            with self.condition:
-                while self.active_thread:
-                    self.condition.wait()
-        for thread in threads:
-            thread.join()
-
-    def test_lock_reconnect(self):
-        event = threading.Event()
-        other_lock = self.client.Lock(self.lockpath, 'contender')
-        thread = threading.Thread(target=self._thread_lock_acquire_til_event,
-                                  args=('contender', other_lock, event))
-
-        # acquire the lock ourselves first to make the contender line up
-        lock = self.client.Lock(self.lockpath, "test")
-        lock.acquire()
-
-        thread.start()
-        # wait for the contender to line up on the lock
-        wait(lambda: len(lock.contenders()) == 2)
-        eq_(lock.contenders(), ['test', 'contender'])
-
-        self.expire_session()
-
-        lock.release()
-
-        with self.condition:
-            while not self.active_thread:
-                self.condition.wait()
-            eq_(self.active_thread, 'contender')
-
-        event.set()
-        thread.join()
-
-    def test_lock_non_blocking(self):
-        lock_name = uuid.uuid4().hex
-        lock = self.client.Lock(self.lockpath, lock_name)
-        event = threading.Event()
-
-        thread = threading.Thread(target=self._thread_lock_acquire_til_event,
-            args=(lock_name, lock, event))
-        thread.start()
-
-        lock1 = self.client.Lock(self.lockpath, lock_name)
-
-        # wait for the thread to acquire the lock
-        with self.condition:
-            if not self.active_thread:
-                self.condition.wait(5)
-
-        ok_(not lock1.acquire(blocking=False))
-        eq_(lock.contenders(), [lock_name])  # just one - itself
-
-        event.set()
-        thread.join()
-
-    def test_lock_fail_first_call(self):
-        event1 = threading.Event()
-        lock1 = self.client.Lock(self.lockpath, "one")
-        thread1 = threading.Thread(target=self._thread_lock_acquire_til_event,
-            args=("one", lock1, event1))
-        thread1.start()
-
-        # wait for this thread to acquire the lock
-        with self.condition:
-            if not self.active_thread:
-                self.condition.wait(5)
-                eq_(self.active_thread, "one")
-        eq_(lock1.contenders(), ["one"])
-        event1.set()
-        thread1.join()
-
-    def test_lock_cancel(self):
-        event1 = threading.Event()
-        lock1 = self.client.Lock(self.lockpath, "one")
-        thread1 = threading.Thread(target=self._thread_lock_acquire_til_event,
-            args=("one", lock1, event1))
-        thread1.start()
-
-        # wait for this thread to acquire the lock
-        with self.condition:
-            if not self.active_thread:
-                self.condition.wait(5)
-                eq_(self.active_thread, "one")
-
-        client2 = self._get_client()
-        client2.start()
-        event2 = threading.Event()
-        lock2 = client2.Lock(self.lockpath, "two")
-        thread2 = threading.Thread(target=self._thread_lock_acquire_til_event,
-            args=("two", lock2, event2))
-        thread2.start()
-
-        # this one should block in acquire. check that it is a contender
-        wait(lambda: len(lock2.contenders()) > 1)
-        eq_(lock2.contenders(), ["one", "two"])
-
-        lock2.cancel()
-        with self.condition:
-            if not "two" in self.cancelled_threads:
-                self.condition.wait()
-                assert "two" in self.cancelled_threads
-
-        eq_(lock2.contenders(), ["one"])
-
-        thread2.join()
-        event1.set()
-        thread1.join()
-        client2.stop()
-
-    def test_lock_double_calls(self):
-        lock1 = self.client.Lock(self.lockpath, "one")
-        lock1.acquire()
-        lock1.acquire()
-        lock1.release()
-        lock1.release()
-
-    def test_lock_reacquire(self):
-        lock = self.client.Lock(self.lockpath, "one")
-        lock.acquire()
-        lock.release()
-        lock.acquire()
-        lock.release()
-
-    def test_lock_timeout(self):
-        timeout = 3
-        e = threading.Event()
-        started = threading.Event()
-
-        # In the background thread, acquire the lock and wait thrice the time
-        # that the main thread is going to wait to acquire the lock.
-        lock1 = self.client.Lock(self.lockpath, "one")
-
-        def _thread(lock, event, timeout):
-            with lock:
-                started.set()
-                event.wait(timeout)
-                if not event.isSet():
-                    # Eventually fail to avoid hanging the tests
-                    self.fail("lock2 never timed out")
-
-        t = threading.Thread(target=_thread, args=(lock1, e, timeout * 3))
-        t.start()
-
-        # Start the main thread's kazoo client and try to acquire the lock
-        # but give up after `timeout` seconds
-        client2 = self._get_client()
-        client2.start()
-        started.wait(5)
-        self.assertTrue(started.isSet())
-        lock2 = client2.Lock(self.lockpath, "two")
-        try:
-            lock2.acquire(timeout=timeout)
-        except LockTimeout:
-            # A timeout is the behavior we're expecting, since the background
-            # thread should still be holding onto the lock
-            pass
-        else:
-            self.fail("Main thread unexpectedly acquired the lock")
-        finally:
-            # Cleanup
-            e.set()
-            t.join()
-            client2.stop()
-
-
-class TestSemaphore(KazooTestCase):
-    def setUp(self):
-        super(TestSemaphore, self).setUp()
-        self.lockpath = "/" + uuid.uuid4().hex
-
-        self.condition = threading.Condition()
-        self.released = threading.Event()
-        self.active_thread = None
-        self.cancelled_threads = []
-
-    def test_basic(self):
-        sem1 = self.client.Semaphore(self.lockpath)
-        sem1.acquire()
-        sem1.release()
-
-    def test_lock_one(self):
-        sem1 = self.client.Semaphore(self.lockpath, max_leases=1)
-        sem2 = self.client.Semaphore(self.lockpath, max_leases=1)
-        started = threading.Event()
-        event = threading.Event()
-
-        sem1.acquire()
-
-        def sema_one():
-            started.set()
-            with sem2:
-                event.set()
-
-        thread = threading.Thread(target=sema_one, args=())
-        thread.start()
-        started.wait(10)
-
-        self.assertFalse(event.is_set())
-
-        sem1.release()
-        event.wait(10)
-        self.assert_(event.is_set())
-        thread.join()
-
-    def test_non_blocking(self):
-        sem1 = self.client.Semaphore(
-            self.lockpath, identifier='sem1', max_leases=2)
-        sem2 = self.client.Semaphore(
-            self.lockpath, identifier='sem2', max_leases=2)
-        sem3 = self.client.Semaphore(
-            self.lockpath, identifier='sem3', max_leases=2)
-
-        sem1.acquire()
-        sem2.acquire()
-        ok_(not sem3.acquire(blocking=False))
-        eq_(set(sem1.lease_holders()), set(['sem1', 'sem2']))
-        sem2.release()
-        # the next line isn't required, but avoids timing issues in tests
-        sem3.acquire()
-        eq_(set(sem1.lease_holders()), set(['sem1', 'sem3']))
-        sem1.release()
-        sem3.release()
-
-    def test_non_blocking_release(self):
-        sem1 = self.client.Semaphore(
-            self.lockpath, identifier='sem1', max_leases=1)
-        sem2 = self.client.Semaphore(
-            self.lockpath, identifier='sem2', max_leases=1)
-        sem1.acquire()
-        sem2.acquire(blocking=False)
-
-        # make sure there's no shutdown / cleanup error
-        sem1.release()
-        sem2.release()
-
-    def test_holders(self):
-        started = threading.Event()
-        event = threading.Event()
-
-        def sema_one():
-            with self.client.Semaphore(self.lockpath, 'fred', max_leases=1):
-                started.set()
-                event.wait()
-
-        thread = threading.Thread(target=sema_one, args=())
-        thread.start()
-        started.wait()
-        sem1 = self.client.Semaphore(self.lockpath)
-        holders = sem1.lease_holders()
-        eq_(holders, ['fred'])
-        event.set()
-        thread.join()
-
-    def test_semaphore_cancel(self):
-        sem1 = self.client.Semaphore(self.lockpath, 'fred', max_leases=1)
-        sem2 = self.client.Semaphore(self.lockpath, 'george', max_leases=1)
-        sem1.acquire()
-        started = threading.Event()
-        event = threading.Event()
-
-        def sema_one():
-            started.set()
-            try:
-                with sem2:
-                    started.set()
-            except CancelledError:
-                event.set()
-
-        thread = threading.Thread(target=sema_one, args=())
-        thread.start()
-        started.wait()
-        eq_(sem1.lease_holders(), ['fred'])
-        eq_(event.is_set(), False)
-        sem2.cancel()
-        event.wait()
-        eq_(event.is_set(), True)
-        thread.join()
-
-    def test_multiple_acquire_and_release(self):
-        sem1 = self.client.Semaphore(self.lockpath, 'fred', max_leases=1)
-        sem1.acquire()
-        sem1.acquire()
-
-        eq_(True, sem1.release())
-        eq_(False, sem1.release())
-
-    def test_handle_session_loss(self):
-        expire_semaphore = self.client.Semaphore(self.lockpath, 'fred',
-                                                 max_leases=1)
-
-        client = self._get_client()
-        client.start()
-        lh_semaphore = client.Semaphore(self.lockpath, 'george', max_leases=1)
-        lh_semaphore.acquire()
-
-        started = threading.Event()
-        event = threading.Event()
-        event2 = threading.Event()
-
-        def sema_one():
-            started.set()
-            with expire_semaphore:
-                event.set()
-                event2.wait()
-
-        thread = threading.Thread(target=sema_one, args=())
-        thread.start()
-
-        started.wait()
-        eq_(lh_semaphore.lease_holders(), ['george'])
-
-        # Fired in a separate thread to make sure we can see the effect
-        expired = threading.Event()
-
-        def expire():
-            self.expire_session()
-            expired.set()
-
-        thread = threading.Thread(target=expire, args=())
-        thread.start()
-        expire_semaphore.wake_event.wait()
-        expired.wait()
-
-        lh_semaphore.release()
-        client.stop()
-
-        event.wait(5)
-        eq_(expire_semaphore.lease_holders(), ['fred'])
-        event2.set()
-        thread.join()
-
-    def test_inconsistent_max_leases(self):
-        sem1 = self.client.Semaphore(self.lockpath, max_leases=1)
-        sem2 = self.client.Semaphore(self.lockpath, max_leases=2)
-
-        sem1.acquire()
-        self.assertRaises(ValueError, sem2.acquire)
-
-    def test_inconsistent_max_leases_other_data(self):
-        sem1 = self.client.Semaphore(self.lockpath, max_leases=1)
-        sem2 = self.client.Semaphore(self.lockpath, max_leases=2)
-
-        self.client.ensure_path(self.lockpath)
-        self.client.set(self.lockpath, b'a$')
-
-        sem1.acquire()
-        # sem2 thinks it's ok to have two lease holders
-        ok_(sem2.acquire(blocking=False))
-
-    def test_reacquire(self):
-        lock = self.client.Semaphore(self.lockpath)
-        lock.acquire()
-        lock.release()
-        lock.acquire()
-        lock.release()
-
-    def test_acquire_after_cancelled(self):
-        lock = self.client.Semaphore(self.lockpath)
-        self.assertTrue(lock.acquire())
-        self.assertTrue(lock.release())
-        lock.cancel()
-        self.assertTrue(lock.cancelled)
-        self.assertTrue(lock.acquire())
-
-    def test_timeout(self):
-        timeout = 3
-        e = threading.Event()
-        started = threading.Event()
-
-        # In the background thread, acquire the lock and wait thrice the time
-        # that the main thread is going to wait to acquire the lock.
-        sem1 = self.client.Semaphore(self.lockpath, "one")
-
-        def _thread(sem, event, timeout):
-            with sem:
-                started.set()
-                event.wait(timeout)
-                if not event.isSet():
-                    # Eventually fail to avoid hanging the tests
-                    self.fail("sem2 never timed out")
-
-        t = threading.Thread(target=_thread, args=(sem1, e, timeout * 3))
-        t.start()
-
-        # Start the main thread's kazoo client and try to acquire the lock
-        # but give up after `timeout` seconds
-        client2 = self._get_client()
-        client2.start()
-        started.wait(5)
-        self.assertTrue(started.isSet())
-        sem2 = client2.Semaphore(self.lockpath, "two")
-        try:
-            sem2.acquire(timeout=timeout)
-        except LockTimeout:
-            # A timeout is the behavior we're expecting, since the background
-            # thread will still be holding onto the lock
-            e.set()
-        finally:
-            # Cleanup
-            t.join()
-            client2.stop()

+ 0 - 92
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_partitioner.py

@@ -1,92 +0,0 @@
-import uuid
-import time
-
-from nose.tools import eq_
-
-from kazoo.testing import KazooTestCase
-from kazoo.recipe.partitioner import PartitionState
-
-
-class KazooPartitionerTests(KazooTestCase):
-    def setUp(self):
-        super(KazooPartitionerTests, self).setUp()
-        self.path = "/" + uuid.uuid4().hex
-
-    def test_party_of_one(self):
-        partitioner = self.client.SetPartitioner(
-            self.path, set=(1, 2, 3), time_boundary=0.2)
-        partitioner.wait_for_acquire(14)
-        eq_(partitioner.state, PartitionState.ACQUIRED)
-        eq_(list(partitioner), [1, 2, 3])
-        partitioner.finish()
-
-    def test_party_of_two(self):
-        partitioners = [self.client.SetPartitioner(self.path, (1, 2),
-                        identifier="p%s" % i, time_boundary=0.2)
-                        for i in range(2)]
-
-        partitioners[0].wait_for_acquire(14)
-        partitioners[1].wait_for_acquire(14)
-        eq_(list(partitioners[0]), [1])
-        eq_(list(partitioners[1]), [2])
-        partitioners[0].finish()
-        time.sleep(0.1)
-        eq_(partitioners[1].release, True)
-        partitioners[1].finish()
-
-    def test_party_expansion(self):
-        partitioners = [self.client.SetPartitioner(self.path, (1, 2, 3),
-                        identifier="p%s" % i, time_boundary=0.2)
-                        for i in range(2)]
-
-        partitioners[0].wait_for_acquire(14)
-        partitioners[1].wait_for_acquire(14)
-        eq_(partitioners[0].state, PartitionState.ACQUIRED)
-        eq_(partitioners[1].state, PartitionState.ACQUIRED)
-
-        eq_(list(partitioners[0]), [1, 3])
-        eq_(list(partitioners[1]), [2])
-
-        # Add another partition, wait till they settle
-        partitioners.append(self.client.SetPartitioner(self.path, (1, 2, 3),
-                            identifier="p2", time_boundary=0.2))
-        time.sleep(0.1)
-        eq_(partitioners[0].release, True)
-        for p in partitioners[:-1]:
-            p.release_set()
-
-        for p in partitioners:
-            p.wait_for_acquire(14)
-
-        eq_(list(partitioners[0]), [1])
-        eq_(list(partitioners[1]), [2])
-        eq_(list(partitioners[2]), [3])
-
-        for p in partitioners:
-            p.finish()
-
-    def test_more_members_than_set_items(self):
-        partitioners = [self.client.SetPartitioner(self.path, (1,),
-                        identifier="p%s" % i, time_boundary=0.2)
-                        for i in range(2)]
-
-        partitioners[0].wait_for_acquire(14)
-        partitioners[1].wait_for_acquire(14)
-        eq_(partitioners[0].state, PartitionState.ACQUIRED)
-        eq_(partitioners[1].state, PartitionState.ACQUIRED)
-
-        eq_(list(partitioners[0]), [1])
-        eq_(list(partitioners[1]), [])
-
-        for p in partitioners:
-            p.finish()
-
-    def test_party_session_failure(self):
-        partitioner = self.client.SetPartitioner(
-            self.path, set=(1, 2, 3), time_boundary=0.2)
-        partitioner.wait_for_acquire(14)
-        eq_(partitioner.state, PartitionState.ACQUIRED)
-        # simulate session failure
-        partitioner._fail_out()
-        partitioner.release_set()
-        self.assertTrue(partitioner.failed)

+ 0 - 98
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_paths.py

@@ -1,98 +0,0 @@
-import sys
-from unittest import TestCase
-
-from kazoo.protocol import paths
-
-
-if sys.version_info > (3, ):  # pragma: nocover
-    def u(s):
-        return s
-else:  # pragma: nocover
-    def u(s):
-        return unicode(s, "unicode_escape")
-
-
-class NormPathTestCase(TestCase):
-
-    def test_normpath(self):
-        self.assertEqual(paths.normpath('/a/b'), '/a/b')
-
-    def test_normpath_empty(self):
-        self.assertEqual(paths.normpath(''), '')
-
-    def test_normpath_unicode(self):
-        self.assertEqual(paths.normpath(u('/\xe4/b')), u('/\xe4/b'))
-
-    def test_normpath_dots(self):
-        self.assertEqual(paths.normpath('/a./b../c'), '/a./b../c')
-
-    def test_normpath_slash(self):
-        self.assertEqual(paths.normpath('/'), '/')
-
-    def test_normpath_multiple_slashes(self):
-        self.assertEqual(paths.normpath('//'), '/')
-        self.assertEqual(paths.normpath('//a/b'), '/a/b')
-        self.assertEqual(paths.normpath('/a//b//'), '/a/b')
-        self.assertEqual(paths.normpath('//a////b///c/'), '/a/b/c')
-
-    def test_normpath_relative(self):
-        self.assertRaises(ValueError, paths.normpath, './a/b')
-        self.assertRaises(ValueError, paths.normpath, '/a/../b')
-
-
-class JoinTestCase(TestCase):
-
-    def test_join(self):
-        self.assertEqual(paths.join('/a'), '/a')
-        self.assertEqual(paths.join('/a', 'b/'), '/a/b/')
-        self.assertEqual(paths.join('/a', 'b', 'c'), '/a/b/c')
-
-    def test_join_empty(self):
-        self.assertEqual(paths.join(''), '')
-        self.assertEqual(paths.join('', 'a', 'b'), 'a/b')
-        self.assertEqual(paths.join('/a', '', 'b/', 'c'), '/a/b/c')
-
-    def test_join_absolute(self):
-        self.assertEqual(paths.join('/a/b', '/c'), '/c')
-
-
-class IsAbsTestCase(TestCase):
-
-    def test_isabs(self):
-        self.assertTrue(paths.isabs('/'))
-        self.assertTrue(paths.isabs('/a'))
-        self.assertTrue(paths.isabs('/a//b/c'))
-        self.assertTrue(paths.isabs('//a/b'))
-
-    def test_isabs_false(self):
-        self.assertFalse(paths.isabs(''))
-        self.assertFalse(paths.isabs('a/'))
-        self.assertFalse(paths.isabs('a/../'))
-
-
-class BaseNameTestCase(TestCase):
-
-    def test_basename(self):
-        self.assertEquals(paths.basename(''), '')
-        self.assertEquals(paths.basename('/'), '')
-        self.assertEquals(paths.basename('//a'), 'a')
-        self.assertEquals(paths.basename('//a/'), '')
-        self.assertEquals(paths.basename('/a/b.//c..'), 'c..')
-
-
-class PrefixRootTestCase(TestCase):
-
-    def test_prefix_root(self):
-        self.assertEquals(paths._prefix_root('/a/', 'b/c'), '/a/b/c')
-        self.assertEquals(paths._prefix_root('/a/b', 'c/d'), '/a/b/c/d')
-        self.assertEquals(paths._prefix_root('/a', '/b/c'), '/a/b/c')
-        self.assertEquals(paths._prefix_root('/a', '//b/c.'), '/a/b/c.')
-
-
-class NormRootTestCase(TestCase):
-
-    def test_norm_root(self):
-        self.assertEquals(paths._norm_root(''), '/')
-        self.assertEquals(paths._norm_root('/'), '/')
-        self.assertEquals(paths._norm_root('//a'), '/a')
-        self.assertEquals(paths._norm_root('//a./b'), '/a./b')

+ 0 - 179
desktop/core/ext-py/kazoo-2.0/kazoo/tests/test_queue.py

@@ -1,179 +0,0 @@
-import uuid
-
-from nose import SkipTest
-from nose.tools import eq_, ok_
-
-from kazoo.testing import KazooTestCase
-from kazoo.tests.util import TRAVIS_ZK_VERSION
-
-
-class KazooQueueTests(KazooTestCase):
-
-    def _makeOne(self):
-        path = "/" + uuid.uuid4().hex
-        return self.client.Queue(path)
-
-    def test_queue_validation(self):
-        queue = self._makeOne()
-        self.assertRaises(TypeError, queue.put, {})
-        self.assertRaises(TypeError, queue.put, b"one", b"100")
-        self.assertRaises(TypeError, queue.put, b"one", 10.0)
-        self.assertRaises(ValueError, queue.put, b"one", -100)
-        self.assertRaises(ValueError, queue.put, b"one", 100000)
-
-    def test_empty_queue(self):
-        queue = self._makeOne()
-        eq_(len(queue), 0)
-        self.assertTrue(queue.get() is None)
-        eq_(len(queue), 0)
-
-    def test_queue(self):
-        queue = self._makeOne()
-        queue.put(b"one")
-        queue.put(b"two")
-        queue.put(b"three")
-        eq_(len(queue), 3)
-
-        eq_(queue.get(), b"one")
-        eq_(queue.get(), b"two")
-        eq_(queue.get(), b"three")
-        eq_(len(queue), 0)
-
-    def test_priority(self):
-        queue = self._makeOne()
-        queue.put(b"four", priority=101)
-        queue.put(b"one", priority=0)
-        queue.put(b"two", priority=0)
-        queue.put(b"three", priority=10)
-
-        eq_(queue.get(), b"one")
-        eq_(queue.get(), b"two")
-        eq_(queue.get(), b"three")
-        eq_(queue.get(), b"four")
-
-
-class KazooLockingQueueTests(KazooTestCase):
-
-    def setUp(self):
-        KazooTestCase.setUp(self)
-        skip = False
-        if TRAVIS_ZK_VERSION and TRAVIS_ZK_VERSION < (3, 4):
-            skip = True
-        elif TRAVIS_ZK_VERSION and TRAVIS_ZK_VERSION >= (3, 4):
-            skip = False
-        else:
-            ver = self.client.server_version()
-            if ver[1] < 4:
-                skip = True
-        if skip:
-            raise SkipTest("Must use Zookeeper 3.4 or above")
-
-    def _makeOne(self):
-        path = "/" + uuid.uuid4().hex
-        return self.client.LockingQueue(path)
-
-    def test_queue_validation(self):
-        queue = self._makeOne()
-        self.assertRaises(TypeError, queue.put, {})
-        self.assertRaises(TypeError, queue.put, b"one", b"100")
-        self.assertRaises(TypeError, queue.put, b"one", 10.0)
-        self.assertRaises(ValueError, queue.put, b"one", -100)
-        self.assertRaises(ValueError, queue.put, b"one", 100000)
-        self.assertRaises(TypeError, queue.put_all, {})
-        self.assertRaises(TypeError, queue.put_all, [{}])
-        self.assertRaises(TypeError, queue.put_all, [b"one"], b"100")
-        self.assertRaises(TypeError, queue.put_all, [b"one"], 10.0)
-        self.assertRaises(ValueError, queue.put_all, [b"one"], -100)
-        self.assertRaises(ValueError, queue.put_all, [b"one"], 100000)
-
-    def test_empty_queue(self):
-        queue = self._makeOne()
-        eq_(len(queue), 0)
-        self.assertTrue(queue.get(0) is None)
-        eq_(len(queue), 0)
-
-    def test_queue(self):
-        queue = self._makeOne()
-        queue.put(b"one")
-        queue.put_all([b"two", b"three"])
-        eq_(len(queue), 3)
-
-        ok_(not queue.consume())
-        ok_(not queue.holds_lock())
-        eq_(queue.get(1), b"one")
-        ok_(queue.holds_lock())
-        # Without consuming, should return the same element
-        eq_(queue.get(1), b"one")
-        ok_(queue.consume())
-        ok_(not queue.holds_lock())
-        eq_(queue.get(1), b"two")
-        ok_(queue.holds_lock())
-        ok_(queue.consume())
-        ok_(not queue.holds_lock())
-        eq_(queue.get(1), b"three")
-        ok_(queue.holds_lock())
-        ok_(queue.consume())
-        ok_(not queue.holds_lock())
-        ok_(not queue.consume())
-        eq_(len(queue), 0)
-
-    def test_consume(self):
-        queue = self._makeOne()
-
-        queue.put(b"one")
-        ok_(not queue.consume())
-        queue.get(.1)
-        ok_(queue.consume())
-        ok_(not queue.consume())
-
-    def test_holds_lock(self):
-        queue = self._makeOne()
-
-        ok_(not queue.holds_lock())
-        queue.put(b"one")
-        queue.get(.1)
-        ok_(queue.holds_lock())
-        queue.consume()
-        ok_(not queue.holds_lock())
-
-    def test_priority(self):
-        queue = self._makeOne()
-        queue.put(b"four", priority=101)
-        queue.put(b"one", priority=0)
-        queue.put(b"two", priority=0)
-        queue.put(b"three", priority=10)
-
-        eq_(queue.get(1), b"one")
-        ok_(queue.consume())
-        eq_(queue.get(1), b"two")
-        ok_(queue.consume())
-        eq_(queue.get(1), b"three")
-        ok_(queue.consume())
-        eq_(queue.get(1), b"four")
-        ok_(queue.consume())
-
-    def test_concurrent_execution(self):
-        queue = self._makeOne()
-        value1 = []
-        value2 = []
-        value3 = []
-        event1 = self.client.handler.event_object()
-        event2 = self.client.handler.event_object()
-        event3 = self.client.handler.event_object()
-
-        def get_concurrently(value, event):
-            q = self.client.LockingQueue(queue.path)
-            value.append(q.get(.1))
-            event.set()
-
-        self.client.handler.spawn(get_concurrently, value1, event1)
-        self.client.handler.spawn(get_concurrently, value2, event2)
-        self.client.handler.spawn(get_concurrently, value3, event3)
-        queue.put(b"one")
-        event1.wait(.2)
-        event2.wait(.2)
-        event3.wait(.2)
-
-        result = value1 + value2 + value3
-        eq_(result.count(b"one"), 1)
-        eq_(result.count(None), 2)

+ 0 - 3
desktop/core/ext-py/kazoo-2.0/requirements.txt

@@ -1,3 +0,0 @@
-coverage==3.7.1
-mock==1.0.1
-nose==1.3.1

+ 0 - 1
desktop/core/ext-py/kazoo-2.0/requirements_gevent.txt

@@ -1 +0,0 @@
-greenlet==0.4.2

+ 0 - 4
desktop/core/ext-py/kazoo-2.0/requirements_sphinx.txt

@@ -1,4 +0,0 @@
-Jinja2==2.7.2
-Pygments==1.6
-Sphinx==1.2.2
-docutils==0.11

+ 0 - 14
desktop/core/ext-py/kazoo-2.0/setup.cfg

@@ -1,14 +0,0 @@
-[easy_install]
-
-[egg_info]
-tag_build = 
-tag_date = 0
-tag_svn_revision = 0
-
-[nosetests]
-cover-package = kazoo
-nocapture = 1
-cover-erase = 1
-where = kazoo
-cover-inclusive = 1
-

+ 802 - 0
desktop/core/ext-py/kazoo-2.8.0/CHANGES.md

@@ -0,0 +1,802 @@
+<a name="2.8.0"></a>
+## 2.8.0 (2020-07-11)
+
+
+#### Features
+
+* **chore:**  using Github templates for issues and PRs (#610) ([eddc0976](https://github.com/python-zk/kazoo/commit/eddc0976bf1ef9d9fb97990cebbc3f9b1abe9d7d))
+* **core:**
+  *  Use strict regex to identify lock contenders. ([cc8ce892](https://github.com/python-zk/kazoo/commit/cc8ce8929116a1f0a2f0d088afa82ac9576395dc))
+  *  Support additionaal lock contenter patterns ([225eeecb](https://github.com/python-zk/kazoo/commit/225eeecbe66c10d46dc7928681783d17f389f13a))
+* **tests:**
+  *  Disable problematic hound-flake8-black integration. ([75f62a0d](https://github.com/python-zk/kazoo/commit/75f62a0dd40a9f9bdefcb04cea5ee5fcd3438c0e))
+  *  Move to pytest ([de97d74b](https://github.com/python-zk/kazoo/commit/de97d74b50b62cd2f0cddc2a04e150575d9c6bc7))
+  *  add Python 3.8 and remove Python 3.6 from the testing suite (#611) ([e4f808f7](https://github.com/python-zk/kazoo/commit/e4f808f7f0fe17e7e01468a2c54684f048e12b52))
+
+#### Performance
+
+* **core:**  Use chain.from_iterable in threading.py (#614) ([13c73ec5](https://github.com/python-zk/kazoo/commit/13c73ec5f4d4f2215deb987a059051bb821674ca))
+
+#### Bug Fixes
+
+* **core:**
+  *  handle SSL_WANT_READ/WRITE errors (#619) ([cbdc4749](https://github.com/python-zk/kazoo/commit/cbdc4749edb5879099c1f9b832c055d9eeb52dea), closes [#618](https://github.com/python-zk/kazoo/issues/618))
+  *  '"is" with a literal' syntax errors (#609) ([6b6ffe62](https://github.com/python-zk/kazoo/commit/6b6ffe62a073d1ed5413c65c2d8ec94ea2fa1760))
+  *  sync() return should be unchrooted ([cbde70ac](https://github.com/python-zk/kazoo/commit/cbde70ac87435afbbacc9806c675184c7f778343), closes [#601](https://github.com/python-zk/kazoo/issues/601))
+
+#### Chore
+
+* **core:**  Update matrix: add pypy3, drop py27 ([522189da](https://github.com/python-zk/kazoo/commit/522189da0f238faafc8f1db34f682f49b15ec503))
+* **tests:**  Add coverage report on codecov.io ([bb475843](https://github.com/python-zk/kazoo/commit/bb475843905af1a2d25b1f5834085c85c28bb175))
+
+
+
+<a name="2.7.0"></a>
+## 2.7.0 (2020-03-13)
+
+#### Features
+
+* **CI:**  Keep only Python 3.{6,7} to CI and bump ZK versions to latests (#574) ([c293aabf](https://github.com/python-zk/kazoo/commit/c293aabf39676b94006cf736f9f75392637b8292))
+* **core:**
+  *  run SASL Kerberos tests as part of build ([5c461bdf](https://github.com/python-zk/kazoo/commit/5c461bdff50efd762805b40fbe283b194d175c61))
+  *  Add create2 support ([1d81f96a](https://github.com/python-zk/kazoo/commit/1d81f96a77a6fd7ae2476cd798a5cb4bf1c1d9a2))
+  *  closed states instead of lost states (#573) ([961b2f3b](https://github.com/python-zk/kazoo/commit/961b2f3be557f8314ab41f75444125222638f9cc))
+  *  improve SASL interface (#546) ([cd49b3fa](https://github.com/python-zk/kazoo/commit/cd49b3fa01136848c5e6bfafb4c241b9704f249d))
+* **recipe:**  add support for curator SharedCount recipe (#559) ([88b657a0](https://github.com/python-zk/kazoo/commit/88b657a0977161f3815657878ba48f82a97a3846), closes [#558](https://github.com/python-zk/kazoo/issues/558))
+* **utils:**  extend create_tcp_connection utility (#568) ([ab0cd00c](https://github.com/python-zk/kazoo/commit/ab0cd00c12624b07dcc3b2d62aa96f8f1e658f65))
+
+#### Bug Fixes
+
+* **CI:**  deploying only for 1 job ([0ba3634d](https://github.com/python-zk/kazoo/commit/0ba3634d99740c9ccc2dd01924a36dffff262f8e))
+* **core:**
+  *  allow requests to be queued in CONNECTING state (#374) (#588) ([a636d7a6](https://github.com/python-zk/kazoo/commit/a636d7a6bb88ab9080e902983b10c8f0f1bf60a8))
+  *  Implement proper retry backoff logic with jitter. ([0bb0659c](https://github.com/python-zk/kazoo/commit/0bb0659cf3fd73714a9d75b093a75c7122e116e6))
+  *  when connection fails, close the ConnectionHandler (#577) (#579) ([c7e80503](https://github.com/python-zk/kazoo/commit/c7e80503f3be97d26ff2de27f9e424070c8181bb))
+* **recipe:**  crash if None in znode (#569) ([ded79467](https://github.com/python-zk/kazoo/commit/ded79467a8254e43841dfeb69f7c3baa1980232c))
+* **tests:**
+  *  Disable JAAS isInitiator for Server ([933b38b5](https://github.com/python-zk/kazoo/commit/933b38b5506d84e05ed6f6c5c8c208a3367400da))
+  *  deactivate TCP port that was enabled by default. ([d7bed550](https://github.com/python-zk/kazoo/commit/d7bed550fee1b861eb2ee81cc685e6d08ee35c34))
+  *  capitalize the default_domain value ([7fd22bfd](https://github.com/python-zk/kazoo/commit/7fd22bfd1992b90042db7946949ce992ddfd1821))
+  *  weaker crypto when configuring Kerberos ([844df87a](https://github.com/python-zk/kazoo/commit/844df87ac83e72c155367cfe4ff4d52d34d46c99))
+  *  prefix with toxinidir variable with a / to ensure path to ensure-zookeeper-env.sh is correct ([c4d42ca7](https://github.com/python-zk/kazoo/commit/c4d42ca7722dec5332ecd4524e8d802a81e2ddca))
+  *  specify -Dfile.encoding=UTF-8 when starting the ZK JVM ([5764da0b](https://github.com/python-zk/kazoo/commit/5764da0b3c25556cb6760f68c51b387f2fd8307b))
+
+
+
+<a name="2.6.1"></a>
+### 2.6.1 (2019-01-22)
+
+
+#### Bug Fixes
+
+* **client:**  add missing paren (#550) ([1452a48f](https://github.com/python-zk/kazoo/commit/1452a48f3070fe9034314476a6fdb94ca206dede))
+* **core:**
+  *  support deprecated KazooRetry argument (#545) ([4242da80](https://github.com/python-zk/kazoo/commit/4242da801e8da7b76d7e88e37c3948f97a2b5aae))
+  *  reduce timeout for the first Connect() request (#540) ([2ae392e6](https://github.com/python-zk/kazoo/commit/2ae392e69c4b2daca5d8e7f0e79b7ce90423e65c))
+* **handlers:**  make AsyncResult call all registered callbacks instantly if the handler has stopped running (#549) ([d9e0e720](https://github.com/python-zk/kazoo/commit/d9e0e7208e56c31f0abec60a3701f8d6ec1e7d32))
+* **recipe:**
+  *  No more memory leak when ChildrenWatch was stopped (#543) ([37bcda35](https://github.com/python-zk/kazoo/commit/37bcda357463155aba5f2383bc70528413a10f1b))
+  *  No more memory leak once TreeCache was closed (#524) ([c48f2733](https://github.com/python-zk/kazoo/commit/c48f2733f2a6b2c2941738e4208e8cfede676730))
+
+
+
+<a name="2.6.0"></a>
+## 2.6.0 (2018-11-14)
+
+
+#### Features
+
+* **core:**
+  *  add SASL DIGEST-MD5 support ([aa2664b8](https://github.com/python-zk/kazoo/commit/aa2664b880d1456c3ccf6515c6ca42653047e272))
+  *  Added SSL support (#513) ([35ce1066](https://github.com/python-zk/kazoo/commit/35ce10669ace9d0d7e787793f0d4937d5d389f69))
+* **tests:**
+  *  update Zookeeper 3.5.2-alpha to 3.5.4-beta ([30330915](https://github.com/python-zk/kazoo/commit/3033091530b8f0aba13a1b8d031a7297e54006c2), closes [#477](https://github.com/python-zk/kazoo/issues/477))
+  *  update Zookeeper version from 3.4.10 to 3.4.13 ([287749b4](https://github.com/python-zk/kazoo/commit/287749b422c886f69e46d108d2ddbb5ad064773e))
+
+#### Bug Fixes
+
+* **core:**
+  *  ensure timeout argument is positive (#534) ([8c5ce118](https://github.com/python-zk/kazoo/commit/8c5ce11883a86b15bc6497706cf36abf1b36145f))
+  *  get_children with include_data=True uses GetChildren2 types (#514) ([901cba7a](https://github.com/python-zk/kazoo/commit/901cba7a40d67ec96c06abe109e3cf51a992b24d))
+  *  allow authentification in RO and RW modes ([2320ab39](https://github.com/python-zk/kazoo/commit/2320ab391f3804a9ddea9c5c86eb86467bb1dbf8))
+  *  Use a copy of auth data when reconnecting (#509) ([de20be91](https://github.com/python-zk/kazoo/commit/de20be917855713169863b65a7aa0634fb78b698))
+  *  change KazooRetry to uniformly jitter over the whole backoff interval (#521) ([60366d2c](https://github.com/python-zk/kazoo/commit/60366d2c7910fc833991fad8e04bbe33817c0544))
+* **recipe:**  Delete lock node in queue recipe if entry already consumed ([7a8167de](https://github.com/python-zk/kazoo/commit/7a8167dea381b3a2015c869a443c96b9d5179411))
+
+#### Doc
+
+*   make badges link to travis and pypi (#528) ([367a1df3](https://github.com/python-zk/kazoo/commit/367a1df35b3b168580327e9f52a4cb9c000ea750))
+*   specify description type for pypi to render correctly ([cc4006e6](https://github.com/python-zk/kazoo/commit/cc4006e6a8ea9441b01a631f3350357a8a2e4088))
+*   remove broken downloads badge ([47e07a96](https://github.com/python-zk/kazoo/commit/47e07a9674713b0756bce0811545c4442d40b60b))
+* **core:**  fix broken zookeeper programmers guide link ([8ecf8a50](https://github.com/python-zk/kazoo/commit/8ecf8a50c746ab7cc588ce9ac10a91ad1d1e5f34))
+
+
+
+<a name="2.5.0"></a>
+## 2.5.0 (2018-06-01)
+
+
+#### Performance
+
+* **recipe:**  Give TreeCache standalone queue ([4456f180](https://github.com/python-zk/kazoo/commit/4456f180735a0f8520bfc42474de9d27fa01bb2c))
+
+#### Doc
+
+*   Correctly document supported versions ([f860de52](https://github.com/python-zk/kazoo/commit/f860de5284e8ba7d0ed4171d9e5c5bef41f6b64d))
+*   Add license to Wheel ([43d156de](https://github.com/python-zk/kazoo/commit/43d156de3d41173d7baf6e8edb4efa377b3732fc))
+*   minor tweaks to contributing.md (#464) ([5837d11b](https://github.com/python-zk/kazoo/commit/5837d11bb541be1296e1b3c1842b11ceb7e743d4))
+
+#### Features
+
+* **recipe:**  allow non ephemeral locking ([6f7a603d](https://github.com/python-zk/kazoo/commit/6f7a603de9f04ec46d9946c6f5b1cb6e2b913b63))
+
+#### Chore
+
+*   drop python 2.6 compatible gevent ([2e8dcd38](https://github.com/python-zk/kazoo/commit/2e8dcd3836d01640f07e8de911cdfb3639f97d20))
+*   remove debian packaging (#468) ([a28423aa](https://github.com/python-zk/kazoo/commit/a28423aac7f33111388372dec50653a3091b9045))
+*   stop bundling virtualenv ([af9b4cab](https://github.com/python-zk/kazoo/commit/af9b4cab39982d961647afca8119816ffe7bf5e6))
+*   remove python 3.3 from tox ([cf66474b](https://github.com/python-zk/kazoo/commit/cf66474b27b4efc9f65e292434c2fcffb697d34d))
+*   remove `easy_install` instructions ([6e6627d5](https://github.com/python-zk/kazoo/commit/6e6627d58628dec11d127fc5508f9a1d16e9c317))
+
+#### Bug Fixes
+
+*   Pass watch as keyword arg instead of positional arg (#495) ([23850792](https://github.com/python-zk/kazoo/commit/2385079267db0bea6793c4f20588644381803a98))
+*   need gevent >= 1.2, not > 1.1 ([18f3531b](https://github.com/python-zk/kazoo/commit/18f3531b605119a547cfc4d5a4223b4b3f185405))
+*   Remove use of "async" as a variable ([225d3369](https://github.com/python-zk/kazoo/commit/225d3369c7a0736125a9375951a079f70fbe9e79), closes [#455](https://github.com/python-zk/kazoo/issues/455))
+* **core:**
+  *  Fix gevent 1.3b1+ timeout import ([257b5896](https://github.com/python-zk/kazoo/commit/257b58961f7ddd9db04d6efa070739a1b0404487))
+  *  Correctly fire multiple callbacks ([0905c47b](https://github.com/python-zk/kazoo/commit/0905c47bff3cfc42382daff0d5ac81189c8ba46d))
+  *  resolve race in IAsyncResult.wait() (#487) ([4d268adf](https://github.com/python-zk/kazoo/commit/4d268adf9837836f05dde5ec81be0d7bbd759e78))
+* **recipe:**
+  *  conn hangs when TreeCache refreshing ([11194137](https://github.com/python-zk/kazoo/commit/111941371daec00a2ecb5d8c29b9b1d35d6aa4ff))
+  *  Unexpected exceptions break TreeCache ([db0c2d4f](https://github.com/python-zk/kazoo/commit/db0c2d4f8ab5ecfb367b7b2accfd9c52c1c91fcd))
+
+#### Refactor
+
+*   Unify queue factory in various handlers ([cbd02f5c](https://github.com/python-zk/kazoo/commit/cbd02f5ccc6ea9e6dd6b5da01a0397ea649143a0))
+
+
+
+<a name="2.4.0"></a>
+## 2.4.0 (2017-06-14)
+
+**PYTHON SUPPORTED VERSIONS CHANGE**: Please note that Kazoo no longer tests
+on Python 2.6 or 3.3. Tested versions are 2.7, 3.4, 3.5, 3.6, and PyPy. The
+multiple endpoint support for KazooClient may not work correctly on 2.6.
+
+#### Bug Fixes
+
+*   add missed parens to LockingQueue function call. ([88cf4aa7](https://github.com/python-zk/kazoo/commit/88cf4aa7bcd1437a44f6d3aeec34989c467fcf9d))
+* **core:**  revert PR #305 SetWatches which caused RuntimeError ([a7b45390](https://github.com/python-zk/kazoo/commit/a7b45390f3720a33c9ad3896a8a185bfb2628839))
+
+#### Features
+
+*   pep8 all the things ([92880342](https://github.com/python-zk/kazoo/commit/928803420721b81962e50d425610e62b0c12e438), closes [#445](https://github.com/python-zk/kazoo/issues/445))
+*   drop Python 2.6/3.3 official support, add 3.5/3.6 testing ([2faba9ff](https://github.com/python-zk/kazoo/commit/2faba9ff3bdeff151ac6c922bf65b2dcf9c7bd7b), closes [#441](https://github.com/python-zk/kazoo/issues/441))
+* **core:**
+  *  allow multiple endpoints in KazooClient hosts arg ([72a8d96c](https://github.com/python-zk/kazoo/commit/72a8d96ca188c3c2e93bd0243283539ebd6c16f1), closes [#411](https://github.com/python-zk/kazoo/issues/411))
+  *  use epoll when available to support fds > 1023 ([267e61b4](https://github.com/python-zk/kazoo/commit/267e61b4323bc13505e8933fa9b89d0591af3a69), closes [#171](https://github.com/python-zk/kazoo/issues/171))
+* **recipe:**  Add TreeCache recipe ([ec8b337e](https://github.com/python-zk/kazoo/commit/ec8b337e6f1a4ff12e669f4b96ca98fb37ee5d8a))
+
+
+
+<a name="2.3.1"></a>
+## 2.3.1 (2017-06-01)
+
+
+#### Chore
+
+*   update MANIFEST.in to reflect changes to filenames ([c9a38c5d](https://github.com/python-zk/kazoo/commit/c9a38c5d650d6d92ff30fd3c1c792fc71db9ce02))
+*   add travis deployment and update ZK versions ([7d5d59cb](https://github.com/python-zk/kazoo/commit/7d5d59cb049244b89625d621c9d91d9a44c4b051), closes [#436](https://github.com/python-zk/kazoo/issues/436))
+
+2.3.0 (2017-05-31)
+------------------
+
+Please note, there have been a few dozen merges that failed to update the
+changelog here. As such, the log here should not be considered conclusive as
+to the changes that are arriving in 2.3.0.
+
+Changes being made now to ensure more accuracy in the changelog will appear
+in all future versions going forward. Read the commit history for a better
+understanding of changes merged between 2.2.1 and 2.3.0.
+
+All future commits must abide by the new CONTRIBUTING.md document describing
+how to label commits so they can be automatically used to automatically
+generate an accurate changelog.
+
+*WARNING:* THIS IS THE LAST KAZOO RELEASE THAT SUPPORTS PYTHON 2.6. ALL FUTURE
+VERSIONS WILL REQUIRE PYTHON 2.7 AND ABOVE.
+
+### Features
+
+-   allow having observers and different sized clusters
+
+### Bug Handling
+
+-   \#372: fully resolve multiple records for hosts in the zookeeper
+    connection string
+
+### Documentation
+
+-   Fix the recipe examples, so they actually work by connecting to
+    ZooKeeper. Without start() they just hang and can't be killed.
+
+2.2.1 (2015-06-17)
+------------------
+
+### Bug Handling
+
+-   handle NameError with basestring on py3k.
+
+### Documentation
+
+2.2 (2015-06-15)
+----------------
+
+### Documentation
+
+### Features
+
+-   Issue \#234: Add support for reconfig cluster membership operation
+
+### Bug Handling
+
+-   \#315: multiple acquires of a kazoo lock using the lock recipe would
+    block when using acquire even when non-blocking is specified (only
+    when the lock was/has been already acquired).
+-   \#318: At exit register takes `*args` and `**kwargs` not args and
+    kargs
+
+### Documentation
+
+2.1 (2015-05-11)
+----------------
+
+### Features
+
+-   Start running tests against Zookeeper 3.5.0 alpha and explicitly
+    configure the admin.serverPort in tests to avoid port conflicts. The
+    Zookeeper alpha version is not yet officially supported.
+-   Integrate eventlet *handler* support into kazoo so that along with
+    [gevent, threading] handlers there can now be a dedicated eventlet
+    handler for projects that need to (or want to) use eventlet (such as
+    those working in the openstack community). The
+    `requirements_eventlet.txt` file lists the optional eventlet
+    requirement(s) that needs to be satisfied when this new handler is
+    used.
+-   Use `six` to nicely handle the cross compatibility of kazoo with
+    python 2.x and 3.x (reducing/removing the need to have custom
+    compatibility code that replicates what six already provides).
+-   Add `state_change_event` to
+    `kazoo.recipe.partitioner.SetPartitioner` which is set on every
+    state change.
+-   Add a NonBlockingLease recipe. The recipe allows e.g. cron jobs
+    scheduled on multiple machines to ensure that at most N instances
+    will run a particular job, with lease timeout for graceful handover
+    in case of node failures.
+
+### Bug Handling
+
+-   \#291: Kazoo lock recipe was only partially re-entrant in that
+    multiple calls to acquire would obtain the the lock but the first
+    call to release would remove the underlying lock. This would leave
+    the X - 1 other acquire statements unprotected (and no longer
+    holding there expected lock). To fix this the comment about that
+    lock recipe being re-entrant has been removed and multiple acquires
+    will now block when attempted.
+-   \#78: Kazoo now uses socketpairs instead of pipes making it
+    compatible with Windows.
+-   \#144, \#221: Let client.command work with IPv6 addresses.
+-   \#216: Fixed timeout for ConnectionHandler.\_invoke.
+-   \#261: Creating a sequential znode under / doesn't work.
+-   \#274: Add server\_version() retries (by default 4 attempts will be
+    made) to better handle flakey responses.
+-   \#271: Fixed handling of KazooState.SUSPENDED in SetPartitioner.
+-   \#283: Fixed a race condition in SetPartitioner when party changes
+    during handling of lock acquisition.
+-   \#303: don't crash on random input as the hosts string.
+
+### Documentation
+
+-   \#222: Document that committed on the transaction is used to ensure
+    only one commit and is not an indicator of whether operations in the
+    transaction returned desired results.
+
+2.0 (2014-06-19)
+----------------
+
+### Documentation
+
+-   Extend support to Python 3.4, deprecating Python 3.2.
+-   Issue \#198: Mention Zake as a sophisticated kazoo mock testing
+    library.
+-   Issue \#181: Add documentation on basic logging setup.
+
+2.0b1 (2014-04-24)
+------------------
+
+### API Changes
+
+-   Null or None data is no longer treated as "". Pull req \#165, patch
+    by Raul Gutierrez S. This will affect how you should treat null data
+    in a znode vs. an empty string.
+-   Passing acl=[] to create() now works properly instead of an
+    InvalidACLError as it returned before. Patch by Raul Gutierrez S in
+    PR \#164.
+-   Removed the dependency on zope.interface. The classes in the
+    interfaces module are left for documentation purposes only (issue
+    \#131).
+
+### Features
+
+-   Logging levels have been reduced.
+    -   Logging previously at the `logging.DEBUG` level is now logged at
+    the `kazoo.loggingsupport.BLATHER` level (5).
+    -   Some low-level logging previously at the `logging.INFO` level is
+    now logged at the `logging.DEBUG` level.
+-   Issue \#133: Introduce a new environment variable
+    ZOOKEEPER\_PORT\_OFFSET for the testing support, to run the testing
+    cluster on a different range.
+
+### Bug Handling
+
+-   When authenticating via add\_auth() the auth data will be saved to
+    ensure that the authentication happens on reconnect (as is the case
+    when feeding auth data via KazooClient's constructor). PR \#172,
+    patch by Raul Gutierrez S.
+-   Change gevent import to remove deprecation warning when newer gevent
+    is used. PR \#191, patch by Hiroaki Kawai.
+-   Lock recipe was failing to use the client's sleep\_func causing
+    issues with gevent. Issue \#150.
+-   Calling a DataWatch or ChildrenWatch instance twice (decorator) now
+    throws an exception as only a single function can be associated with
+    a single watcher. Issue \#154.
+-   Another fix for atexit handling so that when disposing of
+    connections the atexit handler is removed. PR \#190, patch by Devaev
+    Maxim.
+-   Fix atexit handling for kazoo threading handler, PR \#183. Patch by
+    Brian Wickman.
+-   Partitioner should handle a suspended connection properly and
+    restore an allocated state if it was allocated previously. Patch by
+    Manish Tomar.
+-   Issue \#167: Closing a client that was never started throws a type
+    error. Patch by Joshua Harlow.
+-   Passing dictionaries to KazooClient.\_\_init\_\_() wasn't actually
+    working properly. Patch by Ryan Uber.
+-   Issue \#119: Handler timeout takes the max of the random interval or
+    the read timeout to ensure a negative number isn't used for the read
+    timeout.
+-   Fix ordering of exception catches in lock.acquire as it was
+    capturing a parent exception before the child. Patch by ReneSac.
+-   Fix issue with client.stop() not always setting the client state to
+    KeeperState.CLOSED. Patch by Jyrki Pulliainen in PR \#174.
+-   Issue \#169: Fixed pipes leaking into child processes.
+
+### Documentation
+
+-   Add section on contributing recipes, add maintainer/status
+    information for existing recipes.
+-   Add note about alternate use of DataWatch.
+
+1.3.1 (2013-09-25)
+------------------
+
+### Bug Handling
+
+-   \#118, \#125, \#128: Fix unknown variable in KazooClient
+    command\_retry argument handling.
+-   \#126: Fix KazooRetry.copy to correctly copy sleep function.
+-   \#118: Correct session/socket timeout conversion (int vs. float).
+
+### Documentation
+
+-   \#121: Add a note about kazoo.recipe.queue.LockingQueue requiring a
+    Zookeeper 3.4+ server.
+
+1.3 (2013-09-05)
+----------------
+
+### Features
+
+-   \#115: Limit the backends we use for SLF4J during tests.
+-   \#112: Add IPv6 support. Patch by Dan Kruchinin.
+
+1.2.1 (2013-08-01)
+------------------
+
+### Bug Handling
+
+-   Issue \#108: Circular import fail when importing
+    kazoo.recipe.watchers directly has now been resolved. Watchers and
+    partitioner properly import the KazooState from
+    kazoo.protocol.states rather than kazoo.client.
+-   Issue \#109: Partials not usable properly as a datawatch call can
+    now be used. All funcs will be called with 3 args and fall back to 2
+    args if there's an argument error.
+-   Issue \#106, \#107: client.create\_async didn't strip change root
+    from the returned path.
+
+1.2 (2013-07-24)
+----------------
+
+### Features
+
+-   KazooClient can now be stopped more reliably even if its in the
+    middle of a long retry sleep. This utilizes the new interrupt
+    feature of KazooRetry which lets the sleep be broken down into
+    chunks and an interrupt function called to determine if the retry
+    should fail early.
+-   Issue \#62, \#92, \#89, \#101, \#102: Allow KazooRetry to have a max
+    deadline, transition properly when connection fails to LOST, and
+    setup separate connection retry behavior from client command retry
+    behavior. Patches by Mike Lundy.
+-   Issue \#100: Make it easier to see exception context in threading
+    and connection modules.
+-   Issue \#85: Increase information density of logs and don't prevent
+    dynamic reconfiguration of log levels at runtime.
+-   Data-watchers for the same node are no longer 'stacked'. That is, if
+    a get and an exists call occur for the same node with the same watch
+    function, then it will be registered only once. This change results
+    in Kazoo behaving per Zookeeper client spec regarding repeat watch
+    use.
+
+### Bug Handling
+
+-   Issue \#53: Throw a warning upon starting if the chroot path doesn't
+    exist so that it's more obvious when the chroot should be created
+    before performing more operations.
+-   Kazoo previously would let the same function be registered as a
+    data-watch or child-watch multiple times, and then call it multiple
+    times upon being triggered. This was non-compliant Zookeeper client
+    behavior, the same watch can now only be registered once for the
+    same znode path per Zookeeper client documentation.
+-   Issue \#105: Avoid rare import lock problems by moving module
+    imports in client.py to the module scope.
+-   Issue \#103: Allow prefix-less sequential znodes.
+-   Issue \#98: Extend testing ZK harness to work with different file
+    locations on some versions of Debian/Ubuntu.
+-   Issue \#97: Update some docstrings to reflect current state of
+    handlers.
+-   Issue \#62, \#92, \#89, \#101, \#102: Allow KazooRetry to have a max
+    deadline, transition properly when connection fails to LOST, and
+    setup separate connection retry behavior from client command retry
+    behavior. Patches by Mike Lundy.
+
+### API Changes
+
+-   The kazoo.testing.harness.KazooTestHarness class directly inherits
+    from unittest.TestCase and you need to ensure to call its
+    \_\_init\_\_ method.
+-   DataWatch no longer takes any parameters besides for the optional
+    function during instantiation. The additional options are now
+    implicitly True, with the user being left to ignore events as they
+    choose. See the DataWatch API docs for more information.
+-   Issue \#99: Better exception raised when the writer fails to close.
+    A WriterNotClosedException that inherits from KazooException is now
+    raised when the writer fails to close in time.
+
+1.1 (2013-06-08)
+----------------
+
+### Features
+
+-   Issue \#93: Add timeout option to lock/semaphore acquire methods.
+-   Issue \#79 / \#90: Add ability to pass the WatchedEvent to DataWatch
+    and ChildWatch functions.
+-   Respect large client timeout values when closing the connection.
+-   Add a max\_leases consistency check to the semaphore recipe.
+-   Issue \#76: Extend testing helpers to allow customization of the
+    Java classpath by specifying the new ZOOKEEPER\_CLASSPATH
+    environment variable.
+-   Issue \#65: Allow non-blocking semaphore acquisition.
+
+### Bug Handling
+
+-   Issue \#96: Provide Windows compatibility in testing harness.
+-   Issue \#95: Handle errors deserializing connection response.
+-   Issue \#94: Clean up stray bytes in connection pipe.
+-   Issue \#87 / \#88: Allow re-acquiring lock after cancel.
+-   Issue \#77: Use timeout in initial socket connection.
+-   Issue \#69: Only ensure path once in lock and semaphore recipes.
+-   Issue \#68: Closing the connection causes exceptions to be raised by
+    watchers which assume the connection won't be closed when running
+    commands.
+-   Issue \#66: Require ping reply before sending another ping,
+    otherwise the connection will be considered dead and a
+    ConnectionDropped will be raised to trigger a reconnect.
+-   Issue \#63: Watchers weren't reset on lost connection.
+-   Issue \#58: DataWatcher failed to re-register for changes after
+    non-existent node was created then deleted.
+
+### API Changes
+
+-   KazooClient.create\_async now supports the makepath argument.
+-   KazooClient.ensure\_path now has an async version,
+    ensure\_path\_async.
+
+1.0 (2013-03-26)
+----------------
+
+### Features
+
+-   Added a LockingQueue recipe. The queue first locks an item and
+    removes it from the queue only after the consume() method is called.
+    This enables other nodes to retake the item if an error occurs on
+    the first node.
+
+### Bug Handling
+
+-   Issue \#50: Avoid problems with sleep function in mixed
+    gevent/threading setup.
+-   Issue \#56: Avoid issues with watch callbacks evaluating to false.
+
+1.0b1 (2013-02-24)
+------------------
+
+### Features
+
+-   Refactored the internal connection handler to use a single thread.
+    It now uses a deque and pipe to signal the ZK thread that there's a
+    new command to send, so that the ZK thread can send it, or retrieve
+    a response. Processing ZK requests and responses serially in a
+    single thread eliminates the need for a bunch of the locking, the
+    peekable queue and two threads working on the same underlying
+    socket.
+-   Issue \#48: Added documentation for the retry helper module.
+-   Issue \#55: Fix os.pipe file descriptor leak and introduce a
+    KazooClient.close method. The method is particular useful in tests,
+    where multiple KazooClients are created and closed in the same
+    process.
+
+### Bug Handling
+
+-   Issue \#46: Avoid TypeError in GeneratorContextManager on process
+    shutdown.
+-   Issue \#43: Let DataWatch return node data if allow\_missing\_node
+    is used.
+
+0.9 (2013-01-07)
+----------------
+
+### API Changes
+
+-   When a retry operation ultimately fails, it now raises a
+    kazoo.retry.RetryFailedError exception, instead of a general
+    Exception instance. RetryFailedError also inherits from the base
+    KazooException.
+
+### Features
+
+-   Improvements to Debian packaging rules.
+
+### Bug Handling
+
+-   Issue \#39 / \#41: Handle connection dropped errors during session
+    writes. Ensure client connection is re-established to a new ZK node
+    if available.
+-   Issue \#38: Set CLOEXEC flag on all sockets when available.
+-   Issue \#37 / \#40: Handle timeout errors during select calls on
+    sockets.
+-   Issue \#36: Correctly set ConnectionHandler.writer\_stopped even if
+    an exception is raised inside the writer, like a retry operation
+    failing.
+
+0.8 (2012-10-26)
+----------------
+
+### API Changes
+
+-   The KazooClient.\_\_init\_\_ took as watcher argument as its second
+    keyword argument. The argument had no effect anymore since version
+    0.5 and was removed.
+
+### Bug Handling
+
+-   Issue \#35: KazooClient.\_\_init\_\_ didn't pass on
+    retry\_max\_delay to the retry helper.
+-   Issue \#34: Be more careful while handling socket connection errors.
+
+0.7 (2012-10-15)
+----------------
+
+### Features
+
+-   DataWatch now has a allow\_missing\_node setting that allows a watch
+    to be set on a node that doesn't exist when the DataWatch is
+    created.
+-   Add new Queue recipe, with optional priority support.
+-   Add new Counter recipe.
+-   Added debian packaging rules.
+
+### Bug Handling
+
+-   Issue \#31 fixed: Only catch KazooExceptions in catch-all calls.
+-   Issue \#15 fixed again: Force sleep delay to be a float to appease
+    gevent.
+-   Issue \#29 fixed: DataWatch and ChildrenWatch properly re-register
+    their watches on server disconnect.
+
+0.6 (2012-09-27)
+----------------
+
+### API Changes
+
+-   Node paths are assumed to be Unicode objects. Under Python 2
+    pure-ascii strings will also be accepted. Node values are considered
+    bytes. The byte type is an alias for str under Python 2.
+-   New KeeperState.CONNECTED\_RO state for Zookeeper servers connected
+    in read-only mode.
+-   New NotReadOnlyCallError exception when issuing a write change
+    against a server thats currently read-only.
+
+### Features
+
+-   Add support for Python 3.2, 3.3 and PyPy (only for the threading
+    handler).
+-   Handles connecting to Zookeeper 3.4+ read-only servers.
+-   Automatic background scanning for a Read/Write server when connected
+    to a server in read-only mode.
+-   Add new Semaphore recipe.
+-   Add a new retry\_max\_delay argument to the client and by default
+    limit the retry delay to at most an hour regardless of exponential
+    backoff settings.
+-   Add new randomize\_hosts argument to KazooClient, allowing one to
+    disable host randomization.
+
+### Bug Handling
+
+-   Fix bug with locks not handling intermediary lock contenders
+    disappearing.
+-   Fix bug with set\_data type check failing to catch unicode values.
+-   Fix bug with gevent 0.13.x backport of peekable queue.
+-   Fix PatientChildrenWatch to use handler specific sleep function.
+
+0.5 (2012-09-06)
+----------------
+
+Skipping a version to reflect the magnitude of the change. Kazoo is now
+a pure Python client with no C bindings. This release should run without
+a problem on alternate Python implementations such as PyPy and Jython.
+Porting to Python 3 in the future should also be much easier.
+
+### Documentation
+
+-   Docs have been restructured to handle the new classes and locations
+    of the methods from the pure Python refactor.
+
+### Bug Handling
+
+This change may introduce new bugs, however there is no longer the
+possibility of a complete Python segfault due to errors in the C library
+and/or the C binding.
+
+-   Possible segfaults from the C lib are gone.
+-   Password mangling due to the C lib is gone.
+-   The party recipes didn't set their participating flag to False after
+    leaving.
+
+### Features
+
+-   New client.command and client.server\_version API, exposing
+    Zookeeper's four letter commands and giving access to structured
+    version information.
+-   Added 'include\_data' option for get\_children to include the node's
+    Stat object.
+-   Substantial increase in logging data with debug mode. All
+    correspondence with the Zookeeper server can now be seen to help in
+    debugging.
+
+### API Changes
+
+-   The testing helpers have been moved from testing.\_\_init\_\_ into a
+    testing.harness module. The official API's of KazooTestCase and
+    KazooTestHarness can still be directly imported from testing.
+-   The kazoo.handlers.util module was removed.
+-   Backwards compatible exception class aliases are provided for now in
+    kazoo exceptions for the prior C exception names.
+-   Unicode strings now work fine for node names and are properly
+    converted to and from unicode objects.
+-   The data value argument for the create and create\_async methods of
+    the client was made optional and defaults to an empty byte string.
+    The data value must be a byte string. Unicode values are no longer
+    allowed and will raise a TypeError.
+
+0.3 (2012-08-23)
+----------------
+
+### API Changes
+
+-   Handler interface now has an rlock\_object for use by recipes.
+
+### Bug Handling
+
+-   Fixed password bug with updated zc-zookeeper-static release, which
+    retains null bytes in the password properly.
+-   Fixed reconnect hammering, so that the reconnection follows retry
+    jitter and retry backoff's.
+-   Fixed possible bug with using a threading.Condition in the set
+    partitioner. Set partitioner uses new rlock\_object handler API to
+    get an appropriate RLock for gevent.
+-   Issue \#17 fixed: Wrap timeout exceptions with staticmethod so they
+    can be used directly as intended. Patch by Bob Van Zant.
+-   Fixed bug with client reconnection looping indefinitely using an
+    expired session id.
+
+0.2 (2012-08-12)
+----------------
+
+### Documentation
+
+-   Fixed doc references to start\_async using an AsyncResult object, it
+    uses an Event object.
+
+### Bug Handling
+
+-   Issue \#16 fixed: gevent zookeeper logging failed to handle a monkey
+    patched logging setup. Logging is now setup such that a greenlet is
+    used for logging messages under gevent, and the thread one is used
+    otherwise.
+-   Fixed bug similar to \#14 for ChildrenWatch on the session listener.
+-   Issue \#14 fixed: DataWatch had inconsistent handling of the node it
+    was watching not existing. DataWatch also properly spawns its
+    \_get\_data function to avoid blocking session events.
+-   Issue \#15 fixed: sleep\_func for SequentialGeventHandler was not
+    set on the class appropriately leading to additional arguments being
+    passed to gevent.sleep.
+-   Issue \#9 fixed: Threads/greenlets didn't gracefully shut down.
+    Handler now has a start/stop that is used by the client when calling
+    start and stop that shuts down the handler workers. This addresses
+    errors and warnings that could be emitted upon process shutdown
+    regarding a clean exit of the workers.
+-   Issue \#12 fixed: gevent 0.13 doesn't use the same
+    start\_new\_thread as gevent 1.0 which resulted in a fully
+    monkey-patched environment halting due to the wrong thread. Updated
+    to use the older kazoo method of getting the real thread module
+    object.
+
+### API Changes
+
+-   The KazooClient handler is now officially exposed as
+    KazooClient.handler so that the appropriate sync objects can be used
+    by end-users.
+-   Refactored ChildrenWatcher used by SetPartitioner into a publicly
+    exposed PatientChildrenWatch under recipe.watchers.
+
+### Deprecations
+
+-   connect/connect\_async has been renamed to start/start\_async to
+    better match the stop to indicate connection handling. The prior
+    names are aliased for the time being.
+
+### Recipes
+
+-   Added Barrier and DoubleBarrier implementation.
+
+0.2b1 (2012-07-27)
+------------------
+
+### Bug Handling
+
+-   ZOOKEEPER-1318: SystemError is caught and rethrown as the proper
+    invalid state exception in older zookeeper python bindings where
+    this issue is still valid.
+-   ZOOKEEPER-1431: Install the latest zc-zookeeper-static library or
+    use the packaged ubuntu one for ubuntu 12.04 or later.
+-   ZOOKEEPER-553: State handling isn't checked via this method, we
+    track it in a simpler manner with the watcher to ensure we know the
+    right state.
+
+### Features
+
+-   Exponential backoff with jitter for retrying commands.
+-   Gevent 0.13 and 1.0b support.
+-   Lock, Party, SetPartitioner, and Election recipe implementations.
+-   Data and Children watching API's.
+-   State transition handling with listener registering to handle
+    session state changes (choose to fatal the app on session
+    expiration, etc.)
+-   Zookeeper logging stream redirected into Python logging channel
+    under the name 'Zookeeper'.
+-   Base client library with handler support for threading and gevent
+    async environments.
+

+ 167 - 0
desktop/core/ext-py/kazoo-2.8.0/CONTRIBUTING.md

@@ -0,0 +1,167 @@
+# Contribution Guidelines
+
+We gladly accept outside contributions. We use our
+[Github issue tracker](https://github.com/python-zk/kazoo/issues)
+for both discussions and talking about new features or bugs. You can
+also fork the project and sent us a pull request. If you have a more
+general topic to discuss, the
+[user@zookeeper.apache.org](https://zookeeper.apache.org/lists.html)
+mailing list is a good place to do so. You can sometimes find us on
+IRC in the
+[#zookeeper channel on freenode](https://zookeeper.apache.org/irc.html).
+
+[See the README](/README.rst) for contact information.
+
+## Development
+
+If you want to work on the code and send us a
+[pull request](https://help.github.com/articles/using-pull-requests),
+first fork the repository on github to your own account. Then clone
+your new repository and run the build scripts:
+
+```
+    git clone git@github.com:<username>/kazoo.git
+    cd kazoo
+    make
+```
+
+You need a supported version of Python installed and available as `python`
+in your shell. To run Zookeeper you also need a Java runtime (JRE or JDK).
+Please refer to the Zookeeper documentation for compatible Java versions for
+each Zookeeper version. To run tests, you need to have `tox`, the Python
+testing tool, installed in your shell.
+
+You can run all the tests by calling:
+
+```
+    make test
+```
+
+Or to run individual tests:
+
+```
+    export ZOOKEEPER_PATH=/<path to current folder>/bin/zookeeper/
+    bin/pytest -v kazoo/tests/test_client.py::TestClient::test_create
+```
+
+The pytest test runner allows you to filter by test module, class or
+individual test method.
+
+If you made changes to the documentation, you can build it locally:
+
+```
+    make html
+```
+
+And then open `./docs/_build/html/index.html` in a web browser to
+verify the correct rendering.
+
+
+## Bug Reports
+
+You can file issues here on GitHub. Please try to include as much information as
+you can and under what conditions you saw the issue.
+
+## Adding Recipes
+
+New recipes are welcome, however they should include the status/maintainer
+RST information so its clear who is maintaining the recipe. This means
+that if you submit a recipe for inclusion with Kazoo, you should be ready
+to support/maintain it, and address bugs that may be found.
+
+Ideally a recipe should have at least two maintainers.
+
+## Sending Pull Requests
+
+Patches should be submitted as pull requests (PR).
+
+Before submitting a PR:
+- Your code must run and pass all the automated tests before you submit your PR
+  for review. "Work in progress" pull requests are allowed to be submitted, but
+  should be clearly labeled as such and should not be merged until all tests
+  pass and the code has been reviewed.
+- Your patch should include new tests that cover your changes. It is your and
+  your reviewer's responsibility to ensure your patch includes adequate tests.
+
+When submitting a PR:
+- You agree to license your code under the project's open source license
+  ([APL 2.0](/LICENSE)).
+- Base your branch off the current `master`.
+- Add both your code and new tests if relevant.
+- Sign your git commit.
+- Run the test suite to make sure your code passes linting and tests.
+- Ensure your changes do not reduce code coverage of the test suite.
+- Please do not include merge commits in pull requests; include only commits
+  with the new relevant code.
+
+
+## Code Review
+
+This project is production Mozilla code and subject to our [engineering practices and quality standards](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Committing_Rules_and_Responsibilities). Every patch must be peer reviewed.
+
+## Git Commit Guidelines
+
+We loosely follow the [Angular commit guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#type)
+of `<type>(scope): <subject>` where `type` must be one of:
+
+* **feat**: A new feature
+* **fix**: A bug fix
+* **docs**: Documentation only changes
+* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing
+  semi-colons, etc)
+* **refactor**: A code change that neither fixes a bug or adds a feature
+* **perf**: A code change that improves performance
+* **test**: Adding missing tests
+* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
+  generation
+
+Scope may be left off if none of these components are applicable:
+
+* **core**: Core client/connection handling
+* **recipe**: Changes/Fixes/Additions to recipes
+
+### Subject
+
+The subject contains succinct description of the change:
+
+* use the imperative, present tense: "change" not "changed" nor "changes"
+* don't capitalize first letter
+* no dot (.) at the end
+
+### Body
+
+In order to maintain a reference to the context of the commit, add
+`closes #<issue_number>` if it closes a related issue or `issue #<issue_number>`
+if it's a partial fix.
+
+You can also write a detailed description of the commit. Just as in the
+**subject**, use the imperative, present tense: "change" not "changed" nor
+"changes". Please include the motivation for the change and contrast this with
+previous behavior.
+
+### Footer
+
+The footer should contain any information about **Breaking Changes** and is also
+the place to reference GitHub issues that this commit **Closes**.
+
+### Example
+
+A properly formatted commit message should look like:
+
+```
+feat(core): add tasty cookies to the client handler
+
+Properly formatted commit messages provide understandable history and
+documentation. This patch will provide a delicious cookie when all tests have
+passed and the commit message is properly formatted.
+
+BREAKING CHANGE: This patch requires developer to lower expectations about
+    what "delicious" and "cookie" may mean. Some sadness may result.
+
+Closes #3.14, #9.75
+```
+
+# Legal
+
+Currently we don't have any legal contributor agreement, so code
+ownership stays with the original authors.

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/LICENSE → desktop/core/ext-py/kazoo-2.8.0/LICENSE


+ 4 - 4
desktop/core/ext-py/kazoo-2.0/MANIFEST.in → desktop/core/ext-py/kazoo-2.8.0/MANIFEST.in

@@ -1,6 +1,6 @@
-include CHANGES.rst
-include CONTRIBUTING.rst
-include README.rst
+include CHANGES.md
+include CONTRIBUTING.md
+include README.md
 include LICENSE
 include MANIFEST.in
 exclude .gitignore
@@ -8,5 +8,5 @@ exclude .travis.yml
 exclude Makefile
 exclude run_failure.py
 recursive-include kazoo *
-recursive-exclude sw *
+recursive-include docs *
 global-exclude *pyc *pyo

+ 861 - 0
desktop/core/ext-py/kazoo-2.8.0/PKG-INFO

@@ -0,0 +1,861 @@
+Metadata-Version: 2.1
+Name: kazoo
+Version: 2.8.0
+Summary: Higher Level Zookeeper Client
+Home-page: https://kazoo.readthedocs.io
+Author: Kazoo team
+Author-email: python-zk@googlegroups.com
+License: Apache 2.0
+Description: Kazoo
+        =====
+        
+        [![Build Status](https://travis-ci.org/python-zk/kazoo.svg?branch=master)](https://travis-ci.org/python-zk/kazoo)
+        [![Latest Version](https://img.shields.io/pypi/v/kazoo.svg)](https://pypi.org/project/kazoo/)
+        [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
+        
+        `kazoo` implements a higher level API to [Apache
+        Zookeeper](http://zookeeper.apache.org/) for Python clients.
+        
+        See [the full docs](http://kazoo.rtfd.org/) for more information.
+        
+        License
+        -------
+        
+        `kazoo` is offered under the Apache License 2.0.
+        
+        Authors
+        -------
+        
+        `kazoo` started under the [Nimbus
+        Project](http://www.nimbusproject.org/) and through collaboration with
+        the open-source community has been merged with code from
+        [Mozilla](http://www.mozilla.org/) and the [Zope
+        Corporation](http://zope.com/). It has since gathered an active
+        community of over fifty contributors.
+        
+        
+        <a name="2.8.0"></a>
+        ## 2.8.0 (2020-07-11)
+        
+        
+        #### Features
+        
+        * **chore:**  using Github templates for issues and PRs (#610) ([eddc0976](https://github.com/python-zk/kazoo/commit/eddc0976bf1ef9d9fb97990cebbc3f9b1abe9d7d))
+        * **core:**
+          *  Use strict regex to identify lock contenders. ([cc8ce892](https://github.com/python-zk/kazoo/commit/cc8ce8929116a1f0a2f0d088afa82ac9576395dc))
+          *  Support additionaal lock contenter patterns ([225eeecb](https://github.com/python-zk/kazoo/commit/225eeecbe66c10d46dc7928681783d17f389f13a))
+        * **tests:**
+          *  Disable problematic hound-flake8-black integration. ([75f62a0d](https://github.com/python-zk/kazoo/commit/75f62a0dd40a9f9bdefcb04cea5ee5fcd3438c0e))
+          *  Move to pytest ([de97d74b](https://github.com/python-zk/kazoo/commit/de97d74b50b62cd2f0cddc2a04e150575d9c6bc7))
+          *  add Python 3.8 and remove Python 3.6 from the testing suite (#611) ([e4f808f7](https://github.com/python-zk/kazoo/commit/e4f808f7f0fe17e7e01468a2c54684f048e12b52))
+        
+        #### Performance
+        
+        * **core:**  Use chain.from_iterable in threading.py (#614) ([13c73ec5](https://github.com/python-zk/kazoo/commit/13c73ec5f4d4f2215deb987a059051bb821674ca))
+        
+        #### Bug Fixes
+        
+        * **core:**
+          *  handle SSL_WANT_READ/WRITE errors (#619) ([cbdc4749](https://github.com/python-zk/kazoo/commit/cbdc4749edb5879099c1f9b832c055d9eeb52dea), closes [#618](https://github.com/python-zk/kazoo/issues/618))
+          *  '"is" with a literal' syntax errors (#609) ([6b6ffe62](https://github.com/python-zk/kazoo/commit/6b6ffe62a073d1ed5413c65c2d8ec94ea2fa1760))
+          *  sync() return should be unchrooted ([cbde70ac](https://github.com/python-zk/kazoo/commit/cbde70ac87435afbbacc9806c675184c7f778343), closes [#601](https://github.com/python-zk/kazoo/issues/601))
+        
+        #### Chore
+        
+        * **core:**  Update matrix: add pypy3, drop py27 ([522189da](https://github.com/python-zk/kazoo/commit/522189da0f238faafc8f1db34f682f49b15ec503))
+        * **tests:**  Add coverage report on codecov.io ([bb475843](https://github.com/python-zk/kazoo/commit/bb475843905af1a2d25b1f5834085c85c28bb175))
+        
+        
+        
+        <a name="2.7.0"></a>
+        ## 2.7.0 (2020-03-13)
+        
+        #### Features
+        
+        * **CI:**  Keep only Python 3.{6,7} to CI and bump ZK versions to latests (#574) ([c293aabf](https://github.com/python-zk/kazoo/commit/c293aabf39676b94006cf736f9f75392637b8292))
+        * **core:**
+          *  run SASL Kerberos tests as part of build ([5c461bdf](https://github.com/python-zk/kazoo/commit/5c461bdff50efd762805b40fbe283b194d175c61))
+          *  Add create2 support ([1d81f96a](https://github.com/python-zk/kazoo/commit/1d81f96a77a6fd7ae2476cd798a5cb4bf1c1d9a2))
+          *  closed states instead of lost states (#573) ([961b2f3b](https://github.com/python-zk/kazoo/commit/961b2f3be557f8314ab41f75444125222638f9cc))
+          *  improve SASL interface (#546) ([cd49b3fa](https://github.com/python-zk/kazoo/commit/cd49b3fa01136848c5e6bfafb4c241b9704f249d))
+        * **recipe:**  add support for curator SharedCount recipe (#559) ([88b657a0](https://github.com/python-zk/kazoo/commit/88b657a0977161f3815657878ba48f82a97a3846), closes [#558](https://github.com/python-zk/kazoo/issues/558))
+        * **utils:**  extend create_tcp_connection utility (#568) ([ab0cd00c](https://github.com/python-zk/kazoo/commit/ab0cd00c12624b07dcc3b2d62aa96f8f1e658f65))
+        
+        #### Bug Fixes
+        
+        * **CI:**  deploying only for 1 job ([0ba3634d](https://github.com/python-zk/kazoo/commit/0ba3634d99740c9ccc2dd01924a36dffff262f8e))
+        * **core:**
+          *  allow requests to be queued in CONNECTING state (#374) (#588) ([a636d7a6](https://github.com/python-zk/kazoo/commit/a636d7a6bb88ab9080e902983b10c8f0f1bf60a8))
+          *  Implement proper retry backoff logic with jitter. ([0bb0659c](https://github.com/python-zk/kazoo/commit/0bb0659cf3fd73714a9d75b093a75c7122e116e6))
+          *  when connection fails, close the ConnectionHandler (#577) (#579) ([c7e80503](https://github.com/python-zk/kazoo/commit/c7e80503f3be97d26ff2de27f9e424070c8181bb))
+        * **recipe:**  crash if None in znode (#569) ([ded79467](https://github.com/python-zk/kazoo/commit/ded79467a8254e43841dfeb69f7c3baa1980232c))
+        * **tests:**
+          *  Disable JAAS isInitiator for Server ([933b38b5](https://github.com/python-zk/kazoo/commit/933b38b5506d84e05ed6f6c5c8c208a3367400da))
+          *  deactivate TCP port that was enabled by default. ([d7bed550](https://github.com/python-zk/kazoo/commit/d7bed550fee1b861eb2ee81cc685e6d08ee35c34))
+          *  capitalize the default_domain value ([7fd22bfd](https://github.com/python-zk/kazoo/commit/7fd22bfd1992b90042db7946949ce992ddfd1821))
+          *  weaker crypto when configuring Kerberos ([844df87a](https://github.com/python-zk/kazoo/commit/844df87ac83e72c155367cfe4ff4d52d34d46c99))
+          *  prefix with toxinidir variable with a / to ensure path to ensure-zookeeper-env.sh is correct ([c4d42ca7](https://github.com/python-zk/kazoo/commit/c4d42ca7722dec5332ecd4524e8d802a81e2ddca))
+          *  specify -Dfile.encoding=UTF-8 when starting the ZK JVM ([5764da0b](https://github.com/python-zk/kazoo/commit/5764da0b3c25556cb6760f68c51b387f2fd8307b))
+        
+        
+        
+        <a name="2.6.1"></a>
+        ### 2.6.1 (2019-01-22)
+        
+        
+        #### Bug Fixes
+        
+        * **client:**  add missing paren (#550) ([1452a48f](https://github.com/python-zk/kazoo/commit/1452a48f3070fe9034314476a6fdb94ca206dede))
+        * **core:**
+          *  support deprecated KazooRetry argument (#545) ([4242da80](https://github.com/python-zk/kazoo/commit/4242da801e8da7b76d7e88e37c3948f97a2b5aae))
+          *  reduce timeout for the first Connect() request (#540) ([2ae392e6](https://github.com/python-zk/kazoo/commit/2ae392e69c4b2daca5d8e7f0e79b7ce90423e65c))
+        * **handlers:**  make AsyncResult call all registered callbacks instantly if the handler has stopped running (#549) ([d9e0e720](https://github.com/python-zk/kazoo/commit/d9e0e7208e56c31f0abec60a3701f8d6ec1e7d32))
+        * **recipe:**
+          *  No more memory leak when ChildrenWatch was stopped (#543) ([37bcda35](https://github.com/python-zk/kazoo/commit/37bcda357463155aba5f2383bc70528413a10f1b))
+          *  No more memory leak once TreeCache was closed (#524) ([c48f2733](https://github.com/python-zk/kazoo/commit/c48f2733f2a6b2c2941738e4208e8cfede676730))
+        
+        
+        
+        <a name="2.6.0"></a>
+        ## 2.6.0 (2018-11-14)
+        
+        
+        #### Features
+        
+        * **core:**
+          *  add SASL DIGEST-MD5 support ([aa2664b8](https://github.com/python-zk/kazoo/commit/aa2664b880d1456c3ccf6515c6ca42653047e272))
+          *  Added SSL support (#513) ([35ce1066](https://github.com/python-zk/kazoo/commit/35ce10669ace9d0d7e787793f0d4937d5d389f69))
+        * **tests:**
+          *  update Zookeeper 3.5.2-alpha to 3.5.4-beta ([30330915](https://github.com/python-zk/kazoo/commit/3033091530b8f0aba13a1b8d031a7297e54006c2), closes [#477](https://github.com/python-zk/kazoo/issues/477))
+          *  update Zookeeper version from 3.4.10 to 3.4.13 ([287749b4](https://github.com/python-zk/kazoo/commit/287749b422c886f69e46d108d2ddbb5ad064773e))
+        
+        #### Bug Fixes
+        
+        * **core:**
+          *  ensure timeout argument is positive (#534) ([8c5ce118](https://github.com/python-zk/kazoo/commit/8c5ce11883a86b15bc6497706cf36abf1b36145f))
+          *  get_children with include_data=True uses GetChildren2 types (#514) ([901cba7a](https://github.com/python-zk/kazoo/commit/901cba7a40d67ec96c06abe109e3cf51a992b24d))
+          *  allow authentification in RO and RW modes ([2320ab39](https://github.com/python-zk/kazoo/commit/2320ab391f3804a9ddea9c5c86eb86467bb1dbf8))
+          *  Use a copy of auth data when reconnecting (#509) ([de20be91](https://github.com/python-zk/kazoo/commit/de20be917855713169863b65a7aa0634fb78b698))
+          *  change KazooRetry to uniformly jitter over the whole backoff interval (#521) ([60366d2c](https://github.com/python-zk/kazoo/commit/60366d2c7910fc833991fad8e04bbe33817c0544))
+        * **recipe:**  Delete lock node in queue recipe if entry already consumed ([7a8167de](https://github.com/python-zk/kazoo/commit/7a8167dea381b3a2015c869a443c96b9d5179411))
+        
+        #### Doc
+        
+        *   make badges link to travis and pypi (#528) ([367a1df3](https://github.com/python-zk/kazoo/commit/367a1df35b3b168580327e9f52a4cb9c000ea750))
+        *   specify description type for pypi to render correctly ([cc4006e6](https://github.com/python-zk/kazoo/commit/cc4006e6a8ea9441b01a631f3350357a8a2e4088))
+        *   remove broken downloads badge ([47e07a96](https://github.com/python-zk/kazoo/commit/47e07a9674713b0756bce0811545c4442d40b60b))
+        * **core:**  fix broken zookeeper programmers guide link ([8ecf8a50](https://github.com/python-zk/kazoo/commit/8ecf8a50c746ab7cc588ce9ac10a91ad1d1e5f34))
+        
+        
+        
+        <a name="2.5.0"></a>
+        ## 2.5.0 (2018-06-01)
+        
+        
+        #### Performance
+        
+        * **recipe:**  Give TreeCache standalone queue ([4456f180](https://github.com/python-zk/kazoo/commit/4456f180735a0f8520bfc42474de9d27fa01bb2c))
+        
+        #### Doc
+        
+        *   Correctly document supported versions ([f860de52](https://github.com/python-zk/kazoo/commit/f860de5284e8ba7d0ed4171d9e5c5bef41f6b64d))
+        *   Add license to Wheel ([43d156de](https://github.com/python-zk/kazoo/commit/43d156de3d41173d7baf6e8edb4efa377b3732fc))
+        *   minor tweaks to contributing.md (#464) ([5837d11b](https://github.com/python-zk/kazoo/commit/5837d11bb541be1296e1b3c1842b11ceb7e743d4))
+        
+        #### Features
+        
+        * **recipe:**  allow non ephemeral locking ([6f7a603d](https://github.com/python-zk/kazoo/commit/6f7a603de9f04ec46d9946c6f5b1cb6e2b913b63))
+        
+        #### Chore
+        
+        *   drop python 2.6 compatible gevent ([2e8dcd38](https://github.com/python-zk/kazoo/commit/2e8dcd3836d01640f07e8de911cdfb3639f97d20))
+        *   remove debian packaging (#468) ([a28423aa](https://github.com/python-zk/kazoo/commit/a28423aac7f33111388372dec50653a3091b9045))
+        *   stop bundling virtualenv ([af9b4cab](https://github.com/python-zk/kazoo/commit/af9b4cab39982d961647afca8119816ffe7bf5e6))
+        *   remove python 3.3 from tox ([cf66474b](https://github.com/python-zk/kazoo/commit/cf66474b27b4efc9f65e292434c2fcffb697d34d))
+        *   remove `easy_install` instructions ([6e6627d5](https://github.com/python-zk/kazoo/commit/6e6627d58628dec11d127fc5508f9a1d16e9c317))
+        
+        #### Bug Fixes
+        
+        *   Pass watch as keyword arg instead of positional arg (#495) ([23850792](https://github.com/python-zk/kazoo/commit/2385079267db0bea6793c4f20588644381803a98))
+        *   need gevent >= 1.2, not > 1.1 ([18f3531b](https://github.com/python-zk/kazoo/commit/18f3531b605119a547cfc4d5a4223b4b3f185405))
+        *   Remove use of "async" as a variable ([225d3369](https://github.com/python-zk/kazoo/commit/225d3369c7a0736125a9375951a079f70fbe9e79), closes [#455](https://github.com/python-zk/kazoo/issues/455))
+        * **core:**
+          *  Fix gevent 1.3b1+ timeout import ([257b5896](https://github.com/python-zk/kazoo/commit/257b58961f7ddd9db04d6efa070739a1b0404487))
+          *  Correctly fire multiple callbacks ([0905c47b](https://github.com/python-zk/kazoo/commit/0905c47bff3cfc42382daff0d5ac81189c8ba46d))
+          *  resolve race in IAsyncResult.wait() (#487) ([4d268adf](https://github.com/python-zk/kazoo/commit/4d268adf9837836f05dde5ec81be0d7bbd759e78))
+        * **recipe:**
+          *  conn hangs when TreeCache refreshing ([11194137](https://github.com/python-zk/kazoo/commit/111941371daec00a2ecb5d8c29b9b1d35d6aa4ff))
+          *  Unexpected exceptions break TreeCache ([db0c2d4f](https://github.com/python-zk/kazoo/commit/db0c2d4f8ab5ecfb367b7b2accfd9c52c1c91fcd))
+        
+        #### Refactor
+        
+        *   Unify queue factory in various handlers ([cbd02f5c](https://github.com/python-zk/kazoo/commit/cbd02f5ccc6ea9e6dd6b5da01a0397ea649143a0))
+        
+        
+        
+        <a name="2.4.0"></a>
+        ## 2.4.0 (2017-06-14)
+        
+        **PYTHON SUPPORTED VERSIONS CHANGE**: Please note that Kazoo no longer tests
+        on Python 2.6 or 3.3. Tested versions are 2.7, 3.4, 3.5, 3.6, and PyPy. The
+        multiple endpoint support for KazooClient may not work correctly on 2.6.
+        
+        #### Bug Fixes
+        
+        *   add missed parens to LockingQueue function call. ([88cf4aa7](https://github.com/python-zk/kazoo/commit/88cf4aa7bcd1437a44f6d3aeec34989c467fcf9d))
+        * **core:**  revert PR #305 SetWatches which caused RuntimeError ([a7b45390](https://github.com/python-zk/kazoo/commit/a7b45390f3720a33c9ad3896a8a185bfb2628839))
+        
+        #### Features
+        
+        *   pep8 all the things ([92880342](https://github.com/python-zk/kazoo/commit/928803420721b81962e50d425610e62b0c12e438), closes [#445](https://github.com/python-zk/kazoo/issues/445))
+        *   drop Python 2.6/3.3 official support, add 3.5/3.6 testing ([2faba9ff](https://github.com/python-zk/kazoo/commit/2faba9ff3bdeff151ac6c922bf65b2dcf9c7bd7b), closes [#441](https://github.com/python-zk/kazoo/issues/441))
+        * **core:**
+          *  allow multiple endpoints in KazooClient hosts arg ([72a8d96c](https://github.com/python-zk/kazoo/commit/72a8d96ca188c3c2e93bd0243283539ebd6c16f1), closes [#411](https://github.com/python-zk/kazoo/issues/411))
+          *  use epoll when available to support fds > 1023 ([267e61b4](https://github.com/python-zk/kazoo/commit/267e61b4323bc13505e8933fa9b89d0591af3a69), closes [#171](https://github.com/python-zk/kazoo/issues/171))
+        * **recipe:**  Add TreeCache recipe ([ec8b337e](https://github.com/python-zk/kazoo/commit/ec8b337e6f1a4ff12e669f4b96ca98fb37ee5d8a))
+        
+        
+        
+        <a name="2.3.1"></a>
+        ## 2.3.1 (2017-06-01)
+        
+        
+        #### Chore
+        
+        *   update MANIFEST.in to reflect changes to filenames ([c9a38c5d](https://github.com/python-zk/kazoo/commit/c9a38c5d650d6d92ff30fd3c1c792fc71db9ce02))
+        *   add travis deployment and update ZK versions ([7d5d59cb](https://github.com/python-zk/kazoo/commit/7d5d59cb049244b89625d621c9d91d9a44c4b051), closes [#436](https://github.com/python-zk/kazoo/issues/436))
+        
+        2.3.0 (2017-05-31)
+        ------------------
+        
+        Please note, there have been a few dozen merges that failed to update the
+        changelog here. As such, the log here should not be considered conclusive as
+        to the changes that are arriving in 2.3.0.
+        
+        Changes being made now to ensure more accuracy in the changelog will appear
+        in all future versions going forward. Read the commit history for a better
+        understanding of changes merged between 2.2.1 and 2.3.0.
+        
+        All future commits must abide by the new CONTRIBUTING.md document describing
+        how to label commits so they can be automatically used to automatically
+        generate an accurate changelog.
+        
+        *WARNING:* THIS IS THE LAST KAZOO RELEASE THAT SUPPORTS PYTHON 2.6. ALL FUTURE
+        VERSIONS WILL REQUIRE PYTHON 2.7 AND ABOVE.
+        
+        ### Features
+        
+        -   allow having observers and different sized clusters
+        
+        ### Bug Handling
+        
+        -   \#372: fully resolve multiple records for hosts in the zookeeper
+            connection string
+        
+        ### Documentation
+        
+        -   Fix the recipe examples, so they actually work by connecting to
+            ZooKeeper. Without start() they just hang and can't be killed.
+        
+        2.2.1 (2015-06-17)
+        ------------------
+        
+        ### Bug Handling
+        
+        -   handle NameError with basestring on py3k.
+        
+        ### Documentation
+        
+        2.2 (2015-06-15)
+        ----------------
+        
+        ### Documentation
+        
+        ### Features
+        
+        -   Issue \#234: Add support for reconfig cluster membership operation
+        
+        ### Bug Handling
+        
+        -   \#315: multiple acquires of a kazoo lock using the lock recipe would
+            block when using acquire even when non-blocking is specified (only
+            when the lock was/has been already acquired).
+        -   \#318: At exit register takes `*args` and `**kwargs` not args and
+            kargs
+        
+        ### Documentation
+        
+        2.1 (2015-05-11)
+        ----------------
+        
+        ### Features
+        
+        -   Start running tests against Zookeeper 3.5.0 alpha and explicitly
+            configure the admin.serverPort in tests to avoid port conflicts. The
+            Zookeeper alpha version is not yet officially supported.
+        -   Integrate eventlet *handler* support into kazoo so that along with
+            [gevent, threading] handlers there can now be a dedicated eventlet
+            handler for projects that need to (or want to) use eventlet (such as
+            those working in the openstack community). The
+            `requirements_eventlet.txt` file lists the optional eventlet
+            requirement(s) that needs to be satisfied when this new handler is
+            used.
+        -   Use `six` to nicely handle the cross compatibility of kazoo with
+            python 2.x and 3.x (reducing/removing the need to have custom
+            compatibility code that replicates what six already provides).
+        -   Add `state_change_event` to
+            `kazoo.recipe.partitioner.SetPartitioner` which is set on every
+            state change.
+        -   Add a NonBlockingLease recipe. The recipe allows e.g. cron jobs
+            scheduled on multiple machines to ensure that at most N instances
+            will run a particular job, with lease timeout for graceful handover
+            in case of node failures.
+        
+        ### Bug Handling
+        
+        -   \#291: Kazoo lock recipe was only partially re-entrant in that
+            multiple calls to acquire would obtain the the lock but the first
+            call to release would remove the underlying lock. This would leave
+            the X - 1 other acquire statements unprotected (and no longer
+            holding there expected lock). To fix this the comment about that
+            lock recipe being re-entrant has been removed and multiple acquires
+            will now block when attempted.
+        -   \#78: Kazoo now uses socketpairs instead of pipes making it
+            compatible with Windows.
+        -   \#144, \#221: Let client.command work with IPv6 addresses.
+        -   \#216: Fixed timeout for ConnectionHandler.\_invoke.
+        -   \#261: Creating a sequential znode under / doesn't work.
+        -   \#274: Add server\_version() retries (by default 4 attempts will be
+            made) to better handle flakey responses.
+        -   \#271: Fixed handling of KazooState.SUSPENDED in SetPartitioner.
+        -   \#283: Fixed a race condition in SetPartitioner when party changes
+            during handling of lock acquisition.
+        -   \#303: don't crash on random input as the hosts string.
+        
+        ### Documentation
+        
+        -   \#222: Document that committed on the transaction is used to ensure
+            only one commit and is not an indicator of whether operations in the
+            transaction returned desired results.
+        
+        2.0 (2014-06-19)
+        ----------------
+        
+        ### Documentation
+        
+        -   Extend support to Python 3.4, deprecating Python 3.2.
+        -   Issue \#198: Mention Zake as a sophisticated kazoo mock testing
+            library.
+        -   Issue \#181: Add documentation on basic logging setup.
+        
+        2.0b1 (2014-04-24)
+        ------------------
+        
+        ### API Changes
+        
+        -   Null or None data is no longer treated as "". Pull req \#165, patch
+            by Raul Gutierrez S. This will affect how you should treat null data
+            in a znode vs. an empty string.
+        -   Passing acl=[] to create() now works properly instead of an
+            InvalidACLError as it returned before. Patch by Raul Gutierrez S in
+            PR \#164.
+        -   Removed the dependency on zope.interface. The classes in the
+            interfaces module are left for documentation purposes only (issue
+            \#131).
+        
+        ### Features
+        
+        -   Logging levels have been reduced.
+            -   Logging previously at the `logging.DEBUG` level is now logged at
+            the `kazoo.loggingsupport.BLATHER` level (5).
+            -   Some low-level logging previously at the `logging.INFO` level is
+            now logged at the `logging.DEBUG` level.
+        -   Issue \#133: Introduce a new environment variable
+            ZOOKEEPER\_PORT\_OFFSET for the testing support, to run the testing
+            cluster on a different range.
+        
+        ### Bug Handling
+        
+        -   When authenticating via add\_auth() the auth data will be saved to
+            ensure that the authentication happens on reconnect (as is the case
+            when feeding auth data via KazooClient's constructor). PR \#172,
+            patch by Raul Gutierrez S.
+        -   Change gevent import to remove deprecation warning when newer gevent
+            is used. PR \#191, patch by Hiroaki Kawai.
+        -   Lock recipe was failing to use the client's sleep\_func causing
+            issues with gevent. Issue \#150.
+        -   Calling a DataWatch or ChildrenWatch instance twice (decorator) now
+            throws an exception as only a single function can be associated with
+            a single watcher. Issue \#154.
+        -   Another fix for atexit handling so that when disposing of
+            connections the atexit handler is removed. PR \#190, patch by Devaev
+            Maxim.
+        -   Fix atexit handling for kazoo threading handler, PR \#183. Patch by
+            Brian Wickman.
+        -   Partitioner should handle a suspended connection properly and
+            restore an allocated state if it was allocated previously. Patch by
+            Manish Tomar.
+        -   Issue \#167: Closing a client that was never started throws a type
+            error. Patch by Joshua Harlow.
+        -   Passing dictionaries to KazooClient.\_\_init\_\_() wasn't actually
+            working properly. Patch by Ryan Uber.
+        -   Issue \#119: Handler timeout takes the max of the random interval or
+            the read timeout to ensure a negative number isn't used for the read
+            timeout.
+        -   Fix ordering of exception catches in lock.acquire as it was
+            capturing a parent exception before the child. Patch by ReneSac.
+        -   Fix issue with client.stop() not always setting the client state to
+            KeeperState.CLOSED. Patch by Jyrki Pulliainen in PR \#174.
+        -   Issue \#169: Fixed pipes leaking into child processes.
+        
+        ### Documentation
+        
+        -   Add section on contributing recipes, add maintainer/status
+            information for existing recipes.
+        -   Add note about alternate use of DataWatch.
+        
+        1.3.1 (2013-09-25)
+        ------------------
+        
+        ### Bug Handling
+        
+        -   \#118, \#125, \#128: Fix unknown variable in KazooClient
+            command\_retry argument handling.
+        -   \#126: Fix KazooRetry.copy to correctly copy sleep function.
+        -   \#118: Correct session/socket timeout conversion (int vs. float).
+        
+        ### Documentation
+        
+        -   \#121: Add a note about kazoo.recipe.queue.LockingQueue requiring a
+            Zookeeper 3.4+ server.
+        
+        1.3 (2013-09-05)
+        ----------------
+        
+        ### Features
+        
+        -   \#115: Limit the backends we use for SLF4J during tests.
+        -   \#112: Add IPv6 support. Patch by Dan Kruchinin.
+        
+        1.2.1 (2013-08-01)
+        ------------------
+        
+        ### Bug Handling
+        
+        -   Issue \#108: Circular import fail when importing
+            kazoo.recipe.watchers directly has now been resolved. Watchers and
+            partitioner properly import the KazooState from
+            kazoo.protocol.states rather than kazoo.client.
+        -   Issue \#109: Partials not usable properly as a datawatch call can
+            now be used. All funcs will be called with 3 args and fall back to 2
+            args if there's an argument error.
+        -   Issue \#106, \#107: client.create\_async didn't strip change root
+            from the returned path.
+        
+        1.2 (2013-07-24)
+        ----------------
+        
+        ### Features
+        
+        -   KazooClient can now be stopped more reliably even if its in the
+            middle of a long retry sleep. This utilizes the new interrupt
+            feature of KazooRetry which lets the sleep be broken down into
+            chunks and an interrupt function called to determine if the retry
+            should fail early.
+        -   Issue \#62, \#92, \#89, \#101, \#102: Allow KazooRetry to have a max
+            deadline, transition properly when connection fails to LOST, and
+            setup separate connection retry behavior from client command retry
+            behavior. Patches by Mike Lundy.
+        -   Issue \#100: Make it easier to see exception context in threading
+            and connection modules.
+        -   Issue \#85: Increase information density of logs and don't prevent
+            dynamic reconfiguration of log levels at runtime.
+        -   Data-watchers for the same node are no longer 'stacked'. That is, if
+            a get and an exists call occur for the same node with the same watch
+            function, then it will be registered only once. This change results
+            in Kazoo behaving per Zookeeper client spec regarding repeat watch
+            use.
+        
+        ### Bug Handling
+        
+        -   Issue \#53: Throw a warning upon starting if the chroot path doesn't
+            exist so that it's more obvious when the chroot should be created
+            before performing more operations.
+        -   Kazoo previously would let the same function be registered as a
+            data-watch or child-watch multiple times, and then call it multiple
+            times upon being triggered. This was non-compliant Zookeeper client
+            behavior, the same watch can now only be registered once for the
+            same znode path per Zookeeper client documentation.
+        -   Issue \#105: Avoid rare import lock problems by moving module
+            imports in client.py to the module scope.
+        -   Issue \#103: Allow prefix-less sequential znodes.
+        -   Issue \#98: Extend testing ZK harness to work with different file
+            locations on some versions of Debian/Ubuntu.
+        -   Issue \#97: Update some docstrings to reflect current state of
+            handlers.
+        -   Issue \#62, \#92, \#89, \#101, \#102: Allow KazooRetry to have a max
+            deadline, transition properly when connection fails to LOST, and
+            setup separate connection retry behavior from client command retry
+            behavior. Patches by Mike Lundy.
+        
+        ### API Changes
+        
+        -   The kazoo.testing.harness.KazooTestHarness class directly inherits
+            from unittest.TestCase and you need to ensure to call its
+            \_\_init\_\_ method.
+        -   DataWatch no longer takes any parameters besides for the optional
+            function during instantiation. The additional options are now
+            implicitly True, with the user being left to ignore events as they
+            choose. See the DataWatch API docs for more information.
+        -   Issue \#99: Better exception raised when the writer fails to close.
+            A WriterNotClosedException that inherits from KazooException is now
+            raised when the writer fails to close in time.
+        
+        1.1 (2013-06-08)
+        ----------------
+        
+        ### Features
+        
+        -   Issue \#93: Add timeout option to lock/semaphore acquire methods.
+        -   Issue \#79 / \#90: Add ability to pass the WatchedEvent to DataWatch
+            and ChildWatch functions.
+        -   Respect large client timeout values when closing the connection.
+        -   Add a max\_leases consistency check to the semaphore recipe.
+        -   Issue \#76: Extend testing helpers to allow customization of the
+            Java classpath by specifying the new ZOOKEEPER\_CLASSPATH
+            environment variable.
+        -   Issue \#65: Allow non-blocking semaphore acquisition.
+        
+        ### Bug Handling
+        
+        -   Issue \#96: Provide Windows compatibility in testing harness.
+        -   Issue \#95: Handle errors deserializing connection response.
+        -   Issue \#94: Clean up stray bytes in connection pipe.
+        -   Issue \#87 / \#88: Allow re-acquiring lock after cancel.
+        -   Issue \#77: Use timeout in initial socket connection.
+        -   Issue \#69: Only ensure path once in lock and semaphore recipes.
+        -   Issue \#68: Closing the connection causes exceptions to be raised by
+            watchers which assume the connection won't be closed when running
+            commands.
+        -   Issue \#66: Require ping reply before sending another ping,
+            otherwise the connection will be considered dead and a
+            ConnectionDropped will be raised to trigger a reconnect.
+        -   Issue \#63: Watchers weren't reset on lost connection.
+        -   Issue \#58: DataWatcher failed to re-register for changes after
+            non-existent node was created then deleted.
+        
+        ### API Changes
+        
+        -   KazooClient.create\_async now supports the makepath argument.
+        -   KazooClient.ensure\_path now has an async version,
+            ensure\_path\_async.
+        
+        1.0 (2013-03-26)
+        ----------------
+        
+        ### Features
+        
+        -   Added a LockingQueue recipe. The queue first locks an item and
+            removes it from the queue only after the consume() method is called.
+            This enables other nodes to retake the item if an error occurs on
+            the first node.
+        
+        ### Bug Handling
+        
+        -   Issue \#50: Avoid problems with sleep function in mixed
+            gevent/threading setup.
+        -   Issue \#56: Avoid issues with watch callbacks evaluating to false.
+        
+        1.0b1 (2013-02-24)
+        ------------------
+        
+        ### Features
+        
+        -   Refactored the internal connection handler to use a single thread.
+            It now uses a deque and pipe to signal the ZK thread that there's a
+            new command to send, so that the ZK thread can send it, or retrieve
+            a response. Processing ZK requests and responses serially in a
+            single thread eliminates the need for a bunch of the locking, the
+            peekable queue and two threads working on the same underlying
+            socket.
+        -   Issue \#48: Added documentation for the retry helper module.
+        -   Issue \#55: Fix os.pipe file descriptor leak and introduce a
+            KazooClient.close method. The method is particular useful in tests,
+            where multiple KazooClients are created and closed in the same
+            process.
+        
+        ### Bug Handling
+        
+        -   Issue \#46: Avoid TypeError in GeneratorContextManager on process
+            shutdown.
+        -   Issue \#43: Let DataWatch return node data if allow\_missing\_node
+            is used.
+        
+        0.9 (2013-01-07)
+        ----------------
+        
+        ### API Changes
+        
+        -   When a retry operation ultimately fails, it now raises a
+            kazoo.retry.RetryFailedError exception, instead of a general
+            Exception instance. RetryFailedError also inherits from the base
+            KazooException.
+        
+        ### Features
+        
+        -   Improvements to Debian packaging rules.
+        
+        ### Bug Handling
+        
+        -   Issue \#39 / \#41: Handle connection dropped errors during session
+            writes. Ensure client connection is re-established to a new ZK node
+            if available.
+        -   Issue \#38: Set CLOEXEC flag on all sockets when available.
+        -   Issue \#37 / \#40: Handle timeout errors during select calls on
+            sockets.
+        -   Issue \#36: Correctly set ConnectionHandler.writer\_stopped even if
+            an exception is raised inside the writer, like a retry operation
+            failing.
+        
+        0.8 (2012-10-26)
+        ----------------
+        
+        ### API Changes
+        
+        -   The KazooClient.\_\_init\_\_ took as watcher argument as its second
+            keyword argument. The argument had no effect anymore since version
+            0.5 and was removed.
+        
+        ### Bug Handling
+        
+        -   Issue \#35: KazooClient.\_\_init\_\_ didn't pass on
+            retry\_max\_delay to the retry helper.
+        -   Issue \#34: Be more careful while handling socket connection errors.
+        
+        0.7 (2012-10-15)
+        ----------------
+        
+        ### Features
+        
+        -   DataWatch now has a allow\_missing\_node setting that allows a watch
+            to be set on a node that doesn't exist when the DataWatch is
+            created.
+        -   Add new Queue recipe, with optional priority support.
+        -   Add new Counter recipe.
+        -   Added debian packaging rules.
+        
+        ### Bug Handling
+        
+        -   Issue \#31 fixed: Only catch KazooExceptions in catch-all calls.
+        -   Issue \#15 fixed again: Force sleep delay to be a float to appease
+            gevent.
+        -   Issue \#29 fixed: DataWatch and ChildrenWatch properly re-register
+            their watches on server disconnect.
+        
+        0.6 (2012-09-27)
+        ----------------
+        
+        ### API Changes
+        
+        -   Node paths are assumed to be Unicode objects. Under Python 2
+            pure-ascii strings will also be accepted. Node values are considered
+            bytes. The byte type is an alias for str under Python 2.
+        -   New KeeperState.CONNECTED\_RO state for Zookeeper servers connected
+            in read-only mode.
+        -   New NotReadOnlyCallError exception when issuing a write change
+            against a server thats currently read-only.
+        
+        ### Features
+        
+        -   Add support for Python 3.2, 3.3 and PyPy (only for the threading
+            handler).
+        -   Handles connecting to Zookeeper 3.4+ read-only servers.
+        -   Automatic background scanning for a Read/Write server when connected
+            to a server in read-only mode.
+        -   Add new Semaphore recipe.
+        -   Add a new retry\_max\_delay argument to the client and by default
+            limit the retry delay to at most an hour regardless of exponential
+            backoff settings.
+        -   Add new randomize\_hosts argument to KazooClient, allowing one to
+            disable host randomization.
+        
+        ### Bug Handling
+        
+        -   Fix bug with locks not handling intermediary lock contenders
+            disappearing.
+        -   Fix bug with set\_data type check failing to catch unicode values.
+        -   Fix bug with gevent 0.13.x backport of peekable queue.
+        -   Fix PatientChildrenWatch to use handler specific sleep function.
+        
+        0.5 (2012-09-06)
+        ----------------
+        
+        Skipping a version to reflect the magnitude of the change. Kazoo is now
+        a pure Python client with no C bindings. This release should run without
+        a problem on alternate Python implementations such as PyPy and Jython.
+        Porting to Python 3 in the future should also be much easier.
+        
+        ### Documentation
+        
+        -   Docs have been restructured to handle the new classes and locations
+            of the methods from the pure Python refactor.
+        
+        ### Bug Handling
+        
+        This change may introduce new bugs, however there is no longer the
+        possibility of a complete Python segfault due to errors in the C library
+        and/or the C binding.
+        
+        -   Possible segfaults from the C lib are gone.
+        -   Password mangling due to the C lib is gone.
+        -   The party recipes didn't set their participating flag to False after
+            leaving.
+        
+        ### Features
+        
+        -   New client.command and client.server\_version API, exposing
+            Zookeeper's four letter commands and giving access to structured
+            version information.
+        -   Added 'include\_data' option for get\_children to include the node's
+            Stat object.
+        -   Substantial increase in logging data with debug mode. All
+            correspondence with the Zookeeper server can now be seen to help in
+            debugging.
+        
+        ### API Changes
+        
+        -   The testing helpers have been moved from testing.\_\_init\_\_ into a
+            testing.harness module. The official API's of KazooTestCase and
+            KazooTestHarness can still be directly imported from testing.
+        -   The kazoo.handlers.util module was removed.
+        -   Backwards compatible exception class aliases are provided for now in
+            kazoo exceptions for the prior C exception names.
+        -   Unicode strings now work fine for node names and are properly
+            converted to and from unicode objects.
+        -   The data value argument for the create and create\_async methods of
+            the client was made optional and defaults to an empty byte string.
+            The data value must be a byte string. Unicode values are no longer
+            allowed and will raise a TypeError.
+        
+        0.3 (2012-08-23)
+        ----------------
+        
+        ### API Changes
+        
+        -   Handler interface now has an rlock\_object for use by recipes.
+        
+        ### Bug Handling
+        
+        -   Fixed password bug with updated zc-zookeeper-static release, which
+            retains null bytes in the password properly.
+        -   Fixed reconnect hammering, so that the reconnection follows retry
+            jitter and retry backoff's.
+        -   Fixed possible bug with using a threading.Condition in the set
+            partitioner. Set partitioner uses new rlock\_object handler API to
+            get an appropriate RLock for gevent.
+        -   Issue \#17 fixed: Wrap timeout exceptions with staticmethod so they
+            can be used directly as intended. Patch by Bob Van Zant.
+        -   Fixed bug with client reconnection looping indefinitely using an
+            expired session id.
+        
+        0.2 (2012-08-12)
+        ----------------
+        
+        ### Documentation
+        
+        -   Fixed doc references to start\_async using an AsyncResult object, it
+            uses an Event object.
+        
+        ### Bug Handling
+        
+        -   Issue \#16 fixed: gevent zookeeper logging failed to handle a monkey
+            patched logging setup. Logging is now setup such that a greenlet is
+            used for logging messages under gevent, and the thread one is used
+            otherwise.
+        -   Fixed bug similar to \#14 for ChildrenWatch on the session listener.
+        -   Issue \#14 fixed: DataWatch had inconsistent handling of the node it
+            was watching not existing. DataWatch also properly spawns its
+            \_get\_data function to avoid blocking session events.
+        -   Issue \#15 fixed: sleep\_func for SequentialGeventHandler was not
+            set on the class appropriately leading to additional arguments being
+            passed to gevent.sleep.
+        -   Issue \#9 fixed: Threads/greenlets didn't gracefully shut down.
+            Handler now has a start/stop that is used by the client when calling
+            start and stop that shuts down the handler workers. This addresses
+            errors and warnings that could be emitted upon process shutdown
+            regarding a clean exit of the workers.
+        -   Issue \#12 fixed: gevent 0.13 doesn't use the same
+            start\_new\_thread as gevent 1.0 which resulted in a fully
+            monkey-patched environment halting due to the wrong thread. Updated
+            to use the older kazoo method of getting the real thread module
+            object.
+        
+        ### API Changes
+        
+        -   The KazooClient handler is now officially exposed as
+            KazooClient.handler so that the appropriate sync objects can be used
+            by end-users.
+        -   Refactored ChildrenWatcher used by SetPartitioner into a publicly
+            exposed PatientChildrenWatch under recipe.watchers.
+        
+        ### Deprecations
+        
+        -   connect/connect\_async has been renamed to start/start\_async to
+            better match the stop to indicate connection handling. The prior
+            names are aliased for the time being.
+        
+        ### Recipes
+        
+        -   Added Barrier and DoubleBarrier implementation.
+        
+        0.2b1 (2012-07-27)
+        ------------------
+        
+        ### Bug Handling
+        
+        -   ZOOKEEPER-1318: SystemError is caught and rethrown as the proper
+            invalid state exception in older zookeeper python bindings where
+            this issue is still valid.
+        -   ZOOKEEPER-1431: Install the latest zc-zookeeper-static library or
+            use the packaged ubuntu one for ubuntu 12.04 or later.
+        -   ZOOKEEPER-553: State handling isn't checked via this method, we
+            track it in a simpler manner with the watcher to ensure we know the
+            right state.
+        
+        ### Features
+        
+        -   Exponential backoff with jitter for retrying commands.
+        -   Gevent 0.13 and 1.0b support.
+        -   Lock, Party, SetPartitioner, and Election recipe implementations.
+        -   Data and Children watching API's.
+        -   State transition handling with listener registering to handle
+            session state changes (choose to fatal the app on session
+            expiration, etc.)
+        -   Zookeeper logging stream redirected into Python logging channel
+            under the name 'Zookeeper'.
+        -   Base client library with handler support for threading and gevent
+            async environments.
+        
+        
+Keywords: zookeeper lock leader configuration
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Intended Audience :: Developers
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Communications
+Classifier: Topic :: System :: Distributed Computing
+Classifier: Topic :: System :: Networking
+Description-Content-Type: text/markdown
+Provides-Extra: test
+Provides-Extra: sasl

+ 26 - 0
desktop/core/ext-py/kazoo-2.8.0/README.md

@@ -0,0 +1,26 @@
+Kazoo
+=====
+
+[![Build Status](https://travis-ci.org/python-zk/kazoo.svg?branch=master)](https://travis-ci.org/python-zk/kazoo)
+[![Latest Version](https://img.shields.io/pypi/v/kazoo.svg)](https://pypi.org/project/kazoo/)
+[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
+
+`kazoo` implements a higher level API to [Apache
+Zookeeper](http://zookeeper.apache.org/) for Python clients.
+
+See [the full docs](http://kazoo.rtfd.org/) for more information.
+
+License
+-------
+
+`kazoo` is offered under the Apache License 2.0.
+
+Authors
+-------
+
+`kazoo` started under the [Nimbus
+Project](http://www.nimbusproject.org/) and through collaboration with
+the open-source community has been merged with code from
+[Mozilla](http://www.mozilla.org/) and the [Zope
+Corporation](http://zope.com/). It has since gathered an active
+community of over fifty contributors.

+ 22 - 21
desktop/core/ext-py/kazoo-2.0/docs/Makefile → desktop/core/ext-py/kazoo-2.8.0/docs/Makefile

@@ -14,64 +14,53 @@ ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
 # the i18n builder cannot share the environment and doctrees with the others
 I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
 
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
+.PHONY: help
 help:
 	@echo "Please use \`make <target>' where <target> is one of"
-	@echo "  html       to make standalone HTML files"
-	@echo "  dirhtml    to make HTML files named index.html in directories"
-	@echo "  singlehtml to make a single large HTML file"
-	@echo "  pickle     to make pickle files"
-	@echo "  json       to make JSON files"
-	@echo "  htmlhelp   to make HTML files and a HTML help project"
-	@echo "  qthelp     to make HTML files and a qthelp project"
-	@echo "  devhelp    to make HTML files and a Devhelp project"
-	@echo "  epub       to make an epub"
-	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-	@echo "  text       to make text files"
-	@echo "  man        to make manual pages"
-	@echo "  texinfo    to make Texinfo files"
-	@echo "  info       to make Texinfo files and run them through makeinfo"
-	@echo "  gettext    to make PO message catalogs"
-	@echo "  changes    to make an overview of all changed/added/deprecated items"
-	@echo "  linkcheck  to check all external links for integrity"
-	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
+	@egrep '^\.PHONY: [a-zA-Z_-]+ .*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = "(: |##)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
 
+.PHONY: clean
 clean:
 	-rm -rf $(BUILDDIR)/*
 
+.PHONY: html ## to make standalone HTML files
 html:
 	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
 	@echo
 	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
 
+.PHONY: dirhtml ## to make HTML files named index.html in directories
 dirhtml:
 	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
 	@echo
 	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
 
+.PHONY: singlehtml ## to make a single large HTML file
 singlehtml:
 	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
 	@echo
 	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
 
+.PHONY: pickle ## to make pickle files
 pickle:
 	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
 	@echo
 	@echo "Build finished; now you can process the pickle files."
 
+.PHONY: json ## to make JSON files
 json:
 	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
 	@echo
 	@echo "Build finished; now you can process the JSON files."
 
+.PHONY: htmlhelp ## to make HTML files and a HTML help project
 htmlhelp:
 	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
 	@echo
 	@echo "Build finished; now you can run HTML Help Workshop with the" \
 	      ".hhp project file in $(BUILDDIR)/htmlhelp."
 
+.PHONY: qthelp ## to make HTML files and a qthelp project
 qthelp:
 	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
 	@echo
@@ -81,6 +70,7 @@ qthelp:
 	@echo "To view the help file:"
 	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/kazoo.qhc"
 
+.PHONY: devhelp ## to make HTML files and a Devhelp project
 devhelp:
 	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
 	@echo
@@ -90,11 +80,13 @@ devhelp:
 	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/kazoo"
 	@echo "# devhelp"
 
+.PHONY: epub ## to make an epub
 epub:
 	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
 	@echo
 	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
 
+.PHONY: latex ## to make LaTeX files, you can set PAPER=a4 or PAPER=letter
 latex:
 	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
 	@echo
@@ -102,22 +94,26 @@ latex:
 	@echo "Run \`make' in that directory to run these through (pdf)latex" \
 	      "(use \`make latexpdf' here to do that automatically)."
 
+.PHONY: latexpdf ## to make LaTeX files and run them through pdflatex
 latexpdf:
 	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
 	@echo "Running LaTeX files through pdflatex..."
 	$(MAKE) -C $(BUILDDIR)/latex all-pdf
 	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
 
+.PHONY: text ## to make text files
 text:
 	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
 	@echo
 	@echo "Build finished. The text files are in $(BUILDDIR)/text."
 
+.PHONY: man ## to make manual pages
 man:
 	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
 	@echo
 	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
 
+.PHONY: texinfo ## to make Texinfo files
 texinfo:
 	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
 	@echo
@@ -125,28 +121,33 @@ texinfo:
 	@echo "Run \`make' in that directory to run these through makeinfo" \
 	      "(use \`make info' here to do that automatically)."
 
+.PHONY: info ## to make Texinfo files and run them through makeinfo
 info:
 	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
 	@echo "Running Texinfo files through makeinfo..."
 	make -C $(BUILDDIR)/texinfo info
 	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
 
+.PHONY: gettext ## to make PO message catalogs
 gettext:
 	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
 	@echo
 	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
 
+.PHONY: changes ## to make an overview of all changed/added/deprecated items
 changes:
 	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
 	@echo
 	@echo "The overview file is in $(BUILDDIR)/changes."
 
+.PHONY: linkcheck ## to check all external links for integrity
 linkcheck:
 	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
 	@echo
 	@echo "Link check complete; look for any errors in the above output " \
 	      "or in $(BUILDDIR)/linkcheck/output.txt."
 
+.PHONY: doctest ## to run all doctests embedded in the documentation (if enabled)
 doctest:
 	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
 	@echo "Testing of doctests in the sources finished, look at the " \

+ 2 - 0
desktop/core/ext-py/kazoo-2.0/docs/api.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api.rst

@@ -16,8 +16,10 @@ organized alphabetically by module name.
    api/interfaces
    api/protocol/states
    api/recipe/barrier
+   api/recipe/cache
    api/recipe/counter
    api/recipe/election
+   api/recipe/lease
    api/recipe/lock
    api/recipe/partitioner
    api/recipe/party

+ 21 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/client.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/client.rst

@@ -30,6 +30,27 @@ Public API
             A :class:`~kazoo.protocol.states.KazooState` attribute indicating
             the current higher-level connection state.
 
+            .. note::
+
+                Up to version 2.6.1, requests could only be submitted
+                in the CONNECTED state.  Requests submitted while
+                SUSPENDED would immediately raise a
+                :exc:`~kazoo.exceptions.SessionExpiredError`.  This
+                was problematic, as sessions are usually recovered on
+                reconnect.
+
+                Kazoo now simply queues requests submitted in the
+                SUSPENDED state, expecting a recovery.  This matches
+                the behavior of the Java and C clients.
+
+                Requests submitted in a LOST state still fail
+                immediately with the corresponding exception.
+
+                See:
+
+                  * https://github.com/python-zk/kazoo/issues/374 and
+                  * https://github.com/python-zk/kazoo/pull/570
+
     .. autoclass:: TransactionRequest
         :members:
         :member-order: bysource

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/exceptions.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/exceptions.rst


+ 18 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/eventlet.rst

@@ -0,0 +1,18 @@
+.. _eventlet_handler_module:
+
+:mod:`kazoo.handlers.eventlet`
+----------------------------
+
+.. automodule:: kazoo.handlers.eventlet
+
+Public API
+++++++++++
+
+    .. autoclass:: SequentialEventletHandler
+        :members:
+
+Private API
++++++++++++
+
+  .. autoclass:: AsyncResult
+     :members:

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/handlers/gevent.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/gevent.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/handlers/threading.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/threading.rst


+ 18 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/api/handlers/utils.rst

@@ -0,0 +1,18 @@
+.. _utils_module:
+
+:mod:`kazoo.handlers.utils`
+---------------------------
+
+.. automodule:: kazoo.handlers.utils
+
+Public API
+++++++++++
+
+    .. autofunction:: capture_exceptions
+    .. autofunction:: wrap
+
+Private API
++++++++++++
+
+  .. autofunction:: create_socket_pair
+  .. autofunction:: create_tcp_socket

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/interfaces.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/interfaces.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/protocol/states.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/protocol/states.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/barrier.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/barrier.rst


+ 26 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/cache.rst

@@ -0,0 +1,26 @@
+.. _cache_module:
+
+:mod:`kazoo.recipe.cache`
+----------------------------
+
+.. automodule:: kazoo.recipe.cache
+
+Public API
+++++++++++
+
+    .. autoclass:: TreeCache
+
+        .. automethod:: start
+        .. automethod:: close
+        .. automethod:: listen
+        .. automethod:: listen_fault
+        .. automethod:: get_data
+        .. automethod:: get_children
+
+    .. autoclass:: TreeEvent
+        :members:
+        :show-inheritance:
+
+    .. autoclass:: NodeData
+        :members:
+        :show-inheritance:

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/counter.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/counter.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/election.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/election.rst


+ 19 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/lease.rst

@@ -0,0 +1,19 @@
+.. _lease_module:
+
+:mod:`kazoo.recipe.lease`
+----------------------------
+
+.. automodule:: kazoo.recipe.lease
+
+Public API
+++++++++++
+
+    .. autoclass:: NonBlockingLease
+        :members:
+
+        .. automethod:: __init__
+
+    .. autoclass:: MultiNonBlockingLease
+        :members:
+
+        .. automethod:: __init__

+ 12 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/lock.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/lock.rst

@@ -13,6 +13,18 @@ Public API
 
         .. automethod:: __init__
 
+    .. autoclass:: ReadLock
+        :members:
+        :inherited-members:
+
+        .. automethod:: __init__
+
+    .. autoclass:: WriteLock
+        :members:
+        :inherited-members:
+
+        .. automethod:: __init__
+
     .. autoclass:: Semaphore
         :members:
 

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/partitioner.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/partitioner.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/party.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/party.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/queue.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/queue.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/recipe/watchers.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/recipe/watchers.rst


+ 23 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/api/retry.rst

@@ -0,0 +1,23 @@
+.. _retry_module:
+
+:mod:`kazoo.retry`
+----------------------------
+
+.. automodule:: kazoo.retry
+
+Public API
+++++++++++
+
+    .. autoclass:: KazooRetry
+        :members:
+        :member-order: bysource
+
+        .. automethod:: __init__
+
+        .. automethod:: __call__
+
+    .. autoexception:: ForceRetryError
+
+    .. autoexception:: RetryFailedError
+
+    .. autoexception:: InterruptedError

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/security.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/security.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/api/testing.rst → desktop/core/ext-py/kazoo-2.8.0/docs/api/testing.rst


+ 3 - 2
desktop/core/ext-py/kazoo-2.0/docs/async_usage.rst → desktop/core/ext-py/kazoo-2.8.0/docs/async_usage.rst

@@ -43,11 +43,12 @@ used because its possible that we might never connect and that should be
 handled gracefully.
 
 The :class:`~kazoo.handlers.gevent.SequentialGeventHandler` is used when you
-want to use gevent. Kazoo doesn't rely on gevents monkey patching and requires
+want to use gevent (and
+:class:`~kazoo.handlers.eventlet.SequentialEventletHandler` when eventlet is
+used). Kazoo doesn't rely on gevents/eventlet monkey patching and requires
 that you pass in the appropriate handler, the default handler is
 :class:`~kazoo.handlers.threading.SequentialThreadingHandler`.
 
-
 Asynchronous Callbacks
 ======================
 

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/basic_usage.rst → desktop/core/ext-py/kazoo-2.8.0/docs/basic_usage.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/changelog.rst → desktop/core/ext-py/kazoo-2.8.0/docs/changelog.rst


+ 5 - 3
desktop/core/ext-py/kazoo-2.0/docs/conf.py → desktop/core/ext-py/kazoo-2.8.0/docs/conf.py

@@ -63,10 +63,12 @@ copyright = u'2011-2014, Kazoo team'
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
-# The short X.Y version.
-version = '2.0'
 # The full version, including alpha/beta/rc tags.
-release = '2.0'
+from kazoo import version
+release = version.__version__
+
+# The short X.Y version.
+version = '.'.join(release.split('.')[:-1])
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

+ 1 - 0
desktop/core/ext-py/kazoo-2.8.0/docs/contributing.rst

@@ -0,0 +1 @@
+.. include:: ../CONTRIBUTING.rst

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/glossary.rst → desktop/core/ext-py/kazoo-2.8.0/docs/glossary.rst


+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/implementation.rst → desktop/core/ext-py/kazoo-2.8.0/docs/implementation.rst


+ 14 - 10
desktop/core/ext-py/kazoo-2.0/docs/index.rst → desktop/core/ext-py/kazoo-2.8.0/docs/index.rst

@@ -11,8 +11,9 @@ Kazoo features:
 * Data and Children Watchers
 * Simplified Zookeeper connection state tracking
 * Unified asynchronous API for use with greenlets or threads
-* Support for gevent 0.13 and gevent 1.0
-* Support for Zookeeper 3.3 and 3.4 servers
+* Support for `gevent`_ >= 1.2
+* Support for `eventlet`_
+* Support for Zookeeper 3.3, 3.4, and 3.5 servers
 * Integrated testing helpers for Zookeeper clusters
 * Pure-Python based implementation of the wire protocol, avoiding all the
   memory leaks, lacking features, and debugging madness of the C library
@@ -45,12 +46,12 @@ Why
 Using :term:`Zookeeper` in a safe manner can be difficult due to the variety of
 edge-cases in :term:`Zookeeper` and other bugs that have been present in the
 Python C binding. Due to how the C library utilizes a separate C thread for
-:term:`Zookeeper` communication some libraries like `gevent`_ also don't work
-properly by default.
+:term:`Zookeeper` communication some libraries like `gevent`_ (or `eventlet`_)
+also don't work properly by default.
 
 By utilizing a pure Python implementation, Kazoo handles all of these
 cases and provides a new asynchronous API which is consistent when
-using threads or `gevent`_ greenlets.
+using threads or `gevent`_ (or `eventlet`_) greenlets.
 
 Source Code
 ===========
@@ -61,13 +62,13 @@ zk/kazoo>`_.
 Bugs/Support
 ============
 
-Bugs and support issues should be reported on the `kazoo github issue tracker
+Bugs should be reported on the `kazoo github issue tracker
 <https://github.com/python-zk/kazoo/issues>`_.
 
 The developers of ``kazoo`` can frequently be found on the Freenode IRC
-network in the #zookeeper channel.
+network in the `\#zookeeper`_ channel.
 
-For general discussions, please use the
+For general discussions and support questions, please use the
 `python-zk <https://groups.google.com/forum/#!forum/python-zk>`_ mailing list
 hosted on Google Groups.
 
@@ -94,13 +95,16 @@ Authors
 ``kazoo`` started under the `Nimbus Project`_ and through collaboration with
 the open-source community has been merged with code from `Mozilla`_ and the
 `Zope Corporation`_. It has since gathered an active community of over two
-dozen contributors.
+dozen contributors from a variety of companies (twitter, mozilla, yahoo! and
+others).
 
 .. _Apache Zookeeper: http://zookeeper.apache.org/
-.. _Zookeeper Programmers Guide: http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html
+.. _Zookeeper Programmers Guide: https://zookeeper.apache.org/doc/current/zookeeperProgrammers.html
 .. _Zookeeper Recipes: http://zookeeper.apache.org/doc/current/recipes.html#sc_recoverableSharedLocks
 .. _Nimbus Project: http://www.nimbusproject.org/
 .. _Zope Corporation: http://zope.com/
 .. _Mozilla: http://www.mozilla.org/
 .. _Netflix Curator: https://github.com/Netflix/curator
 .. _gevent: http://gevent.org/
+.. _eventlet: http://eventlet.net/
+.. _\#zookeeper: irc://chat.freenode.net/zookeeper

+ 1 - 1
desktop/core/ext-py/kazoo-2.0/docs/install.rst → desktop/core/ext-py/kazoo-2.8.0/docs/install.rst

@@ -4,7 +4,7 @@
 Installing
 ==========
 
-kazoo can be installed via ``pip`` or ``easy_install``:
+kazoo can be installed via ``pip``:
 
 .. code-block:: bash
 

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/docs/make.bat → desktop/core/ext-py/kazoo-2.8.0/docs/make.bat


+ 1 - 1
desktop/core/ext-py/kazoo-2.0/docs/testing.rst → desktop/core/ext-py/kazoo-2.8.0/docs/testing.rst

@@ -7,7 +7,7 @@ Testing
 Kazoo has several test harnesses used internally for its own tests that are
 exposed as public API's for use in your own tests for common Zookeeper cluster
 management and session testing. They can be mixed in with your own `unittest`
-or `nose` tests along with a `mock` object that allows you to force specific
+or `pytest` tests along with a `mock` object that allows you to force specific
 `KazooClient` commands to fail in various ways.
 
 The test harness needs to be able to find the Zookeeper Java libraries. You

+ 1 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/__init__.py

@@ -0,0 +1 @@
+from .version import __version__  # noqa

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 424 - 135
desktop/core/ext-py/kazoo-2.8.0/kazoo/client.py


+ 15 - 7
desktop/core/ext-py/kazoo-2.0/kazoo/exceptions.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/exceptions.py

@@ -43,9 +43,10 @@ class WriterNotClosedException(KazooException):
     """
 
 
-class SaslException(KazooException):
-    """Raised if SASL encountered an error.
-    .. versionadded:: 2.1
+class SASLException(KazooException):
+    """Raised if SASL encountered a (local) error.
+
+    .. versionadded:: 2.7.0
     """
 
 
@@ -58,10 +59,7 @@ EXCEPTIONS = defaultdict(_invalid_error_code)
 
 def _zookeeper_exception(code):
     def decorator(klass):
-        def create(*args, **kwargs):
-            return klass(args, kwargs)
-
-        EXCEPTIONS[code] = create
+        EXCEPTIONS[code] = klass
         klass.code = code
         return klass
 
@@ -113,6 +111,16 @@ class BadArgumentsError(ZookeeperError):
     pass
 
 
+@_zookeeper_exception(-13)
+class NewConfigNoQuorumError(ZookeeperError):
+    pass
+
+
+@_zookeeper_exception(-14)
+class ReconfigInProcessError(ZookeeperError):
+    pass
+
+
 @_zookeeper_exception(-100)
 class APIError(ZookeeperError):
     pass

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/__init__.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/__init__.py


+ 179 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/eventlet.py

@@ -0,0 +1,179 @@
+"""A eventlet based handler."""
+from __future__ import absolute_import
+
+import contextlib
+import logging
+
+import eventlet
+from eventlet.green import select as green_select
+from eventlet.green import socket as green_socket
+from eventlet.green import time as green_time
+from eventlet.green import threading as green_threading
+from eventlet import queue as green_queue
+
+from kazoo.handlers import utils
+import kazoo.python2atexit as python2atexit
+
+
+LOG = logging.getLogger(__name__)
+
+# sentinel objects
+_STOP = object()
+
+
+@contextlib.contextmanager
+def _yield_before_after():
+    # Yield to any other co-routines...
+    #
+    # See: http://eventlet.net/doc/modules/greenthread.html
+    # for how this zero sleep is really a cooperative yield to other potential
+    # co-routines...
+    eventlet.sleep(0)
+    try:
+        yield
+    finally:
+        eventlet.sleep(0)
+
+
+class TimeoutError(Exception):
+    pass
+
+
+class AsyncResult(utils.AsyncResult):
+    """A one-time event that stores a value or an exception"""
+    def __init__(self, handler):
+        super(AsyncResult, self).__init__(handler,
+                                          green_threading.Condition,
+                                          TimeoutError)
+
+
+class SequentialEventletHandler(object):
+    """Eventlet handler for sequentially executing callbacks.
+
+    This handler executes callbacks in a sequential manner. A queue is
+    created for each of the callback events, so that each type of event
+    has its callback type run sequentially. These are split into two
+    queues, one for watch events and one for async result completion
+    callbacks.
+
+    Each queue type has a greenthread worker that pulls the callback event
+    off the queue and runs it in the order the client sees it.
+
+    This split helps ensure that watch callbacks won't block session
+    re-establishment should the connection be lost during a Zookeeper
+    client call.
+
+    Watch and completion callbacks should avoid blocking behavior as
+    the next callback of that type won't be run until it completes. If
+    you need to block, spawn a new greenthread and return immediately so
+    callbacks can proceed.
+
+    .. note::
+
+        Completion callbacks can block to wait on Zookeeper calls, but
+        no other completion callbacks will execute until the callback
+        returns.
+
+    """
+    name = "sequential_eventlet_handler"
+    queue_impl = green_queue.LightQueue
+    queue_empty = green_queue.Empty
+
+    def __init__(self):
+        """Create a :class:`SequentialEventletHandler` instance"""
+        self.callback_queue = self.queue_impl()
+        self.completion_queue = self.queue_impl()
+        self._workers = []
+        self._started = False
+
+    @staticmethod
+    def sleep_func(wait):
+        green_time.sleep(wait)
+
+    @property
+    def running(self):
+        return self._started
+
+    timeout_exception = TimeoutError
+
+    def _process_completion_queue(self):
+        while True:
+            cb = self.completion_queue.get()
+            if cb is _STOP:
+                break
+            try:
+                with _yield_before_after():
+                    cb()
+            except Exception:
+                LOG.warning("Exception in worker completion queue greenlet",
+                            exc_info=True)
+            finally:
+                del cb  # release before possible idle
+
+    def _process_callback_queue(self):
+        while True:
+            cb = self.callback_queue.get()
+            if cb is _STOP:
+                break
+            try:
+                with _yield_before_after():
+                    cb()
+            except Exception:
+                LOG.warning("Exception in worker callback queue greenlet",
+                            exc_info=True)
+            finally:
+                del cb  # release before possible idle
+
+    def start(self):
+        if not self._started:
+            # Spawn our worker threads, we have
+            # - A callback worker for watch events to be called
+            # - A completion worker for completion events to be called
+            w = eventlet.spawn(self._process_completion_queue)
+            self._workers.append((w, self.completion_queue))
+            w = eventlet.spawn(self._process_callback_queue)
+            self._workers.append((w, self.callback_queue))
+            self._started = True
+            python2atexit.register(self.stop)
+
+    def stop(self):
+        while self._workers:
+            w, q = self._workers.pop()
+            q.put(_STOP)
+            w.wait()
+        self._started = False
+        python2atexit.unregister(self.stop)
+
+    def socket(self, *args, **kwargs):
+        return utils.create_tcp_socket(green_socket)
+
+    def create_socket_pair(self):
+        return utils.create_socket_pair(green_socket)
+
+    def event_object(self):
+        return green_threading.Event()
+
+    def lock_object(self):
+        return green_threading.Lock()
+
+    def rlock_object(self):
+        return green_threading.RLock()
+
+    def create_connection(self, *args, **kwargs):
+        return utils.create_tcp_connection(green_socket, *args, **kwargs)
+
+    def select(self, *args, **kwargs):
+        with _yield_before_after():
+            return green_select.select(*args, **kwargs)
+
+    def async_result(self):
+        return AsyncResult(self)
+
+    def spawn(self, func, *args, **kwargs):
+        t = green_threading.Thread(target=func, args=args, kwargs=kwargs)
+        t.daemon = True
+        t.start()
+        return t
+
+    def dispatch_callback(self, callback):
+        self.callback_queue.put(lambda: callback.func(*callback.args))

+ 31 - 22
desktop/core/ext-py/kazoo-2.0/kazoo/handlers/gevent.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/gevent.py

@@ -1,24 +1,22 @@
 """A gevent based handler."""
 from __future__ import absolute_import
 
-import atexit
 import logging
 
 import gevent
+from gevent import socket
 import gevent.event
 import gevent.queue
 import gevent.select
 import gevent.thread
-
-from gevent.queue import Empty
-from gevent.queue import Queue
-from gevent import socket
 try:
     from gevent.lock import Semaphore, RLock
 except ImportError:
     from gevent.coros import Semaphore, RLock
 
-from kazoo.handlers.utils import create_tcp_socket, create_tcp_connection
+from kazoo.handlers import utils
+from kazoo import python2atexit
+
 
 _using_libevent = gevent.__version__.startswith('0.')
 
@@ -50,33 +48,42 @@ class SequentialGeventHandler(object):
 
     """
     name = "sequential_gevent_handler"
+    queue_impl = gevent.queue.Queue
+    queue_empty = gevent.queue.Empty
     sleep_func = staticmethod(gevent.sleep)
 
     def __init__(self):
         """Create a :class:`SequentialGeventHandler` instance"""
-        self.callback_queue = Queue()
+        self.callback_queue = self.queue_impl()
         self._running = False
         self._async = None
         self._state_change = Semaphore()
         self._workers = []
 
-    class timeout_exception(gevent.event.Timeout):
+    @property
+    def running(self):
+        return self._running
+
+    class timeout_exception(gevent.Timeout):
         def __init__(self, msg):
-            gevent.event.Timeout.__init__(self, exception=msg)
+            gevent.Timeout.__init__(self, exception=msg)
 
     def _create_greenlet_worker(self, queue):
         def greenlet_worker():
             while True:
                 try:
                     func = queue.get()
-                    if func is _STOP:
-                        break
-                    func()
-                except Empty:
+                    try:
+                        if func is _STOP:
+                            break
+                        func()
+                    except Exception as exc:
+                        log.warning("Exception in worker greenlet")
+                        log.exception(exc)
+                    finally:
+                        del func  # release before possible idle
+                except self.queue_empty:
                     continue
-                except Exception as exc:
-                    log.warning("Exception in worker greenlet")
-                    log.exception(exc)
         return gevent.spawn(greenlet_worker)
 
     def start(self):
@@ -92,7 +99,7 @@ class SequentialGeventHandler(object):
             for queue in (self.callback_queue,):
                 w = self._create_greenlet_worker(queue)
                 self._workers.append(w)
-            atexit.register(self.stop)
+            python2atexit.register(self.stop)
 
     def stop(self):
         """Stop the greenlet workers and empty all queues."""
@@ -110,19 +117,21 @@ class SequentialGeventHandler(object):
                 worker.join()
 
             # Clear the queues
-            self.callback_queue = Queue()  # pragma: nocover
+            self.callback_queue = self.queue_impl()  # pragma: nocover
 
-            if hasattr(atexit, "unregister"):
-                atexit.unregister(self.stop)
+            python2atexit.unregister(self.stop)
 
     def select(self, *args, **kwargs):
         return gevent.select.select(*args, **kwargs)
 
     def socket(self, *args, **kwargs):
-        return create_tcp_socket(socket)
+        return utils.create_tcp_socket(socket)
 
     def create_connection(self, *args, **kwargs):
-        return create_tcp_connection(socket, *args, **kwargs)
+        return utils.create_tcp_connection(socket, *args, **kwargs)
+
+    def create_socket_pair(self):
+        return utils.create_socket_pair(socket)
 
     def event_object(self):
         """Create an appropriate Event object"""

+ 123 - 119
desktop/core/ext-py/kazoo-2.0/kazoo/handlers/threading.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/threading.py

@@ -12,135 +12,63 @@ environments that use threads.
 """
 from __future__ import absolute_import
 
-import atexit
+from collections import defaultdict
+import errno
+from itertools import chain
 import logging
 import select
 import socket
 import threading
 import time
 
+import six
+
+import kazoo.python2atexit as python2atexit
+from kazoo.handlers import utils
+
 try:
     import Queue
 except ImportError:  # pragma: nocover
     import queue as Queue
 
-from kazoo.handlers.utils import create_tcp_socket, create_tcp_connection
 
 # sentinel objects
-_NONE = object()
 _STOP = object()
 
 log = logging.getLogger(__name__)
 
+_HAS_EPOLL = hasattr(select, "epoll")
 
-class TimeoutError(Exception):
-    pass
 
+def _to_fileno(obj):
+    if isinstance(obj, six.integer_types):
+        fd = int(obj)
+    elif hasattr(obj, "fileno"):
+        fd = obj.fileno()
+        if not isinstance(fd, six.integer_types):
+            raise TypeError("fileno() returned a non-integer")
+        fd = int(fd)
+    else:
+        raise TypeError("argument must be an int, or have a fileno() method.")
 
-class AsyncResult(object):
-    """A one-time event that stores a value or an exception"""
-    def __init__(self, handler):
-        self._handler = handler
-        self.value = None
-        self._exception = _NONE
-        self._condition = threading.Condition()
-        self._callbacks = []
-
-    def ready(self):
-        """Return true if and only if it holds a value or an
-        exception"""
-        return self._exception is not _NONE
+    if fd < 0:
+        raise ValueError(
+            "file descriptor cannot be a negative integer (%d)" % (fd,)
+        )
 
-    def successful(self):
-        """Return true if and only if it is ready and holds a value"""
-        return self._exception is None
+    return fd
 
-    @property
-    def exception(self):
-        if self._exception is not _NONE:
-            return self._exception
-
-    def set(self, value=None):
-        """Store the value. Wake up the waiters."""
-        with self._condition:
-            self.value = value
-            self._exception = None
-
-            for callback in self._callbacks:
-                self._handler.completion_queue.put(
-                    lambda: callback(self)
-                )
-            self._condition.notify_all()
-
-    def set_exception(self, exception):
-        """Store the exception. Wake up the waiters."""
-        with self._condition:
-            self._exception = exception
-
-            for callback in self._callbacks:
-                self._handler.completion_queue.put(
-                    lambda: callback(self)
-                )
-            self._condition.notify_all()
-
-    def get(self, block=True, timeout=None):
-        """Return the stored value or raise the exception.
-
-        If there is no value raises TimeoutError.
 
-        """
-        with self._condition:
-            if self._exception is not _NONE:
-                if self._exception is None:
-                    return self.value
-                raise self._exception
-            elif block:
-                self._condition.wait(timeout)
-                if self._exception is not _NONE:
-                    if self._exception is None:
-                        return self.value
-                    raise self._exception
-
-            # if we get to this point we timeout
-            raise TimeoutError()
-
-    def get_nowait(self):
-        """Return the value or raise the exception without blocking.
-
-        If nothing is available, raises TimeoutError
-
-        """
-        return self.get(block=False)
-
-    def wait(self, timeout=None):
-        """Block until the instance is ready."""
-        with self._condition:
-            self._condition.wait(timeout)
-        return self._exception is not _NONE
-
-    def rawlink(self, callback):
-        """Register a callback to call when a value or an exception is
-        set"""
-        with self._condition:
-            # Are we already set? Dispatch it now
-            if self.ready():
-                self._handler.completion_queue.put(
-                    lambda: callback(self)
-                )
-                return
+class KazooTimeoutError(Exception):
+    pass
 
-            if callback not in self._callbacks:
-                self._callbacks.append(callback)
 
-    def unlink(self, callback):
-        """Remove the callback set by :meth:`rawlink`"""
-        with self._condition:
-            if self.ready():
-                # Already triggered, ignore
-                return
-
-            if callback in self._callbacks:
-                self._callbacks.remove(callback)
+class AsyncResult(utils.AsyncResult):
+    """A one-time event that stores a value or an exception"""
+    def __init__(self, handler):
+        super(AsyncResult, self).__init__(handler,
+                                          threading.Condition,
+                                          KazooTimeoutError)
 
 
 class SequentialThreadingHandler(object):
@@ -172,7 +100,7 @@ class SequentialThreadingHandler(object):
 
     """
     name = "sequential_threading_handler"
-    timeout_exception = TimeoutError
+    timeout_exception = KazooTimeoutError
     sleep_func = staticmethod(time.sleep)
     queue_impl = Queue.Queue
     queue_empty = Queue.Empty
@@ -185,8 +113,12 @@ class SequentialThreadingHandler(object):
         self._state_change = threading.Lock()
         self._workers = []
 
+    @property
+    def running(self):
+        return self._running
+
     def _create_thread_worker(self, queue):
-        def thread_worker():  # pragma: nocover
+        def _thread_worker():  # pragma: nocover
             while True:
                 try:
                     func = queue.get()
@@ -198,15 +130,10 @@ class SequentialThreadingHandler(object):
                         log.exception("Exception in worker queue thread")
                     finally:
                         queue.task_done()
+                        del func  # release before possible idle
                 except self.queue_empty:
                     continue
-        t = threading.Thread(target=thread_worker)
-
-        # Even though these should be joined, it's possible stop might
-        # not issue in time so we set them to daemon to let the program
-        # exit anyways
-        t.daemon = True
-        t.start()
+        t = self.spawn(_thread_worker)
         return t
 
     def start(self):
@@ -222,7 +149,7 @@ class SequentialThreadingHandler(object):
                 w = self._create_thread_worker(queue)
                 self._workers.append(w)
             self._running = True
-            atexit.register(self.stop)
+            python2atexit.register(self.stop)
 
     def stop(self):
         """Stop the worker threads and empty all queues."""
@@ -243,17 +170,94 @@ class SequentialThreadingHandler(object):
             # Clear the queues
             self.callback_queue = self.queue_impl()
             self.completion_queue = self.queue_impl()
-            if hasattr(atexit, "unregister"):
-                atexit.unregister(self.stop)
+            python2atexit.unregister(self.stop)
 
     def select(self, *args, **kwargs):
-        return select.select(*args, **kwargs)
+        # if we have epoll, and select is not expected to work
+        # use an epoll-based "select". Otherwise don't touch
+        # anything to minimize changes
+        if _HAS_EPOLL:
+            # if the highest fd we've seen is > 1023
+            if max(map(_to_fileno, chain.from_iterable(args[:3]))) > 1023:
+                return self._epoll_select(*args, **kwargs)
+        return self._select(*args, **kwargs)
+
+    def _select(self, *args, **kwargs):
+        timeout = kwargs.pop('timeout', None)
+        # either the time to give up, or None
+        end = (time.time() + timeout) if timeout else None
+        while end is None or time.time() < end:
+            if end is not None:
+                # make a list, since tuples aren't mutable
+                args = list(args)
+
+                # set the timeout to the remaining time
+                args[3] = end - time.time()
+            try:
+                return select.select(*args, **kwargs)
+            except select.error as ex:
+                # if the system call was interrupted, we'll retry until timeout
+                # in Python 3, system call interruptions are a native exception
+                # in Python 2, they are not
+                errnum = ex.errno if isinstance(ex, OSError) else ex[0]
+                if errnum == errno.EINTR:
+                    continue
+                raise
+        # if we hit our timeout, lets return as a timeout
+        return ([], [], [])
+
+    def _epoll_select(self, rlist, wlist, xlist, timeout=None):
+        """epoll-based drop-in replacement for select to overcome select
+        limitation on a maximum filehandle value
+        """
+        if timeout is None:
+            timeout = -1
+        eventmasks = defaultdict(int)
+        rfd2obj = defaultdict(list)
+        wfd2obj = defaultdict(list)
+        xfd2obj = defaultdict(list)
+        read_evmask = select.EPOLLIN | select.EPOLLPRI  # Just in case
+
+        def store_evmasks(obj_list, evmask, fd2obj):
+            for obj in obj_list:
+                fileno = _to_fileno(obj)
+                eventmasks[fileno] |= evmask
+                fd2obj[fileno].append(obj)
+
+        store_evmasks(rlist, read_evmask, rfd2obj)
+        store_evmasks(wlist, select.EPOLLOUT, wfd2obj)
+        store_evmasks(xlist, select.EPOLLERR, xfd2obj)
+
+        poller = select.epoll()
+
+        for fileno in eventmasks:
+            poller.register(fileno, eventmasks[fileno])
+
+        try:
+            events = poller.poll(timeout)
+            revents = []
+            wevents = []
+            xevents = []
+            for fileno, event in events:
+                if event & read_evmask:
+                    revents += rfd2obj.get(fileno, [])
+                if event & select.EPOLLOUT:
+                    wevents += wfd2obj.get(fileno, [])
+                if event & select.EPOLLERR:
+                    xevents += xfd2obj.get(fileno, [])
+        finally:
+            poller.close()
+
+        return revents, wevents, xevents
 
     def socket(self):
-        return create_tcp_socket(socket)
+        return utils.create_tcp_socket(socket)
 
     def create_connection(self, *args, **kwargs):
-        return create_tcp_connection(socket, *args, **kwargs)
+        return utils.create_tcp_connection(socket, *args, **kwargs)
+
+    def create_socket_pair(self):
+        return utils.create_socket_pair(socket)
 
     def event_object(self):
         """Create an appropriate Event object"""

+ 302 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/handlers/utils.py

@@ -0,0 +1,302 @@
+"""Kazoo handler helpers"""
+
+import errno
+import functools
+import select
+import ssl
+import socket
+import time
+
+HAS_FNCTL = True
+try:
+    import fcntl
+except ImportError:  # pragma: nocover
+    HAS_FNCTL = False
+
+# sentinel objects
+_NONE = object()
+
+
+class AsyncResult(object):
+    """A one-time event that stores a value or an exception"""
+    def __init__(self, handler, condition_factory, timeout_factory):
+        self._handler = handler
+        self._exception = _NONE
+        self._condition = condition_factory()
+        self._callbacks = []
+        self._timeout_factory = timeout_factory
+        self.value = None
+
+    def ready(self):
+        """Return true if and only if it holds a value or an
+        exception"""
+        return self._exception is not _NONE
+
+    def successful(self):
+        """Return true if and only if it is ready and holds a value"""
+        return self._exception is None
+
+    @property
+    def exception(self):
+        if self._exception is not _NONE:
+            return self._exception
+
+    def set(self, value=None):
+        """Store the value. Wake up the waiters."""
+        with self._condition:
+            self.value = value
+            self._exception = None
+            self._do_callbacks()
+            self._condition.notify_all()
+
+    def set_exception(self, exception):
+        """Store the exception. Wake up the waiters."""
+        with self._condition:
+            self._exception = exception
+            self._do_callbacks()
+            self._condition.notify_all()
+
+    def get(self, block=True, timeout=None):
+        """Return the stored value or raise the exception.
+
+        If there is no value raises TimeoutError.
+
+        """
+        with self._condition:
+            if self._exception is not _NONE:
+                if self._exception is None:
+                    return self.value
+                raise self._exception
+            elif block:
+                self._condition.wait(timeout)
+                if self._exception is not _NONE:
+                    if self._exception is None:
+                        return self.value
+                    raise self._exception
+
+            # if we get to this point we timeout
+            raise self._timeout_factory()
+
+    def get_nowait(self):
+        """Return the value or raise the exception without blocking.
+
+        If nothing is available, raises TimeoutError
+
+        """
+        return self.get(block=False)
+
+    def wait(self, timeout=None):
+        """Block until the instance is ready."""
+        with self._condition:
+            if not self.ready():
+                self._condition.wait(timeout)
+        return self._exception is not _NONE
+
+    def rawlink(self, callback):
+        """Register a callback to call when a value or an exception is
+        set"""
+        with self._condition:
+            if callback not in self._callbacks:
+                self._callbacks.append(callback)
+
+            # Are we already set? Dispatch it now
+            if self.ready():
+                self._do_callbacks()
+
+    def unlink(self, callback):
+        """Remove the callback set by :meth:`rawlink`"""
+        with self._condition:
+            if self.ready():
+                # Already triggered, ignore
+                return
+
+            if callback in self._callbacks:
+                self._callbacks.remove(callback)
+
+    def _do_callbacks(self):
+        """Execute the callbacks that were registered by :meth:`rawlink`.
+        If the handler is in running state this method only schedules
+        the calls to be performed by the handler. If it's stopped,
+        the callbacks are called right away."""
+
+        for callback in self._callbacks:
+            if self._handler.running:
+                self._handler.completion_queue.put(
+                    functools.partial(callback, self))
+            else:
+                functools.partial(callback, self)()
+
+def _set_fd_cloexec(fd):
+    flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+    fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC)
+
+
+def _set_default_tcpsock_options(module, sock):
+    sock.setsockopt(module.IPPROTO_TCP, module.TCP_NODELAY, 1)
+    if HAS_FNCTL:
+        _set_fd_cloexec(sock)
+    return sock
+
+
+def create_socket_pair(module, port=0):
+    """Create socket pair.
+
+    If socket.socketpair isn't available, we emulate it.
+    """
+    # See if socketpair() is available.
+    have_socketpair = hasattr(module, 'socketpair')
+    if have_socketpair:
+        client_sock, srv_sock = module.socketpair()
+        return client_sock, srv_sock
+
+    # Create a non-blocking temporary server socket
+    temp_srv_sock = module.socket()
+    temp_srv_sock.setblocking(False)
+    temp_srv_sock.bind(('', port))
+    port = temp_srv_sock.getsockname()[1]
+    temp_srv_sock.listen(1)
+
+    # Create non-blocking client socket
+    client_sock = module.socket()
+    client_sock.setblocking(False)
+    try:
+        client_sock.connect(('localhost', port))
+    except module.error as err:
+        # EWOULDBLOCK is not an error, as the socket is non-blocking
+        if err.errno != errno.EWOULDBLOCK:
+            raise
+
+    # Use select to wait for connect() to succeed.
+    timeout = 1
+    readable = select.select([temp_srv_sock], [], [], timeout)[0]
+    if temp_srv_sock not in readable:
+        raise Exception('Client socket not connected in %s'
+                        ' second(s)' % (timeout))
+    srv_sock, _ = temp_srv_sock.accept()
+    return client_sock, srv_sock
+
+
+def create_tcp_socket(module):
+    """Create a TCP socket with the CLOEXEC flag set.
+    """
+    type_ = module.SOCK_STREAM
+    if hasattr(module, 'SOCK_CLOEXEC'):  # pragma: nocover
+        # if available, set cloexec flag during socket creation
+        type_ |= module.SOCK_CLOEXEC
+    sock = module.socket(module.AF_INET, type_)
+    _set_default_tcpsock_options(module, sock)
+    return sock
+
+
+def create_tcp_connection(module, address, timeout=None,
+                          use_ssl=False, ca=None, certfile=None,
+                          keyfile=None, keyfile_password=None,
+                          verify_certs=True, options=None, ciphers=None):
+    end = None
+    if timeout is None:
+        # thanks to create_connection() developers for
+        # this ugliness...
+        timeout = module.getdefaulttimeout()
+    if timeout is not None:
+        end = time.time() + timeout
+    sock = None
+
+    while True:
+        timeout_at = end if end is None else end - time.time()
+        # The condition is not '< 0' here because socket.settimeout treats 0 as
+        # a special case to put the socket in non-blocking mode.
+        if timeout_at is not None and timeout_at <= 0:
+            break
+
+        if use_ssl:
+            # Disallow use of SSLv2 and V3 (meaning we require TLSv1.0+)
+            context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+
+            if options is not None:
+                context.options = options
+            else:
+                context.options |= ssl.OP_NO_SSLv2
+                context.options |= ssl.OP_NO_SSLv3
+
+            if ciphers:
+                context.set_ciphers(ciphers)
+
+            # Load default CA certs
+            context.load_default_certs(ssl.Purpose.SERVER_AUTH)
+            context.verify_mode = (
+                ssl.CERT_OPTIONAL if verify_certs else ssl.CERT_NONE
+            )
+            if ca:
+                context.load_verify_locations(ca)
+            if certfile and keyfile:
+                context.verify_mode = (
+                    ssl.CERT_REQUIRED if verify_certs else ssl.CERT_NONE
+                )
+                context.load_cert_chain(certfile=certfile,
+                                        keyfile=keyfile,
+                                        password=keyfile_password)
+            try:
+                # Query the address to get back it's address family
+                addrs = socket.getaddrinfo(address[0], address[1], 0,
+                                           socket.SOCK_STREAM)
+                conn = context.wrap_socket(module.socket(addrs[0][0]))
+                conn.settimeout(timeout_at)
+                conn.connect(address)
+                sock = conn
+                break
+            except ssl.SSLError:
+                raise
+        else:
+            try:
+                # if we got a timeout, lets ensure that we decrement the time
+                # otherwise there is no timeout set and we'll call it as such
+                sock = module.create_connection(address, timeout_at)
+                break
+            except Exception as ex:
+                errnum = ex.errno if isinstance(ex, OSError) else ex[0]
+                if errnum == errno.EINTR:
+                    continue
+                raise
+
+    if sock is None:
+        raise module.error
+
+    _set_default_tcpsock_options(module, sock)
+    return sock
+
+
+def capture_exceptions(async_result):
+    """Return a new decorated function that propagates the exceptions of the
+    wrapped function to an async_result.
+
+    :param async_result: An async result implementing :class:`IAsyncResult`
+
+    """
+    def capture(function):
+        @functools.wraps(function)
+        def captured_function(*args, **kwargs):
+            try:
+                return function(*args, **kwargs)
+            except Exception as exc:
+                async_result.set_exception(exc)
+        return captured_function
+    return capture
+
+
+def wrap(async_result):
+    """Return a new decorated function that propagates the return value or
+    exception of wrapped function to an async_result.  NOTE: Only propagates a
+    non-None return value.
+
+    :param async_result: An async result implementing :class:`IAsyncResult`
+
+    """
+    def capture(function):
+        @capture_exceptions(async_result)
+        def captured_function(*args, **kwargs):
+            value = function(*args, **kwargs)
+            if value is not None:
+                async_result.set(value)
+            return value
+        return captured_function
+    return capture

+ 30 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/hosts.py

@@ -0,0 +1,30 @@
+from six.moves import urllib_parse
+
+
+def collect_hosts(hosts):
+    """
+       Collect a set of hosts and an optional chroot from
+       a string or a list of strings.
+    """
+    if isinstance(hosts, list):
+        if hosts[-1].strip().startswith('/'):
+            host_ports, chroot = hosts[:-1], hosts[-1]
+        else:
+            host_ports, chroot = hosts, None
+    else:
+        host_ports, chroot = hosts.partition("/")[::2]
+        host_ports = host_ports.split(",")
+        chroot = "/" + chroot if chroot else None
+
+    result = []
+    for host_port in host_ports:
+        # put all complexity of dealing with
+        # IPv4 & IPv6 address:port on the urlsplit
+        res = urllib_parse.urlsplit("xxx://" + host_port)
+        host = res.hostname
+        if host is None:
+            raise ValueError("bad hostname")
+        port = int(res.port) if res.port else 2181
+        result.append((host.strip(), port))
+
+    return result, chroot

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/interfaces.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/interfaces.py


+ 1 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/loggingsupport.py

@@ -0,0 +1 @@
+BLATHER = 5  # log level for low-level debugging

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/handlers/__init__.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/__init__.py


+ 238 - 114
desktop/core/ext-py/kazoo-2.0/kazoo/protocol/connection.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/connection.py

@@ -1,13 +1,16 @@
 """Zookeeper Protocol Connection Handler"""
+from binascii import hexlify
+from contextlib import contextmanager
+import copy
 import logging
-import os
 import random
 import select
 import socket
+import ssl
 import sys
 import time
-from binascii import hexlify
-from contextlib import contextmanager
+
+import six
 
 from kazoo.exceptions import (
     AuthFailedError,
@@ -15,9 +18,8 @@ from kazoo.exceptions import (
     EXCEPTIONS,
     SessionExpiredError,
     NoNodeError,
-    SaslException
+    SASLException,
 )
-from kazoo.handlers.utils import create_pipe
 from kazoo.loggingsupport import BLATHER
 from kazoo.protocol.serialization import (
     Auth,
@@ -25,13 +27,14 @@ from kazoo.protocol.serialization import (
     Connect,
     Exists,
     GetChildren,
+    GetChildren2,
     Ping,
     PingInstance,
     ReplyHeader,
     SASL,
     Transaction,
     Watch,
-    int_struct
+    int_struct,
 )
 from kazoo.protocol.states import (
     Callback,
@@ -41,10 +44,16 @@ from kazoo.protocol.states import (
 )
 from kazoo.retry import (
     ForceRetryError,
-    RetryFailedError
+    RetryFailedError,
 )
 
-import sasl
+try:
+    import puresasl
+    import puresasl.client
+    PURESASL_AVAILABLE = True
+except ImportError:
+    PURESASL_AVAILABLE = False
+
 
 log = logging.getLogger(__name__)
 
@@ -136,12 +145,11 @@ class RWServerAvailable(Exception):
 
 class ConnectionHandler(object):
     """Zookeeper connection handler"""
-    def __init__(self, client, retry_sleeper, logger=None, sasl_server_principal=None):
+    def __init__(self, client, retry_sleeper, logger=None, sasl_options=None):
         self.client = client
         self.handler = client.handler
         self.retry_sleeper = retry_sleeper
         self.logger = logger or log
-        self.sasl_server_principal = sasl_server_principal
 
         # Our event objects
         self.connection_closed = client.handler.event_object()
@@ -150,8 +158,8 @@ class ConnectionHandler(object):
         self.connection_stopped.set()
         self.ping_outstanding = client.handler.event_object()
 
-        self._read_pipe = None
-        self._write_pipe = None
+        self._read_sock = None
+        self._write_sock = None
 
         self._socket = None
         self._xid = None
@@ -160,6 +168,8 @@ class ConnectionHandler(object):
 
         self._connection_routine = None
 
+        self.sasl_options = sasl_options
+        self.sasl_cli = None
 
     # This is instance specific to avoid odd thread bug issues in Python
     # during shutdown global cleanup
@@ -174,7 +184,8 @@ class ConnectionHandler(object):
     def start(self):
         """Start the connection up"""
         if self.connection_closed.is_set():
-            self._read_pipe, self._write_pipe = create_pipe()
+            rw_sockets = self.handler.create_socket_pair()
+            self._read_sock, self._write_sock = rw_sockets
             self.connection_closed.clear()
         if self._connection_routine:
             raise Exception("Unable to start, connection routine already "
@@ -197,12 +208,12 @@ class ConnectionHandler(object):
         if not self.connection_stopped.is_set():
             raise Exception("Cannot close connection until it is stopped")
         self.connection_closed.set()
-        wp, rp = self._write_pipe, self._read_pipe
-        self._write_pipe = self._read_pipe = None
-        if wp is not None:
-            os.close(wp)
-        if rp is not None:
-            os.close(rp)
+        ws, rs = self._write_sock, self._read_sock
+        self._write_sock = self._read_sock = None
+        if ws is not None:
+            ws.close()
+        if rs is not None:
+            rs.close()
 
     def _server_pinger(self):
         """Returns a server pinger iterable, that will ping the next
@@ -222,13 +233,29 @@ class ConnectionHandler(object):
         remaining = length
         with self._socket_error_handling():
             while remaining > 0:
-                s = self.handler.select([self._socket], [], [], timeout)[0]
-                if not s:  # pragma: nocover
-                    # If the read list is empty, we got a timeout. We don't
-                    # have to check wlist and xlist as we don't set any
-                    raise self.handler.timeout_exception("socket time-out")
-
-                chunk = self._socket.recv(remaining)
+                # Because of SSL framing, a select may not return when using
+                # an SSL socket because the underlying physical socket may not
+                # have anything to select, but the wrapped object may still
+                # have something to read as it has previously gotten enough
+                # data from the underlying socket.
+                if (hasattr(self._socket, "pending") and
+                        self._socket.pending() > 0):
+                    pass
+                else:
+                    s = self.handler.select([self._socket], [], [], timeout)[0]
+                    if not s:  # pragma: nocover
+                        # If the read list is empty, we got a timeout. We don't
+                        # have to check wlist and xlist as we don't set any
+                        raise self.handler.timeout_exception(
+                            "socket time-out during read")
+                try:
+                    chunk = self._socket.recv(remaining)
+                except ssl.SSLError as e:
+                    if e.errno in (ssl.SSL_ERROR_WANT_READ,
+                                   ssl.SSL_ERROR_WANT_WRITE):
+                        continue
+                    else:
+                        raise
                 if chunk == b'':
                     raise ConnectionDropped('socket connection broken')
                 msgparts.append(chunk)
@@ -243,8 +270,8 @@ class ConnectionHandler(object):
         if xid:
             header, buffer, offset = self._read_header(timeout)
             if header.xid != xid:
-                raise RuntimeError('xids do not match, expected %r received %r',
-                                   xid, header.xid)
+                raise RuntimeError('xids do not match, expected %r '
+                                   'received %r', xid, header.xid)
             if header.zxid > 0:
                 zxid = header.zxid
             if header.err:
@@ -262,8 +289,9 @@ class ConnectionHandler(object):
             try:
                 obj, _ = request.deserialize(msg, 0)
             except Exception:
-                self.logger.exception("Exception raised during deserialization"
-                                      " of request: %s", request)
+                self.logger.exception(
+                    "Exception raised during deserialization "
+                    "of request: %s", request)
 
                 # raise ConnectionDropped so connect loop will retry
                 raise ConnectionDropped('invalid server response')
@@ -281,8 +309,9 @@ class ConnectionHandler(object):
         if request.type:
             b.extend(int_struct.pack(request.type))
         b += request.serialize()
-        self.logger.log((BLATHER if isinstance(request, Ping) else logging.DEBUG),
-                        "Sending request(xid=%s): %s", xid, request)
+        self.logger.log(
+            (BLATHER if isinstance(request, Ping) else logging.DEBUG),
+            "Sending request(xid=%s): %s", xid, request)
         self._write(int_struct.pack(len(b)) + b, timeout)
 
     def _write(self, msg, timeout):
@@ -295,9 +324,17 @@ class ConnectionHandler(object):
                 if not s:  # pragma: nocover
                     # If the write list is empty, we got a timeout. We don't
                     # have to check rlist and xlist as we don't set any
-                    raise self.handler.timeout_exception("socket time-out")
+                    raise self.handler.timeout_exception("socket time-out"
+                                                         " during write")
                 msg_slice = buffer(msg, sent)
-                bytes_sent = self._socket.send(msg_slice)
+                try:
+                    bytes_sent = self._socket.send(msg_slice)
+                except ssl.SSLError as e:
+                    if e.errno in (ssl.SSL_ERROR_WANT_READ,
+                                   ssl.SSL_ERROR_WANT_WRITE):
+                        continue
+                    else:
+                        raise
                 if not bytes_sent:
                     raise ConnectionDropped('socket connection broken')
                 sent += bytes_sent
@@ -340,8 +377,10 @@ class ConnectionHandler(object):
         if header.zxid and header.zxid > 0:
             client.last_zxid = header.zxid
         if header.xid != xid:
-            raise RuntimeError('xids do not match, expected %r '
+            exc = RuntimeError('xids do not match, expected %r '
                                'received %r', xid, header.xid)
+            async_object.set_exception(exc)
+            raise exc
 
         # Determine if its an exists request and a no node error
         exists_error = (header.err == NoNodeError.code and
@@ -363,8 +402,9 @@ class ConnectionHandler(object):
                 try:
                     response = request.deserialize(buffer, offset)
                 except Exception as exc:
-                    self.logger.exception("Exception raised during deserialization"
-                                          " of request: %s", request)
+                    self.logger.exception(
+                        "Exception raised during deserialization "
+                        "of request: %s", request)
                     async_object.set_exception(exc)
                     return
                 self.logger.debug(
@@ -379,7 +419,7 @@ class ConnectionHandler(object):
             # Determine if watchers should be registered
             watcher = getattr(request, 'watcher', None)
             if not client._stopped.is_set() and watcher:
-                if isinstance(request, GetChildren):
+                if isinstance(request, (GetChildren, GetChildren2)):
                     client._child_watchers[request.path].add(watcher)
                 else:
                     client._data_watchers[request.path].add(watcher)
@@ -420,11 +460,11 @@ class ConnectionHandler(object):
         except IndexError:
             # Not actually something on the queue, this can occur if
             # something happens to cancel the request such that we
-            # don't clear the pipe below after sending
+            # don't clear the socket below after sending
             try:
                 # Clear possible inconsistence (no request in the queue
-                # but have data in the read pipe), which causes cpu to spin.
-                os.read(self._read_pipe, 1)
+                # but have data in the read socket), which causes cpu to spin.
+                self._read_sock.recv(1)
             except OSError:
                 pass
             return
@@ -440,12 +480,12 @@ class ConnectionHandler(object):
         if request.type == Auth.type:
             xid = AUTH_XID
         else:
-            self._xid += 1
+            self._xid = (self._xid % 2147483647) + 1
             xid = self._xid
 
         self._submit(request, connect_timeout, xid)
         client._queue.popleft()
-        os.read(self._read_pipe, 1)
+        self._read_sock.recv(1)
         client._pending.append((request, async_object, xid))
 
     def _send_ping(self, connect_timeout):
@@ -479,14 +519,37 @@ class ConnectionHandler(object):
             self.client._session_callback(KeeperState.CLOSED)
             self.logger.log(BLATHER, 'Connection stopped')
 
+    def _expand_client_hosts(self):
+        # Expand the entire list in advance so we can randomize it if needed
+        host_ports = []
+        for host, port in self.client.hosts:
+            try:
+                host = host.strip()
+                for rhost in socket.getaddrinfo(host, port, 0, 0,
+                                                socket.IPPROTO_TCP):
+                    host_ports.append((host, rhost[4][0], rhost[4][1]))
+            except socket.gaierror as e:
+                # Skip hosts that don't resolve
+                self.logger.warning("Cannot resolve %s: %s", host, e)
+                pass
+        if self.client.randomize_hosts:
+            random.shuffle(host_ports)
+        return host_ports
+
     def _connect_loop(self, retry):
         # Iterate through the hosts a full cycle before starting over
         status = None
-        for host, port in self.client.hosts:
+        host_ports = self._expand_client_hosts()
+
+        # Check for an empty hostlist, indicating none resolved
+        if len(host_ports) == 0:
+            return STOP_CONNECTING
+
+        for host, hostip, port in host_ports:
             if self.client._stopped.is_set():
                 status = STOP_CONNECTING
                 break
-            status = self._connect_attempt(host, port, retry)
+            status = self._connect_attempt(host, hostip, port, retry)
             if status is STOP_CONNECTING:
                 break
 
@@ -495,9 +558,9 @@ class ConnectionHandler(object):
         else:
             raise ForceRetryError('Reconnecting')
 
-    def _connect_attempt(self, host, port, retry):
+    def _connect_attempt(self, host, hostip, port, retry):
         client = self.client
-        TimeoutError = self.handler.timeout_exception
+        KazooTimeoutError = self.handler.timeout_exception
         close_connection = False
 
         self._socket = None
@@ -513,46 +576,47 @@ class ConnectionHandler(object):
             client._session_callback(KeeperState.CONNECTING)
 
         try:
-            read_timeout, connect_timeout = self._connect(host, port)
+            self._xid = 0
+            read_timeout, connect_timeout = self._connect(host, hostip, port)
             read_timeout = read_timeout / 1000.0
             connect_timeout = connect_timeout / 1000.0
             retry.reset()
-            self._xid = 0
-
-            while not close_connection:
-                # Watch for something to read or send
-                jitter_time = random.randint(0, 40) / 100.0
-                # Ensure our timeout is positive
-                timeout = max([read_timeout / 2.0 - jitter_time, jitter_time])
-                s = self.handler.select([self._socket, self._read_pipe],
-                                        [], [], timeout)[0]
-
-                if not s:
-                    if self.ping_outstanding.is_set():
-                        self.ping_outstanding.clear()
-                        raise ConnectionDropped(
-                            "outstanding heartbeat ping not received")
-                    self._send_ping(connect_timeout)
-                elif s[0] == self._socket:
-                    response = self._read_socket(read_timeout)
-                    close_connection = response == CLOSE_RESPONSE
-                else:
-                    self._send_request(read_timeout, connect_timeout)
-
+            self.ping_outstanding.clear()
+            with self._socket_error_handling():
+                while not close_connection:
+                    # Watch for something to read or send
+                    jitter_time = random.randint(0, 40) / 100.0
+                    # Ensure our timeout is positive
+                    timeout = max([read_timeout / 2.0 - jitter_time,
+                                   jitter_time])
+                    s = self.handler.select([self._socket, self._read_sock],
+                                            [], [], timeout)[0]
+
+                    if not s:
+                        if self.ping_outstanding.is_set():
+                            self.ping_outstanding.clear()
+                            raise ConnectionDropped(
+                                "outstanding heartbeat ping not received")
+                        self._send_ping(connect_timeout)
+                    elif s[0] == self._socket:
+                        response = self._read_socket(read_timeout)
+                        close_connection = response == CLOSE_RESPONSE
+                    else:
+                        self._send_request(read_timeout, connect_timeout)
             self.logger.info('Closing connection to %s:%s', host, port)
             client._session_callback(KeeperState.CLOSED)
             return STOP_CONNECTING
-        except (ConnectionDropped, TimeoutError) as e:
+        except (ConnectionDropped, KazooTimeoutError) as e:
             if isinstance(e, ConnectionDropped):
                 self.logger.warning('Connection dropped: %s', e)
             else:
-                self.logger.warning('Connection time-out')
+                self.logger.warning('Connection time-out: %s', e)
             if client._state != KeeperState.CONNECTING:
                 self.logger.warning("Transition to CONNECTING")
                 client._session_callback(KeeperState.CONNECTING)
-        except AuthFailedError:
+        except AuthFailedError as err:
             retry.reset()
-            self.logger.warning('AUTH_FAILED closing')
+            self.logger.warning('AUTH_FAILED closing: %s', err)
             client._session_callback(KeeperState.AUTH_FAILED)
             return STOP_CONNECTING
         except SessionExpiredError:
@@ -570,18 +634,27 @@ class ConnectionHandler(object):
             if self._socket is not None:
                 self._socket.close()
 
-    def _connect(self, host, port):
+    def _connect(self, host, hostip, port):
         client = self.client
-        self.logger.info('Connecting to %s:%s', host, port)
+        self.logger.info('Connecting to %s(%s):%s, use_ssl: %r',
+                         host, hostip, port, self.client.use_ssl)
 
         self.logger.log(BLATHER,
-                          '    Using session_id: %r session_passwd: %s',
-                          client._session_id,
-                          hexlify(client._session_passwd))
+                        '    Using session_id: %r session_passwd: %s',
+                        client._session_id,
+                        hexlify(client._session_passwd))
 
         with self._socket_error_handling():
             self._socket = self.handler.create_connection(
-                (host, port), client._session_timeout / 1000.0)
+                address=(hostip, port),
+                timeout=client._session_timeout / 1000.0,
+                use_ssl=self.client.use_ssl,
+                keyfile=self.client.keyfile,
+                certfile=self.client.certfile,
+                ca=self.client.ca,
+                keyfile_password=self.client.keyfile_password,
+                verify_certs=self.client.verify_certs,
+            )
 
         self._socket.setblocking(0)
 
@@ -589,7 +662,8 @@ class ConnectionHandler(object):
                           client._session_id or 0, client._session_passwd,
                           client.read_only)
 
-        connect_result, zxid = self._invoke(client._session_timeout, connect)
+        connect_result, zxid = self._invoke(
+            client._session_timeout / 1000.0 / len(client.hosts), connect)
 
         if connect_result.time_out <= 0:
             raise SessionExpiredError("Session has expired")
@@ -606,16 +680,13 @@ class ConnectionHandler(object):
         client._session_passwd = connect_result.passwd
 
         self.logger.log(BLATHER,
-                          'Session created, session_id: %r session_passwd: %s\n'
-                          '    negotiated session timeout: %s\n'
-                          '    connect timeout: %s\n'
-                          '    read timeout: %s', client._session_id,
-                          hexlify(client._session_passwd),
-                          negotiated_session_timeout, connect_timeout,
-                          read_timeout)
-
-        if self.sasl_server_principal:
-            self._authenticate_with_sasl(host, connect_timeout / 1000.0)
+                        'Session created, session_id: %r session_passwd: %s\n'
+                        '    negotiated session timeout: %s\n'
+                        '    connect timeout: %s\n'
+                        '    read timeout: %s', client._session_id,
+                        hexlify(client._session_passwd),
+                        negotiated_session_timeout, connect_timeout,
+                        read_timeout)
 
         if connect_result.read_only:
             client._session_callback(KeeperState.CONNECTED_RO)
@@ -624,41 +695,97 @@ class ConnectionHandler(object):
             client._session_callback(KeeperState.CONNECTED)
             self._ro_mode = None
 
-        for scheme, auth in client.auth_data:
+        if self.sasl_options is not None:
+            self._authenticate_with_sasl(host, connect_timeout / 1000.0)
+
+        # Get a copy of the auth data before iterating, in case it is
+        # changed.
+        client_auth_data_copy = copy.copy(client.auth_data)
+
+        for scheme, auth in client_auth_data_copy:
             ap = Auth(0, scheme, auth)
-            zxid = self._invoke(connect_timeout, ap, xid=AUTH_XID)
+            zxid = self._invoke(connect_timeout / 1000.0, ap, xid=AUTH_XID)
             if zxid:
                 client.last_zxid = zxid
 
         return read_timeout, connect_timeout
 
     def _authenticate_with_sasl(self, host, timeout):
-        saslc = sasl.Client()
-        saslc.setAttr('host', str(host))
-        saslc.setAttr('service', str(self.sasl_server_principal))
-        saslc.init()
-
-        ret, chosen_mech, initial_response = saslc.start('GSSAPI')
-        if not ret:
-            raise SaslException(saslc.getError())
-
-        response = initial_response
-
+        """Establish a SASL authenticated connection to the server.
+        """
+        if not PURESASL_AVAILABLE:
+            raise SASLException('Missing SASL support')
+
+        if 'service' not in self.sasl_options:
+            self.sasl_options['service'] = 'zookeeper'
+
+        # NOTE: Zookeeper hardcoded the domain for Digest authentication
+        # instead of using the hostname. See
+        # zookeeper/util/SecurityUtils.java#L74 and Server/Client
+        # initializations.
+        if self.sasl_options['mechanism'] == 'DIGEST-MD5':
+            host = 'zk-sasl-md5'
+
+        sasl_cli = self.client.sasl_cli = puresasl.client.SASLClient(
+            host=host,
+            **self.sasl_options
+        )
+
+        # Inititalize the process with an empty challenge token
+        challenge = None
         xid = 0
 
         while True:
-            xid += 1
+            if sasl_cli.complete:
+                break
+
+            try:
+                response = sasl_cli.process(challenge=challenge)
+            except puresasl.SASLError as err:
+                six.reraise(
+                    SASLException,
+                    SASLException('library error: %s' % err.message),
+                    sys.exc_info()[2]
+                )
+            except puresasl.SASLProtocolException as err:
+                six.reraise(
+                    AuthFailedError,
+                    AuthFailedError('protocol error: %s' % err.message),
+                    sys.exc_info()[2]
+                )
+            except Exception as err:
+                six.reraise(
+                    AuthFailedError,
+                    AuthFailedError('Unknown error: %s' % err),
+                    sys.exc_info()[2]
+                )
+
+            if sasl_cli.complete and not response:
+                break
+            elif response is None:
+                response = b''
+
+            xid = (xid % 2147483647) + 1
 
             request = SASL(response)
             self._submit(request, timeout, xid)
 
-            header, buffer, offset = self._read_header(timeout)
+            try:
+                header, buffer, offset = self._read_header(timeout)
+            except ConnectionDropped:
+                # Zookeeper simply drops connections with failed authentication
+                six.reraise(
+                    AuthFailedError,
+                    AuthFailedError('Connection dropped in SASL'),
+                    sys.exc_info()[2]
+                )
+
             if header.xid != xid:
                 raise RuntimeError('xids do not match, expected %r '
                                    'received %r', xid, header.xid)
 
             if header.zxid > 0:
-                client.last_zxid = zxid
+                self.client.last_zxid = header.zxid
 
             if header.err:
                 callback_exception = EXCEPTIONS[header.err]()
@@ -666,11 +793,8 @@ class ConnectionHandler(object):
                     'Received error(xid=%s) %r', xid, callback_exception)
                 raise callback_exception
 
-            token, _ = SASL.deserialize(buffer, offset)
-
-            if not token:
-                break
+            challenge, _ = SASL.deserialize(buffer, offset)
 
-            ret, response = saslc.step(token)
-            if not ret:
-                raise SaslException(saslc.getError())
+        # If we made it here, authentication is ok, and we are connected.
+        # Remove sensible information from the object.
+        sasl_cli.dispose()

+ 3 - 2
desktop/core/ext-py/kazoo-2.0/kazoo/protocol/paths.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/paths.py

@@ -11,7 +11,7 @@ def normpath(path, trailing=False):
     new_path = '/'.join(new_comps)
     if trailing is True and path.endswith('/'):
         new_path += '/'
-    if path.startswith('/'):
+    if path.startswith('/') and new_path != '/':
         return '/' + new_path
     return new_path
 
@@ -47,7 +47,8 @@ def basename(p):
 
 def _prefix_root(root, path, trailing=False):
     """Prepend a root to a path. """
-    return normpath(join(_norm_root(root), path.lstrip('/')), trailing=trailing)
+    return normpath(join(_norm_root(root), path.lstrip('/')),
+                    trailing=trailing)
 
 
 def _norm_root(root):

+ 51 - 12
desktop/core/ext-py/kazoo-2.0/kazoo/protocol/serialization.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/serialization.py

@@ -2,11 +2,14 @@
 from collections import namedtuple
 import struct
 
+import six
+
 from kazoo.exceptions import EXCEPTIONS
 from kazoo.protocol.states import ZnodeStat
 from kazoo.security import ACL
 from kazoo.security import Id
 
+
 # Struct objects with formats compiled
 bool_struct = struct.Struct('B')
 int_struct = struct.Struct('!i')
@@ -14,15 +17,11 @@ int_int_struct = struct.Struct('!ii')
 int_int_long_struct = struct.Struct('!iiq')
 
 int_long_int_long_struct = struct.Struct('!iqiq')
+long_struct = struct.Struct('!q')
 multiheader_struct = struct.Struct('!iBi')
 reply_header_struct = struct.Struct('!iqi')
 stat_struct = struct.Struct('!qqqqiiiqiiq')
 
-try:  # pragma: nocover
-    basestring
-except NameError:
-    basestring = str
-
 
 def read_string(buffer, offset):
     """Reads an int specified buffer into a string and returns the
@@ -112,7 +111,7 @@ class Connect(namedtuple('Connect', 'protocol_version last_zxid_seen'
         password, offset = read_buffer(bytes, offset)
 
         try:
-            read_only = bool_struct.unpack_from(bytes, offset)[0] is 1
+            read_only = bool_struct.unpack_from(bytes, offset)[0] == 1
             offset += bool_struct.size
         except struct.error:
             read_only = False
@@ -345,13 +344,53 @@ class Transaction(namedtuple('Transaction', 'operations')):
     def unchroot(client, response):
         resp = []
         for result in response:
-            if isinstance(result, basestring):
+            if isinstance(result, six.string_types):
                 resp.append(client.unchroot(result))
             else:
                 resp.append(result)
         return resp
 
 
+class Create2(namedtuple('Create2', 'path data acl flags')):
+    type = 15
+
+    def serialize(self):
+        b = bytearray()
+        b.extend(write_string(self.path))
+        b.extend(write_buffer(self.data))
+        b.extend(int_struct.pack(len(self.acl)))
+        for acl in self.acl:
+            b.extend(int_struct.pack(acl.perms) +
+                     write_string(acl.id.scheme) + write_string(acl.id.id))
+        b.extend(int_struct.pack(self.flags))
+        return b
+
+    @classmethod
+    def deserialize(cls, bytes, offset):
+        path, offset = read_string(bytes, offset)
+        stat = ZnodeStat._make(stat_struct.unpack_from(bytes, offset))
+        return path, stat
+
+
+class Reconfig(namedtuple('Reconfig',
+                          'joining leaving new_members config_id')):
+    type = 16
+
+    def serialize(self):
+        b = bytearray()
+        b.extend(write_string(self.joining))
+        b.extend(write_string(self.leaving))
+        b.extend(write_string(self.new_members))
+        b.extend(long_struct.pack(self.config_id))
+        return b
+
+    @classmethod
+    def deserialize(cls, bytes, offset):
+        data, offset = read_buffer(bytes, offset)
+        stat = ZnodeStat._make(stat_struct.unpack_from(bytes, offset))
+        return data, stat
+
+
 class Auth(namedtuple('Auth', 'auth_type scheme auth')):
     type = 100
 
@@ -360,18 +399,18 @@ class Auth(namedtuple('Auth', 'auth_type scheme auth')):
                 write_string(self.auth))
 
 
-class SASL(namedtuple('SASL', 'token')):
+class SASL(namedtuple('SASL', 'challenge')):
     type = 102
 
     def serialize(self):
         b = bytearray()
-        b.extend(write_buffer(self.token))
+        b.extend(write_buffer(self.challenge))
         return b
 
     @classmethod
     def deserialize(cls, bytes, offset):
-        token, offset = read_buffer(bytes, offset)
-        return token, offset
+        challenge, offset = read_buffer(bytes, offset)
+        return challenge, offset
 
 
 class Watch(namedtuple('Watch', 'type state path')):
@@ -407,4 +446,4 @@ class MultiHeader(namedtuple('MultiHeader', 'type done err')):
     def deserialize(cls, bytes, offset):
         t, done, err = multiheader_struct.unpack_from(bytes, offset)
         offset += multiheader_struct.size
-        return cls(t, done is 1, err), offset
+        return cls(t, done == 1, err), offset

+ 9 - 3
desktop/core/ext-py/kazoo-2.0/kazoo/protocol/states.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/protocol/states.py

@@ -93,13 +93,19 @@ class EventType(object):
         removed). This event does not indicate the data for a child
         node has changed, which must have its own watch established.
 
+    .. attribute:: NONE
+
+        The connection state has been altered.
+
     """
     CREATED = 'CREATED'
     DELETED = 'DELETED'
     CHANGED = 'CHANGED'
     CHILD = 'CHILD'
+    NONE = 'NONE'
 
 EVENT_TYPE_MAP = {
+    -1: EventType.NONE,
     1: EventType.CREATED,
     2: EventType.DELETED,
     3: EventType.CHANGED,
@@ -146,8 +152,8 @@ class ZnodeStat(namedtuple('ZnodeStat', 'czxid mzxid ctime mtime version'
                            ' numChildren pzxid')):
     """A ZnodeStat structure with convenience properties
 
-    When getting the value of a node from Zookeeper, the properties for
-    the node known as a "Stat structure" will be retrieved. The
+    When getting the value of a znode from Zookeeper, the properties for
+    the znode known as a "Stat structure" will be retrieved. The
     :class:`ZnodeStat` object provides access to the standard Stat
     properties and additional properties that are more readable and use
     Python time semantics (seconds since epoch instead of ms).
@@ -169,7 +175,7 @@ class ZnodeStat(namedtuple('ZnodeStat', 'czxid mzxid ctime mtime version'
 
     .. attribute:: created (ctime)
 
-        The time in seconds from epoch when this node was created.
+        The time in seconds from epoch when this znode was created.
         (ctime is in milliseconds)
 
     .. attribute:: last_modified (mtime)

+ 69 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/python2atexit.py

@@ -0,0 +1,69 @@
+"""Uses the old atexit with added unregister for python 2.x
+and the new atexit for python 3.x
+"""
+import atexit
+import sys
+
+
+__all__ = ["register", "unregister"]
+
+
+_exithandlers = []
+
+
+def _run_exitfuncs():
+    """run any registered exit functions
+
+    _exithandlers is traversed in reverse order so functions are executed
+    last in, first out.
+    """
+
+    exc_info = None
+    while _exithandlers:
+        func, targs, kargs = _exithandlers.pop()
+        try:
+            func(*targs, **kargs)
+        except SystemExit:
+            exc_info = sys.exc_info()
+        except:
+            import traceback
+            sys.stderr.write("Error in atexit._run_exitfuncs:\n")
+            traceback.print_exc()
+            exc_info = sys.exc_info()
+
+    if exc_info is not None:
+        raise exc_info[0](exc_info[1])
+
+
+def register(func, *targs, **kargs):
+    """register a function to be executed upon normal program termination
+
+    func - function to be called at exit
+    targs - optional arguments to pass to func
+    kargs - optional keyword arguments to pass to func
+
+    func is returned to facilitate usage as a decorator.
+    """
+    if hasattr(atexit, "unregister"):
+        atexit.register(func, *targs, **kargs)
+    else:
+        _exithandlers.append((func, targs, kargs))
+    return func
+
+
+def unregister(func):
+    """remove func from the list of functions that are registered
+    doesn't do anything if func is not found
+
+    func = function to be unregistered
+    """
+    if hasattr(atexit, "unregister"):
+        atexit.unregister(func)
+    else:
+        handler_entries = [e for e in _exithandlers if e[0] == func]
+        for e in handler_entries:
+            _exithandlers.remove(e)
+
+if not hasattr(atexit, "unregister"):
+    # Only in python 2.x
+    atexit.register(_run_exitfuncs)

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/protocol/__init__.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/__init__.py


+ 3 - 4
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/barrier.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/barrier.py

@@ -8,10 +8,8 @@ import os
 import socket
 import uuid
 
+from kazoo.exceptions import KazooException, NoNodeError, NodeExistsError
 from kazoo.protocol.states import EventType
-from kazoo.exceptions import KazooException
-from kazoo.exceptions import NoNodeError
-from kazoo.exceptions import NodeExistsError
 
 
 class Barrier(object):
@@ -135,7 +133,8 @@ class DoubleBarrier(object):
         ready = self.client.handler.event_object()
 
         try:
-            self.client.create(self.create_path,
+            self.client.create(
+                self.create_path,
                 self._identifier.encode('utf-8'), ephemeral=True)
         except NodeExistsError:
             pass

+ 427 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/cache.py

@@ -0,0 +1,427 @@
+"""TreeCache
+
+:Maintainer: Jiangge Zhang <tonyseek@gmail.com>
+:Maintainer: Haochuan Guo <guohaochuan@gmail.com>
+:Maintainer: Tianwen Zhang <mail2tevin@gmail.com>
+:Status: Alpha
+
+A port of the Apache Curator's TreeCache recipe. It builds an in-memory cache
+of a subtree in ZooKeeper and keeps it up-to-date.
+
+See also: http://curator.apache.org/curator-recipes/tree-cache.html
+"""
+from __future__ import absolute_import
+
+import contextlib
+import functools
+import logging
+import operator
+import os
+
+from kazoo.exceptions import NoNodeError, KazooException
+from kazoo.protocol.paths import _prefix_root
+from kazoo.protocol.states import KazooState, EventType
+
+
+logger = logging.getLogger(__name__)
+
+
+class TreeCache(object):
+    """The cache of a ZooKeeper subtree.
+
+    :param client: A :class:`~kazoo.client.KazooClient` instance.
+    :param path: The root path of subtree.
+    """
+
+    STATE_LATENT = 0
+    STATE_STARTED = 1
+    STATE_CLOSED = 2
+
+    _STOP = object()
+
+    def __init__(self, client, path):
+        self._client = client
+        self._root = TreeNode.make_root(self, path)
+        self._state = self.STATE_LATENT
+        self._outstanding_ops = 0
+        self._is_initialized = False
+        self._error_listeners = []
+        self._event_listeners = []
+        self._task_queue = client.handler.queue_impl()
+        self._task_thread = None
+
+    def start(self):
+        """Starts the cache.
+
+        The cache is not started automatically. You must call this method.
+
+        After a cache started, all changes of subtree will be synchronized
+        from the ZooKeeper server. Events will be fired for those activity.
+
+        Don't forget to call :meth:`close` if a tree was started and you don't
+        need it anymore, or you will leak the memory of cached nodes, even if
+        you have released all references to the :class:`TreeCache` instance.
+        Because there are so many callbacks that have been registered to the
+        Kazoo client.
+
+        See also :meth:`~TreeCache.listen`.
+
+        .. note::
+
+            This method is not thread safe.
+        """
+        if self._state == self.STATE_LATENT:
+            self._state = self.STATE_STARTED
+        elif self._state == self.STATE_CLOSED:
+            raise KazooException('already closed')
+        else:
+            raise KazooException('already started')
+
+        self._task_thread = self._client.handler.spawn(self._do_background)
+        self._client.add_listener(self._session_watcher)
+        self._client.ensure_path(self._root._path)
+
+        if self._client.connected:
+            # The on_created and other on_* methods must not be invoked outside
+            # the background task. This is the key to keep concurrency safe
+            # without lock.
+            self._in_background(self._root.on_created)
+
+    def close(self):
+        """Closes the cache.
+
+        A closed cache was detached from ZooKeeper's changes. And all nodes
+        will be invalidated.
+
+        Once a tree cache was closed, it could not be started again. You should
+        only close a tree cache while you want to recycle it.
+
+        .. note::
+
+            This method is not thread safe.
+        """
+        if self._state == self.STATE_STARTED:
+            self._state = self.STATE_CLOSED
+            self._task_queue.put(self._STOP)
+            self._client.remove_listener(self._session_watcher)
+            with handle_exception(self._error_listeners):
+                # We must invoke on_deleted outside background queue because:
+                # 1. The background task has been stopped.
+                # 2. The on_deleted on closed tree does not communicate with
+                #    ZooKeeper actually.
+                self._root.on_deleted()
+
+    def listen(self, listener):
+        """Registers a function to listen the cache events.
+
+        The cache events are changes of local data. They are delivered from
+        watching notifications in ZooKeeper session.
+
+        This method can be use as a decorator.
+
+        :param listener: A callable object which accepting a
+                         :class:`~kazoo.recipe.cache.TreeEvent` instance as
+                         its argument.
+        """
+        self._event_listeners.append(listener)
+        return listener
+
+    def listen_fault(self, listener):
+        """Registers a function to listen the exceptions.
+
+        It is possible to meet some exceptions during the cache running. You
+        could specific handlers for them.
+
+        This method can be use as a decorator.
+
+        :param listener: A callable object which accepting an exception as its
+                         argument.
+        """
+        self._error_listeners.append(listener)
+        return listener
+
+    def get_data(self, path, default=None):
+        """Gets data of a node from cache.
+
+        :param path: The absolute path string.
+        :param default: The default value which will be returned if the node
+                        does not exist.
+        :raises ValueError: If the path is outside of this subtree.
+        :returns: A :class:`~kazoo.recipe.cache.NodeData` instance.
+        """
+        node = self._find_node(path)
+        return default if node is None else node._data
+
+    def get_children(self, path, default=None):
+        """Gets node children list from in-memory snapshot.
+
+        :param path: The absolute path string.
+        :param default: The default value which will be returned if the node
+                        does not exist.
+        :raises ValueError: If the path is outside of this subtree.
+        :returns: The :class:`frozenset` which including children names.
+        """
+        node = self._find_node(path)
+        return default if node is None else frozenset(node._children)
+
+    def _find_node(self, path):
+        if not path.startswith(self._root._path):
+            raise ValueError('outside of tree')
+        striped_path = path[len(self._root._path):].strip('/')
+        splited_path = [p for p in striped_path.split('/') if p]
+        current_node = self._root
+        for node_name in splited_path:
+            if node_name not in current_node._children:
+                return
+            current_node = current_node._children[node_name]
+        return current_node
+
+    def _publish_event(self, event_type, event_data=None):
+        event = TreeEvent.make(event_type, event_data)
+        if self._state != self.STATE_CLOSED:
+            logger.debug('public event: %r', event)
+            self._in_background(self._do_publish_event, event)
+
+    def _do_publish_event(self, event):
+        for listener in self._event_listeners:
+            with handle_exception(self._error_listeners):
+                listener(event)
+
+    def _in_background(self, func, *args, **kwargs):
+        self._task_queue.put((func, args, kwargs))
+
+    def _do_background(self):
+        while True:
+            with handle_exception(self._error_listeners):
+                cb = self._task_queue.get()
+                if cb is self._STOP:
+                    break
+                func, args, kwargs = cb
+                func(*args, **kwargs)
+
+                # release before possible idle
+                del cb, func, args, kwargs
+
+    def _session_watcher(self, state):
+        if state == KazooState.SUSPENDED:
+            self._publish_event(TreeEvent.CONNECTION_SUSPENDED)
+        elif state == KazooState.CONNECTED:
+            # The session watcher should not be blocked
+            self._in_background(self._root.on_reconnected)
+            self._publish_event(TreeEvent.CONNECTION_RECONNECTED)
+        elif state == KazooState.LOST:
+            self._is_initialized = False
+            self._publish_event(TreeEvent.CONNECTION_LOST)
+
+
+class TreeNode(object):
+    """The tree node record.
+
+    :param tree: A :class:`~kazoo.recipe.cache.TreeCache` instance.
+    :param path: The path of current node.
+    :param parent: The parent node reference. ``None`` for root node.
+    """
+
+    __slots__ = ('_tree', '_path', '_parent', '_depth', '_children', '_state',
+                 '_data')
+
+    STATE_PENDING = 0
+    STATE_LIVE = 1
+    STATE_DEAD = 2
+
+    def __init__(self, tree, path, parent):
+        self._tree = tree
+        self._path = path
+        self._parent = parent
+        self._depth = parent._depth + 1 if parent else 0
+        self._children = {}
+        self._state = self.STATE_PENDING
+        self._data = None
+
+    @classmethod
+    def make_root(cls, tree, path):
+        return cls(tree, path, None)
+
+    def on_reconnected(self):
+        self._refresh()
+        for child in self._children.values():
+            child.on_reconnected()
+
+    def on_created(self):
+        self._refresh()
+
+    def on_deleted(self):
+        old_children, self._children = self._children, {}
+        old_data, self._data = self._data, None
+
+        for old_child in old_children.values():
+            old_child.on_deleted()
+
+        if self._tree._state == self._tree.STATE_CLOSED:
+            self._reset_watchers()
+            return
+
+        old_state, self._state = self._state, self.STATE_DEAD
+        if old_state == self.STATE_LIVE:
+            self._publish_event(TreeEvent.NODE_REMOVED, old_data)
+
+        if self._parent is None:
+            self._call_client('exists', self._path)  # root node
+        else:
+            child = self._path[len(self._parent._path) + 1:]
+            if self._parent._children.get(child) is self:
+                del self._parent._children[child]
+                self._reset_watchers()
+
+    def _publish_event(self, *args, **kwargs):
+        return self._tree._publish_event(*args, **kwargs)
+
+    def _reset_watchers(self):
+        client = self._tree._client
+        for _watchers in (client._data_watchers, client._child_watchers):
+            _path = _prefix_root(client.chroot, self._path)
+            _watcher = _watchers.get(_path, set())
+            _watcher.discard(self._process_watch)
+
+    def _refresh(self):
+        self._refresh_data()
+        self._refresh_children()
+
+    def _refresh_data(self):
+        self._call_client('get', self._path)
+
+    def _refresh_children(self):
+        # TODO max-depth checking support
+        self._call_client('get_children', self._path)
+
+    def _call_client(self, method_name, path):
+        assert method_name in ('get', 'get_children', 'exists')
+        self._tree._outstanding_ops += 1
+        callback = functools.partial(
+            self._tree._in_background, self._process_result,
+            method_name, path)
+        method = getattr(self._tree._client, method_name + '_async')
+        method(path, watch=self._process_watch).rawlink(callback)
+
+    def _process_watch(self, watched_event):
+        logger.debug('process_watch: %r', watched_event)
+        with handle_exception(self._tree._error_listeners):
+            if watched_event.type == EventType.CREATED:
+                assert self._parent is None, 'unexpected CREATED on non-root'
+                self.on_created()
+            elif watched_event.type == EventType.DELETED:
+                self.on_deleted()
+            elif watched_event.type == EventType.CHANGED:
+                self._refresh_data()
+            elif watched_event.type == EventType.CHILD:
+                self._refresh_children()
+
+    def _process_result(self, method_name, path, result):
+        logger.debug('process_result: %s %s', method_name, path)
+        if method_name == 'exists':
+            assert self._parent is None, 'unexpected EXISTS on non-root'
+            # The result will be `None` if the node doesn't exist.
+            if result.successful() and result.get() is not None:
+                if self._state == self.STATE_DEAD:
+                    self._state = self.STATE_PENDING
+                self.on_created()
+        elif method_name == 'get_children':
+            if result.successful():
+                children = result.get()
+                for child in sorted(children):
+                    full_path = os.path.join(path, child)
+                    if child not in self._children:
+                        node = TreeNode(self._tree, full_path, self)
+                        self._children[child] = node
+                        node.on_created()
+            elif isinstance(result.exception, NoNodeError):
+                self.on_deleted()
+        elif method_name == 'get':
+            if result.successful():
+                data, stat = result.get()
+                old_data, self._data = (
+                    self._data, NodeData.make(path, data, stat))
+                old_state, self._state = self._state, self.STATE_LIVE
+                if old_state == self.STATE_LIVE:
+                    if old_data is None or old_data.stat.mzxid != stat.mzxid:
+                        self._publish_event(TreeEvent.NODE_UPDATED, self._data)
+                else:
+                    self._publish_event(TreeEvent.NODE_ADDED, self._data)
+            elif isinstance(result.exception, NoNodeError):
+                self.on_deleted()
+        else:  # pragma: no cover
+            logger.warning('unknown operation %s', method_name)
+            self._tree._outstanding_ops -= 1
+            return
+
+        self._tree._outstanding_ops -= 1
+        if self._tree._outstanding_ops == 0 and not self._tree._is_initialized:
+            self._tree._is_initialized = True
+            self._publish_event(TreeEvent.INITIALIZED)
+
+
+class TreeEvent(tuple):
+    """The immutable event tuple of cache."""
+
+    NODE_ADDED = 0
+    NODE_UPDATED = 1
+    NODE_REMOVED = 2
+    CONNECTION_SUSPENDED = 3
+    CONNECTION_RECONNECTED = 4
+    CONNECTION_LOST = 5
+    INITIALIZED = 6
+
+    #: An enumerate integer to indicate event type.
+    event_type = property(operator.itemgetter(0))
+
+    #: A :class:`~kazoo.recipe.cache.NodeData` instance.
+    event_data = property(operator.itemgetter(1))
+
+    @classmethod
+    def make(cls, event_type, event_data):
+        """Creates a new TreeEvent tuple.
+
+        :returns: A :class:`~kazoo.recipe.cache.TreeEvent` instance.
+        """
+        assert event_type in (
+            cls.NODE_ADDED, cls.NODE_UPDATED, cls.NODE_REMOVED,
+            cls.CONNECTION_SUSPENDED, cls.CONNECTION_RECONNECTED,
+            cls.CONNECTION_LOST, cls.INITIALIZED)
+        return cls((event_type, event_data))
+
+
+class NodeData(tuple):
+    """The immutable node data tuple of cache."""
+
+    #: The absolute path string of current node.
+    path = property(operator.itemgetter(0))
+
+    #: The bytes data of current node.
+    data = property(operator.itemgetter(1))
+
+    #: The stat information of current node.
+    stat = property(operator.itemgetter(2))
+
+    @classmethod
+    def make(cls, path, data, stat):
+        """Creates a new NodeData tuple.
+
+        :returns: A :class:`~kazoo.recipe.cache.NodeData` instance.
+        """
+        return cls((path, data, stat))
+
+
+@contextlib.contextmanager
+def handle_exception(listeners):
+    try:
+        yield
+    except Exception as e:
+        logger.debug('processing error: %r', e)
+        if listeners:
+            for listener in listeners:
+                try:
+                    listener(e)
+                except BaseException:  # pragma: no cover
+                    logger.exception('Exception handling exception')  # oops
+        else:
+            logger.exception('No listener to process %r', e)

+ 41 - 7
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/counter.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/counter.py

@@ -4,10 +4,9 @@
 :Status: Unknown
 
 """
-
 from kazoo.exceptions import BadVersionError
 from kazoo.retry import ForceRetryError
-
+import struct
 
 class Counter(object):
     """Kazoo Counter
@@ -20,6 +19,12 @@ class Counter(object):
     `type(counter.default)(value)` both using an ascii encoding. As
     such other data types might be used for the counter value.
 
+    If you would like to support clients updating the same znode path using
+    either kazoo's counter recipe or curator's SharedCount recipe, you will
+    need to enable the support_curator flag. This flag limits
+    support to integers only and does not use ascii encoding as described
+    above.
+
     Counter changes can raise
     :class:`~kazoo.exceptions.BadVersionError` if the retry policy
     wasn't able to apply a change.
@@ -29,29 +34,49 @@ class Counter(object):
     .. code-block:: python
 
         zk = KazooClient()
+        zk.start()
         counter = zk.Counter("/int")
         counter += 2
         counter -= 1
         counter.value == 1
+        counter.pre_value == 2
+        counter.post_value == 1
 
         counter = zk.Counter("/float", default=1.0)
         counter += 2.0
         counter.value == 3.0
+        counter.pre_value == 1.0
+        counter.post_value == 3.0
+
+        counter = zk.Counter("/curator", support_curator=True)
+        counter += 2
+        counter -= 1
+        counter.value == 1
+        counter.pre_value == 2
+        counter.post_value == 1
 
     """
-    def __init__(self, client, path, default=0):
+    def __init__(self, client, path, default=0, support_curator=False):
         """Create a Kazoo Counter
 
         :param client: A :class:`~kazoo.client.KazooClient` instance.
         :param path: The counter path to use.
-        :param default: The default value.
+        :param default: The default value to use for new counter paths.
+        :param support_curator: Enable if support for curator's SharedCount
+                                recipe is desired.
 
         """
         self.client = client
         self.path = path
         self.default = default
         self.default_type = type(default)
+        self.support_curator = support_curator
         self._ensured_path = False
+        self.pre_value = None
+        self.post_value = None
+        if self.support_curator and not isinstance(self.default, int):
+            raise TypeError("when support_curator is enabled the default "
+                            "type must be an int")
 
     def _ensure_node(self):
         if not self._ensured_path:
@@ -62,7 +87,10 @@ class Counter(object):
     def _value(self):
         self._ensure_node()
         old, stat = self.client.get(self.path)
-        old = old.decode('ascii') if old != b'' else self.default
+        if self.support_curator:
+            old = struct.unpack(">i", old)[0] if old != b'' else self.default
+        else:
+            old = old.decode('ascii') if old != b'' else self.default
         version = stat.version
         data = self.default_type(old)
         return data, version
@@ -78,12 +106,18 @@ class Counter(object):
         return self
 
     def _inner_change(self, value):
-        data, version = self._value()
-        data = repr(data + value).encode('ascii')
+        self.pre_value, version = self._value()
+        post_value = self.pre_value + value
+        if self.support_curator:
+            data = struct.pack(">i", post_value)
+        else:
+            data = repr(post_value).encode('ascii')
         try:
             self.client.set(self.path, data, version=version)
         except BadVersionError:  # pragma: nocover
+            self.post_value = None
             raise ForceRetryError()
+        self.post_value = post_value
 
     def __add__(self, value):
         """Add value to counter."""

+ 1 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/election.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/election.py

@@ -13,6 +13,7 @@ class Election(object):
     Example usage with a :class:`~kazoo.client.KazooClient` instance::
 
         zk = KazooClient()
+        zk.start()
         election = zk.Election("/electionpath", "my-identifier")
 
         # blocks until the election is won, then calls

+ 147 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/lease.py

@@ -0,0 +1,147 @@
+"""Zookeeper lease implementations
+
+:Maintainer: Lars Albertsson <lars.albertsson@gmail.com>
+:Maintainer: Jyrki Pulliainen <jyrki@spotify.com>
+:Status: Beta
+
+"""
+import datetime
+import json
+import socket
+
+from kazoo.exceptions import CancelledError
+
+
+class NonBlockingLease(object):
+    """Exclusive lease that does not block.
+
+    An exclusive lease ensures that only one client at a time owns the lease.
+    The client may renew the lease without losing it by obtaining a new lease
+    with the same path and same identity.  The lease object evaluates to True
+    if the lease was obtained.
+
+    A common use case is a situation where a task should only run on a single
+    host.  In this case, the clients that did not obtain the lease should exit
+    without performing the protected task.
+
+    The lease stores time stamps using client clocks, and will therefore only
+    work if client clocks are roughly synchronised.  It uses UTC, and works
+    across time zones and daylight savings.
+
+    Example usage: with a :class:`~kazoo.client.KazooClient` instance::
+
+        zk = KazooClient()
+        zk.start()
+        # Hold lease over an hour in order to keep job on same machine,
+        # with failover if it dies.
+        lease = zk.NonBlockingLease(
+            "/db_leases/hourly_cleanup", datetime.timedelta(minutes = 70),
+            identifier = "DB hourly cleanup on " + socket.gethostname())
+        if lease:
+            do_hourly_database_cleanup()
+    """
+
+    # Bump when storage format changes
+    _version = 1
+    _date_format = "%Y-%m-%dT%H:%M:%S"
+    _byte_encoding = 'utf-8'
+
+    def __init__(self, client, path, duration, identifier=None,
+                 utcnow=datetime.datetime.utcnow):
+        """Create a non-blocking lease.
+
+        :param client: A :class:`~kazoo.client.KazooClient` instance.
+        :param path: The lease path to use.
+        :param duration: Duration during which the lease is reserved.  A
+                         :class:`~datetime.timedelta` instance.
+        :param identifier: Unique name to use for this lease holder. Reuse in
+                           order to renew the lease. Defaults to
+                           :meth:`socket.gethostname()`.
+        :param utcnow: Clock function, by default returning
+                       :meth:`datetime.datetime.utcnow()`. Used for testing.
+
+        """
+        ident = identifier or socket.gethostname()
+        self.obtained = False
+        self._attempt_obtaining(client, path, duration, ident, utcnow)
+
+    def _attempt_obtaining(self, client, path, duration, ident, utcnow):
+        client.ensure_path(path)
+        holder_path = path + "/lease_holder"
+        lock = client.Lock(path, ident)
+        try:
+            with lock:
+                now = utcnow()
+                if client.exists(holder_path):
+                    raw, _ = client.get(holder_path)
+                    data = self._decode(raw)
+                    if data["version"] != self._version:
+                        # We need an upgrade, let someone else take the lease
+                        return
+                    current_end = datetime.datetime.strptime(data['end'],
+                                                             self._date_format)
+                    if data['holder'] != ident and now < current_end:
+                        # Another client is still holding the lease
+                        return
+                    client.delete(holder_path)
+                end_lease = (now + duration).strftime(self._date_format)
+                new_data = {'version': self._version, 'holder': ident,
+                            'end': end_lease}
+                client.create(holder_path, self._encode(new_data))
+                self.obtained = True
+
+        except CancelledError:
+            pass
+
+    def _encode(self, data_dict):
+        return json.dumps(data_dict).encode(self._byte_encoding)
+
+    def _decode(self, raw):
+        return json.loads(raw.decode(self._byte_encoding))
+
+    # Python 2.x
+    def __nonzero__(self):
+        return self.obtained
+
+    # Python 3.x
+    def __bool__(self):
+        return self.obtained
+
+
+class MultiNonBlockingLease(object):
+    """Exclusive lease for multiple clients.
+
+    This type of lease is useful when a limited set of hosts should run a
+    particular task. It will attempt to obtain leases trying a sequence of
+    ZooKeeper lease paths.
+
+    :param client: A :class:`~kazoo.client.KazooClient` instance.
+    :param count: Number of host leases allowed.
+    :param path: ZooKeeper path under which lease files are stored.
+    :param duration: Duration during which the lease is reserved.  A
+                     :class:`~datetime.timedelta` instance.
+    :param identifier: Unique name to use for this lease holder. Reuse in order
+                       to renew the lease.
+           Defaults do :meth:`socket.gethostname()`.
+    :param utcnow: Clock function, by default returning
+                   :meth:`datetime.datetime.utcnow()`.  Used for testing.
+
+    """
+
+    def __init__(self, client, count, path, duration, identifier=None,
+                 utcnow=datetime.datetime.utcnow):
+        self.obtained = False
+        for num in range(count):
+            ls = NonBlockingLease(client, '%s/%d' % (path, num), duration,
+                                  identifier=identifier, utcnow=utcnow)
+            if ls:
+                self.obtained = True
+                break
+
+    # Python 2.x
+    def __nonzero__(self):
+        return self.obtained
+
+    # Python 3.x
+    def __bool__(self):
+        return self.obtained

+ 307 - 89
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/lock.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/lock.py

@@ -1,7 +1,7 @@
 """Zookeeper Locking Implementations
 
-:Maintainer: None
-:Status: Unknown
+:Maintainer: Ben Bangert <ben@groovie.org>
+:Status: Production
 
 Error Handling
 ==============
@@ -14,18 +14,45 @@ changes and re-act appropriately. In the event that a
 and/or the lease has been lost.
 
 """
+import re
+import sys
+
+try:
+    from time import monotonic as now
+except ImportError:
+    from time import time as now
 import uuid
 
+import six
+
+from kazoo.exceptions import (
+    CancelledError,
+    KazooException,
+    LockTimeout,
+    NoNodeError,
+)
+from kazoo.protocol.states import KazooState
 from kazoo.retry import (
+    ForceRetryError,
     KazooRetry,
     RetryFailedError,
-    ForceRetryError
 )
-from kazoo.exceptions import CancelledError
-from kazoo.exceptions import KazooException
-from kazoo.exceptions import LockTimeout
-from kazoo.exceptions import NoNodeError
-from kazoo.protocol.states import KazooState
+
+
+class _Watch(object):
+    def __init__(self, duration=None):
+        self.duration = duration
+        self.started_at = None
+
+    def start(self):
+        self.started_at = now()
+
+    def leftover(self):
+        if self.duration is None:
+            return None
+        else:
+            elapsed = now() - self.started_at
+            return max(0, self.duration - elapsed)
 
 
 class Lock(object):
@@ -36,32 +63,60 @@ class Lock(object):
     .. code-block:: python
 
         zk = KazooClient()
+        zk.start()
         lock = zk.Lock("/lockpath", "my-identifier")
         with lock:  # blocks waiting for lock acquisition
             # do something with the lock
 
-    Note: This lock is re-entrant. Repeat calls after acquired will
-    continue to return ''True''.
+    Note: This lock is not *re-entrant*. Repeated calls after already
+    acquired will block.
+
+    This is an exclusive lock. For a read/write lock, see :class:`WriteLock`
+    and :class:`ReadLock`.
 
     """
-    _NODE_NAME = '__lock__'
 
-    def __init__(self, client, path, identifier=None):
+    # Node name, after the contender UUID, before the sequence
+    # number. Involved in read/write locks.
+    _NODE_NAME = "__lock__"
+
+    # Node names which exclude this contender when present at a lower
+    # sequence number. Involved in read/write locks.
+    _EXCLUDE_NAMES = ["__lock__"]
+
+    def __init__(self, client, path, identifier=None, extra_lock_patterns=()):
         """Create a Kazoo lock.
 
         :param client: A :class:`~kazoo.client.KazooClient` instance.
         :param path: The lock path to use.
-        :param identifier: Name to use for this lock contender. This
-                           can be useful for querying to see who the
-                           current lock contenders are.
-
+        :param identifier: Name to use for this lock contender. This can be
+                          useful for querying to see who the current lock
+                          contenders are.
+        :param extra_lock_patterns: Strings that will be used to
+                                    identify other znode in the path
+                                    that should be considered contenders
+                                    for this lock.
+                                    Use this for cross-implementation
+                                    compatibility.
+
+        .. versionadded:: 2.7.1
+            The extra_lock_patterns option.
         """
         self.client = client
         self.path = path
+        self._exclude_names = set(
+            self._EXCLUDE_NAMES + list(extra_lock_patterns)
+        )
+        self._contenders_re = re.compile(
+            r"(?:{patterns})(-?\d{{10}})$".format(
+                patterns="|".join(self._exclude_names)
+            )
+        )
 
         # some data is written to the node. this can be queried via
         # contenders() to see who is contending for the lock
-        self.data = str(identifier or "").encode('utf-8')
+        self.data = str(identifier or "").encode("utf-8")
+        self.node = None
 
         self.wake_event = client.handler.event_object()
 
@@ -76,8 +131,10 @@ class Lock(object):
         self.is_acquired = False
         self.assured_path = False
         self.cancelled = False
-        self._retry = KazooRetry(max_tries=None,
-                                 sleep_func=client.handler.sleep_func)
+        self._retry = KazooRetry(
+            max_tries=None, sleep_func=client.handler.sleep_func
+        )
+        self._lock = client.handler.lock_object()
 
     def _ensure_path(self):
         self.client.ensure_path(self.path)
@@ -88,7 +145,7 @@ class Lock(object):
         self.cancelled = True
         self.wake_event.set()
 
-    def acquire(self, blocking=True, timeout=None):
+    def acquire(self, blocking=True, timeout=None, ephemeral=True):
         """
         Acquire the lock. By defaults blocks and waits forever.
 
@@ -96,6 +153,8 @@ class Lock(object):
         :type blocking: bool
         :param timeout: Don't wait forever to acquire the lock.
         :type timeout: float or None
+        :param ephemeral: Don't use ephemeral znode for the lock.
+        :type ephemeral: bool
 
         :returns: Was the lock acquired?
         :rtype: bool
@@ -103,32 +162,78 @@ class Lock(object):
         :raises: :exc:`~kazoo.exceptions.LockTimeout` if the lock
                  wasn't acquired within `timeout` seconds.
 
+        .. warning::
+
+            When :attr:`ephemeral` is set to False session expiration
+            will not release the lock and must be handled separately.
+
         .. versionadded:: 1.1
             The timeout option.
+
+        .. versionadded:: 2.4.1
+            The ephemeral option.
         """
-        try:
-            retry = self._retry.copy()
-            retry.deadline = timeout
-            self.is_acquired = retry(self._inner_acquire,
-                blocking=blocking, timeout=timeout)
-        except RetryFailedError:
-            self._best_effort_cleanup()
-        except KazooException:
-            # if we did ultimately fail, attempt to clean up
-            self._best_effort_cleanup()
-            self.cancelled = False
-            raise
 
-        if not self.is_acquired:
-            self._delete_node(self.node)
+        def _acquire_lock():
+            got_it = self._lock.acquire(False)
+            if not got_it:
+                raise ForceRetryError()
+            return True
 
-        return self.is_acquired
+        retry = self._retry.copy()
+        retry.deadline = timeout
+
+        # Ensure we are locked so that we avoid multiple threads in
+        # this acquistion routine at the same time...
+        locked = self._lock.acquire(False)
+        if not locked and not blocking:
+            return False
+        if not locked:
+            # Lock acquire doesn't take a timeout, so simulate it...
+            # XXX: This is not true in Py3 >= 3.2
+            try:
+                locked = retry(_acquire_lock)
+            except RetryFailedError:
+                return False
+        already_acquired = self.is_acquired
+        try:
+            gotten = False
+            try:
+                gotten = retry(
+                    self._inner_acquire,
+                    blocking=blocking,
+                    timeout=timeout,
+                    ephemeral=ephemeral,
+                )
+            except RetryFailedError:
+                pass
+            except KazooException:
+                # if we did ultimately fail, attempt to clean up
+                exc_info = sys.exc_info()
+                if not already_acquired:
+                    self._best_effort_cleanup()
+                    self.cancelled = False
+                six.reraise(exc_info[0], exc_info[1], exc_info[2])
+            if gotten:
+                self.is_acquired = gotten
+            if not gotten and not already_acquired:
+                self._best_effort_cleanup()
+            return gotten
+        finally:
+            self._lock.release()
 
     def _watch_session(self, state):
         self.wake_event.set()
         return True
 
-    def _inner_acquire(self, blocking, timeout):
+    def _inner_acquire(self, blocking, timeout, ephemeral=True):
+
+        # wait until it's our chance to get it..
+        if self.is_acquired:
+            if not blocking:
+                return False
+            raise ForceRetryError()
+
         # make sure our election parent node exists
         if not self.assured_path:
             self._ensure_path()
@@ -140,8 +245,9 @@ class Lock(object):
             self.create_tried = True
 
         if not node:
-            node = self.client.create(self.create_path, self.data,
-                                      ephemeral=True, sequence=True)
+            node = self.client.create(
+                self.create_path, self.data, ephemeral=ephemeral, sequence=True
+            )
             # strip off path to node
             node = node[len(self.path) + 1:]
 
@@ -154,47 +260,68 @@ class Lock(object):
             if self.cancelled:
                 raise CancelledError()
 
-            children = self._get_sorted_children()
-
-            try:
-                our_index = children.index(node)
-            except ValueError:  # pragma: nocover
-                # somehow we aren't in the children -- probably we are
-                # recovering from a session failure and our ephemeral
-                # node was removed
-                raise ForceRetryError()
-
-            if self.acquired_lock(children, our_index):
+            predecessor = self._get_predecessor(node)
+            if predecessor is None:
                 return True
 
             if not blocking:
                 return False
 
             # otherwise we are in the mix. watch predecessor and bide our time
-            predecessor = self.path + "/" + children[our_index - 1]
+            predecessor = self.path + "/" + predecessor
             self.client.add_listener(self._watch_session)
             try:
-                if self.client.exists(predecessor, self._watch_predecessor):
-                    self.wake_event.wait(timeout)
-                    if not self.wake_event.isSet():
-                        raise LockTimeout("Failed to acquire lock on %s after %s "
-                                          "seconds" % (self.path, timeout))
+                self.client.get(predecessor, self._watch_predecessor)
+            except NoNodeError:
+                pass  # predecessor has already been deleted
+            else:
+                self.wake_event.wait(timeout)
+                if not self.wake_event.isSet():
+                    raise LockTimeout(
+                        "Failed to acquire lock on %s after %s seconds"
+                        % (self.path, timeout)
+                    )
             finally:
                 self.client.remove_listener(self._watch_session)
 
-    def acquired_lock(self, children, index):
-        return index == 0
-
     def _watch_predecessor(self, event):
         self.wake_event.set()
 
-    def _get_sorted_children(self):
-        children = self.client.get_children(self.path)
+    def _get_predecessor(self, node):
+        """returns `node`'s predecessor or None
 
-        # can't just sort directly: the node names are prefixed by uuids
-        lockname = self._NODE_NAME
-        children.sort(key=lambda c: c[c.find(lockname) + len(lockname):])
-        return children
+        Note: This handle the case where the current lock is not a contender
+        (e.g. rlock), this and also edge cases where the lock's ephemeral node
+        is gone.
+        """
+        children = self.client.get_children(self.path)
+        found_self = False
+        # Filter out the contenders using the computed regex
+        contender_matches = []
+        for child in children:
+            match = self._contenders_re.search(child)
+            if match is not None:
+                contender_matches.append(match)
+            if child == node:
+                # Remember the node's match object so we can short circuit
+                # below.
+                found_self = match
+
+        if found_self is False:  # pragma: nocover
+            # somehow we aren't in the childrens -- probably we are
+            # recovering from a session failure and our ephemeral
+            # node was removed.
+            raise ForceRetryError()
+
+        predecessor = None
+        # Sort the contenders using the sequence number extracted by the regex,
+        # then extract the original string.
+        for match in sorted(contender_matches, key=lambda m: m.groups()):
+            if match is found_self:
+                break
+            predecessor = match.string
+
+        return predecessor
 
     def _find_node(self):
         children = self.client.get_children(self.path)
@@ -208,7 +335,7 @@ class Lock(object):
 
     def _best_effort_cleanup(self):
         try:
-            node = self._find_node()
+            node = self.node or self._find_node()
             if node:
                 self._delete_node(node)
         except KazooException:  # pragma: nocover
@@ -229,7 +356,6 @@ class Lock(object):
 
         self.is_acquired = False
         self.node = None
-
         return True
 
     def contenders(self):
@@ -246,15 +372,37 @@ class Lock(object):
         if not self.assured_path:
             self._ensure_path()
 
-        children = self._get_sorted_children()
-
-        contenders = []
+        children = self.client.get_children(self.path)
+        # We want all contenders, including self (this is especially important
+        # for r/w locks). This is similar to the logic of `_get_predecessor`
+        # except we include our own pattern.
+        all_contenders_re = re.compile(
+            r"(?:{patterns})(-?\d{{10}})$".format(
+                patterns="|".join(self._exclude_names | {self._NODE_NAME})
+            )
+        )
+        # Filter out the contenders using the computed regex
+        contender_matches = []
         for child in children:
+            match = all_contenders_re.search(child)
+            if match is not None:
+                contender_matches.append(match)
+        # Sort the contenders using the sequence number extracted by the regex,
+        # then extract the original string.
+        contender_nodes = [
+            match.string
+            for match in sorted(contender_matches, key=lambda m: m.groups())
+        ]
+        # Retrieve all the contender nodes data (preserving order).
+        contenders = []
+        for node in contender_nodes:
             try:
-                data, stat = self.client.get(self.path + "/" + child)
-                contenders.append(data.decode('utf-8'))
+                data, stat = self.client.get(self.path + "/" + node)
+                if data is not None:
+                    contenders.append(data.decode("utf-8"))
             except NoNodeError:  # pragma: nocover
                 pass
+
         return contenders
 
     def __enter__(self):
@@ -264,6 +412,66 @@ class Lock(object):
         self.release()
 
 
+class WriteLock(Lock):
+    """Kazoo Write Lock
+
+    Example usage with a :class:`~kazoo.client.KazooClient` instance:
+
+    .. code-block:: python
+
+        zk = KazooClient()
+        zk.start()
+        lock = zk.WriteLock("/lockpath", "my-identifier")
+        with lock:  # blocks waiting for lock acquisition
+            # do something with the lock
+
+    The lock path passed to WriteLock and ReadLock must match for them to
+    communicate.  The write lock can not be acquired if it is held by
+    any readers or writers.
+
+    Note: This lock is not *re-entrant*. Repeated calls after already
+    acquired will block.
+
+    This is the write-side of a shared lock.  See :class:`Lock` for a
+    standard exclusive lock and :class:`ReadLock` for the read-side of a
+    shared lock.
+
+    """
+
+    _NODE_NAME = "__lock__"
+    _EXCLUDE_NAMES = ["__lock__", "__rlock__"]
+
+
+class ReadLock(Lock):
+    """Kazoo Read Lock
+
+    Example usage with a :class:`~kazoo.client.KazooClient` instance:
+
+    .. code-block:: python
+
+        zk = KazooClient()
+        zk.start()
+        lock = zk.ReadLock("/lockpath", "my-identifier")
+        with lock:  # blocks waiting for outstanding writers
+            # do something with the lock
+
+    The lock path passed to WriteLock and ReadLock must match for them to
+    communicate.  The read lock blocks if it is held by any writers,
+    but multiple readers may hold the lock.
+
+    Note: This lock is not *re-entrant*. Repeated calls after already
+    acquired will block.
+
+    This is the read-side of a shared lock.  See :class:`Lock` for a
+    standard exclusive lock and :class:`WriteLock` for the write-side of a
+    shared lock.
+
+    """
+
+    _NODE_NAME = "__rlock__"
+    _EXCLUDE_NAMES = ["__lock__"]
+
+
 class Semaphore(object):
     """A Zookeeper-based Semaphore
 
@@ -272,6 +480,8 @@ class Semaphore(object):
     indicate how many available leases are available for the lock
     rather than counting.
 
+    Note: This lock is not meant to be *re-entrant*.
+
     Example:
 
     .. code-block:: python
@@ -296,6 +506,7 @@ class Semaphore(object):
         The max_leases check.
 
     """
+
     def __init__(self, client, path, identifier=None, max_leases=1):
         """Create a Kazoo Lock
 
@@ -321,12 +532,12 @@ class Semaphore(object):
 
         # some data is written to the node. this can be queried via
         # contenders() to see who is contending for the lock
-        self.data = str(identifier or "").encode('utf-8')
+        self.data = str(identifier or "").encode("utf-8")
         self.max_leases = max_leases
         self.wake_event = client.handler.event_object()
 
         self.create_path = self.path + "/" + uuid.uuid4().hex
-        self.lock_path = path + '-' + '__lock__'
+        self.lock_path = path + "-" + "__lock__"
         self.is_acquired = False
         self.assured_path = False
         self.cancelled = False
@@ -339,7 +550,7 @@ class Semaphore(object):
             # node did already exist
             data, _ = self.client.get(self.path)
             try:
-                leases = int(data.decode('utf-8'))
+                leases = int(data.decode("utf-8"))
             except (ValueError, TypeError):
                 # ignore non-numeric data, maybe the node data is used
                 # for other purposes
@@ -347,11 +558,11 @@ class Semaphore(object):
             else:
                 if leases != self.max_leases:
                     raise ValueError(
-                        "Inconsistent max leases: %s, expected: %s" %
-                        (leases, self.max_leases)
+                        "Inconsistent max leases: %s, expected: %s"
+                        % (leases, self.max_leases)
                     )
         else:
-            self.client.set(self.path, str(self.max_leases).encode('utf-8'))
+            self.client.set(self.path, str(self.max_leases).encode("utf-8"))
 
     def cancel(self):
         """Cancel a pending semaphore acquire."""
@@ -386,7 +597,8 @@ class Semaphore(object):
 
         try:
             self.is_acquired = self.client.retry(
-                self._inner_acquire, blocking=blocking, timeout=timeout)
+                self._inner_acquire, blocking=blocking, timeout=timeout
+            )
         except KazooException:
             # if we did ultimately fail, attempt to clean up
             self._best_effort_cleanup()
@@ -408,7 +620,13 @@ class Semaphore(object):
         if self.client.exists(self.create_path):
             return True
 
-        with self.client.Lock(self.lock_path, self.data):
+        w = _Watch(duration=timeout)
+        w.start()
+        lock = self.client.Lock(self.lock_path, self.data)
+        try:
+            gotten = lock.acquire(blocking=blocking, timeout=w.leftover())
+            if not gotten:
+                return False
             while True:
                 self.wake_event.clear()
 
@@ -419,16 +637,16 @@ class Semaphore(object):
                 if blocking:
                     # If blocking, wait until self._watch_lease_change() is
                     # called before returning
-                    self.wake_event.wait(timeout)
+                    self.wake_event.wait(w.leftover())
                     if not self.wake_event.isSet():
                         raise LockTimeout(
-                            "Failed to acquire semaphore on %s "
-                            "after %s seconds" % (self.path, timeout))
+                            "Failed to acquire semaphore on %s"
+                            " after %s seconds" % (self.path, timeout)
+                        )
                 else:
-                    # If not blocking, register another watch that will trigger
-                    # self._get_lease() as soon as the children change again.
-                    self.client.get_children(self.path, self._get_lease)
                     return False
+        finally:
+            lock.release()
 
     def _watch_lease_change(self, event):
         self.wake_event.set()
@@ -445,8 +663,9 @@ class Semaphore(object):
         # Get a list of the current potential lock holders. If they change,
         # notify our wake_event object. This is used to unblock a blocking
         # self._inner_acquire call.
-        children = self.client.get_children(self.path,
-                                            self._watch_lease_change)
+        children = self.client.get_children(
+            self.path, self._watch_lease_change
+        )
 
         # If there are leases available, acquire one
         if len(children) < self.max_leases:
@@ -482,7 +701,6 @@ class Semaphore(object):
     def _inner_release(self):
         if not self.is_acquired:
             return False
-
         try:
             self.client.delete(self.create_path)
         except NoNodeError:  # pragma: nocover
@@ -508,7 +726,7 @@ class Semaphore(object):
         for child in children:
             try:
                 data, stat = self.client.get(self.path + "/" + child)
-                lease_holders.append(data.decode('utf-8'))
+                lease_holders.append(data.decode("utf-8"))
             except NoNodeError:  # pragma: nocover
                 pass
         return lease_holders

+ 105 - 55
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/partitioner.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/partitioner.py

@@ -17,15 +17,16 @@ Example Use-Case
   so that no two workers own the same queue.
 
 """
+from functools import partial
 import logging
 import os
 import socket
-from functools import partial
 
-from kazoo.exceptions import KazooException
+from kazoo.exceptions import KazooException, LockTimeout
 from kazoo.protocol.states import KazooState
 from kazoo.recipe.watchers import PatientChildrenWatch
 
+
 log = logging.getLogger(__name__)
 
 
@@ -80,6 +81,7 @@ class SetPartitioner(object):
 
         from kazoo.client import KazooClient
         client = KazooClient()
+        client.start()
 
         qp = client.SetPartitioner(
             path='/work_queues', set=('queue-1', 'queue-2', 'queue-3'))
@@ -134,7 +136,8 @@ class SetPartitioner(object):
 
     """
     def __init__(self, client, path, set, partition_func=None,
-                 identifier=None, time_boundary=30):
+                 identifier=None, time_boundary=30, max_reaction_time=1,
+                 state_change_event=None):
         """Create a :class:`~SetPartitioner` instance
 
         :param client: A :class:`~kazoo.client.KazooClient` instance.
@@ -147,9 +150,17 @@ class SetPartitioner(object):
                            hostname + process id.
         :param time_boundary: How long the party members must be stable
                               before allocation can complete.
+        :param max_reaction_time: Maximum reaction time for party members
+                                  change.
+        :param state_change_event: An optional Event object that will be set
+                                   on every state change.
 
         """
+        # Used to differentiate two states with the same names in time
+        self.state_id = 0
         self.state = PartitionState.ALLOCATING
+        self.state_change_event = state_change_event or \
+            client.handler.event_object()
 
         self._client = client
         self._path = path
@@ -162,6 +173,7 @@ class SetPartitioner(object):
         self._lock_path = '/'.join([path, 'locks'])
         self._party_path = '/'.join([path, 'party'])
         self._time_boundary = time_boundary
+        self._max_reaction_time = max_reaction_time
 
         self._acquire_event = client.handler.event_object()
 
@@ -175,14 +187,12 @@ class SetPartitioner(object):
                                           identifier=self._identifier)
         self._party.join()
 
-        self._was_allocated = False
         self._state_change = client.handler.rlock_object()
         client.add_listener(self._establish_sessionwatch)
 
         # Now watch the party and set the callback on the async result
         # so we know when we're ready
-        self._children_updated = False
-        self._child_watching(self._allocate_transition, async=True)
+        self._child_watching(self._allocate_transition, client_handler=True)
 
     def __iter__(self):
         """Return the partitions in this partition set"""
@@ -236,8 +246,8 @@ class SetPartitioner(object):
             with self._state_change:
                 if self.failed:
                     return
-                self.state = PartitionState.ALLOCATING
-        self._child_watching(self._allocate_transition, async=True)
+                self._set_state(PartitionState.ALLOCATING)
+        self._child_watching(self._allocate_transition, client_handler=True)
 
     def finish(self):
         """Call to release the set and leave the party"""
@@ -246,7 +256,7 @@ class SetPartitioner(object):
 
     def _fail_out(self):
         with self._state_change:
-            self.state = PartitionState.FAILURE
+            self._set_state(PartitionState.FAILURE)
         if self._party.participating:
             try:
                 self._party.leave()
@@ -255,49 +265,90 @@ class SetPartitioner(object):
 
     def _allocate_transition(self, result):
         """Called when in allocating mode, and the children settled"""
+
         # Did we get an exception waiting for children to settle?
         if result.exception:  # pragma: nocover
             self._fail_out()
             return
 
         children, async_result = result.get()
-        self._children_updated = False
+        children_changed = self._client.handler.event_object()
 
-        # Add a callback when children change on the async_result
         def updated(result):
             with self._state_change:
+                children_changed.set()
                 if self.acquired:
-                    self.state = PartitionState.RELEASE
-            self._children_updated = True
+                    self._set_state(PartitionState.RELEASE)
+
+        with self._state_change:
+            # We can lose connection during processing the event
+            if not self.allocating:
+                return
+
+            # Remember the state ID to check later for race conditions
+            state_id = self.state_id
+
+            # updated() will be called when children change
+            async_result.rawlink(updated)
+
+        # Check whether the state has changed during the lock acquisition
+        # and abort the process if so.
+        def abort_if_needed():
+            if self.state_id == state_id:
+                if children_changed.is_set():
+                    # The party has changed. Repartitioning...
+                    self._abort_lock_acquisition()
+                    return True
+                else:
+                    return False
+            else:
+                if self.allocating or self.acquired:
+                    # The connection was lost and user initiated a new
+                    # allocation process. Abort it to eliminate race
+                    # conditions with locks.
+                    with self._state_change:
+                        self._set_state(PartitionState.RELEASE)
 
-        async_result.rawlink(updated)
+                return True
 
         # Split up the set
-        self._partition_set = self._partition_func(
+        partition_set = self._partition_func(
             self._identifier, list(self._party), self._set)
 
         # Proceed to acquire locks for the working set as needed
-        for member in self._partition_set:
-            if self._children_updated or self.failed:
-                # Still haven't settled down, release locks acquired
-                # so far and go back
-                return self._abort_lock_acquisition()
-
-            lock = self._client.Lock(self._lock_path + '/' +
-                                     str(member))
-            try:
-                lock.acquire()
-            except KazooException:  # pragma: nocover
-                return self.finish()
+        for member in partition_set:
+            lock = self._client.Lock(self._lock_path + '/' + str(member))
+
+            while True:
+                try:
+                    # We mustn't lock without timeout because in that case we
+                    # can get a deadlock if the party state will change during
+                    # lock acquisition.
+                    lock.acquire(timeout=self._max_reaction_time)
+                except LockTimeout:
+                    if abort_if_needed():
+                        return
+                except KazooException:
+                    return self.finish()
+                else:
+                    break
+
             self._locks.append(lock)
 
-        # All locks acquired! Time for state transition, make sure
-        # we didn't inadvertently get lost thus far
+            if abort_if_needed():
+                return
+
+        # All locks acquired. Time for state transition.
         with self._state_change:
-            if self.failed:  # pragma: nocover
-                return self.finish()
-            self.state = PartitionState.ACQUIRED
-            self._acquire_event.set()
+            if self.state_id == state_id and not children_changed.is_set():
+                self._partition_set = partition_set
+                self._set_state(PartitionState.ACQUIRED)
+                self._acquire_event.set()
+                return
+
+        if not abort_if_needed():
+            # This mustn't happen. Means a logical error.
+            self._fail_out()
 
     def _release_locks(self):
         """Attempt to completely remove all the locks"""
@@ -314,22 +365,26 @@ class SetPartitioner(object):
 
     def _abort_lock_acquisition(self):
         """Called during lock acquisition if a party change occurs"""
-        self._partition_set = []
+
         self._release_locks()
+
         if self._locks:
             # This shouldn't happen, it means we couldn't release our
             # locks, abort
             self._fail_out()
             return
-        return self._child_watching(self._allocate_transition)
 
-    def _child_watching(self, func=None, async=False):
+        self._child_watching(self._allocate_transition, client_handler=True)
+
+    def _child_watching(self, func=None, client_handler=False):
         """Called when children are being watched to stabilize
 
         This actually returns immediately, child watcher spins up a
         new thread/greenlet and waits for it to stabilize before
         any callbacks might run.
 
+        :param client_handler: If True, deliver the result using the
+                               client's event handler.
         """
         watcher = PatientChildrenWatch(self._client, self._party_path,
                                        self._time_boundary)
@@ -338,7 +393,7 @@ class SetPartitioner(object):
             # We spin up the function in a separate thread/greenlet
             # to ensure that the rawlink's it might use won't be
             # blocked
-            if async:
+            if client_handler:
                 func = partial(self._client.handler.spawn, func)
             asy.rawlink(func)
         return asy
@@ -347,24 +402,14 @@ class SetPartitioner(object):
         """Register ourself to listen for session events, we shut down
         if we become lost"""
         with self._state_change:
-            # Handle network partition: If connection gets suspended,
-            # change state to ALLOCATING if we had already ACQUIRED. This way
-            # the caller does not process the members since we could eventually
-            # lose session get repartitioned. If we got connected after a suspension
-            # it means we've not lost the session and still have our members. Hence,
-            # restore to ACQUIRED
-            if state == KazooState.SUSPENDED:
-                if self.state == PartitionState.ACQUIRED:
-                    self._was_allocated = True
-                    self.state = PartitionState.ALLOCATING
-            elif state == KazooState.CONNECTED:
-                if self._was_allocated:
-                    self._was_allocated = False
-                    self.state = PartitionState.ACQUIRED
-
-        if state == KazooState.LOST:
-            self._client.handler.spawn(self._fail_out)
-            return True
+            if self.failed:
+                pass
+            elif state == KazooState.LOST:
+                self._client.handler.spawn(self._fail_out)
+            elif not self.release:
+                self._set_state(PartitionState.RELEASE)
+
+        return state == KazooState.LOST
 
     def _partitioner(self, identifier, members, partitions):
         # Ensure consistent order of partitions/members
@@ -375,3 +420,8 @@ class SetPartitioner(object):
         # Now return the partition list starting at our location and
         # skipping the other workers
         return all_partitions[i::len(workers)]
+
+    def _set_state(self, state):
+        self.state = state
+        self.state_id += 1
+        self.state_change_event.set()

+ 0 - 0
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/party.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/party.py


+ 53 - 21
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/queue.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/queue.py

@@ -1,14 +1,19 @@
 """Zookeeper based queue implementations.
 
 :Maintainer: None
-:Status: Unknown
+:Status: Possibly Buggy
 
-"""
+.. note::
+
+    This queue was reported to cause memory leaks over long running periods.
+    See: https://github.com/python-zk/kazoo/issues/175
 
+"""
 import uuid
+
 from kazoo.exceptions import NoNodeError, NodeExistsError
-from kazoo.retry import ForceRetryError
 from kazoo.protocol.states import EventType
+from kazoo.retry import ForceRetryError
 
 
 class BaseQueue(object):
@@ -81,24 +86,21 @@ class Queue(BaseQueue):
 
     def _inner_get(self):
         if not self._children:
-            self._children = self.client.retry(self.client.get_children, self.path)
+            self._children = self.client.retry(
+                self.client.get_children, self.path)
             self._children = sorted(self._children)
         if not self._children:
             return None
         name = self._children[0]
         try:
             data, stat = self.client.get(self.path + "/" + name)
+            self.client.delete(self.path + "/" + name)
         except NoNodeError:  # pragma: nocover
             # the first node has vanished in the meantime, try to
             # get another one
+            self._children = []
             raise ForceRetryError()
-        try:
-            self.client.delete(self.path + "/" + name)
-        except NoNodeError:  # pragma: nocover
-            # we were able to get the data but someone else has removed
-            # the node in the meantime. consider the item as processed
-            # by the other process
-            raise ForceRetryError()
+
         self._children.pop(0)
         return data
 
@@ -223,7 +225,7 @@ class LockingQueue(BaseQueue):
         :rtype: bytes
         """
         self._ensure_paths()
-        if not self.processing_element is None:
+        if self.processing_element is not None:
             return self.processing_element[1]
         else:
             return self._inner_get(timeout)
@@ -248,7 +250,7 @@ class LockingQueue(BaseQueue):
         :returns: True if element was removed successfully, False otherwise.
         :rtype: bool
         """
-        if not self.processing_element is None and self.holds_lock:
+        if self.processing_element is not None and self.holds_lock():
             id_, value = self.processing_element
             with self.client.transaction() as transaction:
                 transaction.delete("{path}/{id}".format(
@@ -262,6 +264,24 @@ class LockingQueue(BaseQueue):
         else:
             return False
 
+    def release(self):
+        """Removes the lock from currently processed item without consuming it.
+
+        :returns: True if the lock was removed successfully, False otherwise.
+        :rtype: bool
+
+        """
+        if self.processing_element is not None and self.holds_lock():
+            id_, value = self.processing_element
+            with self.client.transaction() as transaction:
+                transaction.delete("{path}/{id}".format(
+                    path=self._lock_path,
+                    id=id_))
+            self.processing_element = None
+            return True
+        else:
+            return False
+
     def _inner_get(self, timeout):
         flag = self.client.handler.event_object()
         lock = self.client.handler.lock_object()
@@ -269,21 +289,23 @@ class LockingQueue(BaseQueue):
         value = []
 
         def check_for_updates(event):
-            if not event is None and event.type != EventType.CHILD:
+            if event is not None and event.type != EventType.CHILD:
                 return
             with lock:
                 if canceled or flag.isSet():
                     return
-                values = self.client.retry(self.client.get_children,
+                values = self.client.retry(
+                    self.client.get_children,
                     self._entries_path,
                     check_for_updates)
-                taken = self.client.retry(self.client.get_children,
+                taken = self.client.retry(
+                    self.client.get_children,
                     self._lock_path,
                     check_for_updates)
                 available = self._filter_locked(values, taken)
                 if len(available) > 0:
                     ret = self._take(available[0])
-                    if not ret is None:
+                    if ret is not None:
                         # By this time, no one took the task
                         value.append(ret)
                         flag.set()
@@ -303,7 +325,7 @@ class LockingQueue(BaseQueue):
         taken = set(taken)
         available = sorted(values)
         return (available if len(taken) == 0 else
-            [x for x in available if x not in taken])
+                [x for x in available if x not in taken])
 
     def _take(self, id_):
         try:
@@ -313,9 +335,19 @@ class LockingQueue(BaseQueue):
                     id=id_),
                 self.id,
                 ephemeral=True)
-            value, stat = self.client.retry(self.client.get,
+        except NodeExistsError:
+            # Item is already locked
+            return None
+
+        try:
+            value, stat = self.client.retry(
+                self.client.get,
                 "{path}/{id}".format(path=self._entries_path, id=id_))
-        except (NoNodeError, NodeExistsError):
-            # Item is already consumed or locked
+        except NoNodeError:
+            # Item is already consumed
+            self.client.delete(
+                "{path}/{id}".format(
+                    path=self._lock_path,
+                    id=id_))
             return None
         return (id_, value)

+ 21 - 10
desktop/core/ext-py/kazoo-2.0/kazoo/recipe/watchers.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/recipe/watchers.py

@@ -10,18 +10,19 @@
     will result in an exception being thrown.
 
 """
+from functools import partial, wraps
 import logging
 import time
 import warnings
-from functools import partial, wraps
 
-from kazoo.retry import KazooRetry
 from kazoo.exceptions import (
     ConnectionClosedError,
     NoNodeError,
     KazooException
 )
 from kazoo.protocol.states import KazooState
+from kazoo.retry import KazooRetry
+
 
 log = logging.getLogger(__name__)
 
@@ -110,7 +111,7 @@ class DataWatch(object):
         self._run_lock = client.handler.lock_object()
         self._version = None
         self._retry = KazooRetry(max_tries=None,
-            sleep_func=client.handler.sleep_func)
+                                 sleep_func=client.handler.sleep_func)
         self._include_event = None
         self._ever_called = False
         self._used = False
@@ -163,6 +164,7 @@ class DataWatch(object):
                 result = self._func(data, stat)
             if result is False:
                 self._stopped = True
+                self._func = None
                 self._client.remove_listener(self._session_watcher)
         except Exception as exc:
             log.exception(exc)
@@ -315,8 +317,13 @@ class ChildrenWatch(object):
             if self._stopped:
                 return
 
-            children = self._client.retry(self._client.get_children,
-                                          self._path, self._watcher)
+            try:
+                children = self._client.retry(self._client.get_children,
+                                              self._path, self._watcher)
+            except NoNodeError:
+                self._stopped = True
+                return
+
             if not self._watch_established:
                 self._watch_established = True
 
@@ -333,18 +340,22 @@ class ChildrenWatch(object):
                     result = self._func(children)
                 if result is False:
                     self._stopped = True
+                    self._func = None
+                    if self._allow_session_lost:
+                        self._client.remove_listener(self._session_watcher)
             except Exception as exc:
                 log.exception(exc)
                 raise
 
     def _watcher(self, event):
-        self._get_children(event)
+        if event.type != "NONE":
+            self._get_children(event)
 
     def _session_watcher(self, state):
         if state in (KazooState.LOST, KazooState.SUSPENDED):
             self._watch_established = False
-        elif state == KazooState.CONNECTED and \
-             not self._watch_established and not self._stopped:
+        elif (state == KazooState.CONNECTED and
+              not self._watch_established and not self._stopped):
             self._client.handler.spawn(self._get_children)
 
 
@@ -414,6 +425,6 @@ class PatientChildrenWatch(object):
         except Exception as exc:
             self.asy.set_exception(exc)
 
-    def _children_watcher(self, async, event):
+    def _children_watcher(self, async_result, event):
         self.children_changed.set()
-        async.set(time.time())
+        async_result.set(time.time())

+ 24 - 20
desktop/core/ext-py/kazoo-2.0/kazoo/retry.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/retry.py

@@ -10,6 +10,7 @@ from kazoo.exceptions import (
     SessionExpiredError,
 )
 
+
 log = logging.getLogger(__name__)
 
 
@@ -41,21 +42,22 @@ class KazooRetry(object):
         SessionExpiredError,
     )
 
-    def __init__(self, max_tries=1, delay=0.1, backoff=2, max_jitter=0.8,
-                 max_delay=3600, ignore_expire=True, sleep_func=time.sleep,
+    def __init__(self, max_tries=1, delay=0.1, backoff=2, max_jitter=0.4,
+                 max_delay=60.0, ignore_expire=True, sleep_func=time.sleep,
                  deadline=None, interrupt=None):
         """Create a :class:`KazooRetry` instance for retrying function
-        calls
+        calls.
 
         :param max_tries: How many times to retry the command. -1 means
                           infinite tries.
         :param delay: Initial delay between retry attempts.
         :param backoff: Backoff multiplier between retry attempts.
                         Defaults to 2 for exponential backoff.
-        :param max_jitter: Additional max jitter period to wait between
-                           retry attempts to avoid slamming the server.
+        :param max_jitter: Percentage of jitter to apply to each retry's delay
+                           to ensure all clients to do not hammer the server
+                           at the same time. Between 0.0 and 1.0.
         :param max_delay: Maximum delay in seconds, regardless of other
-                          backoff settings. Defaults to one hour.
+                          backoff settings. Defaults to one minute.
         :param ignore_expire:
             Whether a session expiration should be ignored and treated
             as a retry-able command.
@@ -69,7 +71,8 @@ class KazooRetry(object):
         self.max_tries = max_tries
         self.delay = delay
         self.backoff = backoff
-        self.max_jitter = int(max_jitter * 100)
+        # Ensure max_jitter is in (0, 1)
+        self.max_jitter = max(min(max_jitter, 1.0), 0.0)
         self.max_delay = float(max_delay)
         self._attempts = 0
         self._cur_delay = delay
@@ -92,7 +95,7 @@ class KazooRetry(object):
         obj = KazooRetry(max_tries=self.max_tries,
                          delay=self.delay,
                          backoff=self.backoff,
-                         max_jitter=self.max_jitter / 100.0,
+                         max_jitter=self.max_jitter,
                          max_delay=self.max_delay,
                          sleep_func=self.sleep_func,
                          deadline=self.deadline,
@@ -128,23 +131,24 @@ class KazooRetry(object):
                 if self._attempts == self.max_tries:
                     raise RetryFailedError("Too many retry attempts")
                 self._attempts += 1
-                sleeptime = self._cur_delay + (random.randint(0, self.max_jitter) / 100.0)
+                jitter = random.uniform(1.0-self.max_jitter,
+                                        1.0+self.max_jitter)
+                sleeptime = self._cur_delay * jitter
 
-                if self._cur_stoptime is not None and time.time() + sleeptime >= self._cur_stoptime:
+                if self._cur_stoptime is not None and \
+                   time.time() + sleeptime >= self._cur_stoptime:
                     raise RetryFailedError("Exceeded retry deadline")
 
                 if self.interrupt:
-                    while sleeptime > 0:
-                        # Break the time period down and sleep for no longer than
-                        # 0.1 before calling the interrupt
-                        if sleeptime < 0.1:
-                            self.sleep_func(sleeptime)
-                            sleeptime -= sleeptime
-                        else:
-                            self.sleep_func(0.1)
-                            sleeptime -= 0.1
+                    remain_time = sleeptime
+                    while remain_time > 0:
+                        # Break the time period down and sleep for no
+                        # longer than 0.1 before calling the interrupt
+                        self.sleep_func(min(0.1, remain_time))
+                        remain_time -= 0.1
                         if self.interrupt():
                             raise InterruptedError()
                 else:
                     self.sleep_func(sleeptime)
-                self._cur_delay = min(self._cur_delay * self.backoff, self.max_delay)
+                self._cur_delay = min(sleeptime * self.backoff,
+                                      self.max_delay)

+ 12 - 3
desktop/core/ext-py/kazoo-2.0/kazoo/security.py → desktop/core/ext-py/kazoo-2.8.0/kazoo/security.py

@@ -15,7 +15,6 @@ class ACL(namedtuple('ACL', 'perms id')):
     a :class:`Permissions` setting. For convenience,
     :meth:`make_digest_acl` should be used to create an ACL object with
     the desired scheme, id, and permissions.
-
     """
     @property
     def acl_list(self):
@@ -60,7 +59,17 @@ READ_ACL_UNSAFE = [ACL(Permissions.READ, ANYONE_ID_UNSAFE)]
 
 
 def make_digest_acl_credential(username, password):
-    """Create a SHA1 digest credential"""
+    """Create a SHA1 digest credential.
+
+    .. note::
+
+        This function uses UTF-8 to encode non-ASCII codepoints,
+        whereas ZooKeeper uses the "default locale" for decoding.  It
+        may be a good idea to start the JVM with `-Dfile.encoding=UTF-8`
+        in non-UTF-8 locales.
+        See: https://github.com/python-zk/kazoo/pull/584
+
+    """
     credential = username.encode('utf-8') + b":" + password.encode('utf-8')
     cred_hash = b64encode(hashlib.sha1(credential).digest()).strip()
     return username + ":" + cred_hash.decode('utf-8')
@@ -135,4 +144,4 @@ def make_digest_acl(username, password, read=False, write=False,
     """
     cred = make_digest_acl_credential(username, password)
     return make_acl("digest", cred, read=read, write=write, create=create,
-        delete=delete, admin=admin, all=all)
+                    delete=delete, admin=admin, all=all)

+ 4 - 0
desktop/core/ext-py/kazoo-2.8.0/kazoo/testing/__init__.py

@@ -0,0 +1,4 @@
+from kazoo.testing.harness import KazooTestCase, KazooTestHarness
+
+
+__all__ = ('KazooTestHarness', 'KazooTestCase', )

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů