Skip to content
Snippets Groups Projects
Commit 6481f1f2 authored by Mayr, Hannes's avatar Mayr, Hannes Committed by Hock, Martin
Browse files

Change code style to black

parent af1cd1d4
Branches
Tags
2 merge requests!52Create v0.2.2,!43Change code style to black
Showing
with 422 additions and 311 deletions
...@@ -19,7 +19,7 @@ PEP8: ...@@ -19,7 +19,7 @@ PEP8:
stage: linting stage: linting
script: script:
- pip install flake8 - pip install flake8
- flake8 --count . - flake8 --count --max-line-length=88 .
Pylint: Pylint:
stage: linting stage: linting
...@@ -27,6 +27,19 @@ Pylint: ...@@ -27,6 +27,19 @@ Pylint:
- pip install pylint - pip install pylint
- find . -type f -name '*.py' | xargs pylint -rn --rcfile='plotid/.pylintrc' # Find all python files and check the code with pylint - find . -type f -name '*.py' | xargs pylint -rn --rcfile='plotid/.pylintrc' # Find all python files and check the code with pylint
Autoformatting:
stage: linting
script:
- pip install black
- black --check --verbose --diff --color .
Typechecker:
stage: linting
script:
- pip install mypy
- mypy --ignore-missing-imports --strict plotid tests examples
allow_failure: true
test: test:
stage: testing stage: testing
tags: tags:
......
...@@ -14,15 +14,16 @@ ...@@ -14,15 +14,16 @@
import os import os
import sys import sys
sys.path.insert(0, os.path.abspath('../..'))
sys.path.insert(0, os.path.abspath("../.."))
from plotid import __version__, __author__ # noqa: E402 from plotid import __version__, __author__ # noqa: E402
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = 'plotID' project = "plotID"
copyright = '2022, ' + __author__ copyright = "2022, " + __author__
author = __author__ author = __author__
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
...@@ -34,16 +35,12 @@ release = __version__ ...@@ -34,16 +35,12 @@ release = __version__
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions = ["sphinx.ext.napoleon", "autoapi.extension", "myst_parser"]
'sphinx.ext.napoleon', autoapi_type = "python"
'autoapi.extension', autoapi_dirs = ["../../plotid", "../../tests"]
"myst_parser"
]
autoapi_type = 'python'
autoapi_dirs = ['../../plotid', '../../tests']
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
...@@ -56,10 +53,10 @@ exclude_patterns = [] ...@@ -56,10 +53,10 @@ exclude_patterns = []
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # a list of builtin themes.
# #
html_theme = 'sphinx_rtd_theme' html_theme = "sphinx_rtd_theme"
html_logo = '_static/plotID.jpg' html_logo = "_static/plotID.jpg"
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css". # so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static'] html_static_path = ["_static"]
...@@ -15,8 +15,8 @@ from plotid.publish import publish ...@@ -15,8 +15,8 @@ from plotid.publish import publish
PROJECT_ID = "MR05_" PROJECT_ID = "MR05_"
# %% Read example images # %% Read example images
IMG1 = 'example_image1.png' IMG1 = "example_image1.png"
IMG2 = 'example_image2.png' IMG2 = "example_image2.png"
# %% TagPlot # %% TagPlot
...@@ -24,8 +24,9 @@ IMG2 = 'example_image2.png' ...@@ -24,8 +24,9 @@ IMG2 = 'example_image2.png'
IMGS_AS_LIST = [IMG1, IMG2] IMGS_AS_LIST = [IMG1, IMG2]
# Example for how to use tagplot with image files # Example for how to use tagplot with image files
FIGS_AND_IDS = tagplot(IMGS_AS_LIST, 'image', prefix=PROJECT_ID, FIGS_AND_IDS = tagplot(
id_method='time', location='west') IMGS_AS_LIST, "image", prefix=PROJECT_ID, id_method="time", location="west"
)
# Required arguments: tagplot(images as list, desired plot engine) # Required arguments: tagplot(images as list, desired plot engine)
...@@ -34,7 +35,6 @@ FIGS_AND_IDS = tagplot(IMGS_AS_LIST, 'image', prefix=PROJECT_ID, ...@@ -34,7 +35,6 @@ FIGS_AND_IDS = tagplot(IMGS_AS_LIST, 'image', prefix=PROJECT_ID,
# Export your tagged images, copy the research data that generated the images, # 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. # specify the destination folder and give a name for the exported image files.
publish(FIGS_AND_IDS, ['../README.md', '../docs', '../LICENSE'], publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "./data", "my_image")
'./data', 'my_image')
# Required arguments: publish(output of tagplot(), list of files, # Required arguments: publish(output of tagplot(), list of files,
# path to destination folder, name(s) for the resulting images) # path to destination folder, name(s) for the resulting images)
...@@ -25,13 +25,13 @@ y_2 = np.sin(x) + 2 ...@@ -25,13 +25,13 @@ y_2 = np.sin(x) + 2
# 1. figure # 1. figure
FIG1 = plt.figure() FIG1 = plt.figure()
plt.plot(x, y, color='black') plt.plot(x, y, color="black")
plt.plot(x, y_2, color='yellow') plt.plot(x, y_2, color="yellow")
# 2. figure # 2. figure
FIG2 = plt.figure() FIG2 = plt.figure()
plt.plot(x, y, color='blue') plt.plot(x, y, color="blue")
plt.plot(x, y_2, color='red') plt.plot(x, y_2, color="red")
# %% tagplot # %% tagplot
...@@ -39,13 +39,13 @@ plt.plot(x, y_2, color='red') ...@@ -39,13 +39,13 @@ plt.plot(x, y_2, color='red')
FIGS_AS_LIST = [FIG1, FIG2] FIGS_AS_LIST = [FIG1, FIG2]
# Example for how to use tagplot with matplotlib figures # Example for how to use tagplot with matplotlib figures
FIGS_AND_IDS = tagplot(FIGS_AS_LIST, 'matplotlib', location='west', FIGS_AND_IDS = tagplot(
id_method='random', prefix=PROJECT_ID) FIGS_AS_LIST, "matplotlib", location="west", id_method="random", prefix=PROJECT_ID
)
# Required arguments: tagplot(images as list, desired plot engine) # Required arguments: tagplot(images as list, desired plot engine)
# %% Publish # %% Publish
publish(FIGS_AND_IDS, ['../README.md', '../docs', '../LICENSE'], publish(FIGS_AND_IDS, ["../README.md", "../docs", "../LICENSE"], "data", "my_plot")
'data', 'my_plot')
# Required arguments: publish(output of tagplot(), list of files, # Required arguments: publish(output of tagplot(), list of files,
# path to destination folder, name(s) for the resulting images) # path to destination folder, name(s) for the resulting images)
...@@ -10,5 +10,5 @@ research data, the plot is based on. Additionally, the script that created the ...@@ -10,5 +10,5 @@ research data, the plot is based on. Additionally, the script that created the
plot will also be copied to the directory. plot will also be copied to the directory.
""" """
__version__ = '0.2.2' __version__ = "0.2.2"
__author__ = 'Institut Fluidsystemtechnik within nfdi4ing at TU Darmstadt' __author__ = "Institut Fluidsystemtechnik within nfdi4ing at TU Darmstadt"
...@@ -27,19 +27,20 @@ def create_id(id_method): ...@@ -27,19 +27,20 @@ def create_id(id_method):
figure_id : str figure_id : str
""" """
match id_method: match id_method:
case 'time': case "time":
figure_id = time.time() # UNIX Time figure_id = time.time() # UNIX Time
figure_id = hex(int(figure_id)) # convert time to hexadecimal str figure_id = hex(int(figure_id)) # convert time to hexadecimal str
time.sleep(1) # break for avoiding duplicate IDs time.sleep(1) # break for avoiding duplicate IDs
case 'random': case "random":
figure_id = str(uuid.uuid4()) # creates a random UUID figure_id = str(uuid.uuid4()) # creates a random UUID
figure_id = figure_id[0:8] # only use first 8 numbers figure_id = figure_id[0:8] # only use first 8 numbers
case _: case _:
raise ValueError( raise ValueError(
f'Your chosen ID method "{id_method}" is not supported.\n' f'Your chosen ID method "{id_method}" is not supported.\n'
'At the moment these methods are available:\n' "At the moment these methods are available:\n"
'"time": Unix time converted to hexadecimal\n' '"time": Unix time converted to hexadecimal\n'
'"random": Random UUID') '"random": Random UUID'
)
return figure_id return figure_id
......
...@@ -45,12 +45,12 @@ class PlotOptions: ...@@ -45,12 +45,12 @@ class PlotOptions:
def __init__(self, figs, rotation, position, **kwargs): def __init__(self, figs, rotation, position, **kwargs):
self.figs = figs self.figs = figs
self.figure_ids = kwargs.get('figure_ids', []) self.figure_ids = kwargs.get("figure_ids", [])
self.rotation = rotation self.rotation = rotation
self.position = position self.position = position
self.prefix = kwargs.get('prefix', '') self.prefix = kwargs.get("prefix", "")
self.id_method = kwargs.get('id_method', 'time') self.id_method = kwargs.get("id_method", "time")
self.qrcode = kwargs.get('qrcode', False) self.qrcode = kwargs.get("qrcode", False)
def __str__(self): def __str__(self):
"""Representation if an object of this class is printed.""" """Representation if an object of this class is printed."""
...@@ -76,7 +76,7 @@ class PlotOptions: ...@@ -76,7 +76,7 @@ class PlotOptions:
raise TypeError("Prefix is not a string.") raise TypeError("Prefix is not a string.")
if not isinstance(self.id_method, str): if not isinstance(self.id_method, str):
raise TypeError('The chosen id_method is not a string.') raise TypeError("The chosen id_method is not a string.")
# Store figs in a list, even if it is only one. # Store figs in a list, even if it is only one.
if not isinstance(self.figs, list): if not isinstance(self.figs, list):
...@@ -145,14 +145,19 @@ def validate_list(list_var, elt_type=str, is_file=False): ...@@ -145,14 +145,19 @@ def validate_list(list_var, elt_type=str, is_file=False):
if isinstance(list_var, list): if isinstance(list_var, list):
for elt in list_var: for elt in list_var:
if not isinstance(elt, elt_type): if not isinstance(elt, elt_type):
raise TypeError(f'The list of {list_var} contains an ' raise TypeError(
f'object which is not of type {elt_type}.') f"The list of {list_var} contains an "
f"object which is not of type {elt_type}."
)
if is_file: if is_file:
# Check if directory and files exist # Check if directory and files exist
if not os.path.exists(elt): if not os.path.exists(elt):
raise FileNotFoundError('The specified directory' raise FileNotFoundError(
f'/file {elt} does not exist.') "The specified directory" f"/file {elt} does not exist."
)
else: else:
raise TypeError(f'The specified {list_var} are neither a ' raise TypeError(
f'{elt_type} nor a list of {elt_type}.') f"The specified {list_var} are neither a "
f"{elt_type} nor a list of {elt_type}."
)
return list_var return list_var
...@@ -33,18 +33,16 @@ class PublishOptions: ...@@ -33,18 +33,16 @@ class PublishOptions:
Export the plot and copy specified files to the destiantion folder. Export the plot and copy specified files to the destiantion folder.
""" """
def __init__(self, figs_and_ids, src_datapaths, dst_path, plot_names, def __init__(self, figs_and_ids, src_datapaths, dst_path, plot_names, **kwargs):
**kwargs):
if not isinstance(figs_and_ids, PlotIDTransfer): if not isinstance(figs_and_ids, PlotIDTransfer):
raise RuntimeError('figs_and_ids is not an instance of ' raise RuntimeError("figs_and_ids is not an instance of " "PlotIDTransfer.")
'PlotIDTransfer.')
self.figure = figs_and_ids.figs self.figure = figs_and_ids.figs
self.figure_ids = figs_and_ids.figure_ids self.figure_ids = figs_and_ids.figure_ids
self.src_datapaths = src_datapaths self.src_datapaths = src_datapaths
self.dst_path = os.path.abspath(dst_path) self.dst_path = os.path.abspath(dst_path)
self.plot_names = plot_names self.plot_names = plot_names
self.data_storage = kwargs.get('data_storage', 'individual') self.data_storage = kwargs.get("data_storage", "individual")
self.dst_path_head, self.dst_dirname = os.path.split(self.dst_path) self.dst_path_head, self.dst_dirname = os.path.split(self.dst_path)
def __str__(self): def __str__(self):
...@@ -75,23 +73,25 @@ class PublishOptions: ...@@ -75,23 +73,25 @@ class PublishOptions:
self.plot_names = validate_list(self.plot_names) self.plot_names = validate_list(self.plot_names)
if not os.path.isfile(sys.argv[0]): if not os.path.isfile(sys.argv[0]):
raise FileNotFoundError('Cannot copy original python script. ' raise FileNotFoundError(
'Running publish from a shell is not ' "Cannot copy original python script. "
'possible.') "Running publish from a shell is not "
"possible."
)
# Check if self.src_datapaths are strings and existing files. # Check if self.src_datapaths are strings and existing files.
self.src_datapaths = validate_list(self.src_datapaths, self.src_datapaths = validate_list(self.src_datapaths, is_file=True)
is_file=True)
# Check if destination directory is allowed path # Check if destination directory is allowed path
if not os.path.exists(self.dst_path_head): if not os.path.exists(self.dst_path_head):
raise FileNotFoundError('The specified destination directory ' raise FileNotFoundError(
f'{self.dst_path_head} does not exist.') "The specified destination directory "
f"{self.dst_path_head} does not exist."
)
# Check if data_storage is a string # Check if data_storage is a string
if not isinstance(self.data_storage, str): if not isinstance(self.data_storage, str):
raise TypeError('The specified data_storage method is not a ' raise TypeError("The specified data_storage method is not a " "string.")
'string.')
def export(self): def export(self):
""" """
...@@ -112,55 +112,66 @@ class PublishOptions: ...@@ -112,55 +112,66 @@ class PublishOptions:
# Export plot figure to picture. # Export plot figure to picture.
plot_paths = save_plot(self.figure, self.plot_names) plot_paths = save_plot(self.figure, self.plot_names)
match self.data_storage: match self.data_storage:
case 'centralized': case "centralized":
self.centralized_data_storage() self.centralized_data_storage()
case 'individual': case "individual":
for i, plot in enumerate(plot_paths): for i, plot in enumerate(plot_paths):
try: try:
# Create folder with ID as name # Create folder with ID as name
dst_path = os.path.join(self.dst_path, dst_path = os.path.join(self.dst_path, self.figure_ids[i])
self.figure_ids[i]) dst_path_invisible = os.path.join(
dst_path_invisible = os.path.join(self.dst_path, '.' self.dst_path, "." + self.figure_ids[i]
+ self.figure_ids[i]) )
# If dir with the same ID already exists ask user # If dir with the same ID already exists ask user
# if it should be overwritten. # if it should be overwritten.
if os.path.isdir(dst_path): if os.path.isdir(dst_path):
warnings.warn(f'Folder "{dst_path}" already exists' warnings.warn(
' – plot has already been published.' f'Folder "{dst_path}" already exists'
" – plot has already been published."
) )
overwrite_dir = input('Do you want to overwrite ' overwrite_dir = input(
'the existing folder? ' "Do you want to overwrite "
'(yes/no[default])\n') "the existing folder? "
if overwrite_dir in ('yes', 'y', 'Yes', 'YES'): "(yes/no[default])\n"
)
if overwrite_dir in ("yes", "y", "Yes", "YES"):
shutil.rmtree(dst_path) shutil.rmtree(dst_path)
else: else:
raise RuntimeError('publish has finished ' raise RuntimeError(
'without an export.\nRerun ' "publish has finished "
'tagplot if you need a new' "without an export.\nRerun "
' ID or consider ' "tagplot if you need a new"
'overwriting.') " ID or consider "
"overwriting."
)
self.individual_data_storage(dst_path_invisible, plot) self.individual_data_storage(dst_path_invisible, plot)
# If export was successful, make the directory visible # If export was successful, make the directory visible
os.rename(dst_path_invisible, dst_path) os.rename(dst_path_invisible, dst_path)
except FileExistsError as exc: except FileExistsError as exc:
delete_dir = input('There was an error while ' delete_dir = input(
'publishing the data. Should the ' "There was an error while "
'partially copied data at ' "publishing the data. Should the "
f'{dst_path_invisible} be' "partially copied data at "
' removed? (yes/no[default])\n') f"{dst_path_invisible} be"
if delete_dir in ('yes', 'y', 'Yes', 'YES'): " removed? (yes/no[default])\n"
)
if delete_dir in ("yes", "y", "Yes", "YES"):
shutil.rmtree(dst_path_invisible) shutil.rmtree(dst_path_invisible)
raise RuntimeError('Publishing was unsuccessful. ' raise RuntimeError(
'Try re-running publish.') from exc "Publishing was unsuccessful. " "Try re-running publish."
) from exc
case _: case _:
raise ValueError(f'The data storage method {self.data_storage}' raise ValueError(
' is not available.') f"The data storage method {self.data_storage}" " is not available."
)
print(f'Publish was successful.\nYour plot(s), your' print(
f' data and your\nscript {sys.argv[0]}' f"Publish was successful.\nYour plot(s), your"
f'\nwere copied to {self.dst_path}.') f" data and your\nscript {sys.argv[0]}"
f"\nwere copied to {self.dst_path}."
)
def centralized_data_storage(self): def centralized_data_storage(self):
""" """
...@@ -192,8 +203,10 @@ class PublishOptions: ...@@ -192,8 +203,10 @@ class PublishOptions:
""" """
# Copy all files to destination directory # Copy all files to destination directory
print('Copying data has been started. Depending on the size of' print(
' your data this may take a while...') "Copying data has been started. Depending on the size of"
" your data this may take a while..."
)
os.makedirs(destination) os.makedirs(destination)
# Copy data to destination folder # Copy data to destination folder
for path in self.src_datapaths: for path in self.src_datapaths:
...@@ -214,8 +227,10 @@ class PublishOptions: ...@@ -214,8 +227,10 @@ class PublishOptions:
name_tmp, orig_ext = os.path.splitext(pic_path) name_tmp, orig_ext = os.path.splitext(pic_path)
orig_name, _ = os.path.splitext(name_tmp) orig_name, _ = os.path.splitext(name_tmp)
final_file_path = orig_name + orig_ext final_file_path = orig_name + orig_ext
os.rename(os.path.join(destination, pic_path), os.rename(
os.path.join(destination, final_file_path)) os.path.join(destination, pic_path),
os.path.join(destination, final_file_path),
)
def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs): def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs):
...@@ -249,7 +264,8 @@ def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs): ...@@ -249,7 +264,8 @@ def publish(figs_and_ids, src_datapath, dst_path, plot_name, **kwargs):
None. None.
""" """
publish_container = PublishOptions(figs_and_ids, src_datapath, dst_path, publish_container = PublishOptions(
plot_name, **kwargs) figs_and_ids, src_datapath, dst_path, plot_name, **kwargs
)
publish_container.validate_input() publish_container.validate_input()
publish_container.export() publish_container.export()
...@@ -12,7 +12,7 @@ import matplotlib ...@@ -12,7 +12,7 @@ import matplotlib
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def save_plot(figures, plot_names, extension='png'): def save_plot(figures, plot_names, extension="png"):
""" """
Export plot(s). Export plot(s).
...@@ -35,34 +35,36 @@ def save_plot(figures, plot_names, extension='png'): ...@@ -35,34 +35,36 @@ def save_plot(figures, plot_names, extension='png'):
figures = [figures] figures = [figures]
# PIL has different classes for different file formats. Therefore, the # PIL has different classes for different file formats. Therefore, the
# type is checked to contain 'PIL' and 'ImageFile'. # type is checked to contain 'PIL' and 'ImageFile'.
if all(x in str(type(figures)) for x in ['PIL', 'ImageFile']): if all(x in str(type(figures)) for x in ["PIL", "ImageFile"]):
figures = [figures] figures = [figures]
if not isinstance(figures, list): if not isinstance(figures, list):
raise TypeError('Figures are not given as list.') raise TypeError("Figures are not given as list.")
if isinstance(plot_names, str): if isinstance(plot_names, str):
plot_names = [plot_names] plot_names = [plot_names]
if len(plot_names) < len(figures): if len(plot_names) < len(figures):
warnings.warn('There are more figures than plot names. The first name' warnings.warn(
' will be taken for all plots with an appended number.') "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] first_name = plot_names[0]
plot_names = [None] * len(figures) plot_names = [None] * len(figures)
for i, _ in enumerate(plot_names): for i, _ in enumerate(plot_names):
plot_names[i] = first_name + f'{i+1}' plot_names[i] = first_name + f"{i+1}"
elif len(plot_names) > len(figures): elif len(plot_names) > len(figures):
raise IndexError('There are more plot names than figures.') raise IndexError("There are more plot names than figures.")
plot_path = [] plot_path = []
for i, fig in enumerate(figures): for i, fig in enumerate(figures):
if isinstance(fig, matplotlib.figure.Figure): if isinstance(fig, matplotlib.figure.Figure):
plt.figure(fig) plt.figure(fig)
plot_path.append(plot_names[i] + '.tmp.' + extension) plot_path.append(plot_names[i] + ".tmp." + extension)
plt.savefig(plot_path[i]) plt.savefig(plot_path[i])
elif all(x in str(type(fig)) for x in ['PIL', 'ImageFile']): elif all(x in str(type(fig)) for x in ["PIL", "ImageFile"]):
plot_path.append(plot_names[i] + '.tmp.' + extension) plot_path.append(plot_names[i] + ".tmp." + extension)
fig.save(plot_path[i]) fig.save(plot_path[i])
else: else:
raise TypeError(f'Figure number {i} is not a valid figure object.') raise TypeError(f"Figure number {i} is not a valid figure object.")
return plot_path return plot_path
...@@ -16,7 +16,7 @@ from plotid.tagplot_matplotlib import tagplot_matplotlib ...@@ -16,7 +16,7 @@ from plotid.tagplot_matplotlib import tagplot_matplotlib
from plotid.tagplot_image import tagplot_image from plotid.tagplot_image import tagplot_image
def tagplot(figs, engine, location='east', **kwargs): def tagplot(figs, engine, location="east", **kwargs):
""" """
Tag your figure/plot with an ID. Tag your figure/plot with an ID.
...@@ -65,28 +65,30 @@ def tagplot(figs, engine, location='east', **kwargs): ...@@ -65,28 +65,30 @@ def tagplot(figs, engine, location='east', **kwargs):
raise TypeError("Location is not a string.") raise TypeError("Location is not a string.")
match location: match location:
case 'north': case "north":
rotation = 0 rotation = 0
position = (0.35, 0.975) position = (0.35, 0.975)
case 'east': case "east":
rotation = 90 rotation = 90
position = (0.975, 0.35) position = (0.975, 0.35)
case 'south': case "south":
rotation = 0 rotation = 0
position = (0.35, 0.015) position = (0.35, 0.015)
case 'west': case "west":
rotation = 90 rotation = 90
position = (0.025, 0.35) position = (0.025, 0.35)
case 'southeast': case "southeast":
rotation = 0 rotation = 0
position = (0.75, 0.015) position = (0.75, 0.015)
case 'custom': case "custom":
# TODO: Get rotation and position from user input & check if valid # TODO: Get rotation and position from user input & check if valid
pass pass
case _: case _:
warnings.warn(f'Location "{location}" is not a defined ' warnings.warn(
f'Location "{location}" is not a defined '
'location, TagPlot uses location "east" ' 'location, TagPlot uses location "east" '
'instead.') "instead."
)
rotation = 90 rotation = 90
position = (0.975, 0.35) position = (0.975, 0.35)
...@@ -94,10 +96,9 @@ def tagplot(figs, engine, location='east', **kwargs): ...@@ -94,10 +96,9 @@ def tagplot(figs, engine, location='east', **kwargs):
option_container.validate_input() option_container.validate_input()
match engine: match engine:
case 'matplotlib' | 'pyplot': case "matplotlib" | "pyplot":
return tagplot_matplotlib(option_container) return tagplot_matplotlib(option_container)
case 'image' | 'fallback': case "image" | "fallback":
return tagplot_image(option_container) return tagplot_image(option_container)
case _: case _:
raise ValueError( raise ValueError(f'The plot engine "{engine}" is not supported.')
f'The plot engine "{engine}" is not supported.')
...@@ -28,15 +28,16 @@ def tagplot_image(plotid_object): ...@@ -28,15 +28,16 @@ def tagplot_image(plotid_object):
""" """
# Check if plotid_object is a valid instance of PlotOptions # Check if plotid_object is a valid instance of PlotOptions
if not isinstance(plotid_object, PlotOptions): if not isinstance(plotid_object, PlotOptions):
raise TypeError('The given options container is not an instance' raise TypeError(
'of PlotOptions.') "The given options container is not an instance" "of PlotOptions."
)
# Check if figs is a list of files # Check if figs is a list of files
for img in plotid_object.figs: for img in plotid_object.figs:
if not isinstance(img, str): if not isinstance(img, str):
raise TypeError('Name of the image is not a string.') raise TypeError("Name of the image is not a string.")
if not os.path.isfile(img): if not os.path.isfile(img):
raise TypeError('File does not exist.') raise TypeError("File does not exist.")
# Check if figs is a valid file is done by pillow internally # Check if figs is a valid file is done by pillow internally
color = (128, 128, 128) # grey color = (128, 128, 128) # grey
...@@ -47,13 +48,18 @@ def tagplot_image(plotid_object): ...@@ -47,13 +48,18 @@ def tagplot_image(plotid_object):
plotid_object.figure_ids.append(img_id) plotid_object.figure_ids.append(img_id)
img = Image.open(img) img = Image.open(img)
img_txt = Image.new('L', font.getsize(img_id)) img_txt = Image.new("L", font.getsize(img_id))
draw_txt = ImageDraw.Draw(img_txt) draw_txt = ImageDraw.Draw(img_txt)
draw_txt.text((0, 0), img_id, font=font, fill=255) draw_txt.text((0, 0), img_id, font=font, fill=255)
txt = img_txt.rotate(plotid_object.rotation, expand=1) txt = img_txt.rotate(plotid_object.rotation, expand=1)
img.paste(ImageOps.colorize(txt, (0, 0, 0), color), img.paste(
(int(img.width*plotid_object.position[0]), ImageOps.colorize(txt, (0, 0, 0), color),
int(img.height*(1-plotid_object.position[1]))), txt) (
int(img.width * plotid_object.position[0]),
int(img.height * (1 - plotid_object.position[1])),
),
txt,
)
if plotid_object.qrcode: if plotid_object.qrcode:
qrcode = create_qrcode(img_id) qrcode = create_qrcode(img_id)
......
...@@ -30,16 +30,17 @@ def tagplot_matplotlib(plotid_object): ...@@ -30,16 +30,17 @@ def tagplot_matplotlib(plotid_object):
""" """
# Check if plotid_object is a valid instance of PlotOptions # Check if plotid_object is a valid instance of PlotOptions
if not isinstance(plotid_object, PlotOptions): if not isinstance(plotid_object, PlotOptions):
raise TypeError('The given options container is not an instance' raise TypeError(
'of PlotOptions.') "The given options container is not an instance" "of PlotOptions."
)
# Check if figs is a list of valid figures # Check if figs is a list of valid figures
for figure in plotid_object.figs: for figure in plotid_object.figs:
if not isinstance(figure, matplotlib.figure.Figure): if not isinstance(figure, matplotlib.figure.Figure):
raise TypeError('Figure is not a valid matplotlib-figure.') raise TypeError("Figure is not a valid matplotlib-figure.")
fontsize = 'small' fontsize = "small"
color = 'grey' color = "grey"
# Loop to create and position the IDs # Loop to create and position the IDs
for fig in plotid_object.figs: for fig in plotid_object.figs:
...@@ -48,15 +49,21 @@ def tagplot_matplotlib(plotid_object): ...@@ -48,15 +49,21 @@ def tagplot_matplotlib(plotid_object):
plotid_object.figure_ids.append(fig_id) plotid_object.figure_ids.append(fig_id)
plt.figure(fig) plt.figure(fig)
plt.figtext(x=plotid_object.position[0], y=plotid_object.position[1], plt.figtext(
s=fig_id, ha='left', wrap=True, x=plotid_object.position[0],
y=plotid_object.position[1],
s=fig_id,
ha="left",
wrap=True,
rotation=plotid_object.rotation, rotation=plotid_object.rotation,
fontsize=fontsize, color=color) fontsize=fontsize,
color=color,
)
if plotid_object.qrcode: if plotid_object.qrcode:
qrcode = create_qrcode(fig_id) qrcode = create_qrcode(fig_id)
qrcode.thumbnail((100, 100), Image.ANTIALIAS) qrcode.thumbnail((100, 100), Image.ANTIALIAS)
fig.figimage(qrcode, fig.bbox.xmax - 100, 0, cmap='bone') fig.figimage(qrcode, fig.bbox.xmax - 100, 0, cmap="bone")
fig.tight_layout() fig.tight_layout()
figs_and_ids = PlotIDTransfer(plotid_object.figs, plotid_object.figure_ids) figs_and_ids = PlotIDTransfer(plotid_object.figs, plotid_object.figure_ids)
......
...@@ -10,14 +10,14 @@ import os ...@@ -10,14 +10,14 @@ import os
import unittest import unittest
import coverage import coverage
path = os.path.abspath('plotid') path = os.path.abspath("plotid")
sys.path.append(path) sys.path.append(path)
cov = coverage.Coverage() cov = coverage.Coverage()
cov.start() cov.start()
loader = unittest.TestLoader() loader = unittest.TestLoader()
tests = loader.discover('.') tests = loader.discover(".")
testRunner = unittest.runner.TextTestRunner(verbosity=2) testRunner = unittest.runner.TextTestRunner(verbosity=2)
result = testRunner.run(tests) result = testRunner.run(tests)
......
...@@ -17,26 +17,25 @@ class TestCreateID(unittest.TestCase): ...@@ -17,26 +17,25 @@ class TestCreateID(unittest.TestCase):
def test_existence(self): def test_existence(self):
"""Test if create_id returns a string.""" """Test if create_id returns a string."""
self.assertIsInstance(cid.create_id('time'), str) self.assertIsInstance(cid.create_id("time"), str)
self.assertIsInstance(cid.create_id('random'), str) self.assertIsInstance(cid.create_id("random"), str)
def test_errors(self): def test_errors(self):
"""Test if Errors are raised when id_method is wrong.""" """Test if Errors are raised when id_method is wrong."""
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
cid.create_id(3) cid.create_id(3)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
cid.create_id('h') cid.create_id("h")
def test_length(self): def test_length(self):
"""Test if figure_id has the correct length.""" """Test if figure_id has the correct length."""
self.assertEqual(len(cid.create_id('time')), 10) self.assertEqual(len(cid.create_id("time")), 10)
self.assertEqual(len(cid.create_id('random')), 8) self.assertEqual(len(cid.create_id("random")), 8)
def test_qrcode(self): def test_qrcode(self):
"""Test if qrcode returns a image.""" """Test if qrcode returns a image."""
self.assertIsInstance(create_qrcode('test_ID'), self.assertIsInstance(create_qrcode("test_ID"), qrcode.image.pil.PilImage)
qrcode.image.pil.PilImage)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -20,42 +20,47 @@ class TestTagplot(unittest.TestCase): ...@@ -20,42 +20,47 @@ class TestTagplot(unittest.TestCase):
""" """
Test if input validation runs successful. Test if input validation runs successful.
""" """
PlotOptions('FIG', ROTATION, POSITION, prefix='xyz', PlotOptions(
id_method='random').validate_input() "FIG", ROTATION, POSITION, prefix="xyz", id_method="random"
).validate_input()
def test_prefix(self): def test_prefix(self):
"""Test if Error is raised if prefix is not a string.""" """Test if Error is raised if prefix is not a string."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
PlotOptions(['FIG'], ROTATION, POSITION, prefix=3).validate_input() PlotOptions(["FIG"], ROTATION, POSITION, prefix=3).validate_input()
def test_data_storage(self): def test_data_storage(self):
"""Test if Error is raised if id_method is not a string.""" """Test if Error is raised if id_method is not a string."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
PlotOptions(['FIG'], ROTATION, POSITION, PlotOptions(["FIG"], ROTATION, POSITION, id_method=4).validate_input()
id_method=4).validate_input()
def test_str_plotoptions(self): def test_str_plotoptions(self):
""" """
Test if the string representation of a PlotOptions object is correct. Test if the string representation of a PlotOptions object is correct.
""" """
plot_obj = PlotOptions('FIG', ROTATION, POSITION, prefix='xyz', plot_obj = PlotOptions(
id_method='random') "FIG", ROTATION, POSITION, prefix="xyz", id_method="random"
self.assertEqual(str(plot_obj), )
self.assertEqual(
str(plot_obj),
"<class 'plotid.plotoptions.PlotOptions'>: {'figs': " "<class 'plotid.plotoptions.PlotOptions'>: {'figs': "
"'FIG', 'figure_ids': [], 'rotation': 270, 'position'" "'FIG', 'figure_ids': [], 'rotation': 270, 'position'"
": (100, 200), 'prefix': 'xyz', 'id_method': " ": (100, 200), 'prefix': 'xyz', 'id_method': "
"'random', 'qrcode': False}") "'random', 'qrcode': False}",
)
def test_str_plotidtransfer(self): def test_str_plotidtransfer(self):
""" """
Test if the string representation of a PlotIDTransfer object is Test if the string representation of a PlotIDTransfer object is
correct. correct.
""" """
transfer_obj = PlotIDTransfer('FIG', []) transfer_obj = PlotIDTransfer("FIG", [])
self.assertEqual(str(transfer_obj), self.assertEqual(
str(transfer_obj),
"<class 'plotid.plotoptions.PlotIDTransfer'>: " "<class 'plotid.plotoptions.PlotIDTransfer'>: "
"{'figs': 'FIG', 'figure_ids': []}") "{'figs': 'FIG', 'figure_ids': []}",
)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -16,18 +16,18 @@ from plotid.publish import publish, PublishOptions ...@@ -16,18 +16,18 @@ from plotid.publish import publish, PublishOptions
from plotid.plotoptions import PlotIDTransfer from plotid.plotoptions import PlotIDTransfer
SRC_DIR = 'test_src_folder' SRC_DIR = "test_src_folder"
SRC_FILES = ['test_file1.txt', 'test_file2.jpg', 'test_file3.exe'] SRC_FILES = ["test_file1.txt", "test_file2.jpg", "test_file3.exe"]
PIC_NAME = 'test_picture' PIC_NAME = "test_picture"
DST_DIR = 'test_dst_folder' DST_DIR = "test_dst_folder"
DST_PARENT_DIR = 'test_parent' DST_PARENT_DIR = "test_parent"
DST_PATH = os.path.join(DST_PARENT_DIR, DST_DIR) DST_PATH = os.path.join(DST_PARENT_DIR, DST_DIR)
FIG = plt.figure(figsize=[6.4, 4.8], dpi=100) FIG = plt.figure(figsize=[6.4, 4.8], dpi=100)
FIG2 = plt.figure(figsize=[6.4, 4.8], dpi=100) FIG2 = plt.figure(figsize=[6.4, 4.8], dpi=100)
FIGS_AS_LIST = [FIG, FIG2] FIGS_AS_LIST = [FIG, FIG2]
IDS_AS_LIST = ['MR05_0x63203c6f', 'MR05_0x63203c70'] IDS_AS_LIST = ["MR05_0x63203c6f", "MR05_0x63203c70"]
FIGS_AND_IDS = PlotIDTransfer(FIGS_AS_LIST, IDS_AS_LIST) FIGS_AND_IDS = PlotIDTransfer(FIGS_AS_LIST, IDS_AS_LIST)
PIC_NAME_LIST = [PIC_NAME, 'second_picture'] PIC_NAME_LIST = [PIC_NAME, "second_picture"]
class TestPublish(unittest.TestCase): class TestPublish(unittest.TestCase):
...@@ -40,26 +40,36 @@ class TestPublish(unittest.TestCase): ...@@ -40,26 +40,36 @@ class TestPublish(unittest.TestCase):
os.makedirs(SRC_DIR, exist_ok=True) os.makedirs(SRC_DIR, exist_ok=True)
os.makedirs(DST_PARENT_DIR, exist_ok=True) os.makedirs(DST_PARENT_DIR, exist_ok=True)
for file in SRC_FILES: for file in SRC_FILES:
open(file, 'w', encoding='utf-8').close() open(file, "w", encoding="utf-8").close()
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_publish(self): def test_publish(self):
""" """
Test publish and check if an exported picture file exists. Test publish and check if an exported picture file exists.
The destination path is given with trailing slash. The destination path is given with trailing slash.
""" """
publish(PlotIDTransfer(FIG, 'testID'), SRC_DIR, DST_PATH + '/', publish(
PIC_NAME, data_storage='individual') PlotIDTransfer(FIG, "testID"),
assert os.path.isfile(os.path.join(DST_PATH, 'testID', SRC_DIR,
PIC_NAME + '.png')) DST_PATH + "/",
PIC_NAME,
data_storage="individual",
)
assert os.path.isfile(os.path.join(DST_PATH, "testID", PIC_NAME + ".png"))
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_publish_multiple_figs(self): def test_publish_multiple_figs(self):
""" """
Test publish with multiple figures and check if all exported picture Test publish with multiple figures and check if all exported picture
...@@ -67,8 +77,7 @@ class TestPublish(unittest.TestCase): ...@@ -67,8 +77,7 @@ class TestPublish(unittest.TestCase):
""" """
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME_LIST) publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME_LIST)
for i, name in enumerate(PIC_NAME_LIST): for i, name in enumerate(PIC_NAME_LIST):
assert os.path.isfile(os.path.join(DST_PATH, IDS_AS_LIST[i], assert os.path.isfile(os.path.join(DST_PATH, IDS_AS_LIST[i], name + ".png"))
name + '.png'))
def test_figs_and_ids(self): def test_figs_and_ids(self):
""" """
...@@ -76,14 +85,14 @@ class TestPublish(unittest.TestCase): ...@@ -76,14 +85,14 @@ class TestPublish(unittest.TestCase):
PlotIDTransfer object. PlotIDTransfer object.
""" """
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
publish('FIGS_AND_IDS', SRC_DIR, DST_PATH, PIC_NAME_LIST) publish("FIGS_AND_IDS", SRC_DIR, DST_PATH, PIC_NAME_LIST)
def test_wrong_ids(self): def test_wrong_ids(self):
"""Test if Error is raised if IDs are of wrong type.""" """Test if Error is raised if IDs are of wrong type."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
publish(PlotIDTransfer(FIG, 3), SRC_DIR, DST_PATH, PIC_NAME) publish(PlotIDTransfer(FIG, 3), SRC_DIR, DST_PATH, PIC_NAME)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
publish(PlotIDTransfer(FIG, ['i', 4]), SRC_DIR, DST_PATH, PIC_NAME) publish(PlotIDTransfer(FIG, ["i", 4]), SRC_DIR, DST_PATH, PIC_NAME)
def test_publish_multiple_src_files(self): def test_publish_multiple_src_files(self):
""" """
...@@ -92,8 +101,13 @@ class TestPublish(unittest.TestCase): ...@@ -92,8 +101,13 @@ class TestPublish(unittest.TestCase):
""" """
files_and_dir = list(SRC_FILES) files_and_dir = list(SRC_FILES)
files_and_dir.append(SRC_DIR) files_and_dir.append(SRC_DIR)
publish(FIGS_AND_IDS, files_and_dir, DST_PATH, PIC_NAME_LIST, publish(
data_storage='individual') FIGS_AND_IDS,
files_and_dir,
DST_PATH,
PIC_NAME_LIST,
data_storage="individual",
)
for identifier in IDS_AS_LIST: for identifier in IDS_AS_LIST:
for file in SRC_FILES: for file in SRC_FILES:
path = os.path.join(DST_PATH, identifier) path = os.path.join(DST_PATH, identifier)
...@@ -103,7 +117,7 @@ class TestPublish(unittest.TestCase): ...@@ -103,7 +117,7 @@ class TestPublish(unittest.TestCase):
def test_src_directory(self): def test_src_directory(self):
"""Test if Error is raised when source directory does not exist.""" """Test if Error is raised when source directory does not exist."""
with self.assertRaises(FileNotFoundError): with self.assertRaises(FileNotFoundError):
publish(FIGS_AND_IDS, 'not_existing_folder', DST_PATH, PIC_NAME) publish(FIGS_AND_IDS, "not_existing_folder", DST_PATH, PIC_NAME)
def test_src_directory_type(self): def test_src_directory_type(self):
"""Test if Error is raised when source directory is not a string.""" """Test if Error is raised when source directory is not a string."""
...@@ -118,8 +132,7 @@ class TestPublish(unittest.TestCase): ...@@ -118,8 +132,7 @@ class TestPublish(unittest.TestCase):
destination dir does not exist. destination dir does not exist.
""" """
with self.assertRaises(FileNotFoundError): with self.assertRaises(FileNotFoundError):
publish(FIGS_AND_IDS, SRC_DIR, 'not_existing_folder/data', publish(FIGS_AND_IDS, SRC_DIR, "not_existing_folder/data", PIC_NAME)
PIC_NAME)
def test_script_exists(self): def test_script_exists(self):
""" """
...@@ -137,30 +150,46 @@ class TestPublish(unittest.TestCase): ...@@ -137,30 +150,46 @@ class TestPublish(unittest.TestCase):
python = "python" python = "python"
with self.assertRaises(CalledProcessError): with self.assertRaises(CalledProcessError):
run([python, "-c", run(
[
python,
"-c",
"import matplotlib.pyplot as plt\n" "import matplotlib.pyplot as plt\n"
"from plotid.publish import publish\n" "from plotid.publish import publish\n"
"from plotid.plotoptions import PlotIDTransfer\n" "from plotid.plotoptions import PlotIDTransfer\n"
"publish(PlotIDTransfer(plt.figure(), 'testID2')," "publish(PlotIDTransfer(plt.figure(), 'testID2'),"
" 'test_src_folder', 'test_parent/test_dst_folder'," " 'test_src_folder', 'test_parent/test_dst_folder',"
" 'test_picture')"], " 'test_picture')",
capture_output=True, check=True) ],
process = run([python, "-c", capture_output=True,
check=True,
)
process = run(
[
python,
"-c",
"import matplotlib.pyplot as plt\n" "import matplotlib.pyplot as plt\n"
"from plotid.publish import publish\n" "from plotid.publish import publish\n"
"from plotid.plotoptions import PlotIDTransfer\n" "from plotid.plotoptions import PlotIDTransfer\n"
"publish(PlotIDTransfer(plt.figure(), 'testID2'), " "publish(PlotIDTransfer(plt.figure(), 'testID2'), "
"'test_src_folder', 'test_parent/test_dst_folder', " "'test_src_folder', 'test_parent/test_dst_folder', "
"'test_picture')"], "'test_picture')",
capture_output=True) ],
assert ("FileNotFoundError: Cannot copy original python script. " capture_output=True,
)
assert (
"FileNotFoundError: Cannot copy original python script. "
"Running publish from a shell" "Running publish from a shell"
" is not possible.") in process.stderr.decode() " is not possible."
) in process.stderr.decode()
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_dst_already_exists_yes(self): def test_dst_already_exists_yes(self):
""" """
Test if publish succeeds if the user wants to overwrite an existing Test if publish succeeds if the user wants to overwrite an existing
...@@ -169,14 +198,18 @@ class TestPublish(unittest.TestCase): ...@@ -169,14 +198,18 @@ class TestPublish(unittest.TestCase):
os.mkdir(DST_PATH) os.mkdir(DST_PATH)
os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0])) os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0]))
# Mock user input as 'yes' # Mock user input as 'yes'
with patch('builtins.input', return_value='yes'): with patch("builtins.input", return_value="yes"):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, publish(
data_storage='individual') FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage="individual"
)
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_dst_already_exists_no(self): def test_dst_already_exists_no(self):
""" """
Test if publish exits with error if the user does not want to overwrite Test if publish exits with error if the user does not want to overwrite
...@@ -186,14 +219,17 @@ class TestPublish(unittest.TestCase): ...@@ -186,14 +219,17 @@ class TestPublish(unittest.TestCase):
os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0])) os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0]))
os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[1])) os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[1]))
# Mock user input as 'no' # Mock user input as 'no'
with patch('builtins.input', return_value='no'): with patch("builtins.input", return_value="no"):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME) publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME)
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_dst_already_exists_empty(self): def test_dst_already_exists_empty(self):
""" """
Test if publish exits with error if the user does not want to overwrite Test if publish exits with error if the user does not want to overwrite
...@@ -203,15 +239,19 @@ class TestPublish(unittest.TestCase): ...@@ -203,15 +239,19 @@ class TestPublish(unittest.TestCase):
os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0])) os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[0]))
os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[1])) os.mkdir(os.path.join(DST_PATH, IDS_AS_LIST[1]))
# Mock user input as empty (no should be default). # Mock user input as empty (no should be default).
with patch('builtins.input', return_value=''): with patch("builtins.input", return_value=""):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, publish(
data_storage='individual') FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, data_storage="individual"
)
# Skip test if tests are run from command line. # Skip test if tests are run from command line.
@unittest.skipIf(not os.path.isfile(sys.argv[0]), 'Publish is not called ' @unittest.skipIf(
'from a Python script. Therefore, the script cannot be ' not os.path.isfile(sys.argv[0]),
'copied.') "Publish is not called "
"from a Python script. Therefore, the script cannot be "
"copied.",
)
def test_dst_invisible_already_exists(self): def test_dst_invisible_already_exists(self):
""" """
Test if after a crash of publish the partially copied data is Test if after a crash of publish the partially copied data is
...@@ -219,33 +259,37 @@ class TestPublish(unittest.TestCase): ...@@ -219,33 +259,37 @@ class TestPublish(unittest.TestCase):
To mock this, the invisible directory already exists. To mock this, the invisible directory already exists.
""" """
os.mkdir(DST_PATH) os.mkdir(DST_PATH)
invisible_path1 = os.path.join(DST_PATH, '.' + IDS_AS_LIST[0]) invisible_path1 = os.path.join(DST_PATH, "." + IDS_AS_LIST[0])
os.mkdir(invisible_path1) os.mkdir(invisible_path1)
# Mock user input as 'yes' for deleting the partial copied data # Mock user input as 'yes' for deleting the partial copied data
with patch('builtins.input', side_effect=['yes', 'yes']): with patch("builtins.input", side_effect=["yes", "yes"]):
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME) publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME)
assert not os.path.isdir(invisible_path1) assert not os.path.isdir(invisible_path1)
os.remove('test_picture1.tmp.png') os.remove("test_picture1.tmp.png")
os.remove('test_picture2.tmp.png') os.remove("test_picture2.tmp.png")
def test_plot_names(self): def test_plot_names(self):
"""Test if Error is raised if plot_name is not a string.""" """Test if Error is raised if plot_name is not a string."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, 7.6, publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, 7.6, data_storage="individual")
data_storage='individual')
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, ()) publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, ())
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, ['test', 3]) publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, ["test", 3])
def test_data_storage(self): def test_data_storage(self):
""" """
Test if Error is raised when unsupported storage method was chosen. Test if Error is raised when unsupported storage method was chosen.
""" """
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
publish(FIGS_AND_IDS, SRC_DIR, DST_PATH, PIC_NAME, publish(
data_storage='none_existing_method') FIGS_AND_IDS,
SRC_DIR,
DST_PATH,
PIC_NAME,
data_storage="none_existing_method",
)
with self.assertRaises(TypeError): 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, PIC_NAME, data_storage=3)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
...@@ -264,7 +308,8 @@ class TestPublish(unittest.TestCase): ...@@ -264,7 +308,8 @@ class TestPublish(unittest.TestCase):
" 640x480 with 0 Axes>], 'figure_ids': " " 640x480 with 0 Axes>], 'figure_ids': "
"['MR05_0x63203c6f', 'MR05_0x63203c70'], " "['MR05_0x63203c6f', 'MR05_0x63203c70'], "
"'src_datapaths': 'test_src_folder'", "'src_datapaths': 'test_src_folder'",
str(publish_obj)) str(publish_obj),
)
def tearDown(self): def tearDown(self):
"""Delete all files created in setUp.""" """Delete all files created in setUp."""
...@@ -274,5 +319,5 @@ class TestPublish(unittest.TestCase): ...@@ -274,5 +319,5 @@ class TestPublish(unittest.TestCase):
os.remove(file) os.remove(file)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -11,9 +11,9 @@ from PIL import Image ...@@ -11,9 +11,9 @@ from PIL import Image
from plotid.save_plot import save_plot from plotid.save_plot import save_plot
FIGURE = plt.figure() FIGURE = plt.figure()
PLOT_NAME = 'PLOT_NAME' PLOT_NAME = "PLOT_NAME"
IMG1 = 'image1.png' IMG1 = "image1.png"
IMG2 = 'image2.jpg' IMG2 = "image2.jpg"
class TestSavePlot(unittest.TestCase): class TestSavePlot(unittest.TestCase):
...@@ -30,9 +30,9 @@ class TestSavePlot(unittest.TestCase): ...@@ -30,9 +30,9 @@ class TestSavePlot(unittest.TestCase):
Test if save_plot succeeds with valid arguments Test if save_plot succeeds with valid arguments
using the matplotlib engine. using the matplotlib engine.
""" """
plot_paths = save_plot(FIGURE, [PLOT_NAME], extension='jpg') plot_paths = save_plot(FIGURE, [PLOT_NAME], extension="jpg")
self.assertIsInstance(plot_paths, list) self.assertIsInstance(plot_paths, list)
os.remove(PLOT_NAME + '.tmp.jpg') os.remove(PLOT_NAME + ".tmp.jpg")
def test_save_plot_image_png(self): def test_save_plot_image_png(self):
""" """
...@@ -42,7 +42,7 @@ class TestSavePlot(unittest.TestCase): ...@@ -42,7 +42,7 @@ class TestSavePlot(unittest.TestCase):
img1 = Image.open(IMG1) img1 = Image.open(IMG1)
plot_paths = save_plot(img1, [PLOT_NAME]) plot_paths = save_plot(img1, [PLOT_NAME])
self.assertIsInstance(plot_paths, list) self.assertIsInstance(plot_paths, list)
os.remove(PLOT_NAME + '.tmp.png') os.remove(PLOT_NAME + ".tmp.png")
def test_save_plot_image_jpg(self): def test_save_plot_image_jpg(self):
""" """
...@@ -51,10 +51,10 @@ class TestSavePlot(unittest.TestCase): ...@@ -51,10 +51,10 @@ class TestSavePlot(unittest.TestCase):
""" """
img2 = Image.open(IMG2) img2 = Image.open(IMG2)
imgs_as_list = [img2, img2] imgs_as_list = [img2, img2]
plot_paths = save_plot(imgs_as_list, [PLOT_NAME], extension='jpg') plot_paths = save_plot(imgs_as_list, [PLOT_NAME], extension="jpg")
self.assertIsInstance(plot_paths, list) self.assertIsInstance(plot_paths, list)
os.remove(PLOT_NAME + '1.tmp.jpg') os.remove(PLOT_NAME + "1.tmp.jpg")
os.remove(PLOT_NAME + '2.tmp.jpg') os.remove(PLOT_NAME + "2.tmp.jpg")
def test_more_figs_than_names(self): def test_more_figs_than_names(self):
""" """
...@@ -64,8 +64,8 @@ class TestSavePlot(unittest.TestCase): ...@@ -64,8 +64,8 @@ class TestSavePlot(unittest.TestCase):
with self.assertWarns(Warning): with self.assertWarns(Warning):
save_plot([FIGURE, FIGURE, FIGURE], [PLOT_NAME]) save_plot([FIGURE, FIGURE, FIGURE], [PLOT_NAME])
for i in (1, 2, 3): for i in (1, 2, 3):
assert os.path.isfile(PLOT_NAME + f'{i}.tmp.png') assert os.path.isfile(PLOT_NAME + f"{i}.tmp.png")
os.remove(PLOT_NAME + f'{i}.tmp.png') os.remove(PLOT_NAME + f"{i}.tmp.png")
def test_more_names_than_figs(self): def test_more_names_than_figs(self):
"""Test if Error is raised if more names than figures are given.""" """Test if Error is raised if more names than figures are given."""
...@@ -75,7 +75,7 @@ class TestSavePlot(unittest.TestCase): ...@@ -75,7 +75,7 @@ class TestSavePlot(unittest.TestCase):
def test_wrong_fig_type(self): def test_wrong_fig_type(self):
"""Test if Error is raised when not a figure object is given.""" """Test if Error is raised when not a figure object is given."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
save_plot('figure', 'PLOT_NAME', extension='jpg') save_plot("figure", "PLOT_NAME", extension="jpg")
def test_wrong_fig_in_list(self): def test_wrong_fig_in_list(self):
""" """
...@@ -83,13 +83,13 @@ class TestSavePlot(unittest.TestCase): ...@@ -83,13 +83,13 @@ class TestSavePlot(unittest.TestCase):
valid figures. valid figures.
""" """
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
save_plot([FIGURE, 'figure', FIGURE], 'PLOT_NAME', extension='jpg') save_plot([FIGURE, "figure", FIGURE], "PLOT_NAME", extension="jpg")
os.remove('PLOT_NAME1.tmp.jpg') os.remove("PLOT_NAME1.tmp.jpg")
def tearDown(self): def tearDown(self):
os.remove(IMG1) os.remove(IMG1)
os.remove(IMG2) os.remove(IMG2)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -13,13 +13,13 @@ from plotid.tagplot import tagplot ...@@ -13,13 +13,13 @@ from plotid.tagplot import tagplot
FIG1 = plt.figure() FIG1 = plt.figure()
FIG2 = plt.figure() FIG2 = plt.figure()
FIGS_AS_LIST = [FIG1, FIG2] FIGS_AS_LIST = [FIG1, FIG2]
IMG1 = 'image1.png' IMG1 = "image1.png"
IMG2 = 'image2.jpg' IMG2 = "image2.jpg"
IMGS_AS_LIST = [IMG1, IMG2] IMGS_AS_LIST = [IMG1, IMG2]
PROJECT_ID = "MR01" PROJECT_ID = "MR01"
PLOT_ENGINE = "matplotlib" PLOT_ENGINE = "matplotlib"
METHOD = 'time' METHOD = "time"
class TestTagplot(unittest.TestCase): class TestTagplot(unittest.TestCase):
...@@ -36,30 +36,34 @@ class TestTagplot(unittest.TestCase): ...@@ -36,30 +36,34 @@ class TestTagplot(unittest.TestCase):
Test if tagplot runs successful. Test if tagplot runs successful.
""" """
tagplot(FIGS_AS_LIST, PLOT_ENGINE, prefix=PROJECT_ID, id_method=METHOD) tagplot(FIGS_AS_LIST, PLOT_ENGINE, prefix=PROJECT_ID, id_method=METHOD)
tagplot(IMGS_AS_LIST, 'image', location='north') tagplot(IMGS_AS_LIST, "image", location="north")
def test_prefix(self): def test_prefix(self):
"""Test if Error is raised if prefix is not a string.""" """Test if Error is raised if prefix is not a string."""
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location='southeast', tagplot(
prefix=3, id_method=METHOD) FIGS_AS_LIST,
PLOT_ENGINE,
location="southeast",
prefix=3,
id_method=METHOD,
)
def test_plotengine(self): def test_plotengine(self):
""" """
Test if Errors are raised if the provided plot engine is not supported. Test if Errors are raised if the provided plot engine is not supported.
""" """
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
tagplot(FIGS_AS_LIST, 1, location='north') tagplot(FIGS_AS_LIST, 1, location="north")
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
tagplot(FIGS_AS_LIST, 'xyz', location='south') tagplot(FIGS_AS_LIST, "xyz", location="south")
def test_idmethod(self): def test_idmethod(self):
""" """
Test if Errors are raised if the id_method is not an string. Test if Errors are raised if the id_method is not an string.
""" """
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=(0, 1), tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=(0, 1), location="west")
location='west')
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=1) tagplot(FIGS_AS_LIST, PLOT_ENGINE, id_method=1)
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
...@@ -72,12 +76,12 @@ class TestTagplot(unittest.TestCase): ...@@ -72,12 +76,12 @@ class TestTagplot(unittest.TestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location=1) tagplot(FIGS_AS_LIST, PLOT_ENGINE, location=1)
with self.assertWarns(Warning): with self.assertWarns(Warning):
tagplot(FIGS_AS_LIST, PLOT_ENGINE, location='up') tagplot(FIGS_AS_LIST, PLOT_ENGINE, location="up")
def tearDown(self): def tearDown(self):
os.remove(IMG1) os.remove(IMG1)
os.remove(IMG2) os.remove(IMG2)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -13,14 +13,14 @@ from plotid.plotoptions import PlotOptions ...@@ -13,14 +13,14 @@ from plotid.plotoptions import PlotOptions
FIG1 = plt.figure() FIG1 = plt.figure()
IMG1 = 'image1.png' IMG1 = "image1.png"
FIG2 = plt.figure() FIG2 = plt.figure()
IMG2 = 'image2.jpg' IMG2 = "image2.jpg"
IMGS_AS_LIST = [IMG1, IMG2] IMGS_AS_LIST = [IMG1, IMG2]
# Constants for tests # Constants for tests
PROJECT_ID = "MR01" PROJECT_ID = "MR01"
METHOD = 'time' METHOD = "time"
ROTATION = 90 ROTATION = 90
POSITION = (0.975, 0.35) POSITION = (0.975, 0.35)
...@@ -39,14 +39,18 @@ class TestTagplotImage(unittest.TestCase): ...@@ -39,14 +39,18 @@ class TestTagplotImage(unittest.TestCase):
Test of returned objects. Check if they are png and jpg files, Test of returned objects. Check if they are png and jpg files,
respectively. respectively.
""" """
options = PlotOptions(IMGS_AS_LIST, ROTATION, POSITION, options = PlotOptions(
prefix=PROJECT_ID, id_method=METHOD, qrcode=True) IMGS_AS_LIST,
ROTATION,
POSITION,
prefix=PROJECT_ID,
id_method=METHOD,
qrcode=True,
)
options.validate_input() options.validate_input()
figs_and_ids = tagplot_image(options) figs_and_ids = tagplot_image(options)
self.assertIsInstance(figs_and_ids.figs[0], self.assertIsInstance(figs_and_ids.figs[0], PngImagePlugin.PngImageFile)
PngImagePlugin.PngImageFile) self.assertIsInstance(figs_and_ids.figs[1], JpegImagePlugin.JpegImageFile)
self.assertIsInstance(figs_and_ids.figs[1],
JpegImagePlugin.JpegImageFile)
def test_single_image(self): def test_single_image(self):
""" """
...@@ -56,20 +60,20 @@ class TestTagplotImage(unittest.TestCase): ...@@ -56,20 +60,20 @@ class TestTagplotImage(unittest.TestCase):
options = PlotOptions(IMG1, ROTATION, POSITION) options = PlotOptions(IMG1, ROTATION, POSITION)
options.validate_input() options.validate_input()
figs_and_ids = tagplot_image(options) figs_and_ids = tagplot_image(options)
self.assertIsInstance(figs_and_ids.figs[0], self.assertIsInstance(figs_and_ids.figs[0], PngImagePlugin.PngImageFile)
PngImagePlugin.PngImageFile)
def test_image_not_str(self): def test_image_not_str(self):
"""Test if Error is raised if wrong type of image is given.""" """Test if Error is raised if wrong type of image is given."""
options = PlotOptions(3, ROTATION, POSITION, options = PlotOptions(
prefix=PROJECT_ID, id_method=METHOD) 3, ROTATION, POSITION, prefix=PROJECT_ID, id_method=METHOD
)
options.validate_input() options.validate_input()
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot_image(options) tagplot_image(options)
def test_image_not_file(self): def test_image_not_file(self):
"""Test if Error is raised if the image file does not exist.""" """Test if Error is raised if the image file does not exist."""
options = PlotOptions('xyz', ROTATION, POSITION) options = PlotOptions("xyz", ROTATION, POSITION)
options.validate_input() options.validate_input()
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot_image(options) tagplot_image(options)
...@@ -79,12 +83,12 @@ class TestTagplotImage(unittest.TestCase): ...@@ -79,12 +83,12 @@ class TestTagplotImage(unittest.TestCase):
Test if Error is raised if not an instance of PlotOptions is passed. Test if Error is raised if not an instance of PlotOptions is passed.
""" """
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot_image('wrong_object') tagplot_image("wrong_object")
def tearDown(self): def tearDown(self):
os.remove(IMG1) os.remove(IMG1)
os.remove(IMG2) os.remove(IMG2)
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
...@@ -17,7 +17,7 @@ FIGS_AS_LIST = [FIG1, FIG2] ...@@ -17,7 +17,7 @@ FIGS_AS_LIST = [FIG1, FIG2]
# Constants for tests # Constants for tests
PROJECT_ID = "MR01" PROJECT_ID = "MR01"
METHOD = 'time' METHOD = "time"
ROTATION = 90 ROTATION = 90
POSITION = (0.975, 0.35) POSITION = (0.975, 0.35)
...@@ -29,8 +29,14 @@ class TestTagplotMatplotlib(unittest.TestCase): ...@@ -29,8 +29,14 @@ class TestTagplotMatplotlib(unittest.TestCase):
def test_mplfigures(self): def test_mplfigures(self):
"""Test of returned objects. Check if they are matplotlib figures.""" """Test of returned objects. Check if they are matplotlib figures."""
options = PlotOptions(FIGS_AS_LIST, ROTATION, POSITION, options = PlotOptions(
prefix=PROJECT_ID, id_method=METHOD, qrcode=True) FIGS_AS_LIST,
ROTATION,
POSITION,
prefix=PROJECT_ID,
id_method=METHOD,
qrcode=True,
)
options.validate_input() options.validate_input()
figs_and_ids = tagplot_matplotlib(options) figs_and_ids = tagplot_matplotlib(options)
self.assertIsInstance(figs_and_ids.figs[0], Figure) self.assertIsInstance(figs_and_ids.figs[0], Figure)
...@@ -58,8 +64,8 @@ class TestTagplotMatplotlib(unittest.TestCase): ...@@ -58,8 +64,8 @@ class TestTagplotMatplotlib(unittest.TestCase):
Test if Error is raised if not an instance of PlotOptions is passed. Test if Error is raised if not an instance of PlotOptions is passed.
""" """
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
tagplot_matplotlib('wrong_object') tagplot_matplotlib("wrong_object")
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment