##// END OF EJS Templates
pandoc version is now checked at each call to pandoc.pandoc(...). Version is tested with IPython.utils.version.version_check
Daniel B. Vasquez -
Show More
@@ -1,142 +1,158 b''
1 """Utility for calling pandoc"""
1 """Utility for calling pandoc"""
2 #-----------------------------------------------------------------------------
2 #-----------------------------------------------------------------------------
3 # Copyright (c) 2013 the IPython Development Team.
3 # Copyright (c) 2013 the IPython Development Team.
4 #
4 #
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib imports
16 # Stdlib imports
17 import subprocess
17 import subprocess
18 import re
18 import re
19 import warnings
19 import warnings
20 from io import TextIOWrapper, BytesIO
20 from io import TextIOWrapper, BytesIO
21
21
22 # IPython imports
22 # IPython imports
23 from IPython.utils.py3compat import cast_bytes
23 from IPython.utils.py3compat import cast_bytes
24 from IPython.utils.version import check_version
25
24
26
25 from .exceptions import ConversionException
27 from .exceptions import ConversionException
26
28
27
29
28 #----------------------------------------------------------------------------
30 #----------------------------------------------------------------------------
29 # Preliminary checks.
31 # Preliminary checks.
30 # Not finding Pandoc is not always fatal so only a warning is issued at the
32 # Not finding Pandoc is not always fatal so only a warning is issued at the
31 # module root level so that the import of this module is not fatal.
33 # module root level so that the import of this module is not fatal.
32 #----------------------------------------------------------------------------
34 #----------------------------------------------------------------------------
33
35
34 class PandocMissing(ConversionException):
36 class PandocMissing(ConversionException):
35 """Exception raised when Pandoc is missing. """
37 """Exception raised when Pandoc is missing. """
36 def __init__(self, cmd, exc, *args, **kwargs):
38 def __init__(self, cmd, exc, *args, **kwargs):
37 super(PandocMissing, self).__init__( "The command '%s' returned an error: %s.\n" %(" ".join(cmd), exc) +
39 super(PandocMissing, self).__init__( "The command '%s' returned an error: %s.\n" %(" ".join(cmd), exc) +
38 "Please check that pandoc is installed:\n" +
40 "Please check that pandoc is installed:\n" +
39 "http://johnmacfarlane.net/pandoc/installing.html" )
41 "http://johnmacfarlane.net/pandoc/installing.html" )
40
42
41 def pandoc_available(failmode="return", warn=False, alt=None):
43 def pandoc_available(failmode="return", warn=False, alt=None):
42 """Is pandoc available. Only tries to call Pandoc
44 """Is pandoc available. Only tries to call Pandoc
43 and inform you that it succeeded or failed.
45 and inform you that it succeeded or failed.
44
46
45 Parameters
47 Parameters
46 ----------
48 ----------
47 - failmode : string
49 - failmode : string
48 either "return" or "raise". If "return" and pandoc
50 either "return" or "raise". If "return" and pandoc
49 is not available, will return (False, e) where e is
51 is not available, will return (False, e) where e is
50 the exception returned by subprocess.check_call.
52 the exception returned by subprocess.check_call.
51 - warn : bool
53 - warn : bool
52 issue a user warning if pandoc is not available.
54 issue a user warning if pandoc is not available.
53 - alt: list of strings
55 - alt: list of strings
54 command to print in the error (not used as actual call)
56 command to print in the error (not used as actual call)
55
57
56 Return
58 Return
57 ------
59 ------
58 out : (Bool, Exception)
60 out : (Bool, Exception)
59 On success will return (True, None). On failure and failmode=="return"
61 On success will return (True, None). On failure and failmode=="return"
60 will return (False, OSError instance)
62 will return (False, OSError instance)
61 """
63 """
62
64
63 cmd = ["pandoc", "-v"]
65 cmd = ["pandoc", "-v"]
64
66
65 try:
67 try:
66 out = subprocess.check_output(cmd, universal_newlines=True)
68 out = subprocess.check_output(cmd, universal_newlines=True)
67 return True, None
69 return True, None
68 except OSError as e:
70 except OSError as e:
69 if warn:
71 if warn:
70 warnings.warn(
72 warnings.warn(
71 "Pandoc cannot be found (calling %s failed).\n" % " ".join(alt or cmd) +
73 "Pandoc cannot be found (calling %s failed).\n" % " ".join(alt or cmd) +
72 "Please check that pandoc is installed:\n" +
74 "Please check that pandoc is installed:\n" +
73 "http://johnmacfarlane.net/pandoc/installing.html"
75 "http://johnmacfarlane.net/pandoc/installing.html"
74 )
76 )
75
77
76 if failmode == "return":
78 if failmode == "return":
77 return False, e
79 return False, e
78 else:
80 else:
79 raise PandocMissing(alt or cmd, e)
81 raise PandocMissing(alt or cmd, e)
80
82
81
83
82 #-----------------------------------------------------------------------------
84 #-----------------------------------------------------------------------------
83 # Classes and functions
85 # Classes and functions
84 #-----------------------------------------------------------------------------
86 #-----------------------------------------------------------------------------
85
87
86
88
87 minimal_version = "1.12.1"
89 minimal_version = "1.12.1"
90 minimal_version_ok = False
88
91
89 def pandoc(source, fmt, to, extra_args=None, encoding='utf-8'):
92 def pandoc(source, fmt, to, extra_args=None, encoding='utf-8'):
90 """Convert an input string in format `from` to format `to` via pandoc.
93 """Convert an input string in format `from` to format `to` via pandoc.
91
94
92 This function will raise an error if pandoc is not installed.
95 This function will raise PandocMissing if pandoc is not installed.
93 Any error messages generated by pandoc are printed to stderr.
96 Any error messages generated by pandoc are printed to stderr.
94
97
95 Parameters
98 Parameters
96 ----------
99 ----------
97 source : string
100 source : string
98 Input string, assumed to be valid format `from`.
101 Input string, assumed to be valid format `from`.
99 fmt : string
102 fmt : string
100 The name of the input format (markdown, etc.)
103 The name of the input format (markdown, etc.)
101 to : string
104 to : string
102 The name of the output format (html, etc.)
105 The name of the output format (html, etc.)
103
106
104 Returns
107 Returns
105 -------
108 -------
106 out : unicode
109 out : unicode
107 Output as returned by pandoc.
110 Output as returned by pandoc.
108 """
111 """
109 cmd = ['pandoc', '-f', fmt, '-t', to]
112 cmd = ['pandoc', '-f', fmt, '-t', to]
110 if extra_args:
113 if extra_args:
111 cmd.extend(extra_args)
114 cmd.extend(extra_args)
112
115
113 # if pandoc is missing let the exception bubble us out of here
116 # if pandoc is missing let the exception bubble us out of here
114 pandoc_available(failmode="raise", alt=cmd)
117 pandoc_available(failmode="raise", alt=cmd)
118 check_pandoc_version()
115
119
116 # we can safely continue
120 # we can safely continue
117 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
121 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
118 out, _ = p.communicate(cast_bytes(source, encoding))
122 out, _ = p.communicate(cast_bytes(source, encoding))
119 out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
123 out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
120 return out.rstrip('\n')
124 return out.rstrip('\n')
121
125
122
126
123 def get_pandoc_version():
127 def get_pandoc_version():
124 """Gets the Pandoc version if Pandoc is installed."""
128 """Gets the Pandoc version if Pandoc is installed.
129 PandocMissing will be raised if pandoc is unavailable.
130 """
125 try:
131 try:
126 return pandoc.version
132 if not minimal_version_ok:
133 raise AttributeError()
134 else:
135 return pandoc.version
127 except AttributeError:
136 except AttributeError:
128 out = pandoc("None", "None", "None", ["-v"])
137 cmd = ["pandoc", "-v"]
138 try:
139 out = subprocess.check_output(cmd, universal_newlines=True)
140 except OSError as e:
141 raise PandocMissing(cmd, e)
129 pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})')
142 pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})')
130 pandoc.version = pv_re.search(out).group(0)
143 pandoc.version = pv_re.search(out).group(0)
131 return pandoc.version
144 return pandoc.version
132
145
133 def check_pandoc_version():
146 def check_pandoc_version():
134 """Returns True if minimal pandoc version is met"""
147 """Returns True if minimal pandoc version is met.
135 return get_pandoc_version() >= minimal_version
148 PandocMissing will be raised if pandoc is unavailable.
136
149 """
137 if pandoc_available(warn=True)[0]:
150 global minimal_version_ok
138 if(not check_pandoc_version()):
151 if not minimal_version_ok:
139 warnings.warn( "You are using an old version of pandoc (%s)\n" % pandoc.version +
152 minimal_version_ok = check_version( get_pandoc_version(), minimal_version )
140 "Recommended version is %s.\nTry updating." % minimal_version +
153 if not minimal_version_ok:
141 "http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...",
154 warnings.warn( "You are using an old version of pandoc (%s)\n" % pandoc.version +
142 RuntimeWarning, stacklevel=2)
155 "Recommended version is %s.\nTry updating." % minimal_version +
156 "http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...",
157 RuntimeWarning, stacklevel=2)
158 return minimal_version_ok
General Comments 0
You need to be logged in to leave comments. Login now