#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module :code:`base` contains definitions required for building
moodle mathematical expressions.
"""
[docs]class Settings:
"""
Representation of moodle math parameters.
If you need change parameters, access to them throught :data:`mmParams`.
"""
decimal_sep = '.'
list_sep = ';'
math_type = 'grade'
def __init__(self):
pass
[docs] def setup(self, **kwargs):
if kwargs['decimal_sep']:
self.decimal_sep = kwargs['decimal_sep']
if kwargs['list_sep']:
self.list_sep = kwargs['list_sep']
if kwargs['math_type']:
self.math_type = kwargs['math_type']
[docs] def period_comma(self):
self.decimal_sep = '.'
self.list_sep = ','
[docs] def period_semicolon(self):
self.decimal_sep = '.'
self.list_sep = ';'
[docs] def comma_semicolon(self):
self.decimal_sep = ','
self.list_sep = ';'
[docs] def grade(self):
self.math_type = 'grade'
[docs] def answer(self):
self.math_type = 'answer'
mmParams = Settings()
"""
(:obj:`Settings`): Object that represents moodle math parameters and manages
them.
"""
def _add(expr1, expr2):
return Expression('({0} + {1})'.format(str(expr1), str(expr2)))
def _sub(expr1, expr2):
return Expression('({0} - {1})'.format(str(expr1), str(expr2)))
def _mul(expr1, expr2):
return Expression('({0} * {1})'.format(str(expr1), str(expr2)))
def _div(expr1, expr2):
return Expression('({0}/{1})'.format(str(expr1), str(expr2)))
def _mod(expr1, expr2):
if mmParams.math_type == 'grade':
fun_string = "mod"
else:
fun_string = "fmod"
return Expression("{0}({1}{2}{3})".format(fun_string, str(expr1), \
mmParams.list_sep, str(expr2)))
def _pow(expr1, expr2):
return Expression('({0} ^ {1})'.format(str(expr1), str(expr2)))
def _bool(expr):
return Expression.__ceil__(abs(expr) / (1 + abs(expr)))
def _not(expr):
return abs(expr - 1)
[docs]class Expression():
"""Implement a generic mathematical expression in moodle format.
Args:
expression (str): Math moodle expression.
Returns:
:obj:`Expression`: Moodle math object.
Examples:
>>> str(mm.Expression('a'))
'a'
>>> a = mm.Expression('a')
>>> b = mm.Expression('b')
>>> str(a + b)
'(a + b)'
>>> str(a + 1)
'(a + 1)'
"""
def __init__(self, expression):
self.root = expression
# String type methods
def __str__(self):
return self.root
def __repr__(self):
return "Expression('{0}')".format(str(self))
# Math type methods
def __round__(self, count):
return Expression('round({0}{1}{2})'.format(
str(self), mmParams.list_sep, str(count)))
def __ceil__(self):
return Expression('ceil({0})'.format(str(self)))
def __floor__(self):
return Expression('floor({0})'.format(str(self)))
def __trunc__(self):
return (self < 0) * Expression.__ceil__(self) + (self >= 0) \
* Expression.__floor__(self)
# Numeric type operations
def __add__(self, expression):
return _add(self, expression)
def __radd__(self, expression):
return _add(expression, self)
def __sub__(self, expression):
return _sub(self, expression)
def __rsub__(self, expression):
return _sub(expression, self)
def __mul__(self, expression):
return _mul(self, expression)
def __rmul__(self, expression):
return _mul(expression, self)
def __truediv__(self, expression):
return _div(self, expression)
def __rtruediv__(self, expression):
return _div(expression, self)
def __floordiv__(self, expression):
return Expression.__floor__(self / expression)
def __rfloordiv__(self, expression):
return Expression.__floor__(expression / self)
def __mod__(self, expression):
return _mod(self, expression)
def __rmod__(self, expression):
return _mod(expression, self)
def __pow__(self, expression):
return _pow(self, expression)
def __rpow__(self, expression):
return _pow(expression, self)
def __neg__(self):
return Expression('-({0})'.format(str(self)))
def __pos__(self):
return Expression(str(self))
def __abs__(self):
return Expression('abs({0})'.format(str(self)))
# Relational operators
def __ne__(self, expression):
return _bool(self - expression)
def __eq__(self, expression):
return _not(self != expression)
def __lt__(self, expression):
diff = expression - self
return _bool(diff + abs(diff))
def __gt__(self, expression):
diff = expression - self
return _bool(diff - abs(diff))
def __le__(self, expression):
return _not(self > expression)
def __ge__(self, expression):
return _not(self < expression)
# Bitwise operators (input must be 0 or 1)
def __and__(self, expression):
return self * expression
def __or__(self, expression):
return self + expression
def __xor__(self, expression):
return (self | expression) & (_not(self) | _not(expression))
# Container type operations
def __contains__(self, expression):
return str(expression) in str(self)
[docs]def grade_var(id_activity):
"""Implement a moodle variable for using in grade calculation.
Args:
id_activity (str): Moodle ID of the activity.
Returns:
:obj:`Expression`: Moodle ID ready for grade calculation.
Examples:
We can create a moodle id activity for calculation as follow:
>>> a = mm.grade_var('a')
>>> str(a)
'[[a]]'
>>> str(a + 1)
'([[a]] + 1)'
See Also:
:class:`Expression`
:func:`answer_var`
"""
return Expression('[[{}]]'.format(id_activity))
[docs]def answer_var(answer_variable):
"""Implement a moodle variable for using in correct answer calculation.
Args:
answer_variable (str): Variable name string.
Returns:
:obj:`Expression`: Moodle variable ready for calculations.
Examples:
We can create a moodle answer variable for calculation as follow:
>>> a = mm.answer_var('a')
>>> str(a)
'{a}'
See Also:
:class:`Expression`
:func:`grade_var`.
"""
return Expression('{{{}}}'.format(answer_variable))
[docs]def moodle_var(name_variable):
"""
Create variable type according to :data:`mmParams.math_type`.
Args:
name_variable (str): Identifier of the moodle variable.
Returns:
:obj:`Expression`: Moodle variable of correct type.
Examples:
>>> mm.mmParams.grade()
>>> mm.moodle_var('a')
Expression('[[a]]')
>>> mm.mmParams.answer()
>>> mm.moodle_var('a')
Expression('{a}')
See_Also:
:class:`Expression`
:func:`grade_var`
:func:`answer_var`
"""
if mmParams.math_type == 'grade':
return grade_var(name_variable)
else:
return answer_var(name_variable)