Example #1
0
 def handle_interactive_exception(self):
     if neotermcolor:
         neotermcolor.cprint('error', 'red')
     else:
         print('error')
     import traceback
     traceback.print_exc()
Example #2
0
def execute(executable, options):
    try:
        return run(executable, capture_output=True,
                   input=options.get('-i'),
                   timeout=options.get('-t') or 10,
                   encoding='utf8'
                  )
    except TimeoutExpired:
        cprint('MAX RUNNING TIME EXCEEDED, PROGRAM KILLED\n', attrs=['bold'])
Example #3
0
def raise_critical(e):
    if 'eva.core' in sys.modules:
        import eva.core
        if isinstance(e, SchemaValidationError):
            logging.error(f'Schema validation error {e}')
            raise
        else:
            logging.critical('REGISTRY SERVER ERROR')
            eva.core.log_traceback()
            eva.core.critical()
            raise
    else:
        from neotermcolor import cprint
        cprint('REGISTRY SERVER ERROR', color='red', attrs='bold')
        raise
Example #4
0
def query(q):
    t_start = time.time()
    result = list(exec_query(q))
    t_spent = time.time() - t_start
    ft = rapidtables.format_table(result, fmt=rapidtables.FORMAT_GENERATOR)
    if ft:
        h, tbl = ft
        neotermcolor.cprint(h, '@finac:title')
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        for t in tbl:
            print(t)
        neotermcolor.cprint('-' * len(h), '@finac:separator')
    print(f'SELECT {len(result)}')
    print(f'Time: {t_spent:.3f}s')
Example #5
0
def lsa(asset=None, start=None, end=None):
    """
    Print list of assets or asset rates for the specified one

    Currency filter can be specified either as code, or as pair "code/code"

    If asset == '*' - print rates table

    Args:
        asset: asset code
        start: start date (for rates), default: first day of current month
        end: end date (for rates)
    """
    if not asset:
        ft = rapidtables.format_table(asset_list(),
                                      fmt=rapidtables.FORMAT_GENERATOR,
                                      align=(rapidtables.ALIGN_LEFT,
                                             rapidtables.ALIGN_RIGHT))
        if not ft:
            return
        h, tbl = ft
        neotermcolor.cprint(h, '@finac:title')
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        for t in tbl:
            neotermcolor.cprint(t)
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        print('Base asset: ', end='')
        neotermcolor.cprint(config.base_asset.upper(), style='finac:sum')
    else:
        rr = []
        for r in asset_list_rates(
                asset=(asset if asset != '*' else None),
                start=start if start else datetime.datetime.today().replace(
                    day=1, hour=0, minute=0, second=0,
                    microsecond=0).timestamp(),
                end=end,
                datefmt=True):
            row = OrderedDict()
            row['pair'] = '{}/{}'.format(r['asset_from'], r['asset_to'])
            row['date'] = r['date']
            row['value'] = r['value']
            rr.append(row)
        ft = rapidtables.format_table(rr, fmt=rapidtables.FORMAT_GENERATOR)
        if not ft:
            return
        h, tbl = ft
        neotermcolor.cprint(h, '@finac:title')
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        for t in tbl:
            neotermcolor.cprint(t)
Example #6
0
def ls(account=None,
       asset=None,
       tp=None,
       passive=None,
       start=None,
       end=None,
       tag=None,
       pending=True,
       hide_empty=False,
       order_by=['tp', 'asset', 'account', 'balance'],
       group_by=None,
       base=None):
    """
    Primary interactive function. Prints account statement if account code
    is specified, otherwise prints summary for all accounts

    Account code may contain '%' symbol as a wildcard.

    Args:
        account: account code
        asset: filter by asset code
        tp: filter by account type (or types)
        passive: list passive, active or all (if None) accounts
        start: start date (for statement), default: first day of current month
        end: end date (or balance date for summary)
        tag: filter transactions by tag (for statement)
        pending: include pending transactions
        hide_empty: hide empty accounts (for summary)
        order_by: column ordering (ordering by base is not supported)
        base: specify base asset
    """
    if account and account.find('%') != -1:
        code = account
        account = None
    else:
        code = None
    if account:
        result = account_statement_summary(
            account=account,
            start=start if start else datetime.datetime.today().replace(
                day=1, hour=0, minute=0, second=0, microsecond=0).timestamp(),
            end=end,
            tag=tag,
            pending=pending,
            datefmt=True)
        stmt = result['statement'].copy()
        acc_info = account_info(account=account)
        precision = asset_precision(asset=acc_info['asset'])
        for i, r in enumerate(stmt):
            r = r.copy()
            del r['is_completed']
            r['amount'] = format_money(r['amount'], precision)
            stmt[i] = r
        ft = rapidtables.format_table(
            stmt,
            fmt=rapidtables.FORMAT_GENERATOR,
            align=(rapidtables.ALIGN_LEFT, rapidtables.ALIGN_RIGHT,
                   rapidtables.ALIGN_LEFT, rapidtables.ALIGN_LEFT,
                   rapidtables.ALIGN_LEFT, rapidtables.ALIGN_LEFT,
                   rapidtables.ALIGN_LEFT))
        rcur = base.upper() if base else acc_info['asset']
        if ft:
            h, tbl = ft
            neotermcolor.cprint(h, '@finac:title')
            neotermcolor.cprint('-' * len(h), '@finac:separator')
            for t, s in zip(tbl, result['statement']):
                neotermcolor.cprint(
                    t,
                    '@finac:credit' if s['amount'] < 0 else '@finac:debit',
                    attrs='')
            neotermcolor.cprint('-' * len(h), '@finac:separator')
            print('Debit turnover: ', end='')
            neotermcolor.cprint(format_money(result['debit'], precision),
                                style='finac:debit_sum',
                                end=', ')
            print('credit turnover: ', end='')
            neotermcolor.cprint(format_money(result['credit'], precision),
                                style='finac:credit_sum')
            print()
            if base:
                precision = asset_precision(base)
            print('Net profit/loss: ', end='')
            pl = result['debit'] - result['credit']
            if base:
                pl = pl * asset_rate(acc_info['asset'], base, date=end)
            neotermcolor.cprint('{} {}'.format(format_money(pl, precision),
                                               rcur),
                                attrs='bold',
                                end='')
            print(', balance', end='')
        else:
            print('Balance', end='')
        balance = account_balance(account=account, date=end)
        if base:
            balance = balance * asset_rate(acc_info['asset'], base, date=end)
        print('{}: '.format(' to date' if end else ''), end='')
        neotermcolor.cprint('{} {}'.format(format_money(balance, precision),
                                           rcur),
                            attrs='bold',
                            end='')
        print()
    else:
        if not base:
            base = config.base_asset
        base = base.upper()
        result = account_list_summary(asset=asset,
                                      tp=tp,
                                      passive=passive,
                                      code=code,
                                      date=end,
                                      order_by=order_by,
                                      group_by=group_by,
                                      hide_empty=hide_empty,
                                      base=base)
        if not group_by:
            kf = 'accounts'
            rt_align = (rapidtables.ALIGN_LEFT, rapidtables.ALIGN_LEFT,
                        rapidtables.ALIGN_CENTER, rapidtables.ALIGN_CENTER,
                        rapidtables.ALIGN_RIGHT, rapidtables.ALIGN_RIGHT)
        elif group_by == 'asset':
            kf = 'assets'
            rt_align = (rapidtables.ALIGN_LEFT, rapidtables.ALIGN_RIGHT,
                        rapidtables.ALIGN_RIGHT)
        else:
            kf = 'account_types'
            rt_align = (rapidtables.ALIGN_LEFT, rapidtables.ALIGN_RIGHT)
        res = result[kf]
        data = res.copy()
        bcp = asset_precision(asset=base)
        for i, r in enumerate(res):
            r = r.copy()
            if group_by not in ['type', 'tp']:
                r['balance'] = format_money(r['balance'],
                                            asset_precision(asset=r['asset']))
            r['balance ' + base] = format_money(r['balance_bc'], bcp)
            del r['balance_bc']
            if not group_by:
                del r['note']
            if 'passive' in r:
                r['passive'] = 'P' if r['passive'] else ''
            res[i] = r
        ft = rapidtables.format_table(res,
                                      fmt=rapidtables.FORMAT_GENERATOR,
                                      align=rt_align)
        if not ft:
            return
        h, tbl = ft
        neotermcolor.cprint(h, '@finac:title')
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        for t, s in zip(tbl, data):
            if s.get('passive'):
                style = 'finac:passive'
            else:
                style = 'finac:credit' if s['balance_bc'] < 0 else None
            neotermcolor.cprint(t, style=style, attrs='')
        neotermcolor.cprint('-' * len(h), '@finac:separator')
        neotermcolor.cprint('Total: ', end='')
        neotermcolor.cprint('{} {}'.format(format_money(result['total'], bcp),
                                           base),
                            style='finac:sum')
        print()
Example #7
0
                 i.split(maxsplit=1)[-1].strip()[1:-1]
                 for i in fh.readlines() if i.startswith('msgid ')
             ]
         del existing_ids[0]
         m_ids = [i for i in MSG_IDS if i not in existing_ids]
     else:
         write_header = True
         m_ids = MSG_IDS
     if m_ids or write_header:
         with po_file.open('a') as fh:
             if write_header:
                 fh.write('#, fuzzy\nmsgid ""\nmsgstr ""\n'
                          '"Content-Type: text/plain; charset=utf-8\\n"\n')
             for i in m_ids:
                 fh.write(f'\nmsgid "{i}"\nmsgstr ""\n')
     cprint(f'+{len(m_ids)}', color='cyan' if m_ids else 'grey')
 elif a.COMMAND == 'compile':
     mo_file = po_file.with_suffix('.mo')
     if not mo_file.exists(
     ) or mo_file.stat().st_mtime < po_file.stat().st_mtime:
         code = os.system(f'msgfmt {po_file} -o {mo_file}')
         if code:
             raise RuntimeError(f'command exited with code {code}')
         cprint('OK', color='green')
     else:
         cprint('skipped', color='grey')
 elif a.COMMAND == 'stat':
     with po_file.open() as fh:
         strs = [x for x in fh.readlines() if x.startswith('msgstr ')]
         del strs[0]
         translated = len(
Example #8
0
EVA_DIR = Path(__file__).parents[3].absolute()
DEFAULTS_DIR = Path(__file__).parent / 'defaults'
SCHEMA = Path(__file__).parent / 'schema.yml'
VENV_SCHEMA = Path(__file__).parent / 'schema-venv.yml'

config_file = EVA_DIR / 'etc/eva_config'

if config_file.exists():
    with ShellConfigFile(config_file.as_posix()) as cf:
        try:
            socket_path = cf.get('YEDB_SOCKET', EVA_DIR / 'var/registry.sock')
            SYSTEM_NAME = cf.get('SYSTEM_NAME', platform.node())
            timeout = float(cf.get("YEDB_TIMEOUT", 5))
        except Exception as e:
            from neotermcolor import cprint
            cprint(f'REGISTRY CONFIGURATION: {e}', color='red', attrs='bold')
            raise
else:
    socket_path = EVA_DIR / 'var/registry.sock'
    timeout = 5
    SYSTEM_NAME = platform.node()

from yedb import YEDB, FieldNotFound, SchemaValidationError

db = YEDB(socket_path, timeout=timeout)

from functools import wraps


def raise_critical(e):
    if 'eva.core' in sys.modules:
Example #9
0
def run_and_test(magic_arguments, outputs_inputs):
    '''Options are:
    -e followed by a space or another option, to express that an
       error is supposed to be raised;
    -i followed by a string, denoting the input to provide, with \\n
       expressing that user presses carriage return;
    -r followed by : possibly surrounded by integers (possibly
       preceded by - but not by +), denoting the range of output to
       examine, the integer to the left defaulting to 0, the integer
       to the right defaulting to the length of the output;
    -s followed a positive integer, denoting maximum running time,
       expressed in seconds, set to 10 by default;
    -t followed a positive integer, denoting maximum output size,
       expressed in bytes, set to 1000 by default.
       
    After the options comes the command to be run, expected to be of
    one of these forms:\n        python3 filename.py
    or\n        python3 -c python_statements_enclosed_by_quotes
    
    The cell is meant to store one or more strings, all surrounded by
    (single or triple) quotes, the first of which can be preceded by
    an arbitrary amount of space, the last of which can be followed
    by an arbitrary amount of space, two successive strings being
    separated by no other characters but spaces and at most one comma.
    
    Strings not separated by a comma are meant to be concatenated.
    
    When using triple quotes, the convention is that all lines between
    the surrounding triple quotes end in \\n, without following spaces;
    such spaces would indeed not be immediately visible in the cell.
    
    Strings separated by a comma represent program output for one and
    user input for the other; the first string represents program
    output.
    
    A string can span many lines, and is then meant to be no different
    to a string written on a single line, be it surrounded by single
    quotes. New line characters are meant to be explicitly indicated.
    For instance,
    'one\n     two'
    (with no space after one) represents the string 'one two', whereas
    'one\\n\n    two'
    (with no space after \\n) represents the string 'one\\ntwo'.
    '''
    # magic_arguments is a string (not ending in \n) that captures the
    # arguments to the magic on the line where it is invoked.
    # Occurrences of embedded \n on the line appear as \\n in the
    # string. The following statement changes all those \\n to \n,
    # so the character \ followed by the character n to the new line
    # character.
    magic_arguments = codecs.decode(magic_arguments, 'unicode_escape').strip()
    options = {}
    # Up to 5 options to process.
    for _ in range(5):
        try:
            offset = process_possible_option(magic_arguments, options)
            if not offset:
                break
            magic_arguments = magic_arguments[offset :].lstrip()
        except CommandToRunError as e:
            print(e)
            return
    if not magic_arguments.startswith('python3 '):
        print('No call to python3 (possibly after options)')
        return
    # len('python3 ') == 8
    magic_arguments = magic_arguments[8 :].lstrip()
    if magic_arguments.startswith('-c'):
        magic_arguments = magic_arguments[2 :].lstrip()
        if len(magic_arguments) < 2 or magic_arguments[0] not in '\'"'\
           or magic_arguments[-1] != magic_arguments[0]:
            print('python3 -c not followed by string')
            return
        # - Get rid of the surrounding quotes, as magic_arguments itself
        #   is a string.
        # - Let repr() escape quotes if needed.
        # - Get rid of the surrounding quotes of the string returned by
        #   repr().
        statements = repr(magic_arguments[1 : -1])[1 : -1]
        # It is assumed that there is a unique import statement of this
        # kind, for a module that is stored in the working directory.
        match = re.search('from (\S+) import \*', statements)
        if match:
            module = match.groups()[0] + '.py'
            if not Path(module).exists():
                print(module, 'is not an existing Python module')
                return
            with NamedTemporaryFile('w', dir='.', suffix='.py') as temp_file:
                expand_with_echoed_input(module, temp_file)
                # temp_file.name is the name of an absolute path to a
                # temporary file.
                # Path(temp_file.name).stem is used to extract only
                # the name of that file, without the .py extension.
                # match.span() is the start and end+1 positions of the
                # occurrence, in magic_arguments, of the name of the
                # module all of whose contents is to be imported.
                p = execute(('python3', '-c',
                             statements.replace(
                                 statements[slice(*match.span())],
                                 f'from {Path(temp_file.name).stem} import *'
                                               )
                            ), options
                           )
        else:
            p = execute(('python3', '-c', statements), options)
    elif not magic_arguments.endswith('.py')\
         or not Path(magic_arguments).exists():
        print(magic_arguments, 'is not an existing Python module')
        return
    else:
        # It is assumed that the module to run is stored in the working
        # directory.
        with NamedTemporaryFile('w', dir='.') as temp_file:
            expand_with_echoed_input(magic_arguments, temp_file)
            p = execute(('python3', temp_file.name), options)
    if not p:
        return
    size_limit = options.get('-s') or 1000
    start, end = options.get('-r', (None, None))
    try:
        error = p.stderr[p.stderr.rindex('\n', 0, -1) + 1 :]
    except ValueError:
        error = ''
    if '-e' in options:
        program_output = error
    elif p.stderr:
        cprint('PROGRAM PRODUCED AN ERROR\n', attrs=['bold'])
        print(error)
        return
    elif len(p.stdout) > size_limit:
        cprint('TOO MUCH OUTPUT, DISPLAYING MAX ALLOWED\n',
               attrs=['bold']
              )
        print(p.stdout[: size_limit][slice(start, end)])
        return
    else:
        program_output = p.stdout[slice(start, end)]
    # outputs_inputs is a string that represents the cell contents,
    # with the end of each line in the cell represented by \n, and with
    # all embedded \n represented by \\n. For instance, if the cell
    # contains
    # 'one
    #  two'
    # then outputs_inputs contains 'one\n two' (the quotes being
    # escaped in case outputs_inputs is itself surrounded by simple
    # quotes), whereas if the cell contains
    # 'one\n
    # two'
    # then outputs_inputs contains 'one\\n\ntwo' (with the same remark
    # on the quotes).
    # Recall:
    # - an occurrence of \n not preceeded by \ is the new line
    #   character;
    # - an occurrence of \\n is two characters: \ followed by n.
    # The call to eval() returns a string in case no successive strings
    # within outputs_inputs have a comma in-between, and a tuple of
    # at least 2 strings otherwise.
    outputs_inputs = eval(outputs_inputs.replace('\n', ''))
    if isinstance(outputs_inputs, str):
        outputs_inputs = [outputs_inputs]
    expected_output = ''.join(outputs_inputs)
    cprint('PASSED' if program_output == expected_output else 'FAILED',
           attrs=['bold']
          )
    if start:
        if start == 1:
            cprint(f'IGNORING FIRST CHARACTER OF OUTPUT', attrs=['underline'])
        elif start > 0:
            cprint(f'IGNORING FIRST {start} CHARACTERS OF OUTPUT',
                   attrs=['underline']
                  )
        elif start == -1:
            cprint(f'IGNORING ALL BUT LAST CHARACTER OF OUTPUT',
                   attrs=['underline']
                  )
        else:
            cprint(f'IGNORING ALL BUT LAST {-start} CHARACTERS OF OUTPUT',
                   attrs=['underline']
                  )
    if end:
        if end == -1:
            cprint(f'IGNORING LAST CHARACTER OF OUTPUT', attrs=['underline'])      
        elif end < 0:
            cprint(f'IGNORING LAST {-end} CHARACTERS OF OUTPUT', 
                   attrs=['underline']
                  )
        elif end == 1:
            cprint(f'IGNORING ALL BUT FIRST CHARACTER OF OUTPUT',
                   attrs=['underline']
                  )
        else:
            cprint(f'IGNORING ALL BUT FIRST {end} CHARACTERS OF OUTPUT',
                   attrs=['underline']
                  )
    if program_output and program_output[-1] != '\n'\
       and expected_output and expected_output[-1] != '\n':
        program_output += '\n'
        expected_output += '\n'
    elif program_output and program_output[-1] != '\n':
        cprint('MISSING NEW LINE AT END OF OUTPUT NOT SHOWN IN DIFF',
               attrs=['bold']
              )
        program_output += '\n'
    elif expected_output and expected_output[-1] != '\n':
        cprint('EXTRA NEW LINE AT END OF OUTPUT NOT SHOWN IN DIFF',
               attrs=['bold']
              )
        expected_output += '\n'
    print()
    coloured_lines = []
    if len(outputs_inputs) > 1:
        grey_or_blue = cycle(('grey', 'blue'))
        coloured_snippets = []
        snippet = [' ']
        starting_new_line = True
        for output_or_input in outputs_inputs:
            colour = next(grey_or_blue)
            for c in output_or_input:
                snippet.append(c)
                if c == '\n':
                    coloured_snippets.append([snippet, colour])
                    coloured_lines.append(coloured_snippets)
                    coloured_snippets = []
                    snippet = [' ']
                    starting_new_line = True
                else:
                    starting_new_line = False
            if snippet and (not starting_new_line or snippet != [' ']):
                coloured_snippets.append([snippet, colour])
                snippet = [' '] if starting_new_line else []
        if coloured_snippets:
            coloured_lines.append(coloured_snippets)
        if expected_output[-1] != '\n':
            coloured_lines[-1][-1][0].append('\n')
    for line in coloured_diff(program_output, expected_output,
                              coloured_lines
                             ):
        print(line, end='')
Example #10
0
def print_debug(*args, **kwargs):
    neotermcolor.cprint(*args, color='grey', attrs=['bold'], **kwargs)
Example #11
0
def print_warn(*args, **kwargs):
    neotermcolor.cprint(*args, color='yellow', attrs=['bold'], **kwargs)
Example #12
0
def print_err(*args, **kwargs):
    neotermcolor.cprint(*args, color='red', **kwargs)