mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
Implement some comparisons and arithmetics for GncNumeric
Derive some numeric comparisons and arithmetics from Fraction class https://github.com/python/cpython/blob/3.7/Lib/fractions.py and general information from https://docs.python.org/3/library/numbers.html#numbers.Integral These methods are bound closer to the gnucash-C-api than those from the fraction class. This is not the full set of comparisons and arithmetics, needs to be extended. It would be good to extend tests to cover this.
This commit is contained in:
parent
5388cc8e2c
commit
567df27cc7
@ -28,6 +28,8 @@
|
||||
# @author Jeff Green, ParIT Worker Co-operative <jeff@parit.ca>
|
||||
# @ingroup python_bindings
|
||||
|
||||
import operator
|
||||
|
||||
from enum import IntEnum
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@ -426,7 +428,7 @@ class GncNumeric(GnuCashCoreClass):
|
||||
elif len(args) == 1:
|
||||
arg = args[0]
|
||||
if isinstance(arg, int):
|
||||
return gnc_numeric_create(arg ,1)
|
||||
return gnc_numeric_create(arg, 1)
|
||||
elif isinstance(arg, float):
|
||||
return double_to_gnc_numeric(arg, GNC_DENOM_AUTO, GNC_HOW_DENOM_FIXED | GNC_HOW_RND_NEVER)
|
||||
elif isinstance(arg, str):
|
||||
@ -434,8 +436,10 @@ class GncNumeric(GnuCashCoreClass):
|
||||
if not string_to_gnc_numeric(arg, instance):
|
||||
raise TypeError('Failed to convert to GncNumeric: ' + str(args))
|
||||
return instance
|
||||
elif isinstance(arg, GncNumeric):
|
||||
return arg.instance
|
||||
else:
|
||||
raise TypeError('Only single int/float/str allowed: ' + str(args))
|
||||
raise TypeError('Only single int/float/str/GncNumeric allowed: ' + str(args))
|
||||
elif len(args) == 2:
|
||||
if isinstance(args[0], int) and isinstance(args[1], int):
|
||||
return gnc_numeric_create(*args)
|
||||
@ -451,6 +455,133 @@ class GncNumeric(GnuCashCoreClass):
|
||||
else:
|
||||
raise TypeError('Required single int/float/str or two ints: ' + str(args))
|
||||
|
||||
# from https://docs.python.org/3/library/numbers.html#numbers.Integral
|
||||
# and https://github.com/python/cpython/blob/3.7/Lib/fractions.py
|
||||
|
||||
def _operator_fallbacks(monomorphic_operator, fallback_operator):
|
||||
"""fallbacks are not needed except for method name,
|
||||
keep for possible later use"""
|
||||
def forward(a, b):
|
||||
if isinstance(b, GncNumeric):
|
||||
return monomorphic_operator(a, b)
|
||||
if isinstance(b, (int, float)):
|
||||
return monomorphic_operator(a, GncNumeric(b))
|
||||
else:
|
||||
return NotImplemented
|
||||
forward.__name__ = '__' + fallback_operator.__name__ + '__'
|
||||
forward.__doc__ = monomorphic_operator.__doc__
|
||||
|
||||
def reverse(b, a):
|
||||
if isinstance(a, (GncNumeric, int, float)):
|
||||
return forward(b, a)
|
||||
else:
|
||||
return NotImplemented
|
||||
reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
|
||||
reverse.__doc__ = monomorphic_operator.__doc__
|
||||
|
||||
return forward, reverse
|
||||
|
||||
def _add(a, b):
|
||||
return a.add(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
|
||||
|
||||
def _sub(a, b):
|
||||
return a.sub(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
|
||||
|
||||
def _mul(a, b):
|
||||
return a.mul(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
|
||||
|
||||
def _div(a, b):
|
||||
return a.div(b, GNC_DENOM_AUTO, GNC_HOW_RND_ROUND)
|
||||
|
||||
def _floordiv(a, b):
|
||||
return a.div(b, 1, GNC_HOW_RND_TRUNC)
|
||||
|
||||
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
|
||||
__iadd__ = __add__
|
||||
__sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
|
||||
__isub__ = __sub__
|
||||
__mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
|
||||
__imul__ = __mul__
|
||||
__truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
|
||||
__itruediv__ = __truediv__
|
||||
__floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
|
||||
__ifloordiv__ = __floordiv__
|
||||
|
||||
# Comparisons derived from https://github.com/python/cpython/blob/3.7/Lib/fractions.py
|
||||
def _lt(a, b):
|
||||
return a.compare(b) == -1
|
||||
|
||||
def _gt(a, b):
|
||||
return a.compare(b) == 1
|
||||
|
||||
def _le(a, b):
|
||||
return a.compare(b) in (0,-1)
|
||||
|
||||
def _ge(a, b):
|
||||
return a.compare(b) in (0,1)
|
||||
|
||||
def _eq(a, b):
|
||||
return a.compare(b) == 0
|
||||
|
||||
def _richcmp(self, other, op):
|
||||
"""Helper for comparison operators, for internal use only.
|
||||
Implement comparison between a GncNumeric instance `self`,
|
||||
and either another GncNumeric instance, an int or a float
|
||||
`other`. If `other` is not an instance of that kind, return
|
||||
NotImplemented. `op` should be one of the six standard
|
||||
comparison operators. The comparisons are based on
|
||||
GncNumeric.compare().
|
||||
"""
|
||||
import math
|
||||
if isinstance(other, GncNumeric):
|
||||
return op(other)
|
||||
elif isinstance(other, (int, float)):
|
||||
return op(GncNumeric(other))
|
||||
else:
|
||||
return NotImplemented
|
||||
|
||||
def __lt__(a, b):
|
||||
"""a < b"""
|
||||
return a._richcmp(b, a._lt)
|
||||
|
||||
def __gt__(a, b):
|
||||
"""a > b"""
|
||||
return a._richcmp(b, a._gt)
|
||||
|
||||
def __le__(a, b):
|
||||
"""a <= b"""
|
||||
return a._richcmp(b, a._le)
|
||||
|
||||
def __ge__(a, b):
|
||||
"""a >= b"""
|
||||
return a._richcmp(b, a._ge)
|
||||
|
||||
def __eq__(a, b):
|
||||
"""a == b"""
|
||||
return a._richcmp(b, a._eq)
|
||||
|
||||
def __bool__(a):
|
||||
"""a != 0"""
|
||||
return bool(a.num())
|
||||
|
||||
def __float__(self):
|
||||
return self.to_double()
|
||||
|
||||
def __int__(self):
|
||||
return int(self.to_double())
|
||||
|
||||
def __pos__(a):
|
||||
"""+a"""
|
||||
return GncNumeric(a.num(), a.denom())
|
||||
|
||||
def __neg__(a):
|
||||
"""-a"""
|
||||
return a.neg()
|
||||
|
||||
def __abs__(a):
|
||||
"""abs(a)"""
|
||||
return a.abs()
|
||||
|
||||
def to_fraction(self):
|
||||
from fractions import Fraction
|
||||
return Fraction(self.num(), self.denom())
|
||||
@ -673,7 +804,7 @@ from gnucash.gnucash_core_c import \
|
||||
# used for the how argument in arithmetic functions like GncNumeric.add
|
||||
from gnucash.gnucash_core_c import \
|
||||
GNC_HOW_DENOM_EXACT, GNC_HOW_DENOM_REDUCE, GNC_HOW_DENOM_LCD, \
|
||||
GNC_HOW_DENOM_FIXED
|
||||
GNC_HOW_DENOM_FIXED, GNC_HOW_DENOM_SIGFIG
|
||||
|
||||
# import account types
|
||||
from gnucash.gnucash_core_c import \
|
||||
|
Loading…
Reference in New Issue
Block a user