mmgen-ticker: various fixes and cleanups

This commit is contained in:
The MMGen Project 2025-10-12 10:01:51 +00:00
commit a8adef0be5
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
3 changed files with 41 additions and 36 deletions

View file

@ -25,7 +25,7 @@ from decimal import Decimal
from collections import namedtuple
from mmgen.color import red, yellow, green, blue, orange, gray
from mmgen.util import msg, msg_r, Msg, Msg_r, die, fmt, fmt_list, fmt_dict, list_gen
from mmgen.util import msg, msg_r, Msg, Msg_r, die, fmt, fmt_list, fmt_dict, list_gen, suf
from mmgen.ui import do_pager
homedir = os.getenv('HOME')
@ -99,18 +99,21 @@ class DataSource:
if not os.path.exists(cfg.cachedir):
os.makedirs(cfg.cachedir)
if not os.path.exists(self.json_fn):
open(self.json_fn, 'w').write('{}')
use_cached_data = cfg.cached_data and not gcfg.download
if use_cached_data:
data_type = 'json'
data_in = open(self.json_fn).read()
try:
data_in = open(self.json_fn).read()
except FileNotFoundError:
die(1, f'Cannot use cached data, because {self.json_fn_disp} does not exist')
else:
data_type = self.net_data_type
elapsed = int(time.time() - os.stat(self.json_fn).st_mtime)
if elapsed >= self.timeout or gcfg.testing:
try:
mtime = os.stat(self.json_fn).st_mtime
except FileNotFoundError:
mtime = 0
if (elapsed := int(time.time() - mtime)) >= self.timeout or gcfg.testing:
if gcfg.testing:
msg('')
self.fetch_delay()
@ -148,14 +151,14 @@ class DataSource:
if use_cached_data:
if not cfg.quiet:
msg(f'Using cached data from ~/{self.json_fn_rel}')
msg(f'Using cached data from {self.json_fn_disp}')
else:
if os.path.exists(self.json_fn):
os.rename(self.json_fn, self.json_fn + '.bak')
with open(self.json_fn, 'w') as fh:
fh.write(json_text)
if not cfg.quiet:
msg(f'JSON data cached to ~/{self.json_fn_rel}')
msg(f'JSON data cached to {self.json_fn_disp}')
if gcfg.download:
sys.exit(0)
@ -168,8 +171,8 @@ class DataSource:
return data
@property
def json_fn_rel(self):
return os.path.relpath(self.json_fn, start=homedir)
def json_fn_disp(self):
return '~/' + os.path.relpath(self.json_fn, start=homedir)
class coinpaprika(base):
desc = 'CoinPaprika'
@ -186,8 +189,9 @@ class DataSource:
self.asset_limit = int(cfg.asset_limit or self.dfl_asset_limit)
def rate_limit_errmsg(self, elapsed):
rem = self.timeout - elapsed
return (
f'Rate limit exceeded! Retry in {self.timeout-elapsed} seconds' +
f'Rate limit exceeded! Retry in {rem} second{suf(rem)}' +
('' if cfg.btc_only else ', or use --cached-data or --btc'))
@property
@ -270,7 +274,8 @@ class DataSource:
'last_updated': data['regularMarketTime']}
def rate_limit_errmsg(self, elapsed):
return f'Rate limit exceeded! Retry in {self.timeout-elapsed} seconds, or use --cached-data'
rem = self.timeout - elapsed
return f'Rate limit exceeded! Retry in {rem} second{suf(rem)}, or use --cached-data'
@property
def json_fn(self):
@ -364,10 +369,10 @@ def gen_data(data):
checking for duplicates.
"""
def dup_sym_errmsg(dup_sym):
def dup_sym_errmsg(data_type, dup_sym):
return (
f'The symbol {dup_sym!r} is shared by the following assets:\n' +
'\n ' + '\n '.join(d['id'] for d in data['cc'] if d['symbol'] == dup_sym) +
'\n ' + '\n '.join(d['id'] for d in data[data_type].data if d['symbol'] == dup_sym) +
'\n\nPlease specify the asset by one of the full IDs listed above\n' +
f'instead of {dup_sym!r}')
@ -421,7 +426,7 @@ def gen_data(data):
if not isinstance(v, dict):
die(2, str(v))
if id in found['id']:
die(1, dup_sym_errmsg(id))
die(1, dup_sym_errmsg('fi', id))
if m := data['hi'].get(k):
spot = v['regularMarketPrice']['raw']
hist = tuple(m.values())
@ -444,7 +449,7 @@ def gen_data(data):
if wants[k]:
if d[k] in wants[k]:
if d[k] in found[k]:
die(1, dup_sym_errmsg(d[k]))
die(1, dup_sym_errmsg('cc', d[k]))
if not 'price_usd' in d:
d['price_usd'] = Decimal(str(d['quotes']['USD']['price']))
d['price_btc'] = Decimal(str(d['quotes']['USD']['price'])) / btcusd

View file

@ -21,7 +21,7 @@ class TickerServer(HTTPD):
def make_response_body(self, method, environ):
with open(f'test/ref/ticker/ticker.json') as fh:
with open('test/ref/ticker/ticker.json') as fh:
text = fh.read()
return text.encode()

View file

@ -61,19 +61,16 @@ class CmdTestScripts(CmdTestBase):
color = True
cmd_group_in = (
('subgroup.ticker_setup', []),
('subgroup.ticker', ['ticker_setup']),
('subgroup.ticker', []),
)
cmd_subgroups = {
'ticker_setup': (
"setup for 'ticker' subgroup",
('ticker_setup', 'ticker setup'),
),
'ticker': (
"'mmnode-ticker' script",
('ticker1', 'ticker [--help]'),
('copy_files', 'copying JSON files to cache'),
('ticker1a', 'ticker [--download=cc] (early caching)'),
('ticker1b', 'ticker [--download=cc] (late caching)'),
('ticker2', 'ticker (bad proxy)'),
('ticker2a', 'ticker [--download=cc]'),
('ticker3', 'ticker [--cached-data]'),
('ticker4', 'ticker [--cached-data --wide]'),
('ticker5', 'ticker [--cached-data --wide --adjust=-0.766] (usr cfg file)'),
@ -103,7 +100,7 @@ class CmdTestScripts(CmdTestBase):
def nt_datadir(self):
return os.path.join( cfg.data_dir_root, 'node_tools' )
def ticker_setup(self):
def copy_files(self):
self.spawn('',msg_only=True)
shutil.copy2(os.path.join(refdir,'ticker-finance.json'),self.tmpdir)
shutil.copy2(os.path.join(refdir,'ticker-finance-history.json'),self.tmpdir)
@ -135,20 +132,23 @@ class CmdTestScripts(CmdTestBase):
t.expect('USAGE:')
return t
def ticker2(self):
t = self.ticker(cached_data=False)
if not cfg.skipping_deps:
t.expect('Creating')
t.expect('Creating')
ret = t.expect(['proxy host could not be resolved', 'unexpected keyword'])
t.exit_val = 1 if ret else 3
return t
def ticker2a(self):
def ticker1a(self, first_run=True):
t = self.ticker(
add_opts = ['--proxy', '', '--download=cc'],
cached_data = False,
use_proxy = False)
if first_run and not cfg.skipping_deps:
t.expect('Creating')
t.expect('Creating')
return t
def ticker1b(self):
return self.ticker1a(first_run=False)
def ticker2(self):
t = self.ticker(cached_data=False)
ret = t.expect(['proxy host could not be resolved', 'unexpected keyword'])
t.exit_val = 1 if ret else 3
return t
def ticker3(self):