commit 186ddddd90a9e21f32f42786d7c0ee26b13859d7
parent a92686dcda65ba4f56a46eec4530e8a3371602e9
Author: lash <dev@holbrook.no>
Date: Wed, 11 Mar 2026 07:57:31 -0600
Add account object to use for validation and in index
Diffstat:
2 files changed, 70 insertions(+), 17 deletions(-)
diff --git a/dummy/tests/account.py b/dummy/tests/account.py
@@ -20,21 +20,24 @@ class TestAccount(unittest.TestCase):
def test_account_lock(self):
idx = AccountIndex(self.uidx)
- idx.add('FOO', 'bar.baz')
- idx.add('FOO', 'bar.baz')
+ # missing account type
+ with self.assertRaises(AttributeError):
+ idx.add('bar/baz', sym='FOO')
+ idx.add('liability/bar/baz', sym='FOO')
+ idx.add('liability/bar/baz', sym='FOO')
with self.assertRaises(AccountError):
- idx.add('FOO', 'bar.baz-')
+ idx.add('asset/bar/baz-', sym='FOO')
with self.assertRaises(AccountError):
- idx.add('BAZ', 'foo.bar')
- self.assertFalse(idx.check('BAR', 'foo.baz'))
- self.assertTrue(idx.check('FOO', 'bar.baz'))
+ idx.add('asset/foo/bar', sym='BAZ')
+ self.assertFalse(idx.check('BAR', 'liability/foo/baz'))
+ self.assertTrue(idx.check('FOO', 'liability/bar/baz'))
def test_account_list(self):
idx = AccountIndex(self.uidx)
- idx.add('FOO', 'bar.bar')
- idx.add('FOO', 'bar.baz')
- idx.add('BAR', 'foo.baz')
+ idx.add('asset/bar/bar', sym='FOO')
+ idx.add('liability/bar/baz', sym='FOO')
+ idx.add('asset/foo/baz', sym='BAR')
v = list(idx)
logg.debug('results {}'.format(v))
self.assertEqual(len(v), 3)
diff --git a/dummy/usawa/account.py b/dummy/usawa/account.py
@@ -1,3 +1,4 @@
+import enum
import logging
from .error import AccountError
@@ -5,32 +6,81 @@ from .error import AccountError
logg = logging.getLogger('account')
-def default_check(path):
- parts = path.split('.')
+def check_path_parts(path):
+ parts = path.split('/')
for v in parts:
if not v.isalnum():
raise AccountError('invalid part: ' + v)
- return True
+ #return True
+ typ = getattr(AccountType, parts[0].lower())
+ return (typ, parts,)
+
+
+def from_account_path(p, sym=None, typ=None):
+ if sym != None:
+ p = sym + '.' + p
+ o = p.split('.')
+ logg.debug('have {} {} {}'.format(p, sym, typ))
+ if len(o) != 2:
+ raise ValueError('account path should have zero or one symbol specifier')
+ sym = o[0]
+ o = check_path_parts(o[1])
+ typ = o[0]
+ path = o[1]
+
+ return (sym, typ, path,)
+
+
+class AccountType(enum.Enum):
+ liability = 'Liability'
+ asset = 'Asset'
+ income = 'Income'
+ expense = 'Expense'
+ imprt = 'Import'
+ export = 'Export'
+
+
+class Account:
+
+ path_parser = from_account_path
+
+ def __init__(self, sym, typ, segments):
+ if not isinstance(typ, AccountType):
+ raise ValueError('invalid account type')
+ self.sym = sym
+ self.typ = typ
+ self.segments = segments
+
+
+ @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 to_path(self):
+ path = self.segments.join('/')
+ path = '{}.{}/{}'.format(self.sym, self.typ, path)
class AccountIndex:
- def __init__(self, unitindex, pathvalidator=default_check):
+ def __init__(self, unitindex): #, pathvalidator=default_check):
self.uidx = unitindex
self.accounts = {}
self.locked = False
- self.validate = pathvalidator
+ #self.validate = pathvalidator
self.iterval = None
- def add(self, sym, path):
+ def add(self, path, sym=None, typ=None):
+ account = Account.from_path(path, sym=sym, typ=typ)
try:
- sym = self.uidx.sym(sym)
+ sym = self.uidx.sym(account.sym)
except KeyError:
raise AccountError('unknown unit ' + sym)
if self.locked:
raise AccountError('account index locked')
- self.validate(path)
if self.accounts.get(sym) == None:
self.accounts[sym] = []
elif path in self.accounts[sym]: