From 9c046e6dabe61b8edc654063a3b9f2b48ec25e0a Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 29 Oct 2024 16:24:43 -0400 Subject: [PATCH 1/6] chore: more git ignores --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e9adf612..49bc0f20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ __pycache__/ src/__pycache__/ -con_duct.egg-info/ +*.egg-info/ .coverage coverage.* .duct/ .idea .tox/ +build/ dist/ +venvs/ From 457e54b9ef41ac638f0823ef05200d2bc2486ea2 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 29 Oct 2024 16:25:46 -0400 Subject: [PATCH 2/6] docs: adjust descriptions/help to uniformly end with . and some wording --- src/con_duct/suite/main.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/con_duct/suite/main.py b/src/con_duct/suite/main.py index 048cc865..f5baf9b1 100644 --- a/src/con_duct/suite/main.py +++ b/src/con_duct/suite/main.py @@ -17,24 +17,24 @@ def execute(args: argparse.Namespace) -> int: def main(argv: Optional[List[str]] = None) -> None: parser = argparse.ArgumentParser( prog="con-duct", - description="A command-line tool for managing various tasks.", + description="A suite of commands to manage or manipulate con-duct logs.", usage="con-duct [options]", ) subparsers = parser.add_subparsers(dest="command", help="Available subcommands") # Subcommand: pp - parser_pp = subparsers.add_parser("pp", help="Pretty print a JSON log") - parser_pp.add_argument("file_path", help="JSON file to pretty print") + parser_pp = subparsers.add_parser("pp", help="Pretty print a JSON log.") + parser_pp.add_argument("file_path", help="JSON file to pretty print.") parser_pp.set_defaults(func=pprint_json) # Subcommand: plot parser_plot = subparsers.add_parser( "plot", help="Plot resource usage for an execution." ) - parser_plot.add_argument("file_path", help="duct-produced usage.json file plot.") + parser_plot.add_argument("file_path", help="duct-produced usage.json file.") parser_plot.add_argument( "--output", - help="Output path for the png file. If not passed, show the file but do not save.", + help="Output path for the image file. If not specified, plot will be shown and not saved.", default=None, ) # parser_plot.add_argument( From 37a4034f842c3a745e38ad96cd88a9ae1d31e28f Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 29 Oct 2024 16:27:13 -0400 Subject: [PATCH 3/6] feat(plot): do not "hardcode" .png . --output filename should include extension matplotlib can save into .svg and others. There is no reason to somehow limit to .png and assume that .png would be added -- just pass entire filename as is to the library. --- src/con_duct/suite/plot.py | 2 +- test/test_suite.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/con_duct/suite/plot.py b/src/con_duct/suite/plot.py index 1436e5af..dae65014 100644 --- a/src/con_duct/suite/plot.py +++ b/src/con_duct/suite/plot.py @@ -52,7 +52,7 @@ def matplotlib_plot(args: argparse.Namespace) -> int: if args.output is not None: plt.savefig(args.output) print( - f"Successfully rendered input file: {args.file_path} to output {args.output}.png" + f"Successfully rendered input file: {args.file_path} to output {args.output}" ) else: plt.show() diff --git a/test/test_suite.py b/test/test_suite.py index 9c12e411..29ec2dce 100644 --- a/test/test_suite.py +++ b/test/test_suite.py @@ -106,11 +106,11 @@ def test_matplotlib_plot_sanity(self, mock_plot_save: MagicMock) -> None: args = argparse.Namespace( command="plot", file_path="test/data/mriqc-example/usage.json", - output="outfile", + output="outfile.png", func=plot.matplotlib_plot, ) assert main.execute(args) == 0 - mock_plot_save.assert_called_once_with("outfile") + mock_plot_save.assert_called_once_with("outfile.png") @patch("con_duct.suite.plot.plt.savefig") @patch("builtins.open", side_effect=FileNotFoundError) @@ -120,7 +120,7 @@ def test_matplotlib_plot_file_not_found( args = argparse.Namespace( command="plot", file_path="test/data/mriqc-example/usage.json", - output="outfile", + output="outfile.png", func=plot.matplotlib_plot, ) assert main.execute(args) == 1 @@ -134,7 +134,7 @@ def test_matplotlib_plot_invalid_json( args = argparse.Namespace( command="plot", file_path="test/data/mriqc-example/usage.json", - output="outfile", + output="outfile.png", func=plot.matplotlib_plot, ) assert main.execute(args) == 1 From be4e26c03984fbb78597ea0f5cec1e0d5ef7ee14 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 29 Oct 2024 16:30:52 -0400 Subject: [PATCH 4/6] fix(plot): delay import of matplotlib and numpy This way "con-duct --help" has a chance to run without crushing whenever people have installation of con-duct without all optional dependencies --- src/con_duct/suite/plot.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/con_duct/suite/plot.py b/src/con_duct/suite/plot.py index dae65014..f529b990 100644 --- a/src/con_duct/suite/plot.py +++ b/src/con_duct/suite/plot.py @@ -1,11 +1,12 @@ import argparse from datetime import datetime import json -import matplotlib.pyplot as plt -import numpy as np def matplotlib_plot(args: argparse.Namespace) -> int: + import matplotlib.pyplot as plt + import numpy as np + data = [] try: with open(args.file_path, "r") as file: From 3729906352e4267b88104de99865e801daf126da Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Tue, 29 Oct 2024 16:41:10 -0400 Subject: [PATCH 5/6] fix(plot,test): simply point to non-existing file and fixup testing With general mocking of builtins.open test does not test target file absence but could trigger some other problem with some other file opening, as it was happening for me now --- test/test_suite.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/test/test_suite.py b/test/test_suite.py index 29ec2dce..719b505a 100644 --- a/test/test_suite.py +++ b/test/test_suite.py @@ -101,7 +101,7 @@ def test_pprint_invalid_json( class TestPlotMatplotlib(unittest.TestCase): - @patch("con_duct.suite.plot.plt.savefig") + @patch("matplotlib.pyplot.savefig") def test_matplotlib_plot_sanity(self, mock_plot_save: MagicMock) -> None: args = argparse.Namespace( command="plot", @@ -112,21 +112,18 @@ def test_matplotlib_plot_sanity(self, mock_plot_save: MagicMock) -> None: assert main.execute(args) == 0 mock_plot_save.assert_called_once_with("outfile.png") - @patch("con_duct.suite.plot.plt.savefig") - @patch("builtins.open", side_effect=FileNotFoundError) - def test_matplotlib_plot_file_not_found( - self, _mock_open: MagicMock, mock_plot_save: MagicMock - ) -> None: + @patch("matplotlib.pyplot.savefig") + def test_matplotlib_plot_file_not_found(self, mock_plot_save: MagicMock) -> None: args = argparse.Namespace( command="plot", - file_path="test/data/mriqc-example/usage.json", + file_path="test/data/mriqc-example/usage_not_to_be_found.json", output="outfile.png", func=plot.matplotlib_plot, ) assert main.execute(args) == 1 mock_plot_save.assert_not_called() - @patch("con_duct.suite.plot.plt.savefig") + @patch("matplotlib.pyplot.savefig") @patch("builtins.open", new_callable=mock_open, read_data='{"invalid": "json"') def test_matplotlib_plot_invalid_json( self, _mock_open: MagicMock, mock_plot_save: MagicMock From 26f4f0eec76de27fea98e153460cae502bd25b61 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Wed, 30 Oct 2024 09:56:06 -0400 Subject: [PATCH 6/6] [DATALAD RUNCMD] Autoupdate readme === Do not change lines below === { "chain": [ "a34a0633e999f95ddfe6710e11f123dbd4b1c5bc" ], "cmd": "./.update-readme-help.py", "exit": 0, "extra_inputs": [], "inputs": [], "outputs": [], "pwd": "." } ^^^ Do not change lines above ^^^ --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1f753fa..4efbefb0 100644 --- a/README.md +++ b/README.md @@ -135,11 +135,11 @@ These helpers may use 3rd party python libraries. usage: con-duct [options] -A command-line tool for managing various tasks. +A suite of commands to manage or manipulate con-duct logs. positional arguments: {pp,plot} Available subcommands - pp Pretty print a JSON log + pp Pretty print a JSON log. plot Plot resource usage for an execution. options: