celery加载配置文件

使用celery的时候,有句:app.config_from_object('dailyblog.conf:settings'),虽然我知道是用来导入配置文件的,但不知道如何实现的。因此,我是带着疑问来研究的,为什么这个method是可以根据字符串搜索配置文件?为什么还会有冒号":"? 研究代码走起。

def config_from_object(self, obj, silent=False, force=False): self._config_source = obj if force or self.configured: del(self.conf) return self.loader.config_from_object(obj, silent=silent)

该方法返回了一个Loader类的config_from_object:

 def config_from_object(self, obj, silent=False):
    if isinstance(obj, string_t):
        try:
            obj = self._smart_import(obj, imp=self.import_from_cwd)
        except (ImportError, AttributeError):
            if silent:
                return False
            raise
    self._conf = force_mapping(obj)
    return True

该类最关键的是两个语句:

    obj = self._smart_import(obj, imp=self.import_from_cwd)
    self._conf = force_mapping(obj)

第一句:

obj = self._smart_import(obj, imp=self.import_from_cwd)

看_smart_import源码:

 def _smart_import(self, path, imp=None):
    imp = self.import_module if imp is None else imp
    if ':' in path:
        # Path includes attribute so can just jump here.
        # e.g. ``os.path:abspath``.
        return symbol_by_name(path, imp=imp)

其实到这,就初步解释了我的第二个疑问,celery对“:”进行了处理,接下来看symbol_by_name的源码:

def symbol_by_name(name, aliases={}, imp=None, package=None,
               sep='.', default=None, **kwargs):

    sep = ':' if ':' in name else sep
    module_name, _, cls_name = name.rpartition(sep)
    if not module_name:
        cls_name, module_name = None, package if package else cls_name
    try:
        try:
            module = imp(module_name, package=package, **kwargs)
        except ValueError as exc:
            reraise(ValueError,
                    ValueError("Couldn't import {0!r}: {1}".format(name, exc)),
                    sys.exc_info()[2])
        return getattr(module, cls_name) if cls_name else module
    except (ImportError, AttributeError):
        if default is None:
            raise
    return default

我删除了不是我关注的地方。看上面的代码,module_name, _, cls_name = name.rpartition(sep),这句话就将我们的参数分离成dailyblog.conf,settings。

然后他执行下面的语句:

 module = imp(module_name, package=package, **kwargs)

这个imp是参数,是loader定义的method,原型:

def import_from_cwd(self, module, imp=None, package=None):
    return import_from_cwd(
        module,
        self.import_module if imp is None else imp,
        package=package,
    )
***********************************
celery  utils:

def import_from_cwd(module, imp=None, package=None):
    """Import module, but make sure it finds modules
    located in the current directory.

    Modules located in the current directory has
    precedence over modules located in `sys.path`.
    """
    if imp is None:
        imp = importlib.import_module
    with cwd_in_path():
        return imp(module, package=package)

到目前为止,导入了当前目录的django.conf模块。然后再看上面symbol_name方法,该方法返回了return getattr(module, cls_name)。到这要明白,settings是一个对象,一个object,所以才会执行该语句。这样就加载了配置文件。

--------EOF---------
本文微信分享/扫码阅读