Esempio n. 1
0
def clean_program(program, cls):
    func = program
    if isinstance(program, FunctionType):
        source = dedent(inspect.getsource(program))
        lines = source.splitlines()
        if lines[-1].strip().startswith("return "):
            func = NoMethodWrapper(program(None))
            assert lines[0] == "def solution(self):"
            assert lines[-1] == f"    return {func.__name__}"
            source = dedent("\n".join(lines[1:-1]))
            program = clean_solution_function(func, source)
        else:
            atok = ASTTokens(source, parse=True)
            func_node = atok.tree.body[0]
            lines = lines[func_node.body[0].first_token.start[0] - 1:]
            if hasattr(cls, "test_values"):
                inputs = list(cls.test_values())[0][0]
            else:
                inputs = {}
            inputs = inputs_string(inputs)
            program = inputs + '\n' + dedent('\n'.join(lines))
        compile(program, "<program>", "exec")  # check validity

        if not any(isinstance(node, ast.Return) for node in ast.walk(ast.parse(source))):
            func = returns_stdout(func)

    no_weird_whitespace(program)
    return program.strip(), func
Esempio n. 2
0
def clean_program(program, inputs=None):
    if callable(program):
        inputs = inputs_string(inputs or {})
        source = dedent(inspect.getsource(program))
        atok = ASTTokens(source, parse=True)
        func = atok.tree.body[0]
        lines = source.splitlines()[func.body[0].first_token.start[0] - 1:]
        program = inputs + '\n' + dedent('\n'.join(lines))
        compile(program, "<program>", "exec")  # check validity
    no_weird_whitespace(program)
    return program.strip()
Esempio n. 3
0
    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 = markdown(cls.final_text.strip())
        cls.step_names.append("final_text")
        cls.step_texts.append(cls.final_text)
Esempio n. 4
0
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]
Esempio n. 5
0
def clean_step_class(cls, clean_inner=True):
    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
        # noinspection PyUnresolvedReferences
        inputs = list(cls.test_values())[0][0]
        program = clean_program(solution, inputs)
    else:
        program = clean_program(program)
    assert program

    if isinstance(hints, str):
        hints = hints.strip().splitlines()
    hints = [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 = markdown(dedent(text).strip())

    messages = []
    if clean_inner:
        for name, inner_cls in inspect.getmembers(cls):
            if not (isinstance(inner_cls, type)
                    and issubclass(inner_cls, Step)):
                continue

            if 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__
                    program_in_text = inner_cls.program_in_text

                messages.append(inner_cls)

                if inner_cls.after_success and issubclass(
                        inner_cls, ExerciseStep):
                    check_exercise(
                        partial(inner_cls.solution, None),
                        partial(cls.solution, None),
                        cls.test_exercise,
                        cls.generate_inputs,
                    )

            clean_step_class(inner_cls, clean_inner=False)

    setattrs(cls, text=text, program=program, messages=messages, hints=hints)