URI: 
       tproper handling of arg_types. add more options for listaddresses - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 92a158b910b54a4e411eda1272ccc09d15553772
   DIR parent bf98b547e127d851005a45c716537b493ee05c93
  HTML Author: ThomasV <thomasv@gitorious>
       Date:   Sat, 30 May 2015 18:49:58 +0200
       
       proper handling of arg_types. add more options for listaddresses
       
       Diffstat:
         M electrum                            |      32 ++-----------------------------
         M lib/commands.py                     |      92 ++++++++++++++++++++-----------
         M lib/wallet.py                       |      11 +++++++++--
       
       3 files changed, 72 insertions(+), 63 deletions(-)
       ---
   DIR diff --git a/electrum b/electrum
       t@@ -181,6 +181,8 @@ def run_cmdline(config):
        
            # arguments passed to function
            args = map(lambda x: config.get(x), map(lambda x: x[0], cmd.params))
       +    # options
       +    args += map(lambda x: config.get(x), cmd.options)
        
            # instanciate wallet for command-line
            storage = WalletStorage(config.get_wallet_path())
       t@@ -297,36 +299,6 @@ def run_cmdline(config):
                # See if they specificed a key on the cmd line, if not prompt
                args.append(prompt_password('Enter PrivateKey (will not echo):', False))
        
       -    elif cmd.name == 'createmultisig':
       -        args = [int(args[0]), json.loads(args[1])]
       -
       -    elif cmd.name == 'createrawtransaction':
       -        args = [json.loads(args[0]), json.loads(args[2])]
       -
       -    elif cmd.name == 'listaddresses':
       -        args = [config.get('show_all'), config.get('show_labels')]
       -
       -    elif cmd.name == 'make_seed':
       -        args = [int(config.get('nbits')), long(config.get('entropy')), config.get('language')]
       -
       -    elif cmd.name in ['payto', 'mktx']:
       -        domain = [config.get('from_addr')] if config.get('from_addr') else None
       -        args = [args[0], Decimal(args[1]), Decimal(config.get('tx_fee')) if config.get('tx_fee') else None, config.get('change_addr'), domain]
       -
       -    elif cmd.name in ['paytomany', 'mksendmanytx']:
       -        domain = [config.get('from_addr')] if config.get('from_addr') else None
       -        args = [args[0], Decimal(config.get('tx_fee')) if config.get('tx_fee') else None, config.get('change_addr'), domain]
       -
       -    elif cmd.name == 'help':
       -        if len(args) < 1:
       -            print_help(parser)
       -            sys.exit(1)
       -
       -    if cmd.name == 'check_seed':
       -        args.append(long(config.get('entropy')))
       -        args.append(config.get('language'))
       -
       -
            # run the command
            if cmd.name == 'deseed':
                if not wallet.seed:
   DIR diff --git a/lib/commands.py b/lib/commands.py
       t@@ -21,6 +21,7 @@ import datetime
        import time
        import copy
        import argparse
       +import json
        
        from util import print_msg, format_satoshis, print_stderr
        from util import StoreDict
       t@@ -57,8 +58,8 @@ def register_command(*args):
        #                                                    options
        register_command('listcontacts',       0, 0, 0, [], [], 'Show your list of contacts', '')
        register_command('create',             0, 1, 0, [], [], 'Create a new wallet', '')
       -register_command('createmultisig',     0, 1, 0, [('num','number'), ('pubkeys', 'Public keys (json)')], [], 'Create multisig address', '')
       -register_command('createrawtx',        0, 1, 0, [('inputs', ''), ('outputs', '')], [], 'Create an unsigned transaction.', 'The syntax is similar to bitcoind.')
       +register_command('createmultisig',     0, 1, 0, [('num', 'number'), ('pubkeys', 'Public keys (json)')], [], 'Create multisig address', '')
       +register_command('createrawtx',        0, 1, 0, [('inputs', 'json'), ('outputs', 'json')], [], 'Create an unsigned transaction.', 'The syntax is similar to bitcoind.')
        register_command('deseed',             0, 1, 0, [], [], 'Remove seed from wallet.', 'This creates a seedless, watching-only wallet.')
        register_command('decoderawtx',        0, 0, 0, [('tx', 'Serialized transaction')], [], 'Decode raw transaction.', '')
        register_command('getprivatekeys',     0, 1, 1, [('address', 'Bitcoin address')], [], 'Get the private keys of a wallet address.', '')
       t@@ -77,7 +78,8 @@ register_command('help',               0, 0, 0, [], [], 'Print help on a command
        register_command('history',            1, 1, 0, [], [], 'Wallet history', 'Returns the transaction history of your wallet')
        register_command('importprivkey',      0, 1, 1, [('privkey', 'Private key')], [], 'Import a private key', '')
        register_command('ismine',             0, 1, 0, [('address', 'Bitcoin address')], [], 'Check if address is in wallet', 'Return true if and only if address is in wallet')
       -register_command('listaddresses',      0, 1, 0, [], ['show_all', 'show_labels'], 'List wallet addresses', 'Returns your list of addresses.')
       +register_command('listaddresses',      0, 1, 0, [], ['show_all', 'show_labels', 'frozen', 'unused', 'funded', 'show_balance'],
       +                 'List wallet addresses', 'Returns your list of addresses.')
        register_command('listunspent',        1, 1, 0, [], [], 'List unspent outputs', 'Returns the list of unspent transaction outputs in your wallet.')
        register_command('getaddressunspent',  1, 0, 0, [('address', 'Bitcoin address')], [], 'Returns the list of unspent inputs for an address.', '')
        register_command('mktx',               0, 1, 1, [('recipient', 'Bitcoin address'), ('amount', 'Amount in BTC')],
       t@@ -106,7 +108,8 @@ register_command('decrypt',            0, 1, 1, [('pubkey', 'public key'), ('mes
        register_command('getmerkle',          1, 0, 0, [('txid', 'Transaction ID'), ('height', 'Block height')], [], 'Get Merkle branch of a transaction included in a block', '')
        register_command('getproof',           1, 0, 0, [('address', '')], [], 'Get Merkle branch of an address in the UTXO set', '')
        register_command('getutxoaddress',     1, 0, 0, [('txid', 'Transction ID'), ('pos', 'Position')], [], 'Get the address of an unspent transaction output', '')
       -register_command('sweep',              1, 0, 0, [('privkey', 'Private key'), ('address', 'Destination address')], ['tx_fee'], 'Sweep a private key.', '')
       +register_command('sweep',              1, 0, 0, [('privkey', 'Private key'), ('address', 'Destination address')], ['tx_fee'],
       +                 'Sweep private key.', 'Returns a transaction that sends all UTXOs to the destination address. The transactoin is not broadcasted.')
        register_command('make_seed',          0, 0, 0, [], ['nbits', 'entropy', 'language'], 'Create a seed.', '')
        register_command('check_seed',         0, 0, 0, [('seed', 'Seed phrase')], ['entropy', 'language'], 'Check that a seed was generated with external entropy.', '')
        
       t@@ -115,19 +118,33 @@ register_command('check_seed',         0, 0, 0, [('seed', 'Seed phrase')], ['ent
        command_options = {
            'password':    ("-W", "--password",   None,  "Password"),
            'concealed':   ("-C", "--concealed",  False, "Don't echo seed to console when restoring"),
       -    'show_all':    ("-a", "--all",        False, "Show all addresses"),
       +    'show_all':    ("-a", "--all",        False, "Include change addresses"),
       +    'frozen':      (None, "--frozen",     False, "Show only frozen addresses"),
       +    'unused':      (None, "--unused",     False, "Show only unused addresses"),
       +    'funded':      (None, "--funded",     False, "Show only funded addresses"),
       +    'show_balance':("-b", "--balance",    False, "Show the balances of listed addresses"),
            'show_labels': ("-l", "--labels",     False, "Show the labels of listed addresses"),
            'tx_fee':      ("-f", "--fee",        None,  "Transaction fee"),
            'from_addr':   ("-F", "--fromaddr",   None,  "Source address. 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."),
            'change_addr': ("-c", "--changeaddr", None,  "Change address. Default is a spare address, or the source address if it's not in the wallet"),
       -    'nbits':       (None, "--nbits",     "128",  "Number of bits of entropy"),
       -    'entropy':     (None, "--entropy",   "1",    "Custom entropy"),
       +    'nbits':       (None, "--nbits",      128,  "Number of bits of entropy"),
       +    'entropy':     (None, "--entropy",    1,    "Custom entropy"),
            'language':    ("-L", "--lang",       None,  "Default language for wordlist"),
            'gap_limit':   ("-G", "--gap",        None,  "Gap limit"),
            'mpk':         (None, "--mpk",        None,  "Restore from master public key"),
        }
        
        
       +arg_types = {
       +    'num':int,
       +    'nbits':int,
       +    'entropy':long,
       +    'pubkeys':json.loads,
       +    'inputs': json.loads,
       +    'outputs':json.loads,
       +    'tx_fee':lambda x: (Decimal(x) if x is not None else None)
       +}
       +
        
        def set_default_subparser(self, name, args=None):
            """see http://stackoverflow.com/questions/5176691/argparse-how-to-specify-a-default-subcommand"""
       t@@ -197,9 +214,15 @@ def get_parser(run_gui, run_daemon, run_cmdline):
                    a, b, default, help = command_options[optname]
                    action = "store_true" if type(default) is bool else 'store'
                    args = (a, b) if a else (b,)
       -            p.add_argument(*args, dest=optname, action=action, default=default, help=help)
       +            if action == 'store':
       +                _type = arg_types.get(optname, str)
       +                p.add_argument(*args, dest=optname, action=action, default=default, help=help, type=_type)
       +            else:
       +                p.add_argument(*args, dest=optname, action=action, default=default, help=help)
       +
                for param, h in cmd.params:
       -            p.add_argument(param, help=h)
       +            _type = arg_types.get(param, str)
       +            p.add_argument(param, help=h, type=_type)
            # 'gui' is the default command
            parser.set_default_subparser('gui')
            return parser
       t@@ -244,7 +267,7 @@ class Commands:
                return l
        
            def getaddressunspent(self, addr):
       -        return self.network.synchronous_get([ ('blockchain.address.listunspent',[addr]) ])[0]
       +        return self.network.synchronous_get([('blockchain.address.listunspent',[addr])])[0]
        
            def getutxoaddress(self, txid, num):
                r = self.network.synchronous_get([ ('blockchain.utxo.get_address',[txid, num]) ])
       t@@ -290,7 +313,7 @@ class Commands:
                return self.network.synchronous_get([('blockchain.transaction.broadcast', [str(tx)])])[0]
        
            def createmultisig(self, num, pubkeys):
       -        assert isinstance(pubkeys, list)
       +        assert isinstance(pubkeys, list), (type(num), type(pubkeys))
                redeem_script = Transaction.multisig_script(pubkeys, num)
                address = hash_160_to_bc_address(hash_160(redeem_script.decode('hex')), 5)
                return {'address':address, 'redeemScript':redeem_script}
       t@@ -421,10 +444,6 @@ class Commands:
                if fee is not None: fee = int(100000000*fee)
                return self.wallet.mktx(final_outputs, self.password, fee , change_addr, domain)
        
       -    def mktx(self, to_address, amount, fee = None, change_addr = None, domain = None):
       -        tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
       -        return tx
       -
            def _read_csv(self, csvpath):
                import csv
                outputs = []
       t@@ -437,17 +456,25 @@ class Commands:
                        outputs.append((address, amount))
                return outputs
        
       -    def mktx_csv(self, path, fee = None, change_addr = None, domain = None):
       +    def mktx(self, to_address, amount, fee = None, change_addr = None, from_addr = None):
       +        domain = [from_addr] if from_addr else None
       +        tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
       +        return tx
       +
       +    def mktx_csv(self, path, fee = None, change_addr = None, from_addr = None):
       +        domain = [from_addr] if from_addr else None
                outputs = self._read_csv(path)
                tx = self._mktx(outputs, fee, change_addr, domain)
                return tx
        
       -    def payto(self, to_address, amount, fee = None, change_addr = None, domain = None):
       +    def payto(self, to_address, amount, fee = None, change_addr = None, from_addr = None):
       +        domain = [from_addr] if from_addr else None
                tx = self._mktx([(to_address, amount)], fee, change_addr, domain)
                r, h = self.wallet.sendtx( tx )
                return h
        
       -    def payto_csv(self, path, fee = None, change_addr = None, domain = None):
       +    def payto_csv(self, path, fee = None, change_addr = None, from_addr = None):
       +        domain = [from_addr] if from_addr else None
                outputs = self._read_csv(path)
                tx = self._mktx(outputs, fee, change_addr, domain)
                r, h = self.wallet.sendtx( tx )
       t@@ -483,19 +510,23 @@ class Commands:
                        results[key] = value
                return results
        
       -    def listaddresses(self, show_all = False, show_label = False):
       +    def listaddresses(self, show_change=False, show_label=False, frozen=False, unused=False, funded=False, show_balance=False):
                out = []
                for addr in self.wallet.addresses(True):
       -            if show_all or not self.wallet.is_change(addr):
       -                if show_label:
       -                    item = { 'address': addr }
       -                    if show_label:
       -                        label = self.wallet.labels.get(addr,'')
       -                        if label:
       -                            item['label'] = label
       -                else:
       -                    item = addr
       -                out.append( item )
       +            if frozen and not self.wallet.is_frozen(addr):
       +                continue
       +            if not show_change and self.wallet.is_change(addr):
       +                continue
       +            if unused and self.wallet.is_used(addr):
       +                continue
       +            if funded and self.wallet.is_empty(addr):
       +                continue
       +            item = addr
       +            if show_balance:
       +                item += ", "+ format_satoshis(sum(self.wallet.get_addr_balance(addr)))
       +            if show_label:
       +                item += ', ' + self.wallet.labels.get(addr,'')
       +            out.append(item)
                return out
        
            def getrawtransaction(self, tx_hash):
       t@@ -503,8 +534,7 @@ class Commands:
                    tx = self.wallet.transactions.get(tx_hash)
                    if tx:
                        return tx
       -
       -        raw = self.network.synchronous_get([ ('blockchain.transaction.get',[tx_hash]) ])[0]
       +        raw = self.network.synchronous_get([('blockchain.transaction.get',[tx_hash])])[0]
                if raw:
                    return Transaction(raw)
                else:
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -1013,8 +1013,11 @@ class Abstract_Wallet(object):
                self.use_encryption = (new_password != None)
                self.storage.put('use_encryption', self.use_encryption,True)
        
       +    def is_frozen(self, addr):
       +        return addr in self.frozen_addresses
       +
            def freeze(self,addr):
       -        if self.is_mine(addr) and addr not in self.frozen_addresses:
       +        if self.is_mine(addr) and self.is_frozen(addr):
                    self.frozen_addresses.append(addr)
                    self.storage.put('frozen_addresses', self.frozen_addresses, True)
                    return True
       t@@ -1022,7 +1025,7 @@ class Abstract_Wallet(object):
                    return False
        
            def unfreeze(self,addr):
       -        if self.is_mine(addr) and addr in self.frozen_addresses:
       +        if self.is_mine(addr) and self.is_frozen(addr):
                    self.frozen_addresses.remove(addr)
                    self.storage.put('frozen_addresses', self.frozen_addresses, True)
                    return True
       t@@ -1148,6 +1151,10 @@ class Abstract_Wallet(object):
                c, u, x = self.get_addr_balance(address)
                return len(h), len(h) > 0 and c == -u
        
       +    def is_empty(self, address):
       +        c, u, x = self.get_addr_balance(address)
       +        return c+u+x == 0
       +
            def address_is_old(self, address, age_limit=2):
                age = -1
                h = self.history.get(address, [])