##// END OF EJS Templates
Backport PR #4934: `ipython profile create` respects `--ipython-dir`...
Thomas Kluyver -
Show More
@@ -1,310 +1,310 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for managing IPython profiles.
3 An application for managing IPython profiles.
4
4
5 To be invoked as the `ipython profile` subcommand.
5 To be invoked as the `ipython profile` subcommand.
6
6
7 Authors:
7 Authors:
8
8
9 * Min RK
9 * Min RK
10
10
11 """
11 """
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Copyright (C) 2008 The IPython Development Team
14 # Copyright (C) 2008 The IPython Development Team
15 #
15 #
16 # Distributed under the terms of the BSD License. The full license is in
16 # Distributed under the terms of the BSD License. The full license is in
17 # the file COPYING, distributed as part of this software.
17 # the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25
25
26 from IPython.config.application import Application
26 from IPython.config.application import Application
27 from IPython.core.application import (
27 from IPython.core.application import (
28 BaseIPythonApplication, base_flags
28 BaseIPythonApplication, base_flags
29 )
29 )
30 from IPython.core.profiledir import ProfileDir
30 from IPython.core.profiledir import ProfileDir
31 from IPython.utils.importstring import import_item
31 from IPython.utils.importstring import import_item
32 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
32 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
33 from IPython.utils.traitlets import Unicode, Bool, Dict
33 from IPython.utils.traitlets import Unicode, Bool, Dict
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Constants
36 # Constants
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39 create_help = """Create an IPython profile by name
39 create_help = """Create an IPython profile by name
40
40
41 Create an ipython profile directory by its name or
41 Create an ipython profile directory by its name or
42 profile directory path. Profile directories contain
42 profile directory path. Profile directories contain
43 configuration, log and security related files and are named
43 configuration, log and security related files and are named
44 using the convention 'profile_<name>'. By default they are
44 using the convention 'profile_<name>'. By default they are
45 located in your ipython directory. Once created, you will
45 located in your ipython directory. Once created, you will
46 can edit the configuration files in the profile
46 can edit the configuration files in the profile
47 directory to configure IPython. Most users will create a
47 directory to configure IPython. Most users will create a
48 profile directory by name,
48 profile directory by name,
49 `ipython profile create myprofile`, which will put the directory
49 `ipython profile create myprofile`, which will put the directory
50 in `<ipython_dir>/profile_myprofile`.
50 in `<ipython_dir>/profile_myprofile`.
51 """
51 """
52 list_help = """List available IPython profiles
52 list_help = """List available IPython profiles
53
53
54 List all available profiles, by profile location, that can
54 List all available profiles, by profile location, that can
55 be found in the current working directly or in the ipython
55 be found in the current working directly or in the ipython
56 directory. Profile directories are named using the convention
56 directory. Profile directories are named using the convention
57 'profile_<profile>'.
57 'profile_<profile>'.
58 """
58 """
59 profile_help = """Manage IPython profiles
59 profile_help = """Manage IPython profiles
60
60
61 Profile directories contain
61 Profile directories contain
62 configuration, log and security related files and are named
62 configuration, log and security related files and are named
63 using the convention 'profile_<name>'. By default they are
63 using the convention 'profile_<name>'. By default they are
64 located in your ipython directory. You can create profiles
64 located in your ipython directory. You can create profiles
65 with `ipython profile create <name>`, or see the profiles you
65 with `ipython profile create <name>`, or see the profiles you
66 already have with `ipython profile list`
66 already have with `ipython profile list`
67
67
68 To get started configuring IPython, simply do:
68 To get started configuring IPython, simply do:
69
69
70 $> ipython profile create
70 $> ipython profile create
71
71
72 and IPython will create the default profile in <ipython_dir>/profile_default,
72 and IPython will create the default profile in <ipython_dir>/profile_default,
73 where you can edit ipython_config.py to start configuring IPython.
73 where you can edit ipython_config.py to start configuring IPython.
74
74
75 """
75 """
76
76
77 _list_examples = "ipython profile list # list all profiles"
77 _list_examples = "ipython profile list # list all profiles"
78
78
79 _create_examples = """
79 _create_examples = """
80 ipython profile create foo # create profile foo w/ default config files
80 ipython profile create foo # create profile foo w/ default config files
81 ipython profile create foo --reset # restage default config files over current
81 ipython profile create foo --reset # restage default config files over current
82 ipython profile create foo --parallel # also stage parallel config files
82 ipython profile create foo --parallel # also stage parallel config files
83 """
83 """
84
84
85 _main_examples = """
85 _main_examples = """
86 ipython profile create -h # show the help string for the create subcommand
86 ipython profile create -h # show the help string for the create subcommand
87 ipython profile list -h # show the help string for the list subcommand
87 ipython profile list -h # show the help string for the list subcommand
88
88
89 ipython locate profile foo # print the path to the directory for profile 'foo'
89 ipython locate profile foo # print the path to the directory for profile 'foo'
90 """
90 """
91
91
92 #-----------------------------------------------------------------------------
92 #-----------------------------------------------------------------------------
93 # Profile Application Class (for `ipython profile` subcommand)
93 # Profile Application Class (for `ipython profile` subcommand)
94 #-----------------------------------------------------------------------------
94 #-----------------------------------------------------------------------------
95
95
96
96
97 def list_profiles_in(path):
97 def list_profiles_in(path):
98 """list profiles in a given root directory"""
98 """list profiles in a given root directory"""
99 files = os.listdir(path)
99 files = os.listdir(path)
100 profiles = []
100 profiles = []
101 for f in files:
101 for f in files:
102 full_path = os.path.join(path, f)
102 full_path = os.path.join(path, f)
103 if os.path.isdir(full_path) and f.startswith('profile_'):
103 if os.path.isdir(full_path) and f.startswith('profile_'):
104 profiles.append(f.split('_',1)[-1])
104 profiles.append(f.split('_',1)[-1])
105 return profiles
105 return profiles
106
106
107
107
108 def list_bundled_profiles():
108 def list_bundled_profiles():
109 """list profiles that are bundled with IPython."""
109 """list profiles that are bundled with IPython."""
110 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
110 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
111 files = os.listdir(path)
111 files = os.listdir(path)
112 profiles = []
112 profiles = []
113 for profile in files:
113 for profile in files:
114 full_path = os.path.join(path, profile)
114 full_path = os.path.join(path, profile)
115 if os.path.isdir(full_path) and profile != "__pycache__":
115 if os.path.isdir(full_path) and profile != "__pycache__":
116 profiles.append(profile)
116 profiles.append(profile)
117 return profiles
117 return profiles
118
118
119
119
120 class ProfileLocate(BaseIPythonApplication):
120 class ProfileLocate(BaseIPythonApplication):
121 description = """print the path an IPython profile dir"""
121 description = """print the path an IPython profile dir"""
122
122
123 def parse_command_line(self, argv=None):
123 def parse_command_line(self, argv=None):
124 super(ProfileLocate, self).parse_command_line(argv)
124 super(ProfileLocate, self).parse_command_line(argv)
125 if self.extra_args:
125 if self.extra_args:
126 self.profile = self.extra_args[0]
126 self.profile = self.extra_args[0]
127
127
128 def start(self):
128 def start(self):
129 print self.profile_dir.location
129 print self.profile_dir.location
130
130
131
131
132 class ProfileList(Application):
132 class ProfileList(Application):
133 name = u'ipython-profile'
133 name = u'ipython-profile'
134 description = list_help
134 description = list_help
135 examples = _list_examples
135 examples = _list_examples
136
136
137 aliases = Dict({
137 aliases = Dict({
138 'ipython-dir' : 'ProfileList.ipython_dir',
138 'ipython-dir' : 'ProfileList.ipython_dir',
139 'log-level' : 'Application.log_level',
139 'log-level' : 'Application.log_level',
140 })
140 })
141 flags = Dict(dict(
141 flags = Dict(dict(
142 debug = ({'Application' : {'log_level' : 0}},
142 debug = ({'Application' : {'log_level' : 0}},
143 "Set Application.log_level to 0, maximizing log output."
143 "Set Application.log_level to 0, maximizing log output."
144 )
144 )
145 ))
145 ))
146
146
147 ipython_dir = Unicode(get_ipython_dir(), config=True,
147 ipython_dir = Unicode(get_ipython_dir(), config=True,
148 help="""
148 help="""
149 The name of the IPython directory. This directory is used for logging
149 The name of the IPython directory. This directory is used for logging
150 configuration (through profiles), history storage, etc. The default
150 configuration (through profiles), history storage, etc. The default
151 is usually $HOME/.ipython. This options can also be specified through
151 is usually $HOME/.ipython. This options can also be specified through
152 the environment variable IPYTHONDIR.
152 the environment variable IPYTHONDIR.
153 """
153 """
154 )
154 )
155
155
156
156
157 def _print_profiles(self, profiles):
157 def _print_profiles(self, profiles):
158 """print list of profiles, indented."""
158 """print list of profiles, indented."""
159 for profile in profiles:
159 for profile in profiles:
160 print ' %s' % profile
160 print ' %s' % profile
161
161
162 def list_profile_dirs(self):
162 def list_profile_dirs(self):
163 profiles = list_bundled_profiles()
163 profiles = list_bundled_profiles()
164 if profiles:
164 if profiles:
165 print
165 print
166 print "Available profiles in IPython:"
166 print "Available profiles in IPython:"
167 self._print_profiles(profiles)
167 self._print_profiles(profiles)
168 print
168 print
169 print " The first request for a bundled profile will copy it"
169 print " The first request for a bundled profile will copy it"
170 print " into your IPython directory (%s)," % self.ipython_dir
170 print " into your IPython directory (%s)," % self.ipython_dir
171 print " where you can customize it."
171 print " where you can customize it."
172
172
173 profiles = list_profiles_in(self.ipython_dir)
173 profiles = list_profiles_in(self.ipython_dir)
174 if profiles:
174 if profiles:
175 print
175 print
176 print "Available profiles in %s:" % self.ipython_dir
176 print "Available profiles in %s:" % self.ipython_dir
177 self._print_profiles(profiles)
177 self._print_profiles(profiles)
178
178
179 profiles = list_profiles_in(os.getcwdu())
179 profiles = list_profiles_in(os.getcwdu())
180 if profiles:
180 if profiles:
181 print
181 print
182 print "Available profiles in current directory (%s):" % os.getcwdu()
182 print "Available profiles in current directory (%s):" % os.getcwdu()
183 self._print_profiles(profiles)
183 self._print_profiles(profiles)
184
184
185 print
185 print
186 print "To use any of the above profiles, start IPython with:"
186 print "To use any of the above profiles, start IPython with:"
187 print " ipython --profile=<name>"
187 print " ipython --profile=<name>"
188 print
188 print
189
189
190 def start(self):
190 def start(self):
191 self.list_profile_dirs()
191 self.list_profile_dirs()
192
192
193
193
194 create_flags = {}
194 create_flags = {}
195 create_flags.update(base_flags)
195 create_flags.update(base_flags)
196 # don't include '--init' flag, which implies running profile create in other apps
196 # don't include '--init' flag, which implies running profile create in other apps
197 create_flags.pop('init')
197 create_flags.pop('init')
198 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
198 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
199 "reset config files in this profile to the defaults.")
199 "reset config files in this profile to the defaults.")
200 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
200 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
201 "Include the config files for parallel "
201 "Include the config files for parallel "
202 "computing apps (ipengine, ipcontroller, etc.)")
202 "computing apps (ipengine, ipcontroller, etc.)")
203
203
204
204
205 class ProfileCreate(BaseIPythonApplication):
205 class ProfileCreate(BaseIPythonApplication):
206 name = u'ipython-profile'
206 name = u'ipython-profile'
207 description = create_help
207 description = create_help
208 examples = _create_examples
208 examples = _create_examples
209 auto_create = Bool(True, config=False)
209 auto_create = Bool(True, config=False)
210 def _log_format_default(self):
210 def _log_format_default(self):
211 return "[%(name)s] %(message)s"
211 return "[%(name)s] %(message)s"
212
212
213 def _copy_config_files_default(self):
213 def _copy_config_files_default(self):
214 return True
214 return True
215
215
216 parallel = Bool(False, config=True,
216 parallel = Bool(False, config=True,
217 help="whether to include parallel computing config files")
217 help="whether to include parallel computing config files")
218 def _parallel_changed(self, name, old, new):
218 def _parallel_changed(self, name, old, new):
219 parallel_files = [ 'ipcontroller_config.py',
219 parallel_files = [ 'ipcontroller_config.py',
220 'ipengine_config.py',
220 'ipengine_config.py',
221 'ipcluster_config.py'
221 'ipcluster_config.py'
222 ]
222 ]
223 if new:
223 if new:
224 for cf in parallel_files:
224 for cf in parallel_files:
225 self.config_files.append(cf)
225 self.config_files.append(cf)
226 else:
226 else:
227 for cf in parallel_files:
227 for cf in parallel_files:
228 if cf in self.config_files:
228 if cf in self.config_files:
229 self.config_files.remove(cf)
229 self.config_files.remove(cf)
230
230
231 def parse_command_line(self, argv):
231 def parse_command_line(self, argv):
232 super(ProfileCreate, self).parse_command_line(argv)
232 super(ProfileCreate, self).parse_command_line(argv)
233 # accept positional arg as profile name
233 # accept positional arg as profile name
234 if self.extra_args:
234 if self.extra_args:
235 self.profile = self.extra_args[0]
235 self.profile = self.extra_args[0]
236
236
237 flags = Dict(create_flags)
237 flags = Dict(create_flags)
238
238
239 classes = [ProfileDir]
239 classes = [ProfileDir]
240
240
241 def _import_app(self, app_path):
241 def _import_app(self, app_path):
242 """import an app class"""
242 """import an app class"""
243 app = None
243 app = None
244 name = app_path.rsplit('.', 1)[-1]
244 name = app_path.rsplit('.', 1)[-1]
245 try:
245 try:
246 app = import_item(app_path)
246 app = import_item(app_path)
247 except ImportError as e:
247 except ImportError as e:
248 self.log.info("Couldn't import %s, config file will be excluded", name)
248 self.log.info("Couldn't import %s, config file will be excluded", name)
249 except Exception:
249 except Exception:
250 self.log.warn('Unexpected error importing %s', name, exc_info=True)
250 self.log.warn('Unexpected error importing %s', name, exc_info=True)
251 return app
251 return app
252
252
253 def init_config_files(self):
253 def init_config_files(self):
254 super(ProfileCreate, self).init_config_files()
254 super(ProfileCreate, self).init_config_files()
255 # use local imports, since these classes may import from here
255 # use local imports, since these classes may import from here
256 from IPython.terminal.ipapp import TerminalIPythonApp
256 from IPython.terminal.ipapp import TerminalIPythonApp
257 apps = [TerminalIPythonApp]
257 apps = [TerminalIPythonApp]
258 for app_path in (
258 for app_path in (
259 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
259 'IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
260 'IPython.html.notebookapp.NotebookApp',
260 'IPython.html.notebookapp.NotebookApp',
261 'IPython.nbconvert.nbconvertapp.NbConvertApp',
261 'IPython.nbconvert.nbconvertapp.NbConvertApp',
262 ):
262 ):
263 app = self._import_app(app_path)
263 app = self._import_app(app_path)
264 if app is not None:
264 if app is not None:
265 apps.append(app)
265 apps.append(app)
266 if self.parallel:
266 if self.parallel:
267 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
267 from IPython.parallel.apps.ipcontrollerapp import IPControllerApp
268 from IPython.parallel.apps.ipengineapp import IPEngineApp
268 from IPython.parallel.apps.ipengineapp import IPEngineApp
269 from IPython.parallel.apps.ipclusterapp import IPClusterStart
269 from IPython.parallel.apps.ipclusterapp import IPClusterStart
270 from IPython.parallel.apps.iploggerapp import IPLoggerApp
270 from IPython.parallel.apps.iploggerapp import IPLoggerApp
271 apps.extend([
271 apps.extend([
272 IPControllerApp,
272 IPControllerApp,
273 IPEngineApp,
273 IPEngineApp,
274 IPClusterStart,
274 IPClusterStart,
275 IPLoggerApp,
275 IPLoggerApp,
276 ])
276 ])
277 for App in apps:
277 for App in apps:
278 app = App()
278 app = App()
279 app.config.update(self.config)
279 app.config.update(self.config)
280 app.log = self.log
280 app.log = self.log
281 app.overwrite = self.overwrite
281 app.overwrite = self.overwrite
282 app.copy_config_files=True
282 app.copy_config_files=True
283 app.profile = self.profile
283 app.ipython_dir=self.ipython_dir
284 app.init_profile_dir()
284 app.profile_dir=self.profile_dir
285 app.init_config_files()
285 app.init_config_files()
286
286
287 def stage_default_config_file(self):
287 def stage_default_config_file(self):
288 pass
288 pass
289
289
290
290
291 class ProfileApp(Application):
291 class ProfileApp(Application):
292 name = u'ipython-profile'
292 name = u'ipython-profile'
293 description = profile_help
293 description = profile_help
294 examples = _main_examples
294 examples = _main_examples
295
295
296 subcommands = Dict(dict(
296 subcommands = Dict(dict(
297 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
297 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
298 list = (ProfileList, ProfileList.description.splitlines()[0]),
298 list = (ProfileList, ProfileList.description.splitlines()[0]),
299 ))
299 ))
300
300
301 def start(self):
301 def start(self):
302 if self.subapp is None:
302 if self.subapp is None:
303 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
303 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
304 print
304 print
305 self.print_description()
305 self.print_description()
306 self.print_subcommands()
306 self.print_subcommands()
307 self.exit(1)
307 self.exit(1)
308 else:
308 else:
309 return self.subapp.start()
309 return self.subapp.start()
310
310
@@ -1,153 +1,166 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for profile-related functions.
2 """Tests for profile-related functions.
3
3
4 Currently only the startup-dir functionality is tested, but more tests should
4 Currently only the startup-dir functionality is tested, but more tests should
5 be added for:
5 be added for:
6
6
7 * ipython profile create
7 * ipython profile create
8 * ipython profile list
8 * ipython profile list
9 * ipython profile create --parallel
9 * ipython profile create --parallel
10 * security dir permissions
10 * security dir permissions
11
11
12 Authors
12 Authors
13 -------
13 -------
14
14
15 * MinRK
15 * MinRK
16
16
17 """
17 """
18 from __future__ import absolute_import
18 from __future__ import absolute_import
19
19
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21 # Imports
21 # Imports
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 import os
24 import os
25 import shutil
25 import shutil
26 import sys
26 import sys
27 import tempfile
27 import tempfile
28
28
29 from unittest import TestCase
29 from unittest import TestCase
30
30
31 import nose.tools as nt
31 import nose.tools as nt
32
32
33 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
33 from IPython.core.profileapp import list_profiles_in, list_bundled_profiles
34 from IPython.core.profiledir import ProfileDir
34 from IPython.core.profiledir import ProfileDir
35
35
36 from IPython.testing import decorators as dec
36 from IPython.testing import decorators as dec
37 from IPython.testing import tools as tt
37 from IPython.testing import tools as tt
38 from IPython.utils import py3compat
38 from IPython.utils import py3compat
39
39 from IPython.utils.process import getoutput
40 from IPython.utils.tempdir import TemporaryDirectory
40
41
41 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
42 # Globals
43 # Globals
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 TMP_TEST_DIR = tempfile.mkdtemp()
45 TMP_TEST_DIR = tempfile.mkdtemp()
45 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
46 HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
46 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
47 IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
47
48
48 #
49 #
49 # Setup/teardown functions/decorators
50 # Setup/teardown functions/decorators
50 #
51 #
51
52
52 def setup():
53 def setup():
53 """Setup test environment for the module:
54 """Setup test environment for the module:
54
55
55 - Adds dummy home dir tree
56 - Adds dummy home dir tree
56 """
57 """
57 # Do not mask exceptions here. In particular, catching WindowsError is a
58 # Do not mask exceptions here. In particular, catching WindowsError is a
58 # problem because that exception is only defined on Windows...
59 # problem because that exception is only defined on Windows...
59 os.makedirs(IP_TEST_DIR)
60 os.makedirs(IP_TEST_DIR)
60
61
61
62
62 def teardown():
63 def teardown():
63 """Teardown test environment for the module:
64 """Teardown test environment for the module:
64
65
65 - Remove dummy home dir tree
66 - Remove dummy home dir tree
66 """
67 """
67 # Note: we remove the parent test dir, which is the root of all test
68 # Note: we remove the parent test dir, which is the root of all test
68 # subdirs we may have created. Use shutil instead of os.removedirs, so
69 # subdirs we may have created. Use shutil instead of os.removedirs, so
69 # that non-empty directories are all recursively removed.
70 # that non-empty directories are all recursively removed.
70 shutil.rmtree(TMP_TEST_DIR)
71 shutil.rmtree(TMP_TEST_DIR)
71
72
72
73
73 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
74 # Test functions
75 # Test functions
75 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
76 def win32_without_pywin32():
77 def win32_without_pywin32():
77 if sys.platform == 'win32':
78 if sys.platform == 'win32':
78 try:
79 try:
79 import pywin32
80 import pywin32
80 except ImportError:
81 except ImportError:
81 return True
82 return True
82 return False
83 return False
83
84
84
85
85 class ProfileStartupTest(TestCase):
86 class ProfileStartupTest(TestCase):
86 def setUp(self):
87 def setUp(self):
87 # create profile dir
88 # create profile dir
88 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, 'test')
89 self.pd = ProfileDir.create_profile_dir_by_name(IP_TEST_DIR, 'test')
89 self.options = ['--ipython-dir', IP_TEST_DIR, '--profile', 'test']
90 self.options = ['--ipython-dir', IP_TEST_DIR, '--profile', 'test']
90 self.fname = os.path.join(TMP_TEST_DIR, 'test.py')
91 self.fname = os.path.join(TMP_TEST_DIR, 'test.py')
91
92
92 def tearDown(self):
93 def tearDown(self):
93 # We must remove this profile right away so its presence doesn't
94 # We must remove this profile right away so its presence doesn't
94 # confuse other tests.
95 # confuse other tests.
95 shutil.rmtree(self.pd.location)
96 shutil.rmtree(self.pd.location)
96
97
97 def init(self, startup_file, startup, test):
98 def init(self, startup_file, startup, test):
98 # write startup python file
99 # write startup python file
99 with open(os.path.join(self.pd.startup_dir, startup_file), 'w') as f:
100 with open(os.path.join(self.pd.startup_dir, startup_file), 'w') as f:
100 f.write(startup)
101 f.write(startup)
101 # write simple test file, to check that the startup file was run
102 # write simple test file, to check that the startup file was run
102 with open(self.fname, 'w') as f:
103 with open(self.fname, 'w') as f:
103 f.write(py3compat.doctest_refactor_print(test))
104 f.write(py3compat.doctest_refactor_print(test))
104
105
105 def validate(self, output):
106 def validate(self, output):
106 tt.ipexec_validate(self.fname, output, '', options=self.options)
107 tt.ipexec_validate(self.fname, output, '', options=self.options)
107
108
108 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
109 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
109 def test_startup_py(self):
110 def test_startup_py(self):
110 self.init('00-start.py', 'zzz=123\n',
111 self.init('00-start.py', 'zzz=123\n',
111 py3compat.doctest_refactor_print('print zzz\n'))
112 py3compat.doctest_refactor_print('print zzz\n'))
112 self.validate('123')
113 self.validate('123')
113
114
114 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
115 @dec.skipif(win32_without_pywin32(), "Test requires pywin32 on Windows")
115 def test_startup_ipy(self):
116 def test_startup_ipy(self):
116 self.init('00-start.ipy', '%profile\n', '')
117 self.init('00-start.ipy', '%profile\n', '')
117 self.validate('test')
118 self.validate('test')
118
119
119
120
120 def test_list_profiles_in():
121 def test_list_profiles_in():
121 # No need to remove these directories and files, as they will get nuked in
122 # No need to remove these directories and files, as they will get nuked in
122 # the module-level teardown.
123 # the module-level teardown.
123 td = tempfile.mkdtemp(dir=TMP_TEST_DIR)
124 td = tempfile.mkdtemp(dir=TMP_TEST_DIR)
124 td = py3compat.str_to_unicode(td)
125 td = py3compat.str_to_unicode(td)
125 for name in ('profile_foo', 'profile_hello', 'not_a_profile'):
126 for name in ('profile_foo', 'profile_hello', 'not_a_profile'):
126 os.mkdir(os.path.join(td, name))
127 os.mkdir(os.path.join(td, name))
127 if dec.unicode_paths:
128 if dec.unicode_paths:
128 os.mkdir(os.path.join(td, u'profile_ΓΌnicode'))
129 os.mkdir(os.path.join(td, u'profile_ΓΌnicode'))
129
130
130 with open(os.path.join(td, 'profile_file'), 'w') as f:
131 with open(os.path.join(td, 'profile_file'), 'w') as f:
131 f.write("I am not a profile directory")
132 f.write("I am not a profile directory")
132 profiles = list_profiles_in(td)
133 profiles = list_profiles_in(td)
133
134
134 # unicode normalization can turn u'ΓΌnicode' into u'u\0308nicode',
135 # unicode normalization can turn u'ΓΌnicode' into u'u\0308nicode',
135 # so only check for *nicode, and that creating a ProfileDir from the
136 # so only check for *nicode, and that creating a ProfileDir from the
136 # name remains valid
137 # name remains valid
137 found_unicode = False
138 found_unicode = False
138 for p in list(profiles):
139 for p in list(profiles):
139 if p.endswith('nicode'):
140 if p.endswith('nicode'):
140 pd = ProfileDir.find_profile_dir_by_name(td, p)
141 pd = ProfileDir.find_profile_dir_by_name(td, p)
141 profiles.remove(p)
142 profiles.remove(p)
142 found_unicode = True
143 found_unicode = True
143 break
144 break
144 if dec.unicode_paths:
145 if dec.unicode_paths:
145 nt.assert_true(found_unicode)
146 nt.assert_true(found_unicode)
146 nt.assert_equal(set(profiles), set(['foo', 'hello']))
147 nt.assert_equal(set(profiles), set(['foo', 'hello']))
147
148
148
149
149 def test_list_bundled_profiles():
150 def test_list_bundled_profiles():
150 # This variable will need to be updated when a new profile gets bundled
151 # This variable will need to be updated when a new profile gets bundled
151 bundled_true = [u'cluster', u'math', u'pysh', u'sympy']
152 bundled_true = [u'cluster', u'math', u'pysh', u'sympy']
152 bundled = sorted(list_bundled_profiles())
153 bundled = sorted(list_bundled_profiles())
153 nt.assert_equal(bundled, bundled_true)
154 nt.assert_equal(bundled, bundled_true)
155
156
157 def test_profile_create_ipython_dir():
158 """ipython profile create respects --ipython-dir"""
159 with TemporaryDirectory() as td:
160 getoutput([sys.executable, '-m', 'IPython', 'profile', 'create',
161 'foo', '--ipython-dir=%s' % td])
162 profile_dir = os.path.join(td, 'profile_foo')
163 assert os.path.exists(profile_dir)
164 ipython_config = os.path.join(profile_dir, 'ipython_config.py')
165 assert os.path.exists(ipython_config)
166 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now