执行源代码时忽略ImportError

6 投票
3 回答
13678 浏览
提问于 2025-04-16 18:03

我有一个应用程序,它可以读取用Python写的测试脚本,并把这些脚本通过网络发送到远程的Python实例去执行。因为控制程序不需要运行这些脚本,所以我不想在控制器的Python环境中安装所有测试脚本所用的模块。不过,控制器确实需要从测试脚本中获取信息,以便知道如何运行测试。

目前,我读取和导入测试脚本数据的方法大致是这样的:

with open( 'test.py', 'r' ) as f:
    source = f.read()

m = types.ModuleType( "imported-temp", "Test module" )
co = compile( source, 'test.py', 'exec' )

exec co in m.__dict__

这样做会生成一个包含测试内容的新模块。不幸的是,如果测试脚本尝试导入控制器没有的模块,exec就会报ImportErrors错误。而且更糟糕的是,这个模块可能不会完全导入。

如果我能确保控制器不会使用那些缺失的模块,有没有办法忽略这些错误?或者有没有其他方法可以找到测试中定义的名称和类?

测试示例:

from controller import testUnit
import somethingThatTheControllerDoesNotHave

_testAttr = ['fast','foo','function']

class PartOne( testUnit ):
    def run( self ):
        pass

控制器需要知道的是_testAttr中的数据,以及所有继承自testUnit的类定义的名称。

3 个回答

3

我觉得,根据你说的内容,你可以直接这样写:

try:
    exec co in m.__dict__
except ImportError: pass

这样有帮助吗?

3

你可以使用Python的ast模块,把脚本解析成一个抽象语法树(AST)。然后,你可以在这个树里查找你感兴趣的元素。这样的话,你就完全不需要执行这个脚本了。

18

写一个导入钩子,这个钩子可以捕捉到错误,如果某个模块不存在,就返回一个假模块。

import __builtin__
from types import ModuleType

class DummyModule(ModuleType):
    def __getattr__(self, key):
        return None
    __all__ = []   # support wildcard imports

def tryimport(name, globals={}, locals={}, fromlist=[], level=-1):
    try:
        return realimport(name, globals, locals, fromlist, level)
    except ImportError:
        return DummyModule(name)

realimport, __builtin__.__import__ = __builtin__.__import__, tryimport

import sys   # works as usual
import foo   # no error

from bar import baz     # also no error
from quux import *      # ditto

你也可以把它写成总是返回一个假模块,或者只有在指定的模块还没有被加载时才返回假模块(提示:如果这个模块在sys.modules里,那说明它已经被加载过了)。

撰写回答