Add more color to nucypher cli output, fixes #1150

pull/2909/head
James Campbell 2022-04-06 18:56:12 +00:00
parent 4a854201a6
commit 8dbea2e743
9 changed files with 39 additions and 39 deletions

View File

@ -55,7 +55,7 @@ def validate_grant_command(
# see what condition my condition was in.
if not condition.condition:
triggered = True
emitter.error(f'Missing options in force mode: {condition.options}')
emitter.error(f'Missing options in force mode: {condition.options}', color="red")
if triggered:
raise click.Abort()
@ -63,20 +63,20 @@ def validate_grant_command(
if alice.federated_only:
if any((value, rate)):
message = "Can't use --value or --rate with a federated Alice."
raise click.BadOptionUsage(option_name="--value, --rate", message=message)
raise click.BadOptionUsage(option_name="--value, --rate", message=click.style(message, fg="red"))
elif bool(value) and bool(rate):
raise click.BadOptionUsage(option_name="--rate", message="Can't use --value if using --rate")
raise click.BadOptionUsage(option_name="--rate", message=click.style("Can't use --value if using --rate", fg="red"))
# From Bob card
if bob:
if any((bob_encrypting_key, bob_verifying_key)):
message = '--bob cannot be used with --bob-encrypting-key or --bob-verifying key'
raise click.BadOptionUsage(option_name='--bob', message=message)
raise click.BadOptionUsage(option_name='--bob', message=click.style(message, fg="red"))
# From hex public keys
else:
if not all((bob_encrypting_key, bob_verifying_key)):
if force:
emitter.message('Missing options in force mode: --bob or --bob-encrypting-key and --bob-verifying-key.')
emitter.message('Missing options in force mode: --bob or --bob-encrypting-key and --bob-verifying-key.', color="red")
click.Abort()
emitter.message("*Caution: Only enter public keys*")

View File

@ -119,7 +119,7 @@ class AliceConfigOptions:
if self.federated_only is False:
raise click.BadOptionUsage(
option_name="--federated-only",
message="--federated-only cannot be explicitly set to False when --dev is set")
message=click.style("--federated-only cannot be explicitly set to False when --dev is set", fg="red"))
return AliceConfiguration(
emitter=emitter,
@ -210,7 +210,7 @@ class AliceFullConfigOptions:
if not opts.eth_provider_uri and not opts.federated_only:
raise click.BadOptionUsage(
option_name='--eth-provider',
message="--eth-provider is required to create a new decentralized alice.")
message=click.style("--eth-provider is required to create a new decentralized alice.", fg="red"))
pay_with = opts.pay_with
if not pay_with and not opts.federated_only:

View File

@ -305,7 +305,7 @@ def destroy(general_config, config_options, config_file, force):
emitter = setup_emitter(general_config)
if config_options.dev:
message = "'nucypher bob destroy' cannot be used in --dev mode"
raise click.BadOptionUsage(option_name='--dev', message=message)
raise click.BadOptionUsage(option_name='--dev', message=click.style(message, fg="red"))
bob_config = config_options.create_config(emitter, config_file)
destroy_configuration(emitter, character_config=bob_config, force=force)
@ -371,7 +371,7 @@ def retrieve_and_decrypt(general_config,
if not (bool(alice_verifying_key) ^ bool(alice)):
message = f"Pass either '--alice_verifying_key' or '--alice'; " \
f"got {'both' if alice_verifying_key else 'neither'}"
raise click.BadOptionUsage(option_name='--alice_verifying_key, --alice', message=message)
raise click.BadOptionUsage(option_name='--alice_verifying_key, --alice', message=click.style(message, fg="red"))
if not alice_verifying_key:
if alice: # from storage

View File

@ -145,4 +145,4 @@ def import_card(filepath):
emitter = StdoutEmitter()
shutil.copy(filepath, Card.CARD_DIR)
# paint_single_card(card=card)
emitter.message(f'Successfully imported card.')
emitter.message(f'Successfully imported card.', color="green")

View File

@ -277,7 +277,7 @@ def download_registry(general_config, config_root, registry_outfile, network, fo
except InMemoryContractRegistry.CantOverwriteRegistry:
emitter.message(CANNOT_OVERWRITE_REGISTRY, color="red")
raise click.Abort
emitter.message(SUCCESSFUL_REGISTRY_DOWNLOAD.format(output_filepath=output_filepath))
emitter.message(SUCCESSFUL_REGISTRY_DOWNLOAD.format(output_filepath=output_filepath), color="green")
@deploy.command()
@ -331,20 +331,20 @@ def upgrade(general_config, actor_options, retarget, target_address, ignore_depl
contract_name = actor_options.contract_name
if not contract_name:
raise click.BadArgumentUsage(message="--contract-name is required when using --upgrade")
raise click.BadArgumentUsage(message=click.style("--contract-name is required when using --upgrade", fg="red"))
try:
# Check contract name exists
Deployer = ADMINISTRATOR.deployers[contract_name]
except KeyError:
message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name, constants=ADMINISTRATOR.deployers.keys())
emitter.echo(message, color='red', bold=True)
emitter.error(message)
raise click.Abort()
deployer = Deployer(registry=local_registry)
# Check deployer address is owner
if Deployer._ownable and deployer_address != deployer.owner: # blockchain read
emitter.echo(DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address,
emitter.error(DEPLOYER_IS_NOT_OWNER.format(deployer_address=deployer_address,
contract_name=contract_name,
agent=deployer.make_agent()))
raise click.Abort()
@ -357,7 +357,7 @@ def upgrade(general_config, actor_options, retarget, target_address, ignore_depl
if retarget:
if not target_address:
raise click.BadArgumentUsage(message="--target-address is required when using --retarget")
raise click.BadArgumentUsage(message=click.style("--target-address is required when using --retarget", fg="red"))
if not actor_options.force:
click.confirm(CONFIRM_RETARGET.format(contract_name=contract_name, target_address=target_address), abort=True)
receipt = ADMINISTRATOR.retarget_proxy(contract_name=contract_name,target_address=target_address, confirmations=confirmations)
@ -402,7 +402,7 @@ def rollback(general_config, actor_options):
emitter = general_config.emitter
ADMINISTRATOR, _, _, _ = actor_options.create_actor(emitter)
if not actor_options.contract_name:
raise click.BadArgumentUsage(message="--contract-name is required when using --rollback")
raise click.BadArgumentUsage(message=click.style("--contract-name is required when using --rollback", fg="red"))
receipt = ADMINISTRATOR.rollback_contract(contract_name=actor_options.contract_name)
paint_receipt_summary(emitter=emitter, receipt=receipt)
@ -440,7 +440,7 @@ def contracts(general_config, actor_options, mode, activate, gas, ignore_deploye
contract_deployer_class = ADMINISTRATOR.deployers[contract_name]
except KeyError:
message = UNKNOWN_CONTRACT_NAME.format(contract_name=contract_name, constants=ADMINISTRATOR.deployers.keys())
emitter.echo(message, color='red', bold=True)
emitter.error(message)
raise click.Abort()
if activate:
@ -448,7 +448,7 @@ def contracts(general_config, actor_options, mode, activate, gas, ignore_deploye
staking_escrow_deployer = contract_deployer_class(registry=ADMINISTRATOR.registry)
if contract_name != STAKING_ESCROW_CONTRACT_NAME or not staking_escrow_deployer.ready_to_activate:
raise click.BadOptionUsage(option_name="--activate",
message=f"You can only activate an idle instance of {STAKING_ESCROW_CONTRACT_NAME}")
message=click.style(f"You can only activate an idle instance of {STAKING_ESCROW_CONTRACT_NAME}", fg="red"))
escrow_address = staking_escrow_deployer._get_deployed_contract().address
prompt = CONFIRM_NETWORK_ACTIVATION.format(staking_escrow_name=STAKING_ESCROW_CONTRACT_NAME,

View File

@ -85,19 +85,19 @@ def run(general_config,
# HTTP/HTTPS
if bool(tls_key_filepath) ^ bool(tls_certificate_filepath):
raise click.BadOptionUsage(option_name='--tls-key-filepath, --tls-certificate-filepath',
message=PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED)
message=click.style(PORTER_BOTH_TLS_KEY_AND_CERTIFICATION_MUST_BE_PROVIDED, fg="red"))
is_https = (tls_key_filepath and tls_certificate_filepath)
# check authentication
if basic_auth_filepath and not is_https:
raise click.BadOptionUsage(option_name='--basic-auth-filepath',
message=PORTER_BASIC_AUTH_REQUIRES_HTTPS)
message=click.style(PORTER_BASIC_AUTH_REQUIRES_HTTPS, fg="red"))
if federated_only:
if not teacher_uri:
raise click.BadOptionUsage(option_name='--teacher',
message="--teacher is required for federated porter.")
message=click.style("--teacher is required for federated porter.", fg="red"))
teacher = Ursula.from_teacher_uri(teacher_uri=teacher_uri,
federated_only=True,
@ -111,11 +111,11 @@ def run(general_config,
# decentralized/blockchain
if not eth_provider_uri:
raise click.BadOptionUsage(option_name='--eth-provider',
message="--eth-provider is required for decentralized porter.")
message=click.style("--eth-provider is required for decentralized porter.", fg="red"))
if not network:
# should never happen - network defaults to 'mainnet' if not specified
raise click.BadOptionUsage(option_name='--network',
message="--network is required for decentralized porter.")
message=click.style("--network is required for decentralized porter.", "red"))
registry = get_registry(network=network, registry_filepath=registry_filepath)
teacher = None

View File

@ -161,7 +161,7 @@ def events(general_config, registry_options, contract_name, from_block, to_block
if csv or csv_file:
if csv and csv_file:
raise click.BadOptionUsage(option_name='--event-filter',
message=f'Pass either --csv or --csv-file, not both.')
message=click.style('Pass either --csv or --csv-file, not both.', fg="red"))
# ensure that event name is specified - different events would have different columns in the csv file
if csv_file and not all((event_name, contract_name)):
@ -169,11 +169,11 @@ def events(general_config, registry_options, contract_name, from_block, to_block
# - each appended event adds their column names first
# - single report-type functionality, see #2561
raise click.BadOptionUsage(option_name='--csv-file, --event-name, --contract_name',
message='--event-name and --contract-name must be specified when outputting to '
'specific file using --csv-file; alternatively use --csv')
message=click.style('--event-name and --contract-name must be specified when outputting to '
'specific file using --csv-file; alternatively use --csv', fg="red"))
if not contract_name:
if event_name:
raise click.BadOptionUsage(option_name='--event-name', message='--event-name requires --contract-name')
raise click.BadOptionUsage(option_name='--event-name', message=click.style('--event-name requires --contract-name', fg="red"))
# FIXME should we force a contract name to be specified?
else:
contract_names = [contract_name]
@ -190,8 +190,8 @@ def events(general_config, registry_options, contract_name, from_block, to_block
# validate block range
if from_block > to_block:
raise click.BadOptionUsage(option_name='--to-block, --from-block',
message=f'Invalid block range provided, '
f'from-block ({from_block}) > to-block ({to_block})')
message=click.style(f'Invalid block range provided, '
f'from-block ({from_block}) > to-block ({to_block})', fg="red"))
# event argument filters
argument_filters = None
@ -200,8 +200,8 @@ def events(general_config, registry_options, contract_name, from_block, to_block
argument_filters = parse_event_filters_into_argument_filters(event_filters)
except ValueError as e:
raise click.BadOptionUsage(option_name='--event-filter',
message=f'Event filter must be specified as name-value pairs of '
f'the form `<name>=<value>` - {str(e)}')
message=click.style(f'Event filter must be specified as name-value pairs of '
f'the form `<name>=<value>` - {str(e)}', fg="red"))
emitter.echo(f"Retrieving events from block {from_block} to {to_block}")
@ -229,7 +229,7 @@ def events(general_config, registry_options, contract_name, from_block, to_block
if event_name and event_name not in agent.events.names:
raise click.BadOptionUsage(option_name='--event-name, --contract_name',
message=f'{contract_name} contract does not have an event named {event_name}')
message=click.style(f'{contract_name} contract does not have an event named {event_name}', fg="red"))
title = f" {agent.contract_name} Events ".center(40, "-")
emitter.echo(f"\n{title}\n", bold=True, color='green')

View File

@ -103,7 +103,7 @@ class UrsulaConfigOptions:
if federated_only:
if registry_filepath or policy_registry_filepath:
raise click.BadOptionUsage(option_name="--registry-filepath",
message=f"--registry-filepath and --policy-registry-filepath cannot be used in federated mode.")
message=click.style("--registry-filepath and --policy-registry-filepath cannot be used in federated mode.", fg="red"))
self.eth_provider_uri = eth_provider_uri
self.signer_uri = signer_uri
@ -180,7 +180,7 @@ class UrsulaConfigOptions:
except FileNotFoundError:
return handle_missing_configuration_file(character_config_class=UrsulaConfiguration, config_file=config_file)
except Keystore.AuthenticationFailed as e:
emitter.echo(str(e), color='red', bold=True)
emitter.error(str(e))
# TODO: Exit codes (not only for this, but for other exceptions)
return click.get_current_context().exit(1)
@ -309,7 +309,7 @@ class UrsulaCharacterOptions:
return ursula_config, URSULA
except Keystore.AuthenticationFailed as e:
emitter.echo(str(e), color='red', bold=True)
emitter.errpr(str(e))
# TODO: Exit codes (not only for this, but for other exceptions)
return click.get_current_context().exit(1)
@ -340,7 +340,7 @@ def init(general_config, config_options, force, config_root, key_material):
if not config_root:
config_root = general_config.config_root
if not config_options.federated_only and not config_options.eth_provider_uri:
raise click.BadOptionUsage('--eth-provider', message="--eth-provider is required to initialize a new ursula.")
raise click.BadOptionUsage('--eth-provider', message=click.style("--eth-provider is required to initialize a new ursula.", fg="red"))
if not config_options.federated_only and not config_options.domain:
config_options.domain = select_network(emitter, message="Select Staking Network")
if not config_options.federated_only and not config_options.payment_network:
@ -413,7 +413,7 @@ def run(general_config, character_options, config_file, interactive, dry_run, pr
if prometheus and not metrics_port:
# Require metrics port when using prometheus
raise click.BadOptionUsage(option_name='metrics-port',
message='--metrics-port is required when using --prometheus')
message=click.style('--metrics-port is required when using --prometheus', fg="red"))
_pre_launch_warnings(emitter, dev=dev_mode, force=None)
@ -483,7 +483,7 @@ def config(general_config, config_options, config_file, force, action):
rest_host = collect_operator_ip_address(emitter=emitter, network=config_options.domain, force=force)
config_options.rest_host = rest_host
elif action:
emitter.echo(f'"{action}" is not a valid command.', color='red')
emitter.error(f'"{action}" is not a valid command.')
raise click.Abort()
updates = config_options.get_updates()
get_or_update_configuration(emitter=emitter,

View File

@ -95,7 +95,7 @@ class StdoutEmitter:
def error(self, e):
if self.verbosity >= 1:
e_str = str(e)
click.echo(message=e_str)
click.echo(message=e_str, color="red")
self.log.info(e_str)
def get_stream(self, verbosity: int = 0):