commit cd9355a09d69b47a8ee57d7d0a3650a54aaab50c
parent 97e179e76e9ad89a926a800945b96b846f88e600
Author: lash <dev@holbrook.no>
Date: Sun, 19 Apr 2026 22:53:30 -0600
Entry tag deserialize, ensure extref store
Diffstat:
4 files changed, 64 insertions(+), 35 deletions(-)
diff --git a/dummy/usawa/cli/entry.py b/dummy/usawa/cli/entry.py
@@ -16,7 +16,7 @@ class AbortMenu(Exception):
pass
-def writehelp(w=sys.stdout):
+def writehelp(w=sys.stdout, short=False):
s = """h: this help
i: input account
o: output account
@@ -178,7 +178,7 @@ def try_entry_uuid(ctx, v):
def try_entry_serial(ctx, v):
v = int(v)
entry = Entry(v, None)
- return ctx.store.get_entry(entry)
+ return ctx.store.get_entry(entry, unitindex=ctx.uidx)
def try_entry_digest(ctx, k):
@@ -220,7 +220,7 @@ def try_entry(ctx, entry_spec):
class EntrySession:
- def __init__(self, ctx, entry=None, heading=None, description=None, extref=None, dt=None, ref=None, amount=None, lines=[], base=None):
+ def __init__(self, ctx, entry=None, heading=None, description=None, extref=None, dt=None, ref=None, amount=None, lines=[], base=None, dynamic=False):
# context props
self.ctx = ctx
self.unitbase = base
@@ -239,6 +239,7 @@ class EntrySession:
self.part_side = 'src'
self.have_src = False
self.have_dst = False
+ self.dynamic = dynamic
# supplementary props
self.heading = heading
@@ -251,9 +252,9 @@ class EntrySession:
self.entry = try_entry(self.ctx, entry)
if self.entry == None:
self.entry = Entry.empty(unitindex=self.ctx.uidx, description=self.description, ref=self.ref, extref=self.extref, tx_date=self.dt, parent=self.ctx.ledger.cur)
- if self.entry.serial > 0:
- raise NotImplementedError('entry edit not yet implemented')
- self._do_prepare()
+ if self.entry.serial < 1:
+ #raise NotImplementedError('entry edit not yet implemented')
+ self._do_prepare()
def _cur_amount(self):
@@ -345,31 +346,40 @@ class EntrySession:
def handle_input(self, v):
- if v == 'i' or v == 'o':
- k = 'src'
- if v == 'o':
- k = 'dst'
- try:
- self.enter_part(side=k)
- except ValueError as e:
- logg.error('enter part fail: ' + str(e))
+ if v == 'x':
+ handle_ref(self.ctx, self.entry, v)
return True
- if v == 'q':
- raise StopIteration()
if v == '+' or v == '-':
r = handle_tag(self.ctx, self.entry, v)
return True
+ if v == 'q':
+ raise StopIteration()
if v == 'w':
self.commit = True
self.final = True
return False
+ if v == 'v':
+ handle_view(self.ctx, self.entry, v)
+ return True
+
+ if self.entry.serial > 0:
+ logg.error('illegal choice for committed entry')
+ return True
+
if v == 't':
self.commit = True
return False
- if v == 'v':
- handle_view(self.ctx, self.entry, v)
+
+ if v == 'i' or v == 'o':
+ k = 'src'
+ if v == 'o':
+ k = 'dst'
+ try:
+ self.enter_part(side=k)
+ except ValueError as e:
+ logg.error('enter part fail: ' + str(e))
return True
- if v == 'x' or v == 'y':
+ if v == 'y':
handle_ref(self.ctx, self.entry, v)
return True
if v == 'd':
@@ -448,8 +458,9 @@ class EntrySession:
def start(self, skip_first=False):
- if not skip_first:
- self.do_interactive_one()
+ if self.entry.serial < 1:
+ if not skip_first:
+ self.do_interactive_one()
r = True
while r:
try:
@@ -477,6 +488,10 @@ Extref: {}
self.entry.extref,
)
+ tags = []
+ if self.entry.tags:
+ tags = self.entry.tags
+ s += "Tags: " + ', '.join(tags) + "\n"
s += "Description: " + self.get_description() + "\n"
for v in self.lines:
diff --git a/dummy/usawa/entry.py b/dummy/usawa/entry.py
@@ -363,9 +363,9 @@ class Entry(UsawaElement):
for v in self.attachment:
attach.append(v.get_digest(binary=True))
- tags = None
+ tags = []
if self.tags:
- tags = self.tags.serialize()
+ tags = self.tags
base = super(Entry, self).serialize()
logg.debug('serializing with parent {}'.format(self.parent.hex()))
@@ -381,6 +381,7 @@ class Entry(UsawaElement):
debit,
attach,
tags,
+ self.extref,
]
return d
@@ -408,19 +409,28 @@ class Entry(UsawaElement):
parent = v[1]
serial = v[2]
ref = v[3].decode('utf-8')
+ extref = None
+ try:
+ extref = v[11]
+ except IndexError:
+ pass
date_reg = datetime.datetime.strptime(v[4].decode('utf-8'), '%Y%m%d%H%M%S')
date = datetime.datetime.strptime(v[5].decode('utf-8'), '%Y%m%d%H%M%S')
description = v[6].decode('utf-8')
dst_data = v[7]
src_data = v[8]
attach_data = v[9]
- tags = None
- try:
- tags = Tags.deserialize(v[10])
- except TypeError:
- pass
+ #tags = None
+ #try:
+ # tags = Tags.deserialize(v[10])
+ #except TypeError:
+ # pass
+ tags = []
+ for s in v[10]:
+ tags.append(s.decode('utf-8'))
o = Entry(serial, date, ref=ref, description=description, parent=parent, tx_datereg=date_reg, tags=tags, unitindex=unitindex)
super(Entry, o).deserialize(v[0])
+ o.balancer = Balancer(unitindex)
for v in src_data:
src = EntryPart.deserialize(v, debit=True)
o.add_part(src)
@@ -522,9 +532,9 @@ class Entry(UsawaElement):
:todo: Current version only takes into account single signature
"""
@staticmethod
- def unwrap(data, acl=None):
+ def unwrap(data, acl=None, unitindex=None):
v = rencode.loads(data)
- entry = Entry.deserialize(v[2])
+ entry = Entry.deserialize(v[2], unitindex=unitindex)
pubkey_bytes = v[0][0][1]
sig = v[1][0]
entry.add_signature(pubkey_bytes, sig)
@@ -599,6 +609,10 @@ class Entry(UsawaElement):
o.text = self.ref
data.append(o)
+ o = lxml.etree.Element('extref')
+ o.text = self.ref
+ data.append(o)
+
o = lxml.etree.Element('serial')
o.text = str(self.serial)
data.append(o)
@@ -680,7 +694,7 @@ class Entry(UsawaElement):
"""
def canon(self):
tree = self.to_tree(canon=True)
- b = lxml.etree.canonicalize(tree, strip_text=True, exclude_tags=['sig', 'lookup'])
+ b = lxml.etree.canonicalize(tree, strip_text=True, exclude_tags=['sig', 'lookup', 'extref'])
return b.encode('utf-8')
@@ -688,7 +702,7 @@ class Entry(UsawaElement):
def tag(self, tag):
if self.tags == None:
self.tags = []
- elif not tag in self.tags:
+ if not tag in self.tags:
self.tags.append(tag)
diff --git a/dummy/usawa/runnable/entry.py b/dummy/usawa/runnable/entry.py
@@ -54,7 +54,7 @@ def main():
ctx.set('unitbase', ctx.uidx.base)
ctx.set('commit', False)
- o = EntrySession(ctx, args.entry)
+ o = EntrySession(ctx, entry=args.entry)
for v in args.x:
o.attach_ref(v)
diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py
@@ -317,10 +317,10 @@ class EntryStore(KeyStore):
:raises: FileExistsError if entry is already in store.
:todo: optimize replacing asset stub with deserialized asset
"""
- def get_entry(self, entry, acl=None):
+ def get_entry(self, entry, acl=None, unitindex=None):
k = pfx_entry(self.ledger, entry)
v = self.db.get(k)
- entry = Entry.unwrap(v)
+ entry = Entry.unwrap(v, unitindex=unitindex)
# TODO: hacky!
i = 0
for o in entry.attachment: