RestrictedPython:从函数内打印时获取打印输出



我正在使用RestrictedPython运行以下代码(使用safeglobals['_print_'] = PrintCollectorcompile_restricted_exec/exec(compiled_code, safe_globals, locals)(。

def foo():
print 'bar'
print '123'
foo()

代码执行后,我可以通过保存PrintCollector实例的locals.pop('_print')获取打印输出,但仅适用于函数外部的print '123'语句。在调试它时,我看到正在创建两个PrintCollector实例,大概是针对使用print语句的两个上下文(模块级别和函数(。

但是,我找不到访问输入def foo()时创建的PrintCollector实例的方法。RestrictedPython的文档非常少,这就是为什么我在这里询问有关如何以RestrictedPython方式访问函数的打印输出的任何建议。

例:

from RestrictedPython import compile_restricted
from RestrictedPython.PrintCollector import PrintCollector
_print_ = PrintCollector
code_string = """
def foo():
print 'bar'
print '123'
foo()
"""
loc = {'_print_': PrintCollector, '_getattr_': getattr}
compiled_code = compile_restricted(code_string, '<string>', 'exec')
exec(compiled_code, loc)
loc['_print']()

更新:以下是我在不使用 print-语句的情况下调试受限代码的方法:

from RestrictedPython import compile_restricted
from RestrictedPython.PrintCollector import PrintCollector
_print_ = PrintCollector
code_string = """
def foo():
global debug_inner
debug_inner = 'bar'
foo()
debug_outer = '123'
results = [debug_inner, debug_outer]
"""
compiled_code = compile_restricted(code_string, '<string>', 'exec')
exec(compiled_code)
print results
# Output should be:
# >>> ['bar', '123']

旧答案:

按照您给出的示例,该函数需要返回printed-变量,并在 print-语句中执行,如以下文档中所述: https://code.activestate.com/pypm/restrictedpython/#print

例:

from RestrictedPython import compile_restricted
from RestrictedPython.PrintCollector import PrintCollector

_print_ = PrintCollector
code_string = """
def hello_world():
print 'Hello inner world!'
return printed
print 'Hello outer world!' # print a string
print hello_world()        # print return of function
results = printed          # fetch printed in a global
"""
# Compile and excecute restricted code:
compiled_code = compile_restricted(code_string, '<string>', 'exec')
exec(compiled_code)
# Now we have `results` available as a global:
print results.split('n') # convert string into list of lines
# We should get:
# >>> ['Hello inner world!', 'Hello outer world!', '', '']

我遇到了同样的问题,我发现也创建了两个 PrintCollector 实例。

所以我继承了类 PrintCollector 并使其成为单例。问题解决了。

def singleton(cls):
_instance = {}
def inner(t):
if cls not in _instance:
_instance[cls] = cls(t)
return _instance[cls]
return inner
@singleton
class SafePrintCollector(PrintCollector):
pass

但是如果你想多次运行 RestrictedPython,你需要添加一个重置方法来清除上次打印输出。

我不明白为什么 _print_ 需要成为工厂,但鉴于如果您想要一个跨越多个 print(( 调用和范围的单个输出累加器,只需定义您自己的类,该类使用静态变量来累积所有输出:

class PrintCollector:
output = []
def __init__(self, _getattr_=None):
self._getattr_ = _getattr_
def write(self, text):
PrintCollector.output.append(text)
def __call__(self):
return ''.join(PrintCollector.output)
def _call_print(self, *objects, **kwargs):
if kwargs.get('file', None) is None:
kwargs['file'] = self
else:
self._getattr_(kwargs['file'], 'write')
print(*objects, **kwargs)

然后,您可以抓取/打印所有输出,如下所示:

print("".join(PrintCollector.output))

当然,关于静态变量的一般警告/警告适用

最新更新