excel2moodle 0.3.3__py3-none-any.whl → 0.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
excel2moodle/__init__.py CHANGED
@@ -1,14 +1,20 @@
1
1
  """This Python program helps to create Moodle questions in less time.
2
2
 
3
- The aim is to put alle the information for the questions into a spreadsheet file, and then parse it, to generate Moodle compliant XML-Files.
4
- Furthermore this program lets you create a single ``.xml``-File with a selection of questions, that then can be imported to a Moodle-Test.
3
+ The aim is to put alle the information for the questions into a spreadsheet
4
+ file, and then parse it, to generate Moodle compliant XML-Files.
5
+ Furthermore this program lets you create a single ``.xml``-File with a selection
6
+ of questions, that then can be imported to a Moodle-Test.
5
7
 
6
8
  Concept
7
9
  =========
8
- The concept is, to store the different questions into categories of similar types and difficulties of questions, for each of which, a separated sheet in the Spreadsheet document should be created.
9
-
10
- There Should be a sheet called *"Kategorien"*, where an overview over the different categories is stored.
11
- This sheet stores The names and descriptions, for all categories. The name have to be the same as the actual sheet names with the questions.
10
+ The concept is, to store the different questions into categories of similar
11
+ types and difficulties of questions, for each of which, a separated sheet in
12
+ the Spreadsheet document should be created.
13
+
14
+ There Should be a sheet called *"Kategorien"*, where an overview over the
15
+ different categories is stored.
16
+ This sheet stores The names and descriptions, for all categories.
17
+ The name have to be the same as the actual sheet names with the questions.
12
18
  Furthermore the points used for grading, are set in the "Kategorien" sheet
13
19
 
14
20
  Functionality
@@ -17,26 +23,33 @@ Functionality
17
23
  * Parse Numeric Questions, each into one XML file
18
24
  * create single XML File from a selection of questions
19
25
  """
26
+
20
27
  from importlib import metadata
21
28
  from importlib.metadata import version
29
+
22
30
  try:
23
31
  __version__ = version("excel2moodle")
24
32
  except Exception:
25
33
  __version__ = "unknown"
26
34
 
27
35
 
28
- if not __package__ == None:
36
+ if __package__ is not None:
29
37
  meta = metadata.metadata(__package__)
30
- e2mMetadata:dict = {
38
+ e2mMetadata: dict = {
31
39
  "version": __version__,
32
- "name": meta['name'],
33
- "description": meta['summary'],
34
- "author": meta['author'],
35
- "license": meta['license-expression'],
40
+ "name": meta["name"],
41
+ "description": meta["summary"],
42
+ "author": meta["author"],
43
+ "license": meta["license-expression"],
36
44
  "documentation": "https://jbosse3.gitlab.io/excel2moodle",
37
- "homepage": meta['project-url'].split()[1],
45
+ "homepage": meta["project-url"].split()[1],
38
46
  "issues": "https://gitlab.com/jbosse3/excel2moodle/issues",
39
- }
47
+ }
48
+
49
+ import logging as logging
50
+ from logging import config as logConfig
51
+
52
+ from PySide6.QtCore import QObject, Signal
40
53
 
41
54
  # from excel2moodle.core import klausurGenerator
42
55
  # from excel2moodle.core import numericMultiQ
@@ -48,67 +61,63 @@ if not __package__ == None:
48
61
  # from excel2moodle.ui import kGeneratorQt
49
62
  from excel2moodle.ui import settings
50
63
 
51
- from PySide6.QtCore import QObject, Signal
52
- import logging as logging
53
- from logging import config as logConfig
54
-
55
64
  loggerConfig = {
56
- 'version': 1,
57
- 'disable_existing_loggers': False,
58
- 'formatters': {
59
- 'standard': {
60
- 'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
61
- },
65
+ "version": 1,
66
+ "disable_existing_loggers": False,
67
+ "formatters": {
68
+ "standard": {"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"},
62
69
  },
63
- 'handlers': {
64
- 'default': {
65
- 'level': 'DEBUG',
66
- 'formatter': 'standard',
67
- 'class': 'logging.StreamHandler',
68
- 'stream': 'ext://sys.stdout', # Default is stderr
70
+ "handlers": {
71
+ "default": {
72
+ "level": "DEBUG",
73
+ "formatter": "standard",
74
+ "class": "logging.StreamHandler",
75
+ "stream": "ext://sys.stdout", # Default is stderr
69
76
  },
70
77
  },
71
- 'loggers': {
72
- '': { # root logger
73
- 'handlers': ['default'],
74
- 'level': 'DEBUG',
75
- 'propagate': True
78
+ "loggers": {
79
+ "": { # root logger
80
+ "handlers": ["default"],
81
+ "level": "DEBUG",
82
+ "propagate": True,
76
83
  },
77
- 'excel2moodle.questionParser': {
78
- 'handlers': ['default'],
79
- 'level': 'DEBUG',
80
- 'propagate': True
84
+ "excel2moodle.questionParser": {
85
+ "handlers": ["default"],
86
+ "level": "DEBUG",
87
+ "propagate": True,
81
88
  },
82
- '__main__': { # if __name__ == '__main__'
83
- 'handlers': ['default'],
84
- 'level': 'DEBUG',
85
- 'propagate': True
89
+ "__main__": { # if __name__ == '__main__'
90
+ "handlers": ["default"],
91
+ "level": "DEBUG",
92
+ "propagate": True,
86
93
  },
87
- }
94
+ },
88
95
  }
89
96
 
97
+
90
98
  class QSignaler(QObject):
91
99
  signal = Signal(str)
92
100
 
101
+
93
102
  class LogHandler(logging.Handler):
94
- def __init__(self, *args, **kwargs)->None:
95
- super().__init__(*args,**kwargs)
103
+ def __init__(self, *args, **kwargs) -> None:
104
+ super().__init__(*args, **kwargs)
96
105
  self.emitter = QSignaler()
97
- # Define a formatter with log level and module
106
+ # Define a formatter with log level and module
98
107
  log_format = "[%(levelname)s] %(module)s: %(message)s"
99
108
  self.formatter = logging.Formatter(log_format)
100
109
  self.setFormatter(self.formatter)
101
110
  self.logLevelColors = {
102
- 'DEBUG': 'gray',
103
- 'INFO': 'green',
104
- 'WARNING': 'orange',
105
- 'ERROR': 'red',
106
- 'CRITICAL': 'pink'
111
+ "DEBUG": "gray",
112
+ "INFO": "green",
113
+ "WARNING": "orange",
114
+ "ERROR": "red",
115
+ "CRITICAL": "pink",
107
116
  }
108
117
 
109
- def emit(self, record)->None:
118
+ def emit(self, record) -> None:
110
119
  log_message = self.format(record)
111
- color = self.logLevelColors.get(record.levelname, 'black')
120
+ color = self.logLevelColors.get(record.levelname, "black")
112
121
  prettyMessage = f'<span style="color:{color};">{log_message}</span>'
113
122
  self.emitter.signal.emit(prettyMessage)
114
123
  return None
@@ -123,5 +132,5 @@ qSignalLogger = LogHandler()
123
132
  logger.addHandler(qSignalLogger)
124
133
 
125
134
 
126
- for k,v in e2mMetadata.items():
135
+ for k, v in e2mMetadata.items():
127
136
  print(f"{k}: \t {v}\n")
excel2moodle/__main__.py CHANGED
@@ -2,20 +2,20 @@
2
2
 
3
3
  from PySide6 import QtWidgets, sys
4
4
 
5
- from excel2moodle.core import dataStructure
5
+ from excel2moodle.core import dataStructure
6
6
  from excel2moodle.ui import appUi as ui
7
7
  from excel2moodle.ui.settings import Settings
8
8
 
9
9
 
10
- def main()->None:
10
+ def main() -> None:
11
11
  app = QtWidgets.QApplication(sys.argv)
12
12
  settings = Settings()
13
- database:dataStructure.QuestionDB = dataStructure.QuestionDB(settings)
13
+ database: dataStructure.QuestionDB = dataStructure.QuestionDB(settings)
14
14
  window = ui.MainWindow(settings, database)
15
15
  database.window = window
16
16
  window.show()
17
17
  sys.exit(app.exec())
18
18
 
19
- if __name__ =="__main__":
20
- main()
21
19
 
20
+ if __name__ == "__main__":
21
+ main()
@@ -1,27 +1,38 @@
1
-
2
1
  import logging
3
- import pandas as pd
2
+
4
3
  import lxml.etree as ET
4
+ import pandas as pd
5
5
 
6
- from excel2moodle.core.exceptions import InvalidFieldException
7
- from excel2moodle.core.questionValidator import Validator
8
- logger = logging.getLogger(__name__)
6
+ from excel2moodle.core.parser import (
7
+ MCQuestionParser,
8
+ NFMQuestionParser,
9
+ NFQuestionParser,
10
+ QNotParsedException,
11
+ )
9
12
  from excel2moodle.core.question import Question
10
13
 
11
- from excel2moodle.core.globals import XMLTags, TextElements, DFIndex, questionTypes, parserSettings
12
- from excel2moodle.core.parser import NFMQuestionParser, NFQuestionParser, MCQuestionParser, QNotParsedException
14
+ logger = logging.getLogger(__name__)
15
+
13
16
 
14
- class Category():
15
- def __init__(self, n:int, name:str, description:str, dataframe: pd.DataFrame, points:float=0, version:int=0)->None:
17
+ class Category:
18
+ def __init__(
19
+ self,
20
+ n: int,
21
+ name: str,
22
+ description: str,
23
+ dataframe: pd.DataFrame,
24
+ points: float = 0,
25
+ version: int = 0,
26
+ ) -> None:
16
27
  self.n = n
17
28
  self.NAME = name
18
29
  self.desc = str(description)
19
- self.dataframe:pd.DataFrame = dataframe
30
+ self.dataframe: pd.DataFrame = dataframe
20
31
  self.points = points
21
32
  self.version = int(version)
22
- self.questions:dict[int,Question] = {}
23
- self.maxVariants:int|None = None
24
- logger.info(f"initializing {self.NAME =}")
33
+ self.questions: dict[int, Question] = {}
34
+ self.maxVariants: int | None = None
35
+ logger.info(f"initializing {self.NAME=}")
25
36
 
26
37
  @property
27
38
  def name(self):
@@ -39,41 +50,50 @@ class Category():
39
50
  return self.NAME == other.NAME
40
51
  return False
41
52
 
42
- def parseQ(self, q:Question, questionData:dict|None=None, xmlTree:ET._Element|None=None)->bool:
53
+ def parseQ(
54
+ self,
55
+ q: Question,
56
+ questionData: dict | None = None,
57
+ xmlTree: ET._Element | None = None,
58
+ ) -> bool:
43
59
  if q.element is not None:
44
60
  logger.info(f"Question {q.id} is already parsed")
45
61
  return True
46
62
  else:
47
63
  if q.qtype == "NF":
48
- parser = NFQuestionParser( q, questionData)
49
- logger.debug(f"setup a new NF parser ")
64
+ parser = NFQuestionParser(q, questionData)
65
+ logger.debug("setup a new NF parser ")
50
66
  elif q.qtype == "MC":
51
- parser = MCQuestionParser( q, questionData)
52
- logger.debug(f"setup a new MC parser ")
67
+ parser = MCQuestionParser(q, questionData)
68
+ logger.debug("setup a new MC parser ")
53
69
  elif q.qtype == "NFM":
54
- parser = NFMQuestionParser( q, questionData)
55
- logger.debug(f"setup a new NFM parser ")
56
- else:
57
- logger.error(f"ERROR, couldn't setup Parser")
70
+ parser = NFMQuestionParser(q, questionData)
71
+ logger.debug("setup a new NFM parser ")
72
+ else:
73
+ logger.error("ERROR, couldn't setup Parser")
58
74
  return False
59
75
  try:
60
76
  parser.parse(xmlTree=xmlTree)
61
77
  return True
62
78
  except QNotParsedException as e:
63
- logger.critical(f"The Question {q.id} couldn't be parsed", exc_info=e, stack_info=True)
79
+ logger.critical(
80
+ f"The Question {q.id} couldn't be parsed",
81
+ exc_info=e,
82
+ stack_info=True,
83
+ )
64
84
  return False
65
85
  finally:
66
86
  del parser
67
87
 
68
- def getCategoryHeader(self)->ET.Element:
69
- """vor den Fragen einer Kategorie wird ein <question type='category'> eingefügt mit Name und Beschreibung"""
70
- header = ET.Element('question', type='category')
71
- cat = ET.SubElement(header,"category")
72
- info = ET.SubElement(header,"info", format='html')
73
- ET.SubElement(cat,"text").text = f"$module$/top/{self.NAME}"
74
- ET.SubElement(info,"text").text = str(self.desc)
75
- ET.SubElement(header,"idnumber").text = str(self.n)
88
+ def getCategoryHeader(self) -> ET.Element:
89
+ """vor den Fragen einer Kategorie wird ein
90
+ <question type='category'> eingefügt mit Name und Beschreibung
91
+ """
92
+ header = ET.Element("question", type="category")
93
+ cat = ET.SubElement(header, "category")
94
+ info = ET.SubElement(header, "info", format="html")
95
+ ET.SubElement(cat, "text").text = f"$module$/top/{self.NAME}"
96
+ ET.SubElement(info, "text").text = str(self.desc)
97
+ ET.SubElement(header, "idnumber").text = str(self.n)
76
98
  ET.indent(header)
77
99
  return header
78
-
79
-
@@ -1,87 +1,100 @@
1
- """Main Module which does the heavy lifting
1
+ """Main Module which does the heavy lifting
2
2
 
3
3
  At the heart is the class ``xmlTest``
4
4
  """
5
5
 
6
+ import logging
6
7
  from pathlib import Path
7
- from PySide6 import QtCore
8
- from PySide6 import QtWidgets
8
+
9
+ import lxml.etree as ET
10
+ import pandas as pd
11
+ from PySide6 import QtCore, QtWidgets
9
12
  from PySide6.QtCore import Signal
10
13
  from PySide6.QtWidgets import QMainWindow, QMessageBox, QTreeWidget
11
- import pandas as pd
12
- import lxml.etree as ET
13
- import logging
14
14
 
15
15
  from excel2moodle import QSignaler
16
16
  from excel2moodle.core import stringHelpers
17
17
  from excel2moodle.core.category import Category
18
- from excel2moodle.ui.dialogs import QuestionVariantDialog
19
- from excel2moodle.ui.treewidget import QuestionItem, CategoryItem
18
+ from excel2moodle.core.exceptions import InvalidFieldException, QNotParsedException
19
+ from excel2moodle.core.question import Question
20
20
  from excel2moodle.core.questionValidator import Validator
21
+ from excel2moodle.ui.dialogs import QuestionVariantDialog
21
22
  from excel2moodle.ui.settings import Settings
22
- from excel2moodle.core.question import Question
23
- from excel2moodle.core.exceptions import InvalidFieldException, QNotParsedException
24
-
23
+ from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
25
24
 
26
25
  logger = logging.getLogger(__name__)
27
26
 
28
27
 
29
- class QuestionDB():
28
+ class QuestionDB:
30
29
  """oberste Klasse für den Test"""
30
+
31
31
  dataChanged = QSignaler()
32
32
 
33
- def __init__(self, settings:Settings):
33
+ def __init__(self, settings: Settings):
34
34
  self.settings = settings
35
35
  self.spreadSheetPath = Path()
36
36
  self.mainPath = Path()
37
- self.window:QMainWindow|None = None
37
+ self.window: QMainWindow | None = None
38
38
  self.version = None
39
39
  self.categoriesMetaData = pd.DataFrame()
40
- self.categories:dict[str,Category]={}
40
+ self.categories: dict[str, Category] = {}
41
41
  self.settings.shPathChanged.connect(self.onSheetPathChanged)
42
42
 
43
43
  @QtCore.Slot(Path)
44
- def onSheetPathChanged(self, sheet:Path)->None:
44
+ def onSheetPathChanged(self, sheet: Path) -> None:
45
45
  logger.debug("Slot, new Spreadsheet triggered")
46
46
  self.spreadSheetPath = sheet
47
- self.svgFolder = (self.spreadSheetPath.parent / 'Abbildungen_SVG')
47
+ svgFolder = self.spreadSheetPath.parent / str(
48
+ self.settings.get("core/pictureSubFolder", default="Abbildungen_SVG")
49
+ )
50
+ svgFolder.resolve()
51
+ self.settings.set("core/pictureFolder", svgFolder)
48
52
  self.retrieveCategoriesData()
49
53
  self.parseAll()
50
54
 
51
- def retrieveCategoriesData(self)->None:
52
- """Scans through the sheet with the metadata for all the question categories
55
+ def retrieveCategoriesData(self) -> None:
56
+ """Scans through the sheet with the metadata for all categories
53
57
 
54
- The information that will be shown in the UI like description and points is retrieved from one spreadsheet sheet.
55
- This method gathers this information and stores it in the ``categoriesMetaData`` dataframe
58
+ The information that will be shown in the UI like description
59
+ and points is retrieved from one spreadsheet sheet.
60
+ This method gathers this information and stores it in the
61
+ ``categoriesMetaData`` dataframe
56
62
  """
57
63
 
58
64
  logger.info("Start Parsing the Excel Metadata Sheet\n")
59
- with open(self.spreadSheetPath, 'rb') as f:
65
+ with open(self.spreadSheetPath, "rb") as f:
60
66
  excelFile = pd.ExcelFile(f)
61
- self.categoriesMetaData = pd.read_excel(f, sheet_name="Kategorien",
62
- usecols=["Kategorie", "Beschreibung", "Punkte", "Version"],
63
- index_col=0)
67
+ self.categoriesMetaData = pd.read_excel(
68
+ f,
69
+ sheet_name="Kategorien",
70
+ usecols=["Kategorie", "Beschreibung", "Punkte", "Version"],
71
+ index_col=0,
72
+ )
64
73
  logger.info("Sucessfully read categoriesMetaData")
65
74
  print(self.categoriesMetaData)
66
75
  self.categories = {}
67
76
  for sh in excelFile.sheet_names:
68
77
  if sh.startswith("KAT"):
69
78
  n = int(sh[4:])
70
- katDf = pd.read_excel(f, sheet_name=str(sh), index_col=0, header=None)
79
+ katDf = pd.read_excel(
80
+ f, sheet_name=str(sh), index_col=0, header=None
81
+ )
71
82
  if not katDf.empty:
72
- p = self.categoriesMetaData["Punkte"].iloc[n-1]
73
- points = (p if not pd.isna(p) else 1)
74
- v = self.categoriesMetaData["Version"].iloc[n-1]
75
- version = (v if not pd.isna(v) else 0)
76
- self.categories[sh] = Category(n,sh,
77
- self.categoriesMetaData["Beschreibung"].iloc[n-1],
78
- dataframe=katDf,
79
- points=points,
80
- version=version)
83
+ p = self.categoriesMetaData["Punkte"].iloc[n - 1]
84
+ points = p if not pd.isna(p) else 1
85
+ v = self.categoriesMetaData["Version"].iloc[n - 1]
86
+ version = v if not pd.isna(v) else 0
87
+ self.categories[sh] = Category(
88
+ n,
89
+ sh,
90
+ self.categoriesMetaData["Beschreibung"].iloc[n - 1],
91
+ dataframe=katDf,
92
+ points=points,
93
+ version=version,
94
+ )
81
95
  self.dataChanged.signal.emit("whoo")
82
96
  return None
83
97
 
84
-
85
98
  def parseAll(self):
86
99
  self.mainTree = ET.Element("quiz")
87
100
  for c in self.categories.values():
@@ -95,17 +108,25 @@ class QuestionDB():
95
108
  try:
96
109
  check = validator.validate()
97
110
  except InvalidFieldException as e:
98
- logger.error(f"Question {c.id}{q:02d} is invalid.", exc_info=e)
99
- if check:
100
- c.questions[q]=validator.question
111
+ logger.error(
112
+ f"Question {c.id}{
113
+ q:02d} is invalid.",
114
+ exc_info=e,
115
+ )
116
+ if check:
117
+ c.questions[q] = validator.question
101
118
  try:
102
119
  c.parseQ(c.questions[q], validator.qdata)
103
120
  except QNotParsedException as e:
104
- logger.error(f"Frage {c.questions[q].id} konnte nicht erstellt werden", exc_info=e)
121
+ logger.error(
122
+ f"Frage {
123
+ c.questions[q].id} konnte nicht erstellt werden",
124
+ exc_info=e,
125
+ )
105
126
 
106
- def appendQuestions(self, questions:list[QuestionItem], file:Path|None=None):
127
+ def appendQuestions(self, questions: list[QuestionItem], file: Path | None = None):
107
128
  tree = ET.Element("quiz")
108
- catdict:dict[Category,list[Question]]={}
129
+ catdict: dict[Category, list[Question]] = {}
109
130
  for q in questions:
110
131
  logger.debug(f"got a question to append {q=}")
111
132
  cat = q.parent().getCategory()
@@ -114,13 +135,24 @@ class QuestionDB():
114
135
  print(f"Category is parent of Q {cat=}")
115
136
  catdict[cat].append(q.getQuestion())
116
137
  for cat, qlist in catdict.items():
117
- print(f"{cat = }, mit fragen {qlist = }")
118
- self.appendQElements(cat, qlist, tree=tree, includeHeader=self.settings.value("testGen/includeCats"))
138
+ print(f"{cat=}, mit fragen {qlist=}")
139
+ self.appendQElements(
140
+ cat,
141
+ qlist,
142
+ tree=tree,
143
+ includeHeader=self.settings.value("testGen/includeCats"),
144
+ )
119
145
  stringHelpers.printDom(tree, file=file)
120
146
 
121
- def appendQElements(self,cat:Category, qList:list[Question], tree:ET.Element, includeHeader:bool=True)->None:
147
+ def appendQElements(
148
+ self,
149
+ cat: Category,
150
+ qList: list[Question],
151
+ tree: ET.Element,
152
+ includeHeader: bool = True,
153
+ ) -> None:
122
154
  if includeHeader:
123
- tree.append( cat.getCategoryHeader())
155
+ tree.append(cat.getCategoryHeader())
124
156
  logger.debug(f"Appended a new category item {cat=}")
125
157
  sameVariant = False
126
158
  variant = 1
@@ -134,11 +166,11 @@ class QuestionDB():
134
166
  sameVariant = dialog.categoryWide
135
167
  logger.debug(f"Die Fragen-Variante {variant} wurde gewählt")
136
168
  q.assemble(variant)
137
- else: print("skipping this question")
169
+ else:
170
+ print("skipping this question")
138
171
  else:
139
172
  q.assemble()
140
173
  tree.append(q.element)
141
- else: logger.warning(f"Frage {q} wurde nicht erstellt")
174
+ else:
175
+ logger.warning(f"Frage {q} wurde nicht erstellt")
142
176
  return None
143
-
144
-
@@ -4,29 +4,31 @@ This module host different functions. All of them will return an ``lxml.etree.El
4
4
  """
5
5
 
6
6
  import lxml.etree as ET
7
- from .globals import DFIndex, XMLTags
8
- import pandas as pd
9
- from excel2moodle.core.globals import feedbackStr, TextElements, feedBElements
7
+
10
8
  import excel2moodle.core.etHelpers as eth
9
+ from excel2moodle.core.globals import TextElements, feedbackStr, feedBElements
10
+
11
+ from .globals import DFIndex, XMLTags
12
+
11
13
 
12
- def getElement( eleName : str, text: str, **attribs)->ET.Element:
14
+ def getElement(eleName: str, text: str, **attribs) -> ET.Element:
13
15
  """Creates an XML-Element with text
14
-
16
+
15
17
  If ``type(text)``is a ``QuestionFields``, the specific field is directly read.
16
18
  Otherwise it will include whatever is ``text`` as a string
17
19
  :param **kwargs: are treated as attributes for the Element
18
- raises:
20
+ raises:
19
21
  NanException if the spreadsheet cell of text:QuestionFields is ``nan``
20
22
  """
21
23
 
22
24
  toEle = ET.Element(eleName)
23
25
  toEle.text = str(text)
24
26
  for k, v in attribs.items():
25
- toEle.set(k,v)
27
+ toEle.set(k, v)
26
28
  return toEle
27
29
 
28
30
 
29
- def getTextElement( eleName:str, text:str|DFIndex, **attribs)->ET.Element:
31
+ def getTextElement(eleName: str, text: str | DFIndex, **attribs) -> ET.Element:
30
32
  """Creates two nested elements: ``eleName`` with child ``text`` which holds the text"""
31
33
 
32
34
  toEle = ET.Element(eleName, **attribs)
@@ -34,28 +36,31 @@ def getTextElement( eleName:str, text:str|DFIndex, **attribs)->ET.Element:
34
36
  toEle.append(child)
35
37
  return toEle
36
38
 
37
- def getCdatTxtElement(subEle: ET._Element|list[ET._Element])->ET.Element:
39
+
40
+ def getCdatTxtElement(subEle: ET._Element | list[ET._Element]) -> ET.Element:
38
41
  """Puts all ``subEle`` as ``str`` into a ``<text><![CDATA[...subEle...]]</text>`` element"""
39
42
 
40
43
  textEle = ET.Element(XMLTags.TEXT)
41
44
  if isinstance(subEle, list):
42
- elementString : list= []
45
+ elementString: list = []
43
46
  for i in subEle:
44
47
  elementString.append(ET.tostring(i, encoding="unicode", pretty_print=True))
45
48
  textEle.text = ET.CDATA("".join(elementString))
46
49
  return textEle
47
50
  else:
48
- textEle.text = ET.CDATA(ET.tostring(subEle, encoding="unicode", pretty_print=True))
49
- return textEle
51
+ textEle.text = ET.CDATA(
52
+ ET.tostring(subEle, encoding="unicode", pretty_print=True)
53
+ )
54
+ return textEle
50
55
 
51
56
 
52
- def getFeedBEle(feedback:XMLTags,
53
- text:str|None=None, style: TextElements | None = None
54
- )->ET.Element:
57
+ def getFeedBEle(
58
+ feedback: XMLTags, text: str | None = None, style: TextElements | None = None
59
+ ) -> ET.Element:
55
60
  """Gets ET Elements with the feedback for the question."""
56
61
  if style is None:
57
62
  span = feedBElements[feedback]
58
- else:
63
+ else:
59
64
  span = style.create()
60
65
  if text is None:
61
66
  text = feedbackStr[feedback]
@@ -1,20 +1,27 @@
1
-
2
1
  from excel2moodle.core.globals import DFIndex
3
2
 
4
3
 
5
4
  class QNotParsedException(Exception):
6
- def __init__(self, message:str, qID:str|int, *args, **kwargs)->None:
5
+ def __init__(self, message: str, qID: str | int, *args, **kwargs) -> None:
7
6
  super().__init__(message, *args, **kwargs)
8
7
  self.qID = qID
9
8
 
9
+
10
10
  class NanException(QNotParsedException):
11
11
  def __init__(self, message, qID, field, *args, **kwargs):
12
12
  super().__init__(message, qID, *args, **kwargs)
13
13
  self.field = field
14
14
 
15
+
15
16
  class InvalidFieldException(Exception):
16
- def __init__(self, message:str, qID:str, field:DFIndex|list[DFIndex], *args: object, **kwargs) -> None:
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ qID: str,
21
+ field: DFIndex | list[DFIndex],
22
+ *args: object,
23
+ **kwargs,
24
+ ) -> None:
17
25
  super().__init__(message, *args, **kwargs)
18
26
  self.field = field
19
27
  self.index = qID
20
-