python importlib无法在守护进程上下文中找到一个模块

时间:2015-04-12 22:06:39

标签: python python-2.7 python-daemon python-importlib

我有一个脚本可以根据配置动态导入模块。我正在尝试在脚本上实现守护进程上下文(使用python-daemon模块),这似乎干扰了python找到相关模块的能力。

mymodule/__init__.py中的setup()内的load_modules(args, config, logger) try: with daemon.DaemonContext( files_preserve = getLogfileHandlers(logger) ): main_loop(config) 我执行此操作:

setup()

我在mymodule/__main__.py内打电话给PYTHONPATH=. python -m mymodule并且我正在以这种方式加载整个事情: try: with daemon.DaemonContext( files_preserve = getLogfileHandlers(logger) ): load_modules(args, config, logger) main_loop(config)

这很好,但是在load_modules()中设置的侦听端口被新添加的守护进程上下文关闭,所以我想在守护进程上下文中移动该函数调用,如下所示:

load_modules()

模块以for mysubmodule in modules: try: i = importlib.import_module("mymodule.{}".format(mysubmodule)) except ImportError as err: logger.error("import of mymodule.{} failed: {}".format( mysubmodule, err)) 方式加载:

load_modules()

在守护程序上下文之外使用import of mymodule.submodule failed: No module named submodule ,这可以正常工作。当我在守护进程内部移动它时,它似乎无法找到它正在寻找的模块。我明白了:

sys.path

它看起来像某种命名空间问题 - 我注意到异常仅指我尝试导入的模块名称的子模块部分 - 但我已经比较了我能想到的守护进程内部和外部的所有内容,我找不到重要的区别。 /未更改,守护程序上下文不清除environemnt或chrooting。 cwd当然会更改为.,但这不会对python查找模块的能力产生任何影响,因为sys.path的绝对路径出现在PYTHONPATH=. python -m mymodule中。

我在这里缺少什么?

编辑:我正在添加SSCCE以使情况更加清晰。以下三个文件创建一个名为“mymodule”的模块,该模块可以从命令行运行为load_module()__init__.py中有mymodule/__main__.py两个电话,其中一个被注释掉了。您可以通过交换哪一个被评论来证明问题。

from mymodule import setup import sys if __name__ == "__main__": sys.exit(setup())

mymodule/__init__.py

import daemon import importlib import logging def main_loop(): logger = logging.getLogger('loop') logger.debug("Code runs here.") def load_module(): logger = logging.getLogger('load_module') submodule = 'foo' try: i = importlib.import_module("mymodule.{}".format(submodule)) except ImportError as e: logger.error("import of mymodule.{} failed: {}".format( submodule, e)) def setup_logging(): logfile = 'mymodule.log' fh = logging.FileHandler(logfile) root_logger = logging.getLogger() root_logger.addHandler(fh) root_logger.setLevel(logging.DEBUG) def get_logfile_handlers(logger): handlers = [] for handler in logger.handlers: handlers.append(handler.stream.fileno()) return handlers def setup(): setup_logging() logger = logging.getLogger() # load_module() with daemon.DaemonContext( files_preserve = get_logfile_handlers(logger) ): load_module() main_loop()

mymodule/foo.py

import logging logger=logging.getLogger('foo') logger.debug("Inside foo.py")

{{1}}

2 个答案:

答案 0 :(得分:1)

当我在自己的项目中点击它时,我花了4个小时尝试解决这个问题。线索在这里:

  

如果要导入的模块应该包含在一个包中,那么传递给父包的find_module()__path__的第二个参数将被用作路径源。

(来自https://docs.python.org/2/reference/simple_stmts.html#import

成功导入mymodule后,python2不再使用sys.path来搜索子模块,而是使用sys.modules["mymodule"].__path__。导入mymodule时,python2无益地将其__path__设置为存储在相对目录中:

mymodule.__path__ = ['mymodule']

守护进程后,python的CWD设置为/,而mysubmodule的导入内部搜索设置为/mymodule。< / p>

我通过使用os.chdir()在守护进程后将CWD更改回旧目录来解决这个问题:

oldcwd = os.getcwd()
with DaemonizeContext():
    os.chdir(oldcwd)
    # ... daemon things

答案 1 :(得分:-1)

  

这很好用,但是在load_modules()中设置的侦听端口被新添加的守护进程上下文关闭,所以

没有。 load_modules()应该加载模块。它不应该打开端口。

如果您需要保留在上下文之外打开的文件或套接字,请将其传递给files_preserve。如果可能的话,最好只是在上下文中打开文件等,正如我在上面所建议的那样。