"""HTML to pdf converter. Wrapper over the wkhtmltopdf library that takes path to HTML file, path to place where resultant pdf file should be stored and then convert HTML file to PDF in the Letter format. """ import itertools import os import subprocess from oto import response from salessheets.connectors.sentry import sentry_capture_exception from salessheets.constants import errors from salessheets.constants import pdf class NoFileException(Exception): """ Exceptions that raises if os.path.isfile(html) returns False. Attributes: html (str): Wrong provided path. """ def __init__(self, html): """Show exception message. Args: html (str): Wrong provided path to html file. """ Exception.__init__(self, '{html} is not a file!'.format(html=html)) class NoWriteAccessException(Exception): """ Exceptions that raises if os.access(pdf_directory) returns False. Attributes: pdf_directory (str): Path to provided output_pdf file. """ def __init__(self, pdf_directory): """Show exception message. Args: pdf_directory (str): Path to provided output_pdf file that has no write access. """ Exception.__init__(self, 'Can\'t write to {directory} directory!' .format(directory=pdf_directory)) def convert_html_to_pdf(html, output_pdf, pdf_options=None): """ Main function, that convert html to pdf via wkhtmltopdf library. Args: html (str): HTML file path that should be converted to PDF. output_pdf (str): PDF file that will be generated after converting. pdf_options (dict): Dict of long options for wkhtmltopdf. Raises: NoFileException: no file path was provided. NoWriteAccessException: no write rights in output_pdf file directory. """ try: if not os.path.isfile(html): raise NoFileException(html) if len(output_pdf.rsplit('/', 1)) > 1: pdf_directory = output_pdf.rsplit('/', 1)[0] else: pdf_directory = '/' if not os.access(pdf_directory, os.W_OK): raise NoWriteAccessException(pdf_directory) converter = [ pdf.WKHTMLTOPDF, pdf.ENABLE_LOCAL_FILE_ACCESS, pdf.DISABLE_SMART_SHRINKING ] options = pdf.DEFAULT_PDF_OPTIONS if pdf_options: options.update(pdf_options) converter_options = list( itertools.chain.from_iterable( [['--{key}'.format(key=k), str(v)] for (k, v) in options.items()] ) ) converter.extend(converter_options) converter.append(html) converter.append(output_pdf) try: subprocess.check_call(converter, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: message = e.stderr or ''.encode('utf-8') error = response.create_error_response( code=e.returncode, message=(message.decode('utf-8').split('\n')[0])) if sentry_capture_exception: sentry_capture_exception() return error return response.Response() except (NoFileException, NoWriteAccessException) as e: error = response.create_error_response( code=errors.ERROR_CONVERTING_CODE, message=list(e.args) ) if sentry_capture_exception: sentry_capture_exception() return error