bin/shekel: remove iterfzf dependency
This commit is contained in:
parent
d324628e16
commit
d887634ff7
48
bin/shekel
48
bin/shekel
|
@ -10,11 +10,6 @@ fzf).
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
shekel 200 USD CAD
|
shekel 200 USD CAD
|
||||||
Don't remember the currency code? Use fuzzy search:
|
|
||||||
shekel 200 USD british
|
|
||||||
This will spawn an fzf session (requires the iterfzf package and fzf)
|
|
||||||
|
|
||||||
Requires: iterfzf (optional)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -24,32 +19,23 @@ from urllib import request
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
try:
|
|
||||||
from iterfzf import iterfzf
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
API_KEY = "92a7ccb3b6038a7151fc15e99f2de83d" # please use your own!
|
API_KEY = "92a7ccb3b6038a7151fc15e99f2de83d" # please use your own!
|
||||||
API_URL = "http://apilayer.net/api/live?access_key={}¤cies={},{}"
|
API_URL = "http://apilayer.net/api/live?access_key={}¤cies={},{}"
|
||||||
DB_URL = "https://gist.githubusercontent.com/hlissner/f843823949d7c7453b51c6b52b2e1c16/raw/15a1bc7590be40cd78acfd133ecededbc0871610/currencies.json"
|
|
||||||
|
|
||||||
DEFAULT_CODES = ('CAD', 'USD')
|
DEFAULT_CODES = ('CAD', 'USD')
|
||||||
CACHE_FILE = "/tmp/shekel-hist"
|
CACHE_FILE = "/tmp/shekel-hist"
|
||||||
CACHE_TTL = 3600
|
CACHE_TTL = 3600
|
||||||
|
|
||||||
class CurrencyCache():
|
class CurrencyCache():
|
||||||
def __init__(self, path=CACHE_FILE, ttl=CACHE_TTL, db_url=DB_URL):
|
def __init__(self, path=CACHE_FILE, ttl=CACHE_TTL):
|
||||||
self.path = Path(path)
|
self.path = Path(path)
|
||||||
self.ttl = ttl
|
self.ttl = ttl
|
||||||
|
|
||||||
cache = {}
|
cache = {}
|
||||||
if self.path.exists():
|
if self.path.exists():
|
||||||
cache = json.loads(self.path.read_text())
|
cache = json.loads(self.path.read_text())
|
||||||
if "_DB" not in cache:
|
|
||||||
cache['_DB'] = json.loads(request.urlopen(db_url).read().decode('utf-8'))
|
|
||||||
self.cache = cache
|
self.cache = cache
|
||||||
self.data = self.cache['_DB']
|
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
|
@ -90,23 +76,6 @@ def format_currency(curr):
|
||||||
return "{} {}".format(curr['id'], curr['currencyName'])
|
return "{} {}".format(curr['id'], curr['currencyName'])
|
||||||
|
|
||||||
|
|
||||||
def parse(query, db={}):
|
|
||||||
"""
|
|
||||||
Parses QUERY to see if it's an ISO 4217 currency code. Otherwise, treat it
|
|
||||||
like a fuzzy query and prompt the user with a completion list of currencies.
|
|
||||||
|
|
||||||
:param query: An ISO 4217 currency code or a search query
|
|
||||||
:param db: The currency database to use
|
|
||||||
:returns: An ISO 4217 currency code
|
|
||||||
"""
|
|
||||||
if len(query) == 3 and query.isupper():
|
|
||||||
return query
|
|
||||||
code = iterfzf(map(format_currency, db), query=query)
|
|
||||||
if code is None:
|
|
||||||
raise KeyboardInterrupt
|
|
||||||
return code.split(" ")[0]
|
|
||||||
|
|
||||||
|
|
||||||
def currency_rate(from_code, to_code):
|
def currency_rate(from_code, to_code):
|
||||||
"""
|
"""
|
||||||
Retrieves the exchange rate between two currencies.
|
Retrieves the exchange rate between two currencies.
|
||||||
|
@ -120,7 +89,11 @@ def currency_rate(from_code, to_code):
|
||||||
elif not from_code or not to_code:
|
elif not from_code or not to_code:
|
||||||
return None
|
return None
|
||||||
rates = _request_currency_rate(API_URL, API_KEY, from_code, to_code)
|
rates = _request_currency_rate(API_URL, API_KEY, from_code, to_code)
|
||||||
return (1 / rates["USD" + from_code]) * rates["USD" + to_code]
|
try:
|
||||||
|
return (1 / rates["USD" + from_code]) * rates["USD" + to_code]
|
||||||
|
except KeyError as e:
|
||||||
|
print("Could not find currency named {}".format(from_code))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def each_currency_rate(from_code, to_codes, refresh=False):
|
def each_currency_rate(from_code, to_codes, refresh=False):
|
||||||
|
@ -131,15 +104,15 @@ def each_currency_rate(from_code, to_codes, refresh=False):
|
||||||
:param to_codes: a list of ISO 4217 currency codes to convert to
|
:param to_codes: a list of ISO 4217 currency codes to convert to
|
||||||
:yields: a tuple containg (TO_CODE, EXCHANGE_RATE)
|
:yields: a tuple containg (TO_CODE, EXCHANGE_RATE)
|
||||||
"""
|
"""
|
||||||
with CurrencyCache(path=CACHE_FILE, ttl=CACHE_TTL, db_url=DB_URL) as cache:
|
with CurrencyCache(path=CACHE_FILE, ttl=CACHE_TTL) as cache:
|
||||||
if refresh:
|
if refresh:
|
||||||
cache.clear()
|
cache.clear()
|
||||||
for code in to_codes:
|
for code in to_codes:
|
||||||
code = parse(code, db=cache.data)
|
|
||||||
rate = cache.get(from_code, code)
|
rate = cache.get(from_code, code)
|
||||||
if not rate:
|
if not rate:
|
||||||
rate = currency_rate(from_code, code)
|
rate = currency_rate(from_code, code)
|
||||||
cache.store(from_code, code, rate)
|
if rate:
|
||||||
|
cache.store(from_code, code, rate)
|
||||||
if not rate:
|
if not rate:
|
||||||
yield (None, None)
|
yield (None, None)
|
||||||
else:
|
else:
|
||||||
|
@ -162,9 +135,6 @@ def main():
|
||||||
for code, rate in each_currency_rate(args.src, args.dest, refresh=args.refresh):
|
for code, rate in each_currency_rate(args.src, args.dest, refresh=args.refresh):
|
||||||
if code:
|
if code:
|
||||||
print("{:.4f} {}".format(rate * args.amount, code))
|
print("{:.4f} {}".format(rate * args.amount, code))
|
||||||
else:
|
|
||||||
print("Failed to convert {} to {}".format(args.src, code),
|
|
||||||
file=sys.stderr)
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("Aborted!")
|
print("Aborted!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
Loading…
Reference in a new issue