Skip to content

Commit

Permalink
Updated Cloze to new QQuestion
Browse files Browse the repository at this point in the history
Also worked on aiken again, since things still changing
  • Loading branch information
LucasWolfgang committed Oct 10, 2023
1 parent 7660fca commit 1e2f3aa
Show file tree
Hide file tree
Showing 14 changed files with 406 additions and 218 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ disable = ["C0302", # Too many lines in module
"W0511", # TODO's. Not necessary
"W0223", # Method is abstract is not overridden. Used as documentation
"R0912",
"E0401"
"E0401",
"W0122"
#"W0212" # Access to a protected member. Internal methods need to access protected member.
] # but it will be good to revise this one later.

Expand Down
63 changes: 35 additions & 28 deletions qas_editor/answer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
from __future__ import annotations

import logging
from typing import Callable, List
from typing import TYPE_CHECKING, Callable, List

from .enums import (Direction, EmbeddedFormat, ShapeType, TextFormat,
TolFormat, TolType)
from .enums import (Direction, EmbeddedFormat, Orientation, ShapeType,
TextFormat, TolFormat, TolType)
from .parsers.text import FText
from .utils import File, Serializable
from .processors import Proc
from .utils import File

_LOG = logging.getLogger(__name__)

Expand All @@ -44,10 +45,6 @@ def __init__(self, feedbacks: List[FText] = None,
self._proc = None
self._feedbacks = feedbacks
self._hints = hints
self._options: List = []

def __iter__(self):
return iter(self._options)

@property
def feedbacks(self) -> List[FText]:
Expand All @@ -62,24 +59,15 @@ def hints(self) -> List[FText]:
return self._hints

@property
def options(self) -> List:
"""_summary_
Returns:
List[Choice]: _description_
"""
return self._options

@property
def processor(self) -> str:
def processor(self) -> Proc:
"""Function that does the processing part (define grades, when hints
will be shown, etc). Stored in text format.
"""
return self._proc

@processor.setter
def processor(self, value):
if isinstance(value, str):
exec(value) # Ignore the result. What we want is no Exception here
if isinstance(value, Proc):
self._proc = value

def check(self):
Expand Down Expand Up @@ -108,17 +96,36 @@ class ChoicesItem(Item):
"""This is the basic class used to hold possible answers
"""
MARKER_INT = 9635
ITEM_TYPE = Choice

def __init__(self, feedbacks: List[FText] = None,
hints: List[FText] = None):
super().__init__(feedbacks, hints)
self._options: List = []
self.shuffle = False
self.max_choices: int = 1
self.min_choices: int = 0
self.orientation: Orientation = Orientation.VER
self.min_smsg = "Not enough options selected"
self.max_smsg = "Selected options exceed maximum"

@property
def options(self) -> List[Choice]: # Only for type checking
def options(self) -> List[Choice]:
"""_summary_
Returns:
List[Choice]: _description_
"""
return self._options

def check(self):
return True


class Answer(Serializable):
class EntryItem(Item):
"""Represent an input entry.
"""


class Answer:
"""
This is the basic class used to hold possible answers
"""
Expand Down Expand Up @@ -155,7 +162,7 @@ def __init__(self, alength=2, ttype: TolType = None,
self.alength = alength


class EmbeddedItem(Serializable):
class EmbeddedItem:
"""A cloze item. It is embedded in parts of the question text marked by
the <code>MARKER_INT</code> from the questions.py file. This item defile
a question, which possible types are enumerated in <code>ClozeFormat</code>
Expand Down Expand Up @@ -188,7 +195,7 @@ def to_cloze(self) -> str:
return "".join(text)


class DragItem(Serializable):
class DragItem:
"""A dragable item. Use it as base for other "Drag" classes.
All dragable objects have a text parameter, which may be showed in the
canvas, or just used to identify the item.
Expand Down Expand Up @@ -219,7 +226,7 @@ def __init__(self, image: File = None, **kwargs):
self.image = image


class DropZone(Serializable):
class DropZone:
"""A zone where dragable items can be placed. They are related to the
items matching the item number to the zone choise. Zone number is used
only to enumerate the zone.
Expand All @@ -237,7 +244,7 @@ def __init__(self, coord_x: int, coord_y: float, choice: float,
self.number = number


class ACrossWord(Serializable):
class ACrossWord:
"""_summary_
"""

Expand All @@ -250,7 +257,7 @@ def __init__(self, word: str, coord_x: int, coord_y: int, clue: str,
self.clue = clue


class Subquestion(Serializable):
class Subquestion:
"""_summary_
"""

Expand All @@ -261,7 +268,7 @@ def __init__(self, text: str, answer: str, formatting: TextFormat = None):
self.formatting = formatting if formatting else TextFormat.AUTO


class SelectOption(Serializable):
class SelectOption:
"""Internal representation
"""

Expand Down
4 changes: 2 additions & 2 deletions qas_editor/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from .parsers import (aiken, cloze, csv_card, gift, ims, kahoot, latex,
markdown, moodle, olx)
from .question import QQuestion, _Question
from .utils import File, Serializable
from .utils import File

if TYPE_CHECKING:
from .utils import Dataset
Expand All @@ -47,7 +47,7 @@
EXTS = ";;".join(f"{k}(*.{v[2]})" for k,v in SERIALIZERS.items())


class Category(Serializable): # pylint: disable=R0904
class Category: # pylint: disable=R0904
"""A category is a set of questions and other category that have enough
similarities to be grouped together.
"""
Expand Down
18 changes: 12 additions & 6 deletions qas_editor/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ def values(self) -> list:
class EmbeddedFormat(EnhancedEnum):
"""Enumerates Cloze formats
"""
SA = "SHORTANSWER", "MW", "SA", "Short, Case Insensitive"
SAC = "SHORTANSWER_C", "MWC", "SAC", "Short, Case Sensitive"
NUM = "NUMERICAL", "NM", "Numerical"
MC = "MULTICHOICE", "MC", "Multichoice, dropdown"
MVC = "MULTICHOICE_V", "MVC", "Multichoice, vertical column"
MC = "MULTICHOICE", "MC", "MCV", "MULTICHOICE_V", "Multichoice, dropdown"
MCH = "MULTICHOICE_H", "MCH", "Multichoice, horizontal row"
MR = "MULTIRESPONSE", "MR", "Multichoice, vertical row"
MR = "MULTIRESPONSE", "MR", "Multichoice, vertical column"
MRH = "MULTIRESPONSE_H", "MRH", "Multichoice, horizontal row"
NUM = "NUMERICAL", "NM", "Numerical"
SA = "SHORTANSWER", "MW", "SA", "Short, Case Insensitive"
SAC = "SHORTANSWER_C", "MWC", "SAC", "Short, Case Sensitive"


class Direction(EnhancedEnum):
Expand Down Expand Up @@ -133,6 +132,13 @@ class OutFormat(Enum):
GIFT = auto()


class Orientation(Enum):
"""_summary_
"""
HOR = auto()
VER = auto()


class ShapeType(Enum):
"""Enumerates Shape Types
"""
Expand Down
16 changes: 9 additions & 7 deletions qas_editor/parsers/aiken.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
import re
from typing import TYPE_CHECKING, Type

from .. import processors as pcsr
from ..answer import Choice, ChoicesItem
from ..enums import Language
from ..processors import PROCESSORS
from ..question import QMultichoice, QQuestion
from ..question import QQuestion

if TYPE_CHECKING:
from ..category import Category
Expand Down Expand Up @@ -54,7 +54,8 @@ def _from_question(buffer, line: str, name: str, language: Language):
simple_choice.options.append(Choice(match[1]))
question.body[language].text.append(header.strip())
question.body[language].text.append(simple_choice)
simple_choice.processor = PROCESSORS["multichoice"].format(index=target)
mapper = {target: {"value": 100}}
simple_choice.processor = pcsr.Proc(pcsr.mapper, mapper)
return question


Expand Down Expand Up @@ -93,14 +94,15 @@ def write_aiken(category: Category, language: Language, file_path: str) -> None:
"""
def _to_aiken(cat: Category, writer):
for question in cat.questions:
if (len(question.body[language]) == 2 and
if (len(question.body[language]) == 2 and
isinstance(question.body[language][1], ChoicesItem)):
writer(f"{question.body[language].text[0]}\n")
correct = "ANSWER: None\n\n"
exec(question.body[language].text[1].processor, globals())
for num, ans in enumerate(question.body[language].text[1]):
proc = question.body[language].text[1].processor
opts = question.body[language].text[1].options
for num, ans in enumerate(opts):
writer(f"{chr(num+65)}) {ans}\n")
if processor(num) == 100.0:
if proc.func(num)["value"] == 100.0:
correct = f"ANSWER: {chr(num+65)}\n\n"
writer(correct)
for name in cat:
Expand Down
Loading

0 comments on commit 1e2f3aa

Please sign in to comment.