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,下一次再说。
     
  • 相关阅读:
    js window对象属相和方法相关整理资料
    js中把字符串转换成number格式方法
    oracle中CAST函数使用简介【转】
    Oracle使用SQL语句修改字段类型
    @GeneratorValue与@GenericGenerator注解使用心得
    @Column 注解详情
    Spring中的注入方式 和使用的注解 详解
    maven教程
    wxpyhon 对话框
    wxpython 按钮等事件的触发
  • 原文地址:https://www.cnblogs.com/aomi/p/7340432.html
Copyright © 2011-2022 走看看