##// END OF EJS Templates
big cleanup of nbconvert.utils.pandoc module. Remove useless functions, less cached values.
Daniel B. Vasquez -
Show More
@@ -1,65 +1,75 b''
1 """Test Pandoc module"""
1 """Test Pandoc module"""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2013 The IPython Development Team
4 # Copyright (C) 2013 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import os
14 import os
15
15
16 from .base import TestsBase
16 from .base import TestsBase
17 from ..utils import pandoc
17 from ..utils import pandoc
18
18
19 from IPython.testing import decorators as dec
19 from IPython.testing import decorators as dec
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Constants
22 # Constants
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Classes and functions
27 # Classes and functions
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30
30 class TestPandoc(TestsBase):
31 class TestPandoc(TestsBase):
31 """Collection of Pandoc tests"""
32 """Collection of Pandoc tests"""
32
33
33 def __init__(self, *args, **kwargs):
34 def __init__(self, *args, **kwargs):
34 super(TestPandoc, self).__init__(*args, **kwargs)
35 super(TestPandoc, self).__init__(*args, **kwargs)
35 self.original_env = os.environ.copy()
36 self.original_env = os.environ.copy()
36
37
37 @dec.onlyif_cmds_exist('pandoc')
38 @dec.onlyif_cmds_exist('pandoc')
38 def test_pandoc_available(self):
39 def test_pandoc_available(self):
39 """ Test behaviour of pandoc_available() """
40 """ Test behaviour that pandoc functions raise PandocMissing as documented """
41 pandoc.clean_cache()
42
40 os.environ["PATH"] = ""
43 os.environ["PATH"] = ""
41 assert not pandoc.pandoc_available()
44 assert pandoc_function_raised_missing(pandoc.get_pandoc_version) == True
42 try:
45 assert pandoc_function_raised_missing(pandoc.check_pandoc_version) == True
43 pandoc.pandoc_available(failmode="raise")
46 assert pandoc_function_raised_missing(pandoc.pandoc, "", "markdown", "html") == True
44 except pandoc.PandocMissing:
45 assert True
46
47
48 # original_env["PATH"] should contain pandoc
47 os.environ["PATH"] = self.original_env["PATH"]
49 os.environ["PATH"] = self.original_env["PATH"]
48 assert pandoc.pandoc_available()
50 assert pandoc_function_raised_missing(pandoc.get_pandoc_version) == False
49 try:
51 assert pandoc_function_raised_missing(pandoc.check_pandoc_version) == False
50 pandoc.pandoc_available(failmode="raise")
52 assert pandoc_function_raised_missing(pandoc.pandoc, "", "markdown", "html") == False
51 except pandoc.PandocMissing:
53
52 assert False
53
54
54 @dec.onlyif_cmds_exist('pandoc')
55 @dec.onlyif_cmds_exist('pandoc')
55 def test_minimal_version(self):
56 def test_minimal_version(self):
56 original_minversion = pandoc.minimal_version
57 original_minversion = pandoc._minimal_version
57
58
58 pandoc.minimal_version = "120.0"
59 pandoc._minimal_version = "120.0"
59 assert not pandoc.check_pandoc_version()
60 assert not pandoc.check_pandoc_version()
60
61
61 pandoc.minimal_version = pandoc.get_pandoc_version()
62 pandoc._minimal_version = pandoc.get_pandoc_version()
62 assert pandoc.check_pandoc_version()
63 assert pandoc.check_pandoc_version()
63
64
64
65
65
66
67
68 def pandoc_function_raised_missing(f, *args, **kwargs):
69 try:
70 f(*args, **kwargs)
71 except pandoc.PandocMissing as e:
72 print e
73 return True
74 else:
75 return False
@@ -1,192 +1,135 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
24 from IPython.utils.version import check_version
25 from IPython.utils.process import find_cmd, FindCmdError
25 from IPython.utils.process import is_cmd_found, FindCmdError
26
26
27
27
28 from .exceptions import ConversionException
28 from .exceptions import ConversionException
29
29
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31 # Classes and functions
31 # Classes and functions
32 #-----------------------------------------------------------------------------
32 #-----------------------------------------------------------------------------
33 minimal_version = "1.12.1"
33 _minimal_version = "1.12.1"
34
35 # command line to make pandoc print it's version. It is also the
36 # easiest way to make pandoc return at all.
37 __pandoc_version_call = ['pandoc', '-v']
38
39
34
40 def pandoc(source, fmt, to, extra_args=None, encoding='utf-8'):
35 def pandoc(source, fmt, to, extra_args=None, encoding='utf-8'):
41 """Convert an input string in format `from` to format `to` via pandoc.
36 """Convert an input string in format `from` to format `to` via pandoc.
42
37
43 Parameters
38 Parameters
44 ----------
39 ----------
45 source : string
40 source : string
46 Input string, assumed to be valid format `from`.
41 Input string, assumed to be valid format `from`.
47 fmt : string
42 fmt : string
48 The name of the input format (markdown, etc.)
43 The name of the input format (markdown, etc.)
49 to : string
44 to : string
50 The name of the output format (html, etc.)
45 The name of the output format (html, etc.)
51
46
52 Returns
47 Returns
53 -------
48 -------
54 out : unicode
49 out : unicode
55 Output as returned by pandoc.
50 Output as returned by pandoc.
56
51
57 Exceptions
52 Exceptions
58 ----------
53 ----------
59 This function will raise PandocMissing if pandoc is not installed.
54 This function will raise PandocMissing if pandoc is not installed.
60 Any error messages generated by pandoc are printed to stderr.
55 Any error messages generated by pandoc are printed to stderr.
61
56
62 """
57 """
63 cmd = ['pandoc', '-f', fmt, '-t', to]
58 cmd = ['pandoc', '-f', fmt, '-t', to]
64 if extra_args:
59 if extra_args:
65 cmd.extend(extra_args)
60 cmd.extend(extra_args)
66
61
67 # this will raise an exception that will pop us out of here
62 # this will raise an exception that will pop us out of here
68 check_pandoc_version()
63 check_pandoc_version()
69
64
70 # we can safely continue
65 # we can safely continue
71 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
66 p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
72 out, _ = p.communicate(cast_bytes(source, encoding))
67 out, _ = p.communicate(cast_bytes(source, encoding))
73 out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
68 out = TextIOWrapper(BytesIO(out), encoding, 'replace').read()
74 return out.rstrip('\n')
69 return out.rstrip('\n')
75
70
76
71
77 def pandoc_available(failmode="return", warn=False):
78 """Is pandoc available. Relies on `IPython.utils.process.find_cmd`.
79
80 Parameters
81 ----------
82 - failmode : string
83 either "return" or "raise". See below.
84 - warn : bool
85 issue a user warning if pandoc is not available.
86
87 Return
88 ------
89 out : (Bool, Exception)
90 On success will return True. On failure and failmode=="return"
91 will return False-valued PandocMissing instance. If failmode is
92 anything else, the function will not return but raise PandocMissing.
93 """
94
95 try:
96 find_cmd("pandoc")
97 return True
98 except FindCmdError as e:
99 if warn:
100 warnings.warn(
101 "Pandoc cannot be found (find_cmd('pandoc') failed).\n"+
102 "Please check that pandoc is installed:\n" +
103 "http://johnmacfarlane.net/pandoc/installing.html"
104 )
105
106 exc = PandocMissing("pandoc", e)
107 if failmode == "return":
108 return exc
109 else:
110 raise exc
111
112
113 def get_pandoc_version():
72 def get_pandoc_version():
114 """Gets the Pandoc version if Pandoc is installed.
73 """Gets the Pandoc version if Pandoc is installed.
115
74
116 Return
75 Return
117 ------
76 ------
118 If the minimal version is not met, it will probe Pandoc for its version, cache it and return that value.
77 If the minimal version is not met, it will probe Pandoc for its version, cache it and return that value.
119 If the minimal version is met, it will return the cached version and stop probing Pandoc
78 If the minimal version is met, it will return the cached version and stop probing Pandoc
120 (unless `clean_cache()` is called).
79 (unless `clean_cache()` is called).
121
80
122 Exceptions
81 Exceptions
123 ----------
82 ----------
124 PandocMissing will be raised if pandoc is unavailable.
83 PandocMissing will be raised if pandoc is unavailable.
125 """
84 """
85 global __version
126
86
127 if __cache['version_ok'] and __cache['version']:
87 if __version is not None:
128 return __cache['version']
88 return __version
129 else:
89 else:
130 pandoc_available(failmode="raise")
90 if not is_cmd_found('pandoc'):
131 out = subprocess.check_output(__pandoc_version_call, universal_newlines=True)
91 raise PandocMissing()
92
93 out = subprocess.check_output( ['pandoc', '-v'], universal_newlines=True)
132 pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})')
94 pv_re = re.compile(r'(\d{0,3}\.\d{0,3}\.\d{0,3})')
133 __cache['version'] = version = pv_re.search(out).group(0)
95 __version = pv_re.search(out).group(0)
134 return version
96 return __version
135
97
136
98
137 def check_pandoc_version():
99 def check_pandoc_version():
138 """Returns True if minimal pandoc version is met.
100 """Returns True if minimal pandoc version is met.
139
101
140 Exceptions
102 Exceptions
141 ----------
103 ----------
142 PandocMissing will be raised if pandoc is unavailable.
104 PandocMissing will be raised if pandoc is unavailable.
143 """
105 """
144 ok = __cache['version_ok']
106 v = get_pandoc_version()
107 ok = check_version(v , _minimal_version )
145 if not ok:
108 if not ok:
146 __cache['version_ok'] = ok = check_version( get_pandoc_version(), minimal_version )
109 warnings.warn( "You are using an old version of pandoc (%s)\n" % v +
147 if not ok:
110 "Recommended version is %s.\nTry updating." % _minimal_version +
148 warnings.warn( "You are using an old version of pandoc (%s)\n" % __cache['version'] +
111 "http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...",
149 "Recommended version is %s.\nTry updating." % minimal_version +
112 RuntimeWarning, stacklevel=2)
150 "http://johnmacfarlane.net/pandoc/installing.html.\nContinuing with doubts...",
113 return ok
151 RuntimeWarning, stacklevel=2)
152 return __cache['version_ok']
153
114
154 #-----------------------------------------------------------------------------
115 #-----------------------------------------------------------------------------
155 # Exception handling
116 # Exception handling
156 #-----------------------------------------------------------------------------
117 #-----------------------------------------------------------------------------
157 class PandocMissing(ConversionException):
118 class PandocMissing(ConversionException):
158 """Exception raised when Pandoc is missing. """
119 """Exception raised when Pandoc is missing. """
159 def __init__(self, cmd, exc, *args, **kwargs):
120 def __init__(self, *args, **kwargs):
160 super(PandocMissing, self).__init__( "The command '%s' returned an error: %s.\n" %(" ".join(cmd), exc) +
121 super(PandocMissing, self).__init__( "Pandoc wasn't found.\n" +
161 "Please check that pandoc is installed:\n" +
122 "Please check that pandoc is installed:\n" +
162 "http://johnmacfarlane.net/pandoc/installing.html" )
123 "http://johnmacfarlane.net/pandoc/installing.html" )
163 self.exc = exc
164
165 def __bool__(self):
166 return False
167
168 __nonzero__ = __bool__
169
170
124
171 #-----------------------------------------------------------------------------
125 #-----------------------------------------------------------------------------
172 # Internal state management
126 # Internal state management
173 #-----------------------------------------------------------------------------
127 #-----------------------------------------------------------------------------
174 def clean_cache(new=False):
128 def clean_cache():
175 if new:
129 global __version
176 global __cache
130 __version = None
177 cache = {}
178 __cache = cache
179 else:
180 cache = __cache
181 cache.clear()
182
183 cache['version_ok'] = False
184 cache['version'] = None
185 return cache
186
187 # The following holds cache values about the pandoc executable.
188 __cache = clean_cache(new=True)
189
131
132 __version = None
190
133
191
134
192
135
General Comments 0
You need to be logged in to leave comments. Login now