def _execute_with_timeout(self, code, filename, kind): """ Execute the given code, but stop after `self.allowed_time`. Args: code (str): filename (str): kind (:py:class:`pedal.sandbox.sandbox_mixins.SandboxContextKind`): Returns: :py:class:`pedal.sandbox.sandbox.Sandbox` """ try: return timeout(self.allowed_time, self._execute, code, filename, kind, False) except TimeoutError as timeout_exception: self._stop_patches() self._capture_exception(timeout_exception, sys.exc_info(), code, filename) return self
def run(self, code, as_filename=None, modules=None, inputs=None, threaded=None, report_exceptions=True, context=False): """ Execute the given string of code in this sandbox. Args: code (str): The string of code to be executed. as_filename (str): The filename to use when executing the code - this is cosmetic, technically speaking, it has no relation to anything on disk. It will be present in tracebacks. Defaults to Source's filename. modules (dict[str:Module]): Modules to mock. inputs (list[str]): The inputs to give from STDIN, as a list of strings. You can also give a function that emulates the input function; e.g., consuming a prompt (str) and producing strings. This could be used to make a more interactive input system. context (str): The context to give any exceptions. If None, then the recorded context will be used. If a string, tracebacks will be shown with the given context. If False, no context will be given (the default). threaded (bool): whether or not to run this code in a separate thread. Defaults to :attribute:`Sandbox.threaded`. report_exceptions (bool): Whether or not to capture exceptions. """ # Handle any threading if necessary if threaded is None: threaded = self.threaded if threaded: try: return timeout(self.allowed_time, self.run, code, as_filename, modules, inputs, False, report_exceptions, context) except TimeoutError as timeout_exception: self._capture_exception(timeout_exception, sys.exc_info(), report_exceptions) return self if as_filename is None: as_filename = os.path.basename(self.report['source']['filename']) if inputs is None: if self.inputs is None: inputs = mocked._make_inputs('0', repeat='0') else: inputs = self.inputs if isinstance(inputs, (tuple, list)): inputs = mocked._make_inputs(*inputs) elif isinstance(inputs, str): inputs = mocked._make_inputs(inputs) inputs = self._track_inputs(inputs) # Override builtins and mock stuff out mocked_functions = self.mocked_functions.copy() mocked_functions['input'] = inputs mocked_functions['raw_input'] = inputs mocked_functions['sys'] = sys mocked_functions['os'] = os mocked._override_builtins(self.data, mocked_functions) self.exception = None self.exception_position = None self.exception_formatted = None # Patch in dangerous built-ins capture_stdout = io.StringIO() self._start_patches(patch('sys.stdout', capture_stdout), patch('time.sleep', return_value=None), patch.dict('sys.modules', self.mocked_modules)) # Compile and run student code try: compiled_code = compile(code, as_filename, 'exec') with self.trace._as_filename(as_filename, code): exec(compiled_code, self.data) except Exception as user_exception: self._capture_exception(user_exception, sys.exc_info(), report_exceptions, context) finally: self._stop_patches() self.append_output(capture_stdout.getvalue()) if context is None: self.call_contexts[self.call_id].append(code) elif isinstance(context, str): self.call_contexts[self.call_id].append(context) elif context is not False: self.call_contexts[self.call_id] = context return self
def run(self, code, as_filename=None, modules=None, inputs=None, threaded=None, report_exceptions=True, context=False): """ Execute the given string of code in this sandbox. Args: code (str): The string of code to be executed. as_filename (str): The filename to use when executing the code - this is cosmetic, technically speaking, it has no relation to anything on disk. It will be present in tracebacks. Defaults to Source's filename. modules (dict[str:Module]): Modules to mock. inputs (list[str]): The inputs to give from STDIN, as a list of strings. You can also give a function that emulates the input function; e.g., consuming a prompt (str) and producing strings. This could be used to make a more interactive input system. context (str): The context to give any exceptions. If None, then the recorded context will be used. If a string, tracebacks will be shown with the given context. If False, no context will be given (the default). threaded (bool): whether or not to run this code in a separate thread. Defaults to :attribute:`Sandbox.threaded`. report_exceptions (bool): Whether or not to capture exceptions. """ # Handle any threading if necessary if threaded is None: threaded = self.threaded if threaded: try: return timeout(self.allowed_time, self.run, code, as_filename, modules, inputs, False, report_exceptions, context) except TimeoutError as timeout_exception: self._capture_exception(timeout_exception, sys.exc_info(), report_exceptions) return self if as_filename is None: as_filename = os.path.basename(self.report['source']['filename']) if inputs is None: if self.inputs is None: inputs = mocked._make_inputs('0', repeat='0') else: inputs = self.inputs if isinstance(inputs, (tuple, list)): inputs = mocked._make_inputs(*inputs) elif isinstance(inputs, str): inputs = mocked._make_inputs(inputs) inputs = self._track_inputs(inputs) # Override builtins and mock stuff out mocked_functions = self.mocked_functions.copy() mocked_functions['input'] = inputs mocked_functions['raw_input'] = inputs mocked_functions['sys'] = sys mocked_functions['os'] = os mocked._override_builtins(self.data, mocked_functions) self.exception = None self.exception_position = None self.exception_formatted = None # Patch in dangerous built-ins capture_stdout = io.StringIO() self._start_patches( patch('sys.stdout', capture_stdout), patch('time.sleep', return_value=None), patch.dict('sys.modules', self.mocked_modules) ) # Compile and run student code try: compiled_code = compile(code, as_filename, 'exec') with self.trace._as_filename(as_filename, code): exec(compiled_code, self.data) except Exception as user_exception: self._capture_exception(user_exception, sys.exc_info(), report_exceptions, context) finally: self._stop_patches() self.append_output(capture_stdout.getvalue()) if context is None: self.call_contexts[self.call_id].append(code) elif isinstance(context, str): self.call_contexts[self.call_id].append(context) elif context is not False: self.call_contexts[self.call_id] = context return self