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 = [] cls.step_texts = [] for key, value in cls.__dict__.items(): if getattr(value, "is_step", False): clean_step_class(value) cls.step_names.append(key) cls.step_texts.append(value.text) assert isinstance(cls.final_text, str) no_weird_whitespace(cls.final_text) cls.final_text = highlighted_markdown(cls.final_text.strip()) cls.step_names.append("final_text") cls.step_texts.append(cls.final_text) assert "__copyable__" not in str(cls.step_texts)
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) assert text no_weird_whitespace(text) if solution: assert cls.tests program, cls.solution = clean_program(solution, cls) else: program, _ = clean_program(program, cls) assert program if isinstance(hints, str): hints = hints.strip().splitlines() hints = [highlighted_markdown(hint) for hint in hints] if "__program_" in text: text = text.replace("__program__", program) indented = indent(program, ' ') 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." assert "__program_" not in text text = highlighted_markdown(dedent(text).strip()) 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 clean_step_class(inner_cls) # noinspection PyAbstractClass class inner_cls(inner_cls, cls): __name__ = inner_cls.__name__ __qualname__ = inner_cls.__qualname__ __module__ = inner_cls.__module__ messages.append(inner_cls) if inner_cls.after_success and issubclass(inner_cls, ExerciseStep): check_exercise( bind_self(inner_cls.solution), bind_self(cls.solution), cls.test_exercise, cls.generate_inputs, ) setattrs(cls, text=text, program=program, messages=messages, hints=hints) if hints: cls.get_solution = get_solution(cls) if cls.predicted_output_choices: cls.predicted_output_choices.append("Error") cls.predicted_output_choices = [ s.rstrip() for s in cls.predicted_output_choices ] if not cls.correct_output: cls.correct_output = get_stdout(cls.program).rstrip() assert cls.correct_output in cls.predicted_output_choices assert cls.correct_output != "Error" assert cls.correct_output if isinstance(cls.disallowed, Disallowed): cls.disallowed = [cls.disallowed]
class API: def __init__(self, request): self.request = request @property def user(self) -> User: return self.request.user def run_code(self, code, source, page_index, step_index): page_slug = page_slugs_list[page_index] entry_dict = dict( input=code, source=source, page_slug=page_slug, step_name=pages[page_slug].step_names[step_index], user_id=self.user.id, ) entry = None if settings.SAVE_CODE_ENTRIES: entry = CodeEntry.objects.create(**entry_dict) result = worker_result(entry_dict) if settings.SAVE_CODE_ENTRIES: entry.output = result["output"] entry.save() if result["error"]: return dict(error=result["error"]) if passed := result["passed"]: self.move_step(page_index, step_index + 1) output_parts = result["output_parts"] if not result["awaiting_input"]: output_parts.append(dict(text=">>> ", color="white")) birdseye_url = None birdseye_objects = result["birdseye_objects"] if birdseye_objects: functions = birdseye_objects["functions"] top_old_function_id = only(f["id"] for f in functions if f["name"] == "<module>") function_ids = [d.pop('id') for d in functions] functions = [ eye.db.Function(**{ **d, 'hash': uuid4().hex }) for d in functions ] with eye.db.session_scope() as session: for func in functions: session.add(func) session.commit() function_ids = { old: func.id for old, func in zip(function_ids, functions) } call_id = None for call in birdseye_objects["calls"]: old_function_id = call["function_id"] is_top_call = old_function_id == top_old_function_id call["function_id"] = function_ids[old_function_id] call["start_time"] = datetime.fromisoformat( call["start_time"]) call = eye.db.Call(**call) session.add(call) if is_top_call: call_id = call.id birdseye_url = f"/birdseye/call/{call_id}" return dict( result=output_parts, message=highlighted_markdown(result["message"]), state=self.current_state(), birdseye_url=birdseye_url, passed=passed, )