<commit_before>#!/usr/bin/env python

import argparse
import datetime
import json
import os
import psutil
import traceback
import logging

from prompt_toolkit import prompt
from prompt_toolkit.contrib.completers import WordCompleter
from prompt_toolkit.history import FileHistory
from prompt_toolkit.shortcuts import print_tokens
from prompt_toolkit.styles import style_from_dict
from prompt_toolkit.token import Token
from twisted.internet import reactor, task

from neo import __version__
from neo.Core.Blockchain import Blockchain
from neocore.Fixed8 import Fixed8
from neo.IO.MemoryStream import StreamManager
from neo.Implementations.Blockchains.LevelDB.LevelDBBlockchain import LevelDBBlockchain
from neo.Implementations.Blockchains.LevelDB.DebugStorage import DebugStorage
from neo.Implementations.Wallets.peewee.UserWallet import UserWallet
from neo.Implementations.Notifications.LevelDB.NotificationDB import NotificationDB
from neo.Network.NodeLeader import NodeLeader
from neo.Prompt.Commands.BuildNRun import BuildAndRun, LoadAndRun
from neo.Prompt.Commands.Invoke import InvokeContract, TestInvokeContract, test_invoke
from neo.Prompt.Commands.LoadSmartContract import LoadContract, GatherContractDetails, ImportContractAddr, \
    ImportMultiSigContractAddr
from neo.Prompt.Commands.Send import construct_and_send, parse_and_sign
from neo.contrib.nex.withdraw import RequestWithdrawFrom, PrintHolds, DeleteHolds, WithdrawOne, WithdrawAll, \
    CancelWithdrawalHolds, ShowCompletedHolds, CleanupCompletedHolds
from neo.Prompt.Commands.Tokens import token_approve_allowance, token_get_allowance, token_send, token_send_from, \
    token_mint, token_crowdsale_register
from neo.Prompt.Commands.Wallet import DeleteAddress, ImportWatchAddr, ImportToken, ClaimGas, DeleteToken, AddAlias, \
    ShowUnspentCoins
from neo.Prompt.Utils import get_arg
from neo.Prompt.InputParser import InputParser
from neo.Settings import settings, DIR_PROJECT_ROOT
from neo.UserPreferences import preferences
from neocore.KeyPair import KeyPair
from neocore.UInt256 import UInt256

# Logfile settings & setup
LOGFILE_FN = os.path.join(DIR_PROJECT_ROOT, 'prompt.log')
LOGFILE_MAX_BYTES = 5e7  # 50 MB
LOGFILE_BACKUP_COUNT = 3  # 3 logfiles history
settings.set_logfile(LOGFILE_FN, LOGFILE_MAX_BYTES, LOGFILE_BACKUP_COUNT)

# Prompt history filename
FILENAME_PROMPT_HISTORY = os.path.join(DIR_PROJECT_ROOT, '.prompt.py.history')


class PromptInterface(object):
    go_on = True

    _walletdb_loop = None

    Wallet = None

    _known_things = []

    commands = ['quit',
                'help',
                'block {index/hash} (tx)',
                'header {index/hash}',
                'tx {hash}',
                'asset {assetId}',
                'asset search {query}',
                'contract {contract hash}',
                'contract search {query}',
                'notifications {block_number or address}',
                'mem',
                'nodes',
                'state',
                'config debug {on/off}',
                'config sc-events {on/off}',
                'build {path/to/file.py} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'load_run {path/to/file.avm} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'import wif {wif}',
                'import nep2 {nep2_encrypted_key}',
                'import contract {path/to/file.avm} {params} {returntype} {needs_storage} {needs_dynamic_invoke}',
                'import contract_addr {contract_hash} {pubkey}',
                'import watch_addr {address}',
                'import token {token_contract_hash}',
                'export wif {address}',
                'export nep2 {address}',
                'open wallet {path}',
                'create wallet {path}',
                'wallet {verbose}',
                'wallet claim',
                'wallet migrate',
                'wallet rebuild {start block}',
                'wallet delete_addr {addr}',
                'wallet alias {addr} {title}',
                'wallet tkn_send {token symbol} {address_from} {address to} {amount} ',
                'wallet tkn_send_from {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_approve {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_allowance {token symbol} {address_from} {address to}',
                'wallet tkn_mint {token symbol} {mint_to_addr} (--attach-neo={amount}, --attach-gas={amount})',
                'wallet unspent',
                'wallet close',
                'withdraw_request {asset_name} {contract_hash} {to_addr} {amount}',
                'withdraw holds # lists all current holds',
                'withdraw completed # lists completed holds eligible for cleanup',
                'withdraw cancel # cancels current holds',
                'witdraw cleanup # cleans up completed holds',
                'withdraw # withdraws the first hold availabe',
                'withdraw all # withdraw all holds available',
                'send {assetId or name} {address} {amount} (--from-addr={addr})',
                'sign {transaction in JSON format}',
                'testinvoke {contract hash} {params} (--attach-neo={amount}, --attach-gas={amount})',
                'debugstorage {on/off/reset}'
                ]

    history = FileHistory(FILENAME_PROMPT_HISTORY)

    token_style = None
    start_height = None
    start_dt = None

    def __init__(self):
        self.input_parser = InputParser()
        self.start_height = Blockchain.Default().Height
        self.start_dt = datetime.datetime.utcnow()

        self.token_style = style_from_dict({
            Token.Command: preferences.token_style['Command'],
            Token.Neo: preferences.token_style['Neo'],
            Token.Default: preferences.token_style['Default'],
            Token.Number: preferences.token_style['Number'],
        })

    def get_bottom_toolbar(self, cli=None):
        out = []
        try:
            out = [(Token.Command, '[%s] Progress: ' % settings.net_name),
                   (Token.Number, str(Blockchain.Default().Height)),
                   (Token.Neo, '/'),
                   (Token.Number, str(Blockchain.Default().HeaderHeight))]
        except Exception as e:
            pass

        return out

    def get_completer(self):

        standard_completions = ['block', 'tx', 'header', 'mem', 'neo', 'gas',
                                'help', 'state', 'nodes', 'exit', 'quit',
                                'config', 'import', 'export', 'open',
                                'wallet', 'contract', 'asset', 'wif',
                                'watch_addr', 'contract_addr', 'testinvoke', 'tkn_send',
                                'tkn_mint', 'tkn_send_from', 'tkn_approve', 'tkn_allowance',
                                'build', 'notifications', ]

        if self.Wallet:
            for addr in self.Wallet.Addresses:
                if addr not in self._known_things:
                    self._known_things.append(addr)
            for alias in self.Wallet.NamedAddr:
                if alias.Title not in self._known_things:
                    self._known_things.append(alias.Title)
            for tkn in self.Wallet.GetTokens().values():
                if tkn.symbol not in self._known_things:
                    self._known_things.append(tkn.symbol)

        all_completions = standard_completions + self._known_things

        completer = WordCompleter(all_completions)

        return completer

    def quit(self):
        print('Shutting down. This may take a bit...')
        self.go_on = False
        NotificationDB.close()
        Blockchain.Default().Dispose()
        reactor.stop()
        NodeLeader.Instance().Shutdown()

    def help(self):
        tokens = []
        for c in self.commands:
            tokens.append((Token.Command, "%s\n" % c))
        print_tokens(tokens, self.token_style)

    def do_open(self, arguments):
        if self.Wallet:
            self.do_close_wallet()

        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)
<commit_msg>Gracefully close wallet on exit (#226)<commit_after>#!/usr/bin/env python

import argparse
import datetime
import json
import os
import psutil
import traceback
import logging

from prompt_toolkit import prompt
from prompt_toolkit.contrib.completers import WordCompleter
from prompt_toolkit.history import FileHistory
from prompt_toolkit.shortcuts import print_tokens
from prompt_toolkit.styles import style_from_dict
from prompt_toolkit.token import Token
from twisted.internet import reactor, task

from neo import __version__
from neo.Core.Blockchain import Blockchain
from neocore.Fixed8 import Fixed8
from neo.IO.MemoryStream import StreamManager
from neo.Implementations.Blockchains.LevelDB.LevelDBBlockchain import LevelDBBlockchain
from neo.Implementations.Blockchains.LevelDB.DebugStorage import DebugStorage
from neo.Implementations.Wallets.peewee.UserWallet import UserWallet
from neo.Implementations.Notifications.LevelDB.NotificationDB import NotificationDB
from neo.Network.NodeLeader import NodeLeader
from neo.Prompt.Commands.BuildNRun import BuildAndRun, LoadAndRun
from neo.Prompt.Commands.Invoke import InvokeContract, TestInvokeContract, test_invoke
from neo.Prompt.Commands.LoadSmartContract import LoadContract, GatherContractDetails, ImportContractAddr, \
    ImportMultiSigContractAddr
from neo.Prompt.Commands.Send import construct_and_send, parse_and_sign
from neo.contrib.nex.withdraw import RequestWithdrawFrom, PrintHolds, DeleteHolds, WithdrawOne, WithdrawAll, \
    CancelWithdrawalHolds, ShowCompletedHolds, CleanupCompletedHolds
from neo.Prompt.Commands.Tokens import token_approve_allowance, token_get_allowance, token_send, token_send_from, \
    token_mint, token_crowdsale_register
from neo.Prompt.Commands.Wallet import DeleteAddress, ImportWatchAddr, ImportToken, ClaimGas, DeleteToken, AddAlias, \
    ShowUnspentCoins
from neo.Prompt.Utils import get_arg
from neo.Prompt.InputParser import InputParser
from neo.Settings import settings, DIR_PROJECT_ROOT
from neo.UserPreferences import preferences
from neocore.KeyPair import KeyPair
from neocore.UInt256 import UInt256

# Logfile settings & setup
LOGFILE_FN = os.path.join(DIR_PROJECT_ROOT, 'prompt.log')
LOGFILE_MAX_BYTES = 5e7  # 50 MB
LOGFILE_BACKUP_COUNT = 3  # 3 logfiles history
settings.set_logfile(LOGFILE_FN, LOGFILE_MAX_BYTES, LOGFILE_BACKUP_COUNT)

# Prompt history filename
FILENAME_PROMPT_HISTORY = os.path.join(DIR_PROJECT_ROOT, '.prompt.py.history')


class PromptInterface(object):
    go_on = True

    _walletdb_loop = None

    Wallet = None

    _known_things = []

    commands = ['quit',
                'help',
                'block {index/hash} (tx)',
                'header {index/hash}',
                'tx {hash}',
                'asset {assetId}',
                'asset search {query}',
                'contract {contract hash}',
                'contract search {query}',
                'notifications {block_number or address}',
                'mem',
                'nodes',
                'state',
                'config debug {on/off}',
                'config sc-events {on/off}',
                'build {path/to/file.py} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'load_run {path/to/file.avm} (test {params} {returntype} {needs_storage} {needs_dynamic_invoke} {test_params})',
                'import wif {wif}',
                'import nep2 {nep2_encrypted_key}',
                'import contract {path/to/file.avm} {params} {returntype} {needs_storage} {needs_dynamic_invoke}',
                'import contract_addr {contract_hash} {pubkey}',
                'import watch_addr {address}',
                'import token {token_contract_hash}',
                'export wif {address}',
                'export nep2 {address}',
                'open wallet {path}',
                'create wallet {path}',
                'wallet {verbose}',
                'wallet claim',
                'wallet migrate',
                'wallet rebuild {start block}',
                'wallet delete_addr {addr}',
                'wallet alias {addr} {title}',
                'wallet tkn_send {token symbol} {address_from} {address to} {amount} ',
                'wallet tkn_send_from {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_approve {token symbol} {address_from} {address to} {amount}',
                'wallet tkn_allowance {token symbol} {address_from} {address to}',
                'wallet tkn_mint {token symbol} {mint_to_addr} (--attach-neo={amount}, --attach-gas={amount})',
                'wallet unspent',
                'wallet close',
                'withdraw_request {asset_name} {contract_hash} {to_addr} {amount}',
                'withdraw holds # lists all current holds',
                'withdraw completed # lists completed holds eligible for cleanup',
                'withdraw cancel # cancels current holds',
                'witdraw cleanup # cleans up completed holds',
                'withdraw # withdraws the first hold availabe',
                'withdraw all # withdraw all holds available',
                'send {assetId or name} {address} {amount} (--from-addr={addr})',
                'sign {transaction in JSON format}',
                'testinvoke {contract hash} {params} (--attach-neo={amount}, --attach-gas={amount})',
                'debugstorage {on/off/reset}'
                ]

    history = FileHistory(FILENAME_PROMPT_HISTORY)

    token_style = None
    start_height = None
    start_dt = None

    def __init__(self):
        self.input_parser = InputParser()
        self.start_height = Blockchain.Default().Height
        self.start_dt = datetime.datetime.utcnow()

        self.token_style = style_from_dict({
            Token.Command: preferences.token_style['Command'],
            Token.Neo: preferences.token_style['Neo'],
            Token.Default: preferences.token_style['Default'],
            Token.Number: preferences.token_style['Number'],
        })

    def get_bottom_toolbar(self, cli=None):
        out = []
        try:
            out = [(Token.Command, '[%s] Progress: ' % settings.net_name),
                   (Token.Number, str(Blockchain.Default().Height)),
                   (Token.Neo, '/'),
                   (Token.Number, str(Blockchain.Default().HeaderHeight))]
        except Exception as e:
            pass

        return out

    def get_completer(self):

        standard_completions = ['block', 'tx', 'header', 'mem', 'neo', 'gas',
                                'help', 'state', 'nodes', 'exit', 'quit',
                                'config', 'import', 'export', 'open',
                                'wallet', 'contract', 'asset', 'wif',
                                'watch_addr', 'contract_addr', 'testinvoke', 'tkn_send',
                                'tkn_mint', 'tkn_send_from', 'tkn_approve', 'tkn_allowance',
                                'build', 'notifications', ]

        if self.Wallet:
            for addr in self.Wallet.Addresses:
                if addr not in self._known_things:
                    self._known_things.append(addr)
            for alias in self.Wallet.NamedAddr:
                if alias.Title not in self._known_things:
                    self._known_things.append(alias.Title)
            for tkn in self.Wallet.GetTokens().values():
                if tkn.symbol not in self._known_things:
                    self._known_things.append(tkn.symbol)

        all_completions = standard_completions + self._known_things

        completer = WordCompleter(all_completions)

        return completer

    def quit(self):
        print('Shutting down. This may take a bit...')
        self.go_on = False
        self.do_close_wallet()
        NotificationDB.close()
        Blockchain.Default().Dispose()
        reactor.stop()
        NodeLeader.Instance().Shutdown()

    def help(self):
        tokens = []
        for c in self.commands:
            tokens.append((Token.Command, "%s\n" % c))
        print_tokens(tokens, self.token_style)

    def do_open(self, arguments):
        if self.Wallet:
            self.do_close_wallet()

        item = get_arg(arguments)

        if item and item == 'wallet':

            path = get_arg(arguments, 1)

{'fraction_non_alphanumeric': 0.10061527325370974, 'fraction_numerical': 0.002352515381831343, 'mean_word_length': 2.416941467436109, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '848929', 'n_tokens_mistral': 4795, 'n_tokens_neox': 4587, 'n_words': 1126}