diff --git a/README.md b/README.md index a069a17e913079c16884d9110319bc5f2e17e0ae..ae2a53cd332f27bb0bf00295a835515f94663bbb 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ plotID has two main functionalities: 2. Export the resulting file to a specified directory along the corresponding research data, the plot is based on. Additionally, the script that created the plot will also be copied to the directory. ### tagplot() -Tag your figure/plot with an ID. +Tag your figure/plot with an ID. It is possible to tag multiple figures at once. `tagplot(figures, plot_engine)` The variable "figures" can be a single figure or a list of multiple figures. The argument "plot_engine" defines which plot engine was used to create the figures. It also determines which plot engine plotID uses to place the ID on the plot. Currently supported plot engines are: @@ -69,13 +69,13 @@ FIGS_AS_LIST = [FIG1, FIG2] ### publish() -Save plot, data and measuring script. +Save plot, data and measuring script. It is possible to export multiple figures at once. `publish(src_datapath, dst_path, figure, plot_name)` -- "src_datapath" specifies the path to (raw) data that should be published. +- "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. - "dst_path" is the path to the destination directory, where all the data should be copied/exported to. -- "figure" expects the figure that was tagged and now should be saved as picture. -- "plot_name" will be the file name for the exported plot. +- "figure" expects the figure or a list of figures that were tagged and now should be saved as pictures. +- "plot_names" will be the file names for the exported plots. If you give only one plot name but several figures, plotID will name the exported plots with an appended number, e.g. example_fig1.png, example_fig2.png, ... Optional parameters can be used to customize the publish process. - data_storage: str, optional @@ -96,6 +96,7 @@ If you want to build plotID yourself, follow these steps: 4. Build the package `python3 -m build` + ## Documentation If you have more questions about plotID, please have a look at the [documentation](link-to-docs). Also have a look at the example.py that is shipped with plotID. diff --git a/plotid/example.py b/plotid/example.py index fcf7713916dc9ffc92ff7b9508f8b2d8778dcb7a..e7fdce69b3195b1b77904cfac7f5c8699e50f56b 100644 --- a/plotid/example.py +++ b/plotid/example.py @@ -47,12 +47,14 @@ FIGS_AS_LIST = [FIG1, FIG2] # %% Save figure as tiff-file, but publish also exports the plot to a picture # file in the destination folder. -for i, figure in enumerate(TAGGED_FIGS): - NAME = "Test"+str(i)+".tiff" - figure.savefig(NAME) +# for i, figure in enumerate(TAGGED_FIGS): +# NAME = "Test"+str(i)+".tiff" +# figure.savefig(NAME) # %% Publish # Arguments: Source directory, destination directory, figure, plot name, # publish-mode). -publish('../../tests', '/home/chief/Dokumente/fst/plotid_python/data', - FIG1, 'Bild', 'individual') + +publish(['../README.md', '../tests', '../LICENSE'], + '/home/chief/Dokumente/fst/plotid_python/data', + FIGS_AS_LIST, 'Bild', 'individual') diff --git a/plotid/plotoptions.py b/plotid/plotoptions.py index 6503422c73fe66f0fcd5a5fe9f44cdbd5ded1c7c..cab0b8be8a588da25990ba04840488086e619c73 100644 --- a/plotid/plotoptions.py +++ b/plotid/plotoptions.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Contains the PlotOption class.""" +"""Contains the PlotOptions and PublishOptions class.""" class PlotOptions: @@ -10,7 +10,7 @@ class PlotOptions: Methods ------- __init__ - validate_input: Check if input is correct type. + validate_input : Check if input is correct type. Attributes ---------- @@ -18,7 +18,7 @@ class PlotOptions: Figure that will be tagged. prefix : str Prefix that is placed before the ID. - id_method : int + id_method : str Method that decides which method is used to generate the ID. rotation : int Rotation angle for the ID. @@ -49,7 +49,6 @@ class PlotOptions: 0, if all checks succeed. """ - # %% Validate inputs # Input validation for figs is done in submodules tagplot_$engine.py if isinstance(self.prefix, str): pass diff --git a/plotid/publish.py b/plotid/publish.py index c5c53dd58da59cca6e3adb56149b3ca9e071726b..ce479a3bb22952ed80d09b480e791e4ecad1f4cd 100644 --- a/plotid/publish.py +++ b/plotid/publish.py @@ -8,7 +8,7 @@ the plot is based on. Additionally, the script that produced the plot will be copied to the destination directory. Functions: - publish(path-like, path-like, figure, string, string) -> None + publish(str, str, figure, str, str) -> None """ import os @@ -18,6 +18,201 @@ import warnings from plotid.save_plot import save_plot +class PublishOptions: + """ + Container objects which include all publish options provided by plotid. + + Methods + ------- + __init__ + validate_input: Check if input is correct type. + + Attributes + ---------- + src_datapaths : str or list of str + Path(s) to data that should be published. + dst_path : str + Path to the destination directory. + figure : figure object + Figure that was tagged and now should be saved as picture. + plot_name : str + Name for the exported plot. + data_storage : str + Method how the data should be stored. Available options: + centralized : The data files will copied only once. All other plots + will reference this data via sym link. + individual [default]: The complete data files will be copied to a + separate folder for every plot. + """ + + def __init__(self, src_datapaths, dst_path, figure, plot_names, + data_storage): + + self.src_datapaths = src_datapaths + self.dst_path = dst_path + self.figure = figure + self.plot_names = plot_names + self.data_storage = data_storage + self.dst_path_head, self.dst_dirname = os.path.split(self.dst_path) + + def validate_input(self): + """ + Validate if input for PublishOptions is correct type. + + Raises + ------ + FileNotFoundError + If the path to the source or the destination directory does not + exist. + TypeError + If input data is of wrong type. + + Returns + ------- + None. + + """ + if isinstance(self.src_datapaths, str): + self.src_datapaths = [self.src_datapaths] + if isinstance(self.src_datapaths, list): + for path in self.src_datapaths: + if not isinstance(path, str): + raise TypeError(f'{path} is not a string.') + # Check if source directory and files exist + if not os.path.exists(path): + raise FileNotFoundError('The specified source directory' + f'/file {path} does not exist.') + else: + raise TypeError('The source directory/files are neither ' + 'a string nor a list.') + + # Check if destination directory is allowed path + if not os.path.exists(self.dst_path_head): + raise FileNotFoundError('The specified destination directory ' + 'does not exist.') + + # Check if plot_name is a string or a list of strings + if isinstance(self.plot_names, str): + self.plot_names = [self.plot_names] + if isinstance(self.plot_names, list): + for name in self.plot_names: + if not isinstance(name, str): + raise TypeError('The list of plot_names contains an object' + ' which is not a string.') + else: + raise TypeError('The specified plot_names is neither a string nor' + ' a list of strings.') + + # 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.') + + def export(self): + """ + Export the plot and copy specified files to the destiantion folder. + + Raises + ------ + RuntimeError + If user does not want to overwrite existing folder. + ValueError + If non-supported data_storage method is given. + + Returns + ------- + None. + + """ + # Export plot figure to picture. + plot_paths = save_plot(self.figure, self.plot_names) + + # If dst dir already exists ask user if it should be overwritten. + if os.path.isdir(self.dst_path): + warnings.warn(f'Folder "{self.dst_dirname}" already exists – ' + 'plot has already been published.') + overwrite_dir = input('Do you want to overwrite the existing' + ' folder? (yes/no[default])\n') + + if overwrite_dir in ('yes', 'y'): + shutil.rmtree(self.dst_path) + else: + raise RuntimeError('PlotID has finished without an export.\n' + 'Rerun TagPlot if you need a new ID or ' + 'consider overwriting.') + + # Create invisible folder + dst_path_invisible = os.path.join(self.dst_path_head, + '.' + self.dst_dirname) + + # If invisible Folder exists, delete it + # (publish was not successful before) + if os.path.isdir(dst_path_invisible): + shutil.rmtree(dst_path_invisible) + + match self.data_storage: + case 'centralized': + self.centralized_data_storage() + case 'individual': + self.individual_data_storage(dst_path_invisible, plot_paths) + case _: + raise ValueError('The data storage method {data_storage} ' + 'is not available.') + + # If export was successful, make the directory visible + os.rename(dst_path_invisible, self.dst_path) + print(f'Publish was successful.\nYour plot(s) {plot_paths},\nyour' + f' data {self.src_datapaths}\nand your script {sys.argv[0]}\n' + f'were copied to {self.dst_path}\nin {self.data_storage} mode.') + + def centralized_data_storage(self): + """ + Store the data only in one directory and link all others to it. + + Returns + ------- + None. + + """ + # Does nothing, not implemented yet + pass + + def individual_data_storage(self, destination, pic_paths): + """ + Store all the data in an individual directory. + + Parameters + ---------- + destination : path-like + Directory where the data should be stored. + pic_path : path-like + Path to the picture file that will be stored in destination. + + Returns + ------- + None. + + """ + # Copy all files to destination directory + print('Copying data has been started. Depending on the size of' + ' your data this may take a while...') + os.makedirs(destination) + # Copy data to destination folder + for path in self.src_datapaths: + try: + shutil.copytree(path, destination, dirs_exist_ok=True) + except NotADirectoryError: + shutil.copy2(path, destination) + + # Copy script that calls this function to folder + shutil.copy2(sys.argv[0], destination) + # Copy plot files to folder + for path in pic_paths: + if os.path.isfile(path): + shutil.copy2(path, destination) + os.remove(path) + + def publish(src_datapath, dst_path, figure, plot_name, data_storage='individual'): """ @@ -25,85 +220,27 @@ def publish(src_datapath, dst_path, figure, plot_name, Parameters ---------- - src_datapath : string + src_datapath : str Path to data that should be published. - dst_path : string + dst_path : str Path to the destination directory. figure : figure object Figure that was tagged and now should be saved as picture. - plot_name: string + plot_name : str Name for the exported plot. - data_storage: string + data_storage : str Method how the data should be stored. Available options: - centralized: The raw data will copied only once. All other plots + 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. This is the default value. + individual [default]: The complete raw data will be copied to a + folder for every plot, respectively. Returns ------- None. """ - # Check if source directory exists - if not os.path.exists(src_datapath): - raise FileNotFoundError('The specified source directory ' - 'does not exist.') - - # Check if destination directory is allowed path - dst_path_head, dst_dirname = os.path.split(dst_path) - if not os.path.exists(dst_path_head): - raise FileNotFoundError('The specified destination directory ' - 'does not exist.') - - # If dst dir already exists ask user if it should be overwritten or not. - if os.path.isdir(dst_path): - warnings.warn(f'Folder "{dst_dirname}" already exists – ' - 'plot has already been published.') - overwrite_dir = input('Do you want to overwrite the existing folder?' - ' (yes/no[default])\n') - - if overwrite_dir in ('yes', 'y'): - shutil.rmtree(dst_path) - else: - raise RuntimeError('PlotID has finished without an export.\n' - 'Rerun TagPlot if you need a new ID or ' - 'consider overwriting.') - - # Export plot figure to picture. - plot_path = save_plot(figure, plot_name) - - # Create invisible folder - dst_path_invisible = os.path.join(dst_path_head, '.' + dst_dirname) - # If invisible Folder exists, delete it (publish was not successful before) - if os.path.isdir(dst_path_invisible): - shutil.rmtree(dst_path_invisible) - - match data_storage: - case 'centralized': - # Does nothing, not implemented yet - pass - case 'individual': - # Copy all files to destination directory - print('Copying data has been started. Depending on the size of ' - 'your data this may take a while...') - # Copy data to invisible folder - shutil.copytree(src_datapath, dst_path_invisible) - - # Copy script that calls this function to folder - shutil.copy2(sys.argv[0], dst_path_invisible) - # Copy plot file to folder - if os.path.isfile(plot_path): - shutil.copy2(plot_path, dst_path_invisible) - os.remove(plot_path) - case _: - raise ValueError('The data storage method {data_storage} ' - 'is not available.') - - print('Copying data finished. Starting to clean up.') - - # If export was successful, make the directory visible - os.rename(dst_path_invisible, dst_path) - print(f'Publish was successful.\nYour plot "{plot_path}",\n' - f'your data "{src_datapath}"\nand your script "{sys.argv[0]}"\n' - f'were copied to {dst_path}\nin {data_storage} mode.') + publish_container = PublishOptions(src_datapath, dst_path, figure, + plot_name, data_storage) + publish_container.validate_input() + publish_container.export() diff --git a/plotid/save_plot.py b/plotid/save_plot.py index 0292e6155608e2d7b76b6b32c1915f7957c1fa3d..5522fce64e04043f49708be7184d6a2ef1d5bb64 100644 --- a/plotid/save_plot.py +++ b/plotid/save_plot.py @@ -7,33 +7,59 @@ Functions: save_plot(figure, string) -> path-like """ +import warnings import matplotlib import matplotlib.pyplot as plt -def save_plot(figure, plot_name, extension='png'): +def save_plot(figures, plot_names, extension='png'): """ - Export plot. + Export plot(s). Parameters ---------- - figure : figure object + figure : list of/single figure object Figure that was tagged and now should be saved as picture. - plot_name: Name of the file where the plot will be saved to. - extension: string + plot_name : list of strings + Names of the files where the plots will be saved to. + extension : str File extension for the plot export. Returns ------- - plot_path: Name of the created picture. + plot_path : list + Names of the created pictures. """ - match type(figure): - case matplotlib.figure.Figure: - plt.figure(figure) - plot_path = plot_name + '.' + extension - plt.savefig(plot_path) - case _: - raise TypeError('The given figure is not a valid figure object.') + # Check if figs is a valid figure or a list of valid figures + if isinstance(figures, matplotlib.figure.Figure): + figures = [figures] + if isinstance(figures, list): + for fig in figures: + if isinstance(fig, matplotlib.figure.Figure): + pass + else: + raise TypeError('Figures is neither a valid matplotlib-figure nor' + ' a list of matplotlib-figures.') + + if len(plot_names) < len(figures): + warnings.warn('There are more figures than plot names. The first name' + ' will be taken for all plots with an appended number.') + first_name = plot_names[0] + plot_names = [None] * len(figures) + for i, _ in enumerate(plot_names): + plot_names[i] = first_name + f'{i+1}' + elif len(plot_names) > len(figures): + raise IndexError('There are more plot names than figures.') + + plot_path = [] + # match type(figures): + # case matplotlib.figure.Figure: + for i, fig in enumerate(figures): + plt.figure(fig) + plot_path.append(plot_names[i] + '.' + extension) + plt.savefig(plot_path[i]) + # case _: + # raise TypeError('The given figure is not a valid figure object.') return plot_path diff --git a/plotid/tagplot_matplotlib.py b/plotid/tagplot_matplotlib.py index 8f50afac84c7d1c1789b6cea794d1f017338dd80..916ee5b0e306f4fabee9ade93a5a05aa13cc6429 100644 --- a/plotid/tagplot_matplotlib.py +++ b/plotid/tagplot_matplotlib.py @@ -27,12 +27,13 @@ def tagplot_matplotlib(plotid_object): # Check if figs is a valid figure or a list of valid figures if isinstance(plotid_object.figs, matplotlib.figure.Figure): plotid_object.figs = [plotid_object.figs] - elif isinstance(plotid_object.figs, list): + if isinstance(plotid_object.figs, list): for figure in plotid_object.figs: if isinstance(figure, matplotlib.figure.Figure): pass else: - raise TypeError('Figure is not a valid matplotlib-figure.') + raise TypeError('Figures is neither a valid matplotlib-figure nor' + ' a list of matplotlib-figures.') fontsize = 'small' color = 'grey' diff --git a/tests/runner_tests.py b/tests/runner_tests.py index 69eef8bb54345623e2fb3a728f391c01b439041b..ce944d6f7379a4a71b7921a6afb358728dc63e1c 100644 --- a/tests/runner_tests.py +++ b/tests/runner_tests.py @@ -26,7 +26,7 @@ cov.save() if result.wasSuccessful(): covered = cov.report(show_missing=True, precision=2) - assert covered > 90, "Not enough coverage." + assert covered > 95, "Not enough coverage." sys.exit(0) else: sys.exit(1) diff --git a/tests/test_publish.py b/tests/test_publish.py index d09b7419f1793f9bae0a47788ebc06a1b1b60c74..a797b0114eb84f6448156ad2c8061785ef21fbb5 100644 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -14,12 +14,16 @@ from plotid.publish import publish SRC_DIR = 'test_src_folder' +SRC_FILES = ['test_file1.txt', 'test_file2.jpg', 'test_file3.exe'] PIC_NAME = 'test_picture' DST_DIR = 'test_dst_folder' DST_PARENT_DIR = 'test_parent' DST_PATH = os.path.join(DST_PARENT_DIR, DST_DIR) INVISIBLE_PATH = os.path.join(DST_PARENT_DIR, '.' + DST_DIR) -fig = plt.figure() +FIG = plt.figure() +FIG2 = plt.figure() +FIGS_AS_LIST = [FIG, FIG2] +PIC_NAME_LIST = [PIC_NAME, 'second_picture'] class TestPublish(unittest.TestCase): @@ -28,9 +32,11 @@ class TestPublish(unittest.TestCase): """ def setUp(self): - """ Generate source and destination directory and test image. """ + """ Generate source and destination directory and source files. """ os.makedirs(SRC_DIR, exist_ok=True) os.makedirs(DST_PARENT_DIR, exist_ok=True) + for file in SRC_FILES: + open(file, 'w', encoding='utf-8').close() # Skip test if tests are run from command line. @unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @@ -38,20 +44,53 @@ class TestPublish(unittest.TestCase): 'copied.') def test_publish(self): """ Test publish and check if an exported picture file exists. """ - publish(SRC_DIR, DST_PATH, fig, PIC_NAME, 'individual') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual') assert os.path.isfile(os.path.join(DST_PATH, PIC_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(self): + """ + Test publish with multiple figures and check if all exported picture + files exist. + """ + publish(SRC_DIR, DST_PATH, FIGS_AS_LIST, PIC_NAME_LIST, 'individual') + for name in PIC_NAME_LIST: + assert os.path.isfile(os.path.join(DST_PATH, name + '.png')) + + def test_publish_multiple_src_files(self): + """ + Test publish with multiple source files and check + if the exported data files exist. + """ + files_and_dir = list(SRC_FILES) + files_and_dir.append(SRC_DIR) + publish(files_and_dir, DST_PATH, FIGS_AS_LIST, PIC_NAME_LIST, + 'individual') + assert os.path.isdir(DST_PATH) + for file in SRC_FILES: + assert os.path.isfile(os.path.join(DST_PATH, file)) + def test_src_directory(self): """ Test if Error is raised when source directory does not exist.""" with self.assertRaises(FileNotFoundError): - publish('not_existing_folder', DST_PATH, fig, + publish('not_existing_folder', DST_PATH, FIG, PIC_NAME, 'individual') + def test_src_directory_type(self): + """ Test if Error is raised when source directory is not a string.""" + with self.assertRaises(TypeError): + publish([SRC_DIR, 4], DST_PATH, FIG, PIC_NAME, 'individual') + with self.assertRaises(TypeError): + publish(4, DST_PATH, FIG, PIC_NAME, 'individual') + def test_dst_directory(self): """ Test if Error is raised when destination dir does not exist.""" with self.assertRaises(FileNotFoundError): publish(SRC_DIR, 'not_existing_folder', - fig, PIC_NAME, 'individual') + FIG, PIC_NAME, 'individual') # Skip test if tests are run from command line. @unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @@ -65,7 +104,7 @@ class TestPublish(unittest.TestCase): os.mkdir(DST_PATH) # Mock user input as 'yes' with patch('builtins.input', return_value='yes'): - publish(SRC_DIR, DST_PATH, fig, PIC_NAME, 'individual') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual') # Skip test if tests are run from command line. @unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @@ -80,7 +119,7 @@ class TestPublish(unittest.TestCase): # Mock user input as 'no' with patch('builtins.input', return_value='no'): with self.assertRaises(RuntimeError): - publish(SRC_DIR, DST_PATH, fig, PIC_NAME, 'individual') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual') # Skip test if tests are run from command line. @unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @@ -95,7 +134,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(SRC_DIR, DST_PATH, fig, PIC_NAME, 'individual') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual') # Skip test if tests are run from command line. @unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @@ -107,19 +146,34 @@ class TestPublish(unittest.TestCase): directory from a previous run (delete the folder and proceed). """ os.mkdir(INVISIBLE_PATH) - publish(SRC_DIR, DST_PATH, fig, PIC_NAME, 'individual') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'individual') + + def test_plot_names(self): + """ Test if Error is raised if plot_name is not a string. """ + with self.assertRaises(TypeError): + publish(SRC_DIR, DST_PATH, FIG, 7.6, 'individual') + with self.assertRaises(TypeError): + publish(SRC_DIR, DST_PATH, FIG, (), 'individual') + with self.assertRaises(TypeError): + publish(SRC_DIR, DST_PATH, FIG, ['test', 3], 'individual') def test_data_storage(self): """ Test if Error is raised when unsupported storage method was chosen. """ with self.assertRaises(ValueError): - publish(SRC_DIR, DST_PATH, fig, PIC_NAME, 'none_existing_method') + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 'none_existing_method') + with self.assertRaises(TypeError): + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, 3) + with self.assertRaises(TypeError): + publish(SRC_DIR, DST_PATH, FIG, PIC_NAME, []) def tearDown(self): """ Delete all files created in setUp. """ shutil.rmtree(SRC_DIR) shutil.rmtree(DST_PARENT_DIR) + for file in SRC_FILES: + os.remove(file) if __name__ == '__main__': diff --git a/tests/test_save_plot.py b/tests/test_save_plot.py index 0f28ae73c00ffffc2deb9d178ea277b2a8730667..dcf9e39f7354235479e4c2edd81e1256abda8c03 100644 --- a/tests/test_save_plot.py +++ b/tests/test_save_plot.py @@ -20,9 +20,26 @@ class TestSavePlot(unittest.TestCase): def test_save_plot(self): """ Test if save_plot succeeds with valid arguments. """ - save_plot(FIGURE, PLOT_NAME, extension='jpg') + plot_paths = save_plot(FIGURE, [PLOT_NAME], extension='jpg') + self.assertIsInstance(plot_paths, list) os.remove(PLOT_NAME + '.jpg') + def test_more_figs_than_names(self): + """ + Test if a warning is raised if more figures than plot names are given. + Additionally, check if files are named correctly. + """ + with self.assertWarns(Warning): + save_plot([FIGURE, FIGURE, FIGURE], [PLOT_NAME]) + for i in (1, 2, 3): + assert os.path.isfile(PLOT_NAME + f'{i}.png') + os.remove(PLOT_NAME + f'{i}.png') + + def test_more_names_than_figs(self): + """ Test if Error is raised if more names than figures are given. """ + with self.assertRaises(IndexError): + save_plot([FIGURE, FIGURE], [PLOT_NAME, PLOT_NAME, PLOT_NAME]) + def test_wrong_fig_type(self): """ Test if Error is raised when not a figure object is given. """ with self.assertRaises(TypeError):