"""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