##// END OF EJS Templates
IPython behaves properly when started in a directory with non-ascii characters in the name. + Unit test....
Thomas Kluyver -
Show More
@@ -0,0 +1,33 b''
1 """Tests for IPython.core.application"""
2
3 import os
4 import tempfile
5
6 from IPython.core.application import Application
7
8 def test_unicode_cwd():
9 """Check that IPython can start with unicode characters in the path."""
10 wd = tempfile.mkdtemp(suffix="€")
11
12 old_wd = os.getcwdu()
13 os.chdir(wd)
14 #raise Exception(repr(os.getcwd()))
15 try:
16 app = Application()
17 # The lines below are copied from Application.initialize()
18 app.create_default_config()
19 app.log_default_config()
20 app.set_default_config_log_level()
21
22 # Find resources needed for filesystem access, using information from
23 # the above two
24 app.find_ipython_dir()
25 app.find_resources()
26 app.find_config_file_name()
27 app.find_config_file_paths()
28
29 # File-based config
30 app.pre_load_file_config()
31 app.load_file_config(suppress_errors=False)
32 finally:
33 os.chdir(old_wd)
@@ -1,459 +1,461 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating componenets.
6 handling configuration and creating componenets.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15
15
16 Notes
16 Notes
17 -----
17 -----
18 """
18 """
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Copyright (C) 2008-2009 The IPython Development Team
21 # Copyright (C) 2008-2009 The IPython Development Team
22 #
22 #
23 # Distributed under the terms of the BSD License. The full license is in
23 # Distributed under the terms of the BSD License. The full license is in
24 # the file COPYING, distributed as part of this software.
24 # the file COPYING, distributed as part of this software.
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Imports
28 # Imports
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 import logging
31 import logging
32 import os
32 import os
33 import sys
33 import sys
34
34
35 from IPython.core import release, crashhandler
35 from IPython.core import release, crashhandler
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
37 from IPython.config.loader import (
37 from IPython.config.loader import (
38 PyFileConfigLoader,
38 PyFileConfigLoader,
39 ArgParseConfigLoader,
39 ArgParseConfigLoader,
40 Config,
40 Config,
41 )
41 )
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Classes and functions
44 # Classes and functions
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 class ApplicationError(Exception):
47 class ApplicationError(Exception):
48 pass
48 pass
49
49
50
50
51 class BaseAppConfigLoader(ArgParseConfigLoader):
51 class BaseAppConfigLoader(ArgParseConfigLoader):
52 """Default command line options for IPython based applications."""
52 """Default command line options for IPython based applications."""
53
53
54 def _add_ipython_dir(self, parser):
54 def _add_ipython_dir(self, parser):
55 """Add the --ipython-dir option to the parser."""
55 """Add the --ipython-dir option to the parser."""
56 paa = parser.add_argument
56 paa = parser.add_argument
57 paa('--ipython-dir',
57 paa('--ipython-dir',
58 dest='Global.ipython_dir',type=unicode,
58 dest='Global.ipython_dir',type=unicode,
59 help=
59 help=
60 """Set to override default location of the IPython directory
60 """Set to override default location of the IPython directory
61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
62 specified through the environment variable IPYTHON_DIR.""",
62 specified through the environment variable IPYTHON_DIR.""",
63 metavar='Global.ipython_dir')
63 metavar='Global.ipython_dir')
64
64
65 def _add_log_level(self, parser):
65 def _add_log_level(self, parser):
66 """Add the --log-level option to the parser."""
66 """Add the --log-level option to the parser."""
67 paa = parser.add_argument
67 paa = parser.add_argument
68 paa('--log-level',
68 paa('--log-level',
69 dest="Global.log_level",type=int,
69 dest="Global.log_level",type=int,
70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
71 metavar='Global.log_level')
71 metavar='Global.log_level')
72
72
73 def _add_version(self, parser):
73 def _add_version(self, parser):
74 """Add the --version option to the parser."""
74 """Add the --version option to the parser."""
75 parser.add_argument('--version', action="version",
75 parser.add_argument('--version', action="version",
76 version=self.version)
76 version=self.version)
77
77
78 def _add_arguments(self):
78 def _add_arguments(self):
79 self._add_ipython_dir(self.parser)
79 self._add_ipython_dir(self.parser)
80 self._add_log_level(self.parser)
80 self._add_log_level(self.parser)
81 self._add_version(self.parser)
81 self._add_version(self.parser)
82
82
83
83
84 class Application(object):
84 class Application(object):
85 """Load a config, construct configurables and set them running.
85 """Load a config, construct configurables and set them running.
86
86
87 The configuration of an application can be done via three different Config
87 The configuration of an application can be done via three different Config
88 objects, which are loaded and ultimately merged into a single one used
88 objects, which are loaded and ultimately merged into a single one used
89 from that point on by the app. These are:
89 from that point on by the app. These are:
90
90
91 1. default_config: internal defaults, implemented in code.
91 1. default_config: internal defaults, implemented in code.
92 2. file_config: read from the filesystem.
92 2. file_config: read from the filesystem.
93 3. command_line_config: read from the system's command line flags.
93 3. command_line_config: read from the system's command line flags.
94
94
95 During initialization, 3 is actually read before 2, since at the
95 During initialization, 3 is actually read before 2, since at the
96 command-line one may override the location of the file to be read. But the
96 command-line one may override the location of the file to be read. But the
97 above is the order in which the merge is made.
97 above is the order in which the merge is made.
98 """
98 """
99
99
100 name = u'ipython'
100 name = u'ipython'
101 description = 'IPython: an enhanced interactive Python shell.'
101 description = 'IPython: an enhanced interactive Python shell.'
102 #: Usage message printed by argparse. If None, auto-generate
102 #: Usage message printed by argparse. If None, auto-generate
103 usage = None
103 usage = None
104 #: The command line config loader. Subclass of ArgParseConfigLoader.
104 #: The command line config loader. Subclass of ArgParseConfigLoader.
105 command_line_loader = BaseAppConfigLoader
105 command_line_loader = BaseAppConfigLoader
106 #: The name of the config file to load, determined at runtime
106 #: The name of the config file to load, determined at runtime
107 config_file_name = None
107 config_file_name = None
108 #: The name of the default config file. Track separately from the actual
108 #: The name of the default config file. Track separately from the actual
109 #: name because some logic happens only if we aren't using the default.
109 #: name because some logic happens only if we aren't using the default.
110 default_config_file_name = u'ipython_config.py'
110 default_config_file_name = u'ipython_config.py'
111 default_log_level = logging.WARN
111 default_log_level = logging.WARN
112 #: Set by --profile option
112 #: Set by --profile option
113 profile_name = None
113 profile_name = None
114 #: User's ipython directory, typically ~/.ipython or ~/.config/ipython/
114 #: User's ipython directory, typically ~/.ipython or ~/.config/ipython/
115 ipython_dir = None
115 ipython_dir = None
116 #: Internal defaults, implemented in code.
116 #: Internal defaults, implemented in code.
117 default_config = None
117 default_config = None
118 #: Read from the filesystem.
118 #: Read from the filesystem.
119 file_config = None
119 file_config = None
120 #: Read from the system's command line flags.
120 #: Read from the system's command line flags.
121 command_line_config = None
121 command_line_config = None
122 #: The final config that will be passed to the main object.
122 #: The final config that will be passed to the main object.
123 master_config = None
123 master_config = None
124 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
124 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
125 argv = None
125 argv = None
126 #: extra arguments computed by the command-line loader
126 #: extra arguments computed by the command-line loader
127 extra_args = None
127 extra_args = None
128 #: The class to use as the crash handler.
128 #: The class to use as the crash handler.
129 crash_handler_class = crashhandler.CrashHandler
129 crash_handler_class = crashhandler.CrashHandler
130
130
131 # Private attributes
131 # Private attributes
132 _exiting = False
132 _exiting = False
133 _initialized = False
133 _initialized = False
134
134
135 def __init__(self, argv=None):
135 def __init__(self, argv=None):
136 self.argv = sys.argv[1:] if argv is None else argv
136 self.argv = sys.argv[1:] if argv is None else argv
137 self.init_logger()
137 self.init_logger()
138
138
139 def init_logger(self):
139 def init_logger(self):
140 self.log = logging.getLogger(self.__class__.__name__)
140 self.log = logging.getLogger(self.__class__.__name__)
141 # This is used as the default until the command line arguments are read.
141 # This is used as the default until the command line arguments are read.
142 self.log.setLevel(self.default_log_level)
142 self.log.setLevel(self.default_log_level)
143 self._log_handler = logging.StreamHandler()
143 self._log_handler = logging.StreamHandler()
144 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
144 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
145 self._log_handler.setFormatter(self._log_formatter)
145 self._log_handler.setFormatter(self._log_formatter)
146 self.log.addHandler(self._log_handler)
146 self.log.addHandler(self._log_handler)
147
147
148 def _set_log_level(self, level):
148 def _set_log_level(self, level):
149 self.log.setLevel(level)
149 self.log.setLevel(level)
150
150
151 def _get_log_level(self):
151 def _get_log_level(self):
152 return self.log.level
152 return self.log.level
153
153
154 log_level = property(_get_log_level, _set_log_level)
154 log_level = property(_get_log_level, _set_log_level)
155
155
156 def initialize(self):
156 def initialize(self):
157 """Initialize the application.
157 """Initialize the application.
158
158
159 Loads all configuration information and sets all application state, but
159 Loads all configuration information and sets all application state, but
160 does not start any relevant processing (typically some kind of event
160 does not start any relevant processing (typically some kind of event
161 loop).
161 loop).
162
162
163 Once this method has been called, the application is flagged as
163 Once this method has been called, the application is flagged as
164 initialized and the method becomes a no-op."""
164 initialized and the method becomes a no-op."""
165
165
166 if self._initialized:
166 if self._initialized:
167 return
167 return
168
168
169 # The first part is protected with an 'attempt' wrapper, that will log
169 # The first part is protected with an 'attempt' wrapper, that will log
170 # failures with the basic system traceback machinery. Once our crash
170 # failures with the basic system traceback machinery. Once our crash
171 # handler is in place, we can let any subsequent exception propagate,
171 # handler is in place, we can let any subsequent exception propagate,
172 # as our handler will log it with much better detail than the default.
172 # as our handler will log it with much better detail than the default.
173 self.attempt(self.create_crash_handler)
173 self.attempt(self.create_crash_handler)
174
174
175 # Configuration phase
175 # Configuration phase
176 # Default config (internally hardwired in application code)
176 # Default config (internally hardwired in application code)
177 self.create_default_config()
177 self.create_default_config()
178 self.log_default_config()
178 self.log_default_config()
179 self.set_default_config_log_level()
179 self.set_default_config_log_level()
180
180
181 # Command-line config
181 # Command-line config
182 self.pre_load_command_line_config()
182 self.pre_load_command_line_config()
183 self.load_command_line_config()
183 self.load_command_line_config()
184 self.set_command_line_config_log_level()
184 self.set_command_line_config_log_level()
185 self.post_load_command_line_config()
185 self.post_load_command_line_config()
186 self.log_command_line_config()
186 self.log_command_line_config()
187
187
188 # Find resources needed for filesystem access, using information from
188 # Find resources needed for filesystem access, using information from
189 # the above two
189 # the above two
190 self.find_ipython_dir()
190 self.find_ipython_dir()
191 self.find_resources()
191 self.find_resources()
192 self.find_config_file_name()
192 self.find_config_file_name()
193 self.find_config_file_paths()
193 self.find_config_file_paths()
194
194
195 # File-based config
195 # File-based config
196 self.pre_load_file_config()
196 self.pre_load_file_config()
197 self.load_file_config()
197 self.load_file_config()
198 self.set_file_config_log_level()
198 self.set_file_config_log_level()
199 self.post_load_file_config()
199 self.post_load_file_config()
200 self.log_file_config()
200 self.log_file_config()
201
201
202 # Merge all config objects into a single one the app can then use
202 # Merge all config objects into a single one the app can then use
203 self.merge_configs()
203 self.merge_configs()
204 self.log_master_config()
204 self.log_master_config()
205
205
206 # Construction phase
206 # Construction phase
207 self.pre_construct()
207 self.pre_construct()
208 self.construct()
208 self.construct()
209 self.post_construct()
209 self.post_construct()
210
210
211 # Done, flag as such and
211 # Done, flag as such and
212 self._initialized = True
212 self._initialized = True
213
213
214 def start(self):
214 def start(self):
215 """Start the application."""
215 """Start the application."""
216 self.initialize()
216 self.initialize()
217 self.start_app()
217 self.start_app()
218
218
219 #-------------------------------------------------------------------------
219 #-------------------------------------------------------------------------
220 # Various stages of Application creation
220 # Various stages of Application creation
221 #-------------------------------------------------------------------------
221 #-------------------------------------------------------------------------
222
222
223 def create_crash_handler(self):
223 def create_crash_handler(self):
224 """Create a crash handler, typically setting sys.excepthook to it."""
224 """Create a crash handler, typically setting sys.excepthook to it."""
225 self.crash_handler = self.crash_handler_class(self)
225 self.crash_handler = self.crash_handler_class(self)
226 sys.excepthook = self.crash_handler
226 sys.excepthook = self.crash_handler
227
227
228 def create_default_config(self):
228 def create_default_config(self):
229 """Create defaults that can't be set elsewhere.
229 """Create defaults that can't be set elsewhere.
230
230
231 For the most part, we try to set default in the class attributes
231 For the most part, we try to set default in the class attributes
232 of Configurables. But, defaults the top-level Application (which is
232 of Configurables. But, defaults the top-level Application (which is
233 not a HasTraits or Configurables) are not set in this way. Instead
233 not a HasTraits or Configurables) are not set in this way. Instead
234 we set them here. The Global section is for variables like this that
234 we set them here. The Global section is for variables like this that
235 don't belong to a particular configurable.
235 don't belong to a particular configurable.
236 """
236 """
237 c = Config()
237 c = Config()
238 c.Global.ipython_dir = get_ipython_dir()
238 c.Global.ipython_dir = get_ipython_dir()
239 c.Global.log_level = self.log_level
239 c.Global.log_level = self.log_level
240 self.default_config = c
240 self.default_config = c
241
241
242 def log_default_config(self):
242 def log_default_config(self):
243 self.log.debug('Default config loaded:')
243 self.log.debug('Default config loaded:')
244 self.log.debug(repr(self.default_config))
244 self.log.debug(repr(self.default_config))
245
245
246 def set_default_config_log_level(self):
246 def set_default_config_log_level(self):
247 try:
247 try:
248 self.log_level = self.default_config.Global.log_level
248 self.log_level = self.default_config.Global.log_level
249 except AttributeError:
249 except AttributeError:
250 # Fallback to the default_log_level class attribute
250 # Fallback to the default_log_level class attribute
251 pass
251 pass
252
252
253 def create_command_line_config(self):
253 def create_command_line_config(self):
254 """Create and return a command line config loader."""
254 """Create and return a command line config loader."""
255 return self.command_line_loader(
255 return self.command_line_loader(
256 self.argv,
256 self.argv,
257 description=self.description,
257 description=self.description,
258 version=release.version,
258 version=release.version,
259 usage=self.usage
259 usage=self.usage
260 )
260 )
261
261
262 def pre_load_command_line_config(self):
262 def pre_load_command_line_config(self):
263 """Do actions just before loading the command line config."""
263 """Do actions just before loading the command line config."""
264 pass
264 pass
265
265
266 def load_command_line_config(self):
266 def load_command_line_config(self):
267 """Load the command line config."""
267 """Load the command line config."""
268 loader = self.create_command_line_config()
268 loader = self.create_command_line_config()
269 self.command_line_config = loader.load_config()
269 self.command_line_config = loader.load_config()
270 self.extra_args = loader.get_extra_args()
270 self.extra_args = loader.get_extra_args()
271
271
272 def set_command_line_config_log_level(self):
272 def set_command_line_config_log_level(self):
273 try:
273 try:
274 self.log_level = self.command_line_config.Global.log_level
274 self.log_level = self.command_line_config.Global.log_level
275 except AttributeError:
275 except AttributeError:
276 pass
276 pass
277
277
278 def post_load_command_line_config(self):
278 def post_load_command_line_config(self):
279 """Do actions just after loading the command line config."""
279 """Do actions just after loading the command line config."""
280 pass
280 pass
281
281
282 def log_command_line_config(self):
282 def log_command_line_config(self):
283 self.log.debug("Command line config loaded:")
283 self.log.debug("Command line config loaded:")
284 self.log.debug(repr(self.command_line_config))
284 self.log.debug(repr(self.command_line_config))
285
285
286 def find_ipython_dir(self):
286 def find_ipython_dir(self):
287 """Set the IPython directory.
287 """Set the IPython directory.
288
288
289 This sets ``self.ipython_dir``, but the actual value that is passed to
289 This sets ``self.ipython_dir``, but the actual value that is passed to
290 the application is kept in either ``self.default_config`` or
290 the application is kept in either ``self.default_config`` or
291 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
291 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
292 ``sys.path`` so config files there can be referenced by other config
292 ``sys.path`` so config files there can be referenced by other config
293 files.
293 files.
294 """
294 """
295
295
296 try:
296 try:
297 self.ipython_dir = self.command_line_config.Global.ipython_dir
297 self.ipython_dir = self.command_line_config.Global.ipython_dir
298 except AttributeError:
298 except AttributeError:
299 self.ipython_dir = self.default_config.Global.ipython_dir
299 self.ipython_dir = self.default_config.Global.ipython_dir
300 sys.path.append(os.path.abspath(self.ipython_dir))
300 sys.path.append(os.path.abspath(self.ipython_dir))
301 if not os.path.isdir(self.ipython_dir):
301 if not os.path.isdir(self.ipython_dir):
302 os.makedirs(self.ipython_dir, mode=0777)
302 os.makedirs(self.ipython_dir, mode=0777)
303 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
303 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
304
304
305 def find_resources(self):
305 def find_resources(self):
306 """Find other resources that need to be in place.
306 """Find other resources that need to be in place.
307
307
308 Things like cluster directories need to be in place to find the
308 Things like cluster directories need to be in place to find the
309 config file. These happen right after the IPython directory has
309 config file. These happen right after the IPython directory has
310 been set.
310 been set.
311 """
311 """
312 pass
312 pass
313
313
314 def find_config_file_name(self):
314 def find_config_file_name(self):
315 """Find the config file name for this application.
315 """Find the config file name for this application.
316
316
317 This must set ``self.config_file_name`` to the filename of the
317 This must set ``self.config_file_name`` to the filename of the
318 config file to use (just the filename). The search paths for the
318 config file to use (just the filename). The search paths for the
319 config file are set in :meth:`find_config_file_paths` and then passed
319 config file are set in :meth:`find_config_file_paths` and then passed
320 to the config file loader where they are resolved to an absolute path.
320 to the config file loader where they are resolved to an absolute path.
321
321
322 If a profile has been set at the command line, this will resolve it.
322 If a profile has been set at the command line, this will resolve it.
323 """
323 """
324 try:
324 try:
325 self.config_file_name = self.command_line_config.Global.config_file
325 self.config_file_name = self.command_line_config.Global.config_file
326 except AttributeError:
326 except AttributeError:
327 pass
327 pass
328 else:
328 else:
329 return
329 return
330
330
331 try:
331 try:
332 self.profile_name = self.command_line_config.Global.profile
332 self.profile_name = self.command_line_config.Global.profile
333 except AttributeError:
333 except AttributeError:
334 # Just use the default as there is no profile
334 # Just use the default as there is no profile
335 self.config_file_name = self.default_config_file_name
335 self.config_file_name = self.default_config_file_name
336 else:
336 else:
337 # Use the default config file name and profile name if set
337 # Use the default config file name and profile name if set
338 # to determine the used config file name.
338 # to determine the used config file name.
339 name_parts = self.default_config_file_name.split('.')
339 name_parts = self.default_config_file_name.split('.')
340 name_parts.insert(1, u'_' + self.profile_name + u'.')
340 name_parts.insert(1, u'_' + self.profile_name + u'.')
341 self.config_file_name = ''.join(name_parts)
341 self.config_file_name = ''.join(name_parts)
342
342
343 def find_config_file_paths(self):
343 def find_config_file_paths(self):
344 """Set the search paths for resolving the config file.
344 """Set the search paths for resolving the config file.
345
345
346 This must set ``self.config_file_paths`` to a sequence of search
346 This must set ``self.config_file_paths`` to a sequence of search
347 paths to pass to the config file loader.
347 paths to pass to the config file loader.
348 """
348 """
349 # Include our own profiles directory last, so that users can still find
349 # Include our own profiles directory last, so that users can still find
350 # our shipped copies of builtin profiles even if they don't have them
350 # our shipped copies of builtin profiles even if they don't have them
351 # in their local ipython directory.
351 # in their local ipython directory.
352 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
352 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
353 self.config_file_paths = (os.getcwd(), self.ipython_dir, prof_dir)
353 self.config_file_paths = (os.getcwdu(), self.ipython_dir, prof_dir)
354
354
355 def pre_load_file_config(self):
355 def pre_load_file_config(self):
356 """Do actions before the config file is loaded."""
356 """Do actions before the config file is loaded."""
357 pass
357 pass
358
358
359 def load_file_config(self):
359 def load_file_config(self, suppress_errors=True):
360 """Load the config file.
360 """Load the config file.
361
361
362 This tries to load the config file from disk. If successful, the
362 This tries to load the config file from disk. If successful, the
363 ``CONFIG_FILE`` config variable is set to the resolved config file
363 ``CONFIG_FILE`` config variable is set to the resolved config file
364 location. If not successful, an empty config is used.
364 location. If not successful, an empty config is used.
365 """
365 """
366 self.log.debug("Attempting to load config file: %s" %
366 self.log.debug("Attempting to load config file: %s" %
367 self.config_file_name)
367 self.config_file_name)
368 loader = PyFileConfigLoader(self.config_file_name,
368 loader = PyFileConfigLoader(self.config_file_name,
369 path=self.config_file_paths)
369 path=self.config_file_paths)
370 try:
370 try:
371 self.file_config = loader.load_config()
371 self.file_config = loader.load_config()
372 self.file_config.Global.config_file = loader.full_filename
372 self.file_config.Global.config_file = loader.full_filename
373 except IOError:
373 except IOError:
374 # Only warn if the default config file was NOT being used.
374 # Only warn if the default config file was NOT being used.
375 if not self.config_file_name==self.default_config_file_name:
375 if not self.config_file_name==self.default_config_file_name:
376 self.log.warn("Config file not found, skipping: %s" %
376 self.log.warn("Config file not found, skipping: %s" %
377 self.config_file_name, exc_info=True)
377 self.config_file_name, exc_info=True)
378 self.file_config = Config()
378 self.file_config = Config()
379 except:
379 except:
380 if not suppress_errors: # For testing purposes
381 raise
380 self.log.warn("Error loading config file: %s" %
382 self.log.warn("Error loading config file: %s" %
381 self.config_file_name, exc_info=True)
383 self.config_file_name, exc_info=True)
382 self.file_config = Config()
384 self.file_config = Config()
383
385
384 def set_file_config_log_level(self):
386 def set_file_config_log_level(self):
385 # We need to keeep self.log_level updated. But we only use the value
387 # We need to keeep self.log_level updated. But we only use the value
386 # of the file_config if a value was not specified at the command
388 # of the file_config if a value was not specified at the command
387 # line, because the command line overrides everything.
389 # line, because the command line overrides everything.
388 if not hasattr(self.command_line_config.Global, 'log_level'):
390 if not hasattr(self.command_line_config.Global, 'log_level'):
389 try:
391 try:
390 self.log_level = self.file_config.Global.log_level
392 self.log_level = self.file_config.Global.log_level
391 except AttributeError:
393 except AttributeError:
392 pass # Use existing value
394 pass # Use existing value
393
395
394 def post_load_file_config(self):
396 def post_load_file_config(self):
395 """Do actions after the config file is loaded."""
397 """Do actions after the config file is loaded."""
396 pass
398 pass
397
399
398 def log_file_config(self):
400 def log_file_config(self):
399 if hasattr(self.file_config.Global, 'config_file'):
401 if hasattr(self.file_config.Global, 'config_file'):
400 self.log.debug("Config file loaded: %s" %
402 self.log.debug("Config file loaded: %s" %
401 self.file_config.Global.config_file)
403 self.file_config.Global.config_file)
402 self.log.debug(repr(self.file_config))
404 self.log.debug(repr(self.file_config))
403
405
404 def merge_configs(self):
406 def merge_configs(self):
405 """Merge the default, command line and file config objects."""
407 """Merge the default, command line and file config objects."""
406 config = Config()
408 config = Config()
407 config._merge(self.default_config)
409 config._merge(self.default_config)
408 config._merge(self.file_config)
410 config._merge(self.file_config)
409 config._merge(self.command_line_config)
411 config._merge(self.command_line_config)
410
412
411 # XXX fperez - propose to Brian we rename master_config to simply
413 # XXX fperez - propose to Brian we rename master_config to simply
412 # config, I think this is going to be heavily used in examples and
414 # config, I think this is going to be heavily used in examples and
413 # application code and the name is shorter/easier to find/remember.
415 # application code and the name is shorter/easier to find/remember.
414 # For now, just alias it...
416 # For now, just alias it...
415 self.master_config = config
417 self.master_config = config
416 self.config = config
418 self.config = config
417
419
418 def log_master_config(self):
420 def log_master_config(self):
419 self.log.debug("Master config created:")
421 self.log.debug("Master config created:")
420 self.log.debug(repr(self.master_config))
422 self.log.debug(repr(self.master_config))
421
423
422 def pre_construct(self):
424 def pre_construct(self):
423 """Do actions after the config has been built, but before construct."""
425 """Do actions after the config has been built, but before construct."""
424 pass
426 pass
425
427
426 def construct(self):
428 def construct(self):
427 """Construct the main objects that make up this app."""
429 """Construct the main objects that make up this app."""
428 self.log.debug("Constructing main objects for application")
430 self.log.debug("Constructing main objects for application")
429
431
430 def post_construct(self):
432 def post_construct(self):
431 """Do actions after construct, but before starting the app."""
433 """Do actions after construct, but before starting the app."""
432 pass
434 pass
433
435
434 def start_app(self):
436 def start_app(self):
435 """Actually start the app."""
437 """Actually start the app."""
436 self.log.debug("Starting application")
438 self.log.debug("Starting application")
437
439
438 #-------------------------------------------------------------------------
440 #-------------------------------------------------------------------------
439 # Utility methods
441 # Utility methods
440 #-------------------------------------------------------------------------
442 #-------------------------------------------------------------------------
441
443
442 def exit(self, exit_status=0):
444 def exit(self, exit_status=0):
443 if self._exiting:
445 if self._exiting:
444 pass
446 pass
445 else:
447 else:
446 self.log.debug("Exiting application: %s" % self.name)
448 self.log.debug("Exiting application: %s" % self.name)
447 self._exiting = True
449 self._exiting = True
448 sys.exit(exit_status)
450 sys.exit(exit_status)
449
451
450 def attempt(self, func):
452 def attempt(self, func):
451 try:
453 try:
452 func()
454 func()
453 except SystemExit:
455 except SystemExit:
454 raise
456 raise
455 except:
457 except:
456 self.log.critical("Aborting application: %s" % self.name,
458 self.log.critical("Aborting application: %s" % self.name,
457 exc_info=True)
459 exc_info=True)
458 self.exit(0)
460 self.exit(0)
459
461
@@ -1,417 +1,417 b''
1 """Tests for various magic functions.
1 """Tests for various magic functions.
2
2
3 Needs to be run by nose (to make ipython session available).
3 Needs to be run by nose (to make ipython session available).
4 """
4 """
5 from __future__ import absolute_import
5 from __future__ import absolute_import
6
6
7 #-----------------------------------------------------------------------------
7 #-----------------------------------------------------------------------------
8 # Imports
8 # Imports
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 import os
11 import os
12 import sys
12 import sys
13 import tempfile
13 import tempfile
14 import types
14 import types
15 from cStringIO import StringIO
15 from cStringIO import StringIO
16
16
17 import nose.tools as nt
17 import nose.tools as nt
18
18
19 from IPython.utils.path import get_long_path_name
19 from IPython.utils.path import get_long_path_name
20 from IPython.testing import decorators as dec
20 from IPython.testing import decorators as dec
21 from IPython.testing import tools as tt
21 from IPython.testing import tools as tt
22
22
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24 # Test functions begin
24 # Test functions begin
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 def test_rehashx():
26 def test_rehashx():
27 # clear up everything
27 # clear up everything
28 _ip = get_ipython()
28 _ip = get_ipython()
29 _ip.alias_manager.alias_table.clear()
29 _ip.alias_manager.alias_table.clear()
30 del _ip.db['syscmdlist']
30 del _ip.db['syscmdlist']
31
31
32 _ip.magic('rehashx')
32 _ip.magic('rehashx')
33 # Practically ALL ipython development systems will have more than 10 aliases
33 # Practically ALL ipython development systems will have more than 10 aliases
34
34
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
35 yield (nt.assert_true, len(_ip.alias_manager.alias_table) > 10)
36 for key, val in _ip.alias_manager.alias_table.iteritems():
36 for key, val in _ip.alias_manager.alias_table.iteritems():
37 # we must strip dots from alias names
37 # we must strip dots from alias names
38 nt.assert_true('.' not in key)
38 nt.assert_true('.' not in key)
39
39
40 # rehashx must fill up syscmdlist
40 # rehashx must fill up syscmdlist
41 scoms = _ip.db['syscmdlist']
41 scoms = _ip.db['syscmdlist']
42 yield (nt.assert_true, len(scoms) > 10)
42 yield (nt.assert_true, len(scoms) > 10)
43
43
44
44
45 def test_magic_parse_options():
45 def test_magic_parse_options():
46 """Test that we don't mangle paths when parsing magic options."""
46 """Test that we don't mangle paths when parsing magic options."""
47 ip = get_ipython()
47 ip = get_ipython()
48 path = 'c:\\x'
48 path = 'c:\\x'
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
49 opts = ip.parse_options('-f %s' % path,'f:')[0]
50 # argv splitting is os-dependent
50 # argv splitting is os-dependent
51 if os.name == 'posix':
51 if os.name == 'posix':
52 expected = 'c:x'
52 expected = 'c:x'
53 else:
53 else:
54 expected = path
54 expected = path
55 nt.assert_equals(opts['f'], expected)
55 nt.assert_equals(opts['f'], expected)
56
56
57
57
58 def doctest_hist_f():
58 def doctest_hist_f():
59 """Test %hist -f with temporary filename.
59 """Test %hist -f with temporary filename.
60
60
61 In [9]: import tempfile
61 In [9]: import tempfile
62
62
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
63 In [10]: tfile = tempfile.mktemp('.py','tmp-ipython-')
64
64
65 In [11]: %hist -nl -f $tfile 3
65 In [11]: %hist -nl -f $tfile 3
66
66
67 In [13]: import os; os.unlink(tfile)
67 In [13]: import os; os.unlink(tfile)
68 """
68 """
69
69
70
70
71 def doctest_hist_r():
71 def doctest_hist_r():
72 """Test %hist -r
72 """Test %hist -r
73
73
74 XXX - This test is not recording the output correctly. For some reason, in
74 XXX - This test is not recording the output correctly. For some reason, in
75 testing mode the raw history isn't getting populated. No idea why.
75 testing mode the raw history isn't getting populated. No idea why.
76 Disabling the output checking for now, though at least we do run it.
76 Disabling the output checking for now, though at least we do run it.
77
77
78 In [1]: 'hist' in _ip.lsmagic()
78 In [1]: 'hist' in _ip.lsmagic()
79 Out[1]: True
79 Out[1]: True
80
80
81 In [2]: x=1
81 In [2]: x=1
82
82
83 In [3]: %hist -rl 2
83 In [3]: %hist -rl 2
84 x=1 # random
84 x=1 # random
85 %hist -r 2
85 %hist -r 2
86 """
86 """
87
87
88 def doctest_hist_op():
88 def doctest_hist_op():
89 """Test %hist -op
89 """Test %hist -op
90
90
91 In [1]: class b:
91 In [1]: class b:
92 ...: pass
92 ...: pass
93 ...:
93 ...:
94
94
95 In [2]: class s(b):
95 In [2]: class s(b):
96 ...: def __str__(self):
96 ...: def __str__(self):
97 ...: return 's'
97 ...: return 's'
98 ...:
98 ...:
99
99
100 In [3]:
100 In [3]:
101
101
102 In [4]: class r(b):
102 In [4]: class r(b):
103 ...: def __repr__(self):
103 ...: def __repr__(self):
104 ...: return 'r'
104 ...: return 'r'
105 ...:
105 ...:
106
106
107 In [5]: class sr(s,r): pass
107 In [5]: class sr(s,r): pass
108 ...:
108 ...:
109
109
110 In [6]:
110 In [6]:
111
111
112 In [7]: bb=b()
112 In [7]: bb=b()
113
113
114 In [8]: ss=s()
114 In [8]: ss=s()
115
115
116 In [9]: rr=r()
116 In [9]: rr=r()
117
117
118 In [10]: ssrr=sr()
118 In [10]: ssrr=sr()
119
119
120 In [11]: bb
120 In [11]: bb
121 Out[11]: <...b instance at ...>
121 Out[11]: <...b instance at ...>
122
122
123 In [12]: ss
123 In [12]: ss
124 Out[12]: <...s instance at ...>
124 Out[12]: <...s instance at ...>
125
125
126 In [13]:
126 In [13]:
127
127
128 In [14]: %hist -op
128 In [14]: %hist -op
129 >>> class b:
129 >>> class b:
130 ... pass
130 ... pass
131 ...
131 ...
132 >>> class s(b):
132 >>> class s(b):
133 ... def __str__(self):
133 ... def __str__(self):
134 ... return 's'
134 ... return 's'
135 ...
135 ...
136 >>>
136 >>>
137 >>> class r(b):
137 >>> class r(b):
138 ... def __repr__(self):
138 ... def __repr__(self):
139 ... return 'r'
139 ... return 'r'
140 ...
140 ...
141 >>> class sr(s,r): pass
141 >>> class sr(s,r): pass
142 >>>
142 >>>
143 >>> bb=b()
143 >>> bb=b()
144 >>> ss=s()
144 >>> ss=s()
145 >>> rr=r()
145 >>> rr=r()
146 >>> ssrr=sr()
146 >>> ssrr=sr()
147 >>> bb
147 >>> bb
148 <...b instance at ...>
148 <...b instance at ...>
149 >>> ss
149 >>> ss
150 <...s instance at ...>
150 <...s instance at ...>
151 >>>
151 >>>
152 """
152 """
153
153
154 def test_macro():
154 def test_macro():
155 ip = get_ipython()
155 ip = get_ipython()
156 ip.history_manager.reset() # Clear any existing history.
156 ip.history_manager.reset() # Clear any existing history.
157 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
157 cmds = ["a=1", "def b():\n return a**2", "print(a,b())"]
158 for i, cmd in enumerate(cmds, start=1):
158 for i, cmd in enumerate(cmds, start=1):
159 ip.history_manager.store_inputs(i, cmd)
159 ip.history_manager.store_inputs(i, cmd)
160 ip.magic("macro test 1-3")
160 ip.magic("macro test 1-3")
161 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
161 nt.assert_equal(ip.user_ns["test"].value, "\n".join(cmds)+"\n")
162
162
163 # List macros.
163 # List macros.
164 assert "test" in ip.magic("macro")
164 assert "test" in ip.magic("macro")
165
165
166 def test_macro_run():
166 def test_macro_run():
167 """Test that we can run a multi-line macro successfully."""
167 """Test that we can run a multi-line macro successfully."""
168 ip = get_ipython()
168 ip = get_ipython()
169 ip.history_manager.reset()
169 ip.history_manager.reset()
170 cmds = ["a=10", "a+=1", "print a", "%macro test 2-3"]
170 cmds = ["a=10", "a+=1", "print a", "%macro test 2-3"]
171 for cmd in cmds:
171 for cmd in cmds:
172 ip.run_cell(cmd)
172 ip.run_cell(cmd)
173 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint a\n")
173 nt.assert_equal(ip.user_ns["test"].value, "a+=1\nprint a\n")
174 original_stdout = sys.stdout
174 original_stdout = sys.stdout
175 new_stdout = StringIO()
175 new_stdout = StringIO()
176 sys.stdout = new_stdout
176 sys.stdout = new_stdout
177 try:
177 try:
178 ip.run_cell("test")
178 ip.run_cell("test")
179 nt.assert_true("12" in new_stdout.getvalue())
179 nt.assert_true("12" in new_stdout.getvalue())
180 ip.run_cell("test")
180 ip.run_cell("test")
181 nt.assert_true("13" in new_stdout.getvalue())
181 nt.assert_true("13" in new_stdout.getvalue())
182 finally:
182 finally:
183 sys.stdout = original_stdout
183 sys.stdout = original_stdout
184 new_stdout.close()
184 new_stdout.close()
185
185
186
186
187 # XXX failing for now, until we get clearcmd out of quarantine. But we should
187 # XXX failing for now, until we get clearcmd out of quarantine. But we should
188 # fix this and revert the skip to happen only if numpy is not around.
188 # fix this and revert the skip to happen only if numpy is not around.
189 #@dec.skipif_not_numpy
189 #@dec.skipif_not_numpy
190 @dec.skip_known_failure
190 @dec.skip_known_failure
191 def test_numpy_clear_array_undec():
191 def test_numpy_clear_array_undec():
192 from IPython.extensions import clearcmd
192 from IPython.extensions import clearcmd
193
193
194 _ip.ex('import numpy as np')
194 _ip.ex('import numpy as np')
195 _ip.ex('a = np.empty(2)')
195 _ip.ex('a = np.empty(2)')
196 yield (nt.assert_true, 'a' in _ip.user_ns)
196 yield (nt.assert_true, 'a' in _ip.user_ns)
197 _ip.magic('clear array')
197 _ip.magic('clear array')
198 yield (nt.assert_false, 'a' in _ip.user_ns)
198 yield (nt.assert_false, 'a' in _ip.user_ns)
199
199
200
200
201 # Multiple tests for clipboard pasting
201 # Multiple tests for clipboard pasting
202 @dec.parametric
202 @dec.parametric
203 def test_paste():
203 def test_paste():
204 _ip = get_ipython()
204 _ip = get_ipython()
205 def paste(txt, flags='-q'):
205 def paste(txt, flags='-q'):
206 """Paste input text, by default in quiet mode"""
206 """Paste input text, by default in quiet mode"""
207 hooks.clipboard_get = lambda : txt
207 hooks.clipboard_get = lambda : txt
208 _ip.magic('paste '+flags)
208 _ip.magic('paste '+flags)
209
209
210 # Inject fake clipboard hook but save original so we can restore it later
210 # Inject fake clipboard hook but save original so we can restore it later
211 hooks = _ip.hooks
211 hooks = _ip.hooks
212 user_ns = _ip.user_ns
212 user_ns = _ip.user_ns
213 original_clip = hooks.clipboard_get
213 original_clip = hooks.clipboard_get
214
214
215 try:
215 try:
216 # This try/except with an emtpy except clause is here only because
216 # This try/except with an emtpy except clause is here only because
217 # try/yield/finally is invalid syntax in Python 2.4. This will be
217 # try/yield/finally is invalid syntax in Python 2.4. This will be
218 # removed when we drop 2.4-compatibility, and the emtpy except below
218 # removed when we drop 2.4-compatibility, and the emtpy except below
219 # will be changed to a finally.
219 # will be changed to a finally.
220
220
221 # Run tests with fake clipboard function
221 # Run tests with fake clipboard function
222 user_ns.pop('x', None)
222 user_ns.pop('x', None)
223 paste('x=1')
223 paste('x=1')
224 yield nt.assert_equal(user_ns['x'], 1)
224 yield nt.assert_equal(user_ns['x'], 1)
225
225
226 user_ns.pop('x', None)
226 user_ns.pop('x', None)
227 paste('>>> x=2')
227 paste('>>> x=2')
228 yield nt.assert_equal(user_ns['x'], 2)
228 yield nt.assert_equal(user_ns['x'], 2)
229
229
230 paste("""
230 paste("""
231 >>> x = [1,2,3]
231 >>> x = [1,2,3]
232 >>> y = []
232 >>> y = []
233 >>> for i in x:
233 >>> for i in x:
234 ... y.append(i**2)
234 ... y.append(i**2)
235 ...
235 ...
236 """)
236 """)
237 yield nt.assert_equal(user_ns['x'], [1,2,3])
237 yield nt.assert_equal(user_ns['x'], [1,2,3])
238 yield nt.assert_equal(user_ns['y'], [1,4,9])
238 yield nt.assert_equal(user_ns['y'], [1,4,9])
239
239
240 # Now, test that paste -r works
240 # Now, test that paste -r works
241 user_ns.pop('x', None)
241 user_ns.pop('x', None)
242 yield nt.assert_false('x' in user_ns)
242 yield nt.assert_false('x' in user_ns)
243 _ip.magic('paste -r')
243 _ip.magic('paste -r')
244 yield nt.assert_equal(user_ns['x'], [1,2,3])
244 yield nt.assert_equal(user_ns['x'], [1,2,3])
245
245
246 # Also test paste echoing, by temporarily faking the writer
246 # Also test paste echoing, by temporarily faking the writer
247 w = StringIO()
247 w = StringIO()
248 writer = _ip.write
248 writer = _ip.write
249 _ip.write = w.write
249 _ip.write = w.write
250 code = """
250 code = """
251 a = 100
251 a = 100
252 b = 200"""
252 b = 200"""
253 try:
253 try:
254 paste(code,'')
254 paste(code,'')
255 out = w.getvalue()
255 out = w.getvalue()
256 finally:
256 finally:
257 _ip.write = writer
257 _ip.write = writer
258 yield nt.assert_equal(user_ns['a'], 100)
258 yield nt.assert_equal(user_ns['a'], 100)
259 yield nt.assert_equal(user_ns['b'], 200)
259 yield nt.assert_equal(user_ns['b'], 200)
260 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
260 yield nt.assert_equal(out, code+"\n## -- End pasted text --\n")
261
261
262 finally:
262 finally:
263 # This should be in a finally clause, instead of the bare except above.
263 # This should be in a finally clause, instead of the bare except above.
264 # Restore original hook
264 # Restore original hook
265 hooks.clipboard_get = original_clip
265 hooks.clipboard_get = original_clip
266
266
267
267
268 def test_time():
268 def test_time():
269 _ip.magic('time None')
269 _ip.magic('time None')
270
270
271
271
272 def doctest_time():
272 def doctest_time():
273 """
273 """
274 In [10]: %time None
274 In [10]: %time None
275 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
275 CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
276 Wall time: 0.00 s
276 Wall time: 0.00 s
277 """
277 """
278
278
279
279
280 def test_doctest_mode():
280 def test_doctest_mode():
281 "Toggle doctest_mode twice, it should be a no-op and run without error"
281 "Toggle doctest_mode twice, it should be a no-op and run without error"
282 _ip.magic('doctest_mode')
282 _ip.magic('doctest_mode')
283 _ip.magic('doctest_mode')
283 _ip.magic('doctest_mode')
284
284
285
285
286 def test_parse_options():
286 def test_parse_options():
287 """Tests for basic options parsing in magics."""
287 """Tests for basic options parsing in magics."""
288 # These are only the most minimal of tests, more should be added later. At
288 # These are only the most minimal of tests, more should be added later. At
289 # the very least we check that basic text/unicode calls work OK.
289 # the very least we check that basic text/unicode calls work OK.
290 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
290 nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo')
291 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
291 nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo')
292
292
293
293
294 def test_dirops():
294 def test_dirops():
295 """Test various directory handling operations."""
295 """Test various directory handling operations."""
296 curpath = lambda :os.path.splitdrive(os.getcwd())[1].replace('\\','/')
296 curpath = lambda :os.path.splitdrive(os.getcwdu())[1].replace('\\','/')
297
297
298 startdir = os.getcwd()
298 startdir = os.getcwdu()
299 ipdir = _ip.ipython_dir
299 ipdir = _ip.ipython_dir
300 try:
300 try:
301 _ip.magic('cd "%s"' % ipdir)
301 _ip.magic('cd "%s"' % ipdir)
302 nt.assert_equal(curpath(), ipdir)
302 nt.assert_equal(curpath(), ipdir)
303 _ip.magic('cd -')
303 _ip.magic('cd -')
304 nt.assert_equal(curpath(), startdir)
304 nt.assert_equal(curpath(), startdir)
305 _ip.magic('pushd "%s"' % ipdir)
305 _ip.magic('pushd "%s"' % ipdir)
306 nt.assert_equal(curpath(), ipdir)
306 nt.assert_equal(curpath(), ipdir)
307 _ip.magic('popd')
307 _ip.magic('popd')
308 nt.assert_equal(curpath(), startdir)
308 nt.assert_equal(curpath(), startdir)
309 finally:
309 finally:
310 os.chdir(startdir)
310 os.chdir(startdir)
311
311
312
312
313 def check_cpaste(code, should_fail=False):
313 def check_cpaste(code, should_fail=False):
314 """Execute code via 'cpaste' and ensure it was executed, unless
314 """Execute code via 'cpaste' and ensure it was executed, unless
315 should_fail is set.
315 should_fail is set.
316 """
316 """
317 _ip.user_ns['code_ran'] = False
317 _ip.user_ns['code_ran'] = False
318
318
319 src = StringIO()
319 src = StringIO()
320 src.write('\n')
320 src.write('\n')
321 src.write(code)
321 src.write(code)
322 src.write('\n--\n')
322 src.write('\n--\n')
323 src.seek(0)
323 src.seek(0)
324
324
325 stdin_save = sys.stdin
325 stdin_save = sys.stdin
326 sys.stdin = src
326 sys.stdin = src
327
327
328 try:
328 try:
329 _ip.magic('cpaste')
329 _ip.magic('cpaste')
330 except:
330 except:
331 if not should_fail:
331 if not should_fail:
332 raise AssertionError("Failure not expected : '%s'" %
332 raise AssertionError("Failure not expected : '%s'" %
333 code)
333 code)
334 else:
334 else:
335 assert _ip.user_ns['code_ran']
335 assert _ip.user_ns['code_ran']
336 if should_fail:
336 if should_fail:
337 raise AssertionError("Failure expected : '%s'" % code)
337 raise AssertionError("Failure expected : '%s'" % code)
338 finally:
338 finally:
339 sys.stdin = stdin_save
339 sys.stdin = stdin_save
340
340
341
341
342 def test_cpaste():
342 def test_cpaste():
343 """Test cpaste magic"""
343 """Test cpaste magic"""
344
344
345 def run():
345 def run():
346 """Marker function: sets a flag when executed.
346 """Marker function: sets a flag when executed.
347 """
347 """
348 _ip.user_ns['code_ran'] = True
348 _ip.user_ns['code_ran'] = True
349 return 'run' # return string so '+ run()' doesn't result in success
349 return 'run' # return string so '+ run()' doesn't result in success
350
350
351 tests = {'pass': ["> > > run()",
351 tests = {'pass': ["> > > run()",
352 ">>> > run()",
352 ">>> > run()",
353 "+++ run()",
353 "+++ run()",
354 "++ run()",
354 "++ run()",
355 " >>> run()"],
355 " >>> run()"],
356
356
357 'fail': ["+ + run()",
357 'fail': ["+ + run()",
358 " ++ run()"]}
358 " ++ run()"]}
359
359
360 _ip.user_ns['run'] = run
360 _ip.user_ns['run'] = run
361
361
362 for code in tests['pass']:
362 for code in tests['pass']:
363 check_cpaste(code)
363 check_cpaste(code)
364
364
365 for code in tests['fail']:
365 for code in tests['fail']:
366 check_cpaste(code, should_fail=True)
366 check_cpaste(code, should_fail=True)
367
367
368 def test_xmode():
368 def test_xmode():
369 # Calling xmode three times should be a no-op
369 # Calling xmode three times should be a no-op
370 xmode = _ip.InteractiveTB.mode
370 xmode = _ip.InteractiveTB.mode
371 for i in range(3):
371 for i in range(3):
372 _ip.magic("xmode")
372 _ip.magic("xmode")
373 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
373 nt.assert_equal(_ip.InteractiveTB.mode, xmode)
374
374
375 def doctest_who():
375 def doctest_who():
376 """doctest for %who
376 """doctest for %who
377
377
378 In [1]: %reset -f
378 In [1]: %reset -f
379
379
380 In [2]: alpha = 123
380 In [2]: alpha = 123
381
381
382 In [3]: beta = 'beta'
382 In [3]: beta = 'beta'
383
383
384 In [4]: %who int
384 In [4]: %who int
385 alpha
385 alpha
386
386
387 In [5]: %who str
387 In [5]: %who str
388 beta
388 beta
389
389
390 In [6]: %whos
390 In [6]: %whos
391 Variable Type Data/Info
391 Variable Type Data/Info
392 ----------------------------
392 ----------------------------
393 alpha int 123
393 alpha int 123
394 beta str beta
394 beta str beta
395
395
396 In [7]: %who_ls
396 In [7]: %who_ls
397 Out[7]: ['alpha', 'beta']
397 Out[7]: ['alpha', 'beta']
398 """
398 """
399
399
400 def doctest_precision():
400 def doctest_precision():
401 """doctest for %precision
401 """doctest for %precision
402
402
403 In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain']
403 In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain']
404
404
405 In [2]: %precision 5
405 In [2]: %precision 5
406 Out[2]: '%.5f'
406 Out[2]: '%.5f'
407
407
408 In [3]: f.float_format
408 In [3]: f.float_format
409 Out[3]: '%.5f'
409 Out[3]: '%.5f'
410
410
411 In [4]: %precision %e
411 In [4]: %precision %e
412 Out[4]: '%e'
412 Out[4]: '%e'
413
413
414 In [5]: f(3.1415927)
414 In [5]: f(3.1415927)
415 Out[5]: '3.141593e+00'
415 Out[5]: '3.141593e+00'
416 """
416 """
417
417
General Comments 0
You need to be logged in to leave comments. Login now