excel2moodle 0.3.6__py3-none-any.whl → 0.4.0__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.
@@ -2,8 +2,6 @@ import logging
2
2
  import re
3
3
 
4
4
  import lxml.etree as ET
5
- import pandas as pd
6
- from asteval import Interpreter
7
5
 
8
6
  import excel2moodle.core.etHelpers as eth
9
7
  from excel2moodle.core import stringHelpers
@@ -14,16 +12,13 @@ from excel2moodle.core.globals import (
14
12
  XMLTags,
15
13
  feedbackStr,
16
14
  feedBElements,
17
- parserSettings,
18
15
  )
19
16
  from excel2moodle.core.question import Picture, Question
17
+ from excel2moodle.core.settings import Settings, SettingsKey
20
18
  from excel2moodle.logger import LogAdapterQuestionID
21
- from excel2moodle.ui.settings import Settings, SettingsKey
22
19
 
23
20
  loggerObj = logging.getLogger(__name__)
24
21
 
25
- settings = Settings()
26
-
27
22
 
28
23
  class QuestionParser:
29
24
  """Setup the Parser Object.
@@ -32,42 +27,42 @@ class QuestionParser:
32
27
  Important to implement the answers methods.
33
28
  """
34
29
 
35
- def __init__(self, question: Question, data: dict) -> None:
30
+ settings = Settings()
31
+
32
+ def __init__(self) -> None:
36
33
  """Initialize the general Question parser."""
34
+ self.genFeedbacks: list[XMLTags] = []
35
+ self.logger: logging.LoggerAdapter
36
+
37
+ def setup(self, question: Question) -> None:
37
38
  self.question: Question = question
38
- self.rawInput = data
39
+ self.rawInput = question.rawData
39
40
  self.logger = LogAdapterQuestionID(loggerObj, {"qID": self.question.id})
40
41
  self.logger.debug(
41
42
  "The following Data was provided: %s",
42
43
  self.rawInput,
43
44
  )
44
- self.genFeedbacks: list[XMLTags] = []
45
45
 
46
46
  def hasPicture(self) -> bool:
47
47
  """Create a ``Picture`` object ``question``if the question needs a pic."""
48
48
  if hasattr(self, "picture") and self.question.picture.ready:
49
49
  return True
50
- picKey = self.rawInput[DFIndex.PICTURE]
51
- svgFolder = settings.get(SettingsKey.PICTUREFOLDER)
52
- if picKey != 0 and pd.notna(picKey):
53
- if not hasattr(self.question, "picture"):
54
- self.question.picture = Picture(picKey, svgFolder, self.question)
55
- if self.question.picture.ready:
56
- return True
57
- return False
50
+ picKey = self.rawInput.get(DFIndex.PICTURE, False)
51
+ f = self.settings.get(SettingsKey.PICTUREFOLDER)
52
+ svgFolder = (f / self.question.katName).resolve()
53
+ if not hasattr(self.question, "picture"):
54
+ self.question.picture = Picture(picKey, svgFolder, self.question.id)
55
+ return bool(self.question.picture.ready)
58
56
 
59
57
  def setMainText(self) -> None:
60
58
  paragraphs: list[ET._Element] = [TextElements.PLEFT.create()]
61
59
  ET.SubElement(paragraphs[0], "b").text = f"ID {self.question.id}"
62
60
  text = self.rawInput[DFIndex.TEXT]
63
- pcount = 0
64
61
  for t in text:
65
- if not pd.isna(t):
66
- pcount += 1
67
- paragraphs.append(TextElements.PLEFT.create())
68
- paragraphs[-1].text = t
62
+ paragraphs.append(TextElements.PLEFT.create())
63
+ paragraphs[-1].text = t
69
64
  self.question.qtextParagraphs = paragraphs
70
- self.logger.debug("Created main Text with: %s paragraphs", pcount)
65
+ self.logger.debug("Created main Text with: %s paragraphs", len(text))
71
66
 
72
67
  def setBPoints(self) -> None:
73
68
  """If there bulletPoints are set in the Spreadsheet it creates an unordered List-Element in ``Question.bulletList``."""
@@ -75,12 +70,12 @@ class QuestionParser:
75
70
  bps: str = self.rawInput[DFIndex.BPOINTS]
76
71
  try:
77
72
  bulletList = self.formatBulletList(bps)
78
- except IndexError as e:
73
+ except IndexError:
79
74
  msg = f"konnt Bullet Liste {self.question.id} nicht generieren"
80
75
  raise QNotParsedException(
81
76
  msg,
82
77
  self.question.id,
83
- exc_info=e,
78
+ # exc_info=e,
84
79
  )
85
80
  self.logger.debug(
86
81
  "Generated BPoint List: \n %s",
@@ -90,7 +85,7 @@ class QuestionParser:
90
85
 
91
86
  def formatBulletList(self, bps: str) -> ET.Element:
92
87
  self.logger.debug("Formatting the bulletpoint list")
93
- li: list[str] = stringHelpers.stripWhitespace(bps.split(";"))
88
+ li: list[str] = stringHelpers.getListFromStr(bps)
94
89
  name = []
95
90
  var = []
96
91
  quant = []
@@ -138,24 +133,12 @@ class QuestionParser:
138
133
  elif txtEle is True:
139
134
  self.tmpEle.append(eth.getTextElement(eleName, t, **attribs))
140
135
 
141
- def appendFromSettings(self, key="standards") -> None:
142
- """Appends 1 to 1 mapped Elements defined in the parserSettings to the element."""
143
- parser = ["Parser"]
144
- if isinstance(self, MCQuestionParser):
145
- parser.append("MCParser")
146
- elif isinstance(self, NFQuestionParser):
147
- parser.append("NFParser")
148
- for p in parser:
149
- try:
150
- for k, v in parserSettings[p][key].items():
151
- self.appendToTmpEle(k, text=v)
152
- except KeyError as e:
153
- msg = f"Invalider Input aus den Einstellungen Parser: {
154
- type(p) =}"
155
- self.logger.exception(msg, exc_info=e)
156
- raise QNotParsedException(msg, self.question.id, exc_info=e)
136
+ def _appendStandardTags(self) -> None:
137
+ """Append the elements defined in the ``cls.standardTags``."""
138
+ for k, v in type(self.question).standardTags.items():
139
+ self.appendToTmpEle(k, text=v)
157
140
 
158
- def parse(self, xmlTree: ET._Element | None = None) -> None:
141
+ def parse(self) -> None:
159
142
  """Parse the Question.
160
143
 
161
144
  Generates an new Question Element stored as ``self.tmpEle:ET.Element``
@@ -163,7 +146,6 @@ class QuestionParser:
163
146
  """
164
147
  self.logger.info("Starting to parse")
165
148
  self.tmpEle = ET.Element(XMLTags.QUESTION, type=self.question.moodleType)
166
- # self.tmpEle.set(XMLTags.TYPE, self.question.moodleType)
167
149
  self.appendToTmpEle(XMLTags.NAME, text=DFIndex.NAME, txtEle=True)
168
150
  self.appendToTmpEle(XMLTags.ID, text=self.question.id)
169
151
  if self.hasPicture():
@@ -171,11 +153,9 @@ class QuestionParser:
171
153
  self.tmpEle.append(ET.Element(XMLTags.QTEXT, format="html"))
172
154
  self.appendToTmpEle(XMLTags.POINTS, text=str(self.question.points))
173
155
  self.appendToTmpEle(XMLTags.PENALTY, text="0.3333")
174
- self.appendFromSettings()
156
+ self._appendStandardTags()
175
157
  for feedb in self.genFeedbacks:
176
158
  self.tmpEle.append(eth.getFeedBEle(feedb))
177
- if xmlTree is not None:
178
- xmlTree.append(self.tmpEle)
179
159
  ansList = self.setAnswers()
180
160
  self.setMainText()
181
161
  self.setBPoints()
@@ -208,7 +188,6 @@ class QuestionParser:
208
188
  def getNumericAnsElement(
209
189
  self,
210
190
  result: float,
211
- tolerance: float = 0,
212
191
  fraction: float = 100,
213
192
  format: str = "moodle_auto_format",
214
193
  ) -> ET.Element:
@@ -232,164 +211,15 @@ class QuestionParser:
232
211
  TextElements.SPANGREEN,
233
212
  ),
234
213
  )
235
- tolerance = self.getTolerancePercent(tolerance)
236
- tol = abs(round(result * (tolerance / 100), 3))
237
- ansEle.append(eth.getElement(XMLTags.TOLERANCE, text=str(tol)))
238
- return ansEle
239
-
240
- def getTolerancePercent(self, tolerance: float) -> int:
241
- """Get the correct tolerance.
242
- If ``tolerance < 1``: it is interpreted as the fraction.
243
- If ``tolerance >= 1``: it is interpreted as percentage.
244
- """
245
- if tolerance == 0 or pd.isna(tolerance) or tolerance >= 100:
246
- tolerance = settings.get(SettingsKey.PARSERNF_TOLERANCE)
214
+ tolerance = float(self.rawInput.get(DFIndex.TOLERANCE, 0))
215
+ if tolerance == 0 or tolerance >= 100:
216
+ tolerance = self.settings.get(SettingsKey.TOLERANCE)
247
217
  self.logger.info(
248
218
  "Using default tolerance %s percent from settings",
249
219
  tolerance,
250
220
  )
251
- tolerancePercent = 100 * tolerance if tolerance < 1 else tolerance
252
- self.logger.debug("Using tolerance %s percent", tolerancePercent)
253
- return int(tolerancePercent)
254
-
255
-
256
- class NFQuestionParser(QuestionParser):
257
- """Subclass for parsing numeric questions."""
258
-
259
- def __init__(self, *args) -> None:
260
- super().__init__(*args)
261
- self.genFeedbacks = [XMLTags.GENFEEDB]
262
-
263
- def setAnswers(self) -> list[ET.Element]:
264
- result = self.rawInput[DFIndex.RESULT]
265
- ansEle: list[ET.Element] = []
266
- tol = self.rawInput[DFIndex.TOLERANCE]
267
- ansEle.append(self.getNumericAnsElement(result=result, tolerance=tol))
221
+ tolPercent = 100 * tolerance if tolerance < 1 else tolerance
222
+ self.logger.debug("Using tolerance %s percent", tolPercent)
223
+ relTolerance = abs(round(result * (tolerance / 100), 3))
224
+ ansEle.append(eth.getElement(XMLTags.TOLERANCE, text=str(relTolerance)))
268
225
  return ansEle
269
-
270
-
271
- class NFMQuestionParser(QuestionParser):
272
- def __init__(self, *args) -> None:
273
- super().__init__(*args)
274
- self.genFeedbacks = [XMLTags.GENFEEDB]
275
- self.astEval = Interpreter()
276
-
277
- def setAnswers(self) -> None:
278
- equation = self.rawInput[DFIndex.RESULT]
279
- bps = str(self.rawInput[DFIndex.BPOINTS])
280
- ansElementsList: list[ET.Element] = []
281
- varNames: list[str] = self._getVarsList(bps)
282
- self.question.variables, number = self._getVariablesDict(varNames)
283
- for n in range(number):
284
- self._setupAstIntprt(self.question.variables, n)
285
- result = self.astEval(equation)
286
- if isinstance(result, float):
287
- tol = self.rawInput[DFIndex.TOLERANCE]
288
- ansElementsList.append(
289
- self.getNumericAnsElement(result=round(result, 3), tolerance=tol),
290
- )
291
- self.question.answerVariants = ansElementsList
292
- self.setVariants(len(ansElementsList))
293
-
294
- def setVariants(self, number: int) -> None:
295
- self.question.variants = number
296
- mvar = self.question.category.maxVariants
297
- if mvar is None:
298
- self.question.category.maxVariants = number
299
- else:
300
- self.question.category.maxVariants = min(number, mvar)
301
-
302
- def _setupAstIntprt(self, var: dict[str, list[float | int]], index: int) -> None:
303
- """Setup the asteval Interpreter with the variables."""
304
- for name, value in var.items():
305
- self.astEval.symtable[name] = value[index]
306
-
307
- def _getVariablesDict(self, keyList: list) -> tuple[dict[str, list[float]], int]:
308
- """Liest alle Variablen-Listen deren Name in ``keyList`` ist aus dem DataFrame im Column[index]."""
309
- dic: dict = {}
310
- num: int = 0
311
- for k in keyList:
312
- val = self.rawInput[k]
313
- if isinstance(val, str):
314
- li = stringHelpers.stripWhitespace(val.split(";"))
315
- num = len(li)
316
- vars: list[float] = [float(i.replace(",", ".")) for i in li]
317
- dic[str(k)] = vars
318
- else:
319
- dic[str(k)] = [str(val)]
320
- num = 1
321
- return dic, num
322
-
323
- @staticmethod
324
- def _getVarsList(bps: str | list[str]) -> list:
325
- """Durchsucht den bulletPoints String nach den Variablen, die als "{var}" gekennzeichnet sind."""
326
- vars = []
327
- if isinstance(bps, list):
328
- for _p in bps:
329
- vars.extend(re.findall(r"\{\w\}", str(bps)))
330
- else:
331
- vars = re.findall(r"\{\w\}", str(bps))
332
- variablen = []
333
- for v in vars:
334
- variablen.append(v.strip("{}"))
335
- return variablen
336
-
337
-
338
- class MCQuestionParser(QuestionParser):
339
- def __init__(self, *args) -> None:
340
- super().__init__(*args)
341
- self.genFeedbacks = [
342
- XMLTags.CORFEEDB,
343
- XMLTags.PCORFEEDB,
344
- XMLTags.INCORFEEDB,
345
- ]
346
-
347
- def getAnsElementsList(
348
- self,
349
- answerList: list,
350
- fraction: float = 50,
351
- format="html",
352
- ) -> list[ET.Element]:
353
- elementList: list[ET.Element] = []
354
- for ans in answerList:
355
- p = TextElements.PLEFT.create()
356
- p.text = str(ans)
357
- text = eth.getCdatTxtElement(p)
358
- elementList.append(
359
- ET.Element(XMLTags.ANSWER, fraction=str(fraction), format=format),
360
- )
361
- elementList[-1].append(text)
362
- if fraction < 0:
363
- elementList[-1].append(
364
- eth.getFeedBEle(
365
- XMLTags.ANSFEEDBACK,
366
- text=feedbackStr["wrong"],
367
- style=TextElements.SPANRED,
368
- ),
369
- )
370
- elif fraction > 0:
371
- elementList[-1].append(
372
- eth.getFeedBEle(
373
- XMLTags.ANSFEEDBACK,
374
- text=feedbackStr["right"],
375
- style=TextElements.SPANGREEN,
376
- ),
377
- )
378
- return elementList
379
-
380
- def setAnswers(self) -> list[ET.Element]:
381
- ansStyle = self.rawInput[DFIndex.ANSTYPE]
382
- true = stringHelpers.stripWhitespace(self.rawInput[DFIndex.TRUE].split(";"))
383
- trueAnsList = stringHelpers.texWrapper(true, style=ansStyle)
384
- self.logger.debug(f"got the following true answers \n {trueAnsList=}")
385
- false = stringHelpers.stripWhitespace(self.rawInput[DFIndex.FALSE].split(";"))
386
- falseAnsList = stringHelpers.texWrapper(false, style=ansStyle)
387
- self.logger.debug(f"got the following false answers \n {falseAnsList=}")
388
- truefrac = 1 / len(trueAnsList) * 100
389
- falsefrac = 1 / len(trueAnsList) * (-100)
390
- self.tmpEle.find(XMLTags.PENALTY).text = str(round(truefrac / 100, 4))
391
- ansList = self.getAnsElementsList(trueAnsList, fraction=round(truefrac, 4))
392
- ansList.extend(
393
- self.getAnsElementsList(falseAnsList, fraction=round(falsefrac, 4)),
394
- )
395
- return ansList
@@ -1,40 +1,60 @@
1
1
  import base64
2
2
  import logging
3
3
  import re
4
+ import typing
4
5
  from pathlib import Path
5
6
  from re import Match
6
7
 
7
8
  import lxml.etree as ET
8
9
 
9
10
  from excel2moodle.core import etHelpers
11
+ from excel2moodle.core.category import Category
10
12
  from excel2moodle.core.exceptions import QNotParsedException
11
13
  from excel2moodle.core.globals import (
14
+ DFIndex,
12
15
  TextElements,
13
16
  XMLTags,
14
17
  questionTypes,
15
18
  )
19
+ from excel2moodle.core.settings import Settings, SettingsKey
16
20
  from excel2moodle.logger import LogAdapterQuestionID
17
21
 
18
22
  loggerObj = logging.getLogger(__name__)
23
+ settings = Settings()
19
24
 
20
25
 
21
26
  class Question:
27
+ standardTags: typing.ClassVar[dict[str, str | float]] = {
28
+ "hidden": 0,
29
+ }
30
+
31
+ def __init_subclass__(cls, **kwargs) -> None:
32
+ super().__init_subclass__(**kwargs)
33
+ subclassTags = getattr(cls, "standartTags", {})
34
+ superclassTags = super(cls, cls).standardTags
35
+ mergedTags = superclassTags.copy()
36
+ mergedTags.update(subclassTags)
37
+ cls.standardTags = mergedTags
38
+
39
+ @classmethod
40
+ def addStandardTags(cls, key, value) -> None:
41
+ cls.standardTags[key] = value
42
+
22
43
  def __init__(
23
44
  self,
24
- category,
25
- name: str,
26
- number: int,
45
+ category: Category,
46
+ rawData: dict[str, float | str | int | list[str]],
27
47
  parent=None,
28
- qtype: str = "type",
29
48
  points: float = 0,
30
49
  ) -> None:
50
+ self.rawData = rawData
31
51
  self.category = category
32
52
  self.katName = self.category.name
33
- self.name = name
34
- self.number = number
53
+ self.name: str = self.rawData.get(DFIndex.NAME)
54
+ self.number: int = self.rawData.get(DFIndex.NUMBER)
35
55
  self.parent = parent
36
- self.qtype: str = qtype
37
- self.moodleType = questionTypes[qtype]
56
+ self.qtype: str = self.rawData.get(DFIndex.TYPE)
57
+ self.moodleType = questionTypes[self.qtype]
38
58
  self.points = points if points != 0 else self.category.points
39
59
  self.element: ET.Element | None = None
40
60
  self.picture: Picture
@@ -45,21 +65,20 @@ class Question:
45
65
  self.variants: int | None = None
46
66
  self.variables: dict[str, list[float | int]] = {}
47
67
  self.setID()
48
- self.standardTags = {"hidden": "false"}
49
68
  self.logger = LogAdapterQuestionID(loggerObj, {"qID": self.id})
50
69
  self.logger.debug("Sucess initializing")
51
70
 
52
71
  def __repr__(self) -> str:
53
72
  li: list[str] = []
54
- li.append(f"Question v{self.category.version}")
55
- li.append(f"{self.id=}")
73
+ li.append(f"Question v{self.id}")
74
+ li.append(f"{self.qtype}")
56
75
  li.append(f"{self.parent=}")
57
- return "\n".join(li)
76
+ return "\t".join(li)
58
77
 
59
78
  def assemble(self, variant: int = 1) -> None:
60
79
  textElements: list[ET.Element] = []
61
80
  textElements.extend(self.qtextParagraphs)
62
- self.logger.debug("Starting assembly")
81
+ self.logger.debug("Starting assembly, (variant %s)", variant)
63
82
  if self.element is not None:
64
83
  mainText = self.element.find(XMLTags.QTEXT)
65
84
  self.logger.debug(f"found existing Text in element {mainText=}")
@@ -78,7 +97,6 @@ class Question:
78
97
  textElements.append(self.picture.htmlTag)
79
98
  mainText.append(self.picture.element)
80
99
  mainText.append(etHelpers.getCdatTxtElement(textElements))
81
- # self.element.insert(3, mainText)
82
100
  self.logger.debug("inserted MainText to element")
83
101
  if len(self.answerVariants) > 0:
84
102
  ans = self.element.find(XMLTags.ANSWER)
@@ -117,61 +135,94 @@ class Question:
117
135
 
118
136
 
119
137
  class Picture:
120
- def __init__(self, picKey: str, imgFolder: Path, question: Question) -> None:
121
- self.pic = picKey
138
+ def __init__(
139
+ self, picKey: str, imgFolder: Path, questionId: str, width: int = 0
140
+ ) -> None:
141
+ self.logger = LogAdapterQuestionID(loggerObj, {"qID": questionId})
142
+ self.picID: str
143
+ w: int = width if width > 0 else settings.get(SettingsKey.PICTUREWIDTH)
144
+ self.size: dict[str, str] = {"width": str(w)}
122
145
  self.ready: bool = False
123
- self.question = question
124
- self.logger = LogAdapterQuestionID(loggerObj, {"qID": self.question.id})
125
- self.imgFolder = (imgFolder / question.katName).resolve()
146
+ self.imgFolder = imgFolder
126
147
  self.htmlTag: ET.Element
127
148
  self.path: Path
128
- self._setPath()
129
- if hasattr(self, "picID"):
149
+ self.questionId: str = questionId
150
+ self.logger.debug("Instantiating a new picture in %s", picKey)
151
+ if self.getImgId(picKey):
130
152
  self.ready = self.__getImg()
131
-
132
- def _setPath(self) -> None:
133
- if self.pic == 1:
134
- self.picID = self.question.id
135
153
  else:
136
- selectedPic = self.pic[2:]
137
- self.logger.debug("Got the picture key: %s", selectedPic)
138
- try:
139
- self.picID = f"{self.question.category.id}{int(selectedPic):02d}"
140
- except ValueError as e:
141
- self.logger.warning(
142
- msg=f"Bild-ID konnte aus dem Key: {self.pic} nicht festgestellt werden",
143
- exc_info=e,
144
- )
145
-
146
- def __getBase64Img(self, imgPath):
147
- with open(imgPath, "rb") as img:
148
- return base64.b64encode(img.read()).decode("utf-8")
154
+ self.ready = False
155
+
156
+ def getImgId(self, imgKey: str) -> bool:
157
+ """Get the image ID and width based on the given key.
158
+ The key should either be the full ID (as the question) or only the question Num.
159
+ If only the number is given, the category.id is prepended.
160
+ The width should be specified by `ID:width:XX`. where xx is the px value.
161
+ """
162
+ width = re.findall(r"\:width\:(\d+)", str(imgKey))
163
+ height = re.findall(r"\:height\:(\d+)", str(imgKey))
164
+ if len(width) > 0 and width[0]:
165
+ self.size["width"] = width[0]
166
+ elif len(height) > 0 and height[0]:
167
+ self.size["height"] = height[0]
168
+ self.size.pop("width")
169
+ self.logger.debug("Size of picture is %s", self.size)
170
+ if imgKey in ("true", "True", "yes"):
171
+ self.picID = self.questionId
172
+ return True
173
+ num: list[int | str] = re.findall(r"^\d+", str(imgKey))
174
+ app: list[int | str] = re.findall(r"^\d+([A-Za-z_\-]+)", str(imgKey))
175
+ if imgKey in ("false", "nan", False) or len(num) == 0:
176
+ return False
177
+ imgID: int = int(num[0])
178
+ if imgID < 10:
179
+ picID = f"{self.questionId[:3]}{imgID:02d}"
180
+ elif imgID < 10000:
181
+ picID = f"{self.questionId[:1]}{imgID:04d}"
182
+ elif imgID <= 100000:
183
+ picID = str(imgID)
184
+ if len(app) > 0 and app[0]:
185
+ self.picID = f"{picID}{app[0]}"
186
+ else:
187
+ self.picID = str(picID)
188
+ self.logger.debug("Evaluated the imgID %s from %s", self.picID, imgKey)
189
+ return True
149
190
 
150
- def __setImgElement(self, dir: Path, picID: int) -> None:
151
- """Gibt das Bild im dirPath mit dir qID als base64 encodiert mit den entsprechenden XML-Tags zurück."""
152
- self.path: Path = (dir / str(picID)).with_suffix(".svg")
153
- self.element: ET.Element = ET.Element(
154
- "file",
155
- name=f"{self.path.name}",
156
- path="/",
157
- encoding="base64",
158
- )
159
- self.element.text = self.__getBase64Img(self.path)
191
+ def _getBase64Img(self, imgPath: Path):
192
+ with imgPath.open("rb") as img:
193
+ return base64.b64encode(img.read()).decode("utf-8")
160
194
 
161
195
  def __getImg(self) -> bool:
196
+ suffixes = ["png", "svg", "jpeg", "jpg"]
197
+ paths = [
198
+ path
199
+ for suf in suffixes
200
+ for path in self.imgFolder.glob(f"{self.picID}.{suf}")
201
+ ]
202
+ self.logger.debug("Found the following paths %s", paths)
162
203
  try:
163
- self.__setImgElement(self.imgFolder, int(self.picID))
164
- self.htmlTag = ET.Element(
165
- "img",
166
- src=f"@@PLUGINFILE@@/{self.path.name}",
167
- alt=f"Bild {self.path.name}",
168
- width="500",
169
- )
170
- return True
171
- except FileNotFoundError as e:
204
+ self.path = paths[0]
205
+ except IndexError as e:
206
+ msg = f"The Picture from key {self.picID} is not found"
207
+ # raise InvalidFieldException(msg, self.questionId, DFIndex.PICTURE)
172
208
  self.logger.warning(
173
209
  msg=f"Bild {self.picID} konnte nicht gefunden werden ",
174
210
  exc_info=e,
175
211
  )
176
212
  self.element = None
177
213
  return False
214
+ base64Img = self._getBase64Img(self.path)
215
+ self.element: ET.Element = ET.Element(
216
+ "file",
217
+ name=f"{self.path.name}",
218
+ path="/",
219
+ encoding="base64",
220
+ )
221
+ self.element.text = base64Img
222
+ self.htmlTag = ET.Element(
223
+ "img",
224
+ src=f"@@PLUGINFILE@@/{self.path.name}",
225
+ alt=f"Bild {self.path.name}",
226
+ **self.size,
227
+ )
228
+ return True