This patch use python's tokenize module to parse price list line formula to extract Decimal from the number to get more accurate computations. It should close issue 1792.

Please review this at http://codereview.appspot.com/3981048/

Affected files:
   M price_list.py


Index: price_list.py
===================================================================
--- a/price_list.py
+++ b/price_list.py
@@ -1,14 +1,44 @@
  #This file is part of Tryton.  The COPYRIGHT file at the top level of
  #this repository contains the full copyright notices and license terms.
  from __future__ import with_statement
-import re
  from decimal import Decimal
+import tokenize
+from StringIO import StringIO
  from trytond.model import ModelView, ModelSQL, fields
  from trytond.tools import safe_eval
  from trytond.pyson import If, In, Eval, Get
  from trytond.transaction import Transaction

-_RE_DECIMAL = re.compile('([\.0-9]+(\.[0-9]+)?)')
+
+# code snippet taken from http://docs.python.org/library/tokenize.html
+def decistmt(s):
+    """Substitute Decimals for floats in a string of statements.
+
+    >>> from decimal import Decimal
+    >>> s = 'print +21.3e-5*-.1234/81.7'
+    >>> decistmt(s)
+    "print +Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7')"
+
+    >>> exec(s)
+    -3.21716034272e-007
+    >>> exec(decistmt(s))
+    -3.217160342717258261933904529E-7
+    """
+    result = []
+    # tokenize the string
+    g = tokenize.generate_tokens(StringIO(s).readline)
+    for toknum, tokval, _, _, _  in g:
+        # replace NUMBER tokens
+        if toknum == tokenize.NUMBER and '.' in tokval:
+            result.extend([
+                (tokenize.NAME, 'Decimal'),
+                (tokenize.OP, '('),
+                (tokenize.STRING, repr(tokval)),
+                (tokenize.OP, ')')
+            ])
+        else:
+            result.append((toknum, tokval))
+    return tokenize.untokenize(result)


  class PriceList(ModelSQL, ModelView):
@@ -201,7 +231,6 @@
          '''
          context = Transaction().context.copy()
          context['Decimal'] = Decimal
- return safe_eval(_RE_DECIMAL.sub(lambda m: "Decimal('%s')" % m.group(1),
-            line.formula), context)
+        return safe_eval(decistmt(line.formula), context)

  PriceListLine()


--
[email protected] mailing list

Reply via email to