diff --git a/gui/qt/contact_list.py b/gui/qt/contact_list.py index 81b6ca869..27c9efb59 100644 --- a/gui/qt/contact_list.py +++ b/gui/qt/contact_list.py @@ -23,7 +23,6 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import webbrowser -import os from electrum.i18n import _ from electrum.bitcoin import is_address diff --git a/gui/qt/invoice_list.py b/gui/qt/invoice_list.py index d36c4866b..586dd71c5 100644 --- a/gui/qt/invoice_list.py +++ b/gui/qt/invoice_list.py @@ -23,10 +23,11 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -from .util import * from electrum.i18n import _ from electrum.util import format_time +from .util import * + class InvoiceList(MyTreeWidget): filter_columns = [0, 1, 2, 3] # Date, Requestor, Description, Amount diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py index 89c0ce1d7..8ab63b871 100644 --- a/gui/qt/main_window.py +++ b/gui/qt/main_window.py @@ -39,15 +39,14 @@ import PyQt5.QtCore as QtCore from .exception_window import Exception_Hook from PyQt5.QtWidgets import * -from electrum.util import bh2u, bfh - from electrum import keystore, simple_config from electrum.bitcoin import COIN, is_address, TYPE_ADDRESS, NetworkConstants from electrum.plugins import run_hook from electrum.i18n import _ from electrum.util import (format_time, format_satoshis, PrintError, format_satoshis_plain, NotEnoughFunds, - UserCancelled, NoDynamicFeeEstimates) + UserCancelled, NoDynamicFeeEstimates, profiler, + export_meta, import_meta, bh2u, bfh) from electrum import Transaction from electrum import util, bitcoin, commands, coinchooser from electrum import paymentrequest @@ -58,10 +57,8 @@ from .qrcodewidget import QRCodeWidget, QRDialog from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit from .transaction_dialog import show_transaction from .fee_slider import FeeSlider - from .util import * -from electrum.util import profiler, export_meta, import_meta class StatusBarButton(QPushButton): def __init__(self, icon, tooltip, func): @@ -2420,16 +2417,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError): def do_import_labels(self): def import_labels(path): - #TODO: Import labels validation - def import_labels_validate(data): - return data + def _validate(data): + return data # TODO + def import_labels_assign(data): for key, value in data.items(): self.wallet.set_label(key, value) - import_meta(path, import_labels_validate, import_labels_assign) + import_meta(path, _validate, import_labels_assign) + def on_import(): - self.address_list.update() - self.history_list.update() + self.need_update.set() import_meta_gui(self, _('labels'), import_labels, on_import) def do_export_labels(self): diff --git a/gui/qt/util.py b/gui/qt/util.py index 60a594bb0..916762162 100644 --- a/gui/qt/util.py +++ b/gui/qt/util.py @@ -6,12 +6,15 @@ import queue from collections import namedtuple from functools import partial -from electrum.i18n import _ from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * +from electrum.i18n import _ from electrum.util import FileImportFailed, FileExportFailed +from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED + + if platform.system() == 'Windows': MONOSPACE_FONT = 'Lucida Console' elif platform.system() == 'Darwin': @@ -22,8 +25,6 @@ else: dialogs = [] -from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_EXPIRED - pr_icons = { PR_UNPAID:":icons/unpaid.png", PR_PAID:":icons/confirmed.png", @@ -675,28 +676,35 @@ class AcceptFileDragDrop: def onFileAdded(self, fn): raise NotImplementedError() + def import_meta_gui(electrum_window, title, importer, on_success): - filename = electrum_window.getOpenFileName(_("Open {} file").format(title) , "*.json") + filter_ = "JSON (*.json);;All files (*)" + filename = electrum_window.getOpenFileName(_("Open {} file").format(title), filter_) if not filename: - return + return try: - importer(filename) + importer(filename) except FileImportFailed as e: - electrum_window.show_critical(str(e)) + electrum_window.show_critical(str(e)) else: - electrum_window.show_message(_("Your {} were successfully imported" ).format(title)) - on_success() + 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: + filter_ = "JSON (*.json);;All files (*)" + filename = electrum_window.getSaveFileName(_("Select file to save your {}").format(title), + 'electrum_{}.json'.format(title), filter_) + 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))) + electrum_window.show_message(_("Your {0} were exported to '{1}'") + .format(title, str(filename))) + if __name__ == "__main__": app = QApplication([]) diff --git a/lib/contacts.py b/lib/contacts.py index df10e0863..0015a8610 100644 --- a/lib/contacts.py +++ b/lib/contacts.py @@ -25,7 +25,6 @@ import dns import json import traceback import sys -import os from . import bitcoin from . import dnssec @@ -52,14 +51,14 @@ class Contacts(dict): self.storage.put('contacts', dict(self)) def import_file(self, path): - import_meta(path, self.validate, self.load_meta) + import_meta(path, self._validate, self.load_meta) def load_meta(self, data): self.update(data) self.save() - def export_file(self, fileName): - export_meta(self, fileName) + def export_file(self, filename): + export_meta(self, filename) def __setitem__(self, key, value): dict.__setitem__(self, key, value) @@ -117,14 +116,14 @@ class Contacts(dict): except AttributeError: return None - def validate(self, data): - for k,v in list(data.items()): + def _validate(self, data): + for k, v in list(data.items()): if k == 'contacts': return self._validate(v) if not bitcoin.is_address(k): data.pop(k) else: - _type,_ = v + _type, _ = v if _type != 'address': data.pop(k) return data diff --git a/lib/paymentrequest.py b/lib/paymentrequest.py index 878c541e7..471186705 100644 --- a/lib/paymentrequest.py +++ b/lib/paymentrequest.py @@ -468,31 +468,29 @@ class InvoiceStore(object): continue def import_file(self, path): - import_meta(path, self.validate, self.on_import) - - #TODO: Invoice import validation - def validate(self, data): - return data + def validate(data): + return data # TODO + import_meta(path, validate, self.on_import) def on_import(self, data): self.load(data) self.save() - def export_file(self, fileName): - export_meta(self.before_save(), fileName) + def export_file(self, filename): + export_meta(self.dump(), filename) - def before_save(self): - l= {} + def dump(self): + d = {} for k, pr in self.invoices.items(): - l[k] = { + d[k] = { 'hex': bh2u(pr.raw), 'requestor': pr.requestor, 'txid': pr.tx } - return l + return d def save(self): - self.storage.put('invoices', self.before_save()) + self.storage.put('invoices', self.dump()) def get_status(self, key): pr = self.get(key) diff --git a/lib/util.py b/lib/util.py index ee66ff3f3..7099141b3 100644 --- a/lib/util.py +++ b/lib/util.py @@ -66,12 +66,14 @@ class FileImportFailed(Exception): def __str__(self): return _("Failed to import from file.") + "\n" + self.message + class FileExportFailed(Exception): - def __init__(self, reason=''): - self.message = str(reason) + def __init__(self, message=''): + self.message = str(message) def __str__(self): - return( _("Failed to export to file.") + "\n" + self.message ) + return _("Failed to export to file.") + "\n" + self.message + # Throw this exception to unwind the stack like when an error occurs. # However unlike other exceptions the user won't be informed. @@ -788,6 +790,7 @@ def setup_thread_excepthook(): def versiontuple(v): return tuple(map(int, (v.split(".")))) + def import_meta(path, validater, load_meta): try: with open(path, 'r') as f: @@ -798,13 +801,14 @@ def import_meta(path, validater, load_meta): traceback.print_exc(file=sys.stderr) raise FileImportFailed(_("Invalid JSON code.")) except BaseException as e: - traceback.print_exc(file=sys.stdout) - raise FileImportFailed(e) + traceback.print_exc(file=sys.stdout) + raise FileImportFailed(e) + def export_meta(meta, fileName): - try: - with open(fileName, 'w+') as f: + 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)) + except (IOError, os.error) as e: + traceback.print_exc(file=sys.stderr) + raise FileExportFailed(e)