3 from .
import __version__
9 """General SteadyDB error."""
13 """Database cursor is invalid."""
17 creator, maxusage=None, setsession=None,
18 failures=None, ping=1, closeable=True, *args, **kwargs):
19 """A tough version of the connection constructor of a DB-API 2 module.
21 creator: either an arbitrary function returning new DB-API 2 compliant
22 connection objects or a DB-API 2 compliant database module
23 maxusage: maximum usage limit for the underlying DB-API 2 connection
24 (number of database operations, 0 or None means unlimited usage)
25 callproc(), execute() and executemany() count as one operation.
26 When the limit is reached, the connection is automatically reset.
27 setsession: an optional list of SQL commands that may serve to prepare
28 the session, e.g. ["set datestyle to german", "set time zone mez"]
29 failures: an optional exception class or a tuple of exception classes
30 for which the failover mechanism shall be applied, if the default
31 (OperationalError, InternalError) is not adequate
32 ping: determines when the connection should be checked with ping()
33 (0 = None = never, 1 = default = when _ping_check() is called,
34 2 = whenever a cursor is created, 4 = when a query is executed,
35 7 = always, and all other bit combinations of these values)
36 closeable: if this is set to false, then closing the connection will
37 be silently ignored, but by default the connection can be closed
38 args, kwargs: the parameters that shall be passed to the creator
39 function or the connection constructor of the DB-API 2 module
41 return SteadyDBConnection(
42 creator, maxusage, setsession,
43 failures, ping, closeable, *args, **kwargs)
47 """A "tough" version of DB-API 2 connections."""
52 self, creator, maxusage=None, setsession=None,
53 failures=None, ping=1, closeable=True, *args, **kwargs):
54 """Create a "tough" DB-API 2 connection."""
62 except AttributeError:
66 self.
_dbapi = creator.dbapi
67 except AttributeError:
69 self.
_dbapi = sys.modules[creator.__module__]
70 if self.
_dbapi.connect != creator:
72 except (AttributeError, KeyError):
76 except AttributeError:
79 except AttributeError:
82 raise TypeError(
"%r is not a connection provider." % (creator,))
85 if not isinstance(maxusage, baseint):
86 raise TypeError(
"'maxusage' must be an integer value.")
89 if failures
is not None and not isinstance(
90 failures, tuple)
and not issubclass(failures, Exception):
91 raise TypeError(
"'failures' must be a tuple of exceptions.")
93 self.
_ping = ping
if isinstance(ping, int)
else 0
95 self._args, self.
_kwargs = args, kwargs
99 """Enter the runtime context for the connection object."""
103 """Exit the runtime context for the connection object.
105 This does not close the connection, but it ends a transaction.
107 if exc[0]
is None and exc[1]
is None and exc[2]
is None:
113 """Create a new connection using the creator function."""
119 except AttributeError:
123 except AttributeError:
127 self.
_dbapi = sys.modules[mod]
128 if not callable(self.
_dbapi.connect):
130 except (AttributeError, KeyError):
141 mod = con.OperationalError.__module__
142 except AttributeError:
146 self.
_dbapi = sys.modules[mod]
147 if not callable(self.
_dbapi.connect):
149 except (AttributeError, KeyError):
163 except AttributeError:
166 except AttributeError:
171 self.
_dbapi.OperationalError,
172 self.
_dbapi.InternalError)
173 except AttributeError:
178 except AttributeError:
181 con.OperationalError, con.InternalError)
182 except AttributeError:
183 raise AttributeError(
184 "Could not determine failure exceptions"
185 " (please set failures or creator.dbapi).")
191 except Exception
as error:
202 """Execute the SQL commands for session preparation."""
206 cursor = con.cursor()
212 """Store a database connection for subsequent use."""
219 """Close the tough connection.
221 You can always close a tough connection with this method
222 and it will not complain if you close it more than once.
233 """Reset a tough connection.
235 Rollback if forced or the connection was in a transaction.
244 """Check whether the connection is still alive using ping().
246 If the the underlying connection is not active and the ping
247 parameter is set accordingly, the connection will be recreated
248 unless the connection is currently inside a transaction.
250 if ping & self.
_ping:
256 except (AttributeError, IndexError, TypeError, ValueError):
279 """Return the underlying DB-API 2 module of the connection."""
281 raise AttributeError(
282 "Could not determine DB-API 2 module"
283 " (please set creator.dbapi).")
287 """Return the thread safety level of the connection."""
290 raise AttributeError(
291 "Could not determine threadsafety"
292 " (please set creator.dbapi or creator.threadsafety).")
297 """Close the tough connection.
299 You are allowed to close a tough connection by default
300 and it will not complain if you close it more than once.
302 You can disallow closing connections by setting
303 the closeable parameter to something false. In this case,
304 closing tough connections will be silently ignored.
312 """Indicate the beginning of a transaction.
314 During a transaction, connections won't be transparently
315 replaced, and all errors will be raised to the application.
317 If the underlying driver supports this method, it will be called
318 with the given parameters (e.g. for distributed transactions).
322 begin = self.
_con.begin
323 except AttributeError:
326 begin(*args, **kwargs)
329 """Commit any pending transaction."""
344 """Rollback pending transaction."""
359 """Cancel a long-running transaction.
361 If the underlying driver supports this method, it will be called.
365 cancel = self.
_con.cancel
366 except AttributeError:
371 def ping(self, *args, **kwargs):
372 """Ping connection."""
373 return self.
_con.
ping(*args, **kwargs)
376 """A "tough" version of the method cursor()."""
385 and not transaction):
395 cursor = con.cursor(*args, **kwargs)
414 """Return a new Cursor Object using the connection."""
418 """Delete the steady connection."""
426 """A "tough" version of DB-API 2 cursors."""
429 """Create a "tough" DB-API 2 cursor."""
438 self.
_cursor = con._cursor(*args, **kwargs)
439 except AttributeError:
440 raise TypeError(
"%r is not a SteadyDBConnection." % (con,))
444 """Enter the runtime context for the cursor object."""
448 """Exit the runtime context for the cursor object."""
452 """Store input sizes in case cursor needs to be reopened."""
456 """Store output sizes in case cursor needs to be reopened."""
460 """Clear stored input and output sizes."""
465 """Set stored input and output sizes for cursor execution."""
472 cursor.setoutputsize(size)
474 cursor.setoutputsize(size, column)
477 """Close the tough cursor.
479 It will not complain if you close it more than once.
489 """Return a "tough" version of the given cursor method."""
491 def tough_method(*args, **kwargs):
492 execute = name.startswith(
'execute')
494 transaction = con._transaction
499 if (con._maxusage
and con._usage >= con._maxusage
500 and not transaction):
504 method = getattr(self.
_cursor, name)
505 result = method(*args, **kwargs)
508 except con._failures
as error:
511 cursor2 = con._cursor(
519 method = getattr(cursor2, name)
520 result = method(*args, **kwargs)
540 cursor2 = con2.cursor(
555 method2 = getattr(cursor2, name)
556 result = method2(*args, **kwargs)
559 except error.__class__:
562 except Exception
as error:
594 """Inherit methods and attributes of underlying cursor."""
596 if name.startswith((
'execute',
'call')):
600 return getattr(self.
_cursor, name)
605 """Delete the steady cursor."""