diff --git a/README.md b/README.md index cb3c6d0355c732afba08a01f5d9e0a99d70cff08..58d92a3f0d888b71ca87f3d302a27a877283dd27 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,9 @@ Optional parameters can be used to customize the tag process. - *prefix* : str, optional Will be added as prefix to the ID. - *id_method* : str, optional - id_method for creating the ID. Create an ID by Unix time is referenced as 'time', create a random ID with id_method='random'. The default is 'time'. + id_method for creating the ID. Create an ID by Unix time is referenced as "time", create a random ID with id_method="random". The default is "time". - *location* : string, optional - Location for ID to be displayed on the plot. Default is 'east'. + Location for ID to be displayed on the plot. Default is "east". - *qrcode* : boolean, optional Experimental support for encoding the ID in a QR Code. - *id_on_plot* : boolean, optional @@ -72,13 +72,13 @@ Example: FIG1 = plt.figure() FIG2 = plt.figure() FIGS_AS_LIST = [FIG1, FIG2] -FIGS_AND_IDS = tagplot(FIGS_AS_LIST, 'matplotlib', prefix='XY23_', id_method='random', location='west') +FIGS_AND_IDS = tagplot(FIGS_AS_LIST, "matplotlib", prefix="XY23_", id_method="random", location="west") ``` ### publish() Save plot, data and measuring script. It is possible to export multiple figures at once. -`publish(figs_and_ids, src_datapath, dst_path, plot_name)` +`publish(figs_and_ids, src_datapath, dst_path)` - *figs_and_ids* must be a PlotIDTransfer object. Therefore, it can be directly passed from tagplot() to publish(). - *src_datapath* specifies the path to (raw) data that should be published. It can be a string or a list of strings that specifies all files and directories which will be published. @@ -90,8 +90,10 @@ Optional parameters can be used to customize the publish process. Method how the data should be stored. Available options: - *centralized*: The raw data will copied only once. All other plots will reference this data via sym link. - *individual*: The complete raw data will be copied to a folder for every plot, respectively. +- *plot_names* : str or list of str, optional + Name for the exported plot. If not provided, the corresponding IDs will be used. Example: -`publish(figs_and_ids, '/home/user/Documents/research_data', '/home/user/Documents/exported_data', 'EnergyOverTime-Plot')` +`publish(figs_and_ids, "/home/user/Documents/research_data", "/home/user/Documents/exported_data", plot_names=["EnergyOverTime-Plot", "TimeOverEnergy-Plot")` ## Build If you want to build plotID yourself, follow these steps: diff --git a/examples/image_example.py b/examples/image_example.py index 4c4693369b250799a536a4f410783abf6f5d32ba..e4fdb344b759aded33faa13b2f7558bf9f297a9a 100644 --- a/examples/image_example.py +++ b/examples/image_example.py @@ -35,6 +35,6 @@ FIGS_AND_IDS = tagplot( # Export your tagged images, copy the research data that generated the images, # specify the destination folder and give a name for the exported image files. -publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "./data", "my_image") +publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "./data") # Required arguments: publish(output of tagplot(), list of files, -# path to destination folder, name(s) for the resulting images) +# path to destination folder) diff --git a/examples/matplotlib_example.py b/examples/matplotlib_example.py index eddfab4f3de0d513836a93126f22187451ed14fe..db348a5ec21a6f1cdd33bdbcb3e91edfa276636f 100644 --- a/examples/matplotlib_example.py +++ b/examples/matplotlib_example.py @@ -46,6 +46,6 @@ FIGS_AND_IDS = tagplot( # %% Publish -publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "data", "my_plot") +publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "data") # Required arguments: publish(output of tagplot(), list of files, -# path to destination folder, name(s) for the resulting images) +# path to destination folder) diff --git a/plotid/publish.py b/plotid/publish.py index d10d0223c6c23c259363fe5a147502aa31b5a99c..b669644f4f5a0cc3e36ddb08740b49065a1645e7 100644 --- a/plotid/publish.py +++ b/plotid/publish.py @@ -33,17 +33,17 @@ class PublishOptions: Export the plot and copy specified files to the destiantion folder. """ - def __init__(self, figs_and_ids, src_datapaths, dst_path, plot_names, **kwargs): + def __init__(self, figs_and_ids, src_datapaths, dst_path, **kwargs): if not isinstance(figs_and_ids, PlotIDTransfer): - raise RuntimeError("figs_and_ids is not an instance of " "PlotIDTransfer.") + raise RuntimeError("figs_and_ids is not an instance of PlotIDTransfer.") self.figure = figs_and_ids.figs self.figure_ids = figs_and_ids.figure_ids self.src_datapaths = src_datapaths self.dst_path = os.path.abspath(dst_path) - self.plot_names = plot_names self.data_storage = kwargs.get("data_storage", "individual") self.dst_path_head, self.dst_dirname = os.path.split(self.dst_path) + self.plot_names = kwargs.get("plot_names", self.figure_ids) def __str__(self): """Representation if an object of this class is printed.""" @@ -91,7 +91,7 @@ class PublishOptions: # Check if data_storage is a string if not isinstance(self.data_storage, str): - raise TypeError("The specified data_storage method is not a " "string.") + raise TypeError("The specified data_storage method is not a string.") def export(self): """ @@ -160,7 +160,7 @@ class PublishOptions: if delete_dir in ("yes", "y", "Yes", "YES"): shutil.rmtree(dst_path_invisible) raise RuntimeError( - "Publishing was unsuccessful. " "Try re-running publish." + "Publishing was unsuccessful. Try re-running publish." ) from exc case _: raise ValueError( @@ -233,7 +233,7 @@ class PublishOptions: ) -def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs): +def publish(figs_and_ids, src_datapath, dst_path, **kwargs): """ Save plot, data and measuring script. @@ -245,8 +245,7 @@ def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs): Path to data that should be published. dst_path : str Path to the destination directory. - plot_name : str or list of str - Name for the exported plot. + **kwargs : dict, optional Extra arguments for additional publish options. @@ -258,14 +257,14 @@ def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs): will reference this data via sym link. individual [default]: The complete raw data will be copied to a folder for every plot, respectively. + plot_names : str or list of str, optional + Name for the exported plot. If not provided, the corresponding IDs will be used. Returns ------- None. """ - publish_container = PublishOptions( - figs_and_ids, src_datapath, dst_path, plot_name, **kwargs - ) + publish_container = PublishOptions(figs_and_ids, src_datapath, dst_path, **kwargs) publish_container.validate_input() publish_container.export() diff --git a/tests/test_publish.py b/tests/test_publish.py index 7bacf8c136eecff5eea6a8f72049f18ca42e922c..f279f7f0b9232689dc9599d277c94c6fc7c7ea04 100644 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -58,7 +58,7 @@ class TestPublish(unittest.TestCase): PlotIDTransfer(FIG, "testID"), SRC_DIR, DST_PATH + "/", - PIC_NAME, + plot_names=PIC_NAME, data_storage="individual", ) assert os.path.isfile(os.path.join(DST_PATH, "testID", PIC_NAME + ".png")) @@ -70,29 +70,47 @@ class TestPublish(unittest.TestCase): "from a Python script. Therefore, the script cannot be " "copied.", ) - def test_publish_multiple_figs(self): + def test_publish_multiple_figs_custom_name(self): """ Test publish with multiple figures and check if all exported picture - files exist. + files exist with the provided strings as their names. """ - publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME_LIST) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, plot_names=PIC_NAME_LIST) for i, name in enumerate(PIC_NAME_LIST): assert os.path.isfile(os.path.join(DST_PATH, IDS_AS_LIST[i], name + ".png")) + # Skip test if tests are run from command line. + @unittest.skipIf( + not os.path.isfile(sys.argv[0]), + "Publish is not called " + "from a Python script. Therefore, the script cannot be " + "copied.", + ) + def test_publish_multiple_figs_standard_name(self): + """ + Test publish with multiple figures and check if all exported picture + files exist with the IDs as their names. + """ + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH) + for identifier in IDS_AS_LIST: + assert os.path.isfile( + os.path.join(DST_PATH, identifier, identifier + ".png") + ) + def test_figs_and_ids(self): """ Test if RuntimeError is raised when figs_and_ids is not an PlotIDTransfer object. """ with self.assertRaises(RuntimeError): - publish("FIGS_AND_IDS", SRC_DIR, DST_PATH, PIC_NAME_LIST) + publish("FIGS_AND_IDS", SRC_DIR, DST_PATH) def test_wrong_ids(self): """Test if Error is raised if IDs are of wrong type.""" with self.assertRaises(TypeError): - publish(PlotIDTransfer(FIG, 3), SRC_DIR, DST_PATH, PIC_NAME) + publish(PlotIDTransfer(FIG, 3), SRC_DIR, DST_PATH) with self.assertRaises(TypeError): - publish(PlotIDTransfer(FIG, ["i", 4]), SRC_DIR, DST_PATH, PIC_NAME) + publish(PlotIDTransfer(FIG, ["i", 4]), SRC_DIR, DST_PATH) def test_publish_multiple_src_files(self): """ @@ -105,7 +123,7 @@ class TestPublish(unittest.TestCase): FIGS_AND_IDS, files_and_dir, DST_PATH, - PIC_NAME_LIST, + plot_names=PIC_NAME_LIST, data_storage="individual", ) for identifier in IDS_AS_LIST: @@ -117,14 +135,14 @@ class TestPublish(unittest.TestCase): def test_src_directory(self): """Test if Error is raised when source directory does not exist.""" with self.assertRaises(FileNotFoundError): - publish(FIGS_AND_IDS, "not_existing_folder", DST_PATH, PIC_NAME) + publish(FIGS_AND_IDS, "not_existing_folder", DST_PATH) def test_src_directory_type(self): """Test if Error is raised when source directory is not a string.""" with self.assertRaises(TypeError): - publish(FIGS_AND_IDS, [SRC_DIR, 4], DST_PATH, PIC_NAME) + publish(FIGS_AND_IDS, [SRC_DIR, 4], DST_PATH) with self.assertRaises(TypeError): - publish(FIGS_AND_IDS, 4, DST_PATH, PIC_NAME) + publish(FIGS_AND_IDS, 4, DST_PATH) def test_dst_directory(self): """ @@ -132,7 +150,7 @@ class TestPublish(unittest.TestCase): destination dir does not exist. """ with self.assertRaises(FileNotFoundError): - publish(FIGS_AND_IDS, SRC_DIR, "not_existing_folder/data", PIC_NAME) + publish(FIGS_AND_IDS, SRC_DIR, "not_existing_folder/data") def test_script_exists(self): """ @@ -158,8 +176,7 @@ class TestPublish(unittest.TestCase): "from plotid.publish import publish\n" "from plotid.plotoptions import PlotIDTransfer\n" "publish(PlotIDTransfer(plt.figure(), 'testID2')," - " 'test_src_folder', 'test_parent/test_dst_folder'," - " 'test_picture')", + " 'test_src_folder', 'test_parent/test_dst_folder')", ], capture_output=True, check=True, @@ -172,8 +189,7 @@ class TestPublish(unittest.TestCase): "from plotid.publish import publish\n" "from plotid.plotoptions import PlotIDTransfer\n" "publish(PlotIDTransfer(plt.figure(), 'testID2'), " - "'test_src_folder', 'test_parent/test_dst_folder', " - "'test_picture')", + "'test_src_folder', 'test_parent/test_dst_folder')", ], capture_output=True, ) @@ -199,9 +215,7 @@ class TestPublish(unittest.TestCase): os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0])) # Mock user input as 'yes' with patch("builtins.input", return_value="yes"): - publish( - FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage="individual" - ) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, data_storage="individual") # Skip test if tests are run from command line. @unittest.skipIf( @@ -221,7 +235,7 @@ class TestPublish(unittest.TestCase): # Mock user input as 'no' with patch("builtins.input", return_value="no"): with self.assertRaises(RuntimeError): - publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH) # Skip test if tests are run from command line. @unittest.skipIf( @@ -241,9 +255,7 @@ class TestPublish(unittest.TestCase): # Mock user input as empty (no should be default). with patch("builtins.input", return_value=""): with self.assertRaises(RuntimeError): - publish( - FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage="individual" - ) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, data_storage="individual") # Skip test if tests are run from command line. @unittest.skipIf( @@ -264,7 +276,7 @@ class TestPublish(unittest.TestCase): # Mock user input as 'yes' for deleting the partial copied data with patch("builtins.input", side_effect=["yes", "yes"]): with self.assertRaises(RuntimeError): - publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, plot_names=PIC_NAME) assert not os.path.isdir(invisible_path1) os.remove("test_picture1.tmp.png") os.remove("test_picture2.tmp.png") @@ -284,16 +296,12 @@ class TestPublish(unittest.TestCase): """ with self.assertRaises(ValueError): publish( - FIGS_AND_IDS, - SRC_DIR, - DST_PATH, - PIC_NAME, - data_storage="none_existing_method", + FIGS_AND_IDS, SRC_DIR, DST_PATH, data_storage="none_existing_method" ) with self.assertRaises(TypeError): - publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage=3) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, data_storage=3) with self.assertRaises(TypeError): - publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage=[]) + publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, data_storage=[]) def test_str(self): """ @@ -301,7 +309,7 @@ class TestPublish(unittest.TestCase): correct. """ self.maxDiff = None - publish_obj = PublishOptions(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME) + publish_obj = PublishOptions(FIGS_AND_IDS, SRC_DIR, DST_PATH) self.assertIn( "<class 'plotid.publish.PublishOptions'>: {'figure': " "[<Figure size 640x480 with 0 Axes>, <Figure size"