[med-svn] [Git][med-team/q2cli][upstream] New upstream version 2020.11.0

Étienne Mollier gitlab at salsa.debian.org
Wed Dec 2 14:13:33 GMT 2020



Étienne Mollier pushed to branch upstream at Debian Med / q2cli


Commits:
4248084e by Étienne Mollier at 2020-12-02T13:45:51+01:00
New upstream version 2020.11.0
- - - - -


30 changed files:

- .travis.yml
- LICENSE
- Makefile
- ci/recipe/meta.yaml
- q2cli/__init__.py
- q2cli/__main__.py
- q2cli/_version.py
- q2cli/builtin/__init__.py
- q2cli/builtin/dev.py
- q2cli/builtin/info.py
- q2cli/builtin/tools.py
- q2cli/click/__init__.py
- q2cli/click/command.py
- q2cli/click/option.py
- q2cli/click/parser.py
- q2cli/click/type.py
- q2cli/commands.py
- q2cli/core/__init__.py
- q2cli/core/cache.py
- q2cli/core/completion.py
- q2cli/core/config.py
- + q2cli/core/usage.py
- q2cli/tests/__init__.py
- q2cli/tests/test_cli.py
- q2cli/tests/test_core.py
- q2cli/tests/test_dev.py
- q2cli/tests/test_tools.py
- + q2cli/tests/test_usage.py
- q2cli/util.py
- setup.py


Changes:

=====================================
.travis.yml
=====================================
@@ -14,7 +14,6 @@ install:
   - wget -q https://raw.githubusercontent.com/qiime2/environment-files/master/latest/staging/qiime2-latest-py36-linux-conda.yml
   - conda env create -q -n test-env --file qiime2-latest-py36-linux-conda.yml
   - source activate test-env
-  - conda install -q nose
   - pip install -q flake8
   - pip install -q https://github.com/qiime2/q2lint/archive/master.zip
   - make install


=====================================
LICENSE
=====================================
@@ -1,6 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2016-2019, QIIME 2 development team.
+Copyright (c) 2016-2020, QIIME 2 development team.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without


=====================================
Makefile
=====================================
@@ -10,7 +10,7 @@ lint:
 	flake8
 
 test: all
-	QIIMETEST= nosetests
+	QIIMETEST= pytest
 
 install: all
 	$(PYTHON) setup.py install && \


=====================================
ci/recipe/meta.yaml
=====================================
@@ -18,6 +18,8 @@ requirements:
   host:
     - python  {{ python }}
     - setuptools
+    # q2cli leverages pytest functionality
+    - pytest
 
   run:
     - python  {{ python }}


=====================================
q2cli/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/__main__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/_version.py
=====================================
@@ -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.10.0)"
-    git_full = "271df1dcf0c419046811dd20832f9c13446732f8"
-    git_date = "2019-11-01 01:04:25 +0000"
+    git_refnames = " (HEAD -> master, tag: 2020.11.0)"
+    git_full = "e09576b507ecee9df78ed142aacad6dd595654ca"
+    git_date = "2020-11-25 17:13:09 +0000"
     keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
     return keywords
 


=====================================
q2cli/builtin/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/builtin/dev.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/builtin/info.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/builtin/tools.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/click/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/click/command.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/click/option.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/click/parser.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/click/type.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -105,6 +105,7 @@ class QIIME2Type(click.ParamType):
         import tempfile
         import qiime2.sdk
         import qiime2.sdk.util
+        import q2cli.util
 
         try:
             try:
@@ -124,8 +125,13 @@ class QIIME2Type(click.ParamType):
                     self.fail(f'{value!r} is not a valid filepath', param, ctx)
                 else:
                     raise ControlFlowException
-            except Exception:
-                raise ControlFlowException
+            except Exception as e:
+                # If we made it here, QIIME 2 was confident that the thing we
+                # are trying to load is a QIIME 2 Result, however, we have run
+                # into some kind of catastrophic error.
+                header = ('There was a problem loading %s as a '
+                          'QIIME 2 Result:' % value)
+                q2cli.util.exit_with_error(e, header=header)
         except ControlFlowException:
             self.fail('%r is not a QIIME 2 Artifact (.qza)' % value, param,
                       ctx)
@@ -185,7 +191,7 @@ class QIIME2Type(click.ParamType):
                 metadata_column = metadata.get_column(column)
             except Exception:
                 self.fail("There was an issue with retrieving column %r from "
-                          "the metadata:" % column)
+                          "the metadata." % column)
 
             if metadata_column not in self.type_expr:
                 self.fail("Metadata column is of type %r, but expected %r."


=====================================
q2cli/commands.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -219,6 +219,7 @@ class ActionCommand(BaseCommandMixin, click.Command):
                               'during execution of this action. Or silence '
                               'output if execution is successful (silence is '
                               'golden).'),
+            q2cli.util.usage_example_option(self._get_action),
             q2cli.util.citations_option(self._get_citation_records)
         ]
 


=====================================
q2cli/core/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/core/cache.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -265,6 +265,7 @@ class DeploymentCache:
 
     def _get_action_state(self, action):
         import itertools
+        from q2cli.core.usage import cache_examples
 
         state = {
             'id': action.id,
@@ -272,6 +273,7 @@ class DeploymentCache:
             'description': action.description,
             'signature': [],
             'deprecated': action.deprecated,
+            'examples': cache_examples(action)
         }
 
         sig = action.signature


=====================================
q2cli/core/completion.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/core/config.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/core/usage.py
=====================================
@@ -0,0 +1,220 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2016-2020, QIIME 2 development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE, distributed with this software.
+# ----------------------------------------------------------------------------
+
+import textwrap
+
+from qiime2.sdk import usage, util
+
+from q2cli.util import to_cli_name
+
+
+def is_collection(val):
+    return isinstance(val, list) or isinstance(val, set)
+
+
+class CLIUsage(usage.Usage):
+    def __init__(self):
+        super().__init__()
+        self._cache_recorder = []
+
+    def cache(self):
+        return self._cache_recorder
+
+    def _add_cache_record(self, source, value):
+        record = dict(source=source, value=value)
+        self._cache_recorder.append(record)
+
+    def _init_data_(self, ref, factory):
+        return ref
+
+    def _init_metadata_(self, ref, factory):
+        return ref
+
+    def _init_data_collection_(self, ref, collection_type, records):
+        # All collection types are saved as a list, for ordering,
+        # and for JSON serialization.
+        return sorted([r.ref for r in records])
+
+    def _merge_metadata_(self, ref, records):
+        return sorted([r.ref for r in records])
+
+    def _get_metadata_column_(self, column_name, record):
+        # Returns a list for JSON serialization.
+        return [record.ref, column_name]
+
+    def _comment_(self, text):
+        self._add_cache_record(source='comment', value=text)
+
+    def _action_(self, action, input_opts, output_opts):
+        action_f, action_sig = action.get_action()
+        signature = self._destructure_signature(action_sig)
+        inputs, params, mds, outputs = self._destructure_opts(
+            signature, input_opts, output_opts)
+
+        value = dict(plugin_id=action_f.plugin_id, action_id=action_f.id,
+                     inputs=inputs, params=params, mds=mds, outputs=outputs)
+        self._add_cache_record(source='action', value=value)
+        return output_opts
+
+    def _assert_has_line_matching_(self, ref, label, path, expression):
+        # TODO: implement this method - we can model the
+        # `assert_has_line_matching` behavior that @thermokarst added
+        # to galaxy.
+        pass
+
+    def _destructure_signature(self, action_sig):
+        # In the future this could return a more robust spec subset,
+        # if necessary.
+        def distill_spec(spec):
+            return str(spec.qiime_type)
+
+        inputs = {k: distill_spec(v) for k, v in action_sig.inputs.items()}
+        outputs = {k: distill_spec(v) for k, v in action_sig.outputs.items()}
+        params, mds = {}, {}
+
+        for param_name, spec in action_sig.inputs.items():
+            inputs[param_name] = distill_spec(spec)
+
+        for param_name, spec in action_sig.parameters.items():
+            if util.is_metadata_type(spec.qiime_type):
+                mds[param_name] = distill_spec(spec)
+            else:
+                params[param_name] = distill_spec(spec)
+
+        return {'inputs': inputs, 'params': params,
+                'mds': mds, 'outputs': outputs}
+
+    def _destructure_opts(self, signature, input_opts, output_opts):
+        inputs, params, mds, outputs = {}, {}, {}, {}
+
+        for opt_name, val in input_opts.items():
+            if opt_name in signature['inputs'].keys():
+                inputs[opt_name] = (val, signature['inputs'][opt_name])
+            elif opt_name in signature['params'].keys():
+                # Coerce all collection types into lists, to
+                # allow for JSON serialization.
+                if is_collection(val):
+                    val = list(val)
+                params[opt_name] = (val, signature['params'][opt_name])
+            elif opt_name in signature['mds'].keys():
+                mds[opt_name] = (val, signature['mds'][opt_name])
+
+        for opt_name, val in output_opts.items():
+            outputs[opt_name] = (val, signature['outputs'][opt_name])
+
+        return inputs, params, mds, outputs
+
+
+class CLIRenderer:
+    def __init__(self, records):
+        self.cache_records = records
+
+    def render(self):
+        if len(self.cache_records) == 0:
+            yield 'No examples have been registered for this action yet.'
+        else:
+            for record in self.cache_records:
+                yield self.dispatch(record)
+
+    def dispatch(self, record):
+        source = record['source']
+
+        if source == 'comment':
+            return self.template_comment(record['value'])
+        elif source == 'action':
+            return self.template_action(
+                record['value']['plugin_id'],
+                record['value']['action_id'],
+                record['value']['inputs'],
+                record['value']['params'],
+                record['value']['mds'],
+                record['value']['outputs'],
+            )
+        else:
+            raise Exception
+
+    def template_comment(self, comment):
+        return f'# {comment}'
+
+    def template_action(self, plugin_id, action_id,
+                        inputs, params, mds, outputs):
+        templates = [
+            *list(self._template_inputs(inputs)),
+            *list(self._template_parameters(params)),
+            *list(self._template_metadata(mds)),
+            *list(self._template_outputs(outputs)),
+        ]
+
+        base_cmd = to_cli_name(f'qiime {plugin_id} {action_id}')
+        action_t = self._format_templates(base_cmd, templates)
+        return action_t
+
+    def _format_templates(self, command, templates):
+        wrapper = textwrap.TextWrapper(initial_indent=' ' * 4)
+        templates = [command] + [wrapper.fill(t) for t in templates]
+        return ' \\\n'.join(templates)
+
+    def _template_inputs(self, input_opts):
+        for opt_name, (ref, _) in input_opts.items():
+            refs = ref if isinstance(ref, list) else [ref]
+            for ref in refs:
+                opt_name = to_cli_name(opt_name)
+                yield f'--i-{opt_name} {ref}.qza'
+
+    def _template_parameters(self, param_opts):
+        for opt_name, (val, _) in param_opts.items():
+            vals = val if is_collection(val) else [val]
+            for val in sorted(vals):
+                opt_name = to_cli_name(opt_name)
+                yield f'--p-{opt_name} {val}'
+
+    def _template_metadata(self, md_opts):
+        for opt_name, (ref, qiime_type) in md_opts.items():
+            qiime_type = util.parse_type(qiime_type)
+            is_mdc = util.is_metadata_column_type(qiime_type)
+            # Make this into a tuple to differentiate in the following loop
+            ref = tuple(ref) if is_mdc else ref
+            refs = ref if isinstance(ref, list) else [ref]
+            for ref in refs:
+                opt_name = to_cli_name(opt_name)
+                ref, col = ref if is_mdc else (ref, None)
+                yield f'--m-{opt_name}-file {ref}.tsv'
+                if col is not None:
+                    yield f'--m-{opt_name}-column \'{col}\''
+
+    def _template_outputs(self, output_opts):
+        for opt_name, (ref, qiime_type) in output_opts.items():
+            opt_name = to_cli_name(opt_name)
+            qiime_type = util.parse_type(qiime_type)
+            ext = 'qzv' if util.is_visualization_type(qiime_type) else 'qza'
+            yield f'--o-{opt_name} {ref}.{ext}'
+
+
+def cache_examples(action):
+    all_examples = []
+    for example in action.examples:
+        use = CLIUsage()
+        header = str(example).replace('_', ' ')
+        use._comment_(f'### example: {header} ###')
+        action.examples[example](use)
+        cache = use.cache()
+        all_examples.extend(cache)
+    return all_examples
+
+
+def examples(action):
+    import q2cli.core.cache
+
+    plugin_id = to_cli_name(action.plugin_id)
+    cached_plugin = q2cli.core.cache.CACHE.plugins[plugin_id]
+    cached_action = cached_plugin['actions'][action.id]
+    cached_examples = cached_action['examples']
+
+    cache_render = CLIRenderer(cached_examples)
+    for rendered in cache_render.render():
+        yield rendered


=====================================
q2cli/tests/__init__.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/tests/test_cli.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -311,6 +311,22 @@ class CliTests(unittest.TestCase):
                                         f'{temp!r}'):
                 obj._convert_input(self.artifact1_path, None, None)
 
+    def test_syntax_error_in_env(self):
+        qiime_cli = RootCommand()
+        command = qiime_cli.get_command(ctx=None, name='dummy-plugin')
+
+        viz_path = os.path.join(self.tempdir, 'viz')
+
+        with unittest.mock.patch('qiime2.sdk.Result.load',
+                                 side_effect=SyntaxError):
+            result = self.runner.invoke(
+                command, ['most-common-viz', '--i-ints', self.artifact1_path,
+                          '--o-visualization', viz_path, '--verbose'])
+
+        self.assertEqual(result.exit_code, 1)
+        self.assertTrue('problem loading' in result.output)
+        self.assertTrue(self.artifact1_path in result.output)
+
     def test_deprecated_help_text(self):
         qiime_cli = RootCommand()
         command = qiime_cli.get_command(ctx=None, name='dummy-plugin')
@@ -340,6 +356,26 @@ class CliTests(unittest.TestCase):
 
         self.assertTrue('deprecated' in result.output)
 
+    def test_examples(self):
+        qiime_cli = RootCommand()
+        command = qiime_cli.get_command(ctx=None, name='dummy-plugin')
+        result = self.runner.invoke(
+            command, ['typical-pipeline', '--examples']
+        )
+        self.assertEqual(result.exit_code, 0)
+
+    def test_no_examples(self):
+        qiime_cli = RootCommand()
+        command = qiime_cli.get_command(ctx=None, name='dummy-plugin')
+        result = self.runner.invoke(
+            command, ['unioned-primitives', '--examples']
+        )
+        self.assertEqual(result.exit_code, 0)
+        self.assertEqual(
+            result.output,
+            "No examples have been registered for this action yet.\n"
+        )
+
 
 class TestOptionalArtifactSupport(unittest.TestCase):
     def setUp(self):
@@ -473,7 +509,7 @@ class TestMetadataSupport(MetadataTestsBase):
 
         self.assertEqual(result.exit_code, 1)
         self.assertTrue(result.output.startswith('Usage:'))
-        self.assertIn("Missing option \"--m-metadata-file\"", result.output)
+        self.assertIn("Missing option '--m-metadata-file'", result.output)
 
     def test_optional_metadata_missing(self):
         result = self._run_command(
@@ -557,7 +593,7 @@ class TestMetadataColumnSupport(MetadataTestsBase):
 
         self.assertEqual(result.exit_code, 1)
         self.assertTrue(result.output.startswith('Usage:'))
-        self.assertIn("Missing option \"--m-metadata-file\"", result.output)
+        self.assertIn("Missing option '--m-metadata-file'", result.output)
 
     def test_optional_metadata_missing(self):
         result = self._run_command(
@@ -575,7 +611,7 @@ class TestMetadataColumnSupport(MetadataTestsBase):
 
         self.assertEqual(result.exit_code, 1)
         self.assertTrue(result.output.startswith('Usage:'))
-        self.assertIn("Missing option \"--m-metadata-column\"", result.output)
+        self.assertIn("Missing option '--m-metadata-column'", result.output)
 
     def test_optional_column_without_metadata(self):
         result = self._run_command(
@@ -585,7 +621,7 @@ class TestMetadataColumnSupport(MetadataTestsBase):
 
         self.assertEqual(result.exit_code, 1)
         self.assertTrue(result.output.startswith('Usage:'))
-        self.assertIn("Missing option \"--m-metadata-file\"", result.output)
+        self.assertIn("Missing option '--m-metadata-file'", result.output)
 
     def test_single_metadata(self):
         for command in ('identity-with-metadata-column',


=====================================
q2cli/tests/test_core.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/tests/test_dev.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/tests/test_tools.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #


=====================================
q2cli/tests/test_usage.py
=====================================
@@ -0,0 +1,160 @@
+# ----------------------------------------------------------------------------
+# Copyright (c) 2016-2020, QIIME 2 development team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file LICENSE, distributed with this software.
+# ----------------------------------------------------------------------------
+
+import pytest
+
+from q2cli.core.usage import examples
+
+from qiime2.core.testing.util import get_dummy_plugin
+
+
+ at pytest.fixture
+def dummy_plugin(monkeypatch):
+    monkeypatch.setenv('QIIMETEST', '')
+    return get_dummy_plugin()
+
+
+params = [
+    (
+        'concatenate_ints',
+        """\
+# ### example: concatenate ints simple ###
+# This example demonstrates basic usage.
+qiime dummy-plugin concatenate-ints \\
+    --i-ints1 ints_a.qza \\
+    --i-ints2 ints_b.qza \\
+    --i-ints3 ints_c.qza \\
+    --p-int1 4 \\
+    --p-int2 2 \\
+    --o-concatenated-ints ints_d.qza
+# ### example: concatenate ints complex ###
+# This example demonstrates chained usage (pt 1).
+qiime dummy-plugin concatenate-ints \\
+    --i-ints1 ints_a.qza \\
+    --i-ints2 ints_b.qza \\
+    --i-ints3 ints_c.qza \\
+    --p-int1 4 \\
+    --p-int2 2 \\
+    --o-concatenated-ints ints_d.qza
+# This example demonstrates chained usage (pt 2).
+qiime dummy-plugin concatenate-ints \\
+    --i-ints1 ints_d.qza \\
+    --i-ints2 ints_b.qza \\
+    --i-ints3 ints_c.qza \\
+    --p-int1 41 \\
+    --p-int2 0 \\
+    --o-concatenated-ints concatenated_ints.qza
+# ### example: comments only ###
+# comment 1
+# comment 2""",
+    ),
+    (
+        'identity_with_metadata',
+        """\
+# ### example: identity with metadata simple ###
+qiime dummy-plugin identity-with-metadata \\
+    --i-ints ints.qza \\
+    --m-metadata-file md.tsv \\
+    --o-out out.qza
+# ### example: identity with metadata merging ###
+qiime dummy-plugin identity-with-metadata \\
+    --i-ints ints.qza \\
+    --m-metadata-file md1.tsv \\
+    --m-metadata-file md2.tsv \\
+    --o-out out.qza""",
+    ),
+    (
+        'identity_with_metadata_column',
+        """\
+# ### example: identity with metadata column get mdc ###
+qiime dummy-plugin identity-with-metadata-column \\
+    --i-ints ints.qza \\
+    --m-metadata-file md.tsv \\
+    --m-metadata-column 'a' \\
+    --o-out out.qza""",
+    ),
+    (
+        'typical_pipeline',
+        """\
+# ### example: typical pipeline simple ###
+qiime dummy-plugin typical-pipeline \\
+    --i-int-sequence ints.qza \\
+    --i-mapping mapper.qza \\
+    --p-do-extra-thing True \\
+    --o-out-map out_map.qza \\
+    --o-left left.qza \\
+    --o-right right.qza \\
+    --o-left-viz left_viz.qzv \\
+    --o-right-viz right_viz.qzv
+# ### example: typical pipeline complex ###
+qiime dummy-plugin typical-pipeline \\
+    --i-int-sequence ints1.qza \\
+    --i-mapping mapper1.qza \\
+    --p-do-extra-thing True \\
+    --o-out-map out_map1.qza \\
+    --o-left left1.qza \\
+    --o-right right1.qza \\
+    --o-left-viz left_viz1.qzv \\
+    --o-right-viz right_viz1.qzv
+qiime dummy-plugin typical-pipeline \\
+    --i-int-sequence left1.qza \\
+    --i-mapping out_map1.qza \\
+    --p-do-extra-thing False \\
+    --o-out-map out_map2.qza \\
+    --o-left left2.qza \\
+    --o-right right2.qza \\
+    --o-left-viz left_viz2.qzv \\
+    --o-right-viz right_viz2.qzv""",
+    ),
+    (
+        'optional_artifacts_method',
+        """\
+# ### example: optional inputs ###
+qiime dummy-plugin optional-artifacts-method \\
+    --i-ints ints.qza \\
+    --p-num1 1 \\
+    --o-output output.qza
+qiime dummy-plugin optional-artifacts-method \\
+    --i-ints ints.qza \\
+    --p-num1 1 \\
+    --p-num2 2 \\
+    --o-output output.qza
+qiime dummy-plugin optional-artifacts-method \\
+    --i-ints ints.qza \\
+    --p-num1 1 \\
+    --p-num2 None \\
+    --o-output ints_b.qza
+qiime dummy-plugin optional-artifacts-method \\
+    --i-ints ints.qza \\
+    --i-optional1 ints_b.qza \\
+    --p-num1 3 \\
+    --p-num2 4 \\
+    --o-output output.qza""",
+    ),
+    (
+        'variadic_input_method',
+        """\
+# ### example: variadic input simple ###
+qiime dummy-plugin variadic-input-method \\
+    --i-ints ints_a.qza \\
+    --i-ints ints_b.qza \\
+    --i-int-set single_int1.qza \\
+    --i-int-set single_int2.qza \\
+    --p-nums 7 \\
+    --p-nums 8 \\
+    --p-nums 9 \\
+    --o-output out.qza""",
+    ),
+]
+
+
+ at pytest.mark.parametrize('action, exp', params)
+def test_examples(dummy_plugin, action, exp):
+    action = dummy_plugin.actions[action]
+    result = list(examples(action))
+    assert exp == '\n'.join(result)


=====================================
q2cli/util.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #
@@ -36,6 +36,10 @@ def to_cli_name(name):
     return name.replace('_', '-')
 
 
+def to_snake_case(name):
+    return name.replace('-', '_')
+
+
 def exit_with_error(e, header='An error has been encountered:',
                     traceback='stderr', status=1):
     import sys
@@ -178,3 +182,23 @@ def citations_option(get_citation_records):
     return click.Option(['--citations'], is_flag=True, expose_value=False,
                         is_eager=True, callback=callback,
                         help='Show citations and exit.')
+
+
+def usage_example_option(action):
+    import click
+    from q2cli.core.usage import examples
+
+    def callback(ctx, param, value):
+        if not value or ctx.resilient_parsing:
+            return
+
+        action = ctx.command._get_action()
+
+        for line in examples(action):
+            click.secho(line)
+
+        ctx.exit()
+
+    return click.Option(['--examples'], is_flag=True, expose_value=False,
+                        is_eager=True, callback=callback,
+                        help='Show usage examples and exit.')


=====================================
setup.py
=====================================
@@ -1,5 +1,5 @@
 # ----------------------------------------------------------------------------
-# Copyright (c) 2016-2019, QIIME 2 development team.
+# Copyright (c) 2016-2020, QIIME 2 development team.
 #
 # Distributed under the terms of the Modified BSD License.
 #



View it on GitLab: https://salsa.debian.org/med-team/q2cli/-/commit/4248084e94472cf7195715369d515502741dfcd1

-- 
View it on GitLab: https://salsa.debian.org/med-team/q2cli/-/commit/4248084e94472cf7195715369d515502741dfcd1
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20201202/c38437e9/attachment-0001.html>


More information about the debian-med-commit mailing list