在 运行 程序时检测 input() 事件并使方法调用失败

Detect input() event while running a program and fail the method call

背景
我有一项任务是 运行 许多 python 方法批量处理测试套件。我写了一个程序来动态定义方法和相应的测试用例(使用exec(str)),并自动运行测试用例。

问题
正确的代码不应包含需要用户输入的 input() 语句。但是,存在可能包含 input() 语句的不正确代码,这会阻塞 运行 宁并等待用户输入。我如何检测是否调用了 input() 并且我的程序挂在那里?有没有办法让这样的方法调用失败并继续程序?

总结

我如何检测 input() 是否被调用并且我的程序挂在那里?

假设您有两种方法 - 一种正确,一种不正确:

class Foo:
    def correct(self, x):
        return x
        
    def incorrect(self):
        # You shouldn't use input!
        a = int(input())
        return 42 + a

可以使用unittest.mock library。创建一个函数来检测是否使用了 input 的任何调用:

import unittest.mock

def check(f, *args, **kwargs):
    # Store the real `input` function in a variable
    real_input = __builtins__.input
    
    # Use `unittest.mock` to catch any calls to this variable
    __builtins__.input = unittest.mock.MagicMock()
    
    # Call the desired function with the provided arguments
    f(*args, **kwargs)
    
    # Check if the fake `input` function was called
    result = __builtins__.input.called
    
    # Restore the value of the `input` function
    __builtins__.input = real_input

    # Return if the fake `input` function was called
    return result

你可以这样使用它:

foo = Foo()
print(check(foo.correct, 42))    # Outputs False
print(check(foo.incorrect))      # Outputs True

有没有办法让这样的方法调用失败并继续程序?

替换check函数
def check(f, *args, **kwargs):
    # Use a custom error so that, if the original function throws an
    # error, it wouldn't be catch mistakenly inside the `check` function
    class _MyCustomError(BaseException):
        pass

    real_input = __builtins__.input
    
    __builtins__.input = unittest.mock.Mock(side_effect=_MyCustomError())
    
    try:
        f(*args, **kwargs)
    except _MyCustomError:
        return True
    else:
        return False
    finally:
        __builtins__.input = real_input

经过此修改,用法将是:

foo = Foo()
print(check(foo.correct, 42))    # Outputs False
print(check(foo.incorrect))      # Outputs True and fail the function with _MyCustomError