def check_re(self, text): """Run re.match in sandbox, because re.match('(x+x+)+y', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') is to resource consuming. May be should use https://code.google.com/p/re2/ here. """ if self.match_substring: pattern = "{0}({1}){0}".format(r"(.|\n)*", self.pattern) else: pattern = self.pattern global_dict = {'matched': False, 'pattern': pattern, 'text': text} code = textwrap.dedent(""" import re match = re.match(pattern, text, {flags}) matched = match.group() == text if match else False """).format(flags='' if self.case_sensitive else 'flags=re.I') try: safe_exec.safe_exec(code, global_dict) except safe_exec.SafeExecException: score = False else: score = bool(global_dict['matched']) return score
def main(): gobble = [] for i in xrange(int(1e7)): print i globs = {} safe_exec.safe_exec("a = 17", globs) assert globs["a"] == 17 gobble.append("x" * GOBBLE_CHUNK)
def is_math_quiz_enabled(): code = textwrap.dedent(""" import sympy """) try: safe_exec.safe_exec(code, {}) except safe_exec.SafeExecException: return False return True
def run_python(request): """A page to allow testing the Python sandbox on a production server.""" if not request.user.is_staff: raise Http404 c = {} c['code'] = '' c['results'] = None if request.method == 'POST': py_code = c['code'] = request.POST.get('code') g = {} try: safe_exec(py_code, g) except Exception as e: c['results'] = traceback.format_exc() else: c['results'] = pprint.pformat(g) return render_to_response("debug/run_python_form.html", c)
def attempt_safe(dataset, answer_query, verify_query, is_ordered, query): """ Attempt a SqlProblem, using codejail to sandbox the execution. """ results = { 'answer_query': answer_query, 'dataset': dataset, 'verify_query': verify_query, 'is_ordered': is_ordered, 'query': query } code = """ from sql_grader.problem import SqlProblem submission_result, answer_result, error, comparison = SqlProblem( answer_query=answer_query, dataset=dataset, verify_query=verify_query, is_ordered=is_ordered ).attempt(query) """ # example from edx-platform's use of codejail: # https://github.com/edx/edx-platform/blob/master/common/lib/capa/capa/capa_problem.py#L887 # we have to include the path to the entire sql_grader package. python_path = [ os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')) ] try: safe_exec(code, results, python_path=python_path, slug='sql_grader') except SafeExecException: log.exception(query) # how should resource limits be communicated to the user? results = { 'submission_result': None, 'answer_result': None, 'error': _("We could not execute your query; please try again."), 'comparison': None, } return ( results['submission_result'], results['answer_result'], results['error'], results['comparison'], )
def check_re(self, text): if self.match_substring: pattern = "{0}({1}){0}".format(r"(.|\n)*", self.pattern) else: pattern = self.pattern global_dict = {'matched': False, 'pattern': pattern, 'text': text} code = textwrap.dedent(""" import re match = re.match(pattern, text, {flags}) matched = match.group() == text if match else False """).format(flags='' if self.case_sensitive else 'flags=re.I') try: safe_exec.safe_exec(code, global_dict) except safe_exec.SafeExecException: score = False else: score = bool(global_dict['matched']) return score
def check(self, reply, clue): global_dict = {'matched': False, 'hint': '', 'answer': self.answer, 'reply': reply} code = textwrap.dedent(""" from sympy.parsing.sympy_parser import parse_expr from sympy.utilities.randtest import test_numerically from sympy import latex def compare(reply, answer): if (reply - answer).simplify() == 0: return True n_tries = 3 return all(test_numerically(reply, answer) for _ in range(n_tries)) def to_expr(s): return parse_expr(s.replace("^", "**")) answer = to_expr(answer) try: reply = to_expr(reply) except Exception: matched = False hint = 'failed to parse expression' else: hint = "understood answer as ${}$".format(latex(reply)) if not answer.free_symbols >= reply.free_symbols: matched = False else: matched = compare(reply, answer) """) try: safe_exec.safe_exec(code, global_dict) except safe_exec.SafeExecException: return False score = bool(global_dict['matched']) hint = '' if score == 0: hint = str(global_dict['hint']) return score, hint
def async_init(self): global_dict = {'answer': self.answer} code = textwrap.dedent(""" from sympy.core.compatibility import exec_ from sympy.parsing.sympy_parser import parse_expr exclude_symbols = ['N'] def to_expr(s): global_dict = {} exec_('from sympy import *', global_dict) for symbol in exclude_symbols: global_dict.pop(symbol) return parse_expr(s.replace("^", "**"), global_dict=global_dict) answer = to_expr(answer) """) try: safe_exec.safe_exec(code, global_dict, limits=self.LIMITS) except safe_exec.SafeExecException: raise FormatError('Failed to parse correct answer.')
def generate(self): self._random_context() self._random_variables() dataset = {'task': self.task} global_dict = { 'solve': self.solve, 'variables': self.variables, 'clue': '' } code = textwrap.dedent(""" from sympy import sympify import re str_exp = ' ' + str(solve) + ' ' for variable in variables: replace_value = variable['value'] if float(replace_value) < 0: replace_value = '({})'.format(replace_value) str_exp = re.sub(r'(?P<left>\W)%s(?P<right>\W)' % variable['name'], r'\g<left>%s\g<right>' % replace_value, str_exp) expr = sympify(str(str_exp)) clue = str(expr.evalf()) """) try: safe_exec.safe_exec(code, global_dict) except safe_exec.SafeExecException: return False, 'Cannot generate check function. Perhaps solve expression is wrong.' try: clue = float(parse_decimal(str(global_dict['clue']), 'dummy')) except FormatError: raise FormatError( "Error in solve expression. Perhaps one or more variable is not declared" ) return dataset, clue
def safe_exec(self, *args, **kwargs): safe_exec.safe_exec(*args, **kwargs)
def check(self, reply, clue): global_dict = {'matched': False, 'hint': '', 'answer': self.answer, 'z_re_min': self.z_re_min, 'z_re_max': self.z_re_max, 'z_im_min': self.z_im_min, 'z_im_max': self.z_im_max, 'max_error': self.max_error, 'integer_only': self.integer_only, 'reply': reply} # Below we use our own test_numerically function, because the original function # sympy.utilities.randtest.test_numerically has the following problems: # (1) it uses the relative error for comparison, that does not work well for very large values; # (2) it uses random real numbers, that does not work well some formulas. # see https://vyahhi.myjetbrains.com/youtrack/issue/EDY-4078 for more details. code = textwrap.dedent(""" from random import randint, uniform from sympy import I, Tuple, Symbol, latex from sympy.core.compatibility import exec_ from sympy.parsing.sympy_parser import parse_expr from sympy.utilities.randtest import comp exclude_symbols = ['N'] def random_number(): if integer_only: A, B = randint(z_re_min, z_re_max), randint(z_im_min, z_im_max) else: A, B = uniform(z_re_min, z_re_max), uniform(z_im_min, z_im_max) return A + I*B def test_numerically(f, g, z=None): f, g, z = Tuple(f, g, z) z = [z] if isinstance(z, Symbol) else (f.free_symbols | g.free_symbols) reps = list(zip(z, [random_number() for zi in z])) z1 = f.subs(reps).n() z2 = g.subs(reps).n() return comp(z1 - z2, 0, max_error) def compare(reply, answer): if answer.is_Relational: if not reply.is_Relational: return False, "The answer must be an inequality" return compare_inequalities(reply, answer) if reply.is_Relational: return False, "The answer must not be an inequality" return compare_expressions(reply, answer) def compare_expressions(reply, answer): if (reply - answer).simplify() == 0: return True if reply.is_Number and answer.is_Number: return bool(abs(reply - answer) <= max_error) n_tries = 10 return all(test_numerically(reply, answer) for _ in range(n_tries)) def compare_inequalities(reply, answer): # Compare two single inequalities reversed_rel_op = {'<': '>', '<=': '>=', '>': '<', '>=': '<='} if reply.rel_op == answer.rel_op: return compare_expressions(reply.lhs - reply.rhs, answer.lhs - answer.rhs) elif reversed_rel_op.get(reply.rel_op) == answer.rel_op: return compare_expressions(reply.rhs - reply.lhs, answer.lhs - answer.rhs) return False def to_expr(s): global_dict = {} exec_('from sympy import *', global_dict) for symbol in exclude_symbols: global_dict.pop(symbol) return parse_expr(s.replace("^", "**"), global_dict=global_dict) answer = to_expr(answer) try: reply = to_expr(reply) except Exception: matched = False hint = 'Failed to parse expression.' else: hint = "Understood answer as ${}$.".format(latex(reply)) if not answer.free_symbols >= reply.free_symbols: matched = False else: try: matched = compare(reply, answer) except Exception: matched = False hint += '\\nCannot check answer. Perhaps syntax is wrong.' else: if isinstance(matched, tuple): matched, feedback = matched hint += '\\n' + feedback """) try: safe_exec.safe_exec(code, global_dict, limits=self.LIMITS) except safe_exec.SafeExecException: return False, ('Timed out while checking the answer. ' 'Perhaps it is wrong or too complex.') score = bool(global_dict['matched']) hint = '' if score == 0: hint = str(global_dict['hint']) notation_feedback = [] for symbol, correct_symbol in SYMPY_NOTATION_MAP.items(): if re.search(r'\b{symbol}\b'.format(symbol=symbol), reply): notation_feedback.append('You wrote "{}", maybe you meant to write "{}".' .format(symbol, correct_symbol)) if hint and notation_feedback: hint += '\n' hint += '\n'.join(notation_feedback) return score, hint