python importlib 在守护进程上下文中找不到模块

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

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

setup() 中的 mymodule/__init__.py 我这样做:

load_modules(args, config, logger)

try:
    with daemon.DaemonContext(
            files_preserve = getLogfileHandlers(logger)
            ):
        main_loop(config)

我在 mymodule/__main__.py 中调用了 setup(),并且我以这种方式加载整个内容: PYTHONPATH=. python -m mymodule

这工作正常,但是在 load_modules() 内部设置的监听端口被新添加的守护进程上下文关闭,所以我想将该函数调用移动到守护进程上下文中,如下所示:

try:
    with daemon.DaemonContext(
            files_preserve = getLogfileHandlers(logger)
            ):
        load_modules(args, config, logger)
        main_loop(config)

模块以这种方式加载到 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 未更改,守护进程上下文未清除环境或 chroot。当然,cwd 会更改为 /,但这不会对 python 查找模块的能力产生任何影响,因为 . 的绝对路径出现在 sys.path 中。路径

我在这里缺少什么?

编辑:我正在添加 SSCCE以使情况更加清楚。以下三个文件创建一个名为“mymodule”的模块,该模块可以从命令行作为 PYTHONPATH= 运行。 python -m mymodule. __init__.py 中有两次对 load_module() 的调用,其中一个被注释掉了。您可以通过交换评论的内容来演示该问题。

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")

最佳答案

当我在自己的项目中遇到这个问题时,我花了 4 个小时试图解决这个问题。线索在这里:

If the module being imported is supposed to be contained within a package then the second argument passed to find_module(), __path__ on the parent package, is used as the source of paths.

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

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

mymodule.__path__ = ['mymodule']

守护进程后,Python 的 CWD 设置为 /mysubmodule 的导入内部搜索的唯一位置位于 /mymodule .

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

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

关于python importlib 在守护进程上下文中找不到模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29595193/

相关文章:

python - 如何在动态 Django ModelChoiceField 中设置初始值?

python - Python 守护进程中的 Paramiko 导致 IOError

python - 您如何按照文档规定的方式使用 python-daemon?

Python 守护进程没有显示错误输出

python - Python中的MySQL,MATCH和注入(inject)攻击

Python:打开带有附件的 outlook 组合实例

当年份是两位数时,python从字符串中断转换日期

python - 移动到文本小部件 tkinter 中的特定位置

python - keras中注意力层是如何实现的?

python - 使用 Beautiful Soup 查找特定类