RestrictedPython: получить вывод на печать при печати из функции - PullRequest
0 голосов
/ 05 сентября 2018

Я запускаю следующий код, используя RestrictedPython (используя safeglobals['_print_'] = PrintCollector и compile_restricted_exec / exec(compiled_code, safe_globals, locals)).

def foo():
    print 'bar'

print '123'
foo()

После выполнения кода я могу получить вывод на печать через locals.pop('_print'), который содержит экземпляр PrintCollector, но только для оператора print '123', который находится вне функции. При отладке я вижу два экземпляра PrintCollector, предположительно для двух контекстов (уровень модуля и функция), в которых используется оператор print.

Однако я не могу найти способ доступа к экземпляру PrintCollector, который был создан при вводе def foo(). Документация для 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']()

Ответы [ 2 ]

0 голосов
/ 19 апреля 2019

Я столкнулся с той же проблемой и обнаружил, что два экземпляра 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 несколько раз, вам нужно добавить метод сброса, чтобы очистить последний вывод на печать.

0 голосов
/ 05 сентября 2018

Обновление : Вот как я могу отлаживать код с ограниченным доступом без использования операторов 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!', '', '']
...