commit 3bf0b89cc80dc2a4a076728b4a32ce92e97f5630
parent 53dde933bd84750594973c33794a6aa9ab2300ff
Author: lash <dev@holbrook.no>
Date: Sat, 4 Apr 2026 21:46:09 -0600
WIP Flexible virt real definition, implement for account
Diffstat:
4 files changed, 51 insertions(+), 15 deletions(-)
diff --git a/dummy/usawa/account.py b/dummy/usawa/account.py
@@ -17,7 +17,7 @@ def check_path_parts(path):
return (typ, parts[1:],)
-def from_account_path(p, sym=None, typ=None):
+def from_account_path(p, sym=None, typ=None, virt=False):
if sym != None:
p = sym + '.' + p
o = p.split('.')
@@ -54,7 +54,7 @@ class Account:
path_parser = from_account_path
- def __init__(self, sym, typ, segments):
+ def __init__(self, sym, typ, segments, virt=False):
if not isinstance(typ, AccountType):
raise ValueError('invalid account type: ' + typ)
self.sym = sym
@@ -62,12 +62,13 @@ class Account:
if isinstance(segments, str):
segments = [segments]
self.segments = segments
+ self.virt = False
@staticmethod
- def from_path(path, sym=None, typ=None):
- o = Account.path_parser(path, sym=sym, typ=typ)
- return Account(o[0], o[1], o[2])
+ def from_path(path, sym=None, typ=None, virt=False):
+ o = Account.path_parser(path, sym=sym, typ=typ, virt=virt)
+ return Account(o[0], o[1], o[2], virt=virt)
def to_path(self, display=AccountDisplay.full):
@@ -112,12 +113,11 @@ class AccountIndex:
break
o.add(v.strip())
f.close()
-# return AccountIndex.from_io(f, closer=f.close)
return o
- def add(self, path, sym=None, typ=None):
- account = Account.from_path(path, sym=sym, typ=typ)
+ def add(self, path, sym=None, typ=None, virt=False):
+ account = Account.from_path(path, sym=sym, typ=typ, virt=virt)
try:
sym = self.uidx.sym(account.sym)
except KeyError:
diff --git a/dummy/usawa/data/schema.xsd b/dummy/usawa/data/schema.xsd
@@ -79,8 +79,10 @@
<xs:complexType name="Unit">
<xs:sequence>
<xs:element name="precision" type="xs:positiveInteger" maxOccurs="1" minOccurs="1" />
+ <xs:element name="virt" type="xs:string" maxOccurs="unbounded" minOccurs="0" />
</xs:sequence>
<xs:attribute name="sym" type="xs:string" />
+ <xs:attribute name="real" type="xs:boolean" />
</xs:complexType>
<xs:complexType name="Rate">
diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py
@@ -139,13 +139,16 @@ class RunningTotal:
:rtype: usawa.UnitIndex
"""
@staticmethod
- def from_tree(tree, unitindex):
+ def from_tree(tree, unitindex, real=False):
unit = tree.get('unit')
asset = int(tree.find('asset', namespaces=nsmap()).text)
liability = int(tree.find('liability', namespaces=nsmap()).text)
income = int(tree.find('income', namespaces=nsmap()).text)
expense = int(tree.find('expense', namespaces=nsmap()).text)
- return RunningTotal(unit, unitindex, asset=int(asset), liability=int(liability), income=int(income), expense=int(expense))
+ o = RunningTotal(unit, unitindex, asset=int(asset), liability=int(liability), income=int(income), expense=int(expense))
+ if real:
+ o.set_real()
+ return o
@@ -243,6 +246,7 @@ class Ledger(UsawaElement):
:type wallet: usawa.Wallet
:todo: Add warnings for ignored parameters
:todo: Remove enclosing array for entries
+ :todo: Implement real and virt unit indices for running totals
"""
def __init__(self, unitindex, acl=None, serial=0, base=DEFAULTPARENT, topic=None, src=None, wallet=None):
self.uidx = unitindex
@@ -597,7 +601,7 @@ class Ledger(UsawaElement):
for v in part.iter(NSPREFIX + 'real'):
sym = v.get('unit')
- o = RunningTotal.from_tree(v, unitindex)
+ o = RunningTotal.from_tree(v, unitindex, real=True)
ledger.running[o.sym] = o
logg.debug('ledger running total {} (real): {}'.format(o.sym, o))
diff --git a/dummy/usawa/unit.py b/dummy/usawa/unit.py
@@ -28,7 +28,7 @@ class UnitIndex:
:param precision: The decimal precision of the base unit. Default is 2.
:type precision: int
"""
- def __init__(self, base=None, precision=None):
+ def __init__(self, base=None, precision=None, virt=False):
self.detail = {}
self.rate = {}
self.base = None
@@ -38,6 +38,10 @@ class UnitIndex:
self.detail = {base: precision}
self.set_rate(base, UnitIndex.default_exchange)
self.base = base
+ self.real = {base: True}
+ self.virt = {}
+ if virt:
+ self.virt[base] = True
def clone(self):
@@ -87,9 +91,15 @@ class UnitIndex:
:param ex: The exchange rate of the unit, relative to the base unit. Default is 1000000000 (1.0).
:type ex: int or float
"""
- def add(self, sym, precision=2, rate=1000000000):
+ def add(self, sym, precision=2, rate=1000000000, virt=None):
+ if self.detail.get(sym) != None:
+ raise AttributeError('sym already added')
self.detail[sym] = precision
self.set_rate(sym, rate)
+ if virt:
+ self.virt[sym] = True
+ else:
+ self.real[sym] = True
"""Create a unit index object from XML.
@@ -109,9 +119,15 @@ class UnitIndex:
base = tree.get('base')
r = UnitIndex(base)
for o in tree.iter(NSPREFIX + 'unit'):
+ sym = o.get('sym')
+ if o.get('real'):
+ r.real[sym] = True
precision = int(o.find('precision', namespaces=nsmap()).text)
- logg.debug('add unit {} precision {}'.format(o.get('sym'), precision))
- r.detail[o.get('sym')] = precision
+ virt = o.find('virt', namespaces=nsmap())
+ if virt != None:
+ r.virt[sym] = True
+ logg.debug('add unit {} precision {}'.format(sym, precision))
+ r.detail[sym] = precision
r.check()
return r
@@ -161,6 +177,14 @@ class UnitIndex:
return list(self.detail.keys())
+ def reals(self):
+ return list(self.real.keys())
+
+
+ def virts(self):
+ return list(self.virt.keys())
+
+
"""Generate a string representing the decimal equivalent of the value to the precision of the unit.
:param sym: The symbol to use precision for.
@@ -291,9 +315,15 @@ class UnitIndex:
for k in self.detail.keys():
unit = lxml.etree.SubElement(tree, 'unit')
unit.set('sym', k)
+ if self.real.get(k):
+ unit.set('real', '1')
o = lxml.etree.SubElement(unit, 'precision')
o.text = str(self.detail[k])
unit.append(o)
+ if self.virt.get(k):
+ o = lxml.etree.SubElement(unit, 'virt')
+ o.text = '1'
+ unit.append(o)
tree.append(unit)
return tree