pandoc.py
128 lines
| 4.3 KiB
| text/x-python
|
PythonLexer
MinRK
|
r11267 | """Utility for calling pandoc""" | ||
#----------------------------------------------------------------------------- | ||||
Jonathan Frederic
|
r14827 | # Copyright (c) 2014 the IPython Development Team. | ||
MinRK
|
r11267 | # | ||
# 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 | ||||
Daniel B. Vasquez
|
r14763 | from IPython.utils.version import check_version | ||
Daniel B. Vasquez
|
r14768 | from IPython.utils.process import is_cmd_found, FindCmdError | ||
Daniel B. Vasquez
|
r14763 | |||
David Wolever
|
r11703 | from .exceptions import ConversionException | ||
MinRK
|
r11267 | #----------------------------------------------------------------------------- | ||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
Daniel B. Vasquez
|
r14768 | _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. | ||
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
|
r14766 | |||
Exceptions | ||||
---------- | ||||
This function will raise PandocMissing if pandoc is not installed. | ||||
Any error messages generated by pandoc are printed to stderr. | ||||
MinRK
|
r11267 | """ | ||
Daniel B. Vasquez
|
r14760 | cmd = ['pandoc', '-f', fmt, '-t', to] | ||
MinRK
|
r11293 | if extra_args: | ||
Daniel B. Vasquez
|
r14760 | cmd.extend(extra_args) | ||
Daniel B. Vasquez
|
r14765 | # this will raise an exception that will pop us out of here | ||
Daniel B. Vasquez
|
r14763 | check_pandoc_version() | ||
Daniel B. Vasquez
|
r14760 | |||
# 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
|
r14763 | """Gets the Pandoc version if Pandoc is installed. | ||
Daniel B. Vasquez
|
r14766 | |||
Return | ||||
------ | ||||
If the minimal version is not met, it will probe Pandoc for its version, cache it and return that value. | ||||
If the minimal version is met, it will return the cached version and stop probing Pandoc | ||||
(unless `clean_cache()` is called). | ||||
Exceptions | ||||
---------- | ||||
Daniel B. Vasquez
|
r14763 | PandocMissing will be raised if pandoc is unavailable. | ||
""" | ||||
Daniel B. Vasquez
|
r14768 | global __version | ||
Daniel B. Vasquez
|
r14766 | |||
Jonathan Frederic
|
r14827 | if __version is None: | ||
Daniel B. Vasquez
|
r14768 | if not is_cmd_found('pandoc'): | ||
raise PandocMissing() | ||||
out = subprocess.check_output( ['pandoc', '-v'], universal_newlines=True) | ||||
Daniel B. Vasquez
|
r14760 | pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})') | ||
Daniel B. Vasquez
|
r14768 | __version = pv_re.search(out).group(0) | ||
Jonathan Frederic
|
r14827 | return __version | ||
Daniel B. Vasquez
|
r14766 | |||
Daniel B. Vasquez
|
r14759 | |||
def check_pandoc_version(): | ||||
Daniel B. Vasquez
|
r14763 | """Returns True if minimal pandoc version is met. | ||
Daniel B. Vasquez
|
r14766 | |||
Exceptions | ||||
---------- | ||||
Daniel B. Vasquez
|
r14763 | PandocMissing will be raised if pandoc is unavailable. | ||
""" | ||||
Daniel B. Vasquez
|
r14768 | v = get_pandoc_version() | ||
ok = check_version(v , _minimal_version ) | ||||
Daniel B. Vasquez
|
r14766 | if not ok: | ||
Daniel B. Vasquez
|
r14768 | warnings.warn( "You are using an old version of pandoc (%s)\n" % v + | ||
"Recommended version is %s.\nTry updating." % _minimal_version + | ||||
"http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...", | ||||
RuntimeWarning, stacklevel=2) | ||||
return ok | ||||
Daniel B. Vasquez
|
r14766 | |||
Daniel B. Vasquez
|
r14767 | #----------------------------------------------------------------------------- | ||
# Exception handling | ||||
#----------------------------------------------------------------------------- | ||||
class PandocMissing(ConversionException): | ||||
"""Exception raised when Pandoc is missing. """ | ||||
Daniel B. Vasquez
|
r14768 | def __init__(self, *args, **kwargs): | ||
super(PandocMissing, self).__init__( "Pandoc wasn't found.\n" + | ||||
Daniel B. Vasquez
|
r14767 | "Please check that pandoc is installed:\n" + | ||
"http://johnmacfarlane.net/pandoc/installing.html" ) | ||||
#----------------------------------------------------------------------------- | ||||
# Internal state management | ||||
#----------------------------------------------------------------------------- | ||||
Daniel B. Vasquez
|
r14768 | def clean_cache(): | ||
global __version | ||||
__version = None | ||||
Daniel B. Vasquez
|
r14767 | |||
Daniel B. Vasquez
|
r14768 | __version = None | ||