如何在运行exec脚本时隐藏args到argparse?

问题描述 投票:0回答:1

我有两个文件。runner.py 运转 target.py 与subprocess或exec。它们都有命令行选项。

如果运行者在运行目标时使用 子流程 没关系。

$ python runner.py
run target.py with subprocess...
target.py: running with dummy = False

如果运行者在运行目标代码时 执行员 (附 -e 选项)。)

$ python runner.py -e
run target.py with exec...
usage: runner.py [-h] [-d]
runner.py: error: unrecognized arguments: -e

命令行参数 -etarget.py 代码(只接受一个 --dummy 选项)并引发一个错误。

当我用exec运行脚本时,如何隐藏args到argparse?

下面是代码。

runner.py

import subprocess
import argparse


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-e", "--exec", help="run with exec", action="store_true")
    args = parser.parse_args()

    target_filename = "target.py"

    if args.exec:
        print("run target.py with exec...")
        source_code = open(target_filename).read()
        compiled = compile(source_code, filename=target_filename, mode="exec")
        exec(compiled) # OPTION 1 - error on argparse
        # exec(compiled, {}) # OPTION 2 - target does not go inside "if main"
        # exec(compiled, dict(__name__="__main__")) # OPTION 3 - same error as OPTION 1 
    else:
        print("run target.py with subprocess...")
        subprocess.run(["python3", target_filename])

我试着用上面注释的选项来隐藏 globals,但没有成功。这似乎与 argparse 工作。

target.py

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-d", "--dummy", help="a dummy option", action="store_true")
    args = parser.parse_args()

    print(f"target.py: running with dummy = {args.dummy}")
python python-3.x argparse python-exec
1个回答
0
投票

有一个 argparse 冲突处理程序 选项,所以可以写 argparse.ArgumentParser(conflict_handler='resolve') 在目标脚本中。resolve 删除了冲突的选项,但这并不能很好地处理类似的情况,即在 runner 和 target 中的选项名称相同,或者你不能或不想改变 target 文件的情况。


这是我找到的解决方案。在内部,argparse使用 sys.argv 检索命令行设置的选项。

您可以直接设置 sys.argv = [target_filename] 删除了这些选项,但改变了 sys 会带来很多其他问题。

使用 unittest.mock.patch (python3.4+)的 sys.argv 可以这样安全地修改。

from unittest.mock import patch

# [...]    

source_code = open(target_filename).read()
compiled = compile(source_code, filename=target_filename, mode="exec")

# remove command args
with patch('sys.argv', [target_filename]):
    exec(compiled)

所以我们也可以用选项来运行目标脚本代码。

# run target
with patch('sys.argv', [target_filename]):  
    exec(compiled)

# run target with -d
with patch('sys.argv', [target_filename, "-d"]):
    exec(compiled)
© www.soinside.com 2019 - 2024. All rights reserved.