def format_terminal_row(headers, example_row): """Uses headers and a row of example data to generate a format string for printing a single row of data. Args: headers (tuple of strings): The headers for each column of data example_row (tuple): A representative tuple of strings or ints Returns string: A format string with a size for each column """ def format_column(col): if isinstance(col, str): return '{{:{w}.{w}}}' return '{{:<{w}}}' widths = [max(len(h), len(str(d))) for h, d in zip(headers, example_row)] # Truncate last column to fit terminal width original_last_width = widths[-1] if sys.stdout.isatty(): widths[-1] = max( len(headers[-1]), # console width - width of other columns and gutters - 3 for '...' tty.width() - sum(w + 2 for w in widths[0:-1]) - 3) # Build format string cols = [format_column(c).format(w=w) for c, w in zip(example_row, widths)] format_string = ' '.join(cols) if original_last_width > widths[-1]: format_string += '...' return format_string
def _do_identity_policy_list(args): rest_client = RestClient(args.url) state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _POLICY_PREFIX) head = state['head'] state_values = state['data'] printable_policies = [] for state_value in state_values: policies_list = PolicyList() decoded = b64decode(state_value['data']) policies_list.ParseFromString(decoded) for policy in policies_list.policies: printable_policies.append(policy) printable_policies.sort(key=lambda p: p.name) if args.format == 'default': tty_width = tty.width() for policy in printable_policies: # Set value width to the available terminal space, or the min width width = tty_width - len(policy.name) - 3 width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH value = "Entries:\n" for entry in policy.entries: entry_string = (" " * 4) + Policy.Type.Name(entry.type) + " " \ + entry.key value += (entry_string[:width] + '...' if len(entry_string) > width else entry_string) + "\n" print('{}: \n {}'.format(policy.name, value)) elif args.format == 'csv': try: writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL) writer.writerow(['POLICY NAME', 'ENTRIES']) for policy in printable_policies: output = [policy.name] for entry in policy.entries: output.append( Policy.Type.Name(entry.type) + " " + entry.key) writer.writerow(output) except csv.Error: raise CliException('Error writing CSV') elif args.format == 'json' or args.format == 'yaml': output = {} for policy in printable_policies: value = "Entries: " for entry in policy.entries: entry_string = Policy.Type.Name(entry.type) + " " \ + entry.key value += entry_string + " " output[policy.name] = value policies_snapshot = {'head': head, 'policies': output} if args.format == 'json': print(json.dumps(policies_snapshot, indent=2, sort_keys=True)) else: print(yaml.dump(policies_snapshot, default_flow_style=False)[0:-1]) else: raise AssertionError('Unknown format {}'.format(args.format))
def _do_config_list(args): """Lists the current on-chain configuration values. """ rest_client = RestClient(args.url) state = rest_client.list_state(subtree=SETTINGS_NAMESPACE) prefix = args.filter head = state['head'] state_values = state['data'] printable_settings = [] proposals_address = _key_to_address('sawtooth.settings.vote.proposals') for state_value in state_values: if state_value['address'] == proposals_address: # This is completely internal setting and we won't list it here continue decoded = b64decode(state_value['data']) setting = Setting() setting.ParseFromString(decoded) for entry in setting.entries: if entry.key.startswith(prefix): printable_settings.append(entry) printable_settings.sort(key=lambda s: s.key) if args.format == 'default': tty_width = tty.width() for setting in printable_settings: # Set value width to the available terminal space, or the min width width = tty_width - len(setting.key) - 3 width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH value = (setting.value[:width] + '...' if len(setting.value) > width else setting.value) print('{}: {}'.format(setting.key, value)) elif args.format == 'csv': try: writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL) writer.writerow(['KEY', 'VALUE']) for setting in printable_settings: writer.writerow([setting.key, setting.value]) except csv.Error: raise CliException('Error writing CSV') elif args.format == 'json' or args.format == 'yaml': settings_snapshot = { 'head': head, 'settings': {setting.key: setting.value for setting in printable_settings} } if args.format == 'json': print(json.dumps(settings_snapshot, indent=2, sort_keys=True)) else: print(yaml.dump(settings_snapshot, default_flow_style=False)[0:-1]) else: raise AssertionError('Unknown format {}'.format(args.format))
def _do_identity_role_list(args): """Lists the current on-chain configuration values. """ rest_client = RestClient(args.url) state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _ROLE_PREFIX) head = state['head'] state_values = state['data'] printable_roles = [] for state_value in state_values: role_list = RoleList() decoded = b64decode(state_value['data']) role_list.ParseFromString(decoded) for role in role_list.roles: printable_roles.append(role) printable_roles.sort(key=lambda r: r.name) if args.format == 'default': tty_width = tty.width() for role in printable_roles: # Set value width to the available terminal space, or the min width width = tty_width - len(role.name) - 3 width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH value = (role.policy_name[:width] + '...' if len(role.policy_name) > width else role.policy_name) print('{}: {}'.format(role.name, value)) elif args.format == 'csv': try: writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL) writer.writerow(['KEY', 'VALUE']) for role in printable_roles: writer.writerow([role.name, role.policy_name]) except csv.Error: raise CliException('Error writing CSV') elif args.format == 'json' or args.format == 'yaml': roles_snapshot = { 'head': head, 'roles': {role.name: role.policy_name for role in printable_roles} } if args.format == 'json': print(json.dumps(roles_snapshot, indent=2, sort_keys=True)) else: print(yaml.dump(roles_snapshot, default_flow_style=False)[0:-1]) else: raise AssertionError('Unknown format {}'.format(args.format))
def do_batch(args): """Runs the batch list or batch show command, printing output to the console Args: args: The parsed arguments sent to the command at runtime """ rest_client = RestClient(args.url) def print_json(data): print( json.dumps(data, indent=2, separators=(',', ': '), sort_keys=True)) def print_yaml(data): print(yaml.dump(data, default_flow_style=False)[0:-1]) if args.subcommand == 'list': batches = rest_client.list_batches() keys = ('batch_id', 'txns', 'signer') headers = (k.upper() for k in keys) def get_data(batch): return (batch['header_signature'], len(batch.get('transactions', [])), batch['header']['signer_pubkey']) if args.format == 'default': # Set column widths based on window and data size window_width = tty.width() try: id_width = len(batches[0]['header_signature']) sign_width = len(batches[0]['header']['signer_pubkey']) except IndexError: # if no data was returned, use short default widths id_width = 30 sign_width = 15 if sys.stdout.isatty(): adjusted = int(window_width) - id_width - 11 adjusted = 6 if adjusted < 6 else adjusted else: adjusted = sign_width fmt_string = '{{:{i}.{i}}} {{:<4}} {{:{a}.{a}}}'\ .format(i=id_width, a=adjusted) # Print data in rows and columns print(fmt_string.format(*headers)) for batch in batches: print( fmt_string.format(*get_data(batch)) + ('...' if adjusted < sign_width and sign_width else '')) elif args.format == 'csv': try: writer = csv.writer(sys.stdout) writer.writerow(headers) for batch in batches: writer.writerow(get_data(batch)) except csv.Error as e: raise CliException('Error writing CSV: {}'.format(e)) elif args.format == 'json' or args.format == 'yaml': data = [{k: d for k, d in zip(keys, get_data(b))} for b in batches] if args.format == 'yaml': print_yaml(data) elif args.format == 'json': print_json(data) else: raise AssertionError('Missing handler: {}'.format(args.format)) else: raise AssertionError('Missing handler: {}'.format(args.format)) if args.subcommand == 'show': batch = rest_client.get_batch(args.batch_id) if args.key: if args.key in batch: print(batch[args.key]) elif args.key in batch['header']: print(batch['header'][args.key]) else: raise CliException( 'key "{}" not found in batch or header'.format(args.key)) else: if args.format == 'yaml': print_yaml(batch) elif args.format == 'json': print_json(batch) else: raise AssertionError('Missing handler: {}'.format(args.format))
def _do_identity_policy_list(args): rest_client = RestClient(args.url) state = rest_client.list_state(subtree=IDENTITY_NAMESPACE + _POLICY_PREFIX) head = state['head'] state_values = state['data'] printable_policies = [] for state_value in state_values: policies_list = PolicyList() decoded = b64decode(state_value['data']) policies_list.ParseFromString(decoded) for policy in policies_list.policies: printable_policies.append(policy) printable_policies.sort(key=lambda p: p.name) if args.format == 'default': tty_width = tty.width() for policy in printable_policies: # Set value width to the available terminal space, or the min width width = tty_width - len(policy.name) - 3 width = width if width > _MIN_PRINT_WIDTH else _MIN_PRINT_WIDTH value = "Entries:\n" for entry in policy.entries: entry_string = (" " * 4) + Policy.EntryType.Name(entry.type) \ + " " + entry.key value += (entry_string[:width] + '...' if len(entry_string) > width else entry_string) + "\n" print('{}: \n {}'.format(policy.name, value)) elif args.format == 'csv': try: writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL) writer.writerow(['POLICY NAME', 'ENTRIES']) for policy in printable_policies: output = [policy.name] for entry in policy.entries: output.append( Policy.EntryType.Name(entry.type) + " " + entry.key) writer.writerow(output) except csv.Error: raise CliException('Error writing CSV') elif args.format == 'json' or args.format == 'yaml': output = {} for policy in printable_policies: value = "Entries: " for entry in policy.entries: entry_string = Policy.EntryType.Name(entry.type) + " " \ + entry.key value += entry_string + " " output[policy.name] = value policies_snapshot = { 'head': head, 'policies': output } if args.format == 'json': print(json.dumps(policies_snapshot, indent=2, sort_keys=True)) else: print(yaml.dump(policies_snapshot, default_flow_style=False)[0:-1]) else: raise AssertionError('Unknown format {}'.format(args.format))
def do_state(args): """Runs the batch list or batch show command, printing output to the console Args: args: The parsed arguments sent to the command at runtime """ rest_client = RestClient(args.url) def print_json(data): print( json.dumps(data, indent=2, separators=(',', ': '), sort_keys=True)) def print_yaml(data): print(yaml.dump(data, default_flow_style=False)[0:-1]) if args.subcommand == 'list': response = rest_client.list_state(args.subtree, args.head) leaves = response['data'] head = response['head'] keys = ('address', 'size', 'data') headers = (k.upper() for k in keys) def get_leaf_data(leaf, decode=True): decoded = b64decode(leaf['data']) return (leaf['address'], len(decoded), str(decoded) if decode else leaf['data']) if args.format == 'default': # Set column widths based on window and data size window_width = tty.width() try: addr_width = len(leaves[0]['address']) data_width = len(str(b64decode(leaves[0]['data']))) except IndexError: # if no data was returned, use short default widths addr_width = 30 data_width = 15 if sys.stdout.isatty(): adjusted = int(window_width) - addr_width - 11 adjusted = 6 if adjusted < 6 else adjusted else: adjusted = data_width fmt_string = '{{:{a}.{a}}} {{:<4}} {{:{j}.{j}}}'\ .format(a=addr_width, j=adjusted) # Print data in rows and columns print(fmt_string.format(*headers)) for leaf in leaves: print( fmt_string.format(*get_leaf_data(leaf)) + ('...' if adjusted < data_width and data_width else '')) print('HEAD BLOCK: "{}"'.format(head)) elif args.format == 'csv': try: writer = csv.writer(sys.stdout) writer.writerow(headers) for leaf in leaves: writer.writerow(get_leaf_data(leaf)) except csv.Error as e: raise CliException('Error writing CSV: {}'.format(e)) print('(data for head block: "{}")'.format(head)) elif args.format == 'json' or args.format == 'yaml': state_data = { 'head': head, 'data': [{k: d for k, d in zip(keys, get_leaf_data(l, False))} for l in leaves] } if args.format == 'yaml': print_yaml(state_data) elif args.format == 'json': print_json(state_data) else: raise AssertionError('Missing handler: {}'.format(args.format)) else: raise AssertionError('Missing handler: {}'.format(args.format)) if args.subcommand == 'show': leaf = rest_client.get_leaf(args.address, args.head) if leaf is not None: print('DATA: "{}"'.format(b64decode(leaf['data']))) print('HEAD: "{}"'.format(leaf['head'])) else: raise CliException('No data available at {}'.format(args.address))