diff --git a/dvc/cli.py b/dvc/cli.py index 49a3bc9f5..e986c8b38 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -27,7 +27,7 @@ from .command import ( move, params, pipeline, - plot, + plots, remote, remove, repro, @@ -74,7 +74,7 @@ COMMANDS = [ version, update, git_hook, - plot, + plots, ] diff --git a/dvc/command/plot.py b/dvc/command/plots.py similarity index 70% rename from dvc/command/plot.py rename to dvc/command/plots.py index 0e29c9c99..07761eef4 100644 --- a/dvc/command/plot.py +++ b/dvc/command/plots.py @@ -4,12 +4,12 @@ import os from dvc.command.base import CmdBase, append_doc_link, fix_subparsers from dvc.exceptions import DvcException -from dvc.repo.plot.data import WORKSPACE_REVISION_NAME +from dvc.repo.plots.data import WORKSPACE_REVISION_NAME logger = logging.getLogger(__name__) -class CmdPLot(CmdBase): +class CmdPlots(CmdBase): def _revisions(self): raise NotImplementedError @@ -79,12 +79,12 @@ class CmdPLot(CmdBase): return 0 -class CmdPlotShow(CmdPLot): +class CmdPlotsShow(CmdPlots): def _revisions(self): return None -class CmdPlotDiff(CmdPLot): +class CmdPlotsDiff(CmdPlots): def _revisions(self): revisions = self.args.revisions or [] if len(revisions) <= 1: @@ -95,143 +95,151 @@ class CmdPlotDiff(CmdPLot): def add_parser(subparsers, parent_parser): - PLOT_HELP = ( + PLOTS_HELP = ( "Generating plots for metrics stored in structured files " "(JSON, CSV, TSV)." ) - plot_parser = subparsers.add_parser( - "plot", + plots_parser = subparsers.add_parser( + "plots", parents=[parent_parser], - description=append_doc_link(PLOT_HELP, "plot"), - help=PLOT_HELP, + description=append_doc_link(PLOTS_HELP, "plots"), + help=PLOTS_HELP, formatter_class=argparse.RawDescriptionHelpFormatter, ) - plot_subparsers = plot_parser.add_subparsers( + plots_subparsers = plots_parser.add_subparsers( dest="cmd", - help="Use `dvc plot CMD --help` to display command-specific help.", + help="Use `dvc plots CMD --help` to display command-specific help.", ) - fix_subparsers(plot_subparsers) + fix_subparsers(plots_subparsers) - SHOW_HELP = "Generate a plot image file from a metrics file." - plot_show_parser = plot_subparsers.add_parser( + SHOW_HELP = "Generate a plots image file from a metrics file." + plots_show_parser = plots_subparsers.add_parser( "show", parents=[parent_parser], - description=append_doc_link(SHOW_HELP, "plot/show"), + description=append_doc_link(SHOW_HELP, "plots/show"), help=SHOW_HELP, formatter_class=argparse.RawDescriptionHelpFormatter, ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "-t", "--template", nargs="?", default=None, help="File to be injected with data.", ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "-f", "--file", default=None, help="Name of the generated file." ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "-s", "--select", default=None, - help="Choose which field(s) or JSONPath to include in the plot.", + help="Choose which field(s) or JSONPath to include in the plots.", ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "-x", default=None, help="Field name for x axis." ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "-y", default=None, help="Field name for y axis." ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "--stdout", action="store_true", default=False, - help="Print plot specification to stdout.", + help="Print plots specification to stdout.", ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "--no-csv-header", action="store_true", default=False, help="Required when CSV or TSV datafile does not have a header.", ) - plot_show_parser.add_argument( + plots_show_parser.add_argument( "--no-html", action="store_true", default=False, help="Do not wrap Vega plot JSON with HTML.", ) - plot_show_parser.add_argument("--title", default=None, help="Plot title.") - plot_show_parser.add_argument("--xlab", default=None, help="X axis title.") - plot_show_parser.add_argument("--ylab", default=None, help="Y axis title.") - plot_show_parser.add_argument( + plots_show_parser.add_argument("--title", default=None, help="Plot title.") + plots_show_parser.add_argument( + "--xlab", default=None, help="X axis title." + ) + plots_show_parser.add_argument( + "--ylab", default=None, help="Y axis title." + ) + plots_show_parser.add_argument( "datafile", nargs="?", default=None, help="Metrics file to visualize", ) - plot_show_parser.set_defaults(func=CmdPlotShow) + plots_show_parser.set_defaults(func=CmdPlotsShow) - PLOT_DIFF_HELP = ( + PLOTS_DIFF_HELP = ( "Plot differences in metrics between commits in the DVC " "repository, or between the last commit and the workspace." ) - plot_diff_parser = plot_subparsers.add_parser( + plots_diff_parser = plots_subparsers.add_parser( "diff", parents=[parent_parser], - description=append_doc_link(PLOT_DIFF_HELP, "plot/diff"), - help=PLOT_DIFF_HELP, + description=append_doc_link(PLOTS_DIFF_HELP, "plots/diff"), + help=PLOTS_DIFF_HELP, formatter_class=argparse.RawDescriptionHelpFormatter, ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-t", "--template", nargs="?", default=None, help="File to be injected with data.", ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-d", "--datafile", nargs="?", default=None, help="Metrics file to visualize", ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-f", "--file", default=None, help="Name of the generated file." ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-s", "--select", default=None, help="Choose which field(s) or JSONPath to include in the plot.", ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-x", default=None, help="Field name for x axis." ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "-y", default=None, help="Field name for y axis." ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "--stdout", action="store_true", default=False, help="Print plot specification to stdout.", ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "--no-csv-header", action="store_true", default=False, help="Provided CSV ot TSV datafile does not have a header.", ) - plot_diff_parser.add_argument( + plots_diff_parser.add_argument( "--no-html", action="store_true", default=False, help="Do not wrap Vega plot JSON with HTML.", ) - plot_diff_parser.add_argument("--title", default=None, help="Plot title.") - plot_diff_parser.add_argument("--xlab", default=None, help="X axis title.") - plot_diff_parser.add_argument("--ylab", default=None, help="Y axis title.") - plot_diff_parser.add_argument( + plots_diff_parser.add_argument("--title", default=None, help="Plot title.") + plots_diff_parser.add_argument( + "--xlab", default=None, help="X axis title." + ) + plots_diff_parser.add_argument( + "--ylab", default=None, help="Y axis title." + ) + plots_diff_parser.add_argument( "revisions", nargs="*", default=None, help="Git commits to plot from", ) - plot_diff_parser.set_defaults(func=CmdPlotDiff) + plots_diff_parser.set_defaults(func=CmdPlotsDiff) diff --git a/dvc/repo/__init__.py b/dvc/repo/__init__.py index d16b4bc40..c0daad963 100644 --- a/dvc/repo/__init__.py +++ b/dvc/repo/__init__.py @@ -59,7 +59,7 @@ class Repo(object): from dvc.repo.get import get from dvc.repo.get_url import get_url from dvc.repo.update import update - from dvc.repo.plot import plot + from dvc.repo.plots import plot def __init__(self, root_dir=None): from dvc.state import State @@ -426,7 +426,7 @@ class Repo(object): @cached_property def plot_templates(self): - from dvc.repo.plot.template import PlotTemplates + from .plots.template import PlotTemplates return PlotTemplates(self.dvc_dir) diff --git a/dvc/repo/plot/__init__.py b/dvc/repo/plots/__init__.py similarity index 94% rename from dvc/repo/plot/__init__.py rename to dvc/repo/plots/__init__.py index 1bf178dcb..ea350a826 100644 --- a/dvc/repo/plot/__init__.py +++ b/dvc/repo/plots/__init__.py @@ -5,8 +5,9 @@ from funcy import first, last from dvc.exceptions import DvcException from dvc.repo import locked -from dvc.repo.plot.data import PlotData -from dvc.repo.plot.template import NoDataForTemplateError, Template + +from .data import PlotData +from .template import NoDataForTemplateError, Template logger = logging.getLogger(__name__) @@ -82,7 +83,7 @@ def fill_template( template_data = {} for template_datafile in template_datafiles: - from dvc.repo.plot.data import _load_from_revisions + from .data import _load_from_revisions plot_datas = _load_from_revisions(repo, template_datafile, revisions) tmp_data = [] @@ -126,7 +127,7 @@ def plot( repo, datafile=None, template=None, revisions=None, embed=False, **kwargs ): if revisions is None: - from dvc.repo.plot.data import WORKSPACE_REVISION_NAME + from .data import WORKSPACE_REVISION_NAME revisions = [WORKSPACE_REVISION_NAME] diff --git a/dvc/repo/plot/data.py b/dvc/repo/plots/data.py similarity index 100% rename from dvc/repo/plot/data.py rename to dvc/repo/plots/data.py diff --git a/dvc/repo/plot/template.py b/dvc/repo/plots/template.py similarity index 99% rename from dvc/repo/plot/template.py rename to dvc/repo/plots/template.py index cc5901464..882becca3 100644 --- a/dvc/repo/plot/template.py +++ b/dvc/repo/plots/template.py @@ -247,7 +247,7 @@ class DefaultScatterTemplate(Template): class PlotTemplates: - TEMPLATES_DIR = "plot" + TEMPLATES_DIR = "plots" TEMPLATES = [ DefaultLinearTemplate, DefaultConfusionTemplate, diff --git a/scripts/completion/dvc.bash b/scripts/completion/dvc.bash index cfa6478e0..77ecf8c6a 100644 --- a/scripts/completion/dvc.bash +++ b/scripts/completion/dvc.bash @@ -5,7 +5,7 @@ # - https://stackoverflow.com/questions/12933362 _dvc_commands='add cache checkout commit config destroy diff fetch get-url get gc \ - import-url import init install lock list metrics move params pipeline plot pull push \ + import-url import init install lock list metrics move params pipeline plots pull push \ remote remove repro root run status unlock unprotect update version' _dvc_options='-h --help -V --version' @@ -53,9 +53,9 @@ _dvc_pipeline='list show' _dvc_pipeline_list='' _dvc_pipeline_show='-c --commands -o --outs --ascii --dot --tree -l --locked' _dvc_pipeline_show_COMPGEN=_dvc_compgen_DVCFiles -_dvc_plot='show diff' -_dvc_plot_show='-t --template -f --file -s --select -x -y --stdout --no-csv-header --no-html --title --xlab --ylab' -_dvc_plot_diff='-t --template -d --datafile -f --file -s --select -x -y --stdout --no-csv-header --no-html --title --xlab --ylab' +_dvc_plots='show diff' +_dvc_plots_show='-t --template -f --file -s --select -x -y --stdout --no-csv-header --no-html --title --xlab --ylab' +_dvc_plots_diff='-t --template -d --datafile -f --file -s --select -x -y --stdout --no-csv-header --no-html --title --xlab --ylab' _dvc_pull='-j --jobs -r --remote -a --all-branches -T --all-tags -f --force -d --with-deps -R --recursive' _dvc_pull_COMPGEN=_dvc_compgen_DVCFiles _dvc_push='-j --jobs -r --remote -a --all-branches -T --all-tags -d --with-deps -R --recursive' diff --git a/scripts/completion/dvc.zsh b/scripts/completion/dvc.zsh index 67958cefd..51a920a7d 100644 --- a/scripts/completion/dvc.zsh +++ b/scripts/completion/dvc.zsh @@ -35,7 +35,7 @@ _dvc_commands() { "pipeline:Manage pipelines." "pull:Pull data files from a DVC remote storage." "push:Push data files to a DVC remote storage." - "plot:Generate plot for metrics structured as JSON, CSV or TSV." + "plots:Generate plot for metrics structured as JSON, CSV or TSV." "remote:Manage remote storage configuration." "remove:Remove outputs of DVC-file." "repro:Check for changes and reproduce DVC-file and dependencies." @@ -213,7 +213,7 @@ _dvc_push=( "*:Stages:_files -g '(*.dvc|Dvcfile)'" ) -_dvc_plot=( +_dvc_plots=( "1:Sub command:(show diff)" ) @@ -323,7 +323,7 @@ case $words[1] in pipeline) _arguments $_dvc_global_options $_dvc_pipeline ;; pull) _arguments $_dvc_global_options $_dvc_pull ;; push) _arguments $_dvc_global_options $_dvc_push ;; - plot) _arguments $_dvc_global_options $_dvc_plot ;; + plots) _arguments $_dvc_global_options $_dvc_plots ;; remote) _arguments $_dvc_global_options $_dvc_remote ;; remove) _arguments $_dvc_global_options $_dvc_remove ;; repro) _arguments $_dvc_global_options $_dvc_repro ;; diff --git a/tests/func/plots/__init__.py b/tests/func/plots/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/func/test_plot.py b/tests/func/plots/test_plots.py similarity index 98% rename from tests/func/test_plot.py rename to tests/func/plots/test_plots.py index 0e9678267..a8be76a83 100644 --- a/tests/func/test_plot.py +++ b/tests/func/plots/test_plots.py @@ -10,13 +10,13 @@ import yaml from bs4 import BeautifulSoup from funcy import first -from dvc.repo.plot import NoDataOrTemplateProvided -from dvc.repo.plot.data import ( +from dvc.repo.plots import NoDataOrTemplateProvided +from dvc.repo.plots.data import ( NoMetricInHistoryError, PlotData, PlotMetricTypeError, ) -from dvc.repo.plot.template import ( +from dvc.repo.plots.template import ( NoDataForTemplateError, NoFieldInDataError, TemplateNotFoundError, @@ -244,7 +244,7 @@ def test_plot_multiple_revs_default(tmp_dir, scm, dvc): def test_plot_multiple_revs(tmp_dir, scm, dvc): - shutil.copy(tmp_dir / ".dvc" / "plot" / "default.json", "template.json") + shutil.copy(tmp_dir / ".dvc" / "plots" / "default.json", "template.json") metric_1 = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric_1, "metric.json") @@ -324,7 +324,7 @@ def test_throw_on_no_metric_at_all(tmp_dir, scm, dvc, caplog): def custom_template(tmp_dir, dvc): custom_template = tmp_dir / "custom_template.json" shutil.copy( - tmp_dir / ".dvc" / "plot" / "default.json", custom_template, + tmp_dir / ".dvc" / "plots" / "default.json", custom_template, ) return custom_template @@ -380,7 +380,7 @@ def test_custom_template_with_specified_data( def test_plot_override_specified_data_source(tmp_dir, scm, dvc): shutil.copy( - tmp_dir / ".dvc" / "plot" / "default.json", + tmp_dir / ".dvc" / "plots" / "default.json", tmp_dir / "newtemplate.json", ) _replace( diff --git a/tests/unit/command/test_plot.py b/tests/unit/command/test_plots.py similarity index 92% rename from tests/unit/command/test_plot.py rename to tests/unit/command/test_plots.py index 1a4d3fb4e..ac10e42b6 100644 --- a/tests/unit/command/test_plot.py +++ b/tests/unit/command/test_plots.py @@ -1,13 +1,13 @@ import pytest from dvc.cli import parse_args -from dvc.command.plot import CmdPlotDiff, CmdPlotShow +from dvc.command.plots import CmdPlotsDiff, CmdPlotsShow def test_metrics_diff(mocker): cli_args = parse_args( [ - "plot", + "plots", "diff", "--file", "result.extension", @@ -34,7 +34,7 @@ def test_metrics_diff(mocker): "tag2", ] ) - assert cli_args.func == CmdPlotDiff + assert cli_args.func == CmdPlotsDiff cmd = cli_args.func(cli_args) @@ -63,7 +63,7 @@ def test_metrics_diff(mocker): def test_metrics_show(mocker): cli_args = parse_args( [ - "plot", + "plots", "show", "-f", "result.extension", @@ -77,7 +77,7 @@ def test_metrics_show(mocker): "datafile", ] ) - assert cli_args.func == CmdPlotShow + assert cli_args.func == CmdPlotsShow cmd = cli_args.func(cli_args) @@ -115,7 +115,7 @@ def test_metrics_show(mocker): def test_revisions(mocker, arg_revisions, is_dirty, expected_revisions): args = mocker.MagicMock() - cmd = CmdPlotDiff(args) + cmd = CmdPlotsDiff(args) mocker.patch.object(args, "revisions", arg_revisions) mocker.patch.object(cmd.repo.scm, "is_dirty", return_value=is_dirty) diff --git a/tests/unit/repo/plots/__init__.py b/tests/unit/repo/plots/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/test_plot.py b/tests/unit/repo/plots/test_data.py similarity index 94% rename from tests/unit/test_plot.py rename to tests/unit/repo/plots/test_data.py index 016f63d7c..687d62979 100644 --- a/tests/unit/test_plot.py +++ b/tests/unit/repo/plots/test_data.py @@ -2,7 +2,7 @@ from collections import OrderedDict import pytest -from dvc.repo.plot.data import _apply_path, _find_data, _lists +from dvc.repo.plots.data import _apply_path, _find_data, _lists @pytest.mark.parametrize(