From 6c730dd5cbb333b8f23713448fac29df9cf598f9 Mon Sep 17 00:00:00 2001 From: Yao Adzaku Date: Tue, 16 Apr 2019 13:46:50 +0000 Subject: [PATCH] pipeline: print locked DVC stages (#1882) * pipeline: add option to display locked DVC stages. The '--locked' option xplicitly displays only locked DVC stages. Fixes #1864 * pipeline: support short option '-l' for displaying locked stages * pipeline: minor cosmetic tweak * pipeline: reformat code with black * pipeline: test printing of locked stages * pipeline: use caplog to ensure command outputs everything as expected * pipeline: cleanup test * pipeline: more strict comparison of test output --- dvc/command/pipeline.py | 24 ++++++++++++++++++++---- tests/test_pipeline.py | 15 +++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/dvc/command/pipeline.py b/dvc/command/pipeline.py index c30160fb9..de0c1ecd3 100644 --- a/dvc/command/pipeline.py +++ b/dvc/command/pipeline.py @@ -14,7 +14,7 @@ logger = logging.getLogger(__name__) class CmdPipelineShow(CmdBase): - def _show(self, target, commands, outs): + def _show(self, target, commands, outs, locked): import networkx from dvc.stage import Stage @@ -22,8 +22,12 @@ class CmdPipelineShow(CmdBase): G = self.repo.graph()[0] stages = networkx.get_node_attributes(G, "stage") node = os.path.relpath(stage.path, self.repo.root_dir) + nodes = networkx.dfs_postorder_nodes(G, node) - for n in networkx.dfs_postorder_nodes(G, node): + if locked: + nodes = [n for n in nodes if stages[n].locked] + + for n in nodes: if commands: logger.info(stages[n].cmd) elif outs: @@ -122,7 +126,7 @@ class CmdPipelineShow(CmdBase): simple_g.add_edges_from(edges) write_dot(simple_g, filename) - def run(self, unlock=False): + def run(self): if not self.args.targets: self.args.targets = self.default_targets @@ -144,7 +148,12 @@ class CmdPipelineShow(CmdBase): target, self.args.commands, self.args.outs ) else: - self._show(target, self.args.commands, self.args.outs) + self._show( + target, + self.args.commands, + self.args.outs, + self.args.locked, + ) except DvcException: msg = "failed to show pipeline for '{}'".format(target) logger.exception(msg) @@ -208,6 +217,13 @@ def add_parser(subparsers, parent_parser): default=False, help="Print output files instead of paths to DVC files.", ) + pipeline_show_parser.add_argument( + "-l", + "--locked", + action="store_true", + default=False, + help="Print locked DVC stages", + ) pipeline_show_parser.add_argument( "--ascii", action="store_true", diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 0bb531454..2e24bb85f 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -1,3 +1,5 @@ +import logging + from dvc.main import main from tests.basic_env import TestDvc @@ -150,6 +152,19 @@ class TestPipelineShow(TestRepro): ret = main(["pipeline", "show", "non-existing"]) self.assertNotEqual(ret, 0) + def test_print_locked_stages(self): + self.dvc.add("foo") + self.dvc.add("bar") + self.dvc.lock_stage("foo.dvc") + + self._caplog.clear() + with self._caplog.at_level(logging.INFO, logger="dvc"): + ret = main(["pipeline", "show", "foo.dvc", "--locked"]) + self.assertEqual(ret, 0) + + assert "foo.dvc" in self._caplog.text + assert "bar.dvc" not in self._caplog.text + class TestPipelineShowDeep(TestReproChangedDeepData): def setUp(self):