mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-05 05:15:12 +00:00
better code organization
function parameters should be lowercase Fix crash on invalid labels import Added invoice exporting and reduced duplicate code Better exception handling removed json module import some more cleanup Cleaned up some stuff Added exporting contacts
This commit is contained in:
parent
36a444ba6c
commit
5997c18aef
7 changed files with 111 additions and 75 deletions
|
@ -23,16 +23,17 @@
|
||||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
import os
|
||||||
|
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.bitcoin import is_address
|
from electrum.bitcoin import is_address
|
||||||
from electrum.util import block_explorer_URL, FileImportFailed
|
from electrum.util import block_explorer_URL
|
||||||
from electrum.plugins import run_hook
|
from electrum.plugins import run_hook
|
||||||
from PyQt5.QtGui import *
|
from PyQt5.QtGui import *
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt5.QtWidgets import (
|
||||||
QAbstractItemView, QFileDialog, QMenu, QTreeWidgetItem)
|
QAbstractItemView, QFileDialog, QMenu, QTreeWidgetItem)
|
||||||
from .util import MyTreeWidget
|
from .util import MyTreeWidget, import_meta_gui, export_meta_gui
|
||||||
|
|
||||||
|
|
||||||
class ContactList(MyTreeWidget):
|
class ContactList(MyTreeWidget):
|
||||||
|
@ -53,15 +54,10 @@ class ContactList(MyTreeWidget):
|
||||||
self.parent.set_contact(item.text(0), item.text(1))
|
self.parent.set_contact(item.text(0), item.text(1))
|
||||||
|
|
||||||
def import_contacts(self):
|
def import_contacts(self):
|
||||||
wallet_folder = self.parent.get_wallet_folder()
|
import_meta_gui(self.parent, _('contacts'), self.parent.contacts.import_file, self.on_update)
|
||||||
filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
|
|
||||||
if not filename:
|
def export_contacts(self):
|
||||||
return
|
export_meta_gui(self.parent, _('contacts'), self.parent.contacts.export_file)
|
||||||
try:
|
|
||||||
self.parent.contacts.import_file(filename)
|
|
||||||
except FileImportFailed as e:
|
|
||||||
self.parent.show_message(str(e))
|
|
||||||
self.on_update()
|
|
||||||
|
|
||||||
def create_menu(self, position):
|
def create_menu(self, position):
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
|
@ -69,6 +65,7 @@ class ContactList(MyTreeWidget):
|
||||||
if not selected:
|
if not selected:
|
||||||
menu.addAction(_("New contact"), lambda: self.parent.new_contact_dialog())
|
menu.addAction(_("New contact"), lambda: self.parent.new_contact_dialog())
|
||||||
menu.addAction(_("Import file"), lambda: self.import_contacts())
|
menu.addAction(_("Import file"), lambda: self.import_contacts())
|
||||||
|
menu.addAction(_("Export file"), lambda: self.export_contacts())
|
||||||
else:
|
else:
|
||||||
names = [item.text(0) for item in selected]
|
names = [item.text(0) for item in selected]
|
||||||
keys = [item.text(1) for item in selected]
|
keys = [item.text(1) for item in selected]
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
from .util import *
|
from .util import *
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
from electrum.util import format_time, FileImportFailed
|
from electrum.util import format_time
|
||||||
|
|
||||||
|
|
||||||
class InvoiceList(MyTreeWidget):
|
class InvoiceList(MyTreeWidget):
|
||||||
|
@ -57,15 +57,10 @@ class InvoiceList(MyTreeWidget):
|
||||||
self.parent.invoices_label.setVisible(len(inv_list))
|
self.parent.invoices_label.setVisible(len(inv_list))
|
||||||
|
|
||||||
def import_invoices(self):
|
def import_invoices(self):
|
||||||
wallet_folder = self.parent.get_wallet_folder()
|
import_meta_gui(self.parent, _('invoices'), self.parent.invoices.import_file, self.on_update)
|
||||||
filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
|
|
||||||
if not filename:
|
def export_invoices(self):
|
||||||
return
|
export_meta_gui(self.parent, _('invoices'), self.parent.invoices.export_file)
|
||||||
try:
|
|
||||||
self.parent.invoices.import_file(filename)
|
|
||||||
except FileImportFailed as e:
|
|
||||||
self.parent.show_message(str(e))
|
|
||||||
self.on_update()
|
|
||||||
|
|
||||||
def create_menu(self, position):
|
def create_menu(self, position):
|
||||||
menu = QMenu()
|
menu = QMenu()
|
||||||
|
|
|
@ -61,7 +61,7 @@ from .fee_slider import FeeSlider
|
||||||
|
|
||||||
from .util import *
|
from .util import *
|
||||||
|
|
||||||
from electrum.util import profiler
|
from electrum.util import profiler, export_meta, import_meta
|
||||||
|
|
||||||
class StatusBarButton(QPushButton):
|
class StatusBarButton(QPushButton):
|
||||||
def __init__(self, icon, tooltip, func):
|
def __init__(self, icon, tooltip, func):
|
||||||
|
@ -484,8 +484,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
contacts_menu = wallet_menu.addMenu(_("Contacts"))
|
contacts_menu = wallet_menu.addMenu(_("Contacts"))
|
||||||
contacts_menu.addAction(_("&New"), self.new_contact_dialog)
|
contacts_menu.addAction(_("&New"), self.new_contact_dialog)
|
||||||
contacts_menu.addAction(_("Import"), lambda: self.contact_list.import_contacts())
|
contacts_menu.addAction(_("Import"), lambda: self.contact_list.import_contacts())
|
||||||
|
contacts_menu.addAction(_("Export"), lambda: self.contact_list.export_contacts())
|
||||||
invoices_menu = wallet_menu.addMenu(_("Invoices"))
|
invoices_menu = wallet_menu.addMenu(_("Invoices"))
|
||||||
invoices_menu.addAction(_("Import"), lambda: self.invoice_list.import_invoices())
|
invoices_menu.addAction(_("Import"), lambda: self.invoice_list.import_invoices())
|
||||||
|
invoices_menu.addAction(_("Export"), lambda: self.invoice_list.export_invoices())
|
||||||
|
|
||||||
wallet_menu.addSeparator()
|
wallet_menu.addSeparator()
|
||||||
wallet_menu.addAction(_("Find"), self.toggle_search).setShortcut(QKeySequence("Ctrl+F"))
|
wallet_menu.addAction(_("Find"), self.toggle_search).setShortcut(QKeySequence("Ctrl+F"))
|
||||||
|
@ -2417,29 +2419,23 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||||
f.write(json.dumps(pklist, indent = 4))
|
f.write(json.dumps(pklist, indent = 4))
|
||||||
|
|
||||||
def do_import_labels(self):
|
def do_import_labels(self):
|
||||||
labelsFile = self.getOpenFileName(_("Open labels file"), "*.json")
|
def import_labels(path):
|
||||||
if not labelsFile: return
|
#TODO: Import labels validation
|
||||||
try:
|
def import_labels_validate(data):
|
||||||
with open(labelsFile, 'r') as f:
|
return data
|
||||||
data = f.read()
|
def import_labels_assign(data):
|
||||||
for key, value in json.loads(data).items():
|
for key, value in data.items():
|
||||||
self.wallet.set_label(key, value)
|
self.wallet.set_label(key, value)
|
||||||
self.show_message(_("Your labels were imported from") + " '%s'" % str(labelsFile))
|
import_meta(path, import_labels_validate, import_labels_assign)
|
||||||
except (IOError, os.error) as reason:
|
def on_import():
|
||||||
self.show_critical(_("Electrum was unable to import your labels.") + "\n" + str(reason))
|
|
||||||
self.address_list.update()
|
self.address_list.update()
|
||||||
self.history_list.update()
|
self.history_list.update()
|
||||||
|
import_meta_gui(self, _('labels'), import_labels, on_import)
|
||||||
|
|
||||||
def do_export_labels(self):
|
def do_export_labels(self):
|
||||||
labels = self.wallet.labels
|
def export_labels(filename):
|
||||||
try:
|
export_meta(self.wallet.labels, filename)
|
||||||
fileName = self.getSaveFileName(_("Select file to save your labels"), 'electrum_labels.json', "*.json")
|
export_meta_gui(self, _('labels'), export_labels)
|
||||||
if fileName:
|
|
||||||
with open(fileName, 'w+') as f:
|
|
||||||
json.dump(labels, f, indent=4, sort_keys=True)
|
|
||||||
self.show_message(_("Your labels were exported to") + " '%s'" % str(fileName))
|
|
||||||
except (IOError, os.error) as reason:
|
|
||||||
self.show_critical(_("Electrum was unable to export your labels.") + "\n" + str(reason))
|
|
||||||
|
|
||||||
def sweep_key_dialog(self):
|
def sweep_key_dialog(self):
|
||||||
d = WindowModalDialog(self, title=_('Sweep private keys'))
|
d = WindowModalDialog(self, title=_('Sweep private keys'))
|
||||||
|
|
|
@ -11,6 +11,7 @@ from PyQt5.QtGui import *
|
||||||
from PyQt5.QtCore import *
|
from PyQt5.QtCore import *
|
||||||
from PyQt5.QtWidgets import *
|
from PyQt5.QtWidgets import *
|
||||||
|
|
||||||
|
from electrum.util import FileImportFailed, FileExportFailed
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
MONOSPACE_FONT = 'Lucida Console'
|
MONOSPACE_FONT = 'Lucida Console'
|
||||||
elif platform.system() == 'Darwin':
|
elif platform.system() == 'Darwin':
|
||||||
|
@ -674,6 +675,28 @@ class AcceptFileDragDrop:
|
||||||
def onFileAdded(self, fn):
|
def onFileAdded(self, fn):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def import_meta_gui(electrum_window, title, importer, on_success):
|
||||||
|
filename = electrum_window.getOpenFileName(_("Open {} file").format(title) , "*.json")
|
||||||
|
if not filename:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
importer(filename)
|
||||||
|
except FileImportFailed as e:
|
||||||
|
electrum_window.show_critical(str(e))
|
||||||
|
else:
|
||||||
|
electrum_window.show_message(_("Your {} were successfully imported" ).format(title))
|
||||||
|
on_success()
|
||||||
|
|
||||||
|
def export_meta_gui(electrum_window, title, exporter):
|
||||||
|
filename = electrum_window.getSaveFileName(_("Select file to save your {}").format(title), 'electrum_{}.json'.format(title), "*.json")
|
||||||
|
if not filename:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
exporter(filename)
|
||||||
|
except FileExportFailed as e:
|
||||||
|
electrum_window.show_critical(str(e))
|
||||||
|
else:
|
||||||
|
electrum_window.show_message(_("Your {0} were exported to '{1}'").format(title,str(filename)))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
|
|
|
@ -25,10 +25,11 @@ import dns
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
from . import bitcoin
|
from . import bitcoin
|
||||||
from . import dnssec
|
from . import dnssec
|
||||||
from .util import FileImportFailed, FileImportFailedEncrypted
|
from .util import export_meta, import_meta
|
||||||
|
|
||||||
|
|
||||||
class Contacts(dict):
|
class Contacts(dict):
|
||||||
|
@ -51,18 +52,15 @@ class Contacts(dict):
|
||||||
self.storage.put('contacts', dict(self))
|
self.storage.put('contacts', dict(self))
|
||||||
|
|
||||||
def import_file(self, path):
|
def import_file(self, path):
|
||||||
try:
|
import_meta(path, self.validate, self.load_meta)
|
||||||
with open(path, 'r') as f:
|
|
||||||
d = self._validate(json.loads(f.read()))
|
def load_meta(self, data):
|
||||||
except json.decoder.JSONDecodeError:
|
self.update(data)
|
||||||
traceback.print_exc(file=sys.stderr)
|
|
||||||
raise FileImportFailedEncrypted()
|
|
||||||
except BaseException:
|
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
raise FileImportFailed()
|
|
||||||
self.update(d)
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def export_file(self, fileName):
|
||||||
|
export_meta(self, fileName)
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
dict.__setitem__(self, key, value)
|
dict.__setitem__(self, key, value)
|
||||||
self.save()
|
self.save()
|
||||||
|
@ -119,7 +117,7 @@ class Contacts(dict):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _validate(self, data):
|
def validate(self, data):
|
||||||
for k,v in list(data.items()):
|
for k,v in list(data.items()):
|
||||||
if k == 'contacts':
|
if k == 'contacts':
|
||||||
return self._validate(v)
|
return self._validate(v)
|
||||||
|
|
|
@ -40,7 +40,7 @@ except ImportError:
|
||||||
from . import bitcoin
|
from . import bitcoin
|
||||||
from . import util
|
from . import util
|
||||||
from .util import print_error, bh2u, bfh
|
from .util import print_error, bh2u, bfh
|
||||||
from .util import FileImportFailed, FileImportFailedEncrypted
|
from .util import export_meta, import_meta
|
||||||
from . import transaction
|
from . import transaction
|
||||||
from . import x509
|
from . import x509
|
||||||
from . import rsakey
|
from . import rsakey
|
||||||
|
@ -468,19 +468,20 @@ class InvoiceStore(object):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def import_file(self, path):
|
def import_file(self, path):
|
||||||
try:
|
import_meta(path, self.validate, self.on_import)
|
||||||
with open(path, 'r') as f:
|
|
||||||
d = json.loads(f.read())
|
#TODO: Invoice import validation
|
||||||
self.load(d)
|
def validate(self, data):
|
||||||
except json.decoder.JSONDecodeError:
|
return data
|
||||||
traceback.print_exc(file=sys.stderr)
|
|
||||||
raise FileImportFailedEncrypted()
|
def on_import(self, data):
|
||||||
except BaseException:
|
self.load(data)
|
||||||
traceback.print_exc(file=sys.stdout)
|
|
||||||
raise FileImportFailed()
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def save(self):
|
def export_file(self, fileName):
|
||||||
|
export_meta(self.before_save(), fileName)
|
||||||
|
|
||||||
|
def before_save(self):
|
||||||
l= {}
|
l= {}
|
||||||
for k, pr in self.invoices.items():
|
for k, pr in self.invoices.items():
|
||||||
l[k] = {
|
l[k] = {
|
||||||
|
@ -488,7 +489,10 @@ class InvoiceStore(object):
|
||||||
'requestor': pr.requestor,
|
'requestor': pr.requestor,
|
||||||
'txid': pr.tx
|
'txid': pr.tx
|
||||||
}
|
}
|
||||||
self.storage.put('invoices', l)
|
return l
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
self.storage.put('invoices', self.before_save())
|
||||||
|
|
||||||
def get_status(self, key):
|
def get_status(self, key):
|
||||||
pr = self.get(key)
|
pr = self.get(key)
|
||||||
|
|
35
lib/util.py
35
lib/util.py
|
@ -60,16 +60,18 @@ class InvalidPassword(Exception):
|
||||||
|
|
||||||
|
|
||||||
class FileImportFailed(Exception):
|
class FileImportFailed(Exception):
|
||||||
|
def __init__(self, message=''):
|
||||||
|
self.message = str(message)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _("Failed to import file.")
|
return _("Failed to import from file.") + "\n" + self.message
|
||||||
|
|
||||||
|
class FileExportFailed(Exception):
|
||||||
|
def __init__(self, reason=''):
|
||||||
|
self.message = str(reason)
|
||||||
|
|
||||||
class FileImportFailedEncrypted(FileImportFailed):
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (_('Failed to import file.') + ' ' +
|
return( _("Failed to export to file.") + "\n" + self.message )
|
||||||
_('Perhaps it is encrypted...') + '\n' +
|
|
||||||
_('Importing encrypted files is not supported.'))
|
|
||||||
|
|
||||||
|
|
||||||
# Throw this exception to unwind the stack like when an error occurs.
|
# Throw this exception to unwind the stack like when an error occurs.
|
||||||
# However unlike other exceptions the user won't be informed.
|
# However unlike other exceptions the user won't be informed.
|
||||||
|
@ -785,3 +787,24 @@ def setup_thread_excepthook():
|
||||||
|
|
||||||
def versiontuple(v):
|
def versiontuple(v):
|
||||||
return tuple(map(int, (v.split("."))))
|
return tuple(map(int, (v.split("."))))
|
||||||
|
|
||||||
|
def import_meta(path, validater, load_meta):
|
||||||
|
try:
|
||||||
|
with open(path, 'r') as f:
|
||||||
|
d = validater(json.loads(f.read()))
|
||||||
|
load_meta(d)
|
||||||
|
#backwards compatibility for JSONDecodeError
|
||||||
|
except ValueError:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise FileImportFailed(_("Invalid JSON code."))
|
||||||
|
except BaseException as e:
|
||||||
|
traceback.print_exc(file=sys.stdout)
|
||||||
|
raise FileImportFailed(e)
|
||||||
|
|
||||||
|
def export_meta(meta, fileName):
|
||||||
|
try:
|
||||||
|
with open(fileName, 'w+') as f:
|
||||||
|
json.dump(meta, f, indent=4, sort_keys=True)
|
||||||
|
except (IOError, os.error) as reason:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise FileExportFailed(str(reason))
|
||||||
|
|
Loading…
Add table
Reference in a new issue