Advertisement
Guest User

Untitled

a guest
Mar 9th, 2016
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.85 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #encoding=utf-8
  3.  
  4. """
  5. A lightweight wrapper around mysql.connector based on torndb.
  6. """
  7.  
  8. from __future__ import absolute_import, division, with_statement
  9.  
  10. import logging
  11. import time
  12. from mysql import connector
  13.  
  14.  
  15. class Connection(object):
  16. """A lightweight wrapper around mysql.connector DB-API connections.
  17.  
  18. The main value we provide is wrapping rows in a dict/object so that
  19. columns can be accessed by name. Typical usage::
  20.  
  21. db = Connection("localhost", "mydatabase")
  22. for article in db.query("SELECT * FROM articles"):
  23. print article.title
  24. """
  25.  
  26. def __init__(self, database, host="127.0.0.1:3306", user=None, password=None,
  27. max_idle_time=7 * 3600, autocommit=True, **kwargs):
  28. self.host = host
  29. self.database = database
  30. self.max_idle_time = float(max_idle_time)
  31.  
  32. args = dict(database=database, autocommit=autocommit, **kwargs)
  33. if user is not None:
  34. args["user"] = user
  35. if password is not None:
  36. args["password"] = password
  37.  
  38. # We accept a path to a MySQL socket file or a host(:port) string
  39. if "/" in host:
  40. args["unix_socket"] = host
  41. else:
  42. self.socket = None
  43. pair = host.split(":")
  44. if len(pair) == 2:
  45. args["host"] = pair[0]
  46. args["port"] = int(pair[1])
  47. else:
  48. args["host"] = host
  49. args["port"] = 3306
  50.  
  51. self._db = None
  52. self._db_args = args
  53. self._last_use_time = time.time()
  54. try:
  55. self.reconnect()
  56. except Exception:
  57. logging.error("Cannot connect to MySQL on %s", self.host,
  58. exc_info=True)
  59.  
  60. @property
  61. def cursor(self):
  62. return self._cursor()
  63.  
  64. def close(self):
  65. """Closes this database connection."""
  66. if getattr(self, "_db", None) is not None:
  67. self._db.close()
  68. self._db = None
  69.  
  70. def reconnect(self):
  71. """Closes the existing database connection and re-opens it."""
  72. self.close()
  73. self._db = connector.connect(**self._db_args)
  74.  
  75. def iter(self, query, *parameters, **kwparameters):
  76. """Returns an iterator for the given query and parameters."""
  77. self._ensure_connected()
  78. cursor = self._cursor(buffered=True)
  79. try:
  80. self._execute(cursor, query, parameters, kwparameters)
  81. column_names = [d[0] for d in cursor.description]
  82. for row in cursor:
  83. yield Row(zip(column_names, row))
  84. finally:
  85. cursor.close()
  86.  
  87. def query(self, query, *parameters, **kwparameters):
  88. """Returns a row list for the given query and parameters."""
  89. cursor = self._cursor()
  90. try:
  91. self._execute(cursor, query, parameters, kwparameters)
  92. column_names = [d[0] for d in cursor.description]
  93. return [Row(zip(column_names, row)) for row in cursor]
  94. finally:
  95. cursor.close()
  96.  
  97. def get(self, query, *parameters, **kwparameters):
  98. """Returns the (singular) row returned by the given query.
  99.  
  100. If the query has no results, returns None. If it has
  101. more than one result, raises an exception.
  102. """
  103. rows = self.query(query, *parameters, **kwparameters)
  104. if not rows:
  105. return None
  106. elif len(rows) > 1:
  107. raise Exception("Multiple rows returned for Database.get() query")
  108. else:
  109. return rows[0]
  110.  
  111. # rowcount is a more reasonable default return value than lastrowid,
  112. # but for historical compatibility execute() must return lastrowid.
  113. def execute(self, query, *parameters, **kwparameters):
  114. """Executes the given query, returning the lastrowid from the query."""
  115. return self.execute_lastrowid(query, *parameters, **kwparameters)
  116.  
  117. def execute_lastrowid(self, query, *parameters, **kwparameters):
  118. """Executes the given query, returning the lastrowid from the query."""
  119. cursor = self._cursor()
  120. try:
  121. self._execute(cursor, query, parameters, kwparameters)
  122. return cursor.lastrowid
  123. finally:
  124. cursor.close()
  125.  
  126. def execute_rowcount(self, query, *parameters, **kwparameters):
  127. """Executes the given query, returning the rowcount from the query."""
  128. cursor = self._cursor()
  129. try:
  130. self._execute(cursor, query, parameters, kwparameters)
  131. return cursor.rowcount
  132. finally:
  133. cursor.close()
  134.  
  135. def executemany(self, query, parameters):
  136. """Executes the given query against all the given param sequences.
  137.  
  138. We return the lastrowid from the query.
  139. """
  140. return self.executemany_lastrowid(query, parameters)
  141.  
  142. def executemany_lastrowid(self, query, parameters):
  143. """Executes the given query against all the given param sequences.
  144.  
  145. We return the lastrowid from the query.
  146. """
  147. cursor = self._cursor()
  148. try:
  149. cursor.executemany(query, parameters)
  150. return cursor.lastrowid
  151. finally:
  152. cursor.close()
  153.  
  154. def executemany_rowcount(self, query, parameters):
  155. """Executes the given query against all the given param sequences.
  156.  
  157. We return the rowcount from the query.
  158. """
  159. cursor = self._cursor()
  160. try:
  161. cursor.executemany(query, parameters)
  162. return cursor.rowcount
  163. finally:
  164. cursor.close()
  165.  
  166. update = delete = execute_rowcount
  167. updatemany = executemany_rowcount
  168.  
  169. insert = execute_lastrowid
  170. insertmany = executemany_lastrowid
  171.  
  172. def _ensure_connected(self):
  173. # Mysql by default closes client connections that are idle for
  174. # 8 hours, but the client library does not report this fact until
  175. # you try to perform a query and it fails. Protect against this
  176. # case by preemptively closing and reopening the connection
  177. # if it has been idle for too long (7 hours by default).
  178. if (self._db is None or
  179. (time.time() - self._last_use_time > self.max_idle_time)):
  180. self.reconnect()
  181. self._last_use_time = time.time()
  182.  
  183. def _cursor(self, buffered=False):
  184. self._ensure_connected()
  185. return self._db.cursor(buffered=buffered)
  186.  
  187. def _execute(self, cursor, query, parameters, kwparameters):
  188. try:
  189. return cursor.execute(query, kwparameters or parameters)
  190. except connector.errors.OperationalError:
  191. logging.error("Error connecting to MySQL on %s", self.host)
  192. self.close()
  193. raise
  194.  
  195. def __del__(self):
  196. self.close()
  197.  
  198.  
  199. class Row(dict):
  200. """A dict that allows for object-like property access syntax."""
  201. def __getattr__(self, name):
  202. try:
  203. return self[name]
  204. except KeyError:
  205. raise AttributeError(name)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement