##// END OF EJS Templates
updated tests to use get_output_error_code
Paul Ivanov -
Show More
@@ -1,177 +1,171 b''
1 """
1 """
2 Contains base test class for nbconvert
2 Contains base test class for nbconvert
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
5 #Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 #Distributed under the terms of the Modified BSD License.
7 #Distributed under the terms of the Modified BSD License.
8 #
8 #
9 #The full license is in the file COPYING.txt, distributed with this software.
9 #The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import subprocess
17 import os
16 import os
18 import glob
17 import glob
19 import shutil
18 import shutil
20 import sys
21
19
22 import IPython
20 import IPython
23 from IPython.utils.tempdir import TemporaryDirectory
21 from IPython.utils.tempdir import TemporaryDirectory
24 from IPython.utils import py3compat
22 from IPython.utils.process import get_output_error_code
25
23
26 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
27 # Classes and functions
25 # Classes and functions
28 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
29
27
30 class TemporaryWorkingDirectory(TemporaryDirectory):
28 class TemporaryWorkingDirectory(TemporaryDirectory):
31 """
29 """
32 Creates a temporary directory and sets the cwd to that directory.
30 Creates a temporary directory and sets the cwd to that directory.
33 Automatically reverts to previous cwd upon cleanup.
31 Automatically reverts to previous cwd upon cleanup.
34 Usage example:
32 Usage example:
35
33
36 with TemporaryWorakingDirectory() as tmpdir:
34 with TemporaryWorakingDirectory() as tmpdir:
37 ...
35 ...
38 """
36 """
39
37
40 def __init__(self, **kw):
38 def __init__(self, **kw):
41 """
39 """
42 Constructor
40 Constructor
43 """
41 """
44 super(TemporaryWorkingDirectory, self).__init__(**kw)
42 super(TemporaryWorkingDirectory, self).__init__(**kw)
45
43
46 #Change cwd to new temp dir. Remember old cwd.
44 #Change cwd to new temp dir. Remember old cwd.
47 self.old_wd = os.getcwd()
45 self.old_wd = os.getcwd()
48 os.chdir(self.name)
46 os.chdir(self.name)
49
47
50
48
51 def cleanup(self):
49 def cleanup(self):
52 """
50 """
53 Destructor
51 Destructor
54 """
52 """
55
53
56 #Revert to old cwd.
54 #Revert to old cwd.
57 os.chdir(self.old_wd)
55 os.chdir(self.old_wd)
58
56
59 #Cleanup
57 #Cleanup
60 super(TemporaryWorkingDirectory, self).cleanup()
58 super(TemporaryWorkingDirectory, self).cleanup()
61
59
62
60
63 class TestsBase(object):
61 class TestsBase(object):
64 """Base tests class. Contains usefull fuzzy comparison and nbconvert
62 """Base tests class. Contains usefull fuzzy comparison and nbconvert
65 functions."""
63 functions."""
66
64
67
65
68 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
66 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
69 fuzzy_spacing=True, ignore_spaces=False,
67 fuzzy_spacing=True, ignore_spaces=False,
70 ignore_newlines=False, case_sensitive=False):
68 ignore_newlines=False, case_sensitive=False):
71 """
69 """
72 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
70 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
73 comparison that ignores insignificant differences in the two comparands.
71 comparison that ignores insignificant differences in the two comparands.
74 The significance of certain differences can be specified via the keyword
72 The significance of certain differences can be specified via the keyword
75 parameters of this method.
73 parameters of this method.
76 """
74 """
77
75
78 if newlines_are_spaces:
76 if newlines_are_spaces:
79 a = a.replace('\n', ' ')
77 a = a.replace('\n', ' ')
80 b = b.replace('\n', ' ')
78 b = b.replace('\n', ' ')
81
79
82 if tabs_are_spaces:
80 if tabs_are_spaces:
83 a = a.replace('\t', ' ')
81 a = a.replace('\t', ' ')
84 b = b.replace('\t', ' ')
82 b = b.replace('\t', ' ')
85
83
86 if ignore_spaces:
84 if ignore_spaces:
87 a = a.replace(' ', '')
85 a = a.replace(' ', '')
88 b = b.replace(' ', '')
86 b = b.replace(' ', '')
89
87
90 if fuzzy_spacing:
88 if fuzzy_spacing:
91 a = self.recursive_replace(a, ' ', ' ')
89 a = self.recursive_replace(a, ' ', ' ')
92 b = self.recursive_replace(b, ' ', ' ')
90 b = self.recursive_replace(b, ' ', ' ')
93
91
94 if ignore_newlines:
92 if ignore_newlines:
95 a = a.replace('\n', '')
93 a = a.replace('\n', '')
96 b = b.replace('\n', '')
94 b = b.replace('\n', '')
97
95
98 if not case_sensitive:
96 if not case_sensitive:
99 a = a.lower()
97 a = a.lower()
100 b = b.lower()
98 b = b.lower()
101
99
102 return a == b
100 return a == b
103
101
104
102
105 def recursive_replace(self, text, search, replacement):
103 def recursive_replace(self, text, search, replacement):
106 """
104 """
107 Performs a recursive replacement operation. Replaces all instances
105 Performs a recursive replacement operation. Replaces all instances
108 of a search string in a text string with a replacement string until
106 of a search string in a text string with a replacement string until
109 the search string no longer exists. Recursion is needed because the
107 the search string no longer exists. Recursion is needed because the
110 replacement string may generate additional search strings.
108 replacement string may generate additional search strings.
111
109
112 For example:
110 For example:
113 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
111 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
114 Another replacement yields "Hi" (the desired output)
112 Another replacement yields "Hi" (the desired output)
115
113
116 Parameters:
114 Parameters:
117 -----------
115 -----------
118 text : string
116 text : string
119 Text to replace in.
117 Text to replace in.
120 search : string
118 search : string
121 String to search for within "text"
119 String to search for within "text"
122 replacement : string
120 replacement : string
123 String to replace "search" with
121 String to replace "search" with
124 """
122 """
125 while search in text:
123 while search in text:
126 text = text.replace(search, replacement)
124 text = text.replace(search, replacement)
127 return text
125 return text
128
126
129
127
130 def create_temp_cwd(self, copy_filenames=None):
128 def create_temp_cwd(self, copy_filenames=None):
131 temp_dir = TemporaryWorkingDirectory()
129 temp_dir = TemporaryWorkingDirectory()
132
130
133 #Copy the files if requested.
131 #Copy the files if requested.
134 if not copy_filenames is None:
132 if not copy_filenames is None:
135 self.copy_files_to(copy_filenames)
133 self.copy_files_to(copy_filenames)
136
134
137 #Return directory handler
135 #Return directory handler
138 return temp_dir
136 return temp_dir
139
137
140
138
141 def copy_files_to(self, copy_filenames=None, destination=None):
139 def copy_files_to(self, copy_filenames=None, destination=None):
142
140
143 #Copy test files into the destination directory.
141 #Copy test files into the destination directory.
144 if copy_filenames:
142 if copy_filenames:
145 for pattern in copy_filenames:
143 for pattern in copy_filenames:
146 for match in glob.glob(os.path.join(self._get_files_path(), pattern)):
144 for match in glob.glob(os.path.join(self._get_files_path(), pattern)):
147 if destination is None:
145 if destination is None:
148 shutil.copyfile(match, os.path.basename(match))
146 shutil.copyfile(match, os.path.basename(match))
149 else:
147 else:
150 if not os.path.isdir(destination):
148 if not os.path.isdir(destination):
151 os.makedirs(destination)
149 os.makedirs(destination)
152 shutil.copyfile(match, os.path.join(destination, os.path.basename(match)))
150 shutil.copyfile(match, os.path.join(destination, os.path.basename(match)))
153
151
154
152
155 def _get_files_path(self):
153 def _get_files_path(self):
156
154
157 #Get the relative path to this module in the IPython directory.
155 #Get the relative path to this module in the IPython directory.
158 names = self.__module__.split('.')[1:-1]
156 names = self.__module__.split('.')[1:-1]
159 names.append('files')
157 names.append('files')
160
158
161 #Build a path using the IPython directory and the relative path we just
159 #Build a path using the IPython directory and the relative path we just
162 #found.
160 #found.
163 path = IPython.__path__[0]
161 path = IPython.__path__[0]
164 for name in names:
162 for name in names:
165 path = os.path.join(path, name)
163 path = os.path.join(path, name)
166 return path
164 return path
167
165
168
166
169 def call(self, parameters):
167 def call(self, parameters, raise_on_error=True):
170 output = subprocess.Popen(parameters, stdout=subprocess.PIPE).communicate()[0]
168 stdout, stderr, retcode = get_output_error_code(parameters)
171
169 if retcode != 0 and raise_on_error:
172 #Convert the output to a string if running Python3
170 raise OSError(stderr)
173 if py3compat.PY3:
171 return stdout, stderr
174 return output.decode('utf-8')
175 else:
176 return output
177 No newline at end of file
@@ -1,149 +1,152 b''
1 """
1 """
2 Contains tests for the nbconvertapp
2 Contains tests for the nbconvertapp
3 """
3 """
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 #Copyright (c) 2013, the IPython Development Team.
5 #Copyright (c) 2013, the IPython Development Team.
6 #
6 #
7 #Distributed under the terms of the Modified BSD License.
7 #Distributed under the terms of the Modified BSD License.
8 #
8 #
9 #The full license is in the file COPYING.txt, distributed with this software.
9 #The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11
11
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13 # Imports
13 # Imports
14 #-----------------------------------------------------------------------------
14 #-----------------------------------------------------------------------------
15
15
16 import os
16 import os
17 from .base import TestsBase
17 from .base import TestsBase
18
18
19 from IPython.utils import py3compat
19 from IPython.utils import py3compat
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21
21
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Constants
24 # Constants
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 # Define ipython commandline name
27 # Define ipython commandline name
28 if py3compat.PY3:
28 if py3compat.PY3:
29 IPYTHON = 'ipython3'
29 IPYTHON = 'ipython3'
30 else:
30 else:
31 IPYTHON = 'ipython'
31 IPYTHON = 'ipython'
32
32
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Classes and functions
35 # Classes and functions
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 class TestNbConvertApp(TestsBase):
38 class TestNbConvertApp(TestsBase):
39 """Collection of NbConvertApp tests"""
39 """Collection of NbConvertApp tests"""
40
40
41
41
42 def test_notebook_help(self):
42 def test_notebook_help(self):
43 """
43 """
44 Will help show if no notebooks are specified?
44 Will help show if no notebooks are specified?
45 """
45 """
46 with self.create_temp_cwd():
46 with self.create_temp_cwd():
47 assert "see '--help-all'" in self.call([IPYTHON, 'nbconvert'])
47 out, err = self.call(IPYTHON + ' nbconvert', raise_on_error=False)
48 assert "see '--help-all'" in out
48
49
49
50
50 def test_glob(self):
51 def test_glob(self):
51 """
52 """
52 Do search patterns work for notebook names?
53 Do search patterns work for notebook names?
53 """
54 """
54 with self.create_temp_cwd(['notebook*.ipynb']):
55 with self.create_temp_cwd(['notebook*.ipynb']):
55 assert not 'error' in self.call([IPYTHON, 'nbconvert',
56 self.call(IPYTHON + ' nbconvert --to="python"'
56 '--to="python"', '--notebooks=["*.ipynb"]']).lower()
57 ' --notebooks=["*.ipynb"]')
57 assert os.path.isfile('notebook1.py')
58 assert os.path.isfile('notebook1.py')
58 assert os.path.isfile('notebook2.py')
59 assert os.path.isfile('notebook2.py')
59
60
60
61
61 def test_glob_subdir(self):
62 def test_glob_subdir(self):
62 """
63 """
63 Do search patterns work for subdirectory notebook names?
64 Do search patterns work for subdirectory notebook names?
64 """
65 """
65 with self.create_temp_cwd() as cwd:
66 with self.create_temp_cwd():
66 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
67 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
67 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to="python"',
68 self.call(IPYTHON + ' nbconvert --to="python"',
68 '--notebooks=["%s"]' % os.path.join('subdir', '*.ipynb')]).lower()
69 ' --notebooks=["%s"]' % os.path.join('subdir', '*.ipynb'))
69 assert os.path.isfile('notebook1.py')
70 assert os.path.isfile('notebook1.py')
70 assert os.path.isfile('notebook2.py')
71 assert os.path.isfile('notebook2.py')
71
72
72
73
73 def test_explicit(self):
74 def test_explicit(self):
74 """
75 """
75 Do explicit notebook names work?
76 Do explicit notebook names work?
76 """
77 """
77 with self.create_temp_cwd(['notebook*.ipynb']):
78 with self.create_temp_cwd(['notebook*.ipynb']):
78 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to="python"',
79 self.call(IPYTHON + ' nbconvert --to="python"'
79 '--notebooks=["notebook2.ipynb"]']).lower()
80 ' --notebooks=["notebook2.ipynb"]')
80 assert not os.path.isfile('notebook1.py')
81 assert not os.path.isfile('notebook1.py')
81 assert os.path.isfile('notebook2.py')
82 assert os.path.isfile('notebook2.py')
82
83
83
84
84 @dec.onlyif_cmds_exist('pdflatex')
85 @dec.onlyif_cmds_exist('pdflatex')
85 def test_post_processor(self):
86 def test_post_processor(self):
86 """
87 """
87 Do post processors work?
88 Do post processors work?
88 """
89 """
89 with self.create_temp_cwd(['notebook1.ipynb']):
90 with self.create_temp_cwd(['notebook1.ipynb']):
90 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to="latex"',
91 self.call(IPYTHON + ' nbconvert --to="latex" notebook1'
91 'notebook1', '--post="PDF"', '--PDFPostProcessor.verbose=True']).lower()
92 ' --post="PDF" --PDFPostProcessor.verbose=True')
92 assert os.path.isfile('notebook1.tex')
93 assert os.path.isfile('notebook1.tex')
93 print("\n\n\t" + "\n\t".join([f for f in os.listdir('.') if os.path.isfile(f)]) + "\n\n")
94 print("\n\n\t" + "\n\t".join([f for f in os.listdir('.') if os.path.isfile(f)]) + "\n\n")
94 assert os.path.isfile('notebook1.pdf')
95 assert os.path.isfile('notebook1.pdf')
95
96
96
97
97 def test_template(self):
98 def test_template(self):
98 """
99 """
99 Do export templates work?
100 Do export templates work?
100 """
101 """
101 with self.create_temp_cwd(['notebook2.ipynb']):
102 with self.create_temp_cwd(['notebook2.ipynb']):
102 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to=slides',
103 self.call(IPYTHON + ' nbconvert --to=slides'
103 '--notebooks=["notebook2.ipynb"]', '--template=reveal']).lower()
104 ' --notebooks=["notebook2.ipynb"]'
105 ' --template=reveal')
104 assert os.path.isfile('notebook2.slides.html')
106 assert os.path.isfile('notebook2.slides.html')
105 with open('notebook2.slides.html') as f:
107 with open('notebook2.slides.html') as f:
106 assert '/reveal.css' in f.read()
108 assert '/reveal.css' in f.read()
107
109
108
110
109 def test_glob_explicit(self):
111 def test_glob_explicit(self):
110 """
112 """
111 Can a search pattern be used along with matching explicit notebook names?
113 Can a search pattern be used along with matching explicit notebook names?
112 """
114 """
113 with self.create_temp_cwd(['notebook*.ipynb']):
115 with self.create_temp_cwd(['notebook*.ipynb']):
114 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to="python"',
116 self.call(IPYTHON + ' nbconvert --to="python" --notebooks='
115 '--notebooks=["*.ipynb", "notebook1.ipynb", "notebook2.ipynb"]']).lower()
117 '["*.ipynb", "notebook1.ipynb", "notebook2.ipynb"]')
116 assert os.path.isfile('notebook1.py')
118 assert os.path.isfile('notebook1.py')
117 assert os.path.isfile('notebook2.py')
119 assert os.path.isfile('notebook2.py')
118
120
119
121
120 def test_explicit_glob(self):
122 def test_explicit_glob(self):
121 """
123 """
122 Can explicit notebook names be used and then a matching search pattern?
124 Can explicit notebook names be used and then a matching search pattern?
123 """
125 """
124 with self.create_temp_cwd(['notebook*.ipynb']):
126 with self.create_temp_cwd(['notebook*.ipynb']):
125 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--to="python"',
127 self.call(IPYTHON + ' nbconvert --to="python" --notebooks='
126 '--notebooks=["notebook1.ipynb", "notebook2.ipynb", "*.ipynb"]']).lower()
128 '["notebook1.ipynb", "notebook2.ipynb", "*.ipynb"]')
127 assert os.path.isfile('notebook1.py')
129 assert os.path.isfile('notebook1.py')
128 assert os.path.isfile('notebook2.py')
130 assert os.path.isfile('notebook2.py')
129
131
130
132
131 def test_default_config(self):
133 def test_default_config(self):
132 """
134 """
133 Does the default config work?
135 Does the default config work?
134 """
136 """
135 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
137 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
136 assert not 'error' in self.call([IPYTHON, 'nbconvert']).lower()
138 self.call(IPYTHON + ' nbconvert')
137 assert os.path.isfile('notebook1.py')
139 assert os.path.isfile('notebook1.py')
138 assert not os.path.isfile('notebook2.py')
140 assert not os.path.isfile('notebook2.py')
139
141
140
142
141 def test_override_config(self):
143 def test_override_config(self):
142 """
144 """
143 Can the default config be overriden?
145 Can the default config be overriden?
144 """
146 """
145 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py',
147 with self.create_temp_cwd(['notebook*.ipynb',
148 'ipython_nbconvert_config.py',
146 'override.py']):
149 'override.py']):
147 assert not 'error' in self.call([IPYTHON, 'nbconvert', '--config="override.py"']).lower()
150 self.call(IPYTHON + ' nbconvert --config="override.py"')
148 assert not os.path.isfile('notebook1.py')
151 assert not os.path.isfile('notebook1.py')
149 assert os.path.isfile('notebook2.py')
152 assert os.path.isfile('notebook2.py')
General Comments 0
You need to be logged in to leave comments. Login now