在不实际执行的情况下导入 python 模块 [英] Importing a python module without actually executing it

查看:45
本文介绍了在不实际执行的情况下导入 python 模块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在复杂应用程序的上下文中,我需要导入用户提供的脚本".理想情况下,脚本应该具有

In the context of a complex application, I need to import user-supplied 'scripts'. Ideally, a script would have

def init():
    blah

def execute():
    more blah

def cleanup():
    yadda

所以我只是

import imp
fname, path, desc = imp.find_module(userscript)
foo = imp.load_module(userscript, fname, path, desc)
foo.init()

然而,众所周知,一旦load_module 运行,用户的脚本就会执行.这意味着,脚本可以是这样的:

However, as we all know, the user's script is executed as soon as load_module runs. Which means, a script can be something like this:

def init():
    blah

yadda

在我import脚本后立即调用yadda部分.

yielding to the yadda part being called as soon as I import the script.

我需要的是一种方法:

  1. 首先检查它是否有init()、execute()和cleanup()
  2. 如果它们存在,一切都很好
  3. 如果它们不存在,请投诉
  4. 不要运行任何其他代码,或者至少在我知道没有 init() 之前不要运行

通常我会强制使用相同的旧 if __name__ == '__main__' 技巧,但我对用户提供的脚本几乎没有控制,所以我正在寻找一个相对轻松的解决方案.我见过各种复杂的技巧,包括解析脚本,但没有什么是真正简单的.我很惊讶它不存在......或者我可能没有得到什么.

Normally I'd force the use the same old if __name__ == '__main__' trick, but I have little control on the user-supplied script, so I'm looking for a relatively painless solution. I have seen all sorts of complicated tricks, including parsing the script, but nothing really simple. I'm surprised it does not exist.. or maybe I'm not getting something.

谢谢.

推荐答案

我尝试使用 ast 模块:

import ast

# which syntax elements are allowed at module level?
whitelist = [
  # docstring
  lambda x: isinstance(x, ast.Expr) \
             and isinstance(x.value, ast.Str),
  # import
  lambda x: isinstance(x, ast.Import),
  # class
  lambda x: isinstance(x, ast.ClassDef),
  # function
  lambda x: isinstance(x, ast.FunctionDef),
]

def validate(source, required_functions):
  tree = ast.parse(source)

  functions = set()
  required_functions = set(required_functions)

  for item in tree.body:
    if isinstance(item, ast.FunctionDef):
      functions.add(item.name)
      continue

    if all(not checker(item) for checker in whitelist):
      return False

  # at least the required functions must be there
  return len(required_functions - functions) == 0


if __name__ == "__main__":
  required_funcs = [ "init", "execute", "cleanup" ]
  with open("/tmp/test.py", "rb") as f:
    print("yay!" if validate(f.read(), required_funcs) else "d'oh!")

这篇关于在不实际执行的情况下导入 python 模块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆