commit 357ae58af2a0510fea4564eec90ff808b5809c4a
parent 7f577b7fcd33cd43c41f2ab92a557e943664161e
Author: lash <dev@holbrook.no>
Date: Sat, 10 Jan 2026 21:16:13 +0100
WIP consolidate args parsing and context building
Diffstat:
4 files changed, 112 insertions(+), 50 deletions(-)
diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py
@@ -222,6 +222,8 @@ class Ledger:
self.cur = self.base
self.entries[self.uidx.base] = []
tree = lxml.etree.XML('<ledger xmlns="http://usawa.defalsify.org/" version="{}"></ledger>'.format(XML_FORMAT_VERSION))
+ if self.tree == None:
+ self.tree = tree
o = lxml.etree.SubElement(tree, NSPREFIX + 'topic', nsmap=nsmap())
if topic == None:
if self.topic == None:
diff --git a/dummy/usawa/runnable/add.py b/dummy/usawa/runnable/add.py
@@ -48,7 +48,7 @@ class Context:
def from_args(args):
ctx = Context()
ctx.unit = args.unit
- ctx.uidx = UnitIndex(ctx.unit)
+ ctx.uidx = UnitIndex(ctx.unit, precision=args.unit_precision)
if args.description != None:
ctx.description = args.description
if args.r != None:
@@ -76,8 +76,6 @@ class Context:
for v in self.dst:
if v == None:
raise ValueError('invalid dst')
- #if self.topic == None:
- # raise ValueError('invalid topic')
if self.ref == None:
raise ValueError('invalid ref')
@@ -120,9 +118,10 @@ argp.add_argument('-o', type=str, dest='output', help='output file for updated X
argp.add_argument('--src-type', dest='src_type', type=str, choices=CATEGORIES, default='expense', help='source type')
argp.add_argument('--dst-type', dest='dst_type', type=str, choices=CATEGORIES, default='asset', help='dest type')
argp.add_argument('-d', '--description', dest='description', type=str, help='interactive edit')
-argp.add_argument('-u', '--unit', type=str, default='BTC', help='Unit to use for transaction')
-argp.add_argument('--unit-precision', type=int, default=2, help='Unit precision')
-argp.add_argument('--unit-rate', type=float, default=1.0, help='Unit exchange rate')
+# TODO: read default from xml if not defined
+argp.add_argument('-u', '--unit', type=str, default=UnixIndex.default_unit, help='Unit to use for transaction')
+argp.add_argument('--unit-precision', dest='unit_precision', type=int, default=UnixIndex.default_precision, help='Unit precision')
+argp.add_argument('--unit-rate', dest='unit_precision', type=float, default=1.0, help='Unit exchange rate')
argp.add_argument('ledger_xml_file', type=str, help='load ledger metadata from XML file')
arg = argp.parse_args()
ctx = Context.from_args(arg)
@@ -139,8 +138,6 @@ store = LedgerStore(db, ledger)
pk = store.get_key()
wallet = DemoWallet(privatekey=pk)
dt = datetime.datetime.now()
-close_fn = None
-f = None
def do_interactive(ctx):
diff --git a/dummy/usawa/runnable/create.py b/dummy/usawa/runnable/create.py
@@ -1,6 +1,9 @@
import os
+import sys
import logging
import urllib.parse
+import argparse
+import datetime
from usawa import Ledger, DemoWallet, UnitIndex
from usawa.store import LedgerStore
@@ -10,19 +13,65 @@ logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
+class Context:
+
+ def __init__(self):
+ self.unit = None
+ self.unit_precision = None
+ self.uidx = None
+ self.topic = None
+ self.uri = None
+ self.output = None
+ self.f = None
+
+
+ def close(self):
+ if self.f and self.f != sys.stdout:
+ self.f.close()
+
+
+ def open(self, output):
+ if output == '<stdout>':
+ self.f = sys.stdout.buffer
+ logg.debug('output is stdout')
+ else:
+ self.f = open(output, 'wb')
+ return self
+
+
+ @staticmethod
+ def from_args(args):
+ ctx = Context()
+ ctx.unit = args.unit
+ ctx.unit_precision = args.unit_precision
+ ctx.uidx = UnitIndex(ctx.unit, precision=ctx.unit_precision)
+ ctx.topic = args.topic
+ ctx.uri = args.src_uri
+ if args.output != None:
+ ctx.output = os.path.realpath(args.output)
+ else:
+ ctx.output = '<stdout>'
+ return ctx
+
+
+ def validate(self):
+ self.topic = parse_topic(self.topic)
+ self.uri = parse_uri(self.uri)
+ self.unit = parse_unit(self.unit)
+ self.unit_precision = parse_unit_precision(self.unit_precision)
+ return self
+
+
def parse_topic(v):
topic = None
if len(v) > 2:
if v[:2] == '0x':
v = v[2:]
- try:
- bytes.fromhex(v)
- topic = v
- except ValueError:
- if not isinstance(v, str):
- raise ValueError('invalid topic')
- topic = v.encode('utf-8').hex()
-
+ topic = bytes.fromhex(v)
+ elif isinstance(v, str):
+ topic = v.encode('utf-8').hex().encode('utf-8')
+ else:
+ raise ValueError('invalid topic')
return topic
@@ -32,47 +81,64 @@ def parse_unit(v):
return v.upper()
-
-print("Creating new ledger")
-v = input("Topic: ")
-topic = None
-if len(v) > 0:
- r = parse_topic(v)
- topic = bytes.fromhex(r)
-logg.debug('topic {} -> {}'.format(v, topic))
+def parse_uri(v):
+ o = urllib.parse.urlparse(v)
+ return urllib.parse.urlunparse(o)
-v = input("Default unit: (default: BTC): ")
-if len(v) == 0:
- v = 'BTC'
-unit = parse_unit(v)
-v = input("Unit decimals (default: 2): ")
-if len(v) == 0:
- v = 2
-dec = int(v)
+def parse_unit_precision(v):
+ return int(v)
-uidx = UnitIndex(unit, precision=dec)
-v = input("Source URI: ")
-src = None
-if len(v) > 0:
- o = urllib.parse.urlparse(v)
- src = urllib.parse.urlunparse(o)
+def input_or_default(prompt, default=None, postfix=': ', validate_fn=None):
+ if default != None:
+ postfix = ' [{}]'.format(default) + postfix
+ v = input(prompt + postfix)
+ if len(v) == 0:
+ if default == None:
+ raise ValueError('empty value and no default')
+ v = default
+ if validate_fn != None:
+ validate_fn(v)
+ return v
+
-v = input("XML output filename (default: start.xml):")
-fp = None
-if len(v) == 0:
- fp = os.path.join('.', 'start.xml')
-fp = os.path.realpath(fp)
+argp = argparse.ArgumentParser()
+argp.add_argument('-i', action='store_true', help='interactive edit')
+argp.add_argument('-t', dest='topic', type=str, help='ledger topic')
+argp.add_argument('-u', '--unit', type=str, default=UnitIndex.default_unit, help='Unit to use for transaction')
+argp.add_argument('-o', type=str, dest='output', help='output file for updated XML document')
+argp.add_argument('-l', type=str, dest='src_uri', help='URI for data source')
+argp.add_argument('--unit-precision', type=int, default=UnitIndex.default_precision, help='Unit precision')
+argp.add_argument('--unit-rate', type=float, default=1.0, help='Unit exchange rate')
+arg = argp.parse_args()
+ctx = Context.from_args(arg)
-ledger = Ledger(uidx, topic=topic, src=src)
+def do_interactive(ctx):
+ logg.debug("Creating new ledger")
+ v = input_or_default("Topic", ctx.topic)
+ ctx.unit = input_or_default("Default unit", ctx.unit)
+ ctx.unit_precision = input_or_default("Unit decimals", ctx.unit_precision)
+ ctx.uri = input_or_default("Source URI", ctx.uri)
+ input_or_default("XML output filename", ctx.output)
+ return ctx
+
+
+if arg.i:
+ ctx = do_interactive(ctx)
+ctx = ctx.open(ctx.output)
+ctx.validate()
+
+ledger = Ledger(ctx.uidx, topic=ctx.topic, src=ctx.uri)
db = ValkeyStore('')
store = LedgerStore(db, ledger)
pk = None
wallet = None
+dt = datetime.datetime.now()
+
try:
pk = store.get_key()
except FileNotFoundError:
@@ -83,7 +149,5 @@ if wallet == None:
wallet = DemoWallet(privatekey=pk)
logg.info('loaded existing key. {}'.format(wallet.pubkey().hex()))
-logg.info('writing XML to file: {}'.format(fp))
-f = open(fp, 'wb')
-f.write(ledger.to_string())
-f.close()
+ctx.f.write(ledger.to_string())
+ctx.close()
diff --git a/dummy/usawa/unit.py b/dummy/usawa/unit.py
@@ -5,12 +5,11 @@ from .xml import nsmap
logg = logging.getLogger('usawa.unit')
-BASE_UNIT = 'BTC'
-
class UnitIndex:
default_precision = 2
+ default_unit = 'BTC'
"""UnitIndex holds metadata for units of account.