def str_from_md(md_lines): st = StepString() md_part = [] WRDs = OneOrMore(WRD) ans_template = 'ANSWER:' + WRDs for line in md_lines: ans = None if line.startswith('SUBSTR:'): st.match_substring = bool_check('SUBSTR', line) continue if line.startswith('CASESENSE:'): st.case_sensitive = bool_check('CASESENSE', line) continue if line.startswith('USE_RE:'): st.use_re = bool_check('USE_RE', line) continue if line.startswith('ANSWER:'): ans = ans_template.parseString(line) st.pattern = ' '.join(ans[1:]) if ans is not None: st.text = html(md_part) return st else: # continue a question or answer md_part.append(line) return st
def from_lines(lines, task_root=None): """Create Step object from lines of markdown text, first line has ## [QUIZ] text return Step object """ lines[0] = lines[0].strip() # ## text | ## long text | ## QUIZ text h2, stype, *a = lines[0].split() if h2 != '##': logger.error('Expected step header format "## [QUIZ] text"') logger.error(f"now: {lines[0]}") return None if stype == 'QUIZ': st = StepMultipleChoice.from_aiken(lines[1:]) elif stype == 'NUMBER': st = StepNumber.num_from_md(lines[1:]) elif stype == 'STRING': st = StepString.str_from_md(lines[1:]) elif stype == 'TASK': st = StepTask.task_from_md(lines[1:], task_root) else: # Text st = Step() st.text = html(lines) return st
def num_from_md(md_lines): st = StepNumber() class Status(Enum): QUESTION = 0 ANSWER = 1 md_part = [] status = Status.QUESTION for line in md_lines: m = re.match(r"\s*ANSWER[:]*\s*(\d+)\s*\+?-?\s*(\d*)\s*", line) if m: exp = int(m.group(1)) var = int(m.group(2)) if m.group(2) != '' else 0 if status == Status.QUESTION: # first answer begin, question end status = Status.ANSWER st.text = html(md_part) st.add_answer(exp, var) elif status == Status.ANSWER: # next variant, commit previous variant st.add_answer(exp, var) else: m_answer = re.match(r'\s*END\s*', line) if m_answer and status == Status.ANSWER: # end of question return st else: # continue a question or answer md_part.append(line) return st
def from_lines(lines, param_dict): """Create Step object from lines of markdown text, first line has ## [QUIZ] text return Step object """ lines[0] = lines[0].strip() # ## text | ## long text | ## QUIZ text h2, stype, *a = lines[0].split() if h2 != '##': logger.error('Expected step header format "## [QUIZ] text"') logger.error(f"now: {lines[0]}") return None text_lines = [h2 + ' ' + ' '.join(a) + '\n' ] + lines[1:] if stype == 'QUIZ': st = StepMultipleChoice.from_aiken(text_lines) elif stype == 'NUMBER': st = StepNumber.num_from_md(text_lines) elif stype == 'STRING': st = StepString.str_from_md(text_lines) elif stype == 'TASK': st = StepTask.task_from_md(text_lines, param_dict) elif stype == 'TASKINLINE': st = StepTaskInline.task_from_md(text_lines, param_dict) elif stype == 'TASKTEXT': st = StepFreeResp.str_from_md(text_lines) elif stype == 'SKIP': st = StepSkip.str_from_md([]) else: # Text st = Step() st.text = html(lines) return st
def add_option(self, variant_md): """ Add 1 answer variant; correct=False by default :param variant_md: - 1 answer variant without leading A) in markdown format """ op = dict(StepMultipleChoice.OPTION_TEMPLATE) op['text'] = html(variant_md) self.options.append(op)
def from_aiken(md_lines): st = StepMultipleChoice() class Status(Enum): QUESTION = 0 VARIANT = 1 ANSWER = 3 letter_seq = [] # letter sequence from aiken variant, A, B, C, D, etc md_part = [] status = Status.QUESTION for line in md_lines: # Is it SHUFFLE option? m = re.match(r'SHUFFLE:\s*(\w+).*', line) if m: if m.group(1).lower() == 'true': st.preserve_order = False elif m.group(1).lower() == 'false': st.preserve_order = True else: logger.warning(f'Unknown value SHUFFLE: [{m.group(1)}]') continue # variant begin by A) or A. m = re.match(r'(\s*)([A-Z])([.)])(.*)', line) if m: letter = m.group(2) # sep = m.group(3) txt = m.group(4) + '\n' if status == Status.QUESTION: # first answer begin, question end status = Status.VARIANT st.text = html(md_part) elif status == Status.VARIANT: # next variant, commit previous variant st.add_option(md_part) md_part = [txt] letter_seq.append(letter) else: m_answer = re.match(r'\s*ANSWER[:]*\s*([A-Z, ]+)\s*', line) if m_answer and status == Status.VARIANT: # end of question st.add_option(md_part) logger.debug(f'group1 = {m_answer.group(1)}') letters = [s.strip() for s in m_answer.group(1).split(',')] logger.debug(f'letters={letters}') st.is_multiple_choice = len(letters) > 1 for letter in letters: ind = letter_seq.index(letter) st.options[ind]['is_correct'] = True return st else: # continue a question or answer md_part.append(line)
def end_state(self, mode, text): print(f'end state mode={mode}') if mode == InputState.Statement: self.text = html(text) elif mode == InputState.TestIn : self.test_input = text elif mode == InputState.TestOut : self.add_sample(to_text(self.test_input), to_text(text)) print(f'tests = {self.test_cases}') elif mode == InputState.Header : self.header = to_text(text) elif mode == InputState.Footer : self.footer = to_text(text) elif mode == InputState.Code : self.template = to_text(text) print(f'template = {self.template}') else: logger.warning(f'Unexpected inline task state={mode}')
def from_aiken(md_lines): st = StepMultipleChoice() WRDs = ZeroOrMore(WRD) opt_template = Char(alphas) + (Char(')') ^ Char('.')) + WRDs ans_template = 'ANSWER:' + OneOrMore(Char(alphas) + Char(',')[0, 1]) class Status(Enum): QUESTION = 0 VARIANT = 1 ANSWER = 3 letter_seq = [] # letter sequence from aiken variant, A, B, C, D, etc md_part = [] status = Status.QUESTION for line in md_lines: # Is it SHUFFLE option? """if line.startswith('SHUFFLE:'): sh = ('SHUFFLE:' + WRD).parseString(line) if sh[1].lower() == 'true': st.preserve_order = False elif sh[1].lower() == 'false': st.preserve_order = True else: logger.warning(f'Unknown value SHUFFLE: [{sh[1]}]') continue""" if line.startswith('SHUFFLE:'): st.preserve_order = not bool_check( 'SHUFFLE', line ) # единсвенная проблема в том, что при неправильном написании true или false будет автоматом ставиться true continue # variant begin by A) or A. if line == opt_template: opt = opt_template.parseString(line) letter = opt[0] txt = ' '.join(opt[2:]) if status == Status.QUESTION: # first answer begin, question end status = Status.VARIANT st.text = html(md_part) elif status == Status.VARIANT: # next variant, commit previous variant st.add_option(md_part) md_part = [txt] letter_seq.append(letter) elif line == ans_template and status == Status.VARIANT: # end of question st.add_option(md_part) ans = ans_template.parseString(line) ans_str = " ".join(ans[1:]) logger.debug(f'group1 = {ans_str}') letters = [s.strip() for s in ans_str.split(',')] logger.debug(f'letters={letters}') st.is_multiple_choice = len(letters) > 1 for letter in letters: ind = letter_seq.index(letter) st.options[ind]['is_correct'] = True return st else: # continue a question or answer md_part.append(line)
def str_from_md(md_lines): st = StepFreeResp() st.text = html(md_lines) return st