URI: 
       tFormat the transaction window fee rate with 1 decimal place (#4286) - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 53320470f590edcea6d3783b530ece173e0d03ff
   DIR parent a161b6e6556dab35e01ab2607f8a9332d7db2c75
  HTML Author: Ben Woosley <Ben.Woosley@gmail.com>
       Date:   Tue, 24 Apr 2018 12:54:14 -0400
       
       Format the transaction window fee rate with 1 decimal place (#4286)
       
       * Fix format_satoshi to properly handle non-integer values
       
       Handling the integer and fraction parts together via string formatting
       simplifies the initial composition because the default behavior manages
       tthe - sign, and the incorporation of the fractional part.
       
       * Limit fee rate output to one decimal place
       
       Via a new precision arg
       
       * Introduce format_fee_satoshis and use it for all fee display
       
       Diffstat:
         M gui/kivy/main_window.py             |       2 +-
         M gui/qt/main_window.py               |      10 ++++------
         M lib/simple_config.py                |       8 ++++++--
         M lib/tests/test_util.py              |      38 ++++++++++++++++++++++++++++++-
         M lib/util.py                         |      21 +++++++++++----------
         M lib/wallet.py                       |       7 +++----
       
       6 files changed, 62 insertions(+), 24 deletions(-)
       ---
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -671,7 +671,7 @@ class ElectrumWindow(App):
                return format_satoshis_plain(amount, self.decimal_point())
        
            def format_amount(self, x, is_diff=False, whitespaces=False):
       -        return format_satoshis(x, is_diff, 0, self.decimal_point(), whitespaces)
       +        return format_satoshis(x, 0, self.decimal_point(), is_diff=is_diff, whitespaces=whitespaces)
        
            def format_amount_and_units(self, x):
                return format_satoshis_plain(x, self.decimal_point()) + ' ' + self.base_unit
   DIR diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -44,8 +44,8 @@ from electrum.bitcoin import COIN, is_address, TYPE_ADDRESS
        from electrum import constants
        from electrum.plugins import run_hook
        from electrum.i18n import _
       -from electrum.util import (format_time, format_satoshis, PrintError,
       -                           format_satoshis_plain, NotEnoughFunds,
       +from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
       +                           format_satoshis_plain, NotEnoughFunds, PrintError,
                                   UserCancelled, NoDynamicFeeEstimates, profiler,
                                   export_meta, import_meta, bh2u, bfh, InvalidPassword)
        from electrum import Transaction
       t@@ -639,7 +639,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    self.require_fee_update = False
        
            def format_amount(self, x, is_diff=False, whitespaces=False):
       -        return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
       +        return format_satoshis(x, self.num_zeros, self.decimal_point, is_diff=is_diff, whitespaces=whitespaces)
        
            def format_amount_and_units(self, amount):
                text = self.format_amount(amount) + ' '+ self.base_unit()
       t@@ -649,7 +649,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                return text
        
            def format_fee_rate(self, fee_rate):
       -        return format_satoshis(fee_rate/1000, False, self.num_zeros, 0, False)  + ' sat/byte'
       +        return format_fee_satoshis(fee_rate/1000, self.num_zeros) + ' sat/byte'
        
            def get_decimal_point(self):
                return self.decimal_point
       t@@ -3192,5 +3192,3 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    self.need_update.set()
                    self.msg_box(QPixmap(":icons/offline_tx.png"), None, _('Success'), _("Transaction added to wallet history"))
                    return True
       -
       -
   DIR diff --git a/lib/simple_config.py b/lib/simple_config.py
       t@@ -7,7 +7,7 @@ import stat
        from copy import deepcopy
        
        from .util import (user_dir, print_error, PrintError,
       -                   NoDynamicFeeEstimates, format_satoshis)
       +                   NoDynamicFeeEstimates, format_fee_satoshis)
        from .i18n import _
        
        FEE_ETA_TARGETS = [25, 10, 5, 2]
       t@@ -367,7 +367,11 @@ class SimpleConfig(PrintError):
                text is what we target: static fee / num blocks to confirm in / mempool depth
                tooltip is the corresponding estimate (e.g. num blocks for a static fee)
                """
       -        rate_str = (format_satoshis(fee_rate/1000, False, 0, 0, False)  + ' sat/byte') if fee_rate is not None else 'unknown'
       +        if fee_rate is None:
       +            rate_str = 'unknown'
       +        else:
       +            rate_str = format_fee_satoshis(fee_rate/1000) + ' sat/byte'
       +
                if dyn:
                    if mempool:
                        depth = self.depth_target(pos)
   DIR diff --git a/lib/tests/test_util.py b/lib/tests/test_util.py
       t@@ -8,6 +8,43 @@ class TestUtil(unittest.TestCase):
                expected = "0.00001234"
                self.assertEqual(expected, result)
        
       +    def test_format_satoshis_negative(self):
       +        result = format_satoshis(-1234)
       +        expected = "-0.00001234"
       +        self.assertEqual(expected, result)
       +
       +    def test_format_fee(self):
       +        result = format_satoshis(1700/1000, 0, 0)
       +        expected = "1.7"
       +        self.assertEqual(expected, result)
       +
       +    def test_format_fee_precision(self):
       +        result = format_satoshis(1666/1000, 0, 0, precision=6)
       +        expected = "1.666"
       +        self.assertEqual(expected, result)
       +
       +        result = format_satoshis(1666/1000, 0, 0, precision=1)
       +        expected = "1.7"
       +        self.assertEqual(expected, result)
       +
       +    def test_format_satoshis_whitespaces(self):
       +        result = format_satoshis(12340, whitespaces=True)
       +        expected = "     0.0001234 "
       +        self.assertEqual(expected, result)
       +
       +        result = format_satoshis(1234, whitespaces=True)
       +        expected = "     0.00001234"
       +        self.assertEqual(expected, result)
       +
       +    def test_format_satoshis_whitespaces_negative(self):
       +        result = format_satoshis(-12340, whitespaces=True)
       +        expected = "    -0.0001234 "
       +        self.assertEqual(expected, result)
       +
       +        result = format_satoshis(-1234, whitespaces=True)
       +        expected = "    -0.00001234"
       +        self.assertEqual(expected, result)
       +
            def test_format_satoshis_diff_positive(self):
                result = format_satoshis(1234, is_diff=True)
                expected = "+0.00001234"
       t@@ -67,4 +104,3 @@ class TestUtil(unittest.TestCase):
        
            def test_parse_URI_parameter_polution(self):
                self.assertRaises(Exception, parse_URI, 'bitcoin:15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma?amount=0.0003&label=test&amount=30.0')
       -
   DIR diff --git a/lib/util.py b/lib/util.py
       t@@ -412,20 +412,18 @@ def format_satoshis_plain(x, decimal_point = 8):
            return "{:.8f}".format(Decimal(x) / scale_factor).rstrip('0').rstrip('.')
        
        
       -def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespaces=False):
       +def format_satoshis(x, num_zeros=0, decimal_point=8, precision=None, is_diff=False, whitespaces=False):
            from locale import localeconv
            if x is None:
                return 'unknown'
       -    x = int(x)  # Some callers pass Decimal
       -    scale_factor = pow (10, decimal_point)
       -    integer_part = "{:d}".format(int(abs(x) / scale_factor))
       -    if x < 0:
       -        integer_part = '-' + integer_part
       -    elif is_diff:
       -        integer_part = '+' + integer_part
       +    if precision is None:
       +        precision = decimal_point
       +    decimal_format = ".0" + str(precision) if precision > 0 else ""
       +    if is_diff:
       +        decimal_format = '+' + decimal_format
       +    result = ("{:" + decimal_format + "f}").format(x / pow (10, decimal_point)).rstrip('0')
       +    integer_part, fract_part = result.split(".")
            dp = localeconv()['decimal_point']
       -    fract_part = ("{:0" + str(decimal_point) + "}").format(abs(x) % scale_factor)
       -    fract_part = fract_part.rstrip('0')
            if len(fract_part) < num_zeros:
                fract_part += "0" * (num_zeros - len(fract_part))
            result = integer_part + dp + fract_part
       t@@ -434,6 +432,9 @@ def format_satoshis(x, is_diff=False, num_zeros = 0, decimal_point = 8, whitespa
                result = " " * (15 - len(result)) + result
            return result
        
       +def format_fee_satoshis(fee, num_zeros=0):
       +    return format_satoshis(fee, num_zeros, 0, precision=1)
       +
        def timestamp_to_datetime(timestamp):
            if timestamp is None:
                return None
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -45,8 +45,8 @@ import sys
        
        from .i18n import _
        from .util import (NotEnoughFunds, PrintError, UserCancelled, profiler,
       -                   format_satoshis, NoDynamicFeeEstimates, TimeoutException,
       -                   WalletFileException, BitcoinException)
       +                   format_satoshis, format_fee_satoshis, NoDynamicFeeEstimates,
       +                   TimeoutException, WalletFileException, BitcoinException)
        
        from .bitcoin import *
        from .version import *
       t@@ -1169,7 +1169,7 @@ class Abstract_Wallet(PrintError):
                    if fee is not None:
                        size = tx.estimated_size()
                        fee_per_byte = fee / size
       -                extra.append('%.1f sat/b'%(fee_per_byte))
       +                extra.append(format_fee_satoshis(fee_per_byte) + ' sat/b')
                    if fee is not None and height in (TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED) \
                       and self.network and self.network.config.has_fee_mempool():
                        exp_n = self.network.config.fee_to_depth(fee_per_byte)
       t@@ -2362,4 +2362,3 @@ class Wallet(object):
                if wallet_type in wallet_constructors:
                    return wallet_constructors[wallet_type]
                raise RuntimeError("Unknown wallet type: " + str(wallet_type))
       -