我有一个脚本可以根据配置动态导入模块。我正在尝试在脚本上实现守护进程上下文(使用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}}
答案 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
。如果可能的话,最好只是在上下文中打开文件等,正如我在上面所建议的那样。