使用Pysandbox实现在线Python Shell

时间:2012-11-05 17:42:46

标签: python implementation pysandbox

我想构建一个像this这样的在线Python shell。目前我正在尝试构建一个模块 在Python中执行以下操作

  1. 创建新会话。
  2. 运行以字符串形式传递的代码并维护当前会话的环境变量。
  3. 我正在尝试使用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个主要问题。

    1. 如何很好地显示错误?例如,运行上面的代码会产生以下输出

      运行中的文件“execute.py”,第60行     self.sandbox.execute(代码)   文件“/home/aaa/aaa/aaa/pysandbox-master/sandbox/sandbox_class.py”,第90行,执行     return self.execute_subprocess(self,code,globals,locals)   在execute_subprocess中输入文件“/home/aaa/aaa/aaa/pysandbox-master/sandbox/subprocess_parent.py”,第119行     提高output_data ['错误'] NameError:名称'a'未定义

    2. 这里不受欢迎的是“execute.py”的调用追溯。我只是希望函数返回以下错误。

      NameError: name 'a' is not defined
      
      1. 如何维护当前会话的环境?例如,在上面的代码序列中

        a = 5
        b = 5
        打印a + b

      2. 应该产生输出10。 有什么想法吗?

1 个答案:

答案 0 :(得分:-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()