# Path: zoonado/exc.py
# class ZKError(Exception):
# class ConnectError(ZKError):
# class NoServersError(ZKError):
# class SessionLost(ZKError):
# class InvalidClientState(ZKError):
# class TimeoutError(ZKError):
# class FailedRetry(ZKError):
# class ResponseErrorMeta(type):
# class ResponseError(ZKError):
# class UnknownError(ResponseError):
# class RolledBack(ResponseError):
# class ZKSystemError(ResponseError):
# class RuntimeInconsistency(ResponseError):
# class DataInconsistency(ResponseError):
# class ConnectionLoss(ResponseError):
# class MarshallingError(ResponseError):
# class Unimplemented(ResponseError):
# class OperationTimeout(ResponseError):
# class BadArguments(ResponseError):
# class UnknownSession(ResponseError):
# class NewConfigNoQuorum(ResponseError):
# class ReconfigInProcess(ResponseError):
# class APIError(ResponseError):
# class NoNode(ResponseError):
# class NoAuth(ResponseError):
# class BadVersion(ResponseError):
# class NoChildrenForEphemerals(ResponseError):
# class NodeExists(ResponseError):
# class NotEmpty(ResponseError):
# class SessionExpired(ResponseError):
# class InvalidCallback(ResponseError):
# class InvalidACL(ResponseError):
# class AuthFailed(ResponseError):
# class SessionMoved(ResponseError):
# class NotReadOnly(ResponseError):
# class EphemeralOnLocalSession(ResponseError):
# class NoWatcher(ResponseError):
#     def __init__(self, host, port, server_id=None):
#     def __str__(self):
#     def __new__(cls, name, bases, attrs):
#     def __str__(self):
#     def __init__(self, error_code):
#     def __str__(self):
# def get_response_error(error_code):
# 
# Path: zoonado/states.py
# class States(object):
# class SessionStateMachine(object):
#     CONNECTED = "connected"
#     SUSPENDED = "suspended"
#     READ_ONLY = "read_only"
#     LOST = "lost"
#     def __init__(self):
#     def transition_to(self, state):
#     def wait_for(self, *states):
#     def __eq__(self, state):
#     def __ne__(self, state):
# 
# Path: zoonado/recipes/sequential.py
# class SequentialRecipe(Recipe):
# 
#     def __init__(self, base_path):
#         super(SequentialRecipe, self).__init__(base_path)
#         self.guid = uuid.uuid4().hex
# 
#         self.owned_paths = {}
# 
#     def sequence_number(self, sibling):
#         return int(sibling[-10:])
# 
#     def determine_znode_label(self, sibling):
#         return sibling.rsplit("-", 2)[0]
# 
#     def sibling_path(self, path):
#         return "/".join([self.base_path, path])
# 
#     @gen.coroutine
#     def create_unique_znode(self, znode_label, data=None):
#         path = self.sibling_path(znode_label + "-" + self.guid + "-")
# 
#         try:
#             created_path = yield self.client.create(
#                 path, data=data, ephemeral=True, sequential=True
#             )
#         except exc.NoNode:
#             yield self.ensure_path()
#             created_path = yield self.client.create(
#                 path, data=data, ephemeral=True, sequential=True
#             )
# 
#         self.owned_paths[znode_label] = created_path
# 
#     @gen.coroutine
#     def delete_unique_znode(self, znode_label):
#         try:
#             yield self.client.delete(self.owned_paths[znode_label])
#         except exc.NoNode:
#             pass
# 
#     @gen.coroutine
#     def analyze_siblings(self):
#         siblings = yield self.client.get_children(self.base_path)
#         siblings = [name for name in siblings if sequential_re.match(name)]
# 
#         siblings.sort(key=self.sequence_number)
# 
#         owned_positions = {}
# 
#         for index, path in enumerate(siblings):
#             if self.guid in path:
#                 owned_positions[self.determine_znode_label(path)] = index
# 
#         raise gen.Return((owned_positions, siblings))
# 
#     @gen.coroutine
#     def wait_on_sibling(self, sibling, time_limit=None):
#         log.debug("Waiting on sibling %s", sibling)
# 
#         path = self.sibling_path(sibling)
# 
#         unblocked = self.client.wait_for_event(WatchEvent.DELETED, path)
#         if time_limit:
#             unblocked = gen.with_timeout(time_limit, unblocked)
# 
#         exists = yield self.client.exists(path=path, watch=True)
#         if not exists:
#             unblocked.set_result(None)
# 
#         try:
#             yield unblocked
#         except gen.TimeoutError:
#             raise exc.TimeoutError


import contextlib
import logging
import time
from tornado import gen, ioloop
from zoonado import exc, states
from .sequential import SequentialRecipe

        @gen.coroutine
        def handle_session_loss():
            yield self.client.session.state.wait_for(states.States.LOST)
            if not state["acquired"]:
                return

            log.warn(
                "Session expired at some point, lock %s no longer acquired.",
                self
            )
            state["acquired"] = False

        ioloop.IOLoop.current().add_callback(handle_session_loss)

        @gen.coroutine
        def on_exit():
            state["acquired"] = False
            yield self.delete_unique_znode(znode_label)

        @contextlib.contextmanager
        def context_manager():
            try:
                yield still_acquired
            finally:
                ioloop.IOLoop.current().add_callback(on_exit)

        return context_manager()



# Path: zoonado/exc.py
# class ZKError(Exception):
# class ConnectError(ZKError):
# class NoServersError(ZKError):
# class SessionLost(ZKError):
# class InvalidClientState(ZKError):
# class TimeoutError(ZKError):
# class FailedRetry(ZKError):
# class ResponseErrorMeta(type):
# class ResponseError(ZKError):
# class UnknownError(ResponseError):
# class RolledBack(ResponseError):
# class ZKSystemError(ResponseError):
# class RuntimeInconsistency(ResponseError):
# class DataInconsistency(ResponseError):
# class ConnectionLoss(ResponseError):
# class MarshallingError(ResponseError):
# class Unimplemented(ResponseError):
# class OperationTimeout(ResponseError):
# class BadArguments(ResponseError):
# class UnknownSession(ResponseError):
# class NewConfigNoQuorum(ResponseError):
# class ReconfigInProcess(ResponseError):
# class APIError(ResponseError):
# class NoNode(ResponseError):
# class NoAuth(ResponseError):
# class BadVersion(ResponseError):
# class NoChildrenForEphemerals(ResponseError):
# class NodeExists(ResponseError):
# class NotEmpty(ResponseError):
# class SessionExpired(ResponseError):
# class InvalidCallback(ResponseError):
# class InvalidACL(ResponseError):
# class AuthFailed(ResponseError):
# class SessionMoved(ResponseError):
# class NotReadOnly(ResponseError):
# class EphemeralOnLocalSession(ResponseError):
# class NoWatcher(ResponseError):
#     def __init__(self, host, port, server_id=None):
#     def __str__(self):
#     def __new__(cls, name, bases, attrs):
#     def __str__(self):
#     def __init__(self, error_code):
#     def __str__(self):
# def get_response_error(error_code):
# 
# Path: zoonado/states.py
# class States(object):
# class SessionStateMachine(object):
#     CONNECTED = "connected"
#     SUSPENDED = "suspended"
#     READ_ONLY = "read_only"
#     LOST = "lost"
#     def __init__(self):
#     def transition_to(self, state):
#     def wait_for(self, *states):
#     def __eq__(self, state):
#     def __ne__(self, state):
# 
# Path: zoonado/recipes/sequential.py
# class SequentialRecipe(Recipe):
# 
#     def __init__(self, base_path):
#         super(SequentialRecipe, self).__init__(base_path)
#         self.guid = uuid.uuid4().hex
# 
#         self.owned_paths = {}
# 
#     def sequence_number(self, sibling):
#         return int(sibling[-10:])
# 
#     def determine_znode_label(self, sibling):
#         return sibling.rsplit("-", 2)[0]
# 
#     def sibling_path(self, path):
#         return "/".join([self.base_path, path])
# 
#     @gen.coroutine
#     def create_unique_znode(self, znode_label, data=None):
#         path = self.sibling_path(znode_label + "-" + self.guid + "-")
# 
#         try:
#             created_path = yield self.client.create(
#                 path, data=data, ephemeral=True, sequential=True
#             )
#         except exc.NoNode:
#             yield self.ensure_path()
#             created_path = yield self.client.create(
#                 path, data=data, ephemeral=True, sequential=True
#             )
# 
#         self.owned_paths[znode_label] = created_path
# 
#     @gen.coroutine
#     def delete_unique_znode(self, znode_label):
#         try:
#             yield self.client.delete(self.owned_paths[znode_label])
#         except exc.NoNode:
#             pass
# 
#     @gen.coroutine
#     def analyze_siblings(self):
#         siblings = yield self.client.get_children(self.base_path)
#         siblings = [name for name in siblings if sequential_re.match(name)]
# 
#         siblings.sort(key=self.sequence_number)
# 
#         owned_positions = {}
# 
#         for index, path in enumerate(siblings):
#             if self.guid in path:
#                 owned_positions[self.determine_znode_label(path)] = index
# 
#         raise gen.Return((owned_positions, siblings))
# 
#     @gen.coroutine
#     def wait_on_sibling(self, sibling, time_limit=None):
#         log.debug("Waiting on sibling %s", sibling)
# 
#         path = self.sibling_path(sibling)
# 
#         unblocked = self.client.wait_for_event(WatchEvent.DELETED, path)
#         if time_limit:
#             unblocked = gen.with_timeout(time_limit, unblocked)
# 
#         exists = yield self.client.exists(path=path, watch=True)
#         if not exists:
#             unblocked.set_result(None)
# 
#         try:
#             yield unblocked
#         except gen.TimeoutError:
#             raise exc.TimeoutError


# Path: zoonado/recipes/base_lock.py
import contextlib
import logging
import time
from tornado import gen, ioloop
from zoonado import exc, states
from .sequential import SequentialRecipe


        @gen.coroutine
        def handle_session_loss():
            yield self.client.session.state.wait_for(states.States.LOST)
            if not state["acquired"]:
                return

            log.warn(
                "Session expired at some point, lock %s no longer acquired.",
                self
            )
            state["acquired"] = False

        ioloop.IOLoop.current().add_callback(handle_session_loss)

        @gen.coroutine
        def on_exit():
            state["acquired"] = False
            yield self.delete_unique_znode(znode_label)

        @contextlib.contextmanager
        def context_manager():
            try:
                yield still_acquired
            finally:
                ioloop.IOLoop.current().add_callback(on_exit)

        return context_manager()



class LockLostError(exc.ZKError):