##// END OF EJS Templates
Further refinement
Jonathan Frederic -
Show More
@@ -1,143 +1,155 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 os
16 import os
17 import glob
17 import glob
18 import shutil
18 import shutil
19
19
20 import IPython
20 import IPython
21 from IPython.utils.tempdir import TemporaryWorkingDirectory
21 from IPython.utils.tempdir import TemporaryWorkingDirectory
22 from IPython.utils.process import get_output_error_code
22 from IPython.utils.process import get_output_error_code
23 from IPython.testing.tools import get_ipython_cmd
23 from IPython.testing.tools import get_ipython_cmd
24 from IPython.testing.ipunittest import ParametricTestCase
24 from IPython.testing.ipunittest import ParametricTestCase
25
25
26 # a trailing space allows for simpler concatenation with the other arguments
26 # a trailing space allows for simpler concatenation with the other arguments
27 ipy_cmd = get_ipython_cmd(as_string=True) + " "
27 ipy_cmd = get_ipython_cmd(as_string=True) + " "
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33
33
34 class TestsBase(ParametricTestCase):
34 class TestsBase(ParametricTestCase):
35 """Base tests class. Contains useful fuzzy comparison and nbconvert
35 """Base tests class. Contains useful fuzzy comparison and nbconvert
36 functions."""
36 functions."""
37
37
38
38
39 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
39 def fuzzy_compare(self, a, b, newlines_are_spaces=True, tabs_are_spaces=True,
40 fuzzy_spacing=True, ignore_spaces=False,
40 fuzzy_spacing=True, ignore_spaces=False,
41 ignore_newlines=False, case_sensitive=False, leave_padding=False):
41 ignore_newlines=False, case_sensitive=False, leave_padding=False):
42 """
42 """
43 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
43 Performs a fuzzy comparison of two strings. A fuzzy comparison is a
44 comparison that ignores insignificant differences in the two comparands.
44 comparison that ignores insignificant differences in the two comparands.
45 The significance of certain differences can be specified via the keyword
45 The significance of certain differences can be specified via the keyword
46 parameters of this method.
46 parameters of this method.
47 """
47 """
48
48
49 if not leave_padding:
49 if not leave_padding:
50 a = a.strip()
50 a = a.strip()
51 b = b.strip()
51 b = b.strip()
52
52
53 if ignore_newlines:
53 if ignore_newlines:
54 a = a.replace('\n', '')
54 a = a.replace('\n', '')
55 b = b.replace('\n', '')
55 b = b.replace('\n', '')
56
56
57 if newlines_are_spaces:
57 if newlines_are_spaces:
58 a = a.replace('\n', ' ')
58 a = a.replace('\n', ' ')
59 b = b.replace('\n', ' ')
59 b = b.replace('\n', ' ')
60
60
61 if tabs_are_spaces:
61 if tabs_are_spaces:
62 a = a.replace('\t', ' ')
62 a = a.replace('\t', ' ')
63 b = b.replace('\t', ' ')
63 b = b.replace('\t', ' ')
64
64
65 if ignore_spaces:
65 if ignore_spaces:
66 a = a.replace(' ', '')
66 a = a.replace(' ', '')
67 b = b.replace(' ', '')
67 b = b.replace(' ', '')
68
68
69 if fuzzy_spacing:
69 if fuzzy_spacing:
70 a = self.recursive_replace(a, ' ', ' ')
70 a = self.recursive_replace(a, ' ', ' ')
71 b = self.recursive_replace(b, ' ', ' ')
71 b = self.recursive_replace(b, ' ', ' ')
72
72
73 if not case_sensitive:
73 if not case_sensitive:
74 a = a.lower()
74 a = a.lower()
75 b = b.lower()
75 b = b.lower()
76
76
77 self.assertEqual(a, b)
77 self.assertEqual(a, b)
78
78
79
79
80 def recursive_replace(self, text, search, replacement):
80 def recursive_replace(self, text, search, replacement):
81 """
81 """
82 Performs a recursive replacement operation. Replaces all instances
82 Performs a recursive replacement operation. Replaces all instances
83 of a search string in a text string with a replacement string until
83 of a search string in a text string with a replacement string until
84 the search string no longer exists. Recursion is needed because the
84 the search string no longer exists. Recursion is needed because the
85 replacement string may generate additional search strings.
85 replacement string may generate additional search strings.
86
86
87 For example:
87 For example:
88 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
88 Replace "ii" with "i" in the string "Hiiii" yields "Hii"
89 Another replacement yields "Hi" (the desired output)
89 Another replacement yields "Hi" (the desired output)
90
90
91 Parameters:
91 Parameters:
92 -----------
92 -----------
93 text : string
93 text : string
94 Text to replace in.
94 Text to replace in.
95 search : string
95 search : string
96 String to search for within "text"
96 String to search for within "text"
97 replacement : string
97 replacement : string
98 String to replace "search" with
98 String to replace "search" with
99 """
99 """
100 while search in text:
100 while search in text:
101 text = text.replace(search, replacement)
101 text = text.replace(search, replacement)
102 return text
102 return text
103
103
104 def create_temp_cwd(self, copy_filenames=None):
104 def create_temp_cwd(self, copy_filenames=None):
105 temp_dir = TemporaryWorkingDirectory()
105 temp_dir = TemporaryWorkingDirectory()
106
106
107 #Copy the files if requested.
107 #Copy the files if requested.
108 if copy_filenames is not None:
108 if copy_filenames is not None:
109 self.copy_files_to(copy_filenames)
109 self.copy_files_to(copy_filenames)
110
110
111 #Return directory handler
111 #Return directory handler
112 return temp_dir
112 return temp_dir
113
113
114
114
115 def copy_files_to(self, copy_filenames, dest='.'):
115 def copy_files_to(self, copy_filenames, dest='.'):
116 "Copy test files into the destination directory"
116 "Copy test files into the destination directory"
117 if not os.path.isdir(dest):
117 if not os.path.isdir(dest):
118 os.makedirs(dest)
118 os.makedirs(dest)
119 files_path = self._get_files_path()
119 files_path = self._get_files_path()
120 for pattern in copy_filenames:
120 for pattern in copy_filenames:
121 for match in glob.glob(os.path.join(files_path, pattern)):
121 for match in glob.glob(os.path.join(files_path, pattern)):
122 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
122 shutil.copyfile(match, os.path.join(dest, os.path.basename(match)))
123
123
124
124
125 def _get_files_path(self):
125 def _get_files_path(self):
126
126
127 #Get the relative path to this module in the IPython directory.
127 #Get the relative path to this module in the IPython directory.
128 names = self.__module__.split('.')[1:-1]
128 names = self.__module__.split('.')[1:-1]
129 names.append('files')
129 names.append('files')
130
130
131 #Build a path using the IPython directory and the relative path we just
131 #Build a path using the IPython directory and the relative path we just
132 #found.
132 #found.
133 path = IPython.__path__[0]
133 path = IPython.__path__[0]
134 for name in names:
134 for name in names:
135 path = os.path.join(path, name)
135 path = os.path.join(path, name)
136 return path
136 return path
137
137
138
138
139 def call(self, parameters, raise_on_error=True):
139 def call(self, parameters, ignore_return_code=False):
140 """
141 Execute a, IPython shell command, listening for both Errors and non-zero
142 return codes.
143
144 PARAMETERS:
145 -----------
146 parameters : str
147 List of parameters to pass to IPython.
148 ignore_return_code : optional bool (default False)
149 Throw an OSError if the return code
150 """
151
140 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
152 stdout, stderr, retcode = get_output_error_code(ipy_cmd + parameters)
141 if retcode != 0 and raise_on_error:
153 if retcode != 0 and not ignore_return_code:
142 raise OSError(stderr)
154 raise OSError(stderr)
143 return stdout, stderr
155 return stdout, stderr
@@ -1,160 +1,160 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 import glob
17 import glob
18
18
19 from .base import TestsBase
19 from .base import TestsBase
20
20
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22
22
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Constants
25 # Constants
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28
28
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30 # Classes and functions
30 # Classes and functions
31 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
32
32
33 class TestNbConvertApp(TestsBase):
33 class TestNbConvertApp(TestsBase):
34 """Collection of NbConvertApp tests"""
34 """Collection of NbConvertApp tests"""
35
35
36
36
37 def test_notebook_help(self):
37 def test_notebook_help(self):
38 """
38 """
39 Will help show if no notebooks are specified?
39 Will help show if no notebooks are specified?
40 """
40 """
41 with self.create_temp_cwd():
41 with self.create_temp_cwd():
42 out, err = self.call('nbconvert --log-level=0', raise_on_error=False)
42 out, err = self.call('nbconvert --log-level 0', ignore_return_code=True)
43 assert "see '--help-all'" in out
43 assert "see '--help-all'" in out
44
44
45
45
46 def test_glob(self):
46 def test_glob(self):
47 """
47 """
48 Do search patterns work for notebook names?
48 Do search patterns work for notebook names?
49 """
49 """
50 with self.create_temp_cwd(['notebook*.ipynb']):
50 with self.create_temp_cwd(['notebook*.ipynb']):
51 self.call("""nbconvert --to="python" --notebooks="['*.ipynb']" --log-level=0""")
51 self.call('nbconvert --to python *.ipynb --log-level 0')
52 assert os.path.isfile('notebook1.py')
52 assert os.path.isfile('notebook1.py')
53 assert os.path.isfile('notebook2.py')
53 assert os.path.isfile('notebook2.py')
54
54
55
55
56 def test_glob_subdir(self):
56 def test_glob_subdir(self):
57 """
57 """
58 Do search patterns work for subdirectory notebook names?
58 Do search patterns work for subdirectory notebook names?
59 """
59 """
60 with self.create_temp_cwd():
60 with self.create_temp_cwd():
61 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
61 self.copy_files_to(['notebook*.ipynb'], 'subdir/')
62 self.call('nbconvert --to="python" --log-level=0 --notebooks='
62 self.call('nbconvert --to python --log-level 0 ' +
63 """"['%s']"' % os.path.join('subdir', '*.ipynb"""))
63 os.path.join('subdir', '*.ipynb'))
64 assert os.path.isfile('notebook1.py')
64 assert os.path.isfile('notebook1.py')
65 assert os.path.isfile('notebook2.py')
65 assert os.path.isfile('notebook2.py')
66
66
67
67
68 def test_explicit(self):
68 def test_explicit(self):
69 """
69 """
70 Do explicit notebook names work?
70 Do explicit notebook names work?
71 """
71 """
72 with self.create_temp_cwd(['notebook*.ipynb']):
72 with self.create_temp_cwd(['notebook*.ipynb']):
73 self.call('nbconvert --log-level=0 --to="python" --notebooks='
73 self.call('nbconvert --log-level 0 --to python notebook2')
74 """"['notebook2.ipynb']\"""")
75 assert not os.path.isfile('notebook1.py')
74 assert not os.path.isfile('notebook1.py')
76 assert os.path.isfile('notebook2.py')
75 assert os.path.isfile('notebook2.py')
77
76
78
77
79 @dec.onlyif_cmds_exist('pdflatex')
78 @dec.onlyif_cmds_exist('pdflatex')
80 @dec.onlyif_cmds_exist('pandoc')
79 @dec.onlyif_cmds_exist('pandoc')
81 def test_filename_spaces(self):
80 def test_filename_spaces(self):
82 """
81 """
83 Generate PDFs with graphics if notebooks have spaces in the name?
82 Generate PDFs with graphics if notebooks have spaces in the name?
84 """
83 """
85 with self.create_temp_cwd(['notebook2.ipynb']):
84 with self.create_temp_cwd(['notebook2.ipynb']):
86 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
85 os.rename('notebook2.ipynb', 'notebook with spaces.ipynb')
87 o,e = self.call('nbconvert --log-level=0 --to="latex" "notebook with spaces"'
86 o,e = self.call('nbconvert --log-level 0 --to latex '
88 ' --post="PDF" --PDFPostProcessor.verbose=True')
87 '"notebook with spaces" --post PDF '
88 '--PDFPostProcessor.verbose=True')
89 assert os.path.isfile('notebook with spaces.tex')
89 assert os.path.isfile('notebook with spaces.tex')
90 assert os.path.isdir('notebook with spaces_files')
90 assert os.path.isdir('notebook with spaces_files')
91 assert os.path.isfile('notebook with spaces.pdf')
91 assert os.path.isfile('notebook with spaces.pdf')
92
92
93 @dec.onlyif_cmds_exist('pdflatex')
93 @dec.onlyif_cmds_exist('pdflatex')
94 @dec.onlyif_cmds_exist('pandoc')
94 @dec.onlyif_cmds_exist('pandoc')
95 def test_post_processor(self):
95 def test_post_processor(self):
96 """
96 """
97 Do post processors work?
97 Do post processors work?
98 """
98 """
99 with self.create_temp_cwd(['notebook1.ipynb']):
99 with self.create_temp_cwd(['notebook1.ipynb']):
100 self.call('nbconvert --log-level=0 --to="latex" notebook1'
100 self.call('nbconvert --log-level 0 --to latex notebook1 '
101 ' --post="PDF" --PDFPostProcessor.verbose=True')
101 '--post PDF --PDFPostProcessor.verbose=True')
102 assert os.path.isfile('notebook1.tex')
102 assert os.path.isfile('notebook1.tex')
103 assert os.path.isfile('notebook1.pdf')
103 assert os.path.isfile('notebook1.pdf')
104
104
105
105
106 @dec.onlyif_cmds_exist('pandoc')
106 @dec.onlyif_cmds_exist('pandoc')
107 def test_template(self):
107 def test_template(self):
108 """
108 """
109 Do export templates work?
109 Do export templates work?
110 """
110 """
111 with self.create_temp_cwd(['notebook2.ipynb']):
111 with self.create_temp_cwd(['notebook2.ipynb']):
112 self.call('nbconvert --log-level=0 --to=slides --notebooks='
112 self.call('nbconvert --log-level 0 --to slides '
113 """"['notebook2.ipynb']" --template=reveal""")
113 'notebook2.ipynb --template reveal')
114 assert os.path.isfile('notebook2.slides.html')
114 assert os.path.isfile('notebook2.slides.html')
115 with open('notebook2.slides.html') as f:
115 with open('notebook2.slides.html') as f:
116 assert '/reveal.css' in f.read()
116 assert '/reveal.css' in f.read()
117
117
118
118
119 def test_glob_explicit(self):
119 def test_glob_explicit(self):
120 """
120 """
121 Can a search pattern be used along with matching explicit notebook names?
121 Can a search pattern be used along with matching explicit notebook names?
122 """
122 """
123 with self.create_temp_cwd(['notebook*.ipynb']):
123 with self.create_temp_cwd(['notebook*.ipynb']):
124 self.call('nbconvert --log-level=0 --to="python" --notebooks='
124 self.call('nbconvert --log-level 0 --to python '
125 """"['*.ipynb','notebook1.ipynb','notebook2.ipynb']\"""")
125 '*.ipynb notebook1.ipynb notebook2.ipynb')
126 assert os.path.isfile('notebook1.py')
126 assert os.path.isfile('notebook1.py')
127 assert os.path.isfile('notebook2.py')
127 assert os.path.isfile('notebook2.py')
128
128
129
129
130 def test_explicit_glob(self):
130 def test_explicit_glob(self):
131 """
131 """
132 Can explicit notebook names be used and then a matching search pattern?
132 Can explicit notebook names be used and then a matching search pattern?
133 """
133 """
134 with self.create_temp_cwd(['notebook*.ipynb']):
134 with self.create_temp_cwd(['notebook*.ipynb']):
135 self.call('nbconvert --log-level=0 --to="python" --notebooks='
135 self.call('nbconvert --log-level 0 --to=python '
136 """"['notebook1.ipynb','notebook2.ipynb','*.ipynb']\"""")
136 'notebook1.ipynb notebook2.ipynb *.ipynb')
137 assert os.path.isfile('notebook1.py')
137 assert os.path.isfile('notebook1.py')
138 assert os.path.isfile('notebook2.py')
138 assert os.path.isfile('notebook2.py')
139
139
140
140
141 def test_default_config(self):
141 def test_default_config(self):
142 """
142 """
143 Does the default config work?
143 Does the default config work?
144 """
144 """
145 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
145 with self.create_temp_cwd(['notebook*.ipynb', 'ipython_nbconvert_config.py']):
146 self.call('nbconvert --log-level=0')
146 self.call('nbconvert --log-level 0')
147 assert os.path.isfile('notebook1.py')
147 assert os.path.isfile('notebook1.py')
148 assert not os.path.isfile('notebook2.py')
148 assert not os.path.isfile('notebook2.py')
149
149
150
150
151 def test_override_config(self):
151 def test_override_config(self):
152 """
152 """
153 Can the default config be overriden?
153 Can the default config be overriden?
154 """
154 """
155 with self.create_temp_cwd(['notebook*.ipynb',
155 with self.create_temp_cwd(['notebook*.ipynb',
156 'ipython_nbconvert_config.py',
156 'ipython_nbconvert_config.py',
157 'override.py']):
157 'override.py']):
158 self.call('nbconvert --log-level=0 --config="override.py"')
158 self.call('nbconvert --log-level 0 --config="override.py"')
159 assert not os.path.isfile('notebook1.py')
159 assert not os.path.isfile('notebook1.py')
160 assert os.path.isfile('notebook2.py')
160 assert os.path.isfile('notebook2.py')
General Comments 0
You need to be logged in to leave comments. Login now