Des calculs comme dans un tableur

Grist, contrairement à un tableur, ne permet pas d’avoir des formules différentes dans chaque cellule. Et c’est très bien comme ça !

Il peut arriver cependant d’être confronté à des problèmes faciles à modéliser dans un tableur, mais bien plus compliqué dans Grist. C’est le cas par exemple en gestion budgétaire, avec des modalités de calculs très différentes d’un sujet à l’autre.

N’utilisez pas la solution proposée ici ! C’est une mauvaise pratique ! Si vous pensez en avoir besoin, c’est que vous avez probablement mal modélisé vos données.

Bon, cependant, voici une formule qui permet de calculer des formules simples saisies dans une colonne de texte. La formule peut être composée d’opérateur mathématiques élémentaires + - * / () et de référence à des cellules de n’importe quelle table et ligne sous la forme :
Nom_table[id_ligne].Colonne

Démo : Spreadsheet

Formule :

import ast
import operator as op

class MathInterpreter:
    __operators_map = {
        ast.Add: op.add,
        ast.Sub: op.sub,
        ast.USub: op.neg,
        ast.Mult: op.mul,
        ast.Div: op.truediv,
    }

    @staticmethod
    def eval(expression: str, variables) -> int | float:
        root_node = ast.parse(expression, mode='eval')
        return MathInterpreter.__walk(root_node, variables)

    @staticmethod
    def __walk(node: ast.AST, variables) -> int | float:
        match node:
            case ast.Expression():
                return MathInterpreter.__walk(node.body, variables)
            case ast.Num():
                return node.n
            case ast.BinOp():
                left, right, op = node.left, node.right, node.op
                method = MathInterpreter.__operators_map[type(op)]
                return method(MathInterpreter.__walk(left, variables), MathInterpreter.__walk(right, variables))
            case ast.UnaryOp():
                operand, op = node.operand, node.op
                method = MathInterpreter.__operators_map[type(op)]
                return method(MathInterpreter.__walk(operand, variables))
            case ast.Name():
                id = node.id
                return variables(id)
            case ast.Attribute():
              
              name = node.value.value.id
              idx = node.value.slice.value
              attr = node.attr
              return variables(name, attr, idx)
              
            case tp:
                raise TypeError(tp)

def findVar(var, attr, idx):
  match (var, attr, idx):
    case (v, a, i):
      return getattr(globals()[v].lookupOne(id=i), a)
  raise KeyError("Ligne inconnue : "+var)

if $Formula != "":
  return MathInterpreter.eval($Formula.replace(",","."), findVar)

J’ai utilisé comme base un algo trouvé ici : How to write a simple math interpreter in Python