import os
import shutil
import subprocess
from termcolor import colored
[docs]class Run(object):
PIPE = subprocess.PIPE
def __init__(self, *args, **kwargs):
self.setup(*args, **kwargs)
[docs] def setup(self, verbose=False, colorize=False):
self.verbose = verbose
self.colorize = colorize
[docs] def _print_cmd(self, cmd):
if self.colorize:
output = []
for arg in cmd:
if arg.startswith('--'):
output.append(colored(arg, color='yellow'))
elif arg.startswith('-'):
output.append(colored(arg, color='blue'))
elif os.path.exists(arg):
output.append(colored(arg, color='white',
on_color='on_cyan'))
else:
output.append(arg)
print(' '.join(output))
else:
print(' '.join(cmd))
[docs] def run(self, *args, **kwargs):
"""
:return: A `CompletedProcess` object.
:rtype: subprocess.CompletedProcess
"""
if self.verbose:
self._print_cmd(args[0])
return subprocess.run(*args, **kwargs)
[docs] def check_output(self, *args, **kwargs):
if self.verbose:
self._print_cmd(args[0])
return subprocess.check_output(*args, **kwargs)
[docs]def check_dependencies(*executables, raise_error=True):
"""Check if the given executables are existing in $PATH.
:param tuple executables: A tuple of executables to check for their
existence in $PATH. Each element of the tuple can be either a string
(e. g. `pdfimages`) or a itself a tuple `('pdfimages', 'poppler')`.
The first entry of this tuple is the name of the executable the second
entry is a description text which is displayed in the raised exception.
:param bool raise_error: Raise an error if an executable doesn’t exist.
:return: True or False. True if all executables exist. False if one or
more executables not exist.
:rtype: bool
"""
errors = []
for executable in executables:
if isinstance(executable, tuple):
if not shutil.which(executable[0]):
errors.append('{} ({})'.format(executable[0], executable[1]))
else:
if not shutil.which(executable):
errors.append(executable)
if errors:
if raise_error:
raise SystemError('Some commands are not installed: ' +
', '.join(errors))
else:
return False
else:
return True
[docs]class FilePath(object):
def __init__(self, path, absolute=False):
self.absolute = absolute
"""Boolean, indicates wheter the path is an absolute path or an
relative path."""
if self.absolute:
self.path = os.path.abspath(path)
"""The absolute (`/home/document/file.ext`) or the relative path
(`document/file.ext`) of the file."""
else:
self.path = os.path.relpath(path)
self.filename = os.path.basename(path)
"""The filename is the combination of the basename and the
extension, e. g. `file.ext`."""
self.extension = os.path.splitext(self.path)[1][1:]
"""The extension of the file, e. g. `ext`."""
self.basename = self.filename[:-len(self.extension) - 1]
"""The basename of the file, e. g. `file`."""
self.base = self.path[:-len(self.extension) - 1]
"""The path without an extension, e. g. `/home/document/file`."""
def __str__(self):
return self.path
def __eq__(self, other):
return self.path == other.path
[docs] def _export(self, path):
return FilePath(path, self.absolute)
[docs] def new(self, extension=None, append='', del_substring=''):
"""
:param str extension: The extension of the new file path.
:param str append: String to append on the basename. This string
is located before the extension.
:param str del_substring: String to delete from the new file path.
:return: A new file path object.
:rtype: FilePath
"""
if not extension:
extension = self.extension
new = '{}{}.{}'.format(self.base, append, extension)
if del_substring:
new = new.replace(del_substring, '')
return self._export(new)
[docs] def remove(self):
"""Remove the file."""
os.remove(self.path)
[docs]def argparser_to_readme(argparser, template='README-template.md',
destination='README.md', indentation=0,
placeholder='{{ argparse }}'):
"""Add the formatted help output of a command line utility using the
Python module `argparse` to a README file. Make sure to set the name
of the program (`prop`) or you get strange program names.
:param object argparser: The argparse parser object.
:param str template: The path of a template text file containing the
placeholder. Default: `README-template.md`
:param str destination: The path of the destination file. Default:
`README.me`
:param int indentation: Indent the formatted help output by X spaces.
Default: 0
:param str placeholder: Placeholder string that gets replaced by the
formatted help output. Default: `{{ argparse }}`
"""
help_string = argparser().format_help()
if indentation > 0:
indent_lines = []
lines = help_string.split('\n')
for line in lines:
indent_lines.append(' ' * indentation + line)
help_string = '\n'.join(indent_lines)
with open(template, 'r', encoding='utf-8') as template_file:
template_string = template_file.read()
readme = template_string.replace(placeholder, help_string)
readme_file = open(destination, 'w')
readme_file.write(readme)
readme_file.close()