zoukankan      html  css  js  c++  java
  • sqlalchemy源代码阅读随笔(2)

    这次阅读的,是Strategies.py文件。

    文件自身,是这么描述的:

    """Strategies for creating new instances of Engine types.
    
    These are semi-private implementation classes which provide the
    underlying 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.
    """

    首先,定义了一个基础类(也可以认为是抽象类):

    class EngineStrategy(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] = self
    
        def create(self, *args, **kwargs):
            """Given arguments, returns a new Engine instance."""
    
            raise NotImplementedError()

    这里我们注意到,定义了create方法,要求后续的继承类必须实现。而self.name却是没有定义的。

    而:

    strategies[self.name] = self,
    是把自己这个class传入到strategies变量中。

    进一步看他的继承类:

    class DefaultEngineStrategy(EngineStrategy):
        """Base class for built-in strategies."""
    
        def create(self, name_or_url, **kwargs):
            # create url.URL object
            u = url.make_url(name_or_url)
    
            plugins = u._instantiate_plugins(kwargs)
    
            u.query.pop('plugin', None)
    
            entrypoint = u._get_entrypoint()
            dialect_cls = entrypoint.get_dialect_cls(u)
    
            if kwargs.pop('_coerce_config', False):
                def pop_kwarg(key, default=None):
                    value = kwargs.pop(key, default)
                    if key in dialect_cls.engine_config_types:
                        value = dialect_cls.engine_config_types[key](value)
                    return value
            else:
                pop_kwarg = kwargs.pop
    
            dialect_args = {}
            # consume dialect arguments from kwargs
            for k in util.get_cls_kwargs(dialect_cls):
                if k in kwargs:
                    dialect_args[k] = pop_kwarg(k)
    
            dbapi = kwargs.pop('module', None)
            if dbapi is None:
                dbapi_args = {}
                for k in util.get_func_kwargs(dialect_cls.dbapi):
                    if k in kwargs:
                        dbapi_args[k] = pop_kwarg(k)
                dbapi = dialect_cls.dbapi(**dbapi_args)
    
            dialect_args['dbapi'] = dbapi
    
            for plugin in plugins:
                plugin.handle_dialect_kwargs(dialect_cls, dialect_args)
    
            # create dialect
            dialect = dialect_cls(**dialect_args)
    
            # assemble connection arguments
            (cargs, cparams) = dialect.create_connect_args(u)
            cparams.update(pop_kwarg('connect_args', {}))
            cargs = list(cargs)  # allow mutability
    
            # look for existing pool or create
            pool = pop_kwarg('pool', None)
            if pool is None:
                def connect(connection_record=None):
                    if dialect._has_events:
                        for fn in dialect.dispatch.do_connect:
                            connection = fn(
                                dialect, connection_record, cargs, cparams)
                            if connection is not None:
                                return connection
                    return dialect.connect(*cargs, **cparams)
    
                creator = pop_kwarg('creator', connect)
    
                poolclass = pop_kwarg('poolclass', None)
                if poolclass is None:
                    poolclass = dialect_cls.get_pool_class(u)
                pool_args = {
                    'dialect': dialect
                }
    
                # consume pool arguments from kwargs, translating a few of
                # the arguments
                translate = {'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',
                             'pre_ping': 'pool_pre_ping'}
                for k in util.get_cls_kwargs(poolclass):
                    tk = translate.get(k, k)
                    if tk in kwargs:
                        pool_args[k] = pop_kwarg(tk)
    
                for plugin in plugins:
                    plugin.handle_pool_kwargs(poolclass, pool_args)
    
                pool = poolclass(creator, **pool_args)
            else:
                if isinstance(pool, poollib._DBProxy):
                    pool = pool.get_pool(*cargs, **cparams)
                else:
                    pool = pool
    
                pool._dialect = dialect
    
            # create engine.
            engineclass = self.engine_cls
            engine_args = {}
            for k in util.get_cls_kwargs(engineclass):
                if k in kwargs:
                    engine_args[k] = pop_kwarg(k)
    
            _initialize = kwargs.pop('_initialize', True)
    
            # all kwargs should be consumed
            if kwargs:
                raise TypeError(
                    "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'" % k for k in kwargs),
                                        dialect.__class__.__name__,
                                        pool.__class__.__name__,
                                        engineclass.__name__))
    
            engine = engineclass(pool, dialect, u, **engine_args)
    
            if _initialize:
                do_on_connect = dialect.on_connect()
                if do_on_connect:
                    def on_connect(dbapi_connection, connection_record):
                        conn = getattr(
                            dbapi_connection, '_sqla_unwrap', dbapi_connection)
                        if conn is None:
                            return
                        do_on_connect(conn)
    
                    event.listen(pool, 'first_connect', on_connect)
                    event.listen(pool, 'connect', on_connect)
    
                def first_connect(dbapi_connection, connection_record):
                    c = base.Connection(engine, connection=dbapi_connection,
                                        _has_events=False)
                    c._execution_options = util.immutabledict()
                    dialect.initialize(c)
                event.listen(pool, 'first_connect', first_connect, once=True)
    
            dialect_cls.engine_created(engine)
            if entrypoint is not dialect_cls:
                entrypoint.engine_created(engine)
    
            for plugin in plugins:
                plugin.engine_created(engine)
    
            return engine

    只是实现了create,但是,还是没有name,再往下看:

    class PlainEngineStrategy(DefaultEngineStrategy):
        """Strategy for configuring a regular Engine."""
    
        name = 'plain'
        engine_cls = base.Engine

    在这里,才给name赋值了。

    意味着,之前的两个class,都不适合外部调用。

    线面,我们看看create_engine的过程,通过pycharm的单步调试去看:

    from sqlalchemy.engine import base, threadlocal, url,create_engine
    
    engineurl ='mysql+pymysql://root:root@192.168.31.196:3306/story_line_dev?charset=utf8'
    storyengine = create_engine(engineurl, max_overflow=5,echo=True)

    create_engine是在engine包里(从源代码结构看,是engine目录下),对于package来说,首先调用的是__init__.py文件:

        default_strategy = 'plain'

    strategy = kwargs.pop('strategy', default_strategy)
        strategy = strategies.strategies[strategy]
        return strategy.create(*args, **kwargs)

    关键是第三行代码:

    strategy = strategies.strategies[strategy],这里实际上就是:
    strategy = strategies.strategies[‘plain’]

    这里又要插一句,在import的时候,就执行了这个代码:

    strategies.py文件里的:PlainEngineStrategy()

    因为,在import的时候,类和方法的名称被import,但不执行。模块里的直接的方法(比如上面写的),会执行。

    下面,我们看看:
    PlainEngineStrategy做了啥:
    name = 'plain'
    engine_cls = base.Engine

    这里,就是调用了base.Engine

    关于base,下一次再说。
     
  • 相关阅读:
    How to install VXDIAG Honda, Toyota and JLR SDD software
    16% off MPPS V16 ECU tuning tool for EDC15 EDC16 EDC17
    Cummins INSITE locked and ask for verification code
    How to use BMW Multi Tool 7.3 to replace lost key for BMW X1
    Bleed Brake Master Cylinder with Intelligent Tester IT2
    Porsche Piwis Tester II “No VCI has been detected”,how to do?
    Creader VIII VS. Creader VII+
    How to solve GM MDI cannot complete the installation
    汽车OBD2诊断程序开发 (原文转载,思路很清晰!)
    汽车节温器单片机开发思路
  • 原文地址:https://www.cnblogs.com/aomi/p/7340432.html
Copyright © 2011-2022 走看看