-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcurrency
executable file
·105 lines (81 loc) · 3 KB
/
currency
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/python3
"""
Get real-time currency exchange rates from wise.com
https://wise.com/us/currency-converter
"""
import os
import re
import sys
from typing import Tuple
import requests
valid_currencies = set(
"aed,all,amd,ang,aoa,ars,aud,awg,azn,bam,bbd,bdt,bgn,bhd,bmd,bnd,bob,brl,bsd,btn,bwp,bzd,"
"cad,chf,clp,cny,cop,crc,cve,czk,djf,dkk,dop,dzd,egp,etb,eur,fjd,fkp,gbp,gel,ggp,ghs,gip,"
"gmd,gnf,gtq,gyd,hkd,hnl,hrk,htg,huf,idr,ils,imp,inr,isk,jep,jmd,jod,jpy,kes,kgs,khr,kmf,"
"krw,kwd,kyd,kzt,lak,lbp,lkr,lrd,lsl,mad,mdl,mga,mkd,mnt,mop,mru,mur,mvr,mwk,mxn,myr,mzn,"
"nad,ngn,nio,nok,npr,nzd,omr,pab,pen,pgk,php,pkr,pln,pyg,qar,ron,rsd,rwf,sar,sbd,scr,sek,"
"sgd,shp,sll,srd,svc,szl,thb,tjs,tmt,tnd,top,try,ttd,twd,tzs,uah,ugx,usd,uyu,uzs,vnd,vuv,"
"wst,xcd,xof,xpf,zar,zmw".split(",")
)
class NotFound(RuntimeError):
pass
def parse_args(*args: str) -> Tuple[float, str, str]:
amount: float | None = None
from_: str | None = None
to: str | None = None
while len(args):
if from_ is None:
if amount is None:
try:
amount = float(args[0])
args = args[1:]
continue
except ValueError:
pass
from_ = args[0]
args = args[1:]
continue
# Allow an optional "to" between the currencies
if args[0].lower() == "to":
args = args[1:]
continue
if to is None:
to = args[0]
args = args[1:]
else:
raise ValueError(f"Unknown argument {args[0]}")
amount = 1.0 if amount is None else amount
if amount <= 0:
raise ValueError(f"invalid amount: {amount}, must be greater than 0.")
if from_ is None or from_ not in valid_currencies:
raise ValueError(f"invalid currency: {from_}")
if to is None or to not in valid_currencies:
raise ValueError(f"invalid currency: {to}")
return amount, from_, to
def get_rate(from_: str, to: str) -> float:
url = f"https://wise.com/us/currency-converter/{from_}-to-{to}-rate"
resp = requests.get(url, timeout=10)
resp.raise_for_status()
pattern = re.compile(r"text-success[^0-9.<]+([0-9.]+)")
matches = pattern.findall(resp.text)
if not matches:
raise NotFound(f"No rate found for {from_} to {to}")
return float(matches[-1])
def usage():
name = os.path.basename(__file__)
print(f"Usage: {name} [amount] <from> <to>\nExample: {name} 4.2 usd jpy\n", file=sys.stderr)
def fmt_number(num) -> str:
s = f"{num:,.10f}"
return s.rstrip("0").rstrip(".")
def main():
try:
(amount, from_, to) = parse_args(*sys.argv[1:])
except ValueError as exc:
print(f"Invalid usage: {exc}", file=sys.stderr)
usage()
return 1
rate = get_rate(from_, to)
print(f"{fmt_number(amount)} {from_.upper()} = {fmt_number(amount * rate)} {to.upper()}")
return 0
if __name__ == "__main__":
sys.exit(main())