def handle_interactive_exception(self): if neotermcolor: neotermcolor.cprint('error', 'red') else: print('error') import traceback traceback.print_exc()
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'])
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
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')
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)
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()
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(
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:
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='')
def print_debug(*args, **kwargs): neotermcolor.cprint(*args, color='grey', attrs=['bold'], **kwargs)
def print_warn(*args, **kwargs): neotermcolor.cprint(*args, color='yellow', attrs=['bold'], **kwargs)
def print_err(*args, **kwargs): neotermcolor.cprint(*args, color='red', **kwargs)