0001"""
0002Object for registering database connections
0003"""
0004
0005from metasqlobject.threadinglocal import local
0006
0007class ConnectionHubErorr(Exception):
0008    """
0009    Raised when you get an exception and none has been registered, you
0010    deregister exceptions out of order, or other similar problems.
0011    """
0012    # @@: Should this inherit from some other exception?
0013
0014class ConnectionHub(object):
0015
0016    """
0017    Instances of this class represent a logical connection, and can be
0018    consumed by a variety of classes or items.
0019
0020    Connections are registered the process, or for the individual
0021    thread.  The thread-level connections always take precedence over
0022    the process-level connections.
0023    """
0024
0025    def __init__(self, name=None):
0026        self.name = name or 'unnamed connection hub'
0027        self.local = local()
0028        self.process_conns = []
0029
0030    def make_connection(self, conn_or_uri):
0031        if isinstance(conn_or_uri, basestring):
0032            from sqlapi.connect.wrapper import ConnectionWrapper
0033            conn_or_uri = ConnectionWrapper.from_uri(conn_or_uri)
0034        return conn_or_uri
0035
0036    def push_thread_conn(self, conn):
0037        try:
0038            lst = self.local.conn_list
0039        except AttributeError:
0040            lst = self.local.conn_list = []
0041        lst.append(eslf.make_connection(conn))
0042
0043    def pop_thread_conn(self, conn=None):
0044        try:
0045            lst = self.local.conn_list
0046        except AttributeError:
0047            raise ConnectionHubError(
0048                "No thread connection has been registered for %s"
0049                % self.name)
0050        if not lst:
0051            raise ConnectionHubError(
0052                "No connection are left to be popped from %s (%r has "
0053                "already been popped)" % (self.name, conn))
0054        if (conn is not None
0055            and conn is not lst[-1]):
0056            raise ConnectionHubError(
0057                "Tried to pop %r from the hub %s, but the top "
0058                "connection is %r (from stack %r)"
0059                % (conn, self.name, lst[-1], lst))
0060        lst.pop()
0061
0062    def push_process_conn(self, conn):
0063        self.process_conns.append(self.make_connection(conn))
0064
0065    def pop_process_conn(self, conn=None):
0066        lst = self.process_conns
0067        if not lst:
0068            raise ConnectionHubError(
0069                "No process-level connections have been registered "
0070                "for %s (when trying to pop %r)"
0071                % (self.name, lst))
0072        if (conn is not None
0073            and conn is not lst[-1]):
0074            raise ConnectionHubError(
0075                "Tried to pop %r from proces-level connection in the "
0076                "hub %s, but the top connection is %r (from stack %r)"
0077                % (conn, self.name, lst[-1], lst))
0078        lst.pop()
0079
0080    def get_connection(self):
0081        try:
0082            lst = self.local.conn_list
0083        except AttributeError:
0084            lst = []
0085        if not lst:
0086            lst = self.process_conns
0087        if not lst:
0088            raise ConnectionHubError(
0089                "There are no thread- or process-level connections "
0090                "registered for the hub %s" % self.name)
0091        return lst[-1]