No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sqlwrapper.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import logging as logger
  4. import sqlalchemy as sqla
  5. from django.conf import settings
  6. #Logger config
  7. logger.getLogger().setLevel('DEBUG')
  8. #To be able to use dango confs
  9. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Lodel.settings")
  10. class SqlWrapper(object):
  11. """ A wrapper class to sqlalchemy
  12. Usefull to provide a standart API
  13. """
  14. ##Read Engine
  15. rengine = None
  16. ##Write Engine
  17. wengine = None
  18. ##Read connection
  19. rconn = None
  20. ##Write connection
  21. wconn = None
  22. ##Configuration dict alias for class access
  23. config=settings.LODEL2SQLWRAPPER
  24. ##SqlAlchemy logging
  25. sqla_logging = False
  26. def __init__(self, alchemy_logs=None):
  27. """ Instanciate a new SqlWrapper
  28. @param alchemy_logs bool: If true activate sqlalchemy logger
  29. """
  30. if (alchemy_logs != None and \
  31. bool(alchemy_logs) != self.__class__.sqla_logging):
  32. #logging config changed for sqlalchemy
  33. self.__class__.restart()
  34. if not self.__class__.started():
  35. self.__class__.start()
  36. pass
  37. @classmethod
  38. def table(c, o):
  39. """ Return a SqlAlchemy Table object
  40. @param o str: Table name
  41. """
  42. if isinstance(o, str):
  43. return sqla.Table(o, sqla.MetaData())
  44. return None
  45. @classmethod
  46. def connect(c,read = None):
  47. if read == None:
  48. return c.connect(True) and c.coonect(False)
  49. elif read:
  50. c.rconn = c.rengine.connect()
  51. else:
  52. c.wconn = c.wengine.connect()
  53. return True #TODO attention c'est pas checké...
  54. @classmethod
  55. def conn(c, read=True):
  56. if read:
  57. res = c.rconn
  58. else:
  59. res = c.wconn
  60. if res == None:
  61. if not c.connect(read):
  62. raise RuntimeError('Unable to connect to Db')
  63. return self.conn(read)
  64. return c.rconn
  65. @classmethod
  66. def rc(c): return c.conn(True)
  67. @classmethod
  68. def wc(c): return c.conn(False)
  69. @classmethod
  70. def start(c, sqlalogging = None):
  71. """ Load engines
  72. Open connections to databases
  73. @param sqlalogging bool: overwrite class parameter about sqlalchemy logging
  74. @return False if already started
  75. """
  76. c.checkConf()
  77. if c.started():
  78. logger.warning('Starting SqlWrapper but it is allready \
  79. started')
  80. return False
  81. c.rengine = c._getEngine(read=True, sqlaloggingi=None)
  82. c.wengine = c._getEngine(read=False, sqlalogging=None)
  83. return True
  84. @classmethod
  85. def stop(c): c.rengine = c.wengine = None; pass
  86. @classmethod
  87. def restart(c): c.stop(); c.start(); pass
  88. @classmethod
  89. def started(c): return (c.rengine != None and c.rengine != None)
  90. @classmethod
  91. def _sqllog(c,sqlalogging = None):
  92. return bool(sqlalogging) if sqlalogging != None else c.sqlalogging
  93. @classmethod
  94. def _getEngine(c, read=True, sqlalogging = None):
  95. """ Return a sqlalchemy engine
  96. @param read bool: If True return the read engine, else
  97. return the write one
  98. @return a sqlachemy engine instance
  99. @todo Put the check on db config in SqlWrapper.checkConf()
  100. """
  101. #Loading confs
  102. connconf = 'dbread' if read else 'dbwrite'
  103. dbconf = connconf if connconf in c.config['db'] else 'default'
  104. if dbconf not in c.config['db']: #This check should not be here
  105. raise NameError('Configuration error no db "'+dbconf+'" in \
  106. configuration files')
  107. cfg = c.config['db'][dbconf] #Database config
  108. edata = c.config['engines'][cfg['ENGINE']] #engine infos
  109. conn_str = cfg['ENGINE']+'+'+edata['driver']+'://'
  110. if cfg['ENGINE'] == 'sqlite':
  111. #Sqlite connection string
  112. conn_str = '%s+%s:///%s'%( cfg['ENGINE'],
  113. edata['driver'],
  114. cfg['NAME'])
  115. else:
  116. #Mysql and Postgres connection string
  117. user = cfg['USER']
  118. user += (':'+cfg['PASSWORD'] if 'PASSWORD' in cfg else '')
  119. if 'HOST' not in cfg:
  120. logger.info('Not HOST in configuration, using \
  121. localhost')
  122. host = 'localhost'
  123. else:
  124. host = cfg['HOST']
  125. host += (':'+cfg['PORT'] if 'PORT' in cfg else '')
  126. conn_str = '%s+%s://'%(cfg['ENGINE'], edata['driver'])
  127. conn_str += '%s@%s/%s'%(user,host,cfg['NAME'])
  128. return sqla.create_engine( conn_str, encoding=edata['encoding'],
  129. echo=c._sqllog(sqlalogging))
  130. @classmethod
  131. def checkConf(c):
  132. """ Class method that check the configuration
  133. Configuration looks like
  134. - db (mandatory)
  135. - ENGINE (mandatory)
  136. - NAME (mandatory)
  137. - USER
  138. - PASSWORD
  139. - engines (mandatory)
  140. - driver (mandatory)
  141. - encoding (mandatory)
  142. - dbread (mandatory if no default db)
  143. - dbwrite (mandatory if no default db)
  144. """
  145. return True #TODO desactivate because buggy
  146. err = []
  147. if 'db' not in c.config:
  148. err.append('Missing "db" in configuration')
  149. else:
  150. if 'default' not in c.config['db']:
  151. if 'dbread' not in c.config:
  152. err.append('Missing "dbread" in configuration and\
  153. no "default" db declared')
  154. if 'dbwrite' not in c.config:
  155. err.append('Missing "dbwrite" in configuration and\
  156. no "default" db declared')
  157. for db in c.config['db']:
  158. if 'ENGINE' not in db:
  159. err.append('Missing "ENGINE" in database "'+db+'"')
  160. else:
  161. if db['ENGINE'] != 'sqlite' and 'USER' not in db:
  162. err.append('Missing "USER" in database "\
  163. '+db+'"')
  164. if 'NAME' not in db:
  165. err.append('Missing "NAME" in database "'+db+'"')
  166. if len(c.config['engines']) == 0:
  167. err.append('Missing "engines" in configuration')
  168. for ename in c.config['engines']:
  169. engine = c.config['engines'][ename]
  170. if 'driver' not in engine:
  171. err.append('Missing "driver" in database engine "\
  172. '+ename+'"')
  173. if 'encoding' not in engine:
  174. err.append('Missing "encoding" in database engine "\
  175. '+ename+'"')
  176. if len(err)>0:
  177. err_str = ""
  178. for e in err:
  179. err_str += e+"\n"
  180. raise NameError('Configuration errors in LODEL2SQLWRAPPER\
  181. :'+err_str)
  182. @property
  183. def cfg(self):
  184. """ Get the dict of options for the wrapper
  185. Its an alias to the classes property SqlWrapper.config
  186. @return a dict containing the Db settings"""
  187. return self.__class__.config