Реализовать онлайн-оболочку Python с помощью Pysandbox
Я хочу создать онлайн-оболочку Python, как это. В настоящее время я пытаюсь построить модуль на Python, который делает следующие вещи
- Создает новый сеанс.
- Запускает код, переданный как ведение строки, и поддерживает переменные среды текущего сеанса.
Я пытаюсь добиться этого с помощью Pysandbox. Вот мои усилия до сих пор
from sandbox import Sandbox, SandboxConfig
from optparse import OptionParser
import sys,traceback
class Runner:
def __init__(self):
self.options = self.parseOptions()
self.sandbox = Sandbox(self.createConfig())
self.localvars = dict()
def parseOptions(self):
parser = OptionParser(usage="%prog [options]")
SandboxConfig.createOptparseOptions(parser, default_timeout=None)
parser.add_option("--debug",
help="Debug mode",
action="store_true", default=False)
parser.add_option("--verbose", "-v",
help="Verbose mode",
action="store_true", default=False)
parser.add_option("--quiet", "-q",
help="Quiet mode",
action="store_true", default=False)
options, argv = parser.parse_args()
if argv:
parser.print_help()
exit(1)
if options.quiet:
options.verbose = False
return options
def createConfig(self):
config = SandboxConfig.fromOptparseOptions(self.options)
config.enable('traceback')
config.enable('stdin')
config.enable('stdout')
config.enable('stderr')
config.enable('exit')
config.enable('site')
config.enable('encodings')
config._builtins_whitelist.add('compile')
config.allowModuleSourceCode('code')
config.allowModule('sys',
'api_version', 'version', 'hexversion')
config.allowSafeModule('sys', 'version_info')
if self.options.debug:
config.allowModule('sys', '_getframe')
config.allowSafeModule('_sandbox', '_test_crash')
config.allowModuleSourceCode('sandbox')
if not config.cpython_restricted:
config.allowPath(__file__)
return config
def Run(self,code):
# log and compile the statement up front
try:
#logging.info('Compiling and evaluating:\n%s' % statement)
compiled = compile(code, '<string>', 'single')
except:
traceback.print_exc(file=sys.stdout)
return
try:
self.sandbox.execute(code)
except:
traceback.print_exc(file=sys.stdout)
def f():
f = open('test.py')
code = ''
for lines in f:
code = code+lines
runner = Runner()
runner.Run('a = 5')
runner.Run('b = 5')
runner.Run('print a+b')
f()
Я сталкиваюсь с 3 основными проблемами.
Как красиво отобразить ошибку? Например, выполнение приведенного выше кода приводит к следующему выводу
Файл "execute.py", строка 60, в файле "Выполнить self.sandbox.execute (code)" в файле "/home/aaa/aaa/aaa/pysandbox-master/sandbox/sandbox_class.py", строка 90, в функции execute возвращает self.execute_subprocess(self, code, globals, localals) Файл "/home/aaa/aaa/aaa/pysandbox-master/sandbox/subprocess_parent.py", строка 119, в execute_subprocess поднять output_data['error'] NameError: name 'a' не определено
Нежелательной вещью здесь является обратный вызов "execute.py". Я просто хочу, чтобы функция возвращала следующую ошибку.
NameError: name 'a' is not defined
Как мне поддерживать среду текущего сеанса? Например, в приведенной выше кодовой последовательности
а = 5
б = 5
напечатать а + б
должен привести к выводу 10. Есть идеи?
1 ответ
Это должно работать, хотя вы можете поиграть с выводом исключения:
from sandbox import Sandbox, SandboxConfig
from optparse import OptionParser
import sys,traceback
class Runner:
def __init__(self):
self.options = self.parseOptions()
self.sandbox = Sandbox(self.createConfig())
self.localvars = dict()
self.code = ''
def parseOptions(self):
parser = OptionParser(usage="%prog [options]")
SandboxConfig.createOptparseOptions(parser)#, default_timeout=None)
parser.add_option("--debug",
help="Debug mode",
action="store_true", default=False)
parser.add_option("--verbose", "-v",
help="Verbose mode",
action="store_true", default=False)
parser.add_option("--quiet", "-q",
help="Quiet mode",
action="store_true", default=False)
options, argv = parser.parse_args()
if argv:
parser.print_help()
exit(1)
if options.quiet:
options.verbose = False
return options
def createConfig(self):
config = SandboxConfig.fromOptparseOptions(self.options)
config.enable('traceback')
config.enable('stdin')
config.enable('stdout')
config.enable('stderr')
config.enable('exit')
config.enable('site')
config.enable('encodings')
config._builtins_whitelist.add('compile')
config.allowModuleSourceCode('code')
config.allowModule('sys',
'api_version', 'version', 'hexversion')
config.allowSafeModule('sys', 'version_info')
if self.options.debug:
config.allowModule('sys', '_getframe')
config.allowSafeModule('_sandbox', '_test_crash')
config.allowModuleSourceCode('sandbox')
if not config.cpython_restricted:
config.allowPath(__file__)
return config
def Run(self,code):
code = '\n'.join([self.code,code])
# log and compile the statement up front
try:
#logging.info('Compiling and evaluating:\n%s' % statement)
compiled = compile(code, '<string>', 'single')
except:
traceback.print_exc(file=sys.stdout)
return
try:
self.sandbox.execute(code)
except:
err = sys.exc_info()[1]
print type(err), err
else:
self.code = code
def f():
f = open('test.py')
code = ''
for lines in f:
code = code+lines
runner = Runner()
runner.Run('a = 5')
runner.Run('b = 5')
runner.Run('print a+b')
f()