def translate_program(cls, program): from core.utils import clean_spaces program = clean_spaces(program) if cls.auto_translate_program: result = translate_code(program) else: result = get(step_program(cls), program) return clean_spaces(result)
def clean_program(program, cls): if callable(program) and not cls.auto_translate_program: program = inspect.getsource(program).splitlines()[1:] if not callable(program): program = clean_spaces(program) if not is_valid_syntax(program): cls.auto_translate_program = False cls.show_solution_program = program = t.translate_program(cls, program) return program func = program source = t.translate_program(cls, inspect.getsource(program)) globs = func.__globals__ # noqa exec(source, globs) func = globs[t.get_code_bit(func.__name__)] func = MethodType(func, "") lines = source.splitlines() cls.is_function_exercise = lines[-1].strip().startswith("return ") if cls.is_function_exercise: func = func() assert lines[0] == f"def {t.get_code_bit('solution')}(self):" assert lines[-1] == f" return {func.__name__}" source = clean_spaces(lines[1:-1]) source = program = clean_solution_function(func, source) tree = ast.parse(source) if not any( isinstance(node, ast.Return) for node in ast.walk(tree) ) and not getattr(cls, "no_returns_stdout", False): func = returns_stdout(func) func = add_stdin_input_arg(func) func = NoMethodWrapper(func) cls.solution = func func_node = function_node(func, tree) if cls.is_function_exercise: cls.show_solution_program = ast.get_source_segment(source, func_node) else: lines = lines[func_node.body[0].lineno - 1 :] cls.show_solution_program = program = clean_spaces(lines) if hasattr(cls, "test_values"): [[inputs, _result]] = itertools.islice(cls.test_values(), 1) cls.stdin_input = inputs.pop("stdin_input", []) if inputs: inputs = inputs_string(inputs) program = inputs + "\n" + program compile(program, "<program>", "exec") # check validity return program
def __init__(cls, *args, **kwargs): super().__init__(*args, **kwargs) if cls.__name__ == "Page": return pages[cls.slug] = cls page_slugs_list.append(cls.slug) cls.step_names = [] for key, value in cls.__dict__.items(): if getattr(value, "is_step", False): cls.step_names.append(key) cls.final_text = clean_spaces(cls.final_text) cls.final_text = t.get(t.step_text(cls.slug, "final_text"), cls.final_text) cls.final_text = clean_spaces(cls.final_text) cls.step_names.append("final_text")
def __init__(self, template, *, label="", message="", max_count=0, predicate=lambda n: True, function_only=False): assert bool(label) ^ bool(message) self.label = label self.message = clean_spaces(message) self.max_count = max_count self.predicate = predicate self.function_only = function_only self.template = template
def setup(self, step_cls, i): label = self.label and t.get(t.disallowed_label(step_cls, i), self.label) message = self.message and t.get(t.disallowed_message(step_cls, i), self.message) if not message: if self.max_count > 0: label = t.Terms.disallowed_default_label.format( max_count=self.max_count, label=label ) message = t.Terms.disallowed_default_message.format(label=label) self.text = clean_spaces(message)
def clean_step_class(cls): assert cls.__name__ != "step_name_here" text = cls.text or cls.__doc__ program = cls.program hints = cls.hints solution = cls.__dict__.get("solution", "") assert bool(solution) ^ bool(program) if issubclass(cls, ExerciseStep) and not issubclass(cls, MessageStep): assert cls.hints, cls if solution: assert cls.tests assert cls.auto_translate_program cls.solution = MethodType(solution, "") program = clean_program(cls.solution, cls) # noqa cls.solution = cls.wrap_solution(cls.solution) if not issubclass(cls, MessageStep) or cls.after_success: cls.test_exercise(cls.solution) else: program = clean_program(program, cls) assert program if isinstance(hints, str): hints = hints.strip().splitlines() hints = [t.get(t.hint(cls, i), hint.strip()) for i, hint in enumerate(hints)] text = clean_spaces(text) assert text text = t.get(cls.text_msgid, text) text = clean_spaces(text) cls.raw_text = text if "__program_" in text: text = text.replace("__program__", program) indented = indent(program, ' ').replace("\\", "\\\\") text = re.sub(r" *__program_indented__", indented, text, flags=re.MULTILINE) else: assert not cls.program_in_text, ( "Either include __program__ or __program_indented__ in the text, " "or set program_in_text = False in the class.", cls, text, ) assert "__program_" not in text, (cls, text) text = clean_spaces(text) for special_message in get_special_messages(cls): msgstr = clean_spaces(special_message.__doc__ or special_message.text) msgstr = t.get(t.special_message_text(cls, special_message), msgstr) special_message.text = msgstr try: special_message.program = t.translate_code(special_message.program) except SyntaxError: pass messages = [] for name, inner_cls in inspect.getmembers(cls): if not (isinstance(inner_cls, type) and issubclass(inner_cls, Step)): continue assert issubclass(inner_cls, MessageStep) inner_cls.tests = inner_cls.tests or cls.tests inner_cls.generate_inputs = getattr(cls, "generate_inputs", None) inner_cls.page = cls.page inner_cls.text_msgid = t.message_step_text(cls, inner_cls) clean_step_class(inner_cls) original_inner_cls = inner_cls # noinspection PyAbstractClass class inner_cls(inner_cls, cls): __qualname__ = inner_cls.__qualname__ __module__ = inner_cls.__module__ inner_cls.__name__ = original_inner_cls.__name__ messages.append(inner_cls) if inner_cls.after_success and issubclass(inner_cls, ExerciseStep): cls.check_exercise(inner_cls.solution) setattrs(cls, text=text, program=program, messages=messages, hints=hints) if hints: cls.get_solution = get_solution(cls) if isinstance(cls.disallowed, Disallowed): cls.disallowed = [cls.disallowed] for i, disallowed in enumerate(cls.disallowed): disallowed.setup(cls, i) if cls.expected_code_source: getattr(t.Terms, f"expected_mode_{cls.expected_code_source}")