pandoc.py
140 lines
| 4.8 KiB
| text/x-python
|
PythonLexer
MinRK
|
r11267 | """Utility for calling pandoc""" | ||
#----------------------------------------------------------------------------- | ||||
# Copyright (c) 2013 the IPython Development Team. | ||||
# | ||||
# Distributed under the terms of the Modified BSD License. | ||||
# | ||||
# The full license is in the file COPYING.txt, distributed with this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
from __future__ import print_function | ||||
# Stdlib imports | ||||
import subprocess | ||||
Daniel B. Vasquez
|
r14759 | import re | ||
import warnings | ||||
MinRK
|
r12523 | from io import TextIOWrapper, BytesIO | ||
MinRK
|
r11267 | |||
# IPython imports | ||||
from IPython.utils.py3compat import cast_bytes | ||||
David Wolever
|
r11703 | from .exceptions import ConversionException | ||
Daniel B. Vasquez
|
r14760 | |||
#---------------------------------------------------------------------------- | ||||
# Preliminary checks. | ||||
# Not finding Pandoc is not always fatal so only a warning is issued at the | ||||
# module root level so that the import of this module is not fatal. | ||||
#---------------------------------------------------------------------------- | ||||
class PandocMissing(ConversionException): | ||||
"""Exception raised when Pandoc is missing. """ | ||||
def __init__(self, cmd, exc, *args, **kwargs): | ||||
super(PandocMissing, self).__init__( "The command '%s' returned an error: %s.\n" %(" ".join(cmd), exc) + | ||||
"Please check that pandoc is installed:\n" + | ||||
"http://johnmacfarlane.net/pandoc/installing.html" ) | ||||
def pandoc_available(failmode="return", warn=False): | ||||
"""Is pandoc available. Only tries to call Pandoc | ||||
and inform you that it succeeded or failed. | ||||
Parameters | ||||
---------- | ||||
- failmode : string | ||||
either "return" or "raise". If "return" and pandoc | ||||
is not available, will return (False, e) where e is | ||||
the exception returned by subprocess.check_call. | ||||
- warn : bool | ||||
issue a user warning if pandoc is not available. | ||||
Return | ||||
------ | ||||
out : (Bool, Exception) | ||||
On success will return (True, None). On failure and failmode=="return" | ||||
will return (False, OSError instance) | ||||
""" | ||||
cmd = ["pandoc", "-v"] | ||||
try: | ||||
out = subprocess.check_output(cmd, universal_newlines=True) | ||||
return True, None | ||||
except OSError, e: | ||||
if warn: | ||||
warnings.warn( | ||||
"Pandoc cannot be found (call %s failed).\n" % " ".join(cmd) + | ||||
"Please check that pandoc is installed:\n" + | ||||
"http://johnmacfarlane.net/pandoc/installing.html" | ||||
) | ||||
if failmode == "return": | ||||
return False, e | ||||
else: | ||||
raise PandocMissing(cmd, e) | ||||
MinRK
|
r11267 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
David Wolever
|
r11702 | |||
Daniel B. Vasquez
|
r14759 | minimal_version = "1.12.1" | ||
David Wolever
|
r11702 | |||
MinRK
|
r11293 | def pandoc(source, fmt, to, extra_args=None, encoding='utf-8'): | ||
MinRK
|
r11267 | """Convert an input string in format `from` to format `to` via pandoc. | ||
This function will raise an error if pandoc is not installed. | ||||
Any error messages generated by pandoc are printed to stderr. | ||||
Parameters | ||||
---------- | ||||
source : string | ||||
Input string, assumed to be valid format `from`. | ||||
fmt : string | ||||
The name of the input format (markdown, etc.) | ||||
to : string | ||||
The name of the output format (html, etc.) | ||||
Returns | ||||
------- | ||||
out : unicode | ||||
Output as returned by pandoc. | ||||
""" | ||||
Daniel B. Vasquez
|
r14760 | cmd = ['pandoc', '-f', fmt, '-t', to] | ||
MinRK
|
r11293 | if extra_args: | ||
Daniel B. Vasquez
|
r14760 | cmd.extend(extra_args) | ||
# if pandoc is missing let the exception bubble us out of here | ||||
pandoc_available(failmode="raise") | ||||
# we can safely continue | ||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | ||||
MinRK
|
r11267 | out, _ = p.communicate(cast_bytes(source, encoding)) | ||
MinRK
|
r12523 | out = TextIOWrapper(BytesIO(out), encoding, 'replace').read() | ||
return out.rstrip('\n') | ||||
MinRK
|
r11267 | |||
Daniel B. Vasquez
|
r14759 | |||
def get_pandoc_version(): | ||||
Daniel B. Vasquez
|
r14760 | """Gets the Pandoc version if Pandoc is installed.""" | ||
try: | ||||
return pandoc.version | ||||
except AttributeError: | ||||
out = pandoc("None", "None", "None", ["-v"]) | ||||
pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})') | ||||
pandoc.version = pv_re.search(out).group(0) | ||||
return pandoc.version | ||||
Daniel B. Vasquez
|
r14759 | |||
def check_pandoc_version(): | ||||
Daniel B. Vasquez
|
r14760 | """Returns True if minimal pandoc version is met""" | ||
return get_pandoc_version() >= minimal_version | ||||
Daniel B. Vasquez
|
r14761 | if pandoc_available(warn=True)[0]: | ||
if(not check_pandoc_version()): | ||||
warnings.warn( "You are using an old version of pandoc (%s)\n" % pandoc.version + | ||||
"Recommended version is %s.\nTry updating." % minimal_version + | ||||
"http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...", | ||||
RuntimeWarning, stacklevel=2) | ||||