# engine/strategies.py# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>## This module is part of SQLAlchemy and is released under# the MIT License: http://www.opensource.org/licenses/mit-license.php"""Strategies for creating new instances of Engine types.These are semi-private implementation classes which provide theunderlying behavior for the "strategy" keyword argument available on:func:`~sqlalchemy.engine.create_engine`. Current available options are``plain``, ``threadlocal``, and ``mock``.New strategies can be added via new ``EngineStrategy`` classes."""fromoperatorimportattrgetterfromsqlalchemy.engineimportbase,threadlocal,urlfromsqlalchemyimportutil,exc,eventfromsqlalchemyimportpoolaspoollibstrategies={}classEngineStrategy(object):"""An adaptor that processes input arguments and produces an Engine. Provides a ``create`` method that receives input arguments and produces an instance of base.Engine or a subclass. """def__init__(self):strategies[self.name]=selfdefcreate(self,*args,**kwargs):"""Given arguments, returns a new Engine instance."""raiseNotImplementedError()classDefaultEngineStrategy(EngineStrategy):"""Base class for built-in strategies."""defcreate(self,name_or_url,**kwargs):# create url.URL objectu=url.make_url(name_or_url)dialect_cls=u.get_dialect()dialect_args={}# consume dialect arguments from kwargsforkinutil.get_cls_kwargs(dialect_cls):ifkinkwargs:dialect_args[k]=kwargs.pop(k)dbapi=kwargs.pop('module',None)ifdbapiisNone:dbapi_args={}forkinutil.get_func_kwargs(dialect_cls.dbapi):ifkinkwargs:dbapi_args[k]=kwargs.pop(k)dbapi=dialect_cls.dbapi(**dbapi_args)dialect_args['dbapi']=dbapi# create dialectdialect=dialect_cls(**dialect_args)# assemble connection arguments(cargs,cparams)=dialect.create_connect_args(u)cparams.update(kwargs.pop('connect_args',{}))# look for existing pool or createpool=kwargs.pop('pool',None)ifpoolisNone:defconnect():try:returndialect.connect(*cargs,**cparams)exceptException,e:invalidated=dialect.is_disconnect(e,None,None)# Py3K#raise exc.DBAPIError.instance(None, None,# e, dialect.dbapi.Error,# connection_invalidated=invalidated#) from e# Py2Kimportsysraiseexc.DBAPIError.instance(None,None,e,dialect.dbapi.Error,connection_invalidated=invalidated),None,sys.exc_info()[2]# end Py2Kcreator=kwargs.pop('creator',connect)poolclass=kwargs.pop('poolclass',None)ifpoolclassisNone:poolclass=dialect_cls.get_pool_class(u)pool_args={}# consume pool arguments from kwargs, translating a few of# the argumentstranslate={'logging_name':'pool_logging_name','echo':'echo_pool','timeout':'pool_timeout','recycle':'pool_recycle','events':'pool_events','use_threadlocal':'pool_threadlocal','reset_on_return':'pool_reset_on_return'}forkinutil.get_cls_kwargs(poolclass):tk=translate.get(k,k)iftkinkwargs:pool_args[k]=kwargs.pop(tk)pool=poolclass(creator,**pool_args)else:ifisinstance(pool,poollib._DBProxy):pool=pool.get_pool(*cargs,**cparams)else:pool=pool# create engine.engineclass=self.engine_clsengine_args={}forkinutil.get_cls_kwargs(engineclass):ifkinkwargs:engine_args[k]=kwargs.pop(k)_initialize=kwargs.pop('_initialize',True)# all kwargs should be consumedifkwargs:raiseTypeError("Invalid argument(s) %s sent to create_engine(), ""using configuration %s/%s/%s. Please check that the ""keyword arguments are appropriate for this combination ""of components."%(','.join("'%s'"%kforkinkwargs),dialect.__class__.__name__,pool.__class__.__name__,engineclass.__name__))engine=engineclass(pool,dialect,u,**engine_args)if_initialize:do_on_connect=dialect.on_connect()ifdo_on_connect:defon_connect(dbapi_connection,connection_record):conn=getattr(dbapi_connection,'_sqla_unwrap',dbapi_connection)ifconnisNone:returndo_on_connect(conn)event.listen(pool,'first_connect',on_connect)event.listen(pool,'connect',on_connect)deffirst_connect(dbapi_connection,connection_record):c=base.Connection(engine,connection=dbapi_connection)# TODO: removing this allows the on connect activities# to generate events. tests currently assume these aren't# sent. do we want users to get all the initial connect# activities as events ?c._has_events=Falsedialect.initialize(c)event.listen(pool,'first_connect',first_connect)returnengineclassPlainEngineStrategy(DefaultEngineStrategy):"""Strategy for configuring a regular Engine."""name='plain'engine_cls=base.EnginePlainEngineStrategy()classThreadLocalEngineStrategy(DefaultEngineStrategy):"""Strategy for configuring an Engine with threadlocal behavior."""name='threadlocal'engine_cls=threadlocal.TLEngineThreadLocalEngineStrategy()classMockEngineStrategy(EngineStrategy):"""Strategy for configuring an Engine-like object with mocked execution. Produces a single mock Connectable object which dispatches statement execution to a passed-in function. """name='mock'defcreate(self,name_or_url,executor,**kwargs):# create url.URL objectu=url.make_url(name_or_url)dialect_cls=u.get_dialect()dialect_args={}# consume dialect arguments from kwargsforkinutil.get_cls_kwargs(dialect_cls):ifkinkwargs:dialect_args[k]=kwargs.pop(k)# create dialectdialect=dialect_cls(**dialect_args)returnMockEngineStrategy.MockConnection(dialect,executor)classMockConnection(base.Connectable):def__init__(self,dialect,execute):self._dialect=dialectself.execute=executeengine=property(lambdas:s)dialect=property(attrgetter('_dialect'))name=property(lambdas:s._dialect.name)defcontextual_connect(self,**kwargs):returnselfdefexecution_options(self,**kw):returnselfdefcompiler(self,statement,parameters,**kwargs):returnself._dialect.compiler(statement,parameters,engine=self,**kwargs)defcreate(self,entity,**kwargs):kwargs['checkfirst']=Falsefromsqlalchemy.engineimportddlddl.SchemaGenerator(self.dialect,self,**kwargs).traverse_single(entity)defdrop(self,entity,**kwargs):kwargs['checkfirst']=Falsefromsqlalchemy.engineimportddlddl.SchemaDropper(self.dialect,self,**kwargs).traverse_single(entity)def_run_visitor(self,visitorcallable,element,connection=None,**kwargs):kwargs['checkfirst']=Falsevisitorcallable(self.dialect,self,**kwargs).traverse_single(element)defexecute(self,object,*multiparams,**params):raiseNotImplementedError()MockEngineStrategy()