Loading q2cli/_version.py +3 −3 Original line number Diff line number Diff line Loading @@ -23,9 +23,9 @@ def get_keywords(): # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = " (tag: 2019.4.0)" git_full = "dc80fad32777035091692ce1083088380a6ac509" git_date = "2019-05-03 04:14:45 +0000" git_refnames = " (tag: 2019.7.0)" git_full = "06b978c96c8efce8be0c8213e744cb4b389f2bc6" git_date = "2019-07-30 18:15:53 +0000" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords Loading q2cli/builtin/dev.py +110 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ # ---------------------------------------------------------------------------- import click from q2cli.click.command import ToolCommand, ToolGroupCommand Loading @@ -29,3 +30,112 @@ def dev(): def refresh_cache(): import q2cli.core.cache q2cli.core.cache.CACHE.refresh() import_theme_help = \ ("Allows for customization of q2cli's command line styling based on an " "imported .theme (INI formatted) file. If you are unfamiliar with .ini " "formatted files look here https://en.wikipedia.org/wiki/INI_file." "\n" "\n" "The .theme file allows you to customize text on the basis of what that " "text represents with the following supported text types: command, " "option, type, default_arg, required, emphasis, problem, warning, error, " "and success. These will be your headers in the '[]' brackets. " "\n" "\n" "`command` refers to the name of the command you issued. `option` refers " "to the arguments you give to the command when running it. `type` refers " "to the QIIME 2 semantic typing of these arguments (where applicable). " "`default_arg` refers to the label next to the argument indicating its " "default value (where applicable), and if it is required (where " "applicable). `required` refers to any arguments that must be passed to " "the command for it to work and gives them special formatting on top of " "your normal `option` formatting. `emphasis` refers to any emphasized " "pieces of text within help text. `problem` refers to the text informing " "you there were issues with the command. `warning` refers to the text " "for non-fatal issues while `error` refers to the text for fatal issues." "`success` refers to text indicating a process completed as expected." "\n" "\n" "Depending on what your terminal supports, some or all of the following " "pieces of the text's formatting may be customized: bold, dim (if true " "the text's brightness is reduced), underline, blink, reverse (if true " "foreground and background colors are reversed), and finally fg " "(foreground color) and bg (background color). The first five may each " "be either true or false, while the colors may be set to any of the " "following: black, red, green, yellow, blue, magenta, cyan, white, " "bright_black, bright_red, bright_green, bright_yellow, bright_blue, " "bright_magenta, bright_cyan, or bright_white.") @dev.command(name='import-theme', short_help='Install new command line theme.', help=import_theme_help, cls=ToolCommand) @click.option('--theme', required=True, type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), help='Path to file containing new theme info') def import_theme(theme): import os import shutil from configparser import Error import q2cli.util from q2cli.core.config import CONFIG try: CONFIG.parse_file(theme) except Error as e: # If they tried to change [error] in a valid manner before we hit our # parsing error, we don't want to use their imported error settings CONFIG.styles = CONFIG.get_default_styles() header = 'Something went wrong while parsing your theme: ' q2cli.util.exit_with_error(e, header=header, traceback=None) shutil.copy(theme, os.path.join(q2cli.util.get_app_dir(), 'cli-colors.theme')) @dev.command(name='export-default-theme', short_help='Export the default settings.', help='Create a .theme (INI formatted) file from the default ' 'settings at the specified filepath.', cls=ToolCommand) @click.option('--output-path', required=True, type=click.Path(exists=False, file_okay=True, dir_okay=False, readable=True), help='Path to output the config to') def export_default_theme(output_path): import configparser from q2cli.core.config import CONFIG parser = configparser.ConfigParser() parser.read_dict(CONFIG.get_default_styles()) with open(output_path, 'w') as fh: parser.write(fh) def abort_if_false(ctx, param, value): if not value: ctx.abort() @dev.command(name='reset-theme', short_help='Reset command line theme to default.', help="Reset command line theme to default. Requres the '--yes' " "parameter to be passed asserting you do want to reset.", cls=ToolCommand) @click.option('--yes', is_flag=True, callback=abort_if_false, expose_value=False, prompt='Are you sure you want to reset your theme?') def reset_theme(): import os import q2cli.util path = os.path.join(q2cli.util.get_app_dir(), 'cli-colors.theme') if os.path.exists(path): os.unlink(path) click.echo('Theme reset.') else: click.echo('Theme was already default.') q2cli/builtin/tools.py +26 −17 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ def export_data(input_path, output_path, output_format): import qiime2.util import qiime2.sdk import distutils from q2cli.core.config import CONFIG result = qiime2.sdk.Result.load(input_path) if output_format is None: if isinstance(result, qiime2.sdk.Artifact): Loading @@ -56,7 +57,7 @@ def export_data(input_path, output_path, output_format): else: if isinstance(result, qiime2.sdk.Visualization): error = '--output-format cannot be used with visualizations' click.secho(error, fg='red', bold=True, err=True) click.echo(CONFIG.cfg_style('error', error), err=True) click.get_current_context().exit(1) else: source = result.view(qiime2.sdk.parse_format(output_format)) Loading @@ -73,7 +74,7 @@ def export_data(input_path, output_path, output_format): output_type = 'file' if os.path.isfile(output_path) else 'directory' success = 'Exported %s as %s to %s %s' % (input_path, output_format, output_type, output_path) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) def show_importable_types(ctx, param, value): Loading Loading @@ -147,6 +148,7 @@ def show_importable_formats(ctx, param, value): def import_data(type, input_path, output_path, input_format): import qiime2.sdk import qiime2.plugin from q2cli.core.config import CONFIG try: artifact = qiime2.sdk.Artifact.import_data(type, input_path, view_type=input_format) Loading @@ -163,7 +165,7 @@ def import_data(type, input_path, output_path, input_format): success = 'Imported %s as %s to %s' % (input_path, input_format, output_path) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) @tools.command(short_help='Take a peek at a QIIME 2 Artifact or ' Loading @@ -176,16 +178,17 @@ def import_data(type, input_path, output_path, input_format): metavar=_COMBO_METAVAR) def peek(path): import qiime2.sdk from q2cli.core.config import CONFIG metadata = qiime2.sdk.Result.peek(path) click.secho("UUID: ", fg="green", nl=False) click.secho(metadata.uuid) click.secho("Type: ", fg="green", nl=False) click.secho(metadata.type) click.echo(CONFIG.cfg_style('type', "UUID")+": ", nl=False) click.echo(metadata.uuid) click.echo(CONFIG.cfg_style('type', "Type")+": ", nl=False) click.echo(metadata.type) if metadata.format is not None: click.secho("Data format: ", fg="green", nl=False) click.secho(metadata.format) click.echo(CONFIG.cfg_style('type', "Data format")+": ", nl=False) click.echo(metadata.format) @tools.command('inspect-metadata', Loading Loading @@ -274,7 +277,7 @@ def _load_metadata(path): @tools.command(short_help='View a QIIME 2 Visualization.', help="Displays a QIIME 2 Visualization until the command " "exits. To open a QIIME 2 Visualization so it can be " "used after the command exits, use 'qiime extract'.", "used after the command exits, use 'qiime tools extract'.", cls=ToolCommand) @click.argument('visualization-path', metavar='VISUALIZATION', type=click.Path(exists=True, file_okay=True, dir_okay=False, Loading @@ -285,6 +288,7 @@ def _load_metadata(path): def view(visualization_path, index_extension): # Guard headless envs from having to import anything large import sys from q2cli.core.config import CONFIG if not os.getenv("DISPLAY") and sys.platform != "darwin": raise click.UsageError( 'Visualization viewing is currently not supported in headless ' Loading @@ -310,15 +314,16 @@ def view(visualization_path, index_extension): if index_extension not in index_paths: raise click.BadParameter( 'No index %s file with is present in the archive. Available index ' 'No index %s file is present in the archive. Available index ' 'extensions are: %s' % (index_extension, ', '.join(index_paths.keys()))) else: index_path = index_paths[index_extension] launch_status = click.launch(index_path) if launch_status != 0: click.echo('Viewing visualization failed while attempting to ' 'open %s' % index_path, err=True) click.echo(CONFIG.cfg_style('error', 'Viewing visualization ' 'failed while attempting to open ' f'{index_path}'), err=True) else: while True: click.echo( Loading Loading @@ -362,6 +367,7 @@ def view(visualization_path, index_extension): def extract(input_path, output_path): import zipfile import qiime2.sdk from q2cli.core.config import CONFIG try: extracted_dir = qiime2.sdk.Result.extract(input_path, output_path) Loading @@ -371,7 +377,7 @@ def extract(input_path, output_path): 'Visualizations can be extracted.' % input_path) else: success = 'Extracted %s to directory %s' % (input_path, extracted_dir) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) @tools.command(short_help='Validate data in a QIIME 2 Artifact.', Loading @@ -393,6 +399,7 @@ def extract(input_path, output_path): default='max', show_default=True) def validate(path, level): import qiime2.sdk from q2cli.core.config import CONFIG try: result = qiime2.sdk.Result.load(path) Loading @@ -411,8 +418,8 @@ def validate(path, level): 'validate result %s:' % path) q2cli.util.exit_with_error(e, header=header) else: click.secho('Result %s appears to be valid at level=%s.' % (path, level), fg="green") click.echo(CONFIG.cfg_style('success', f'Result {path} appears to be ' f'valid at level={level}.')) @tools.command(short_help='Print citations for a QIIME 2 result.', Loading @@ -425,6 +432,7 @@ def validate(path, level): def citations(path): import qiime2.sdk import io from q2cli.core.config import CONFIG ctx = click.get_current_context() try: Loading @@ -439,5 +447,6 @@ def citations(path): click.echo(fh.getvalue(), nl=False) ctx.exit(0) else: click.secho('No citations found.', fg='yellow', err=True) click.echo(CONFIG.cfg_style('problem', 'No citations found.'), err=True) ctx.exit(1) q2cli/click/command.py +20 −30 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ class BaseCommandMixin: # c6042bf2607c5be22b1efef2e42a94ffd281434c/click/core.py#L934 > # Copyright (c) 2014 by the Pallets team. def parse_args(self, ctx, args): from q2cli.core.config import CONFIG if isinstance(self, click.MultiCommand): return super().parse_args(ctx, args) Loading Loading @@ -71,14 +72,15 @@ class BaseCommandMixin: problems = 'There were some problems with the command:' else: problems = 'There was a problem with the command:' click.secho(problems.center(78, ' '), fg='yellow', err=True) click.echo(CONFIG.cfg_style('problem', problems.center(78, ' ')), err=True) for idx, e in enumerate(errors, 1): msg = click.formatting.wrap_text( e.format_message(), initial_indent=' (%d/%d%s) ' % (idx, len(errors), '?' if skip_rest else ''), subsequent_indent=' ') click.secho(msg, err=True, fg='red', bold=True) click.secho(CONFIG.cfg_style('error', msg), err=True) ctx.exit(1) ctx.args = args Loading Loading @@ -113,12 +115,14 @@ class BaseCommandMixin: # /c6042bf2607c5be22b1efef2e42a94ffd281434c/click/core.py#L830 > # Copyright (c) 2014 by the Pallets team. def format_usage(self, ctx, formatter): from q2cli.core.config import CONFIG """Writes the usage line into the formatter.""" pieces = self.collect_usage_pieces(ctx) formatter.write_usage(_style_command(ctx.command_path), formatter.write_usage(CONFIG.cfg_style('command', ctx.command_path), ' '.join(pieces)) def format_options(self, ctx, formatter, COL_MAX=23, COL_MIN=10): from q2cli.core.config import CONFIG # write options opt_groups = {} records = [] Loading Loading @@ -167,7 +171,7 @@ class BaseCommandMixin: rows = [] for subcommand, cmd in commands: help = cmd.get_short_help_str(limit) rows.append((_style_command(subcommand), help)) rows.append((CONFIG.cfg_style('command', subcommand), help)) if rows: with formatter.section(click.style('Commands', bold=True)): Loading @@ -175,6 +179,7 @@ class BaseCommandMixin: def write_option(self, ctx, formatter, opt, record, border, COL_SPACING=2): import itertools from q2cli.core.config import CONFIG full_width = formatter.width - formatter.current_indent indent_text = ' ' * formatter.current_indent opt_text, help_text = record Loading Loading @@ -208,7 +213,8 @@ class BaseCommandMixin: for token in tokens: dangling_edge += len(token) + 1 if token.startswith('--'): token = _style_option(token, required=opt.required) token = CONFIG.cfg_style('option', token, required=opt.required) styled.append(token) line = indent_text + ' '.join(styled) to_write.append(line) Loading @@ -224,11 +230,11 @@ class BaseCommandMixin: line = ' '.join(tokens) if first_iter: dangling_edge += 1 + len(line) line = " " + _style_type(line) line = " " + CONFIG.cfg_style('type', line) first_iter = False else: dangling_edge = len(type_indent) + len(line) line = type_indent + _style_type(line) line = type_indent + CONFIG.cfg_style('type', line) to_write.append(line) formatter.write('\n'.join(to_write)) Loading @@ -244,7 +250,8 @@ class BaseCommandMixin: if type_placement == 'under': padding = ' ' * (border + COL_SPACING - len(type_repr) - len(type_indent)) line = ''.join([type_indent, _style_type(type_repr), padding]) line = ''.join( [type_indent, CONFIG.cfg_style('type', type_repr), padding]) left_col.append(line) if hasattr(opt, 'meta_help') and opt.meta_help is not None: Loading Loading @@ -290,10 +297,13 @@ class BaseCommandMixin: else: pad = formatter.width - len(requirements) - dangling_edge formatter.write((' ' * pad) + _style_reqs(requirements) + '\n') formatter.write( (' ' * pad) + CONFIG.cfg_style( 'default_arg', requirements) + '\n') def _color_important(self, tokens, ctx): import re from q2cli.core.config import CONFIG for t in tokens: if '_' in t: Loading @@ -301,7 +311,7 @@ class BaseCommandMixin: if re.sub(r'[^\w]', '', t) in names: m = re.search(r'(\w+)', t) word = t[m.start():m.end()] word = _style_emphasis(word.replace('_', '-')) word = CONFIG.cfg_style('emphasis', word.replace('_', '-')) token = t[:m.start()] + word + t[m.end():] yield token continue Loading Loading @@ -353,23 +363,3 @@ def simple_wrap(text, target, start_col=0): current_width += 1 + token_len return result def _style_option(text, required=False): return click.style(text, fg='blue', underline=required) def _style_type(text): return click.style(text, fg='green') def _style_reqs(text): return click.style(text, fg='magenta') def _style_command(text): return _style_option(text) def _style_emphasis(text): return click.style(text, underline=True) q2cli/click/type.py +27 −4 Original line number Diff line number Diff line Loading @@ -46,6 +46,10 @@ class OutDirType(click.Path): return value class ControlFlowException(Exception): pass class QIIME2Type(click.ParamType): def __init__(self, type_ast, type_repr, is_output=False): self.type_repr = type_repr Loading Loading @@ -94,14 +98,33 @@ class QIIME2Type(click.ParamType): def _convert_input(self, value, param, ctx): import os import tempfile import qiime2.sdk import qiime2.sdk.util try: try: result = qiime2.sdk.Result.load(value) except OSError as e: if e.errno == 28: temp = tempfile.tempdir self.fail(f'There was not enough space left on {temp!r} ' f'to extract the artifact {value!r}. ' '(Try setting $TMPDIR to a directory with ' 'more space, or increasing the size of ' f'{temp!r})', param, ctx) else: raise ControlFlowException except ValueError as e: if 'does not exist' in str(e): self.fail(f'{value!r} is not a valid filepath', param, ctx) else: raise ControlFlowException except Exception: self.fail('%r is not a QIIME 2 Artifact (.qza)' % value, param, ctx) raise ControlFlowException except ControlFlowException: self.fail('%r is not a QIIME 2 Artifact (.qza)' % value, param, ctx) if isinstance(result, qiime2.sdk.Visualization): maybe = value[:-1] + 'a' Loading Loading
q2cli/_version.py +3 −3 Original line number Diff line number Diff line Loading @@ -23,9 +23,9 @@ def get_keywords(): # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = " (tag: 2019.4.0)" git_full = "dc80fad32777035091692ce1083088380a6ac509" git_date = "2019-05-03 04:14:45 +0000" git_refnames = " (tag: 2019.7.0)" git_full = "06b978c96c8efce8be0c8213e744cb4b389f2bc6" git_date = "2019-07-30 18:15:53 +0000" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords Loading
q2cli/builtin/dev.py +110 −0 Original line number Diff line number Diff line Loading @@ -7,6 +7,7 @@ # ---------------------------------------------------------------------------- import click from q2cli.click.command import ToolCommand, ToolGroupCommand Loading @@ -29,3 +30,112 @@ def dev(): def refresh_cache(): import q2cli.core.cache q2cli.core.cache.CACHE.refresh() import_theme_help = \ ("Allows for customization of q2cli's command line styling based on an " "imported .theme (INI formatted) file. If you are unfamiliar with .ini " "formatted files look here https://en.wikipedia.org/wiki/INI_file." "\n" "\n" "The .theme file allows you to customize text on the basis of what that " "text represents with the following supported text types: command, " "option, type, default_arg, required, emphasis, problem, warning, error, " "and success. These will be your headers in the '[]' brackets. " "\n" "\n" "`command` refers to the name of the command you issued. `option` refers " "to the arguments you give to the command when running it. `type` refers " "to the QIIME 2 semantic typing of these arguments (where applicable). " "`default_arg` refers to the label next to the argument indicating its " "default value (where applicable), and if it is required (where " "applicable). `required` refers to any arguments that must be passed to " "the command for it to work and gives them special formatting on top of " "your normal `option` formatting. `emphasis` refers to any emphasized " "pieces of text within help text. `problem` refers to the text informing " "you there were issues with the command. `warning` refers to the text " "for non-fatal issues while `error` refers to the text for fatal issues." "`success` refers to text indicating a process completed as expected." "\n" "\n" "Depending on what your terminal supports, some or all of the following " "pieces of the text's formatting may be customized: bold, dim (if true " "the text's brightness is reduced), underline, blink, reverse (if true " "foreground and background colors are reversed), and finally fg " "(foreground color) and bg (background color). The first five may each " "be either true or false, while the colors may be set to any of the " "following: black, red, green, yellow, blue, magenta, cyan, white, " "bright_black, bright_red, bright_green, bright_yellow, bright_blue, " "bright_magenta, bright_cyan, or bright_white.") @dev.command(name='import-theme', short_help='Install new command line theme.', help=import_theme_help, cls=ToolCommand) @click.option('--theme', required=True, type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True), help='Path to file containing new theme info') def import_theme(theme): import os import shutil from configparser import Error import q2cli.util from q2cli.core.config import CONFIG try: CONFIG.parse_file(theme) except Error as e: # If they tried to change [error] in a valid manner before we hit our # parsing error, we don't want to use their imported error settings CONFIG.styles = CONFIG.get_default_styles() header = 'Something went wrong while parsing your theme: ' q2cli.util.exit_with_error(e, header=header, traceback=None) shutil.copy(theme, os.path.join(q2cli.util.get_app_dir(), 'cli-colors.theme')) @dev.command(name='export-default-theme', short_help='Export the default settings.', help='Create a .theme (INI formatted) file from the default ' 'settings at the specified filepath.', cls=ToolCommand) @click.option('--output-path', required=True, type=click.Path(exists=False, file_okay=True, dir_okay=False, readable=True), help='Path to output the config to') def export_default_theme(output_path): import configparser from q2cli.core.config import CONFIG parser = configparser.ConfigParser() parser.read_dict(CONFIG.get_default_styles()) with open(output_path, 'w') as fh: parser.write(fh) def abort_if_false(ctx, param, value): if not value: ctx.abort() @dev.command(name='reset-theme', short_help='Reset command line theme to default.', help="Reset command line theme to default. Requres the '--yes' " "parameter to be passed asserting you do want to reset.", cls=ToolCommand) @click.option('--yes', is_flag=True, callback=abort_if_false, expose_value=False, prompt='Are you sure you want to reset your theme?') def reset_theme(): import os import q2cli.util path = os.path.join(q2cli.util.get_app_dir(), 'cli-colors.theme') if os.path.exists(path): os.unlink(path) click.echo('Theme reset.') else: click.echo('Theme was already default.')
q2cli/builtin/tools.py +26 −17 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ def export_data(input_path, output_path, output_format): import qiime2.util import qiime2.sdk import distutils from q2cli.core.config import CONFIG result = qiime2.sdk.Result.load(input_path) if output_format is None: if isinstance(result, qiime2.sdk.Artifact): Loading @@ -56,7 +57,7 @@ def export_data(input_path, output_path, output_format): else: if isinstance(result, qiime2.sdk.Visualization): error = '--output-format cannot be used with visualizations' click.secho(error, fg='red', bold=True, err=True) click.echo(CONFIG.cfg_style('error', error), err=True) click.get_current_context().exit(1) else: source = result.view(qiime2.sdk.parse_format(output_format)) Loading @@ -73,7 +74,7 @@ def export_data(input_path, output_path, output_format): output_type = 'file' if os.path.isfile(output_path) else 'directory' success = 'Exported %s as %s to %s %s' % (input_path, output_format, output_type, output_path) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) def show_importable_types(ctx, param, value): Loading Loading @@ -147,6 +148,7 @@ def show_importable_formats(ctx, param, value): def import_data(type, input_path, output_path, input_format): import qiime2.sdk import qiime2.plugin from q2cli.core.config import CONFIG try: artifact = qiime2.sdk.Artifact.import_data(type, input_path, view_type=input_format) Loading @@ -163,7 +165,7 @@ def import_data(type, input_path, output_path, input_format): success = 'Imported %s as %s to %s' % (input_path, input_format, output_path) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) @tools.command(short_help='Take a peek at a QIIME 2 Artifact or ' Loading @@ -176,16 +178,17 @@ def import_data(type, input_path, output_path, input_format): metavar=_COMBO_METAVAR) def peek(path): import qiime2.sdk from q2cli.core.config import CONFIG metadata = qiime2.sdk.Result.peek(path) click.secho("UUID: ", fg="green", nl=False) click.secho(metadata.uuid) click.secho("Type: ", fg="green", nl=False) click.secho(metadata.type) click.echo(CONFIG.cfg_style('type', "UUID")+": ", nl=False) click.echo(metadata.uuid) click.echo(CONFIG.cfg_style('type', "Type")+": ", nl=False) click.echo(metadata.type) if metadata.format is not None: click.secho("Data format: ", fg="green", nl=False) click.secho(metadata.format) click.echo(CONFIG.cfg_style('type', "Data format")+": ", nl=False) click.echo(metadata.format) @tools.command('inspect-metadata', Loading Loading @@ -274,7 +277,7 @@ def _load_metadata(path): @tools.command(short_help='View a QIIME 2 Visualization.', help="Displays a QIIME 2 Visualization until the command " "exits. To open a QIIME 2 Visualization so it can be " "used after the command exits, use 'qiime extract'.", "used after the command exits, use 'qiime tools extract'.", cls=ToolCommand) @click.argument('visualization-path', metavar='VISUALIZATION', type=click.Path(exists=True, file_okay=True, dir_okay=False, Loading @@ -285,6 +288,7 @@ def _load_metadata(path): def view(visualization_path, index_extension): # Guard headless envs from having to import anything large import sys from q2cli.core.config import CONFIG if not os.getenv("DISPLAY") and sys.platform != "darwin": raise click.UsageError( 'Visualization viewing is currently not supported in headless ' Loading @@ -310,15 +314,16 @@ def view(visualization_path, index_extension): if index_extension not in index_paths: raise click.BadParameter( 'No index %s file with is present in the archive. Available index ' 'No index %s file is present in the archive. Available index ' 'extensions are: %s' % (index_extension, ', '.join(index_paths.keys()))) else: index_path = index_paths[index_extension] launch_status = click.launch(index_path) if launch_status != 0: click.echo('Viewing visualization failed while attempting to ' 'open %s' % index_path, err=True) click.echo(CONFIG.cfg_style('error', 'Viewing visualization ' 'failed while attempting to open ' f'{index_path}'), err=True) else: while True: click.echo( Loading Loading @@ -362,6 +367,7 @@ def view(visualization_path, index_extension): def extract(input_path, output_path): import zipfile import qiime2.sdk from q2cli.core.config import CONFIG try: extracted_dir = qiime2.sdk.Result.extract(input_path, output_path) Loading @@ -371,7 +377,7 @@ def extract(input_path, output_path): 'Visualizations can be extracted.' % input_path) else: success = 'Extracted %s to directory %s' % (input_path, extracted_dir) click.secho(success, fg='green') click.echo(CONFIG.cfg_style('success', success)) @tools.command(short_help='Validate data in a QIIME 2 Artifact.', Loading @@ -393,6 +399,7 @@ def extract(input_path, output_path): default='max', show_default=True) def validate(path, level): import qiime2.sdk from q2cli.core.config import CONFIG try: result = qiime2.sdk.Result.load(path) Loading @@ -411,8 +418,8 @@ def validate(path, level): 'validate result %s:' % path) q2cli.util.exit_with_error(e, header=header) else: click.secho('Result %s appears to be valid at level=%s.' % (path, level), fg="green") click.echo(CONFIG.cfg_style('success', f'Result {path} appears to be ' f'valid at level={level}.')) @tools.command(short_help='Print citations for a QIIME 2 result.', Loading @@ -425,6 +432,7 @@ def validate(path, level): def citations(path): import qiime2.sdk import io from q2cli.core.config import CONFIG ctx = click.get_current_context() try: Loading @@ -439,5 +447,6 @@ def citations(path): click.echo(fh.getvalue(), nl=False) ctx.exit(0) else: click.secho('No citations found.', fg='yellow', err=True) click.echo(CONFIG.cfg_style('problem', 'No citations found.'), err=True) ctx.exit(1)
q2cli/click/command.py +20 −30 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ class BaseCommandMixin: # c6042bf2607c5be22b1efef2e42a94ffd281434c/click/core.py#L934 > # Copyright (c) 2014 by the Pallets team. def parse_args(self, ctx, args): from q2cli.core.config import CONFIG if isinstance(self, click.MultiCommand): return super().parse_args(ctx, args) Loading Loading @@ -71,14 +72,15 @@ class BaseCommandMixin: problems = 'There were some problems with the command:' else: problems = 'There was a problem with the command:' click.secho(problems.center(78, ' '), fg='yellow', err=True) click.echo(CONFIG.cfg_style('problem', problems.center(78, ' ')), err=True) for idx, e in enumerate(errors, 1): msg = click.formatting.wrap_text( e.format_message(), initial_indent=' (%d/%d%s) ' % (idx, len(errors), '?' if skip_rest else ''), subsequent_indent=' ') click.secho(msg, err=True, fg='red', bold=True) click.secho(CONFIG.cfg_style('error', msg), err=True) ctx.exit(1) ctx.args = args Loading Loading @@ -113,12 +115,14 @@ class BaseCommandMixin: # /c6042bf2607c5be22b1efef2e42a94ffd281434c/click/core.py#L830 > # Copyright (c) 2014 by the Pallets team. def format_usage(self, ctx, formatter): from q2cli.core.config import CONFIG """Writes the usage line into the formatter.""" pieces = self.collect_usage_pieces(ctx) formatter.write_usage(_style_command(ctx.command_path), formatter.write_usage(CONFIG.cfg_style('command', ctx.command_path), ' '.join(pieces)) def format_options(self, ctx, formatter, COL_MAX=23, COL_MIN=10): from q2cli.core.config import CONFIG # write options opt_groups = {} records = [] Loading Loading @@ -167,7 +171,7 @@ class BaseCommandMixin: rows = [] for subcommand, cmd in commands: help = cmd.get_short_help_str(limit) rows.append((_style_command(subcommand), help)) rows.append((CONFIG.cfg_style('command', subcommand), help)) if rows: with formatter.section(click.style('Commands', bold=True)): Loading @@ -175,6 +179,7 @@ class BaseCommandMixin: def write_option(self, ctx, formatter, opt, record, border, COL_SPACING=2): import itertools from q2cli.core.config import CONFIG full_width = formatter.width - formatter.current_indent indent_text = ' ' * formatter.current_indent opt_text, help_text = record Loading Loading @@ -208,7 +213,8 @@ class BaseCommandMixin: for token in tokens: dangling_edge += len(token) + 1 if token.startswith('--'): token = _style_option(token, required=opt.required) token = CONFIG.cfg_style('option', token, required=opt.required) styled.append(token) line = indent_text + ' '.join(styled) to_write.append(line) Loading @@ -224,11 +230,11 @@ class BaseCommandMixin: line = ' '.join(tokens) if first_iter: dangling_edge += 1 + len(line) line = " " + _style_type(line) line = " " + CONFIG.cfg_style('type', line) first_iter = False else: dangling_edge = len(type_indent) + len(line) line = type_indent + _style_type(line) line = type_indent + CONFIG.cfg_style('type', line) to_write.append(line) formatter.write('\n'.join(to_write)) Loading @@ -244,7 +250,8 @@ class BaseCommandMixin: if type_placement == 'under': padding = ' ' * (border + COL_SPACING - len(type_repr) - len(type_indent)) line = ''.join([type_indent, _style_type(type_repr), padding]) line = ''.join( [type_indent, CONFIG.cfg_style('type', type_repr), padding]) left_col.append(line) if hasattr(opt, 'meta_help') and opt.meta_help is not None: Loading Loading @@ -290,10 +297,13 @@ class BaseCommandMixin: else: pad = formatter.width - len(requirements) - dangling_edge formatter.write((' ' * pad) + _style_reqs(requirements) + '\n') formatter.write( (' ' * pad) + CONFIG.cfg_style( 'default_arg', requirements) + '\n') def _color_important(self, tokens, ctx): import re from q2cli.core.config import CONFIG for t in tokens: if '_' in t: Loading @@ -301,7 +311,7 @@ class BaseCommandMixin: if re.sub(r'[^\w]', '', t) in names: m = re.search(r'(\w+)', t) word = t[m.start():m.end()] word = _style_emphasis(word.replace('_', '-')) word = CONFIG.cfg_style('emphasis', word.replace('_', '-')) token = t[:m.start()] + word + t[m.end():] yield token continue Loading Loading @@ -353,23 +363,3 @@ def simple_wrap(text, target, start_col=0): current_width += 1 + token_len return result def _style_option(text, required=False): return click.style(text, fg='blue', underline=required) def _style_type(text): return click.style(text, fg='green') def _style_reqs(text): return click.style(text, fg='magenta') def _style_command(text): return _style_option(text) def _style_emphasis(text): return click.style(text, underline=True)
q2cli/click/type.py +27 −4 Original line number Diff line number Diff line Loading @@ -46,6 +46,10 @@ class OutDirType(click.Path): return value class ControlFlowException(Exception): pass class QIIME2Type(click.ParamType): def __init__(self, type_ast, type_repr, is_output=False): self.type_repr = type_repr Loading Loading @@ -94,14 +98,33 @@ class QIIME2Type(click.ParamType): def _convert_input(self, value, param, ctx): import os import tempfile import qiime2.sdk import qiime2.sdk.util try: try: result = qiime2.sdk.Result.load(value) except OSError as e: if e.errno == 28: temp = tempfile.tempdir self.fail(f'There was not enough space left on {temp!r} ' f'to extract the artifact {value!r}. ' '(Try setting $TMPDIR to a directory with ' 'more space, or increasing the size of ' f'{temp!r})', param, ctx) else: raise ControlFlowException except ValueError as e: if 'does not exist' in str(e): self.fail(f'{value!r} is not a valid filepath', param, ctx) else: raise ControlFlowException except Exception: self.fail('%r is not a QIIME 2 Artifact (.qza)' % value, param, ctx) raise ControlFlowException except ControlFlowException: self.fail('%r is not a QIIME 2 Artifact (.qza)' % value, param, ctx) if isinstance(result, qiime2.sdk.Visualization): maybe = value[:-1] + 'a' Loading