Coverage for /home/runner/work/viur-core/viur-core/viur/src/viur/core/bones/spam.py: 25%

47 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-02-07 19:28 +0000

1import logging 

2import random 

3import typing as t 

4from viur.core import i18n, current 

5from viur.core.bones import NumericBone 

6from viur.core.bones.base import getSystemInitialized 

7 

8 

9class SpamBone(NumericBone): 

10 type = "numeric.spam" 

11 

12 def __init__( 

13 self, 

14 descr: str = i18n.translate( 

15 "core.bones.spam.question", 

16 "What is the result of the addition of {{a}} and {{b}}?" 

17 ), 

18 values: t.Iterable[str] = tuple( 

19 i18n.translate(f"core.bones.spam.value.{digit}", digit) 

20 for digit in ("one", "two", "three", "four", "five", "six", "seven", "eight", "nine") 

21 ), 

22 required: bool = True, 

23 msg_invalid: str = i18n.translate( 

24 "core.bones.spam.invalid", 

25 "Your answer was wrong! Please try again." 

26 ), 

27 **kwargs 

28 ): 

29 if "precision" in kwargs: 

30 raise ValueError(f"Cannot use {self.__class__.__name__!r} with a precision") 

31 

32 super().__init__( 

33 required=required, 

34 precision=0, 

35 **kwargs 

36 ) 

37 

38 self.values = tuple(values) 

39 if not self.values or len(self.values) == 1: 

40 raise ValueError("Requires for at least 2 values!") 

41 

42 self.descr_template = descr 

43 self.msg_invalid = msg_invalid 

44 

45 def _dice(self) -> int: 

46 return random.randint(1, len(self.values)) 

47 

48 @property 

49 def descr(self): 

50 """ 

51 The descr-property is generated and uses session variables to construct the question. 

52 """ 

53 # This descr can only be evaluated on initialized systems. 

54 if not getSystemInitialized(): 

55 return None 

56 

57 session = current.session.get() 

58 

59 a = session.get("spambone.value.a") 

60 b = session.get("spambone.value.b") 

61 

62 if a is None or b is None: 

63 a = session["spambone.value.a"] = self._dice() 

64 b = session["spambone.value.b"] = self._dice() 

65 

66 return i18n.translate(self.descr_template).translate(a=self.values[a - 1], b=self.values[b - 1]) 

67 

68 @descr.setter 

69 def descr(self, value: t.Any) -> None: 

70 """ 

71 This setter is a null operation. It makes it possible to make a 

72 super call in init, although the `descr` attribute is set there. 

73 """ 

74 pass 

75 

76 def isInvalid(self, value): 

77 session = current.session.get() 

78 

79 a = session.get("spambone.value.a") or 0 

80 b = session.get("spambone.value.b") or 0 

81 

82 if a and b: 

83 del session["spambone.value.a"] 

84 del session["spambone.value.b"] 

85 

86 try: 

87 value = int(value) 

88 except ValueError: 

89 value = 0 

90 

91 logging.debug(f"{a=}, {b=}, {value=}, expecting {a + b=}") 

92 if value != a + b: 

93 return str(self.msg_invalid)