From 9115ef6416ec9fcadcdcbd774453272d613beef1 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Sat, 18 Aug 2012 08:53:34 +0100 Subject: [PATCH 01/81] alphabetically sort theme names in themes menu --- lib/gui_lite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 6112b246..7e38a214 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -498,7 +498,7 @@ class MiniActuator: qApp.setStyleSheet(style_file.read()) def theme_names(self): - return self.themes.keys() + return sorted(self.themes.keys()) def selected_theme(self): return self.theme_name From 03403391131a1980a0a1186e44fcbacbba9085a7 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 15:10:17 -0700 Subject: [PATCH 02/81] added ImportError and replaced print_error() with sys.exit() to reduce coupling --- electrum | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/electrum b/electrum index 967b5dce..6de8b664 100755 --- a/electrum +++ b/electrum @@ -24,15 +24,13 @@ except ImportError: try: import ecdsa -except: - print_error("Error: python-ecdsa does not seem to be installed. Try 'sudo pip install ecdsa'") - sys.exit(1) +except ImportError: + sys.exit("Error: python-ecdsa does not seem to be installed. Try 'sudo pip install ecdsa'") try: import aes -except: - print_error("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'") - sys.exit(1) +except ImportError: + sys.exit("Error: AES does not seem to be installed. Try 'sudo pip install slowaes'") try: from lib import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password From b95be7e7a4f485916662b030ab3142192381cc0c Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 15:21:20 -0700 Subject: [PATCH 03/81] Created print_error docstring --- lib/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/util.py b/lib/util.py index 98a820c0..9f77ff7b 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,6 +3,7 @@ import platform import sys def print_error(*args): + '''Print out the arguments to standard error''' for item in args: sys.stderr.write(str(item)) sys.stderr.write("\n") From 1eeed7fb27146cb622e3f8090302d4dbba33f4f9 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 15:27:08 -0700 Subject: [PATCH 04/81] Created appdata_dir() docstring --- lib/util.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/util.py b/lib/util.py index 9f77ff7b..b2e98f57 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,13 +3,14 @@ import platform import sys def print_error(*args): - '''Print out the arguments to standard error''' + '''Print out the arguments to standard error.''' for item in args: sys.stderr.write(str(item)) sys.stderr.write("\n") sys.stderr.flush() def appdata_dir(): + '''Find the path to the application data directory; add an electrum folder and return path.''' if platform.system() == "Windows": return os.path.join(os.environ["APPDATA"], "Electrum") elif platform.system() == "Linux": From 59b2762258bfab70b7a333272b6a6646cd318906 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 16:00:46 -0700 Subject: [PATCH 05/81] got rid of print_error() to reduce coupling --- electrum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electrum b/electrum index 6de8b664..da20ae49 100755 --- a/electrum +++ b/electrum @@ -192,8 +192,8 @@ if __name__ == '__main__': cmd = 'help' if not wallet.file_exists and cmd not in ['help','create','restore']: - print_error("Error: Wallet file not found.") - print_error("Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option") + print "Error: Wallet file not found." + print "Type 'electrum create' to create a new wallet, or provide a path to a wallet with the -w option" sys.exit(0) if cmd in ['create', 'restore']: From e5bbb467823d6f90adb493844437e4494a6562a5 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 17:12:08 -0700 Subject: [PATCH 06/81] changed print_error() to sys.exit to reduce coupling --- setup.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.py b/setup.py index fe3049f4..abf1ce86 100644 --- a/setup.py +++ b/setup.py @@ -9,9 +9,7 @@ import os, sys, platform from lib.util import print_error if sys.version_info[:3] < (2,6,0): - print_error("Error: Electrum requires Python version >= 2.6.0...") - sys.exit(1) - + sys.exit("Error: Electrum requires Python version >= 2.6.0...") data_files = [] From 1829d20d720ad6f20d0d62fcd52fc467aa0b6aa5 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 17:16:35 -0700 Subject: [PATCH 07/81] got rid of another unneeded print_error() --- electrum | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/electrum b/electrum index da20ae49..33b2b30c 100755 --- a/electrum +++ b/electrum @@ -198,10 +198,9 @@ if __name__ == '__main__': if cmd in ['create', 'restore']: if wallet.file_exists: - print_error("Error: Remove the existing wallet first!") - sys.stderr.flush() - sys.exit(0) - password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") + sys.exit("Error: Remove the existing wallet first!") + + password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") w_host, w_port, w_protocol = wallet.server.split(':') host = raw_input("server (default:%s):"%w_host) From 8bb841787e0e204561bbfa0b529b3b2f6c6d1ca3 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 17:17:47 -0700 Subject: [PATCH 08/81] got rid of another unneeded print_error() --- electrum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/electrum b/electrum index 33b2b30c..deaadbe4 100755 --- a/electrum +++ b/electrum @@ -223,8 +223,7 @@ if __name__ == '__main__': print_error("Warning: Not hex, trying decode.") seed = mnemonic.mn_decode( seed.split(' ') ) if not seed: - print_error("Error: No seed") - sys.exit(1) + sys.exit("Error: No seed") wallet.seed = str(seed) wallet.init_mpk( wallet.seed ) From a85901b4b2a4a1cce4885abd347cbeed7f8699d1 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 17:46:31 -0700 Subject: [PATCH 09/81] added docstring for the read() function --- lib/wallet.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/wallet.py b/lib/wallet.py index 8c658769..63a41ff7 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -676,6 +676,7 @@ class Wallet: os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE) def read(self): + '''Read the contents of the wallet file.''' import interface upgrade_msg = """This wallet seed is deprecated. Please run upgrade.py for a diagnostic.""" From f0fb3ec0e15d3b87f0acb92c796b7498b9e49e67 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 17:49:51 -0700 Subject: [PATCH 10/81] added small comment for ast.literal_eval --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index 63a41ff7..68f8b1fe 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -688,7 +688,7 @@ class Wallet: except: return try: - d = ast.literal_eval( data ) + d = ast.literal_eval( data ) #parse raw data from reading wallet file interface.old_to_new(d) self.seed_version = d.get('seed_version') self.master_public_key = d.get('master_public_key').decode('hex') From 89109541bd452bd6f60979c81b883ab4068fa258 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 18:08:32 -0700 Subject: [PATCH 11/81] created docstring for set_path() --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index 68f8b1fe..d53ef593 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -351,7 +351,7 @@ class Wallet: self.interface.poke() def set_path(self, wallet_path): - + '''Set the path of the wallet.''' if wallet_path is not None: self.path = wallet_path else: From 1429ef71e139f72f256330baaf7327d6466b165e Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 18:19:59 -0700 Subject: [PATCH 12/81] getting rid of more unnecessary print_errors() --- electrum | 10 ++++------ lib/wallet.py | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/electrum b/electrum index deaadbe4..8ee4427f 100755 --- a/electrum +++ b/electrum @@ -347,17 +347,15 @@ if __name__ == '__main__': f = open(ns,'r') data = f.read() f.close() - except: - print_error("Error: Seed file not found") - sys.exit() + except IOError: + sys.exit("Error: Seed file not found") try: import ast d = ast.literal_eval( data ) seed = d['seed'] imported_keys = d.get('imported_keys',{}) - except: - print_error("Error: Error with seed file") - sys.exit(1) + except IOError: + sys.exit("Error: Error with seed file") mpk = wallet.master_public_key wallet.seed = seed diff --git a/lib/wallet.py b/lib/wallet.py index d53ef593..cbf0cdcb 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -351,7 +351,7 @@ class Wallet: self.interface.poke() def set_path(self, wallet_path): - '''Set the path of the wallet.''' + """Set the path of the wallet.""" if wallet_path is not None: self.path = wallet_path else: From ddf5614af0df6594cf557dc6d492fa917a83adbe Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 18:24:02 -0700 Subject: [PATCH 13/81] getting rid of more unnecessary print_errors() --- electrum | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/electrum b/electrum index 8ee4427f..62f3b659 100755 --- a/electrum +++ b/electrum @@ -501,9 +501,8 @@ if __name__ == '__main__': elif cmd == 'password': try: seed = wallet.pw_decode( wallet.seed, password) - except: - print_error("Error: Password does not decrypt this wallet.") - sys.exit(1) + except StandardError: + sys.exit("Error: Password does not decrypt this wallet.") new_password = prompt_password('New password:') wallet.update_password(seed, password, new_password) From 66ede2e03ea84e5dda4279bda94840a26edecdb6 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 18:28:17 -0700 Subject: [PATCH 14/81] created docstring for local_data_dir() --- lib/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/util.py b/lib/util.py index b2e98f57..e61dbef5 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,14 +3,14 @@ import platform import sys def print_error(*args): - '''Print out the arguments to standard error.''' + """Print out the arguments to standard error.""" for item in args: sys.stderr.write(str(item)) sys.stderr.write("\n") sys.stderr.flush() def appdata_dir(): - '''Find the path to the application data directory; add an electrum folder and return path.''' + """Find the path to the application data directory; add an electrum folder and return path.""" if platform.system() == "Windows": return os.path.join(os.environ["APPDATA"], "Electrum") elif platform.system() == "Linux": @@ -25,6 +25,7 @@ def get_resource_path(*args): return os.path.join(".", *args) def local_data_dir(): + """Return path to the data folder.""" assert sys.argv prefix_path = os.path.dirname(sys.argv[0]) local_data = os.path.join(prefix_path, "data") From d66673eca2b0637aea925798316bf9b31e11cb76 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sun, 19 Aug 2012 19:59:05 -0700 Subject: [PATCH 15/81] more print_errors() deleted --- lib/gui_qt.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index e866c066..030215b0 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -23,9 +23,7 @@ from util import print_error try: import PyQt4 except: - print_error("Error: Could not import PyQt4") - print_error("on Linux systems, you may try 'sudo apt-get install python-qt4'") - sys.exit(1) + sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python-qt4'") from PyQt4.QtGui import * from PyQt4.QtCore import * @@ -36,9 +34,7 @@ from interface import DEFAULT_SERVERS try: import icons_rc except: - print_error("Error: Could not import icons_rc.py") - print_error("Please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'") - sys.exit(1) + sys.exit("Error: Could not import icons_rc.py, please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'") from wallet import format_satoshis import bmp, mnemonic, pyqrnative, qrscanner From 2598e89d00b6d82a514d79528e8d8341337e12f9 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Sat, 18 Aug 2012 09:35:02 +0100 Subject: [PATCH 16/81] More Pythonics util.print_error --- lib/gui_lite.py | 2 +- lib/util.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 7e38a214..738d328d 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -491,7 +491,7 @@ class MiniActuator: try: theme_prefix, theme_path = self.themes[self.theme_name] except KeyError: - util.print_error("Theme not found! ", self.theme_name) + util.print_error("Theme not found!", self.theme_name) return QDir.setCurrent(os.path.join(theme_prefix, theme_path)) with open(rsrc("style.css")) as style_file: diff --git a/lib/util.py b/lib/util.py index e61dbef5..2aabcedf 100644 --- a/lib/util.py +++ b/lib/util.py @@ -3,10 +3,9 @@ import platform import sys def print_error(*args): - """Print out the arguments to standard error.""" - for item in args: - sys.stderr.write(str(item)) - sys.stderr.write("\n") + # Stringify args + args = [str(item) for item in args] + sys.stderr.write(" ".join(args) + "\n") sys.stderr.flush() def appdata_dir(): From c9ed01e90b648d8c57c7d0e4adb986e09e71e588 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 20 Aug 2012 10:12:16 +0100 Subject: [PATCH 17/81] bugfix: wrong indentation level for prompt_password. --- electrum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/electrum b/electrum index 62f3b659..bd9bb728 100755 --- a/electrum +++ b/electrum @@ -199,8 +199,7 @@ if __name__ == '__main__': if cmd in ['create', 'restore']: if wallet.file_exists: sys.exit("Error: Remove the existing wallet first!") - - password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") + password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") w_host, w_port, w_protocol = wallet.server.split(':') host = raw_input("server (default:%s):"%w_host) From 3a648f9119a6716290c078b8fa1c8d96c8ac04a4 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 20 Aug 2012 10:20:40 +0100 Subject: [PATCH 18/81] Show list of all the servers available in the menubar. --- lib/gui_lite.py | 45 +++++++++++++++++++++++++++++++++++++++++++-- lib/interface.py | 2 ++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 738d328d..51ad4fcf 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -4,6 +4,7 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * from decimal import Decimal as D +from interface import DEFAULT_SERVERS from util import get_resource_path as rsrc from i18n import _ import decimal @@ -174,8 +175,10 @@ class MiniWindow(QDialog): menubar = QMenuBar() electrum_menu = menubar.addMenu(_("&Bitcoin")) - self.servers_menu = electrum_menu.addMenu(_("&Servers")) - self.servers_menu.addAction(_("Foo")) + servers_menu = electrum_menu.addMenu(_("&Servers")) + servers_group = QActionGroup(self) + self.actuator.set_servers_gui_stuff(servers_menu, servers_group) + self.actuator.populate_servers_menu() electrum_menu.addSeparator() brain_seed = electrum_menu.addAction(_("&BrainWallet Info")) brain_seed.triggered.connect(self.actuator.show_seed_dialog) @@ -516,6 +519,44 @@ class MiniActuator: def set_config_currency(self, conversion_currency): self.wallet.conversion_currency = conversion_currency + def set_servers_gui_stuff(self, servers_menu, servers_group): + self.servers_menu = servers_menu + self.servers_group = servers_group + + def populate_servers_menu(self): + interface = self.wallet.interface + interface.servers_loaded_callback = self.server_list_changed + if not interface.servers: + print "no servers loaded yet" + servers_list = [] + for x in DEFAULT_SERVERS: + h,port,protocol = x.split(':') + servers_list.append( (h,[(protocol,port)] ) ) + else: + servers_list = interface.servers + server_names = [details[0] for details in servers_list] + current_server = self.wallet.server.split(":")[0] + for server_name in server_names: + server_action = self.servers_menu.addAction(server_name) + server_action.setCheckable(True) + if server_name == current_server: + server_action.setChecked(True) + #class SelectServerFunctor: + # def __init__(self, server_name, servers_list): + # self.server_name = server_name + # self.servers_list = servers_list + # def __call__(self, checked): + # if checked: + # # call server_list_changed + # self. + self.servers_group.addAction(server_action) + + def server_list_changed(self): + # clear servers_menu + # clear servers_group? + # call populate_servers_menu + print "hello" + def copy_address(self, receive_popup): addrs = [addr for addr in self.wallet.all_addresses() if not self.wallet.is_change(addr)] diff --git a/lib/interface.py b/lib/interface.py index 76a3e4c8..7062beef 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -363,6 +363,8 @@ class WalletSynchronizer(threading.Thread): if ports and version: servers.append( (host, ports) ) self.interface.servers = servers + assert self.interface.servers_loaded_callback + self.interface.servers_loaded_callback() elif method == 'blockchain.address.subscribe': addr = params[0] From 02dd51cbba7c1370fdd62f51c3099f85e32d58e6 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 20 Aug 2012 10:25:08 +0100 Subject: [PATCH 19/81] untested hotfix for copying data/ to system wide local data dir. --- setup.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index abf1ce86..5a90bf04 100644 --- a/setup.py +++ b/setup.py @@ -25,10 +25,15 @@ if platform.system() != 'Windows' and platform.system() != 'Darwin': data_files.append( ('/usr/share/locale/%s/LC_MESSAGES'%lang, ['locale/%s/LC_MESSAGES/electrum.mo'%lang]) ) data_files += [ - (util.appdata_dir(), ["data/background.png", "data/style.css"]), - (os.path.join(util.appdata_dir(), "icons"), [ - "data/icons/confirmed.png", - "data/icons/unconfirmed.png" + (util.appdata_dir(), ["data/noface.svg", "data/README"]), + (os.path.join(util.appdata_dir(), "cleanlook"), [ + "data/cleanlook/name.cfg", + "data/cleanlook/style.css" + ]), + (os.path.join(util.appdata_dir(), "dark"), [ + "data/dark/background.png", + "data/dark/name.cfg", + "data/dark/style.css" ]) ] From e28d0e3288438f5eb181bdeeb28f5fc98fe2acfe Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 20 Aug 2012 16:10:36 +0100 Subject: [PATCH 20/81] Revert "changed electrum logo to noface." This reverts commit 3ee35acc276654d74601f2d1ce5e957d10495659. --- TODO | 1 + data/noface.svg | 2 +- electrum.png | Bin 2378 -> 8905 bytes 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TODO b/TODO index b5c8430d..89affccd 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ Client: - Wizard - Multiple wallets - Themes +- Extend GUI with history view (View -> Show History) - Settings window Server: diff --git a/data/noface.svg b/data/noface.svg index 9956854c..dc24f111 100644 --- a/data/noface.svg +++ b/data/noface.svg @@ -52,7 +52,7 @@ inkscape:groupmode="layer" id="layer1"> y{D6rKp%ev4hsMi3H%_4001BWNkl91%Ypva#?sipmRjsO2RZ>X^L>KVGxFH@k_OqP~)7bb8JMV#GVPk|F1UAMFAz&*3 z31O_~7(5ckCXMM6+i~LH;N)2#3=tMW4Iq`ORQ>InbI;jlH*3xJ$KLl=se#zwbwtH3ANa$n%Zi1;9k&9mOgS$Z~ee%=NZ5G`e|;tYyF#EyL>ZWzWud5 zZhimO&d=}psjjuwrm8&0S$U-q`CfnP?6r||IOlNIVyqxy5HVP56>C65Gz5aLsmq#4 zUND|am=sm;K0K)CA6a8Q9zu8sr2NHyk^AjuzV~$le(tw6|Mwc;_M3Z5PpACDcP%%I z_~~A3jN2`uKkS^n**SY6iDQyD!np|Ntj0+q-A+cQlaVATX_^wHDZ~-ADn)-jA>Z6& zw6V!}G@`01Evs7cJZHEyW;B}ML%7!%^V^922VeX3xBPBd0sPX-Vej5)e)b#ih`+G` z?tI;VpKmRG+iT*e+wJUiMqcBry(LNF*)&OrlbBAL>g?>a?B2DD>FH_GEX6w4oIYTz zfhYnOHOtTdwFh5Q788b>Ll%FRmRMR^W;oo^q9|lzIA(LWMOjwoRrP&A`2*04Z~2!+ z)vPDwE&p=zzs3N!y{1F27jw(|8Y}!#*hWM3Ia?w8XfI+&#iX__!MH>U>=?3Z1$ z(^zK+0T7F^7V9F!+IGW=sz-xIgQ7m5s;GjB0$_}wC|ko37cX4m(&B%jj)o&y+Z?jK zF=SGdXH@mqz4ssamEWsZ0p9-O7GpDh^C3aN00O7SKN*>nTa;D(hqVv?B(LaV*$`}O|uJwMgsjqT>&eRH;FFzEeamSz9A zo27HRW@q)f<3~Au{HUa9hoB%BV&^b%ipB{dKu|EI*-r3K7lf*y_7%1Fs4CJNGzLIS z`xZnjB2DNRYcPKz1PvfCGds=P?2IU?B1rII+I#;!8hqzlujj$Pc#z@U4+eheha>KO zF#OF8aQn^Ooz1`JwVnOFUiY1yEPZ{i+ldbB+p9O+a2@$&pgQ!o??Jk zykvidSKoG?Uw?Jlou2ByDNB<#^m;uxe)Nc5bL6n3oeYU0OcWu;G&pJuILl~b$c3{P zS-P~y`szB9NpqTcQBqW%8b|G+4lpT7^1P(>g2z#Lp$>+s@>u7{(hg~o5`0ZQ8bV#* zs}f^kT%2K(2$Lm99HY)4#?ToI=uJ<{B+q}f7>}hatK;7LJuf_AKK+@8b?Y_H4%~QS z#$P;8KfM8dZ-;Vp{hLNNx{~*pgVVf=e+p)x$5c@^k(L{bnya<3k%F&eLa8I zKmR4{J$yYgS6$80rE~bIBI|TWvkun9q-ly1Pch!4E+*I{A)1|oG(nw3jG#hegsEvd zy`GGRn_A=}Da-0c?*lKm&VBkV9|_gpxi)am!*qO$BQ6FsJ*8sE5?(O*`&+- z@n=F+kz71O{rOL`w!Vo=`|LY%0&x+=Xp1j>?k_0IF=bU#)}G8o4Eh5Q#T7YKk&~}q zBE*m#yc!{()dcZ1iXg@^fAwLm8;zvMb1kb%YQOdRfWQCdABg|Wdp=(JTVH?Sxc#Gz z7np4W^t%ZFcil2Glf>?=X&N7%-8IXJXFP+XKLBeHW6C07X$z*PajpJ_Phib_WDP^Svkj8XtcGbzKvDO&mvb z2R$UskgS90bcyrkA@mi59$GBJREcCiQE}FhmRm?&`<*&f~Pap=b978Wn*<+hg)Nrl%pTlihuWpzvuq+ zeScVoUw&1B`Hi2MX#ntNrXp+2tFkP;wmUV$v1dLPNxG;_5u1OZHU--u1jqSvmsnlh zfR@5~AIK*qX~rXfl;24kV6zzR$z6Bd`2xpZlP(`V0f z`rLUI7MIxA98#18p=FEW97(T7oI1*dOH3|YXu?z#X$viU&B4P5ncqJzGcyD2qz-{! zNn-5+{Q4ghmur84-~NR?yOT7zcY1F3!Nb>`&}YB+B|_Qq^w82+^(;UB7#Gi+Vm!)s z;&+sfA?fqt@BcB3b(h`!iVx=^(yY_Cx%U*4F?Cgwq$zQdA|j|No9nBLwl*0JH&|V| z$nx?ztQGdm?_u}+9MdyXbh8L6fY$gtXS}|F7f1K-QR07IA1!jE&cWv(fyJ{I`25{} zsV5(KT$Wb0m{jsZb&x-N?;2^iE`q^-~-ipf`(8Ey`- zHlf##sH&2DG+`?*2|>uZeXNVVChyiZ;H|ZEy8Wm8n}{%&o@FpSi>h+;#51YNl2ea9 z!~=izY1V&MS2%cRKlAf*3_2;+D%M3LSw_AwWODI5?$8m80vb>P;%oNopJ#6OE?Hh& z)!`_YN#%b&cKj!xumC^wZG$9^qWAS?W)AK?a7d3m>$!sWt!FkVO}%IJ!g;n<*D$uJ z?;{suqligS;V~S$@p%|y|K}yBJh2efE09n`u6TbNoQ;^^*RRUcWEhPNs1r1l1o4s^XF~7Gum0#%W5NW;%c1>gM!=?zp8^731|a$~;HJ zpdyVCXfP~GJ50(={_G<~2E{+^~77J$|Obh7?LDrdN5%3t~n0uoo8;Uhn6{~PktG!eToKCP9|)wEkQLV zb2YI{*jzl#7ykSY`Oxp&&dIMlKnVT`;j!&GS0BBe&5cb)!!cD+f)8ljc$;+=@ip~m zNT})^o+k=a6<6(%<%;5~n{GgBm4 zLYhPxxm>D3zsngT&xj(I8e?^K&mIBapb7$F2vtQn9)kv~bxrJxTm~|^oa(HDSiq~& z?RJQq`{Oq@pvNdLnN*%HfAthqRel{6Pf_m)ZOPoglwhnON+R-n zLS2+ZX^I5ED|kQ%^=%YY}62 z&{<>$&bRf zu34LP7F6+*677b@{aa=##xUsjNs}071tHwvtd(aOYstDDkvIk)Km>m^f*3>a6;u=A z*dfO4gvHM0wN-MrNslN-8tGfU4j-t>n$aj{b8AepzDc!Qv9PerrNtGlK7JEfOPa34 zfDi&-zW;OddmTDiLgZY-QVe=xwqhJ0Kr@s0njvd)Y5=Vp(m`s{_qIoNIRa2K0v1{aZ z>l$V%03ncN8P*z%7z{pgMr0miNU{u2MD%iztfBFM?OeUR7}I}B+^sP{2`zUBDA6Rs zTJ!X$9|Ci`=Xw5%zl$V^NVAMA>(K2@v1@)mGrRVnK?xx|0sSBT(!Ko0kNzIL)L@KZ zQj`pbBdm>f)`nhQpVom;2QZ4LG+F^lk|YR%h^P_7iAW#7MGgpU&S-Uc4QTLBI>c7Y z6KO3gCDM4qVN?BgZcjt(LkHJYicZe*#-nmM&djdU}p3 zU!^J=O(A%XF$UBSv~{+&7ZKX@h`andL~+(`AEY4QnveG6)kA2%(1`R6+G@aPAZS2T z5K)8xYEVMs2~8IRQH8JR_*d|L@1OX;^m2xfo!a1Xjqrb+Fa7&m|E%Zo0AcV$!^l}Dh z8W@V9;RwbWT-;FPC)WkrIej!5vbwZ*#qShjES+wT{?s%s$-vh;VbDC^Gr#X3vvYg6 zuiN9~7e9YZ5<6mRN#eM5q~?@EP(FfTrNFF5<@LeH$y6&au35k$!)t(>z;jV}u@V{ie2w~mNN8dpI1CM_IBSUF7}xgvt#eIP=p4puH$M#+gDZ+wGJkpk zFd2_nUO3O}+zj2s;H;yrYR2mutX!IK_TxKNq zAOC-A=4Nu7bvV~xm$br*X%B=}pw(ayQOdHB?NpVZjR%}l4bR9&Bk(oiwFN^1Mu?J_ z-k^)KmN-eVHo~+5>GuC=jwx)ncAGvox*o~GaH61-g7-gq49rC z0qUk?CIqmC;c$zps_`L6P`s;ae_yCQ<)qMjG?J{_Yw|t<>M=%;D8i4&G;q=C0U=;a zLxx1nWwOz_xwgjo+AO#QOlz^W!4O)Son;e}I3ei`p28=0iX+v_a|PRfbUXeH#F1-^ z;_KEs8(O@%xj{ZD@Ig`7Fg}F)swRJ@%G%0Wt65*x0FAYnC?V`T&^N%SO4x4jwWYJR zManiCQy-o-3bZ{*9|E-x)O9l};A_t$pRl#H#c(*}hMWEl#y-8mR1`URzJ+mihhQmz zpq@B##F0gPg@y{%x_Mq%GTho?oKL8|0{WO!l}F05S_$6IEnT|AzC#BaEp2~0XN1u7 z0pkeoYm9XbyOPjQ;Rbr~Wku<8Mw61o(2!ord6Xu2Geh&@f0JNV9|_GK9Kl<_Q2R zhV_jN#^ao#teR*?{?a)sqpE+d@2RTl2UZprp(-0Pv%~Z%Tohx|jCyku4^>swHM8@7#lO(8gprJnIuVxlY}VA*mv|`YHVysboT@u=|EQ)_D3k!>EjdJR$ z(#j(u@=52tS5^IZSrk7o9*=cpVNvFG&o%j845(tP!zL+}84~KcAwx);E`_qJSXx@9 zv+Ec)-gxa!SXyfv0(Au#2Jbm`;+g!+o8NH-kunX|Trn1NIrZriPCtaeXaD=3vaxcJ zs}Js@seXN15e9nwF1>$FO7OmobHSk0WyRvs62sA$styuVN6y*Ln6mP!%AZY&a#EG0 zoPGREt#W={N7W`_KNEFMjq@%uY=aJJV#Nb{&E;=w_sG(y-tLY_NYKEU&JzG2CJ_$|)-a zo7ObQkj7Rk594QSM!%GcC&)wofXp+>0cs_6r^WoX$pJF`~n zf3l$YRQ>;n^7oUa@h3D@TGDdq{24y{yLWNlJ%7foxoLXc1cy=;1$9{wd`*_63tmB`G$`sD@k3_?p#r#K4ng8Bv_JRFfUfuv4Ol>>&DfZK0u|+uNtEs`z$ltgb4C z8*7|D`xsw+;0s(j_ZXclWq$W8{VX9(ELId>*Nm&0Za05ndb&@XM1M=VvMQF=BX=$;w5s#lc&+6Jb_^AN^b>&CC4!0LY!DwqJ zkDWZ($Ovs5Y4FrliK;aHH)9$+2sPFUgI3Whs9;9*tgl@xle>=jWN*wF~cklk-K;vcR@1t=Qba*EQBUx}B6H ziJ6<7Wt11JuMe4&6&o9ytgdg;>0~>+yphFI`u!eB9PbqC0%U25_Iu0>dQA5^q-lb$ z>t+&Ur<b2T|Yy&?k@YtDCoV#$5_4Q50lbR6Zeno!&J^#L;LGSu-)#yII z@Y_S~x@DSQ`JmUjuK!0}*LUXmgvG@rIeGFi4S^<2ZO0Z+R|RpmM>aEyI7g^zR0HFD zf)9;UWt}C89B~rkqNp7QZQM4BqNaaC<6Oh`+F{EijY+c(Y1SppIz&lE+U*giJ#3U= zU4l!x%wDyhW7j`}!R&5SV<0BrsBx%?SX^4=yi97GD-zwf_K9GrK5@36t>_%NHIejUuL} zrs?(iL`l-{1sf595O?~_9XQO@*IiHA8#Kk3iNHn}8)2iA;no%pK6pQ;PoL8DjiC(3 zHD2W|MSkZ!A1lkB`yt02AFF?!IwtqrVShp25?)m4qwGsKsl83(Z z1s;9mVO?2Sm5r^Es+KdAzqq?Bzny&TNzp&~+=Sn}Wr{cb_C&w) z8U8DX8L8@vs=CU?d9G=v&tQ5^jA@J@HbPv48i!zr(k@wVhNyqjCrZ26D8Y(gjUkC+ zI$265O-Pf3B#KDlCS65QOd2P|F2cnLac@Aj`zm_-uc3eS2|DvfuuCGeOz{TU``XWlq(0 zbA441>ZvV~_1ESsln`RAo25rR67U4xgE8TmR&Yt9vm`h%ACIop)WZZ||_3^^L@#T&?KK9hR1MYuo8KBcix#Q-*8$U44-}RIB z|5X@yAAZ&Qu&*j>Hpdga_Ickb{XGZUsxdUNpHI+Y(&+wLHzI15kSWa&Wm`n)c5mI- zMuj#JCW^69(g>{EQ)Ok|T((ew&<p6=Fy*~r1 z!>xZ@MiWmR2y1Lr)K6D z%+AxFo!5g0kITM&2Z%BYp=_s1L&NsBRUI*{q9m8E!)2Uu0006#Nkl-qW*OjFuwzhvpvXxg9r7i{JpQ`e~J3rx<{<@q08{ZrJ z&0D6p%=`piw7kl^bXLipXl1|nN^Ln{a zsoUClivimnV49AO`kM9CRTeIsW%0skhO5gA*OqlS;Ss(b>G_p9oC#!7zsN9yo5J@vn}%hON3VD*mwr;D!(2c{d8Z-MY~BYc0CG3J`c z8LYK9Yg+y9iUvnJ5aENTu6^4p2vi=ds-uRG9ESWsw&!2 zD%3vop_RI-gaq1FrQOmBvMB_pR=Yu39OuJS4ap`ZaT3SIi9KJp4}>I>cnr430H z?h}zwPQ9qy10Nk7-N!k98^GHD8VbBUPDCH*y8hd?wzk{TLiWs85Q@|P6>5Q#)y2k^~&*DT*w zF@0$TMwS;WUr%vNUtGcB4aMXJTifdD>YKyE!@C^?Ff}zL1Ncqe!T(Fa(k%sAf+IUs zctV$%(qSk-^1h1nr!~HUMbL94q5_t>6{M0EEL~H-Mv7 z=Mw`8)P;@F69e4-!U2%WeEjs|X8>|p0Ox$q(9lr85deZ9yb3_JbdP^Ee|_Gh1_p8$ z4nX{zSv_?zZyX_2RZlqrfOFn$Ic=?SXeo2V-}N5UL661#W*-Odu4CbODjbS{b2=P+g?iZ&R>_3R$$e9B~0660tKIcPa+# zNC4a_I@&!DA`-XurK&0(KYonK$w^F3PD0mp1Ofrn)zzV+qrWIV!-C(YuB#f>eZ{zG%e@#jg5`CaN$DE1SWr98yXtI<;$11$<;Is z!C(+4PMknjS6Ag-;Le>pmV;kgIAL*dvEWVy2L~gz`E(D zQYkRT(A3mak~OrowILV`B9TZSo6W-G@j#YkXqsjf8xj?<008j$eDL{vwk9@2gxcC# z)YjIT{*T3CIcEnV`pl_WV4;#3pJ5nQz$PnZ0Y;W%`L+rp!{H5ykedYi2At*4Qyk1g zU{!emM4f+1g%`J`!pnmymhU|)f~G#!(C~d3u05r{cv7Aii2ZIAMs}^f@TvfO*|JhK zS}_+;m&{K^PjOqG{z_O|A3Ol8{zuC@aa1k_Y_Uq)08HpxG`1{RP z8nPXLp5ms`cs>AvAS8Hg2QJZ%yIS95LvjIsYZ3V<;-W_mKU4DP^& zI3|_8`-WU*8QzcxjaibtS5XT90B`F?@745YE zVIzOGcn&g%jYiJ5LV_SH6*C2v1VB~Qv8^>Ym!H8K64n6NlLou?Fc1NI`Xs2TYUPfP zing+1Z|vykNCVhLz4i?W?jVCuZO;ZYaWA3zH5c4<%+mZBW5Y$uFHyfy0Q*hKNQ8ao zWZM=(d;6sI$CSqc1|7G6wKh`rwJ$TdU9Nwegu7g>zgGkR5#4gK2B7PDuBX3ndKt$hq(RImW647WB@pv4mR0_#t5{6-{zeW!R zgQ%;kgCv>L$fr-AB9Yi$?{K+X11En^p6so33;<*72Iu^R0BUM#aQN`yg5_J7KLkPe zy^U!`NpA1~fR%DYf6jSM0D>SSZr;54UdanCyA+K?BJTqD@yiS-l}bU=H0Zj%zW3MT z@#Ne^lFeo@KR>^{GUj&wvAeswe@9rrTB7oE0IM&NJtCb>V{UE^)6>(KnVEmdIlz48 zPedHR&+O3K){mwlk;pFq{K!t3b8~asasW{j$9j5tLN+foY{}Q(K@l$}@+C-HGe9EJ zBuP3~hP77dt*x!?sbLsz5>dhqdD(1sTmJ8IxqjW***Ul)0jxoY8ivsapyUr5x9$RQ zyWO|DySsl_rq#B6t+loFKAwDSTz=mU07Rrql60}VyZeOQx|aRp>5-9<*8sdjM6UyQ z>38OurXd!KK@fz`BuV=2v17;nTn_!p4&Zrv^yraKQIrz^P6B8Huy@l>2C&3AUjVQ` qM6paJ^Y6vQ#apLNo%*Dldi@W#7n2_aYNSX20000 Date: Tue, 21 Aug 2012 22:21:28 -0700 Subject: [PATCH 21/81] added quit functionality to menubar in lite gui --- lib/gui_lite.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 738d328d..0f8daf6d 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -179,8 +179,8 @@ class MiniWindow(QDialog): electrum_menu.addSeparator() brain_seed = electrum_menu.addAction(_("&BrainWallet Info")) brain_seed.triggered.connect(self.actuator.show_seed_dialog) - - electrum_menu.addAction(_("&Quit")) + quit_option = electrum_menu.addAction(_("&Quit")) + quit_option.triggered.connect(self.actuator.quit) view_menu = menubar.addMenu(_("&View")) expert_gui = view_menu.addAction(_("&Pro Mode")) @@ -599,6 +599,9 @@ class MiniActuator: def show_seed_dialog(self): gui_qt.ElectrumWindow.show_seed_dialog(self.wallet) + def quit(self): + sys.exit(0) + class MiniDriver(QObject): INITIALIZING = 0 From 74cea9b709d225a16ea9cf13eec3e58e179a716a Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Tue, 21 Aug 2012 22:36:15 -0700 Subject: [PATCH 22/81] Created docstring for miniActuator __init__() --- lib/gui_lite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 0f8daf6d..11a6b812 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -482,8 +482,8 @@ class ReceivePopup(QDialog): class MiniActuator: def __init__(self, wallet): + """Retrieve the gui theme used in previous session.""" self.wallet = wallet - self.theme_name = self.wallet.theme self.themes = util.load_theme_paths() From deb29affc5bd24c5f56c6f87fd7282141ad60ea0 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Tue, 21 Aug 2012 22:43:35 -0700 Subject: [PATCH 23/81] created load_theme() docstring --- lib/gui_lite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 11a6b812..d594a216 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -488,6 +488,7 @@ class MiniActuator: self.themes = util.load_theme_paths() def load_theme(self): + """Load theme retrieved from wallet file.""" try: theme_prefix, theme_path = self.themes[self.theme_name] except KeyError: From 69110160aca252006d920effa7d1463f8daabc77 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Tue, 21 Aug 2012 23:17:48 -0700 Subject: [PATCH 24/81] created docstring for miniActuator --- lib/gui_lite.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index d594a216..a37790a3 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -480,7 +480,11 @@ class ReceivePopup(QDialog): self.show() class MiniActuator: - + """Initialize the definitions for all the menubar functions and + sending/recieving bitcoins. + """ + + def __init__(self, wallet): """Retrieve the gui theme used in previous session.""" self.wallet = wallet From b027678d0e95d0a048fd366b8eb9e6c9c3ab7891 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Tue, 21 Aug 2012 23:34:12 -0700 Subject: [PATCH 25/81] created several more docstrings in miniActuator --- lib/gui_lite.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index a37790a3..327bfc3d 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -503,15 +503,20 @@ class MiniActuator: qApp.setStyleSheet(style_file.read()) def theme_names(self): + """Sort themes.""" return sorted(self.themes.keys()) def selected_theme(self): + """Select theme.""" return self.theme_name def change_theme(self, theme_name): + """Change theme.""" self.wallet.theme = self.theme_name = theme_name self.load_theme() def set_configured_currency(self, set_quote_currency): + """Set the inital fiat currency conversion country (USD/EUR/GBP) in + the GUI to what it was set to in the wallet.""" currency = self.wallet.conversion_currency # currency can be none when Electrum is used for the first # time and no setting has been created yet. @@ -519,9 +524,11 @@ class MiniActuator: set_quote_currency(currency) def set_config_currency(self, conversion_currency): + """Change the fiat currency conversion country.""" self.wallet.conversion_currency = conversion_currency def copy_address(self, receive_popup): + """Copy the wallet addresses into the client.""" addrs = [addr for addr in self.wallet.all_addresses() if not self.wallet.is_change(addr)] # Select most recent addresses from gap limit @@ -532,6 +539,7 @@ class MiniActuator: receive_popup.popup() def send(self, address, amount, parent_window): + """Send bitcoins to the target address.""" dest_address = self.fetch_destination(address) if dest_address is None or not self.wallet.is_valid(dest_address): @@ -594,6 +602,7 @@ class MiniActuator: return recipient def is_valid(self, address): + """Check if bitcoin address is valid.""" return self.wallet.is_valid(address) def acceptbit(self, currency): From 434ef95d65c364722238ebabca6fd4c478a06d92 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 11:36:04 -0700 Subject: [PATCH 26/81] small comment explaining gui importation section of electrum script --- electrum | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/electrum b/electrum index bd9bb728..7d5e22f4 100755 --- a/electrum +++ b/electrum @@ -126,7 +126,9 @@ if __name__ == '__main__': else: cmd = args[0] firstarg = args[1] if len(args) > 1 else '' - + + #this entire if/else block is just concerned with importing the + #right GUI toolkit based the GUI command line option given if cmd == 'gui': if options.gui=='gtk': From 943bcd0c843cf4f3cc1d8365df6a18ebe3ce6913 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 22 Aug 2012 19:41:06 +0100 Subject: [PATCH 27/81] Use self.close instead of sys.exit (self.close() is the proper Qt method :) --- lib/gui_lite.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 327bfc3d..ad9bf135 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -180,7 +180,7 @@ class MiniWindow(QDialog): brain_seed = electrum_menu.addAction(_("&BrainWallet Info")) brain_seed.triggered.connect(self.actuator.show_seed_dialog) quit_option = electrum_menu.addAction(_("&Quit")) - quit_option.triggered.connect(self.actuator.quit) + quit_option.triggered.connect(self.close) view_menu = menubar.addMenu(_("&View")) expert_gui = view_menu.addAction(_("&Pro Mode")) @@ -613,9 +613,6 @@ class MiniActuator: def show_seed_dialog(self): gui_qt.ElectrumWindow.show_seed_dialog(self.wallet) - def quit(self): - sys.exit(0) - class MiniDriver(QObject): INITIALIZING = 0 From 3e89b650258a45afac878d9ee7cb8ba54d50e714 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 11:53:31 -0700 Subject: [PATCH 28/81] another small toolkit comment --- electrum | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electrum b/electrum index 7d5e22f4..43eb6de6 100755 --- a/electrum +++ b/electrum @@ -160,7 +160,8 @@ if __name__ == '__main__': error_message.showMessage("

Sorry, Electrum requires Qt >= 4.7 to run.

Check your distributions packages or download it at http://qt.nokia.com/downloads

") app.exec_() sys.exit(0) - + + #use the lite version if no toolkit specified try: import lib.gui_lite as gui except ImportError: From 990547a06c1220bccd1118e986a5c9bf7d25f31f Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 12:01:49 -0700 Subject: [PATCH 29/81] changed print_error to NameError exception to reduce coupling --- electrum | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/electrum b/electrum index 43eb6de6..8d8d03f5 100755 --- a/electrum +++ b/electrum @@ -167,8 +167,7 @@ if __name__ == '__main__': except ImportError: import electrum.gui_lite as gui else: - print_error("Error: Unknown GUI: " + options.gui) - exit(1) + raise NameError(sys.exit("Error: Unknown GUI: " + options.gui)) gui = gui.ElectrumGui(wallet) WalletSynchronizer(wallet,True).start() From 62ec74c0100ec6637808c14e51b6c3d9dfc44973 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 16:35:34 -0700 Subject: [PATCH 30/81] created docstring for expand() --- lib/gui_lite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index ad9bf135..0ce5f5ed 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -74,6 +74,7 @@ class ElectrumGui: self.app.exec_() def expand(self): + """Hide the lite mode window and show pro-mode.""" self.mini.hide() self.expert.show() From e34243d778e30c6bd29510dd50270569de1f0785 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 17:20:42 -0700 Subject: [PATCH 31/81] created set_balance() docstring --- lib/gui_lite.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 0ce5f5ed..bf0a64a0 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -275,6 +275,7 @@ class MiniWindow(QDialog): self.amount_input_changed(self.amount_input.text()) def set_balances(self, btc_balance): + """Set the bitcoin balance and update the amount label accordingly.""" self.btc_balance = btc_balance quote_text = self.create_quote_text(btc_balance) if quote_text: @@ -481,7 +482,7 @@ class ReceivePopup(QDialog): self.show() class MiniActuator: - """Initialize the definitions for all the menubar functions and + """Initialize the definitions relating to themes and sending/recieving bitcoins. """ @@ -506,6 +507,7 @@ class MiniActuator: def theme_names(self): """Sort themes.""" return sorted(self.themes.keys()) + def selected_theme(self): """Select theme.""" return self.theme_name From 36e250d3ab007f37dffa0022e9b37b67f5ef9e1e Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 17:26:50 -0700 Subject: [PATCH 32/81] created create_quote_text() docstring --- lib/gui_lite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index bf0a64a0..19bae02e 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -300,6 +300,7 @@ class MiniWindow(QDialog): self.balance_label.show_balance() def create_quote_text(self, btc_balance): + """Return a string copy of the amount of bitcoins in the argument.""" quote_currency = self.quote_currencies[0] quote_balance = self.exchanger.exchange(btc_balance, quote_currency) if quote_balance is None: From fac2bc7387e4ba19232d253da848f3fafa038388 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 17:30:59 -0700 Subject: [PATCH 33/81] updated create_quote_text() docstring --- lib/gui_lite.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 19bae02e..07bf9d8a 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -300,7 +300,8 @@ class MiniWindow(QDialog): self.balance_label.show_balance() def create_quote_text(self, btc_balance): - """Return a string copy of the amount of bitcoins in the argument.""" + """Return a string copy of the amount fiat currency the + user has in bitcoins.""" quote_currency = self.quote_currencies[0] quote_balance = self.exchanger.exchange(btc_balance, quote_currency) if quote_balance is None: From 9f4f7ee3c6ee0fbc6bdb4185cb3ded9108120b13 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 17:45:19 -0700 Subject: [PATCH 34/81] created docstring for set_button_amount() --- lib/gui_lite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 07bf9d8a..8ba16b04 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -318,6 +318,8 @@ class MiniWindow(QDialog): self.amount_input.setText("") def check_button_status(self): + """Check that the bitcoin address is valid and that something + is entered in the amount before making the send button clickable.""" if (self.address_input.property("isValid") == True and len(self.amount_input.text()) > 0): self.send_button.setDisabled(False) From 3bd77170380152fadc3132ad2695d2fa6d43a6ce Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 17:50:54 -0700 Subject: [PATCH 35/81] got rid of boolean value comparison using == as stated in pep8 style guide --- lib/gui_lite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 8ba16b04..2e59115f 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -320,7 +320,7 @@ class MiniWindow(QDialog): def check_button_status(self): """Check that the bitcoin address is valid and that something is entered in the amount before making the send button clickable.""" - if (self.address_input.property("isValid") == True and + if (self.address_input.property("isValid") and len(self.amount_input.text()) > 0): self.send_button.setDisabled(False) else: From f2277adf10475c3563363e2f586e92cbb7b259f9 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 18:05:53 -0700 Subject: [PATCH 36/81] created mousePressedEvents() and se_balance_text() docstrings --- lib/gui_lite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 2e59115f..4d21c3fc 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -391,10 +391,12 @@ class BalanceLabel(QLabel): self.amount_text = "" def mousePressEvent(self, event): + """Change the fiat currency selection if window background is clicked.""" if self.state != self.SHOW_CONNECTING: self.change_quote_currency() def set_balance_text(self, btc_balance, quote_text): + """Set the amount of bitcoins in the gui.""" if self.state == self.SHOW_CONNECTING: self.state = self.SHOW_BALANCE self.balance_text = "%s BTC %s" % (btc_balance, quote_text) From f8c68fc51ef26c48ed58df4ca11ef63a48e53071 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 18:22:56 -0700 Subject: [PATCH 37/81] created amount_input_changed() docstring --- lib/gui_lite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 4d21c3fc..476b21c5 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -285,6 +285,7 @@ class MiniWindow(QDialog): self.setWindowTitle("Electrum - %s BTC" % btc_balance) def amount_input_changed(self, amount_text): + """Update the number of bitcoins displayed.""" self.check_button_status() try: From e0d6570a1f6989e0b253126d4b9e9395eefa8b73 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 18:25:38 -0700 Subject: [PATCH 38/81] created set_quote_currency() docstring --- lib/gui_lite.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 476b21c5..a020da82 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -255,6 +255,7 @@ class MiniWindow(QDialog): pass def set_quote_currency(self, currency): + """Set and display the fiat currency country.""" assert currency in self.quote_currencies self.quote_currencies.remove(currency) self.quote_currencies = [currency] + self.quote_currencies From 6122898915b7e304d43ef1480b7a4eefb4f59d2a Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 18:33:35 -0700 Subject: [PATCH 39/81] changed to use built-in list methods --- lib/gui_lite.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index a020da82..9292f372 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -258,7 +258,8 @@ class MiniWindow(QDialog): """Set and display the fiat currency country.""" assert currency in self.quote_currencies self.quote_currencies.remove(currency) - self.quote_currencies = [currency] + self.quote_currencies + self.quote_currencies.insert(0, currency) + #self.quote_currencies = [currency] + self.quote_currencies self.refresh_balance() def change_quote_currency(self): From c2713f6089755dfd59f89088f69cc0f863b84506 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 18:33:55 -0700 Subject: [PATCH 40/81] changed to use built-in list methods --- lib/gui_lite.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 9292f372..a88ec4a9 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -259,7 +259,6 @@ class MiniWindow(QDialog): assert currency in self.quote_currencies self.quote_currencies.remove(currency) self.quote_currencies.insert(0, currency) - #self.quote_currencies = [currency] + self.quote_currencies self.refresh_balance() def change_quote_currency(self): From 3f167cb650e3330c496d04b34d61506ccc33f831 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 19:50:21 -0700 Subject: [PATCH 41/81] got rid of magic number --- lib/exchange_rate.py | 2 +- lib/gui_lite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py index e8c9fac2..b868b1b9 100644 --- a/lib/exchange_rate.py +++ b/lib/exchange_rate.py @@ -31,7 +31,7 @@ class Exchanger(threading.Thread): connection = httplib.HTTPSConnection('intersango.com') connection.request("GET", "/api/ticker.php") response = connection.getresponse() - if response.status == 404: + if response.reason == httplib.responses[httplib.NOT_FOUND]: return response = json.loads(response.read()) # 1 = BTC:GBP diff --git a/lib/gui_lite.py b/lib/gui_lite.py index a88ec4a9..15971f7e 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -535,7 +535,7 @@ class MiniActuator: set_quote_currency(currency) def set_config_currency(self, conversion_currency): - """Change the fiat currency conversion country.""" + """Change the wallet fiat currency country.""" self.wallet.conversion_currency = conversion_currency def copy_address(self, receive_popup): From 9fc4e1a1b10a486d8c56d8c08f1d86d23dfd2e5e Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Wed, 22 Aug 2012 20:11:38 -0700 Subject: [PATCH 42/81] changed lookup_rate() to non-public --- lib/exchange_rate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py index b868b1b9..77cbf9b1 100644 --- a/lib/exchange_rate.py +++ b/lib/exchange_rate.py @@ -40,16 +40,16 @@ class Exchanger(threading.Thread): # 4 = BTC:PLN quote_currencies = {} try: - quote_currencies["GBP"] = self.lookup_rate(response, 1) - quote_currencies["EUR"] = self.lookup_rate(response, 2) - quote_currencies["USD"] = self.lookup_rate(response, 3) + quote_currencies["GBP"] = self._lookup_rate(response, 1) + quote_currencies["EUR"] = self._lookup_rate(response, 2) + quote_currencies["USD"] = self._lookup_rate(response, 3) with self.lock: self.quote_currencies = quote_currencies self.parent.emit(SIGNAL("refresh_balance()")) except KeyError: pass - def lookup_rate(self, response, quote_id): + def _lookup_rate(self, response, quote_id): return decimal.Decimal(response[str(quote_id)]["last"]) if __name__ == "__main__": From 2b96b6dec1730c4969cd8a8f4e76e3cef6e819f9 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Thu, 23 Aug 2012 10:06:21 +0100 Subject: [PATCH 43/81] Unneeded exception raised. sys.exit returns before exception ever gets a chance to be thrown. --- electrum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum b/electrum index 8d8d03f5..39614764 100755 --- a/electrum +++ b/electrum @@ -167,7 +167,7 @@ if __name__ == '__main__': except ImportError: import electrum.gui_lite as gui else: - raise NameError(sys.exit("Error: Unknown GUI: " + options.gui)) + sys.exit("Error: Unknown GUI: " + options.gui) gui = gui.ElectrumGui(wallet) WalletSynchronizer(wallet,True).start() From 77b3052f44f796c6f8cc2f7151cd662cc373a1fe Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Thu, 23 Aug 2012 10:07:28 +0100 Subject: [PATCH 44/81] (explanation: the value returned is a qVariant not a bool and so needs explicit comparison to work) Revert "got rid of boolean value comparison using == as stated in pep8 style guide" This reverts commit 3bd77170380152fadc3132ad2695d2fa6d43a6ce. --- lib/gui_lite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 15971f7e..d27e50a0 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -322,7 +322,7 @@ class MiniWindow(QDialog): def check_button_status(self): """Check that the bitcoin address is valid and that something is entered in the amount before making the send button clickable.""" - if (self.address_input.property("isValid") and + if (self.address_input.property("isValid") == True and len(self.amount_input.text()) > 0): self.send_button.setDisabled(False) else: From 89953895f8daa60ef83f62492d0df878078f2909 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Thu, 23 Aug 2012 10:09:54 +0100 Subject: [PATCH 45/81] Added explanation to line returning qVariant for future eyes. --- lib/gui_lite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index d27e50a0..b8dc90e3 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -322,6 +322,8 @@ class MiniWindow(QDialog): def check_button_status(self): """Check that the bitcoin address is valid and that something is entered in the amount before making the send button clickable.""" + # self.address_input.property(...) returns a qVariant, not a bool. + # The == is needed to properly invoke a comparison. if (self.address_input.property("isValid") == True and len(self.amount_input.text()) > 0): self.send_button.setDisabled(False) From 31aaf473c81a7358eb711c3117d396b218f11ff1 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 17:05:07 -0700 Subject: [PATCH 46/81] upgraded optparse with the newer module argparse. Can't see any problems so far --- electrum | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/electrum b/electrum index 8d8d03f5..dc6a34b4 100755 --- a/electrum +++ b/electrum @@ -16,7 +16,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import re, sys +import re +import sys +import argparse + try: from lib.util import print_error except ImportError: @@ -99,18 +102,18 @@ protected_commands = ['payto', 'password', 'mktx', 'seed', 'import','signmessage if __name__ == '__main__': usage = "usage: %prog [options] command\nCommands: "+ (', '.join(known_commands)) - parser = OptionParser(usage=usage) - parser.add_option("-g", "--gui", dest="gui", default="lite", help="gui") - parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") - parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") - parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") - parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") - parser.add_option("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses") - parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") - parser.add_option("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") - parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") - parser.add_option("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet") - options, args = parser.parse_args() + parser = argparse.ArgumentParser(prog=usage) + parser.add_argument("-g", "--gui", dest="gui", default="lite", help="gui") + parser.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") + parser.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") + parser.add_argument("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") + parser.add_argument("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") + parser.add_argument("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses") + parser.add_argument("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") + parser.add_argument("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") + parser.add_argument("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") + parser.add_argument("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet") + args = parser.parse_args() wallet = Wallet() wallet.set_path(options.wallet_path) @@ -309,7 +312,6 @@ if __name__ == '__main__': cmd2 = firstarg if cmd2 not in known_commands: parser.print_help() - print print "Type 'electrum help ' to see the help for a specific command" print "Type 'electrum --help' to see the list of options" print "List of commands:", ', '.join(known_commands) From c8f19e1969e85033255c4250c3bffd4584df3edd Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 17:07:38 -0700 Subject: [PATCH 47/81] removed optparse import statment --- electrum | 1 - 1 file changed, 1 deletion(-) diff --git a/electrum b/electrum index 61c8239e..f4b7ef00 100755 --- a/electrum +++ b/electrum @@ -40,7 +40,6 @@ try: except ImportError: from electrum import Wallet, WalletSynchronizer, format_satoshis, mnemonic, prompt_password -from optparse import OptionParser from decimal import Decimal known_commands = { From 47432b32c8aac09bbeae20a5d03f3eb2cbb83288 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 17:44:37 -0700 Subject: [PATCH 48/81] Added more descriptive error if wallet cannot be loaded --- electrum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electrum b/electrum index f4b7ef00..70281656 100755 --- a/electrum +++ b/electrum @@ -178,8 +178,8 @@ if __name__ == '__main__': found = wallet.file_exists if not found: found = gui.restore_or_create() - except SystemExit, e: - exit(e) + except IOError: + exit("Error retrieving wallet file.") except BaseException, e: import traceback traceback.print_exc(file=sys.stdout) From cb67ec4454aecbd55151c7200c1e005da1627e57 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 17:50:44 -0700 Subject: [PATCH 49/81] changed to more descriptive exception --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index cbf0cdcb..4337850b 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -715,7 +715,7 @@ class Wallet: self.conversion_currency = d.get('conversion_currency', 'USD') self.theme = d.get('theme', 'Cleanlook') except: - raise BaseException("cannot read wallet file") + raise IOError("Cannot read wallet file.") self.update_tx_history() From 407070bba0c7a7f174e1f6db6d8f94f6edeb7911 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 17:59:54 -0700 Subject: [PATCH 50/81] Didn't need a seperate variable just for string --- lib/wallet.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index 4337850b..7df45c08 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -679,7 +679,6 @@ class Wallet: '''Read the contents of the wallet file.''' import interface - upgrade_msg = """This wallet seed is deprecated. Please run upgrade.py for a diagnostic.""" self.file_exists = False try: f = open(self.path,"r") @@ -720,7 +719,7 @@ class Wallet: self.update_tx_history() if self.seed_version != SEED_VERSION: - raise BaseException(upgrade_msg) + raise ValueError("This wallet seed is deprecated. Please run upgrade.py for a diagnostic.") if self.remote_url: assert self.master_public_key.encode('hex') == self.get_remote_mpk() From 719b9d7d33c15589ffee41ba64020b6761058e2f Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:01:06 -0700 Subject: [PATCH 51/81] Small cosmetic fix --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index 7df45c08..e95d545c 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -676,7 +676,7 @@ class Wallet: os.chmod(self.path,stat.S_IREAD | stat.S_IWRITE) def read(self): - '''Read the contents of the wallet file.''' + """Read the contents of the wallet file.""" import interface self.file_exists = False From 6b86942ccbb9c0d80f4af190343983440e859f4a Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:02:55 -0700 Subject: [PATCH 52/81] Don't need two try/catch statments if nothing happens when exception is caught --- lib/wallet.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index e95d545c..126b9ede 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -684,9 +684,7 @@ class Wallet: f = open(self.path,"r") data = f.read() f.close() - except: - return - try: + d = ast.literal_eval( data ) #parse raw data from reading wallet file interface.old_to_new(d) self.seed_version = d.get('seed_version') From cdc16acabb45554cd82def8c312aa1444bf84149 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:11:57 -0700 Subject: [PATCH 53/81] changed to more descriptive exception --- lib/wallet.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index 126b9ede..478b6ae4 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -687,6 +687,7 @@ class Wallet: d = ast.literal_eval( data ) #parse raw data from reading wallet file interface.old_to_new(d) + self.seed_version = d.get('seed_version') self.master_public_key = d.get('master_public_key').decode('hex') self.use_encryption = d.get('use_encryption') @@ -836,7 +837,7 @@ class Wallet: try: d.decode('hex') except: - raise BaseException("Invalid password") + raise ValueError("Invalid password") return d else: return s From e12699ae75cb23ac6c2c6f5db21c29ab0dfa9274 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:16:27 -0700 Subject: [PATCH 54/81] getting rid of more BaseExceptions --- lib/wallet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index 478b6ae4..fb3ba9a1 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -920,10 +920,10 @@ class Wallet: def mktx(self, to_address, amount, label, password, fee=None, change_addr=None, from_addr= None): if not self.is_valid(to_address): - raise BaseException("Invalid address") + raise ValueError("Invalid address") inputs, total, fee = self.choose_tx_inputs( amount, fee, from_addr ) if not inputs: - raise BaseException("Not enough funds") + raise ValueError("Not enough funds") if not self.use_change and not change_addr: change_addr = inputs[0][0] From 2de8df6758a8da50b4c2bdfcda5d0e81649936fb Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:17:30 -0700 Subject: [PATCH 55/81] getting rid of another BaseExceptions --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index fb3ba9a1..dfc96fc6 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -994,7 +994,7 @@ class Wallet: self.verify_message(previous, signature, "alias:%s:%s"%(alias,target)) if not self.is_valid(target): - raise BaseException("Invalid bitcoin address") + raise ValueError("Invalid bitcoin address") return target, signing_addr, auth_name From 34a3eea0bfc3f493184478f924f37d8d14741570 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:21:17 -0700 Subject: [PATCH 56/81] changed imports to fit pep8 styleguide --- lib/wallet.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index dfc96fc6..202f27dd 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -16,9 +16,20 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys +import base64 +import os +import re +import hashlib +import copy +import operator +import ast +import threading +import random +import getpass +import aes +import ecdsa -import sys, base64, os, re, hashlib, copy, operator, ast, threading, random, getpass -import aes, ecdsa from ecdsa.util import string_to_number, number_to_string from util import print_error From a6239764d236beb955e54c8b6043f73e8ca8a2e9 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:36:40 -0700 Subject: [PATCH 57/81] small cosmetic change --- lib/wallet.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index 202f27dd..2b4f6514 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -76,8 +76,7 @@ __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' __b58base = len(__b58chars) def b58encode(v): - """ encode v, which is a string of bytes, to base58. - """ + """ encode v, which is a string of bytes, to base58.""" long_value = 0L for (i, c) in enumerate(v[::-1]): @@ -100,8 +99,7 @@ def b58encode(v): return (__b58chars[0]*nPad) + result def b58decode(v, length): - """ decode v into a string of len bytes - """ + """ decode v into a string of len bytes.""" long_value = 0L for (i, c) in enumerate(v[::-1]): long_value += __b58chars.find(c) * (__b58base**i) From 25ad5fcd06e09bf9f59905dd78a9ee0b3857c655 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Thu, 23 Aug 2012 18:38:28 -0700 Subject: [PATCH 58/81] got rid of print_error --- lib/wallet.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index 2b4f6514..f9dae25a 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -166,8 +166,7 @@ def prompt_password(prompt, confirm=True): password2 = getpass.getpass("Confirm: ") if password != password2: - print_error("Error: Passwords do not match.") - sys.exit(1) + sys.exit("Error: Passwords do not match.") else: password = raw_input(prompt) From 58e6050f5257550702ed99b5b67e2303b878ab5d Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Fri, 24 Aug 2012 09:34:30 +0100 Subject: [PATCH 59/81] Better looking set_path(wallet_path) method. Flattened function that's easier to read. --- lib/wallet.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index cbf0cdcb..023daf74 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -354,19 +354,21 @@ class Wallet: """Set the path of the wallet.""" if wallet_path is not None: self.path = wallet_path + return + # Look for wallet file in the default data directory. + # Keeps backwards compatibility. + if "HOME" in os.environ: + wallet_dir = os.path.join(os.environ["HOME"], ".electrum") + elif "LOCALAPPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + elif "APPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["APPDATA"], "Electrum") else: - # backward compatibility: look for wallet file in the default data directory - if "HOME" in os.environ: - wallet_dir = os.path.join( os.environ["HOME"], '.electrum') - elif "LOCALAPPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["LOCALAPPDATA"], 'Electrum' ) - elif "APPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' ) - else: - raise BaseException("No home directory found in environment variables.") - - if not os.path.exists( wallet_dir ): os.mkdir( wallet_dir ) - self.path = os.path.join( wallet_dir, 'electrum.dat' ) + raise BaseException("No home directory found in environment variables.") + # Make wallet directory if it does not yet exist. + if not os.path.exists(wallet_dir): + os.mkdir(wallet_dir) + self.path = os.path.join(wallet_dir, "electrum.dat") def import_key(self, keypair, password): address, key = keypair.split(':') From 5c4be3196a8e16a0048caf9a649db5338297f6ed Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Fri, 24 Aug 2012 09:34:30 +0100 Subject: [PATCH 60/81] Better looking set_path(wallet_path) method. Flattened function that's easier to read. --- lib/wallet.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index f9dae25a..bded27cf 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -362,19 +362,21 @@ class Wallet: """Set the path of the wallet.""" if wallet_path is not None: self.path = wallet_path + return + # Look for wallet file in the default data directory. + # Keeps backwards compatibility. + if "HOME" in os.environ: + wallet_dir = os.path.join(os.environ["HOME"], ".electrum") + elif "LOCALAPPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["LOCALAPPDATA"], "Electrum") + elif "APPDATA" in os.environ: + wallet_dir = os.path.join(os.environ["APPDATA"], "Electrum") else: - # backward compatibility: look for wallet file in the default data directory - if "HOME" in os.environ: - wallet_dir = os.path.join( os.environ["HOME"], '.electrum') - elif "LOCALAPPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["LOCALAPPDATA"], 'Electrum' ) - elif "APPDATA" in os.environ: - wallet_dir = os.path.join( os.environ["APPDATA"], 'Electrum' ) - else: - raise BaseException("No home directory found in environment variables.") - - if not os.path.exists( wallet_dir ): os.mkdir( wallet_dir ) - self.path = os.path.join( wallet_dir, 'electrum.dat' ) + raise BaseException("No home directory found in environment variables.") + # Make wallet directory if it does not yet exist. + if not os.path.exists(wallet_dir): + os.mkdir(wallet_dir) + self.path = os.path.join(wallet_dir, "electrum.dat") def import_key(self, keypair, password): address, key = keypair.split(':') From 3d836ebc385b1c9a3eca76b9d0d1a4165d68d46d Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Fri, 24 Aug 2012 22:01:08 +0100 Subject: [PATCH 61/81] Revert "Don't need two try/catch statments if nothing happens when exception is caught" This reverts commit 6b86942ccbb9c0d80f4af190343983440e859f4a. --- lib/wallet.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index bded27cf..d81da531 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -694,7 +694,9 @@ class Wallet: f = open(self.path,"r") data = f.read() f.close() - + except: + return + try: d = ast.literal_eval( data ) #parse raw data from reading wallet file interface.old_to_new(d) From 26c0b786e9c2c1996b22c68ccacae27fd0aaf27a Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Fri, 24 Aug 2012 22:02:58 +0100 Subject: [PATCH 62/81] RAII open of wallet file. --- lib/wallet.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/wallet.py b/lib/wallet.py index d81da531..5677cd4c 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -691,10 +691,9 @@ class Wallet: self.file_exists = False try: - f = open(self.path,"r") - data = f.read() - f.close() - except: + with open(self.path, "r") as f: + data = f.read() + except IOError: return try: d = ast.literal_eval( data ) #parse raw data from reading wallet file From edf293e61195cca57a0805a1f9b16404b46c3dc9 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sat, 25 Aug 2012 14:11:50 -0700 Subject: [PATCH 63/81] reverted commit 31aaf473c81a7358eb711c3117d396b218f11ff1 due to it breaking electrum --- electrum | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/electrum b/electrum index 70281656..c1f44c78 100755 --- a/electrum +++ b/electrum @@ -18,7 +18,8 @@ import re import sys -import argparse +# import argparse +import optparse try: from lib.util import print_error @@ -101,18 +102,18 @@ protected_commands = ['payto', 'password', 'mktx', 'seed', 'import','signmessage if __name__ == '__main__': usage = "usage: %prog [options] command\nCommands: "+ (', '.join(known_commands)) - parser = argparse.ArgumentParser(prog=usage) - parser.add_argument("-g", "--gui", dest="gui", default="lite", help="gui") - parser.add_argument("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") - parser.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") - parser.add_argument("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") - parser.add_argument("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") - parser.add_argument("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses") - parser.add_argument("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") - parser.add_argument("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") - parser.add_argument("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") - parser.add_argument("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet") - args = parser.parse_args() + parser = OptionParser(prog=usage) + parser.add_option("-g", "--gui", dest="gui", default="lite", help="gui") + parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") + parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") + parser.add_option("-a", "--all", action="store_true", dest="show_all", default=False, help="show all addresses") + parser.add_option("-b", "--balance", action="store_true", dest="show_balance", default=False, help="show the balance at listed addresses") + parser.add_option("-k", "--keys",action="store_true", dest="show_keys",default=False, help="show the private keys of listed addresses") + parser.add_option("-f", "--fee", dest="tx_fee", default="0.005", help="set tx fee") + parser.add_option("-s", "--fromaddr", dest="from_addr", default=None, help="set source address for payto/mktx. if it isn't in the wallet, it will ask for the private key unless supplied in the format public_key:private_key. It's not saved in the wallet.") + parser.add_option("-c", "--changeaddr", dest="change_addr", default=None, help="set the change address for payto/mktx. default is a spare address, or the source address if it's not in the wallet") + parser.add_option("-r", "--remote", dest="remote_url", default=None, help="URL of a remote wallet") + options, args = parser.parse_args() wallet = Wallet() wallet.set_path(options.wallet_path) From dd78f0978bf5a1a1759e2c08329cadd8e4e02ec4 Mon Sep 17 00:00:00 2001 From: Jimbo77 Date: Sat, 25 Aug 2012 14:16:21 -0700 Subject: [PATCH 64/81] needed to include absolute path for optparse methods --- electrum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum b/electrum index c1f44c78..93a236c5 100755 --- a/electrum +++ b/electrum @@ -102,7 +102,7 @@ protected_commands = ['payto', 'password', 'mktx', 'seed', 'import','signmessage if __name__ == '__main__': usage = "usage: %prog [options] command\nCommands: "+ (', '.join(known_commands)) - parser = OptionParser(prog=usage) + parser = optparse.OptionParser(prog=usage) parser.add_option("-g", "--gui", dest="gui", default="lite", help="gui") parser.add_option("-w", "--wallet", dest="wallet_path", help="wallet path (default: electrum.dat)") parser.add_option("-o", "--offline", action="store_true", dest="offline", default=False, help="remain offline") From ce584890ea16b770280fcda814b7a7873dda8e5b Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Sun, 26 Aug 2012 16:05:05 +0200 Subject: [PATCH 65/81] Explanation: Doesn't preserve the same behaviour as code throws BaseException not SystemExit. Therefore it wasn't meant to be catching user errors. Revert "Added more descriptive error if wallet cannot be loaded" This reverts commit 47432b32c8aac09bbeae20a5d03f3eb2cbb83288. --- electrum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electrum b/electrum index 93a236c5..7a384c27 100755 --- a/electrum +++ b/electrum @@ -179,8 +179,8 @@ if __name__ == '__main__': found = wallet.file_exists if not found: found = gui.restore_or_create() - except IOError: - exit("Error retrieving wallet file.") + except SystemExit, e: + exit(e) except BaseException, e: import traceback traceback.print_exc(file=sys.stdout) From 466d1e0f402d9d5580111a0a18608f449567389c Mon Sep 17 00:00:00 2001 From: Maran Date: Sun, 26 Aug 2012 21:30:25 +0200 Subject: [PATCH 66/81] If we are doing a sdist just include everything since we don't know the target os --- setup.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 5a90bf04..0e2fcb3b 100644 --- a/setup.py +++ b/setup.py @@ -7,13 +7,12 @@ from lib.version import ELECTRUM_VERSION as version import lib.util as util import os, sys, platform from lib.util import print_error - if sys.version_info[:3] < (2,6,0): sys.exit("Error: Electrum requires Python version >= 2.6.0...") data_files = [] - -if platform.system() != 'Windows' and platform.system() != 'Darwin': +if (len(sys.argv) > 1 and (sys.argv[1] == "sdist")) or (platform.system() != 'Windows' and platform.system() != 'Darwin'): + print "Including all files" data_files += [ ('/usr/share/applications/',['electrum.desktop']), ('/usr/share/app-install/icons/',['electrum.png']) From a2db281494e9cd233e8e7fd9627b7e53d41ad7b6 Mon Sep 17 00:00:00 2001 From: Maran Date: Sun, 26 Aug 2012 22:15:09 +0200 Subject: [PATCH 67/81] Added a message to the sign/verify message help text to explain spaces inside the message --- electrum | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electrum b/electrum index 7a384c27..0e2b8656 100755 --- a/electrum +++ b/electrum @@ -78,9 +78,9 @@ options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address 'import': 'Imports a key pair\nSyntax: import
:', 'signmessage': - 'Signs a message with a key\nSyntax: signmessage
', + 'Signs a message with a key\nSyntax: signmessage
\nIf you want to lead or end a message with spaces, or want double spaces inside the message make sure you quote the string. I.e. " Hello This is a weird String "', 'verifymessage': - 'Verifies a signature\nSyntax: verifymessage
', + 'Verifies a signature\nSyntax: verifymessage
\nIf you want to lead or end a message with spaces, or want double spaces inside the message make sure you quote the string. I.e. " Hello This is a weird String "', 'eval': "Run python eval() on an object\nSyntax: eval \nExample: eval \"wallet.aliases\"", 'deseed': From 850d0dcd5ff74ce2ba72092dde8846de734a05c0 Mon Sep 17 00:00:00 2001 From: Maran Date: Sun, 26 Aug 2012 23:35:38 +0200 Subject: [PATCH 68/81] Made the error message for verifymessage more transparent --- electrum | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electrum b/electrum index 0e2b8656..1454e9e6 100755 --- a/electrum +++ b/electrum @@ -535,7 +535,8 @@ if __name__ == '__main__': try: wallet.verify_message(address, signature, message) print True - except: + except BaseException as e: + print "Verification error: {0}".format(e) print False elif cmd == 'freeze': From 9815fb5a70e1f36f41f4f21a5ffeff706ea52ef8 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 03:10:28 +0200 Subject: [PATCH 69/81] pw_decode returns ValueError on fail. --- electrum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum b/electrum index 1454e9e6..69cdb563 100755 --- a/electrum +++ b/electrum @@ -504,7 +504,7 @@ if __name__ == '__main__': elif cmd == 'password': try: seed = wallet.pw_decode( wallet.seed, password) - except StandardError: + except ValueError: sys.exit("Error: Password does not decrypt this wallet.") new_password = prompt_password('New password:') From f2fb2356433ebc1f0daf76b33d5564cc23cb2881 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 03:12:43 +0200 Subject: [PATCH 70/81] be more permissive with catching exceptions here as many varities possible. --- electrum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum b/electrum index 69cdb563..d87d276a 100755 --- a/electrum +++ b/electrum @@ -357,7 +357,7 @@ if __name__ == '__main__': d = ast.literal_eval( data ) seed = d['seed'] imported_keys = d.get('imported_keys',{}) - except IOError: + except: sys.exit("Error: Error with seed file") mpk = wallet.master_public_key From b25e93c4bc1af718fad780a2bf6482d5e82eac01 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 03:32:31 +0200 Subject: [PATCH 71/81] Update servers list once fetched from remote. --- lib/gui_lite.py | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 51ad4fcf..c7909a3f 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -469,7 +469,8 @@ class ReceivePopup(QDialog): self.setMouseTracking(True) self.setWindowTitle("Electrum - " + _("Receive Bitcoin payment")) - self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint|Qt.MSWindowsFixedSizeDialogHint) + self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint| + Qt.MSWindowsFixedSizeDialogHint) self.layout().setSizeConstraint(QLayout.SetFixedSize) #self.setFrameStyle(QFrame.WinPanel|QFrame.Raised) #self.setAlignment(Qt.AlignCenter) @@ -482,9 +483,11 @@ class ReceivePopup(QDialog): QCursor.setPos(center_mouse_pos) self.show() -class MiniActuator: +class MiniActuator(QObject): def __init__(self, wallet): + super(QObject, self).__init__() + self.wallet = wallet self.theme_name = self.wallet.theme @@ -522,6 +525,7 @@ class MiniActuator: def set_servers_gui_stuff(self, servers_menu, servers_group): self.servers_menu = servers_menu self.servers_group = servers_group + self.connect(self, SIGNAL("updateservers()"), self.update_servers_list) def populate_servers_menu(self): interface = self.wallet.interface @@ -541,21 +545,29 @@ class MiniActuator: server_action.setCheckable(True) if server_name == current_server: server_action.setChecked(True) - #class SelectServerFunctor: - # def __init__(self, server_name, servers_list): - # self.server_name = server_name - # self.servers_list = servers_list - # def __call__(self, checked): - # if checked: - # # call server_list_changed - # self. + class SelectServerFunctor: + def __init__(self, server_name, server_selected): + self.server_name = server_name + self.server_selected = server_selected + def __call__(self, checked): + if checked: + # call server_selected + self.server_selected(self.server_name) + delegate = SelectServerFunctor(server_name, self.server_selected) + server_action.toggled.connect(delegate) self.servers_group.addAction(server_action) def server_list_changed(self): - # clear servers_menu - # clear servers_group? - # call populate_servers_menu - print "hello" + self.emit(SIGNAL("updateservers()")) + + def update_servers_list(self): + # Clear servers_group + for action in self.servers_group.actions(): + self.servers_group.removeAction(action) + self.populate_servers_menu() + + def server_selected(self, server_name): + print server_name def copy_address(self, receive_popup): addrs = [addr for addr in self.wallet.all_addresses() From 2b6d5ebd5508437870b86e309610236043f9d6f1 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 03:47:40 +0200 Subject: [PATCH 72/81] Change server in lite mode. --- lib/gui_lite.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index c7909a3f..a703f8d6 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -531,14 +531,16 @@ class MiniActuator(QObject): interface = self.wallet.interface interface.servers_loaded_callback = self.server_list_changed if not interface.servers: - print "no servers loaded yet" - servers_list = [] - for x in DEFAULT_SERVERS: - h,port,protocol = x.split(':') - servers_list.append( (h,[(protocol,port)] ) ) + print "No servers loaded yet." + self.servers_list = [] + for server_string in DEFAULT_SERVERS: + host, port, protocol = server_string.split(':') + transports = [(protocol,port)] + self.servers_list.append((host, transports)) else: - servers_list = interface.servers - server_names = [details[0] for details in servers_list] + print "Servers loaded." + self.servers_list = interface.servers + server_names = [details[0] for details in self.servers_list] current_server = self.wallet.server.split(":")[0] for server_name in server_names: server_action = self.servers_menu.addAction(server_name) @@ -567,7 +569,22 @@ class MiniActuator(QObject): self.populate_servers_menu() def server_selected(self, server_name): - print server_name + match = [transports for (host, transports) in self.servers_list + if host == server_name] + assert len(match) == 1 + match = match[0] + # Default to TCP if available else use anything + # TODO: protocol should be selectable. + tcp_port = [port for (protocol, port) in match if protocol == "t"] + if len(tcp_port) == 0: + protocol = match[0][0] + port = match[0][1] + else: + protocol = "t" + port = tcp_port[0] + server_line = "%s:%s:%s" % (server_name, port, protocol) + # Should this have exception handling? + self.wallet.set_server(server_line) def copy_address(self, receive_popup): addrs = [addr for addr in self.wallet.all_addresses() From 3fe5ba85b2696be22339639aa79558b985b1fafb Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 03:49:53 +0200 Subject: [PATCH 73/81] Added QObject to MiniActuator. --- lib/gui_lite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index 3a05812e..d0997bea 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -495,7 +495,7 @@ class ReceivePopup(QDialog): QCursor.setPos(center_mouse_pos) self.show() -class MiniActuator: +class MiniActuator(QObject): """Initialize the definitions relating to themes and sending/recieving bitcoins. """ From 6dfb9e12c7bad5eb50d2b8b4a154874c6af306da Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Mon, 27 Aug 2012 04:02:15 +0200 Subject: [PATCH 74/81] Fixed bug where switching servers causes assert failure. --- lib/interface.py | 8 +++++--- lib/wallet.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/interface.py b/lib/interface.py index 7062beef..db5db092 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -313,7 +313,7 @@ class WalletSynchronizer(threading.Thread): self.loop = loop self.init_interface() - def init_interface(self): + def init_interface(self, servers_loaded_callback=None): try: host, port, protocol = self.wallet.server.split(':') port = int(port) @@ -332,6 +332,7 @@ class WalletSynchronizer(threading.Thread): InterfaceClass = TcpStratumInterface self.interface = InterfaceClass(host, port, self.wallet.debug_server) + self.interface.servers_loaded_callback = servers_loaded_callback self.wallet.interface = self.interface @@ -363,7 +364,7 @@ class WalletSynchronizer(threading.Thread): if ports and version: servers.append( (host, ports) ) self.interface.servers = servers - assert self.interface.servers_loaded_callback + assert self.interface.servers_loaded_callback is not None self.interface.servers_loaded_callback() elif method == 'blockchain.address.subscribe': @@ -427,7 +428,8 @@ class WalletSynchronizer(threading.Thread): self.wallet.trigger_callbacks() if self.loop: time.sleep(5) - self.init_interface() + # Server has been changed. Copy callback for new interface. + self.init_interface(self.interface.servers_loaded_callback) self.start_interface() continue else: diff --git a/lib/wallet.py b/lib/wallet.py index 5677cd4c..95f7232c 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -350,7 +350,7 @@ class Wallet: # raise an error if the format isnt correct a,b,c = server.split(':') b = int(b) - assert c in ['t','h','n'] + assert c in ['t', 'h', 'n'] # set the server if server != self.server: self.server = server From bab09b46278d8dfcb1472d0a0f053907cfca7eae Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 27 Aug 2012 10:38:22 +0200 Subject: [PATCH 75/81] Fix tab issue for password --- electrum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electrum b/electrum index d87d276a..914634d1 100755 --- a/electrum +++ b/electrum @@ -204,7 +204,7 @@ if __name__ == '__main__': if cmd in ['create', 'restore']: if wallet.file_exists: sys.exit("Error: Remove the existing wallet first!") - password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") + password = prompt_password("Password (hit return if you do not wish to encrypt your wallet):") w_host, w_port, w_protocol = wallet.server.split(':') host = raw_input("server (default:%s):"%w_host) From 4e3e4b90ea2651567b0f2d62244b9ed079ddf7ed Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 28 Aug 2012 11:04:11 +0200 Subject: [PATCH 76/81] Fix port number for bytesized --- lib/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/interface.py b/lib/interface.py index 76a3e4c8..172ad24b 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -27,7 +27,7 @@ DEFAULT_TIMEOUT = 5 DEFAULT_SERVERS = [ 'ecdsa.org:50001:t', 'electrum.novit.ro:50001:t', 'uncle-enzo.info:50001:t', - 'electrum.bytesized-hosting.com:50000:t'] # list of default servers + 'electrum.bytesized-hosting.com:50001:t'] # list of default servers def replace_keys(obj, old_key, new_key): From e61d478a80e450067f78dfaaef54e0643b26e299 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 29 Aug 2012 20:31:59 +0100 Subject: [PATCH 77/81] Tidy up of code to comply with style guide. --- lib/interface.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/interface.py b/lib/interface.py index bad7d841..ea347967 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -355,14 +355,14 @@ class WalletSynchronizer(threading.Thread): host = item[1] ports = [] version = None - if len(item)>2: + if len(item) > 2: for v in item[2]: - if re.match("[th]\d+",v): - ports.append((v[0],v[1:])) - if re.match("v(.?)+",v): + if re.match("[th]\d+", v): + ports.append((v[0], v[1:])) + if re.match("v(.?)+", v): version = v[1:] if ports and version: - servers.append( (host, ports) ) + servers.append((host, ports)) self.interface.servers = servers assert self.interface.servers_loaded_callback is not None self.interface.servers_loaded_callback() From b3b910d926c3ab081aa0c5ad2a090909311c631f Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 29 Aug 2012 20:49:31 +0100 Subject: [PATCH 78/81] WalletSynchronizer had a race condition caused by calling the callback before the Qt event loop (or other initialisation) finished. Ergo we split initialisation and the running of the thread, then use Qt SIGNALs to yield back into the Qt event loop. This ensures that the callback for the servers_list_changed is not called until the main Qt event loop is actually running. --- electrum | 3 ++- lib/gui_lite.py | 21 ++++++++++----------- lib/gui_qt.py | 3 +++ lib/interface.py | 18 +++++++++++------- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/electrum b/electrum index 914634d1..aca8083c 100755 --- a/electrum +++ b/electrum @@ -173,7 +173,8 @@ if __name__ == '__main__': sys.exit("Error: Unknown GUI: " + options.gui) gui = gui.ElectrumGui(wallet) - WalletSynchronizer(wallet,True).start() + interface = WalletSynchronizer(wallet, True, gui.server_list_changed) + interface.start() try: found = wallet.file_exists diff --git a/lib/gui_lite.py b/lib/gui_lite.py index d0997bea..f384b458 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -42,14 +42,18 @@ def resize_line_edit_width(line_edit, text_input): text_input += "A" line_edit.setMinimumWidth(metrics.width(text_input)) -class ElectrumGui: +class ElectrumGui(QObject): def __init__(self, wallet): + super(QObject, self).__init__() + self.wallet = wallet self.app = QApplication(sys.argv) def main(self, url): actuator = MiniActuator(self.wallet) + self.connect(self, SIGNAL("updateservers()"), + actuator.update_servers_list) # Should probably not modify the current path but instead # change the behaviour of rsrc(...) old_path = QDir.currentPath() @@ -74,6 +78,9 @@ class ElectrumGui: self.app.exec_() + def server_list_changed(self): + self.emit(SIGNAL("updateservers()")) + def expand(self): """Hide the lite mode window and show pro-mode.""" self.mini.hide() @@ -495,16 +502,13 @@ class ReceivePopup(QDialog): QCursor.setPos(center_mouse_pos) self.show() -class MiniActuator(QObject): +class MiniActuator: """Initialize the definitions relating to themes and - sending/recieving bitcoins. - """ + sending/recieving bitcoins.""" def __init__(self, wallet): """Retrieve the gui theme used in previous session.""" - super(QObject, self).__init__() - self.wallet = wallet self.theme_name = self.wallet.theme self.themes = util.load_theme_paths() @@ -549,11 +553,9 @@ class MiniActuator(QObject): def set_servers_gui_stuff(self, servers_menu, servers_group): self.servers_menu = servers_menu self.servers_group = servers_group - self.connect(self, SIGNAL("updateservers()"), self.update_servers_list) def populate_servers_menu(self): interface = self.wallet.interface - interface.servers_loaded_callback = self.server_list_changed if not interface.servers: print "No servers loaded yet." self.servers_list = [] @@ -583,9 +585,6 @@ class MiniActuator(QObject): server_action.toggled.connect(delegate) self.servers_group.addAction(server_action) - def server_list_changed(self): - self.emit(SIGNAL("updateservers()")) - def update_servers_list(self): # Clear servers_group for action in self.servers_group.actions(): diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 030215b0..66930735 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -1430,6 +1430,9 @@ class ElectrumGui: if app is None: self.app = QApplication(sys.argv) + def server_list_changed(self): + pass + def waiting_dialog(self): s = Timer() diff --git a/lib/interface.py b/lib/interface.py index ea347967..1af2fa25 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -306,14 +306,15 @@ class TcpStratumInterface(Interface): class WalletSynchronizer(threading.Thread): - def __init__(self, wallet, loop=False): + def __init__(self, wallet, loop=False, servers_loaded_callback=None): threading.Thread.__init__(self) self.daemon = True self.wallet = wallet self.loop = loop self.init_interface() + self.servers_loaded_callback = servers_loaded_callback - def init_interface(self, servers_loaded_callback=None): + def init_interface(self): try: host, port, protocol = self.wallet.server.split(':') port = int(port) @@ -332,10 +333,8 @@ class WalletSynchronizer(threading.Thread): InterfaceClass = TcpStratumInterface self.interface = InterfaceClass(host, port, self.wallet.debug_server) - self.interface.servers_loaded_callback = servers_loaded_callback self.wallet.interface = self.interface - def handle_response(self, r): if r is None: return @@ -364,8 +363,13 @@ class WalletSynchronizer(threading.Thread): if ports and version: servers.append((host, ports)) self.interface.servers = servers - assert self.interface.servers_loaded_callback is not None - self.interface.servers_loaded_callback() + # TODO: This assert fails with commands so it should be removed + # after we've ascertained it never fails when running the GUI. + assert self.servers_loaded_callback is not None + # servers_loaded_callback is None for commands, but should + # NEVER be None when using the GUI. + if self.servers_loaded_callback is not None: + self.servers_loaded_callback() elif method == 'blockchain.address.subscribe': addr = params[0] @@ -429,7 +433,7 @@ class WalletSynchronizer(threading.Thread): if self.loop: time.sleep(5) # Server has been changed. Copy callback for new interface. - self.init_interface(self.interface.servers_loaded_callback) + self.init_interface() self.start_interface() continue else: From 4c1bc141044edfb95b9f06503b43019d5b502d95 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 29 Aug 2012 20:54:28 +0100 Subject: [PATCH 79/81] Remove assert which isn't true for the commands (only the GUI). --- lib/interface.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/interface.py b/lib/interface.py index 1af2fa25..6a28cf8e 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -363,9 +363,6 @@ class WalletSynchronizer(threading.Thread): if ports and version: servers.append((host, ports)) self.interface.servers = servers - # TODO: This assert fails with commands so it should be removed - # after we've ascertained it never fails when running the GUI. - assert self.servers_loaded_callback is not None # servers_loaded_callback is None for commands, but should # NEVER be None when using the GUI. if self.servers_loaded_callback is not None: From ca4473c6201390a99a72d473c8f368b2b507d501 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 29 Aug 2012 21:27:22 +0100 Subject: [PATCH 80/81] If wallet does not exist, then it does not even attempt to read the config (read returns on IOError exception). Ergo a new wallet will not ever set the theme name and it will stay as None. We change this to a sensible default so new wallets have a themed GUI. --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index 95f7232c..18125891 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -290,7 +290,7 @@ class Wallet: self.num_zeros = 0 self.master_public_key = '' self.conversion_currency = None - self.theme = None + self.theme = "Cleanlook" # saved fields self.use_encryption = False From 9c122c23eaaba712016a7d233ee0cdb35bb6f689 Mon Sep 17 00:00:00 2001 From: Amir Taaki Date: Wed, 29 Aug 2012 21:43:34 +0100 Subject: [PATCH 81/81] Fixed issue 19 by jimboman77: https://github.com/spesmilo/electrum/issues/19 "Right now the only check thats being done is making sure that the length isn't 0, ie something is being entered before the send button becomes clickable." Also check that entered amount is <= btc_balance before enabling send button. --- lib/gui_lite.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/gui_lite.py b/lib/gui_lite.py index f384b458..f63c1812 100644 --- a/lib/gui_lite.py +++ b/lib/gui_lite.py @@ -332,10 +332,14 @@ class MiniWindow(QDialog): def check_button_status(self): """Check that the bitcoin address is valid and that something is entered in the amount before making the send button clickable.""" + try: + value = D(str(self.amount_input.text())) * 10**8 + except decimal.InvalidOperation: + value = None # self.address_input.property(...) returns a qVariant, not a bool. # The == is needed to properly invoke a comparison. if (self.address_input.property("isValid") == True and - len(self.amount_input.text()) > 0): + value is not None and 0 < value <= self.btc_balance): self.send_button.setDisabled(False) else: self.send_button.setDisabled(True)