commit 8e64f048687ef5affed079788f285e3c0ad9b4ef
parent c1319b7331c50f433684b266a4912cc93198ef10
Author: lash <dev@holbrook.no>
Date: Sun, 24 May 2026 11:21:20 -0600
Attach entry index to ledger object
Diffstat:
5 files changed, 178 insertions(+), 79 deletions(-)
diff --git a/dummy/tests/accountsindex.py b/dummy/tests/accountsindex.py
@@ -0,0 +1,76 @@
+import logging
+import datetime
+import unittest
+import os
+
+from whee.mem import MemStore
+
+from usawa import Ledger, UnitIndex, EntryPart, Entry, DemoWallet, ACL, schema_path
+from usawa.store import LedgerStore
+from usawa.account import AccountIndex, AccountType, AccountDisplay
+from usawa.error import AccountError
+from usawa.index.account import EntryAccountIndex
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+testdir = os.path.realpath(os.path.dirname(__file__))
+
+class TestAccountsIndex(unittest.TestCase):
+
+
+ def setUp(self):
+ self.store = MemStore()
+ self.eidx = EntryAccountIndex()
+
+
+ def test_accountsindex(self):
+ s = 'FOO'
+ uidx = UnitIndex(s)
+ wallet = DemoWallet()
+ o = Ledger(uidx, wallet=wallet)
+ o.register_callback(self.eidx.entry_callback)
+ store = LedgerStore(self.store, ledger=o)
+ store.start()
+
+
+ x = EntryPart(s + '.Income/foo', 1337, debit=True)
+ y = EntryPart(s + '.Asset/foo', 1337)
+ v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
+ v.add_part(x)
+ v.add_part(y)
+ v.sign(wallet)
+ store.add_entry(v, update_ledger=True)
+
+ x = EntryPart(s + '.Expense/bar', 42, debit=True)
+ y = EntryPart(s + '.Liability/bar', 42)
+ v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
+ v.add_part(x)
+ v.add_part(y)
+ v.sign(wallet)
+ store.add_entry(v, update_ledger=True)
+
+ x = EntryPart(s + '.Expense/bar', 42, debit=True)
+ y = EntryPart(s + '.Liability/bar', 42)
+ v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
+ v.add_part(x)
+ v.add_part(y)
+ v.sign(wallet)
+ store.add_entry(v, update_ledger=True)
+
+ self.eidx.start('FOO.income/foo')
+ r = list(self.eidx)
+ self.assertEqual(len(r), 1)
+ entry = Entry.empty(serial=r[0])
+ entry = store.get_entry(entry)
+
+ self.eidx.start('FOO.expense/bar')
+ r = list(self.eidx)
+ self.assertEqual(len(r), 2)
+ for v in r:
+ entry = Entry.empty(serial=v)
+ entry = store.get_entry(entry)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/dummy/tests/entryindex.py b/dummy/tests/entryindex.py
@@ -0,0 +1,59 @@
+import logging
+import datetime
+import unittest
+import os
+import uuid
+
+from usawa import Ledger, UnitIndex, EntryPart, Entry, DemoWallet
+from usawa.store import LedgerStore
+from usawa.error import AccountError
+from usawa.index import EntryIndex
+
+logging.basicConfig(level=logging.DEBUG)
+logg = logging.getLogger()
+
+testdir = os.path.realpath(os.path.dirname(__file__))
+
+class TestEntryIndex(unittest.TestCase):
+
+ def setUp(self):
+ self.eidx = EntryIndex(digest=True)
+ self.uidx = UnitIndex('FOO')
+ self.ledger = Ledger(self.uidx, topic=b'bar', entry_index=self.eidx)
+
+
+ def test_entry_index(self):
+ wallet = DemoWallet()
+
+ dst = EntryPart('FOO.Asset/foo', 1337)
+ src = EntryPart('FOO.Income/foo', 1337, debit=True)
+ entry_a = Entry(1, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), ref=str(uuid.uuid4()), description='foo', unitindex=self.uidx)
+ o = entry_a
+ o.add_part(src)
+ o.add_part(dst)
+ o.sign(wallet)
+ self.ledger.add_entry(o)
+
+ dst = EntryPart('FOO.Expense/bar', 42)
+ src = EntryPart('FOO.Asset/bar', -42, debit=True)
+ now = datetime.datetime.now(datetime.UTC)
+ entry_b = Entry(2, now, parent=self.ledger.cur, ref=str(uuid.uuid4()), description='bar', unitindex=self.uidx)
+ o = entry_b
+ o.add_part(src)
+ o.add_part(dst)
+ o.sign(wallet)
+ self.ledger.add_entry(o)
+
+ r = self.eidx.get_ref(entry_a)
+ self.assertEqual(r, entry_a.ref)
+ r = self.eidx.get_digest(entry_a)
+ self.assertEqual(r, entry_a.sum())
+
+ r = self.eidx.get_ref(entry_b)
+ self.assertEqual(r, entry_b.ref)
+ r = self.eidx.get_digest(entry_b)
+ self.assertEqual(r, entry_b.sum())
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/dummy/tests/index.py b/dummy/tests/index.py
@@ -1,78 +0,0 @@
-import logging
-import datetime
-import unittest
-import os
-
-from whee.mem import MemStore
-
-from usawa import UnitIndex
-from usawa import Ledger, UnitIndex, EntryPart, Entry, DemoWallet, ACL, schema_path
-from usawa.store import LedgerStore
-from usawa.account import AccountIndex, AccountType, AccountDisplay
-from usawa.error import AccountError
-from usawa.index.account import EntryAccountIndex
-
-logging.basicConfig(level=logging.DEBUG)
-logg = logging.getLogger()
-
-testdir = os.path.realpath(os.path.dirname(__file__))
-
-class TestIndex(unittest.TestCase):
-
-
- def setUp(self):
- self.store = MemStore()
- self.eidx = EntryAccountIndex()
-
-
- def test_accountsindex(self):
- s = 'FOO'
- uidx = UnitIndex(s)
- wallet = DemoWallet()
- o = Ledger(uidx, wallet=wallet)
- o.register_callback(self.eidx.entry_callback)
- store = LedgerStore(self.store, ledger=o)
- store.start()
-
-
- x = EntryPart(s + '.Income/foo', 1337, debit=True)
- y = EntryPart(s + '.Asset/foo', 1337)
- v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x)
- v.add_part(y)
- v.sign(wallet)
- store.add_entry(v, update_ledger=True)
-
- x = EntryPart(s + '.Expense/bar', 42, debit=True)
- y = EntryPart(s + '.Liability/bar', 42)
- v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x)
- v.add_part(y)
- v.sign(wallet)
- store.add_entry(v, update_ledger=True)
-
- x = EntryPart(s + '.Expense/bar', 42, debit=True)
- y = EntryPart(s + '.Liability/bar', 42)
- v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x)
- v.add_part(y)
- v.sign(wallet)
- store.add_entry(v, update_ledger=True)
-
- self.eidx.start('FOO.income/foo')
- r = list(self.eidx)
- self.assertEqual(len(r), 1)
- entry = Entry.empty(serial=r[0])
- entry = store.get_entry(entry)
-
- self.eidx.start('FOO.expense/bar')
- r = list(self.eidx)
- self.assertEqual(len(r), 2)
- for v in r:
- entry = Entry.empty(serial=v)
- entry = store.get_entry(entry)
-
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/dummy/usawa/index/entry.py b/dummy/usawa/index/entry.py
@@ -0,0 +1,38 @@
+class EntryIndex:
+
+ def __init__(self, ref=True, digest=False):
+ self.idx = {}
+ self.idx_r = {}
+ self.idx_z = {}
+ self.idx_zr = {}
+ self.m = 0
+ if ref:
+ self.m |= 1
+ if digest:
+ self.m |= 2
+ if self.m == 0:
+ raise AttributeError('nonsense index without anything to index')
+
+
+ def register(self, entry):
+ if self.m & 1 > 0:
+ if entry.ref == None:
+ raise AttrubuteError('ref missing')
+ self.idx[entry.serial] = entry.ref
+ self.idx_r[entry.ref] = entry.serial
+ if self.m & 2 > 0:
+ z = entry.sum()
+ self.idx_z[entry.serial] = z
+ self.idx_zr[z] = entry.serial
+
+
+ def get_ref(self, entry):
+ if self.m & 1 == 0:
+ raise AttributeError('not a ref index')
+ return self.idx[entry.serial]
+
+
+ def get_digest(self, entry):
+ if self.m & 1 == 0:
+ raise AttributeError('not a ref index')
+ return self.idx_z[entry.serial]
diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py
@@ -248,7 +248,7 @@ class Ledger(UsawaElement):
: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):
+ def __init__(self, unitindex, acl=None, serial=0, base=DEFAULTPARENT, topic=None, src=None, wallet=None, entry_index=None):
self.uidx = unitindex
self.sigs = {}
self.entries = {}
@@ -258,6 +258,7 @@ class Ledger(UsawaElement):
self.lookup_algo = 'sha512'
self.pre_cb = []
self.post_cb = []
+ self.entry_index = entry_index
for k in self.uidx.syms():
if self.running.get(k) != None:
@@ -528,6 +529,9 @@ class Ledger(UsawaElement):
if not fn(entry):
raise VerifyError('entry post callback not passed')
+ if self.entry_index:
+ self.entry_index.register(entry)
+
"""Update running total according to the entry.