2015-04-12 30 views
1

我有一個基於配置動態導入模塊的腳本。我試圖在腳本上實現守護程序上下文(使用python-daemon模塊),它似乎干擾了python查找有問題的模塊的能力。python importlib在守護程序上下文中找不到模塊

Insite的mymodule/__init__.pysetup()我這樣做:

load_modules(args, config, logger) 

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

我得setup()一個電話裏面mymodule/__main__.py和我加載整個事情是這樣的: 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不變,守護程序上下文不清除environemnt或chrooting。當然,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") 

回答

-1

這工作得很好,但一個監聽端口是獲取設置裏面load_modules()是由新加入的守護範圍內封閉的,所以

load_modules()號應加載模塊。它不應該打開端口。

如果您需要保留在上下文之外打開的文件或套接字,請將其傳遞到files_preserve。如果可能的話,最好在上下文中簡單地打開文件等,正如我上面所建議的那樣。

+0

這些模塊都做不同的事情。有些碰巧打開文件或打開偵聽端口。我已經檢查過了,DaemonContext並沒有把我放入chroot中。默認情況下,它並沒有這樣做,並且我在沒有發生的問題中指出。我已經比較了開放環境之前和之後儘可能多的環境,唯一的區別是CWD更改爲/。運行sscce,你可以檢查。 – mpounsett

+0

「這些模塊都做不同的事情,有些打開文件或打開偵聽端口。」 - 如果他們將其作爲進口時的副作用,則設計不佳,應該修復它們。編寫一個可以單獨調用的功能,以便在需要時打開端口/文件。 – Kevin

+0

另外,如果它不會將你置入chroot,那麼'files_preserve'參數在做什麼呢? – Kevin

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'] 

daemonizing後,蟒蛇的CWD設置爲/只有地方進口的內部搜索mysubmodule是在/mymodule

我工作圍繞這通過使用os.chdir() daemonizing後更改CWD回老導演:

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