##// END OF EJS Templates
FIX CVE-2022-21699...
Matthias Bussonnier -
Show More
@@ -1,151 +1,155 b''
1 """
1 """
2 IPython: tools for interactive and parallel computing in Python.
2 IPython: tools for interactive and parallel computing in Python.
3
3
4 https://ipython.org
4 https://ipython.org
5 """
5 """
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (c) 2008-2011, IPython Development Team.
7 # Copyright (c) 2008-2011, IPython Development Team.
8 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
8 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
9 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
9 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
10 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
10 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
11 #
11 #
12 # Distributed under the terms of the Modified BSD License.
12 # Distributed under the terms of the Modified BSD License.
13 #
13 #
14 # The full license is in the file COPYING.txt, distributed with this software.
14 # The full license is in the file COPYING.txt, distributed with this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 import os
21 import os
22 import sys
22 import sys
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Setup everything
25 # Setup everything
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 # Don't forget to also update setup.py when this changes!
28 # Don't forget to also update setup.py when this changes!
29 if sys.version_info < (3, 8):
29 if sys.version_info < (3, 8):
30 raise ImportError(
30 raise ImportError(
31 """
31 """
32 IPython 8+ supports Python 3.8 and above, following NEP 29.
32 IPython 8+ supports Python 3.8 and above, following NEP 29.
33 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
33 When using Python 2.7, please install IPython 5.x LTS Long Term Support version.
34 Python 3.3 and 3.4 were supported up to IPython 6.x.
34 Python 3.3 and 3.4 were supported up to IPython 6.x.
35 Python 3.5 was supported with IPython 7.0 to 7.9.
35 Python 3.5 was supported with IPython 7.0 to 7.9.
36 Python 3.6 was supported with IPython up to 7.16.
36 Python 3.6 was supported with IPython up to 7.16.
37 Python 3.7 was still supported with the 7.x branch.
37 Python 3.7 was still supported with the 7.x branch.
38
38
39 See IPython `README.rst` file for more information:
39 See IPython `README.rst` file for more information:
40
40
41 https://github.com/ipython/ipython/blob/master/README.rst
41 https://github.com/ipython/ipython/blob/master/README.rst
42
42
43 """)
43 """)
44
44
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46 # Setup the top level names
46 # Setup the top level names
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48
48
49 from .core.getipython import get_ipython
49 from .core.getipython import get_ipython
50 from .core import release
50 from .core import release
51 from .core.application import Application
51 from .core.application import Application
52 from .terminal.embed import embed
52 from .terminal.embed import embed
53
53
54 from .core.interactiveshell import InteractiveShell
54 from .core.interactiveshell import InteractiveShell
55 from .utils.sysinfo import sys_info
55 from .utils.sysinfo import sys_info
56 from .utils.frame import extract_module_locals
56 from .utils.frame import extract_module_locals
57
57
58 # Release data
58 # Release data
59 __author__ = '%s <%s>' % (release.author, release.author_email)
59 __author__ = '%s <%s>' % (release.author, release.author_email)
60 __license__ = release.license
60 __license__ = release.license
61 __version__ = release.version
61 __version__ = release.version
62 version_info = release.version_info
62 version_info = release.version_info
63 # list of CVEs that should have been patched in this release.
64 # this is informational and should not be relied upon.
65 __patched_cves__ = {"CVE-2022-21699"}
66
63
67
64 def embed_kernel(module=None, local_ns=None, **kwargs):
68 def embed_kernel(module=None, local_ns=None, **kwargs):
65 """Embed and start an IPython kernel in a given scope.
69 """Embed and start an IPython kernel in a given scope.
66
70
67 If you don't want the kernel to initialize the namespace
71 If you don't want the kernel to initialize the namespace
68 from the scope of the surrounding function,
72 from the scope of the surrounding function,
69 and/or you want to load full IPython configuration,
73 and/or you want to load full IPython configuration,
70 you probably want `IPython.start_kernel()` instead.
74 you probably want `IPython.start_kernel()` instead.
71
75
72 Parameters
76 Parameters
73 ----------
77 ----------
74 module : types.ModuleType, optional
78 module : types.ModuleType, optional
75 The module to load into IPython globals (default: caller)
79 The module to load into IPython globals (default: caller)
76 local_ns : dict, optional
80 local_ns : dict, optional
77 The namespace to load into IPython user namespace (default: caller)
81 The namespace to load into IPython user namespace (default: caller)
78 **kwargs : various, optional
82 **kwargs : various, optional
79 Further keyword args are relayed to the IPKernelApp constructor,
83 Further keyword args are relayed to the IPKernelApp constructor,
80 allowing configuration of the Kernel. Will only have an effect
84 allowing configuration of the Kernel. Will only have an effect
81 on the first embed_kernel call for a given process.
85 on the first embed_kernel call for a given process.
82 """
86 """
83
87
84 (caller_module, caller_locals) = extract_module_locals(1)
88 (caller_module, caller_locals) = extract_module_locals(1)
85 if module is None:
89 if module is None:
86 module = caller_module
90 module = caller_module
87 if local_ns is None:
91 if local_ns is None:
88 local_ns = caller_locals
92 local_ns = caller_locals
89
93
90 # Only import .zmq when we really need it
94 # Only import .zmq when we really need it
91 from ipykernel.embed import embed_kernel as real_embed_kernel
95 from ipykernel.embed import embed_kernel as real_embed_kernel
92 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
96 real_embed_kernel(module=module, local_ns=local_ns, **kwargs)
93
97
94 def start_ipython(argv=None, **kwargs):
98 def start_ipython(argv=None, **kwargs):
95 """Launch a normal IPython instance (as opposed to embedded)
99 """Launch a normal IPython instance (as opposed to embedded)
96
100
97 `IPython.embed()` puts a shell in a particular calling scope,
101 `IPython.embed()` puts a shell in a particular calling scope,
98 such as a function or method for debugging purposes,
102 such as a function or method for debugging purposes,
99 which is often not desirable.
103 which is often not desirable.
100
104
101 `start_ipython()` does full, regular IPython initialization,
105 `start_ipython()` does full, regular IPython initialization,
102 including loading startup files, configuration, etc.
106 including loading startup files, configuration, etc.
103 much of which is skipped by `embed()`.
107 much of which is skipped by `embed()`.
104
108
105 This is a public API method, and will survive implementation changes.
109 This is a public API method, and will survive implementation changes.
106
110
107 Parameters
111 Parameters
108 ----------
112 ----------
109 argv : list or None, optional
113 argv : list or None, optional
110 If unspecified or None, IPython will parse command-line options from sys.argv.
114 If unspecified or None, IPython will parse command-line options from sys.argv.
111 To prevent any command-line parsing, pass an empty list: `argv=[]`.
115 To prevent any command-line parsing, pass an empty list: `argv=[]`.
112 user_ns : dict, optional
116 user_ns : dict, optional
113 specify this dictionary to initialize the IPython user namespace with particular values.
117 specify this dictionary to initialize the IPython user namespace with particular values.
114 **kwargs : various, optional
118 **kwargs : various, optional
115 Any other kwargs will be passed to the Application constructor,
119 Any other kwargs will be passed to the Application constructor,
116 such as `config`.
120 such as `config`.
117 """
121 """
118 from IPython.terminal.ipapp import launch_new_instance
122 from IPython.terminal.ipapp import launch_new_instance
119 return launch_new_instance(argv=argv, **kwargs)
123 return launch_new_instance(argv=argv, **kwargs)
120
124
121 def start_kernel(argv=None, **kwargs):
125 def start_kernel(argv=None, **kwargs):
122 """Launch a normal IPython kernel instance (as opposed to embedded)
126 """Launch a normal IPython kernel instance (as opposed to embedded)
123
127
124 `IPython.embed_kernel()` puts a shell in a particular calling scope,
128 `IPython.embed_kernel()` puts a shell in a particular calling scope,
125 such as a function or method for debugging purposes,
129 such as a function or method for debugging purposes,
126 which is often not desirable.
130 which is often not desirable.
127
131
128 `start_kernel()` does full, regular IPython initialization,
132 `start_kernel()` does full, regular IPython initialization,
129 including loading startup files, configuration, etc.
133 including loading startup files, configuration, etc.
130 much of which is skipped by `embed()`.
134 much of which is skipped by `embed()`.
131
135
132 Parameters
136 Parameters
133 ----------
137 ----------
134 argv : list or None, optional
138 argv : list or None, optional
135 If unspecified or None, IPython will parse command-line options from sys.argv.
139 If unspecified or None, IPython will parse command-line options from sys.argv.
136 To prevent any command-line parsing, pass an empty list: `argv=[]`.
140 To prevent any command-line parsing, pass an empty list: `argv=[]`.
137 user_ns : dict, optional
141 user_ns : dict, optional
138 specify this dictionary to initialize the IPython user namespace with particular values.
142 specify this dictionary to initialize the IPython user namespace with particular values.
139 **kwargs : various, optional
143 **kwargs : various, optional
140 Any other kwargs will be passed to the Application constructor,
144 Any other kwargs will be passed to the Application constructor,
141 such as `config`.
145 such as `config`.
142 """
146 """
143 import warnings
147 import warnings
144
148
145 warnings.warn(
149 warnings.warn(
146 "start_kernel is deprecated since IPython 8.0, use from `ipykernel.kernelapp.launch_new_instance`",
150 "start_kernel is deprecated since IPython 8.0, use from `ipykernel.kernelapp.launch_new_instance`",
147 DeprecationWarning,
151 DeprecationWarning,
148 stacklevel=2,
152 stacklevel=2,
149 )
153 )
150 from ipykernel.kernelapp import launch_new_instance
154 from ipykernel.kernelapp import launch_new_instance
151 return launch_new_instance(argv=argv, **kwargs)
155 return launch_new_instance(argv=argv, **kwargs)
@@ -1,490 +1,490 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 configurables.
6 handling configuration and creating configurables.
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
11
12 # Copyright (c) IPython Development Team.
12 # Copyright (c) IPython Development Team.
13 # Distributed under the terms of the Modified BSD License.
13 # Distributed under the terms of the Modified BSD License.
14
14
15 import atexit
15 import atexit
16 from copy import deepcopy
16 from copy import deepcopy
17 import glob
17 import glob
18 import logging
18 import logging
19 import os
19 import os
20 import shutil
20 import shutil
21 import sys
21 import sys
22
22
23 from pathlib import Path
23 from pathlib import Path
24
24
25 from traitlets.config.application import Application, catch_config_error
25 from traitlets.config.application import Application, catch_config_error
26 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
26 from traitlets.config.loader import ConfigFileNotFound, PyFileConfigLoader
27 from IPython.core import release, crashhandler
27 from IPython.core import release, crashhandler
28 from IPython.core.profiledir import ProfileDir, ProfileDirError
28 from IPython.core.profiledir import ProfileDir, ProfileDirError
29 from IPython.paths import get_ipython_dir, get_ipython_package_dir
29 from IPython.paths import get_ipython_dir, get_ipython_package_dir
30 from IPython.utils.path import ensure_dir_exists
30 from IPython.utils.path import ensure_dir_exists
31 from traitlets import (
31 from traitlets import (
32 List, Unicode, Type, Bool, Set, Instance, Undefined,
32 List, Unicode, Type, Bool, Set, Instance, Undefined,
33 default, observe,
33 default, observe,
34 )
34 )
35
35
36 if os.name == "nt":
36 if os.name == "nt":
37 programdata = os.environ.get("PROGRAMDATA", None)
37 programdata = os.environ.get("PROGRAMDATA", None)
38 if programdata is not None:
38 if programdata is not None:
39 SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
39 SYSTEM_CONFIG_DIRS = [str(Path(programdata) / "ipython")]
40 else: # PROGRAMDATA is not defined by default on XP.
40 else: # PROGRAMDATA is not defined by default on XP.
41 SYSTEM_CONFIG_DIRS = []
41 SYSTEM_CONFIG_DIRS = []
42 else:
42 else:
43 SYSTEM_CONFIG_DIRS = [
43 SYSTEM_CONFIG_DIRS = [
44 "/usr/local/etc/ipython",
44 "/usr/local/etc/ipython",
45 "/etc/ipython",
45 "/etc/ipython",
46 ]
46 ]
47
47
48
48
49 ENV_CONFIG_DIRS = []
49 ENV_CONFIG_DIRS = []
50 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
50 _env_config_dir = os.path.join(sys.prefix, 'etc', 'ipython')
51 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
51 if _env_config_dir not in SYSTEM_CONFIG_DIRS:
52 # only add ENV_CONFIG if sys.prefix is not already included
52 # only add ENV_CONFIG if sys.prefix is not already included
53 ENV_CONFIG_DIRS.append(_env_config_dir)
53 ENV_CONFIG_DIRS.append(_env_config_dir)
54
54
55
55
56 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
56 _envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS')
57 if _envvar in {None, ''}:
57 if _envvar in {None, ''}:
58 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
58 IPYTHON_SUPPRESS_CONFIG_ERRORS = None
59 else:
59 else:
60 if _envvar.lower() in {'1','true'}:
60 if _envvar.lower() in {'1','true'}:
61 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
61 IPYTHON_SUPPRESS_CONFIG_ERRORS = True
62 elif _envvar.lower() in {'0','false'} :
62 elif _envvar.lower() in {'0','false'} :
63 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
63 IPYTHON_SUPPRESS_CONFIG_ERRORS = False
64 else:
64 else:
65 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
65 sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar )
66
66
67 # aliases and flags
67 # aliases and flags
68
68
69 base_aliases = {}
69 base_aliases = {}
70 if isinstance(Application.aliases, dict):
70 if isinstance(Application.aliases, dict):
71 # traitlets 5
71 # traitlets 5
72 base_aliases.update(Application.aliases)
72 base_aliases.update(Application.aliases)
73 base_aliases.update(
73 base_aliases.update(
74 {
74 {
75 "profile-dir": "ProfileDir.location",
75 "profile-dir": "ProfileDir.location",
76 "profile": "BaseIPythonApplication.profile",
76 "profile": "BaseIPythonApplication.profile",
77 "ipython-dir": "BaseIPythonApplication.ipython_dir",
77 "ipython-dir": "BaseIPythonApplication.ipython_dir",
78 "log-level": "Application.log_level",
78 "log-level": "Application.log_level",
79 "config": "BaseIPythonApplication.extra_config_file",
79 "config": "BaseIPythonApplication.extra_config_file",
80 }
80 }
81 )
81 )
82
82
83 base_flags = dict()
83 base_flags = dict()
84 if isinstance(Application.flags, dict):
84 if isinstance(Application.flags, dict):
85 # traitlets 5
85 # traitlets 5
86 base_flags.update(Application.flags)
86 base_flags.update(Application.flags)
87 base_flags.update(
87 base_flags.update(
88 dict(
88 dict(
89 debug=(
89 debug=(
90 {"Application": {"log_level": logging.DEBUG}},
90 {"Application": {"log_level": logging.DEBUG}},
91 "set log level to logging.DEBUG (maximize logging output)",
91 "set log level to logging.DEBUG (maximize logging output)",
92 ),
92 ),
93 quiet=(
93 quiet=(
94 {"Application": {"log_level": logging.CRITICAL}},
94 {"Application": {"log_level": logging.CRITICAL}},
95 "set log level to logging.CRITICAL (minimize logging output)",
95 "set log level to logging.CRITICAL (minimize logging output)",
96 ),
96 ),
97 init=(
97 init=(
98 {
98 {
99 "BaseIPythonApplication": {
99 "BaseIPythonApplication": {
100 "copy_config_files": True,
100 "copy_config_files": True,
101 "auto_create": True,
101 "auto_create": True,
102 }
102 }
103 },
103 },
104 """Initialize profile with default config files. This is equivalent
104 """Initialize profile with default config files. This is equivalent
105 to running `ipython profile create <profile>` prior to startup.
105 to running `ipython profile create <profile>` prior to startup.
106 """,
106 """,
107 ),
107 ),
108 )
108 )
109 )
109 )
110
110
111
111
112 class ProfileAwareConfigLoader(PyFileConfigLoader):
112 class ProfileAwareConfigLoader(PyFileConfigLoader):
113 """A Python file config loader that is aware of IPython profiles."""
113 """A Python file config loader that is aware of IPython profiles."""
114 def load_subconfig(self, fname, path=None, profile=None):
114 def load_subconfig(self, fname, path=None, profile=None):
115 if profile is not None:
115 if profile is not None:
116 try:
116 try:
117 profile_dir = ProfileDir.find_profile_dir_by_name(
117 profile_dir = ProfileDir.find_profile_dir_by_name(
118 get_ipython_dir(),
118 get_ipython_dir(),
119 profile,
119 profile,
120 )
120 )
121 except ProfileDirError:
121 except ProfileDirError:
122 return
122 return
123 path = profile_dir.location
123 path = profile_dir.location
124 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
124 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
125
125
126 class BaseIPythonApplication(Application):
126 class BaseIPythonApplication(Application):
127
127
128 name = u'ipython'
128 name = u'ipython'
129 description = Unicode(u'IPython: an enhanced interactive Python shell.')
129 description = Unicode(u'IPython: an enhanced interactive Python shell.')
130 version = Unicode(release.version)
130 version = Unicode(release.version)
131
131
132 aliases = base_aliases
132 aliases = base_aliases
133 flags = base_flags
133 flags = base_flags
134 classes = List([ProfileDir])
134 classes = List([ProfileDir])
135
135
136 # enable `load_subconfig('cfg.py', profile='name')`
136 # enable `load_subconfig('cfg.py', profile='name')`
137 python_config_loader_class = ProfileAwareConfigLoader
137 python_config_loader_class = ProfileAwareConfigLoader
138
138
139 # Track whether the config_file has changed,
139 # Track whether the config_file has changed,
140 # because some logic happens only if we aren't using the default.
140 # because some logic happens only if we aren't using the default.
141 config_file_specified = Set()
141 config_file_specified = Set()
142
142
143 config_file_name = Unicode()
143 config_file_name = Unicode()
144 @default('config_file_name')
144 @default('config_file_name')
145 def _config_file_name_default(self):
145 def _config_file_name_default(self):
146 return self.name.replace('-','_') + u'_config.py'
146 return self.name.replace('-','_') + u'_config.py'
147 @observe('config_file_name')
147 @observe('config_file_name')
148 def _config_file_name_changed(self, change):
148 def _config_file_name_changed(self, change):
149 if change['new'] != change['old']:
149 if change['new'] != change['old']:
150 self.config_file_specified.add(change['new'])
150 self.config_file_specified.add(change['new'])
151
151
152 # The directory that contains IPython's builtin profiles.
152 # The directory that contains IPython's builtin profiles.
153 builtin_profile_dir = Unicode(
153 builtin_profile_dir = Unicode(
154 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
154 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
155 )
155 )
156
156
157 config_file_paths = List(Unicode())
157 config_file_paths = List(Unicode())
158 @default('config_file_paths')
158 @default('config_file_paths')
159 def _config_file_paths_default(self):
159 def _config_file_paths_default(self):
160 return [os.getcwd()]
160 return []
161
161
162 extra_config_file = Unicode(
162 extra_config_file = Unicode(
163 help="""Path to an extra config file to load.
163 help="""Path to an extra config file to load.
164
164
165 If specified, load this config file in addition to any other IPython config.
165 If specified, load this config file in addition to any other IPython config.
166 """).tag(config=True)
166 """).tag(config=True)
167 @observe('extra_config_file')
167 @observe('extra_config_file')
168 def _extra_config_file_changed(self, change):
168 def _extra_config_file_changed(self, change):
169 old = change['old']
169 old = change['old']
170 new = change['new']
170 new = change['new']
171 try:
171 try:
172 self.config_files.remove(old)
172 self.config_files.remove(old)
173 except ValueError:
173 except ValueError:
174 pass
174 pass
175 self.config_file_specified.add(new)
175 self.config_file_specified.add(new)
176 self.config_files.append(new)
176 self.config_files.append(new)
177
177
178 profile = Unicode(u'default',
178 profile = Unicode(u'default',
179 help="""The IPython profile to use."""
179 help="""The IPython profile to use."""
180 ).tag(config=True)
180 ).tag(config=True)
181
181
182 @observe('profile')
182 @observe('profile')
183 def _profile_changed(self, change):
183 def _profile_changed(self, change):
184 self.builtin_profile_dir = os.path.join(
184 self.builtin_profile_dir = os.path.join(
185 get_ipython_package_dir(), u'config', u'profile', change['new']
185 get_ipython_package_dir(), u'config', u'profile', change['new']
186 )
186 )
187
187
188 add_ipython_dir_to_sys_path = Bool(
188 add_ipython_dir_to_sys_path = Bool(
189 False,
189 False,
190 """Should the IPython profile directory be added to sys path ?
190 """Should the IPython profile directory be added to sys path ?
191
191
192 This option was non-existing before IPython 8.0, and ipython_dir was added to
192 This option was non-existing before IPython 8.0, and ipython_dir was added to
193 sys path to allow import of extensions present there. This was historical
193 sys path to allow import of extensions present there. This was historical
194 baggage from when pip did not exist. This now default to false,
194 baggage from when pip did not exist. This now default to false,
195 but can be set to true for legacy reasons.
195 but can be set to true for legacy reasons.
196 """,
196 """,
197 ).tag(config=True)
197 ).tag(config=True)
198
198
199 ipython_dir = Unicode(
199 ipython_dir = Unicode(
200 help="""
200 help="""
201 The name of the IPython directory. This directory is used for logging
201 The name of the IPython directory. This directory is used for logging
202 configuration (through profiles), history storage, etc. The default
202 configuration (through profiles), history storage, etc. The default
203 is usually $HOME/.ipython. This option can also be specified through
203 is usually $HOME/.ipython. This option can also be specified through
204 the environment variable IPYTHONDIR.
204 the environment variable IPYTHONDIR.
205 """
205 """
206 ).tag(config=True)
206 ).tag(config=True)
207 @default('ipython_dir')
207 @default('ipython_dir')
208 def _ipython_dir_default(self):
208 def _ipython_dir_default(self):
209 d = get_ipython_dir()
209 d = get_ipython_dir()
210 self._ipython_dir_changed({
210 self._ipython_dir_changed({
211 'name': 'ipython_dir',
211 'name': 'ipython_dir',
212 'old': d,
212 'old': d,
213 'new': d,
213 'new': d,
214 })
214 })
215 return d
215 return d
216
216
217 _in_init_profile_dir = False
217 _in_init_profile_dir = False
218 profile_dir = Instance(ProfileDir, allow_none=True)
218 profile_dir = Instance(ProfileDir, allow_none=True)
219 @default('profile_dir')
219 @default('profile_dir')
220 def _profile_dir_default(self):
220 def _profile_dir_default(self):
221 # avoid recursion
221 # avoid recursion
222 if self._in_init_profile_dir:
222 if self._in_init_profile_dir:
223 return
223 return
224 # profile_dir requested early, force initialization
224 # profile_dir requested early, force initialization
225 self.init_profile_dir()
225 self.init_profile_dir()
226 return self.profile_dir
226 return self.profile_dir
227
227
228 overwrite = Bool(False,
228 overwrite = Bool(False,
229 help="""Whether to overwrite existing config files when copying"""
229 help="""Whether to overwrite existing config files when copying"""
230 ).tag(config=True)
230 ).tag(config=True)
231 auto_create = Bool(False,
231 auto_create = Bool(False,
232 help="""Whether to create profile dir if it doesn't exist"""
232 help="""Whether to create profile dir if it doesn't exist"""
233 ).tag(config=True)
233 ).tag(config=True)
234
234
235 config_files = List(Unicode())
235 config_files = List(Unicode())
236 @default('config_files')
236 @default('config_files')
237 def _config_files_default(self):
237 def _config_files_default(self):
238 return [self.config_file_name]
238 return [self.config_file_name]
239
239
240 copy_config_files = Bool(False,
240 copy_config_files = Bool(False,
241 help="""Whether to install the default config files into the profile dir.
241 help="""Whether to install the default config files into the profile dir.
242 If a new profile is being created, and IPython contains config files for that
242 If a new profile is being created, and IPython contains config files for that
243 profile, then they will be staged into the new directory. Otherwise,
243 profile, then they will be staged into the new directory. Otherwise,
244 default config files will be automatically generated.
244 default config files will be automatically generated.
245 """).tag(config=True)
245 """).tag(config=True)
246
246
247 verbose_crash = Bool(False,
247 verbose_crash = Bool(False,
248 help="""Create a massive crash report when IPython encounters what may be an
248 help="""Create a massive crash report when IPython encounters what may be an
249 internal error. The default is to append a short message to the
249 internal error. The default is to append a short message to the
250 usual traceback""").tag(config=True)
250 usual traceback""").tag(config=True)
251
251
252 # The class to use as the crash handler.
252 # The class to use as the crash handler.
253 crash_handler_class = Type(crashhandler.CrashHandler)
253 crash_handler_class = Type(crashhandler.CrashHandler)
254
254
255 @catch_config_error
255 @catch_config_error
256 def __init__(self, **kwargs):
256 def __init__(self, **kwargs):
257 super(BaseIPythonApplication, self).__init__(**kwargs)
257 super(BaseIPythonApplication, self).__init__(**kwargs)
258 # ensure current working directory exists
258 # ensure current working directory exists
259 try:
259 try:
260 os.getcwd()
260 os.getcwd()
261 except:
261 except:
262 # exit if cwd doesn't exist
262 # exit if cwd doesn't exist
263 self.log.error("Current working directory doesn't exist.")
263 self.log.error("Current working directory doesn't exist.")
264 self.exit(1)
264 self.exit(1)
265
265
266 #-------------------------------------------------------------------------
266 #-------------------------------------------------------------------------
267 # Various stages of Application creation
267 # Various stages of Application creation
268 #-------------------------------------------------------------------------
268 #-------------------------------------------------------------------------
269
269
270 def init_crash_handler(self):
270 def init_crash_handler(self):
271 """Create a crash handler, typically setting sys.excepthook to it."""
271 """Create a crash handler, typically setting sys.excepthook to it."""
272 self.crash_handler = self.crash_handler_class(self)
272 self.crash_handler = self.crash_handler_class(self)
273 sys.excepthook = self.excepthook
273 sys.excepthook = self.excepthook
274 def unset_crashhandler():
274 def unset_crashhandler():
275 sys.excepthook = sys.__excepthook__
275 sys.excepthook = sys.__excepthook__
276 atexit.register(unset_crashhandler)
276 atexit.register(unset_crashhandler)
277
277
278 def excepthook(self, etype, evalue, tb):
278 def excepthook(self, etype, evalue, tb):
279 """this is sys.excepthook after init_crashhandler
279 """this is sys.excepthook after init_crashhandler
280
280
281 set self.verbose_crash=True to use our full crashhandler, instead of
281 set self.verbose_crash=True to use our full crashhandler, instead of
282 a regular traceback with a short message (crash_handler_lite)
282 a regular traceback with a short message (crash_handler_lite)
283 """
283 """
284
284
285 if self.verbose_crash:
285 if self.verbose_crash:
286 return self.crash_handler(etype, evalue, tb)
286 return self.crash_handler(etype, evalue, tb)
287 else:
287 else:
288 return crashhandler.crash_handler_lite(etype, evalue, tb)
288 return crashhandler.crash_handler_lite(etype, evalue, tb)
289
289
290 @observe('ipython_dir')
290 @observe('ipython_dir')
291 def _ipython_dir_changed(self, change):
291 def _ipython_dir_changed(self, change):
292 old = change['old']
292 old = change['old']
293 new = change['new']
293 new = change['new']
294 if old is not Undefined:
294 if old is not Undefined:
295 str_old = os.path.abspath(old)
295 str_old = os.path.abspath(old)
296 if str_old in sys.path:
296 if str_old in sys.path:
297 sys.path.remove(str_old)
297 sys.path.remove(str_old)
298 if self.add_ipython_dir_to_sys_path:
298 if self.add_ipython_dir_to_sys_path:
299 str_path = os.path.abspath(new)
299 str_path = os.path.abspath(new)
300 sys.path.append(str_path)
300 sys.path.append(str_path)
301 ensure_dir_exists(new)
301 ensure_dir_exists(new)
302 readme = os.path.join(new, "README")
302 readme = os.path.join(new, "README")
303 readme_src = os.path.join(
303 readme_src = os.path.join(
304 get_ipython_package_dir(), "config", "profile", "README"
304 get_ipython_package_dir(), "config", "profile", "README"
305 )
305 )
306 if not os.path.exists(readme) and os.path.exists(readme_src):
306 if not os.path.exists(readme) and os.path.exists(readme_src):
307 shutil.copy(readme_src, readme)
307 shutil.copy(readme_src, readme)
308 for d in ("extensions", "nbextensions"):
308 for d in ("extensions", "nbextensions"):
309 path = os.path.join(new, d)
309 path = os.path.join(new, d)
310 try:
310 try:
311 ensure_dir_exists(path)
311 ensure_dir_exists(path)
312 except OSError as e:
312 except OSError as e:
313 # this will not be EEXIST
313 # this will not be EEXIST
314 self.log.error("couldn't create path %s: %s", path, e)
314 self.log.error("couldn't create path %s: %s", path, e)
315 self.log.debug("IPYTHONDIR set to: %s" % new)
315 self.log.debug("IPYTHONDIR set to: %s" % new)
316
316
317 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
317 def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS):
318 """Load the config file.
318 """Load the config file.
319
319
320 By default, errors in loading config are handled, and a warning
320 By default, errors in loading config are handled, and a warning
321 printed on screen. For testing, the suppress_errors option is set
321 printed on screen. For testing, the suppress_errors option is set
322 to False, so errors will make tests fail.
322 to False, so errors will make tests fail.
323
323
324 `suppress_errors` default value is to be `None` in which case the
324 `suppress_errors` default value is to be `None` in which case the
325 behavior default to the one of `traitlets.Application`.
325 behavior default to the one of `traitlets.Application`.
326
326
327 The default value can be set :
327 The default value can be set :
328 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
328 - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive).
329 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
329 - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive).
330 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
330 - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset.
331
331
332 Any other value are invalid, and will make IPython exit with a non-zero return code.
332 Any other value are invalid, and will make IPython exit with a non-zero return code.
333 """
333 """
334
334
335
335
336 self.log.debug("Searching path %s for config files", self.config_file_paths)
336 self.log.debug("Searching path %s for config files", self.config_file_paths)
337 base_config = 'ipython_config.py'
337 base_config = 'ipython_config.py'
338 self.log.debug("Attempting to load config file: %s" %
338 self.log.debug("Attempting to load config file: %s" %
339 base_config)
339 base_config)
340 try:
340 try:
341 if suppress_errors is not None:
341 if suppress_errors is not None:
342 old_value = Application.raise_config_file_errors
342 old_value = Application.raise_config_file_errors
343 Application.raise_config_file_errors = not suppress_errors;
343 Application.raise_config_file_errors = not suppress_errors;
344 Application.load_config_file(
344 Application.load_config_file(
345 self,
345 self,
346 base_config,
346 base_config,
347 path=self.config_file_paths
347 path=self.config_file_paths
348 )
348 )
349 except ConfigFileNotFound:
349 except ConfigFileNotFound:
350 # ignore errors loading parent
350 # ignore errors loading parent
351 self.log.debug("Config file %s not found", base_config)
351 self.log.debug("Config file %s not found", base_config)
352 pass
352 pass
353 if suppress_errors is not None:
353 if suppress_errors is not None:
354 Application.raise_config_file_errors = old_value
354 Application.raise_config_file_errors = old_value
355
355
356 for config_file_name in self.config_files:
356 for config_file_name in self.config_files:
357 if not config_file_name or config_file_name == base_config:
357 if not config_file_name or config_file_name == base_config:
358 continue
358 continue
359 self.log.debug("Attempting to load config file: %s" %
359 self.log.debug("Attempting to load config file: %s" %
360 self.config_file_name)
360 self.config_file_name)
361 try:
361 try:
362 Application.load_config_file(
362 Application.load_config_file(
363 self,
363 self,
364 config_file_name,
364 config_file_name,
365 path=self.config_file_paths
365 path=self.config_file_paths
366 )
366 )
367 except ConfigFileNotFound:
367 except ConfigFileNotFound:
368 # Only warn if the default config file was NOT being used.
368 # Only warn if the default config file was NOT being used.
369 if config_file_name in self.config_file_specified:
369 if config_file_name in self.config_file_specified:
370 msg = self.log.warning
370 msg = self.log.warning
371 else:
371 else:
372 msg = self.log.debug
372 msg = self.log.debug
373 msg("Config file not found, skipping: %s", config_file_name)
373 msg("Config file not found, skipping: %s", config_file_name)
374 except Exception:
374 except Exception:
375 # For testing purposes.
375 # For testing purposes.
376 if not suppress_errors:
376 if not suppress_errors:
377 raise
377 raise
378 self.log.warning("Error loading config file: %s" %
378 self.log.warning("Error loading config file: %s" %
379 self.config_file_name, exc_info=True)
379 self.config_file_name, exc_info=True)
380
380
381 def init_profile_dir(self):
381 def init_profile_dir(self):
382 """initialize the profile dir"""
382 """initialize the profile dir"""
383 self._in_init_profile_dir = True
383 self._in_init_profile_dir = True
384 if self.profile_dir is not None:
384 if self.profile_dir is not None:
385 # already ran
385 # already ran
386 return
386 return
387 if 'ProfileDir.location' not in self.config:
387 if 'ProfileDir.location' not in self.config:
388 # location not specified, find by profile name
388 # location not specified, find by profile name
389 try:
389 try:
390 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
390 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
391 except ProfileDirError:
391 except ProfileDirError:
392 # not found, maybe create it (always create default profile)
392 # not found, maybe create it (always create default profile)
393 if self.auto_create or self.profile == 'default':
393 if self.auto_create or self.profile == 'default':
394 try:
394 try:
395 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
395 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
396 except ProfileDirError:
396 except ProfileDirError:
397 self.log.fatal("Could not create profile: %r"%self.profile)
397 self.log.fatal("Could not create profile: %r"%self.profile)
398 self.exit(1)
398 self.exit(1)
399 else:
399 else:
400 self.log.info("Created profile dir: %r"%p.location)
400 self.log.info("Created profile dir: %r"%p.location)
401 else:
401 else:
402 self.log.fatal("Profile %r not found."%self.profile)
402 self.log.fatal("Profile %r not found."%self.profile)
403 self.exit(1)
403 self.exit(1)
404 else:
404 else:
405 self.log.debug(f"Using existing profile dir: {p.location!r}")
405 self.log.debug(f"Using existing profile dir: {p.location!r}")
406 else:
406 else:
407 location = self.config.ProfileDir.location
407 location = self.config.ProfileDir.location
408 # location is fully specified
408 # location is fully specified
409 try:
409 try:
410 p = ProfileDir.find_profile_dir(location, self.config)
410 p = ProfileDir.find_profile_dir(location, self.config)
411 except ProfileDirError:
411 except ProfileDirError:
412 # not found, maybe create it
412 # not found, maybe create it
413 if self.auto_create:
413 if self.auto_create:
414 try:
414 try:
415 p = ProfileDir.create_profile_dir(location, self.config)
415 p = ProfileDir.create_profile_dir(location, self.config)
416 except ProfileDirError:
416 except ProfileDirError:
417 self.log.fatal("Could not create profile directory: %r"%location)
417 self.log.fatal("Could not create profile directory: %r"%location)
418 self.exit(1)
418 self.exit(1)
419 else:
419 else:
420 self.log.debug("Creating new profile dir: %r"%location)
420 self.log.debug("Creating new profile dir: %r"%location)
421 else:
421 else:
422 self.log.fatal("Profile directory %r not found."%location)
422 self.log.fatal("Profile directory %r not found."%location)
423 self.exit(1)
423 self.exit(1)
424 else:
424 else:
425 self.log.debug(f"Using existing profile dir: {p.location!r}")
425 self.log.debug(f"Using existing profile dir: {p.location!r}")
426 # if profile_dir is specified explicitly, set profile name
426 # if profile_dir is specified explicitly, set profile name
427 dir_name = os.path.basename(p.location)
427 dir_name = os.path.basename(p.location)
428 if dir_name.startswith('profile_'):
428 if dir_name.startswith('profile_'):
429 self.profile = dir_name[8:]
429 self.profile = dir_name[8:]
430
430
431 self.profile_dir = p
431 self.profile_dir = p
432 self.config_file_paths.append(p.location)
432 self.config_file_paths.append(p.location)
433 self._in_init_profile_dir = False
433 self._in_init_profile_dir = False
434
434
435 def init_config_files(self):
435 def init_config_files(self):
436 """[optionally] copy default config files into profile dir."""
436 """[optionally] copy default config files into profile dir."""
437 self.config_file_paths.extend(ENV_CONFIG_DIRS)
437 self.config_file_paths.extend(ENV_CONFIG_DIRS)
438 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
438 self.config_file_paths.extend(SYSTEM_CONFIG_DIRS)
439 # copy config files
439 # copy config files
440 path = Path(self.builtin_profile_dir)
440 path = Path(self.builtin_profile_dir)
441 if self.copy_config_files:
441 if self.copy_config_files:
442 src = self.profile
442 src = self.profile
443
443
444 cfg = self.config_file_name
444 cfg = self.config_file_name
445 if path and (path / cfg).exists():
445 if path and (path / cfg).exists():
446 self.log.warning(
446 self.log.warning(
447 "Staging %r from %s into %r [overwrite=%s]"
447 "Staging %r from %s into %r [overwrite=%s]"
448 % (cfg, src, self.profile_dir.location, self.overwrite)
448 % (cfg, src, self.profile_dir.location, self.overwrite)
449 )
449 )
450 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
450 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
451 else:
451 else:
452 self.stage_default_config_file()
452 self.stage_default_config_file()
453 else:
453 else:
454 # Still stage *bundled* config files, but not generated ones
454 # Still stage *bundled* config files, but not generated ones
455 # This is necessary for `ipython profile=sympy` to load the profile
455 # This is necessary for `ipython profile=sympy` to load the profile
456 # on the first go
456 # on the first go
457 files = path.glob("*.py")
457 files = path.glob("*.py")
458 for fullpath in files:
458 for fullpath in files:
459 cfg = fullpath.name
459 cfg = fullpath.name
460 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
460 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
461 # file was copied
461 # file was copied
462 self.log.warning("Staging bundled %s from %s into %r"%(
462 self.log.warning("Staging bundled %s from %s into %r"%(
463 cfg, self.profile, self.profile_dir.location)
463 cfg, self.profile, self.profile_dir.location)
464 )
464 )
465
465
466
466
467 def stage_default_config_file(self):
467 def stage_default_config_file(self):
468 """auto generate default config file, and stage it into the profile."""
468 """auto generate default config file, and stage it into the profile."""
469 s = self.generate_config_file()
469 s = self.generate_config_file()
470 config_file = Path(self.profile_dir.location) / self.config_file_name
470 config_file = Path(self.profile_dir.location) / self.config_file_name
471 if self.overwrite or not config_file.exists():
471 if self.overwrite or not config_file.exists():
472 self.log.warning("Generating default config file: %r" % (config_file))
472 self.log.warning("Generating default config file: %r" % (config_file))
473 config_file.write_text(s)
473 config_file.write_text(s)
474
474
475 @catch_config_error
475 @catch_config_error
476 def initialize(self, argv=None):
476 def initialize(self, argv=None):
477 # don't hook up crash handler before parsing command-line
477 # don't hook up crash handler before parsing command-line
478 self.parse_command_line(argv)
478 self.parse_command_line(argv)
479 self.init_crash_handler()
479 self.init_crash_handler()
480 if self.subapp is not None:
480 if self.subapp is not None:
481 # stop here if subapp is taking over
481 # stop here if subapp is taking over
482 return
482 return
483 # save a copy of CLI config to re-load after config files
483 # save a copy of CLI config to re-load after config files
484 # so that it has highest priority
484 # so that it has highest priority
485 cl_config = deepcopy(self.config)
485 cl_config = deepcopy(self.config)
486 self.init_profile_dir()
486 self.init_profile_dir()
487 self.init_config_files()
487 self.init_config_files()
488 self.load_config_file()
488 self.load_config_file()
489 # enforce cl-opts override configfile opts:
489 # enforce cl-opts override configfile opts:
490 self.update_config(cl_config)
490 self.update_config(cl_config)
@@ -1,311 +1,312 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 traitlets.config.application import Application
26 from traitlets.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.paths import get_ipython_dir, get_ipython_package_dir
32 from IPython.paths import get_ipython_dir, get_ipython_package_dir
33 from traitlets import Unicode, Bool, Dict, observe
33 from traitlets import Unicode, Bool, Dict, observe
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 profiles = []
99 profiles = []
100
100
101 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
101 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
102 files = os.scandir(path)
102 files = os.scandir(path)
103 for f in files:
103 for f in files:
104 if f.is_dir() and f.name.startswith('profile_'):
104 if f.is_dir() and f.name.startswith('profile_'):
105 profiles.append(f.name.split('_', 1)[-1])
105 profiles.append(f.name.split('_', 1)[-1])
106 return profiles
106 return profiles
107
107
108
108
109 def list_bundled_profiles():
109 def list_bundled_profiles():
110 """list profiles that are bundled with IPython."""
110 """list profiles that are bundled with IPython."""
111 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
111 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
112 profiles = []
112 profiles = []
113
113
114 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
114 # for python 3.6+ rewrite to: with os.scandir(path) as dirlist:
115 files = os.scandir(path)
115 files = os.scandir(path)
116 for profile in files:
116 for profile in files:
117 if profile.is_dir() and profile.name != "__pycache__":
117 if profile.is_dir() and profile.name != "__pycache__":
118 profiles.append(profile.name)
118 profiles.append(profile.name)
119 return profiles
119 return profiles
120
120
121
121
122 class ProfileLocate(BaseIPythonApplication):
122 class ProfileLocate(BaseIPythonApplication):
123 description = """print the path to an IPython profile dir"""
123 description = """print the path to an IPython profile dir"""
124
124
125 def parse_command_line(self, argv=None):
125 def parse_command_line(self, argv=None):
126 super(ProfileLocate, self).parse_command_line(argv)
126 super(ProfileLocate, self).parse_command_line(argv)
127 if self.extra_args:
127 if self.extra_args:
128 self.profile = self.extra_args[0]
128 self.profile = self.extra_args[0]
129
129
130 def start(self):
130 def start(self):
131 print(self.profile_dir.location)
131 print(self.profile_dir.location)
132
132
133
133
134 class ProfileList(Application):
134 class ProfileList(Application):
135 name = u'ipython-profile'
135 name = u'ipython-profile'
136 description = list_help
136 description = list_help
137 examples = _list_examples
137 examples = _list_examples
138
138
139 aliases = Dict({
139 aliases = Dict({
140 'ipython-dir' : 'ProfileList.ipython_dir',
140 'ipython-dir' : 'ProfileList.ipython_dir',
141 'log-level' : 'Application.log_level',
141 'log-level' : 'Application.log_level',
142 })
142 })
143 flags = Dict(dict(
143 flags = Dict(dict(
144 debug = ({'Application' : {'log_level' : 0}},
144 debug = ({'Application' : {'log_level' : 0}},
145 "Set Application.log_level to 0, maximizing log output."
145 "Set Application.log_level to 0, maximizing log output."
146 )
146 )
147 ))
147 ))
148
148
149 ipython_dir = Unicode(get_ipython_dir(),
149 ipython_dir = Unicode(get_ipython_dir(),
150 help="""
150 help="""
151 The name of the IPython directory. This directory is used for logging
151 The name of the IPython directory. This directory is used for logging
152 configuration (through profiles), history storage, etc. The default
152 configuration (through profiles), history storage, etc. The default
153 is usually $HOME/.ipython. This options can also be specified through
153 is usually $HOME/.ipython. This options can also be specified through
154 the environment variable IPYTHONDIR.
154 the environment variable IPYTHONDIR.
155 """
155 """
156 ).tag(config=True)
156 ).tag(config=True)
157
157
158
158
159 def _print_profiles(self, profiles):
159 def _print_profiles(self, profiles):
160 """print list of profiles, indented."""
160 """print list of profiles, indented."""
161 for profile in profiles:
161 for profile in profiles:
162 print(' %s' % profile)
162 print(' %s' % profile)
163
163
164 def list_profile_dirs(self):
164 def list_profile_dirs(self):
165 profiles = list_bundled_profiles()
165 profiles = list_bundled_profiles()
166 if profiles:
166 if profiles:
167 print()
167 print()
168 print("Available profiles in IPython:")
168 print("Available profiles in IPython:")
169 self._print_profiles(profiles)
169 self._print_profiles(profiles)
170 print()
170 print()
171 print(" The first request for a bundled profile will copy it")
171 print(" The first request for a bundled profile will copy it")
172 print(" into your IPython directory (%s)," % self.ipython_dir)
172 print(" into your IPython directory (%s)," % self.ipython_dir)
173 print(" where you can customize it.")
173 print(" where you can customize it.")
174
174
175 profiles = list_profiles_in(self.ipython_dir)
175 profiles = list_profiles_in(self.ipython_dir)
176 if profiles:
176 if profiles:
177 print()
177 print()
178 print("Available profiles in %s:" % self.ipython_dir)
178 print("Available profiles in %s:" % self.ipython_dir)
179 self._print_profiles(profiles)
179 self._print_profiles(profiles)
180
180
181 profiles = list_profiles_in(os.getcwd())
181 profiles = list_profiles_in(os.getcwd())
182 if profiles:
182 if profiles:
183 print()
183 print()
184 print("Available profiles in current directory (%s):" % os.getcwd())
184 print(
185 self._print_profiles(profiles)
185 "Profiles from CWD have been removed for security reason, see CVE-2022-21699:"
186 )
186
187
187 print()
188 print()
188 print("To use any of the above profiles, start IPython with:")
189 print("To use any of the above profiles, start IPython with:")
189 print(" ipython --profile=<name>")
190 print(" ipython --profile=<name>")
190 print()
191 print()
191
192
192 def start(self):
193 def start(self):
193 self.list_profile_dirs()
194 self.list_profile_dirs()
194
195
195
196
196 create_flags = {}
197 create_flags = {}
197 create_flags.update(base_flags)
198 create_flags.update(base_flags)
198 # don't include '--init' flag, which implies running profile create in other apps
199 # don't include '--init' flag, which implies running profile create in other apps
199 create_flags.pop('init')
200 create_flags.pop('init')
200 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
201 create_flags['reset'] = ({'ProfileCreate': {'overwrite' : True}},
201 "reset config files in this profile to the defaults.")
202 "reset config files in this profile to the defaults.")
202 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
203 create_flags['parallel'] = ({'ProfileCreate': {'parallel' : True}},
203 "Include the config files for parallel "
204 "Include the config files for parallel "
204 "computing apps (ipengine, ipcontroller, etc.)")
205 "computing apps (ipengine, ipcontroller, etc.)")
205
206
206
207
207 class ProfileCreate(BaseIPythonApplication):
208 class ProfileCreate(BaseIPythonApplication):
208 name = u'ipython-profile'
209 name = u'ipython-profile'
209 description = create_help
210 description = create_help
210 examples = _create_examples
211 examples = _create_examples
211 auto_create = Bool(True)
212 auto_create = Bool(True)
212 def _log_format_default(self):
213 def _log_format_default(self):
213 return "[%(name)s] %(message)s"
214 return "[%(name)s] %(message)s"
214
215
215 def _copy_config_files_default(self):
216 def _copy_config_files_default(self):
216 return True
217 return True
217
218
218 parallel = Bool(False,
219 parallel = Bool(False,
219 help="whether to include parallel computing config files"
220 help="whether to include parallel computing config files"
220 ).tag(config=True)
221 ).tag(config=True)
221
222
222 @observe('parallel')
223 @observe('parallel')
223 def _parallel_changed(self, change):
224 def _parallel_changed(self, change):
224 parallel_files = [ 'ipcontroller_config.py',
225 parallel_files = [ 'ipcontroller_config.py',
225 'ipengine_config.py',
226 'ipengine_config.py',
226 'ipcluster_config.py'
227 'ipcluster_config.py'
227 ]
228 ]
228 if change['new']:
229 if change['new']:
229 for cf in parallel_files:
230 for cf in parallel_files:
230 self.config_files.append(cf)
231 self.config_files.append(cf)
231 else:
232 else:
232 for cf in parallel_files:
233 for cf in parallel_files:
233 if cf in self.config_files:
234 if cf in self.config_files:
234 self.config_files.remove(cf)
235 self.config_files.remove(cf)
235
236
236 def parse_command_line(self, argv):
237 def parse_command_line(self, argv):
237 super(ProfileCreate, self).parse_command_line(argv)
238 super(ProfileCreate, self).parse_command_line(argv)
238 # accept positional arg as profile name
239 # accept positional arg as profile name
239 if self.extra_args:
240 if self.extra_args:
240 self.profile = self.extra_args[0]
241 self.profile = self.extra_args[0]
241
242
242 flags = Dict(create_flags)
243 flags = Dict(create_flags)
243
244
244 classes = [ProfileDir]
245 classes = [ProfileDir]
245
246
246 def _import_app(self, app_path):
247 def _import_app(self, app_path):
247 """import an app class"""
248 """import an app class"""
248 app = None
249 app = None
249 name = app_path.rsplit('.', 1)[-1]
250 name = app_path.rsplit('.', 1)[-1]
250 try:
251 try:
251 app = import_item(app_path)
252 app = import_item(app_path)
252 except ImportError:
253 except ImportError:
253 self.log.info("Couldn't import %s, config file will be excluded", name)
254 self.log.info("Couldn't import %s, config file will be excluded", name)
254 except Exception:
255 except Exception:
255 self.log.warning('Unexpected error importing %s', name, exc_info=True)
256 self.log.warning('Unexpected error importing %s', name, exc_info=True)
256 return app
257 return app
257
258
258 def init_config_files(self):
259 def init_config_files(self):
259 super(ProfileCreate, self).init_config_files()
260 super(ProfileCreate, self).init_config_files()
260 # use local imports, since these classes may import from here
261 # use local imports, since these classes may import from here
261 from IPython.terminal.ipapp import TerminalIPythonApp
262 from IPython.terminal.ipapp import TerminalIPythonApp
262 apps = [TerminalIPythonApp]
263 apps = [TerminalIPythonApp]
263 for app_path in (
264 for app_path in (
264 'ipykernel.kernelapp.IPKernelApp',
265 'ipykernel.kernelapp.IPKernelApp',
265 ):
266 ):
266 app = self._import_app(app_path)
267 app = self._import_app(app_path)
267 if app is not None:
268 if app is not None:
268 apps.append(app)
269 apps.append(app)
269 if self.parallel:
270 if self.parallel:
270 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
271 from ipyparallel.apps.ipcontrollerapp import IPControllerApp
271 from ipyparallel.apps.ipengineapp import IPEngineApp
272 from ipyparallel.apps.ipengineapp import IPEngineApp
272 from ipyparallel.apps.ipclusterapp import IPClusterStart
273 from ipyparallel.apps.ipclusterapp import IPClusterStart
273 apps.extend([
274 apps.extend([
274 IPControllerApp,
275 IPControllerApp,
275 IPEngineApp,
276 IPEngineApp,
276 IPClusterStart,
277 IPClusterStart,
277 ])
278 ])
278 for App in apps:
279 for App in apps:
279 app = App()
280 app = App()
280 app.config.update(self.config)
281 app.config.update(self.config)
281 app.log = self.log
282 app.log = self.log
282 app.overwrite = self.overwrite
283 app.overwrite = self.overwrite
283 app.copy_config_files=True
284 app.copy_config_files=True
284 app.ipython_dir=self.ipython_dir
285 app.ipython_dir=self.ipython_dir
285 app.profile_dir=self.profile_dir
286 app.profile_dir=self.profile_dir
286 app.init_config_files()
287 app.init_config_files()
287
288
288 def stage_default_config_file(self):
289 def stage_default_config_file(self):
289 pass
290 pass
290
291
291
292
292 class ProfileApp(Application):
293 class ProfileApp(Application):
293 name = u'ipython profile'
294 name = u'ipython profile'
294 description = profile_help
295 description = profile_help
295 examples = _main_examples
296 examples = _main_examples
296
297
297 subcommands = Dict(dict(
298 subcommands = Dict(dict(
298 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
299 create = (ProfileCreate, ProfileCreate.description.splitlines()[0]),
299 list = (ProfileList, ProfileList.description.splitlines()[0]),
300 list = (ProfileList, ProfileList.description.splitlines()[0]),
300 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
301 locate = (ProfileLocate, ProfileLocate.description.splitlines()[0]),
301 ))
302 ))
302
303
303 def start(self):
304 def start(self):
304 if self.subapp is None:
305 if self.subapp is None:
305 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
306 print("No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()))
306 print()
307 print()
307 self.print_description()
308 self.print_description()
308 self.print_subcommands()
309 self.print_subcommands()
309 self.exit(1)
310 self.exit(1)
310 else:
311 else:
311 return self.subapp.start()
312 return self.subapp.start()
@@ -1,225 +1,225 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """An object for managing IPython profile directories."""
2 """An object for managing IPython profile directories."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import shutil
8 import shutil
9 import errno
9 import errno
10 from pathlib import Path
10 from pathlib import Path
11
11
12 from traitlets.config.configurable import LoggingConfigurable
12 from traitlets.config.configurable import LoggingConfigurable
13 from ..paths import get_ipython_package_dir
13 from ..paths import get_ipython_package_dir
14 from ..utils.path import expand_path, ensure_dir_exists
14 from ..utils.path import expand_path, ensure_dir_exists
15 from traitlets import Unicode, Bool, observe
15 from traitlets import Unicode, Bool, observe
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Module errors
18 # Module errors
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 class ProfileDirError(Exception):
21 class ProfileDirError(Exception):
22 pass
22 pass
23
23
24
24
25 #-----------------------------------------------------------------------------
25 #-----------------------------------------------------------------------------
26 # Class for managing profile directories
26 # Class for managing profile directories
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28
28
29 class ProfileDir(LoggingConfigurable):
29 class ProfileDir(LoggingConfigurable):
30 """An object to manage the profile directory and its resources.
30 """An object to manage the profile directory and its resources.
31
31
32 The profile directory is used by all IPython applications, to manage
32 The profile directory is used by all IPython applications, to manage
33 configuration, logging and security.
33 configuration, logging and security.
34
34
35 This object knows how to find, create and manage these directories. This
35 This object knows how to find, create and manage these directories. This
36 should be used by any code that wants to handle profiles.
36 should be used by any code that wants to handle profiles.
37 """
37 """
38
38
39 security_dir_name = Unicode('security')
39 security_dir_name = Unicode('security')
40 log_dir_name = Unicode('log')
40 log_dir_name = Unicode('log')
41 startup_dir_name = Unicode('startup')
41 startup_dir_name = Unicode('startup')
42 pid_dir_name = Unicode('pid')
42 pid_dir_name = Unicode('pid')
43 static_dir_name = Unicode('static')
43 static_dir_name = Unicode('static')
44 security_dir = Unicode(u'')
44 security_dir = Unicode(u'')
45 log_dir = Unicode(u'')
45 log_dir = Unicode(u'')
46 startup_dir = Unicode(u'')
46 startup_dir = Unicode(u'')
47 pid_dir = Unicode(u'')
47 pid_dir = Unicode(u'')
48 static_dir = Unicode(u'')
48 static_dir = Unicode(u'')
49
49
50 location = Unicode(u'',
50 location = Unicode(u'',
51 help="""Set the profile location directly. This overrides the logic used by the
51 help="""Set the profile location directly. This overrides the logic used by the
52 `profile` option.""",
52 `profile` option.""",
53 ).tag(config=True)
53 ).tag(config=True)
54
54
55 _location_isset = Bool(False) # flag for detecting multiply set location
55 _location_isset = Bool(False) # flag for detecting multiply set location
56 @observe('location')
56 @observe('location')
57 def _location_changed(self, change):
57 def _location_changed(self, change):
58 if self._location_isset:
58 if self._location_isset:
59 raise RuntimeError("Cannot set profile location more than once.")
59 raise RuntimeError("Cannot set profile location more than once.")
60 self._location_isset = True
60 self._location_isset = True
61 new = change['new']
61 new = change['new']
62 ensure_dir_exists(new)
62 ensure_dir_exists(new)
63
63
64 # ensure config files exist:
64 # ensure config files exist:
65 self.security_dir = os.path.join(new, self.security_dir_name)
65 self.security_dir = os.path.join(new, self.security_dir_name)
66 self.log_dir = os.path.join(new, self.log_dir_name)
66 self.log_dir = os.path.join(new, self.log_dir_name)
67 self.startup_dir = os.path.join(new, self.startup_dir_name)
67 self.startup_dir = os.path.join(new, self.startup_dir_name)
68 self.pid_dir = os.path.join(new, self.pid_dir_name)
68 self.pid_dir = os.path.join(new, self.pid_dir_name)
69 self.static_dir = os.path.join(new, self.static_dir_name)
69 self.static_dir = os.path.join(new, self.static_dir_name)
70 self.check_dirs()
70 self.check_dirs()
71
71
72 def _mkdir(self, path, mode=None):
72 def _mkdir(self, path, mode=None):
73 """ensure a directory exists at a given path
73 """ensure a directory exists at a given path
74
74
75 This is a version of os.mkdir, with the following differences:
75 This is a version of os.mkdir, with the following differences:
76
76
77 - returns True if it created the directory, False otherwise
77 - returns True if it created the directory, False otherwise
78 - ignores EEXIST, protecting against race conditions where
78 - ignores EEXIST, protecting against race conditions where
79 the dir may have been created in between the check and
79 the dir may have been created in between the check and
80 the creation
80 the creation
81 - sets permissions if requested and the dir already exists
81 - sets permissions if requested and the dir already exists
82 """
82 """
83 if os.path.exists(path):
83 if os.path.exists(path):
84 if mode and os.stat(path).st_mode != mode:
84 if mode and os.stat(path).st_mode != mode:
85 try:
85 try:
86 os.chmod(path, mode)
86 os.chmod(path, mode)
87 except OSError:
87 except OSError:
88 self.log.warning(
88 self.log.warning(
89 "Could not set permissions on %s",
89 "Could not set permissions on %s",
90 path
90 path
91 )
91 )
92 return False
92 return False
93 try:
93 try:
94 if mode:
94 if mode:
95 os.mkdir(path, mode)
95 os.mkdir(path, mode)
96 else:
96 else:
97 os.mkdir(path)
97 os.mkdir(path)
98 except OSError as e:
98 except OSError as e:
99 if e.errno == errno.EEXIST:
99 if e.errno == errno.EEXIST:
100 return False
100 return False
101 else:
101 else:
102 raise
102 raise
103
103
104 return True
104 return True
105
105
106 @observe('log_dir')
106 @observe('log_dir')
107 def check_log_dir(self, change=None):
107 def check_log_dir(self, change=None):
108 self._mkdir(self.log_dir)
108 self._mkdir(self.log_dir)
109
109
110 @observe('startup_dir')
110 @observe('startup_dir')
111 def check_startup_dir(self, change=None):
111 def check_startup_dir(self, change=None):
112 self._mkdir(self.startup_dir)
112 self._mkdir(self.startup_dir)
113
113
114 readme = os.path.join(self.startup_dir, 'README')
114 readme = os.path.join(self.startup_dir, 'README')
115 src = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'README_STARTUP')
115 src = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'README_STARTUP')
116
116
117 if not os.path.exists(src):
117 if not os.path.exists(src):
118 self.log.warning("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
118 self.log.warning("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
119
119
120 if os.path.exists(src) and not os.path.exists(readme):
120 if os.path.exists(src) and not os.path.exists(readme):
121 shutil.copy(src, readme)
121 shutil.copy(src, readme)
122
122
123 @observe('security_dir')
123 @observe('security_dir')
124 def check_security_dir(self, change=None):
124 def check_security_dir(self, change=None):
125 self._mkdir(self.security_dir, 0o40700)
125 self._mkdir(self.security_dir, 0o40700)
126
126
127 @observe('pid_dir')
127 @observe('pid_dir')
128 def check_pid_dir(self, change=None):
128 def check_pid_dir(self, change=None):
129 self._mkdir(self.pid_dir, 0o40700)
129 self._mkdir(self.pid_dir, 0o40700)
130
130
131 def check_dirs(self):
131 def check_dirs(self):
132 self.check_security_dir()
132 self.check_security_dir()
133 self.check_log_dir()
133 self.check_log_dir()
134 self.check_pid_dir()
134 self.check_pid_dir()
135 self.check_startup_dir()
135 self.check_startup_dir()
136
136
137 def copy_config_file(self, config_file: str, path: Path, overwrite=False) -> bool:
137 def copy_config_file(self, config_file: str, path: Path, overwrite=False) -> bool:
138 """Copy a default config file into the active profile directory.
138 """Copy a default config file into the active profile directory.
139
139
140 Default configuration files are kept in :mod:`IPython.core.profile`.
140 Default configuration files are kept in :mod:`IPython.core.profile`.
141 This function moves these from that location to the working profile
141 This function moves these from that location to the working profile
142 directory.
142 directory.
143 """
143 """
144 dst = Path(os.path.join(self.location, config_file))
144 dst = Path(os.path.join(self.location, config_file))
145 if dst.exists() and not overwrite:
145 if dst.exists() and not overwrite:
146 return False
146 return False
147 if path is None:
147 if path is None:
148 path = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'default')
148 path = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'default')
149 assert isinstance(path, Path)
149 assert isinstance(path, Path)
150 src = path / config_file
150 src = path / config_file
151 shutil.copy(src, dst)
151 shutil.copy(src, dst)
152 return True
152 return True
153
153
154 @classmethod
154 @classmethod
155 def create_profile_dir(cls, profile_dir, config=None):
155 def create_profile_dir(cls, profile_dir, config=None):
156 """Create a new profile directory given a full path.
156 """Create a new profile directory given a full path.
157
157
158 Parameters
158 Parameters
159 ----------
159 ----------
160 profile_dir : str
160 profile_dir : str
161 The full path to the profile directory. If it does exist, it will
161 The full path to the profile directory. If it does exist, it will
162 be used. If not, it will be created.
162 be used. If not, it will be created.
163 """
163 """
164 return cls(location=profile_dir, config=config)
164 return cls(location=profile_dir, config=config)
165
165
166 @classmethod
166 @classmethod
167 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
167 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
168 """Create a profile dir by profile name and path.
168 """Create a profile dir by profile name and path.
169
169
170 Parameters
170 Parameters
171 ----------
171 ----------
172 path : unicode
172 path : unicode
173 The path (directory) to put the profile directory in.
173 The path (directory) to put the profile directory in.
174 name : unicode
174 name : unicode
175 The name of the profile. The name of the profile directory will
175 The name of the profile. The name of the profile directory will
176 be "profile_<profile>".
176 be "profile_<profile>".
177 """
177 """
178 if not os.path.isdir(path):
178 if not os.path.isdir(path):
179 raise ProfileDirError('Directory not found: %s' % path)
179 raise ProfileDirError('Directory not found: %s' % path)
180 profile_dir = os.path.join(path, u'profile_' + name)
180 profile_dir = os.path.join(path, u'profile_' + name)
181 return cls(location=profile_dir, config=config)
181 return cls(location=profile_dir, config=config)
182
182
183 @classmethod
183 @classmethod
184 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
184 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
185 """Find an existing profile dir by profile name, return its ProfileDir.
185 """Find an existing profile dir by profile name, return its ProfileDir.
186
186
187 This searches through a sequence of paths for a profile dir. If it
187 This searches through a sequence of paths for a profile dir. If it
188 is not found, a :class:`ProfileDirError` exception will be raised.
188 is not found, a :class:`ProfileDirError` exception will be raised.
189
189
190 The search path algorithm is:
190 The search path algorithm is:
191 1. ``os.getcwd()``
191 1. ``os.getcwd()`` # removed for security reason.
192 2. ``ipython_dir``
192 2. ``ipython_dir``
193
193
194 Parameters
194 Parameters
195 ----------
195 ----------
196 ipython_dir : unicode or str
196 ipython_dir : unicode or str
197 The IPython directory to use.
197 The IPython directory to use.
198 name : unicode or str
198 name : unicode or str
199 The name of the profile. The name of the profile directory
199 The name of the profile. The name of the profile directory
200 will be "profile_<profile>".
200 will be "profile_<profile>".
201 """
201 """
202 dirname = u'profile_' + name
202 dirname = u'profile_' + name
203 paths = [os.getcwd(), ipython_dir]
203 paths = [ipython_dir]
204 for p in paths:
204 for p in paths:
205 profile_dir = os.path.join(p, dirname)
205 profile_dir = os.path.join(p, dirname)
206 if os.path.isdir(profile_dir):
206 if os.path.isdir(profile_dir):
207 return cls(location=profile_dir, config=config)
207 return cls(location=profile_dir, config=config)
208 else:
208 else:
209 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
209 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
210
210
211 @classmethod
211 @classmethod
212 def find_profile_dir(cls, profile_dir, config=None):
212 def find_profile_dir(cls, profile_dir, config=None):
213 """Find/create a profile dir and return its ProfileDir.
213 """Find/create a profile dir and return its ProfileDir.
214
214
215 This will create the profile directory if it doesn't exist.
215 This will create the profile directory if it doesn't exist.
216
216
217 Parameters
217 Parameters
218 ----------
218 ----------
219 profile_dir : unicode or str
219 profile_dir : unicode or str
220 The path of the profile directory.
220 The path of the profile directory.
221 """
221 """
222 profile_dir = expand_path(profile_dir)
222 profile_dir = expand_path(profile_dir)
223 if not os.path.isdir(profile_dir):
223 if not os.path.isdir(profile_dir):
224 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
224 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
225 return cls(location=profile_dir, config=config)
225 return cls(location=profile_dir, config=config)
@@ -1,897 +1,939 b''
1 ============
1 ============
2 8.x Series
2 8.x Series
3 ============
3 ============
4
4
5
6 IPython 8.0.1 (CVE-2022-21699)
7 ------------------------------
8
9 IPython 8.0.1, 7.31.1 and 5.11 are security releases that change some default
10 values in order to prevent potential Execution with Unnecessary Privileges.
11
12 Almost all version of IPython looks for configuration and profiles in current
13 working directory. Since IPython was developed before pip and environments
14 existed it was used a convenient way to load code/packages in a project
15 dependant way.
16
17 In 2022, it is not necessary anymore, and can lead to confusing behavior where
18 for example cloning a repository and starting IPython or loading a notebook from
19 any Jupyter-Compatible interface that has ipython set as a kernel can lead to
20 code execution.
21
22
23 I did not find any standard way for packaged to advertise CVEs they fix, I'm
24 thus trying to add a ``__patched_cves__`` attribute to the IPython module that
25 list the CVEs that should have been fixed. This attribute is informational only
26 as if a executable has a flaw, this value can always be changed by an attacker.
27
28 .. code::
29
30 In [1]: import IPython
31
32 In [2]: IPython.__patched_cves__
33 Out[2]: {'CVE-2022-21699'}
34
35 In [3]: 'CVE-2022-21699' in IPython.__patched_cves__
36 Out[3]: True
37
38 Thus starting with this version:
39
40 - The current working directory is not searched anymore for profiles or
41 configurations files.
42 - Added a ``__patched_cves__`` attribute (set of strings) to IPython module that contain
43 the list of fixed CVE. This is informational only.
44
45
46
5 IPython 8.0
47 IPython 8.0
6 -----------
48 -----------
7
49
8 IPython 8.0 is bringing a large number of new features and improvements to both the
50 IPython 8.0 is bringing a large number of new features and improvements to both the
9 user of the terminal and of the kernel via Jupyter. The removal of compatibility
51 user of the terminal and of the kernel via Jupyter. The removal of compatibility
10 with older version of Python is also the opportunity to do a couple of
52 with older version of Python is also the opportunity to do a couple of
11 performance improvement in particular with respect to startup time.
53 performance improvement in particular with respect to startup time.
12 The 8.x branch started diverging from its predecessor around IPython 7.12
54 The 8.x branch started diverging from its predecessor around IPython 7.12
13 (January 2020).
55 (January 2020).
14
56
15 This release contains 250+ pull requests, in addition to many of the features
57 This release contains 250+ pull requests, in addition to many of the features
16 and backports that have made it to the 7.x branch. Please see the
58 and backports that have made it to the 7.x branch. Please see the
17 `8.0 milestone <https://github.com/ipython/ipython/milestone/73?closed=1>`__ for the full list of pull requests.
59 `8.0 milestone <https://github.com/ipython/ipython/milestone/73?closed=1>`__ for the full list of pull requests.
18
60
19 Please fell free to send pull requests to updates those notes after release,
61 Please fell free to send pull requests to updates those notes after release,
20 I have likely forgotten a few things reviewing 250+ PRs.
62 I have likely forgotten a few things reviewing 250+ PRs.
21
63
22 Dependencies changes/downstream packaging
64 Dependencies changes/downstream packaging
23 -----------------------------------------
65 -----------------------------------------
24
66
25 Most of our building steps have been changed to be (mostly) declarative
67 Most of our building steps have been changed to be (mostly) declarative
26 and follow PEP 517. We are trying to completely remove ``setup.py`` (:ghpull:`13238`) and are
68 and follow PEP 517. We are trying to completely remove ``setup.py`` (:ghpull:`13238`) and are
27 looking for help to do so.
69 looking for help to do so.
28
70
29 - minimum supported ``traitlets`` version is now 5+
71 - minimum supported ``traitlets`` version is now 5+
30 - we now require ``stack_data``
72 - we now require ``stack_data``
31 - minimal Python is now 3.8
73 - minimal Python is now 3.8
32 - ``nose`` is not a testing requirement anymore
74 - ``nose`` is not a testing requirement anymore
33 - ``pytest`` replaces nose.
75 - ``pytest`` replaces nose.
34 - ``iptest``/``iptest3`` cli entrypoints do not exists anymore.
76 - ``iptest``/``iptest3`` cli entrypoints do not exists anymore.
35 - minimum officially support ``numpy`` version has been bumped, but this should
77 - minimum officially support ``numpy`` version has been bumped, but this should
36 not have much effect on packaging.
78 not have much effect on packaging.
37
79
38
80
39 Deprecation and removal
81 Deprecation and removal
40 -----------------------
82 -----------------------
41
83
42 We removed almost all features, arguments, functions, and modules that were
84 We removed almost all features, arguments, functions, and modules that were
43 marked as deprecated between IPython 1.0 and 5.0. As a reminder, 5.0 was released
85 marked as deprecated between IPython 1.0 and 5.0. As a reminder, 5.0 was released
44 in 2016, and 1.0 in 2013. Last release of the 5 branch was 5.10.0, in May 2020.
86 in 2016, and 1.0 in 2013. Last release of the 5 branch was 5.10.0, in May 2020.
45 The few remaining deprecated features we left have better deprecation warnings
87 The few remaining deprecated features we left have better deprecation warnings
46 or have been turned into explicit errors for better error messages.
88 or have been turned into explicit errors for better error messages.
47
89
48 I will use this occasion to add the following requests to anyone emitting a
90 I will use this occasion to add the following requests to anyone emitting a
49 deprecation warning:
91 deprecation warning:
50
92
51 - Please add at least ``stacklevel=2`` so that the warning is emitted into the
93 - Please add at least ``stacklevel=2`` so that the warning is emitted into the
52 caller context, and not the callee one.
94 caller context, and not the callee one.
53 - Please add **since which version** something is deprecated.
95 - Please add **since which version** something is deprecated.
54
96
55 As a side note, it is much easier to conditionally compare version
97 As a side note, it is much easier to conditionally compare version
56 numbers rather than using ``try/except`` when functionality changes with a version.
98 numbers rather than using ``try/except`` when functionality changes with a version.
57
99
58 I won't list all the removed features here, but modules like ``IPython.kernel``,
100 I won't list all the removed features here, but modules like ``IPython.kernel``,
59 which was just a shim module around ``ipykernel`` for the past 8 years, have been
101 which was just a shim module around ``ipykernel`` for the past 8 years, have been
60 removed, and so many other similar things that pre-date the name **Jupyter**
102 removed, and so many other similar things that pre-date the name **Jupyter**
61 itself.
103 itself.
62
104
63 We no longer need to add ``IPython.extensions`` to the PYTHONPATH because that is being
105 We no longer need to add ``IPython.extensions`` to the PYTHONPATH because that is being
64 handled by ``load_extension``.
106 handled by ``load_extension``.
65
107
66 We are also removing ``Cythonmagic``, ``sympyprinting`` and ``rmagic`` as they are now in
108 We are also removing ``Cythonmagic``, ``sympyprinting`` and ``rmagic`` as they are now in
67 other packages and no longer need to be inside IPython.
109 other packages and no longer need to be inside IPython.
68
110
69
111
70 Documentation
112 Documentation
71 -------------
113 -------------
72
114
73 The majority of our docstrings have now been reformatted and automatically fixed by
115 The majority of our docstrings have now been reformatted and automatically fixed by
74 the experimental `VΓ©lin <https://pypi.org/project/velin/>`_ project to conform
116 the experimental `VΓ©lin <https://pypi.org/project/velin/>`_ project to conform
75 to numpydoc.
117 to numpydoc.
76
118
77 Type annotations
119 Type annotations
78 ----------------
120 ----------------
79
121
80 While IPython itself is highly dynamic and can't be completely typed, many of
122 While IPython itself is highly dynamic and can't be completely typed, many of
81 the functions now have type annotations, and part of the codebase is now checked
123 the functions now have type annotations, and part of the codebase is now checked
82 by mypy.
124 by mypy.
83
125
84
126
85 Featured changes
127 Featured changes
86 ----------------
128 ----------------
87
129
88 Here is a features list of changes in IPython 8.0. This is of course non-exhaustive.
130 Here is a features list of changes in IPython 8.0. This is of course non-exhaustive.
89 Please note as well that many features have been added in the 7.x branch as well
131 Please note as well that many features have been added in the 7.x branch as well
90 (and hence why you want to read the 7.x what's new notes), in particular
132 (and hence why you want to read the 7.x what's new notes), in particular
91 features contributed by QuantStack (with respect to debugger protocol and Xeus
133 features contributed by QuantStack (with respect to debugger protocol and Xeus
92 Python), as well as many debugger features that I was pleased to implement as
134 Python), as well as many debugger features that I was pleased to implement as
93 part of my work at QuanSight and sponsored by DE Shaw.
135 part of my work at QuanSight and sponsored by DE Shaw.
94
136
95 Traceback improvements
137 Traceback improvements
96 ~~~~~~~~~~~~~~~~~~~~~~
138 ~~~~~~~~~~~~~~~~~~~~~~
97
139
98 Previously, error tracebacks for errors happening in code cells were showing a
140 Previously, error tracebacks for errors happening in code cells were showing a
99 hash, the one used for compiling the Python AST::
141 hash, the one used for compiling the Python AST::
100
142
101 In [1]: def foo():
143 In [1]: def foo():
102 ...: return 3 / 0
144 ...: return 3 / 0
103 ...:
145 ...:
104
146
105 In [2]: foo()
147 In [2]: foo()
106 ---------------------------------------------------------------------------
148 ---------------------------------------------------------------------------
107 ZeroDivisionError Traceback (most recent call last)
149 ZeroDivisionError Traceback (most recent call last)
108 <ipython-input-2-c19b6d9633cf> in <module>
150 <ipython-input-2-c19b6d9633cf> in <module>
109 ----> 1 foo()
151 ----> 1 foo()
110
152
111 <ipython-input-1-1595a74c32d5> in foo()
153 <ipython-input-1-1595a74c32d5> in foo()
112 1 def foo():
154 1 def foo():
113 ----> 2 return 3 / 0
155 ----> 2 return 3 / 0
114 3
156 3
115
157
116 ZeroDivisionError: division by zero
158 ZeroDivisionError: division by zero
117
159
118 The error traceback is now correctly formatted, showing the cell number in which the error happened::
160 The error traceback is now correctly formatted, showing the cell number in which the error happened::
119
161
120 In [1]: def foo():
162 In [1]: def foo():
121 ...: return 3 / 0
163 ...: return 3 / 0
122 ...:
164 ...:
123
165
124 Input In [2]: foo()
166 Input In [2]: foo()
125 ---------------------------------------------------------------------------
167 ---------------------------------------------------------------------------
126 ZeroDivisionError Traceback (most recent call last)
168 ZeroDivisionError Traceback (most recent call last)
127 input In [2], in <module>
169 input In [2], in <module>
128 ----> 1 foo()
170 ----> 1 foo()
129
171
130 Input In [1], in foo()
172 Input In [1], in foo()
131 1 def foo():
173 1 def foo():
132 ----> 2 return 3 / 0
174 ----> 2 return 3 / 0
133
175
134 ZeroDivisionError: division by zero
176 ZeroDivisionError: division by zero
135
177
136 The ``stack_data`` package has been integrated, which provides smarter information in the traceback;
178 The ``stack_data`` package has been integrated, which provides smarter information in the traceback;
137 in particular it will highlight the AST node where an error occurs which can help to quickly narrow down errors.
179 in particular it will highlight the AST node where an error occurs which can help to quickly narrow down errors.
138
180
139 For example in the following snippet::
181 For example in the following snippet::
140
182
141 def foo(i):
183 def foo(i):
142 x = [[[0]]]
184 x = [[[0]]]
143 return x[0][i][0]
185 return x[0][i][0]
144
186
145
187
146 def bar():
188 def bar():
147 return foo(0) + foo(
189 return foo(0) + foo(
148 1
190 1
149 ) + foo(2)
191 ) + foo(2)
150
192
151
193
152 calling ``bar()`` would raise an ``IndexError`` on the return line of ``foo``,
194 calling ``bar()`` would raise an ``IndexError`` on the return line of ``foo``,
153 and IPython 8.0 is capable of telling you where the index error occurs::
195 and IPython 8.0 is capable of telling you where the index error occurs::
154
196
155
197
156 IndexError
198 IndexError
157 Input In [2], in <module>
199 Input In [2], in <module>
158 ----> 1 bar()
200 ----> 1 bar()
159 ^^^^^
201 ^^^^^
160
202
161 Input In [1], in bar()
203 Input In [1], in bar()
162 6 def bar():
204 6 def bar():
163 ----> 7 return foo(0) + foo(
205 ----> 7 return foo(0) + foo(
164 ^^^^
206 ^^^^
165 8 1
207 8 1
166 ^^^^^^^^
208 ^^^^^^^^
167 9 ) + foo(2)
209 9 ) + foo(2)
168 ^^^^
210 ^^^^
169
211
170 Input In [1], in foo(i)
212 Input In [1], in foo(i)
171 1 def foo(i):
213 1 def foo(i):
172 2 x = [[[0]]]
214 2 x = [[[0]]]
173 ----> 3 return x[0][i][0]
215 ----> 3 return x[0][i][0]
174 ^^^^^^^
216 ^^^^^^^
175
217
176 The corresponding locations marked here with ``^`` will show up highlighted in
218 The corresponding locations marked here with ``^`` will show up highlighted in
177 the terminal and notebooks.
219 the terminal and notebooks.
178
220
179 Finally, a colon ``::`` and line number is appended after a filename in
221 Finally, a colon ``::`` and line number is appended after a filename in
180 traceback::
222 traceback::
181
223
182
224
183 ZeroDivisionError Traceback (most recent call last)
225 ZeroDivisionError Traceback (most recent call last)
184 File ~/error.py:4, in <module>
226 File ~/error.py:4, in <module>
185 1 def f():
227 1 def f():
186 2 1/0
228 2 1/0
187 ----> 4 f()
229 ----> 4 f()
188
230
189 File ~/error.py:2, in f()
231 File ~/error.py:2, in f()
190 1 def f():
232 1 def f():
191 ----> 2 1/0
233 ----> 2 1/0
192
234
193 Many terminals and editors have integrations enabling you to directly jump to the
235 Many terminals and editors have integrations enabling you to directly jump to the
194 relevant file/line when this syntax is used, so this small addition may have a high
236 relevant file/line when this syntax is used, so this small addition may have a high
195 impact on productivity.
237 impact on productivity.
196
238
197
239
198 Autosuggestions
240 Autosuggestions
199 ~~~~~~~~~~~~~~~
241 ~~~~~~~~~~~~~~~
200
242
201 Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__.
243 Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__.
202
244
203 `Ptpython <https://github.com/prompt-toolkit/ptpython#ptpython>`__ allows users to enable this feature in
245 `Ptpython <https://github.com/prompt-toolkit/ptpython#ptpython>`__ allows users to enable this feature in
204 `ptpython/config.py <https://github.com/prompt-toolkit/ptpython/blob/master/examples/ptpython_config/config.py#L90>`__.
246 `ptpython/config.py <https://github.com/prompt-toolkit/ptpython/blob/master/examples/ptpython_config/config.py#L90>`__.
205
247
206 This feature allows users to accept autosuggestions with ctrl e, ctrl f,
248 This feature allows users to accept autosuggestions with ctrl e, ctrl f,
207 or right arrow as described below.
249 or right arrow as described below.
208
250
209 1. Start ipython
251 1. Start ipython
210
252
211 .. image:: ../_images/8.0/auto_suggest_1_prompt_no_text.png
253 .. image:: ../_images/8.0/auto_suggest_1_prompt_no_text.png
212
254
213 2. Run ``print("hello")``
255 2. Run ``print("hello")``
214
256
215 .. image:: ../_images/8.0/auto_suggest_2_print_hello_suggest.png
257 .. image:: ../_images/8.0/auto_suggest_2_print_hello_suggest.png
216
258
217 3. start typing ``print`` again to see the autosuggestion
259 3. start typing ``print`` again to see the autosuggestion
218
260
219 .. image:: ../_images/8.0/auto_suggest_3_print_hello_suggest.png
261 .. image:: ../_images/8.0/auto_suggest_3_print_hello_suggest.png
220
262
221 4. Press ``ctrl-f``, or ``ctrl-e``, or ``right-arrow`` to accept the suggestion
263 4. Press ``ctrl-f``, or ``ctrl-e``, or ``right-arrow`` to accept the suggestion
222
264
223 .. image:: ../_images/8.0/auto_suggest_4_print_hello.png
265 .. image:: ../_images/8.0/auto_suggest_4_print_hello.png
224
266
225 You can also complete word by word:
267 You can also complete word by word:
226
268
227 1. Run ``def say_hello(): print("hello")``
269 1. Run ``def say_hello(): print("hello")``
228
270
229 .. image:: ../_images/8.0/auto_suggest_second_prompt.png
271 .. image:: ../_images/8.0/auto_suggest_second_prompt.png
230
272
231 2. Start typing the first letter if ``def`` to see the autosuggestion
273 2. Start typing the first letter if ``def`` to see the autosuggestion
232
274
233 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
275 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
234
276
235 3. Press ``alt-f`` (or ``escape`` followed by ``f``), to accept the first word of the suggestion
277 3. Press ``alt-f`` (or ``escape`` followed by ``f``), to accept the first word of the suggestion
236
278
237 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
279 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
238
280
239 Importantly, this feature does not interfere with tab completion:
281 Importantly, this feature does not interfere with tab completion:
240
282
241 1. After running ``def say_hello(): print("hello")``, press d
283 1. After running ``def say_hello(): print("hello")``, press d
242
284
243 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
285 .. image:: ../_images/8.0/auto_suggest_d_phantom.png
244
286
245 2. Press Tab to start tab completion
287 2. Press Tab to start tab completion
246
288
247 .. image:: ../_images/8.0/auto_suggest_d_completions.png
289 .. image:: ../_images/8.0/auto_suggest_d_completions.png
248
290
249 3A. Press Tab again to select the first option
291 3A. Press Tab again to select the first option
250
292
251 .. image:: ../_images/8.0/auto_suggest_def_completions.png
293 .. image:: ../_images/8.0/auto_suggest_def_completions.png
252
294
253 3B. Press ``alt f`` (``escape``, ``f``) to accept to accept the first word of the suggestion
295 3B. Press ``alt f`` (``escape``, ``f``) to accept to accept the first word of the suggestion
254
296
255 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
297 .. image:: ../_images/8.0/auto_suggest_def_phantom.png
256
298
257 3C. Press ``ctrl-f`` or ``ctrl-e`` to accept the entire suggestion
299 3C. Press ``ctrl-f`` or ``ctrl-e`` to accept the entire suggestion
258
300
259 .. image:: ../_images/8.0/auto_suggest_match_parens.png
301 .. image:: ../_images/8.0/auto_suggest_match_parens.png
260
302
261
303
262 Currently, autosuggestions are only shown in the emacs or vi insert editing modes:
304 Currently, autosuggestions are only shown in the emacs or vi insert editing modes:
263
305
264 - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode.
306 - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode.
265 - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__.
307 - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__.
266
308
267
309
268 Show pinfo information in ipdb using "?" and "??"
310 Show pinfo information in ipdb using "?" and "??"
269 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
270
312
271 In IPDB, it is now possible to show the information about an object using "?"
313 In IPDB, it is now possible to show the information about an object using "?"
272 and "??", in much the same way that it can be done when using the IPython prompt::
314 and "??", in much the same way that it can be done when using the IPython prompt::
273
315
274 ipdb> partial?
316 ipdb> partial?
275 Init signature: partial(self, /, *args, **kwargs)
317 Init signature: partial(self, /, *args, **kwargs)
276 Docstring:
318 Docstring:
277 partial(func, *args, **keywords) - new function with partial application
319 partial(func, *args, **keywords) - new function with partial application
278 of the given arguments and keywords.
320 of the given arguments and keywords.
279 File: ~/.pyenv/versions/3.8.6/lib/python3.8/functools.py
321 File: ~/.pyenv/versions/3.8.6/lib/python3.8/functools.py
280 Type: type
322 Type: type
281 Subclasses:
323 Subclasses:
282
324
283 Previously, ``pinfo`` or ``pinfo2`` command had to be used for this purpose.
325 Previously, ``pinfo`` or ``pinfo2`` command had to be used for this purpose.
284
326
285
327
286 Autoreload 3 feature
328 Autoreload 3 feature
287 ~~~~~~~~~~~~~~~~~~~~
329 ~~~~~~~~~~~~~~~~~~~~
288
330
289 Example: When an IPython session is run with the 'autoreload' extension loaded,
331 Example: When an IPython session is run with the 'autoreload' extension loaded,
290 you will now have the option '3' to select, which means the following:
332 you will now have the option '3' to select, which means the following:
291
333
292 1. replicate all functionality from option 2
334 1. replicate all functionality from option 2
293 2. autoload all new funcs/classes/enums/globals from the module when they are added
335 2. autoload all new funcs/classes/enums/globals from the module when they are added
294 3. autoload all newly imported funcs/classes/enums/globals from external modules
336 3. autoload all newly imported funcs/classes/enums/globals from external modules
295
337
296 Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload``.
338 Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload``.
297
339
298 For more information please see the following unit test : ``extensions/tests/test_autoreload.py:test_autoload_newly_added_objects``
340 For more information please see the following unit test : ``extensions/tests/test_autoreload.py:test_autoload_newly_added_objects``
299
341
300 Auto formatting with black in the CLI
342 Auto formatting with black in the CLI
301 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
343 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
302
344
303 If ``black`` is installed in the same environment as IPython, terminal IPython
345 If ``black`` is installed in the same environment as IPython, terminal IPython
304 will now *by default* reformat the code in the CLI when possible. You can
346 will now *by default* reformat the code in the CLI when possible. You can
305 disable this with ``--TerminalInteractiveShell.autoformatter=None``.
347 disable this with ``--TerminalInteractiveShell.autoformatter=None``.
306
348
307 This feature was present in 7.x, but disabled by default.
349 This feature was present in 7.x, but disabled by default.
308
350
309
351
310 History Range Glob feature
352 History Range Glob feature
311 ~~~~~~~~~~~~~~~~~~~~~~~~~~
353 ~~~~~~~~~~~~~~~~~~~~~~~~~~
312
354
313 Previously, when using ``%history``, users could specify either
355 Previously, when using ``%history``, users could specify either
314 a range of sessions and lines, for example:
356 a range of sessions and lines, for example:
315
357
316 .. code-block:: python
358 .. code-block:: python
317
359
318 ~8/1-~6/5 # see history from the first line of 8 sessions ago,
360 ~8/1-~6/5 # see history from the first line of 8 sessions ago,
319 # to the fifth line of 6 sessions ago.``
361 # to the fifth line of 6 sessions ago.``
320
362
321 Or users could specify a glob pattern:
363 Or users could specify a glob pattern:
322
364
323 .. code-block:: python
365 .. code-block:: python
324
366
325 -g <pattern> # glob ALL history for the specified pattern.
367 -g <pattern> # glob ALL history for the specified pattern.
326
368
327 However users could *not* specify both.
369 However users could *not* specify both.
328
370
329 If a user *did* specify both a range and a glob pattern,
371 If a user *did* specify both a range and a glob pattern,
330 then the glob pattern would be used (globbing *all* history) *and the range would be ignored*.
372 then the glob pattern would be used (globbing *all* history) *and the range would be ignored*.
331
373
332 With this enhancement, if a user specifies both a range and a glob pattern, then the glob pattern will be applied to the specified range of history.
374 With this enhancement, if a user specifies both a range and a glob pattern, then the glob pattern will be applied to the specified range of history.
333
375
334 Don't start a multi-line cell with sunken parenthesis
376 Don't start a multi-line cell with sunken parenthesis
335 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
377 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
336
378
337 From now on, IPython will not ask for the next line of input when given a single
379 From now on, IPython will not ask for the next line of input when given a single
338 line with more closing than opening brackets. For example, this means that if
380 line with more closing than opening brackets. For example, this means that if
339 you (mis)type ``]]`` instead of ``[]``, a ``SyntaxError`` will show up, instead of
381 you (mis)type ``]]`` instead of ``[]``, a ``SyntaxError`` will show up, instead of
340 the ``...:`` prompt continuation.
382 the ``...:`` prompt continuation.
341
383
342 IPython shell for ipdb interact
384 IPython shell for ipdb interact
343 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
385 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
344
386
345 The ipdb ``interact`` starts an IPython shell instead of Python's built-in ``code.interact()``.
387 The ipdb ``interact`` starts an IPython shell instead of Python's built-in ``code.interact()``.
346
388
347 Automatic Vi prompt stripping
389 Automatic Vi prompt stripping
348 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
390 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
349
391
350 When pasting code into IPython, it will strip the leading prompt characters if
392 When pasting code into IPython, it will strip the leading prompt characters if
351 there are any. For example, you can paste the following code into the console -
393 there are any. For example, you can paste the following code into the console -
352 it will still work, even though each line is prefixed with prompts (`In`,
394 it will still work, even though each line is prefixed with prompts (`In`,
353 `Out`)::
395 `Out`)::
354
396
355 In [1]: 2 * 2 == 4
397 In [1]: 2 * 2 == 4
356 Out[1]: True
398 Out[1]: True
357
399
358 In [2]: print("This still works as pasted")
400 In [2]: print("This still works as pasted")
359
401
360
402
361 Previously, this was not the case for the Vi-mode prompts::
403 Previously, this was not the case for the Vi-mode prompts::
362
404
363 In [1]: [ins] In [13]: 2 * 2 == 4
405 In [1]: [ins] In [13]: 2 * 2 == 4
364 ...: Out[13]: True
406 ...: Out[13]: True
365 ...:
407 ...:
366 File "<ipython-input-1-727bb88eaf33>", line 1
408 File "<ipython-input-1-727bb88eaf33>", line 1
367 [ins] In [13]: 2 * 2 == 4
409 [ins] In [13]: 2 * 2 == 4
368 ^
410 ^
369 SyntaxError: invalid syntax
411 SyntaxError: invalid syntax
370
412
371 This is now fixed, and Vi prompt prefixes - ``[ins]`` and ``[nav]`` - are
413 This is now fixed, and Vi prompt prefixes - ``[ins]`` and ``[nav]`` - are
372 skipped just as the normal ``In`` would be.
414 skipped just as the normal ``In`` would be.
373
415
374 IPython shell can be started in the Vi mode using ``ipython --TerminalInteractiveShell.editing_mode=vi``,
416 IPython shell can be started in the Vi mode using ``ipython --TerminalInteractiveShell.editing_mode=vi``,
375 You should be able to change mode dynamically with ``%config TerminalInteractiveShell.editing_mode='vi'``
417 You should be able to change mode dynamically with ``%config TerminalInteractiveShell.editing_mode='vi'``
376
418
377 Empty History Ranges
419 Empty History Ranges
378 ~~~~~~~~~~~~~~~~~~~~
420 ~~~~~~~~~~~~~~~~~~~~
379
421
380 A number of magics that take history ranges can now be used with an empty
422 A number of magics that take history ranges can now be used with an empty
381 range. These magics are:
423 range. These magics are:
382
424
383 * ``%save``
425 * ``%save``
384 * ``%load``
426 * ``%load``
385 * ``%pastebin``
427 * ``%pastebin``
386 * ``%pycat``
428 * ``%pycat``
387
429
388 Using them this way will make them take the history of the current session up
430 Using them this way will make them take the history of the current session up
389 to the point of the magic call (such that the magic itself will not be
431 to the point of the magic call (such that the magic itself will not be
390 included).
432 included).
391
433
392 Therefore it is now possible to save the whole history to a file using
434 Therefore it is now possible to save the whole history to a file using
393 ``%save <filename>``, load and edit it using ``%load`` (makes for a nice usage
435 ``%save <filename>``, load and edit it using ``%load`` (makes for a nice usage
394 when followed with :kbd:`F2`), send it to `dpaste.org <http://dpast.org>`_ using
436 when followed with :kbd:`F2`), send it to `dpaste.org <http://dpast.org>`_ using
395 ``%pastebin``, or view the whole thing syntax-highlighted with a single
437 ``%pastebin``, or view the whole thing syntax-highlighted with a single
396 ``%pycat``.
438 ``%pycat``.
397
439
398
440
399 Windows timing implementation: Switch to process_time
441 Windows timing implementation: Switch to process_time
400 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
442 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
401 Timing on Windows, for example with ``%%time``, was changed from being based on ``time.perf_counter``
443 Timing on Windows, for example with ``%%time``, was changed from being based on ``time.perf_counter``
402 (which counted time even when the process was sleeping) to being based on ``time.process_time`` instead
444 (which counted time even when the process was sleeping) to being based on ``time.process_time`` instead
403 (which only counts CPU time). This brings it closer to the behavior on Linux. See :ghpull:`12984`.
445 (which only counts CPU time). This brings it closer to the behavior on Linux. See :ghpull:`12984`.
404
446
405 Miscellaneous
447 Miscellaneous
406 ~~~~~~~~~~~~~
448 ~~~~~~~~~~~~~
407 - Non-text formatters are not disabled in the terminal, which should simplify
449 - Non-text formatters are not disabled in the terminal, which should simplify
408 writing extensions displaying images or other mimetypes in supporting terminals.
450 writing extensions displaying images or other mimetypes in supporting terminals.
409 :ghpull:`12315`
451 :ghpull:`12315`
410 - It is now possible to automatically insert matching brackets in Terminal IPython using the
452 - It is now possible to automatically insert matching brackets in Terminal IPython using the
411 ``TerminalInteractiveShell.auto_match=True`` option. :ghpull:`12586`
453 ``TerminalInteractiveShell.auto_match=True`` option. :ghpull:`12586`
412 - We are thinking of deprecating the current ``%%javascript`` magic in favor of a better replacement. See :ghpull:`13376`.
454 - We are thinking of deprecating the current ``%%javascript`` magic in favor of a better replacement. See :ghpull:`13376`.
413 - ``~`` is now expanded when part of a path in most magics :ghpull:`13385`
455 - ``~`` is now expanded when part of a path in most magics :ghpull:`13385`
414 - ``%/%%timeit`` magic now adds a comma every thousands to make reading a long number easier :ghpull:`13379`
456 - ``%/%%timeit`` magic now adds a comma every thousands to make reading a long number easier :ghpull:`13379`
415 - ``"info"`` messages can now be customised to hide some fields :ghpull:`13343`
457 - ``"info"`` messages can now be customised to hide some fields :ghpull:`13343`
416 - ``collections.UserList`` now pretty-prints :ghpull:`13320`
458 - ``collections.UserList`` now pretty-prints :ghpull:`13320`
417 - The debugger now has a persistent history, which should make it less
459 - The debugger now has a persistent history, which should make it less
418 annoying to retype commands :ghpull:`13246`
460 annoying to retype commands :ghpull:`13246`
419 - ``!pip`` ``!conda`` ``!cd`` or ``!ls`` are likely doing the wrong thing. We
461 - ``!pip`` ``!conda`` ``!cd`` or ``!ls`` are likely doing the wrong thing. We
420 now warn users if they use one of those commands. :ghpull:`12954`
462 now warn users if they use one of those commands. :ghpull:`12954`
421 - Make ``%precision`` work for ``numpy.float64`` type :ghpull:`12902`
463 - Make ``%precision`` work for ``numpy.float64`` type :ghpull:`12902`
422
464
423 Re-added support for XDG config directories
465 Re-added support for XDG config directories
424 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
425
467
426 XDG support through the years comes and goes. There is a tension between having
468 XDG support through the years comes and goes. There is a tension between having
427 an identical location for configuration in all platforms versus having simple instructions.
469 an identical location for configuration in all platforms versus having simple instructions.
428 After initial failures a couple of years ago, IPython was modified to automatically migrate XDG
470 After initial failures a couple of years ago, IPython was modified to automatically migrate XDG
429 config files back into ``~/.ipython``. That migration code has now been removed.
471 config files back into ``~/.ipython``. That migration code has now been removed.
430 IPython now checks the XDG locations, so if you _manually_ move your config
472 IPython now checks the XDG locations, so if you _manually_ move your config
431 files to your preferred location, IPython will not move them back.
473 files to your preferred location, IPython will not move them back.
432
474
433
475
434 Preparing for Python 3.10
476 Preparing for Python 3.10
435 -------------------------
477 -------------------------
436
478
437 To prepare for Python 3.10, we have started working on removing reliance and
479 To prepare for Python 3.10, we have started working on removing reliance and
438 any dependency that is not compatible with Python 3.10. This includes migrating our
480 any dependency that is not compatible with Python 3.10. This includes migrating our
439 test suite to pytest and starting to remove nose. This also means that the
481 test suite to pytest and starting to remove nose. This also means that the
440 ``iptest`` command is now gone and all testing is via pytest.
482 ``iptest`` command is now gone and all testing is via pytest.
441
483
442 This was in large part thanks to the NumFOCUS Small Developer grant, which enabled us to
484 This was in large part thanks to the NumFOCUS Small Developer grant, which enabled us to
443 allocate \$4000 to hire `Nikita Kniazev (@Kojoley) <https://github.com/Kojoley>`_,
485 allocate \$4000 to hire `Nikita Kniazev (@Kojoley) <https://github.com/Kojoley>`_,
444 who did a fantastic job at updating our code base, migrating to pytest, pushing
486 who did a fantastic job at updating our code base, migrating to pytest, pushing
445 our coverage, and fixing a large number of bugs. I highly recommend contacting
487 our coverage, and fixing a large number of bugs. I highly recommend contacting
446 them if you need help with C++ and Python projects.
488 them if you need help with C++ and Python projects.
447
489
448 You can find all relevant issues and PRs with the SDG 2021 tag `<https://github.com/ipython/ipython/issues?q=label%3A%22Numfocus+SDG+2021%22+>`__
490 You can find all relevant issues and PRs with the SDG 2021 tag `<https://github.com/ipython/ipython/issues?q=label%3A%22Numfocus+SDG+2021%22+>`__
449
491
450 Removing support for older Python versions
492 Removing support for older Python versions
451 ------------------------------------------
493 ------------------------------------------
452
494
453
495
454 We are removing support for Python up through 3.7, allowing internal code to use the more
496 We are removing support for Python up through 3.7, allowing internal code to use the more
455 efficient ``pathlib`` and to make better use of type annotations.
497 efficient ``pathlib`` and to make better use of type annotations.
456
498
457 .. image:: ../_images/8.0/pathlib_pathlib_everywhere.jpg
499 .. image:: ../_images/8.0/pathlib_pathlib_everywhere.jpg
458 :alt: "Meme image of Toy Story with Woody and Buzz, with the text 'pathlib, pathlib everywhere'"
500 :alt: "Meme image of Toy Story with Woody and Buzz, with the text 'pathlib, pathlib everywhere'"
459
501
460
502
461 We had about 34 PRs only to update some logic to update some functions from managing strings to
503 We had about 34 PRs only to update some logic to update some functions from managing strings to
462 using Pathlib.
504 using Pathlib.
463
505
464 The completer has also seen significant updates and now makes use of newer Jedi APIs,
506 The completer has also seen significant updates and now makes use of newer Jedi APIs,
465 offering faster and more reliable tab completion.
507 offering faster and more reliable tab completion.
466
508
467 Misc Statistics
509 Misc Statistics
468 ---------------
510 ---------------
469
511
470 Here are some numbers::
512 Here are some numbers::
471
513
472 7.x: 296 files, 12561 blank lines, 20282 comments, 35142 line of code.
514 7.x: 296 files, 12561 blank lines, 20282 comments, 35142 line of code.
473 8.0: 252 files, 12053 blank lines, 19232 comments, 34505 line of code.
515 8.0: 252 files, 12053 blank lines, 19232 comments, 34505 line of code.
474
516
475 $ git diff --stat 7.x...master | tail -1
517 $ git diff --stat 7.x...master | tail -1
476 340 files changed, 13399 insertions(+), 12421 deletions(-)
518 340 files changed, 13399 insertions(+), 12421 deletions(-)
477
519
478 We have commits from 162 authors, who contributed 1916 commits in 23 month, excluding merges (to not bias toward
520 We have commits from 162 authors, who contributed 1916 commits in 23 month, excluding merges (to not bias toward
479 maintainers pushing buttons).::
521 maintainers pushing buttons).::
480
522
481 $ git shortlog -s --no-merges 7.x...master | sort -nr
523 $ git shortlog -s --no-merges 7.x...master | sort -nr
482 535 Matthias Bussonnier
524 535 Matthias Bussonnier
483 86 Nikita Kniazev
525 86 Nikita Kniazev
484 69 Blazej Michalik
526 69 Blazej Michalik
485 49 Samuel Gaist
527 49 Samuel Gaist
486 27 Itamar Turner-Trauring
528 27 Itamar Turner-Trauring
487 18 Spas Kalaydzhisyki
529 18 Spas Kalaydzhisyki
488 17 Thomas Kluyver
530 17 Thomas Kluyver
489 17 Quentin Peter
531 17 Quentin Peter
490 17 James Morris
532 17 James Morris
491 17 Artur Svistunov
533 17 Artur Svistunov
492 15 Bart Skowron
534 15 Bart Skowron
493 14 Alex Hall
535 14 Alex Hall
494 13 rushabh-v
536 13 rushabh-v
495 13 Terry Davis
537 13 Terry Davis
496 13 Benjamin Ragan-Kelley
538 13 Benjamin Ragan-Kelley
497 8 martinRenou
539 8 martinRenou
498 8 farisachugthai
540 8 farisachugthai
499 7 dswij
541 7 dswij
500 7 Gal B
542 7 Gal B
501 7 Corentin Cadiou
543 7 Corentin Cadiou
502 6 yuji96
544 6 yuji96
503 6 Martin Skarzynski
545 6 Martin Skarzynski
504 6 Justin Palmer
546 6 Justin Palmer
505 6 Daniel Goldfarb
547 6 Daniel Goldfarb
506 6 Ben Greiner
548 6 Ben Greiner
507 5 Sammy Al Hashemi
549 5 Sammy Al Hashemi
508 5 Paul Ivanov
550 5 Paul Ivanov
509 5 Inception95
551 5 Inception95
510 5 Eyenpi
552 5 Eyenpi
511 5 Douglas Blank
553 5 Douglas Blank
512 5 Coco Mishra
554 5 Coco Mishra
513 5 Bibo Hao
555 5 Bibo Hao
514 5 AndrΓ© A. Gomes
556 5 AndrΓ© A. Gomes
515 5 Ahmed Fasih
557 5 Ahmed Fasih
516 4 takuya fujiwara
558 4 takuya fujiwara
517 4 palewire
559 4 palewire
518 4 Thomas A Caswell
560 4 Thomas A Caswell
519 4 Talley Lambert
561 4 Talley Lambert
520 4 Scott Sanderson
562 4 Scott Sanderson
521 4 Ram Rachum
563 4 Ram Rachum
522 4 Nick Muoh
564 4 Nick Muoh
523 4 Nathan Goldbaum
565 4 Nathan Goldbaum
524 4 Mithil Poojary
566 4 Mithil Poojary
525 4 Michael T
567 4 Michael T
526 4 Jakub Klus
568 4 Jakub Klus
527 4 Ian Castleden
569 4 Ian Castleden
528 4 Eli Rykoff
570 4 Eli Rykoff
529 4 Ashwin Vishnu
571 4 Ashwin Vishnu
530 3 谭九鼎
572 3 谭九鼎
531 3 sleeping
573 3 sleeping
532 3 Sylvain Corlay
574 3 Sylvain Corlay
533 3 Peter Corke
575 3 Peter Corke
534 3 Paul Bissex
576 3 Paul Bissex
535 3 Matthew Feickert
577 3 Matthew Feickert
536 3 Fernando Perez
578 3 Fernando Perez
537 3 Eric Wieser
579 3 Eric Wieser
538 3 Daniel Mietchen
580 3 Daniel Mietchen
539 3 Aditya Sathe
581 3 Aditya Sathe
540 3 007vedant
582 3 007vedant
541 2 rchiodo
583 2 rchiodo
542 2 nicolaslazo
584 2 nicolaslazo
543 2 luttik
585 2 luttik
544 2 gorogoroumaru
586 2 gorogoroumaru
545 2 foobarbyte
587 2 foobarbyte
546 2 bar-hen
588 2 bar-hen
547 2 Theo Ouzhinski
589 2 Theo Ouzhinski
548 2 Strawkage
590 2 Strawkage
549 2 Samreen Zarroug
591 2 Samreen Zarroug
550 2 Pete Blois
592 2 Pete Blois
551 2 Meysam Azad
593 2 Meysam Azad
552 2 Matthieu Ancellin
594 2 Matthieu Ancellin
553 2 Mark Schmitz
595 2 Mark Schmitz
554 2 Maor Kleinberger
596 2 Maor Kleinberger
555 2 MRCWirtz
597 2 MRCWirtz
556 2 Lumir Balhar
598 2 Lumir Balhar
557 2 Julien Rabinow
599 2 Julien Rabinow
558 2 Juan Luis Cano RodrΓ­guez
600 2 Juan Luis Cano RodrΓ­guez
559 2 Joyce Er
601 2 Joyce Er
560 2 Jakub
602 2 Jakub
561 2 Faris A Chugthai
603 2 Faris A Chugthai
562 2 Ethan Madden
604 2 Ethan Madden
563 2 Dimitri Papadopoulos
605 2 Dimitri Papadopoulos
564 2 Diego Fernandez
606 2 Diego Fernandez
565 2 Daniel Shimon
607 2 Daniel Shimon
566 2 Coco Bennett
608 2 Coco Bennett
567 2 Carlos Cordoba
609 2 Carlos Cordoba
568 2 Boyuan Liu
610 2 Boyuan Liu
569 2 BaoGiang HoangVu
611 2 BaoGiang HoangVu
570 2 Augusto
612 2 Augusto
571 2 Arthur Svistunov
613 2 Arthur Svistunov
572 2 Arthur Moreira
614 2 Arthur Moreira
573 2 Ali Nabipour
615 2 Ali Nabipour
574 2 Adam Hackbarth
616 2 Adam Hackbarth
575 1 richard
617 1 richard
576 1 linar-jether
618 1 linar-jether
577 1 lbennett
619 1 lbennett
578 1 juacrumar
620 1 juacrumar
579 1 gpotter2
621 1 gpotter2
580 1 digitalvirtuoso
622 1 digitalvirtuoso
581 1 dalthviz
623 1 dalthviz
582 1 Yonatan Goldschmidt
624 1 Yonatan Goldschmidt
583 1 Tomasz KΕ‚oczko
625 1 Tomasz KΕ‚oczko
584 1 Tobias Bengfort
626 1 Tobias Bengfort
585 1 Timur Kushukov
627 1 Timur Kushukov
586 1 Thomas
628 1 Thomas
587 1 Snir Broshi
629 1 Snir Broshi
588 1 Shao Yang Hong
630 1 Shao Yang Hong
589 1 Sanjana-03
631 1 Sanjana-03
590 1 Romulo Filho
632 1 Romulo Filho
591 1 Rodolfo Carvalho
633 1 Rodolfo Carvalho
592 1 Richard Shadrach
634 1 Richard Shadrach
593 1 Reilly Tucker Siemens
635 1 Reilly Tucker Siemens
594 1 Rakessh Roshan
636 1 Rakessh Roshan
595 1 Piers Titus van der Torren
637 1 Piers Titus van der Torren
596 1 PhanatosZou
638 1 PhanatosZou
597 1 Pavel Safronov
639 1 Pavel Safronov
598 1 Paulo S. Costa
640 1 Paulo S. Costa
599 1 Paul McCarthy
641 1 Paul McCarthy
600 1 NotWearingPants
642 1 NotWearingPants
601 1 Naelson Douglas
643 1 Naelson Douglas
602 1 Michael Tiemann
644 1 Michael Tiemann
603 1 Matt Wozniski
645 1 Matt Wozniski
604 1 Markus Wageringel
646 1 Markus Wageringel
605 1 Marcus Wirtz
647 1 Marcus Wirtz
606 1 Marcio Mazza
648 1 Marcio Mazza
607 1 LumΓ­r 'Frenzy' Balhar
649 1 LumΓ­r 'Frenzy' Balhar
608 1 Lightyagami1
650 1 Lightyagami1
609 1 Leon Anavi
651 1 Leon Anavi
610 1 LeafyLi
652 1 LeafyLi
611 1 L0uisJ0shua
653 1 L0uisJ0shua
612 1 Kyle Cutler
654 1 Kyle Cutler
613 1 Krzysztof Cybulski
655 1 Krzysztof Cybulski
614 1 Kevin Kirsche
656 1 Kevin Kirsche
615 1 KIU Shueng Chuan
657 1 KIU Shueng Chuan
616 1 Jonathan Slenders
658 1 Jonathan Slenders
617 1 Jay Qi
659 1 Jay Qi
618 1 Jake VanderPlas
660 1 Jake VanderPlas
619 1 Iwan Briquemont
661 1 Iwan Briquemont
620 1 Hussaina Begum Nandyala
662 1 Hussaina Begum Nandyala
621 1 Gordon Ball
663 1 Gordon Ball
622 1 Gabriel Simonetto
664 1 Gabriel Simonetto
623 1 Frank Tobia
665 1 Frank Tobia
624 1 Erik
666 1 Erik
625 1 Elliott Sales de Andrade
667 1 Elliott Sales de Andrade
626 1 Daniel Hahler
668 1 Daniel Hahler
627 1 Dan Green-Leipciger
669 1 Dan Green-Leipciger
628 1 Dan Green
670 1 Dan Green
629 1 Damian Yurzola
671 1 Damian Yurzola
630 1 Coon, Ethan T
672 1 Coon, Ethan T
631 1 Carol Willing
673 1 Carol Willing
632 1 Brian Lee
674 1 Brian Lee
633 1 Brendan Gerrity
675 1 Brendan Gerrity
634 1 Blake Griffin
676 1 Blake Griffin
635 1 Bastian Ebeling
677 1 Bastian Ebeling
636 1 Bartosz Telenczuk
678 1 Bartosz Telenczuk
637 1 Ankitsingh6299
679 1 Ankitsingh6299
638 1 Andrew Port
680 1 Andrew Port
639 1 Andrew J. Hesford
681 1 Andrew J. Hesford
640 1 Albert Zhang
682 1 Albert Zhang
641 1 Adam Johnson
683 1 Adam Johnson
642
684
643 This does not, of course, represent non-code contributions, for which we are also grateful.
685 This does not, of course, represent non-code contributions, for which we are also grateful.
644
686
645
687
646 API Changes using Frappuccino
688 API Changes using Frappuccino
647 -----------------------------
689 -----------------------------
648
690
649 This is an experimental exhaustive API difference using `Frappuccino <https://pypi.org/project/frappuccino/>`_
691 This is an experimental exhaustive API difference using `Frappuccino <https://pypi.org/project/frappuccino/>`_
650
692
651
693
652 The following items are new in IPython 8.0 ::
694 The following items are new in IPython 8.0 ::
653
695
654 + IPython.core.async_helpers.get_asyncio_loop()
696 + IPython.core.async_helpers.get_asyncio_loop()
655 + IPython.core.completer.Dict
697 + IPython.core.completer.Dict
656 + IPython.core.completer.Pattern
698 + IPython.core.completer.Pattern
657 + IPython.core.completer.Sequence
699 + IPython.core.completer.Sequence
658 + IPython.core.completer.__skip_doctest__
700 + IPython.core.completer.__skip_doctest__
659 + IPython.core.debugger.Pdb.precmd(self, line)
701 + IPython.core.debugger.Pdb.precmd(self, line)
660 + IPython.core.debugger.__skip_doctest__
702 + IPython.core.debugger.__skip_doctest__
661 + IPython.core.display.__getattr__(name)
703 + IPython.core.display.__getattr__(name)
662 + IPython.core.display.warn
704 + IPython.core.display.warn
663 + IPython.core.display_functions
705 + IPython.core.display_functions
664 + IPython.core.display_functions.DisplayHandle
706 + IPython.core.display_functions.DisplayHandle
665 + IPython.core.display_functions.DisplayHandle.display(self, obj, **kwargs)
707 + IPython.core.display_functions.DisplayHandle.display(self, obj, **kwargs)
666 + IPython.core.display_functions.DisplayHandle.update(self, obj, **kwargs)
708 + IPython.core.display_functions.DisplayHandle.update(self, obj, **kwargs)
667 + IPython.core.display_functions.__all__
709 + IPython.core.display_functions.__all__
668 + IPython.core.display_functions.__builtins__
710 + IPython.core.display_functions.__builtins__
669 + IPython.core.display_functions.__cached__
711 + IPython.core.display_functions.__cached__
670 + IPython.core.display_functions.__doc__
712 + IPython.core.display_functions.__doc__
671 + IPython.core.display_functions.__file__
713 + IPython.core.display_functions.__file__
672 + IPython.core.display_functions.__loader__
714 + IPython.core.display_functions.__loader__
673 + IPython.core.display_functions.__name__
715 + IPython.core.display_functions.__name__
674 + IPython.core.display_functions.__package__
716 + IPython.core.display_functions.__package__
675 + IPython.core.display_functions.__spec__
717 + IPython.core.display_functions.__spec__
676 + IPython.core.display_functions.b2a_hex
718 + IPython.core.display_functions.b2a_hex
677 + IPython.core.display_functions.clear_output(wait=False)
719 + IPython.core.display_functions.clear_output(wait=False)
678 + IPython.core.display_functions.display(*objs, include='None', exclude='None', metadata='None', transient='None', display_id='None', raw=False, clear=False, **kwargs)
720 + IPython.core.display_functions.display(*objs, include='None', exclude='None', metadata='None', transient='None', display_id='None', raw=False, clear=False, **kwargs)
679 + IPython.core.display_functions.publish_display_data(data, metadata='None', source='<deprecated>', *, transient='None', **kwargs)
721 + IPython.core.display_functions.publish_display_data(data, metadata='None', source='<deprecated>', *, transient='None', **kwargs)
680 + IPython.core.display_functions.update_display(obj, *, display_id, **kwargs)
722 + IPython.core.display_functions.update_display(obj, *, display_id, **kwargs)
681 + IPython.core.extensions.BUILTINS_EXTS
723 + IPython.core.extensions.BUILTINS_EXTS
682 + IPython.core.inputtransformer2.has_sunken_brackets(tokens)
724 + IPython.core.inputtransformer2.has_sunken_brackets(tokens)
683 + IPython.core.interactiveshell.Callable
725 + IPython.core.interactiveshell.Callable
684 + IPython.core.interactiveshell.__annotations__
726 + IPython.core.interactiveshell.__annotations__
685 + IPython.core.ultratb.List
727 + IPython.core.ultratb.List
686 + IPython.core.ultratb.Tuple
728 + IPython.core.ultratb.Tuple
687 + IPython.lib.pretty.CallExpression
729 + IPython.lib.pretty.CallExpression
688 + IPython.lib.pretty.CallExpression.factory(name)
730 + IPython.lib.pretty.CallExpression.factory(name)
689 + IPython.lib.pretty.RawStringLiteral
731 + IPython.lib.pretty.RawStringLiteral
690 + IPython.lib.pretty.RawText
732 + IPython.lib.pretty.RawText
691 + IPython.terminal.debugger.TerminalPdb.do_interact(self, arg)
733 + IPython.terminal.debugger.TerminalPdb.do_interact(self, arg)
692 + IPython.terminal.embed.Set
734 + IPython.terminal.embed.Set
693
735
694 The following items have been removed (or moved to superclass)::
736 The following items have been removed (or moved to superclass)::
695
737
696 - IPython.core.application.BaseIPythonApplication.initialize_subcommand
738 - IPython.core.application.BaseIPythonApplication.initialize_subcommand
697 - IPython.core.completer.Sentinel
739 - IPython.core.completer.Sentinel
698 - IPython.core.completer.skip_doctest
740 - IPython.core.completer.skip_doctest
699 - IPython.core.debugger.Tracer
741 - IPython.core.debugger.Tracer
700 - IPython.core.display.DisplayHandle
742 - IPython.core.display.DisplayHandle
701 - IPython.core.display.DisplayHandle.display
743 - IPython.core.display.DisplayHandle.display
702 - IPython.core.display.DisplayHandle.update
744 - IPython.core.display.DisplayHandle.update
703 - IPython.core.display.b2a_hex
745 - IPython.core.display.b2a_hex
704 - IPython.core.display.clear_output
746 - IPython.core.display.clear_output
705 - IPython.core.display.display
747 - IPython.core.display.display
706 - IPython.core.display.publish_display_data
748 - IPython.core.display.publish_display_data
707 - IPython.core.display.update_display
749 - IPython.core.display.update_display
708 - IPython.core.excolors.Deprec
750 - IPython.core.excolors.Deprec
709 - IPython.core.excolors.ExceptionColors
751 - IPython.core.excolors.ExceptionColors
710 - IPython.core.history.warn
752 - IPython.core.history.warn
711 - IPython.core.hooks.late_startup_hook
753 - IPython.core.hooks.late_startup_hook
712 - IPython.core.hooks.pre_run_code_hook
754 - IPython.core.hooks.pre_run_code_hook
713 - IPython.core.hooks.shutdown_hook
755 - IPython.core.hooks.shutdown_hook
714 - IPython.core.interactiveshell.InteractiveShell.init_deprecation_warnings
756 - IPython.core.interactiveshell.InteractiveShell.init_deprecation_warnings
715 - IPython.core.interactiveshell.InteractiveShell.init_readline
757 - IPython.core.interactiveshell.InteractiveShell.init_readline
716 - IPython.core.interactiveshell.InteractiveShell.write
758 - IPython.core.interactiveshell.InteractiveShell.write
717 - IPython.core.interactiveshell.InteractiveShell.write_err
759 - IPython.core.interactiveshell.InteractiveShell.write_err
718 - IPython.core.interactiveshell.get_default_colors
760 - IPython.core.interactiveshell.get_default_colors
719 - IPython.core.interactiveshell.removed_co_newlocals
761 - IPython.core.interactiveshell.removed_co_newlocals
720 - IPython.core.magics.execution.ExecutionMagics.profile_missing_notice
762 - IPython.core.magics.execution.ExecutionMagics.profile_missing_notice
721 - IPython.core.magics.script.PIPE
763 - IPython.core.magics.script.PIPE
722 - IPython.core.prefilter.PrefilterManager.init_transformers
764 - IPython.core.prefilter.PrefilterManager.init_transformers
723 - IPython.core.release.classifiers
765 - IPython.core.release.classifiers
724 - IPython.core.release.description
766 - IPython.core.release.description
725 - IPython.core.release.keywords
767 - IPython.core.release.keywords
726 - IPython.core.release.long_description
768 - IPython.core.release.long_description
727 - IPython.core.release.name
769 - IPython.core.release.name
728 - IPython.core.release.platforms
770 - IPython.core.release.platforms
729 - IPython.core.release.url
771 - IPython.core.release.url
730 - IPython.core.ultratb.VerboseTB.format_records
772 - IPython.core.ultratb.VerboseTB.format_records
731 - IPython.core.ultratb.find_recursion
773 - IPython.core.ultratb.find_recursion
732 - IPython.core.ultratb.findsource
774 - IPython.core.ultratb.findsource
733 - IPython.core.ultratb.fix_frame_records_filenames
775 - IPython.core.ultratb.fix_frame_records_filenames
734 - IPython.core.ultratb.inspect_error
776 - IPython.core.ultratb.inspect_error
735 - IPython.core.ultratb.is_recursion_error
777 - IPython.core.ultratb.is_recursion_error
736 - IPython.core.ultratb.with_patch_inspect
778 - IPython.core.ultratb.with_patch_inspect
737 - IPython.external.__all__
779 - IPython.external.__all__
738 - IPython.external.__builtins__
780 - IPython.external.__builtins__
739 - IPython.external.__cached__
781 - IPython.external.__cached__
740 - IPython.external.__doc__
782 - IPython.external.__doc__
741 - IPython.external.__file__
783 - IPython.external.__file__
742 - IPython.external.__loader__
784 - IPython.external.__loader__
743 - IPython.external.__name__
785 - IPython.external.__name__
744 - IPython.external.__package__
786 - IPython.external.__package__
745 - IPython.external.__path__
787 - IPython.external.__path__
746 - IPython.external.__spec__
788 - IPython.external.__spec__
747 - IPython.kernel.KernelConnectionInfo
789 - IPython.kernel.KernelConnectionInfo
748 - IPython.kernel.__builtins__
790 - IPython.kernel.__builtins__
749 - IPython.kernel.__cached__
791 - IPython.kernel.__cached__
750 - IPython.kernel.__warningregistry__
792 - IPython.kernel.__warningregistry__
751 - IPython.kernel.pkg
793 - IPython.kernel.pkg
752 - IPython.kernel.protocol_version
794 - IPython.kernel.protocol_version
753 - IPython.kernel.protocol_version_info
795 - IPython.kernel.protocol_version_info
754 - IPython.kernel.src
796 - IPython.kernel.src
755 - IPython.kernel.version_info
797 - IPython.kernel.version_info
756 - IPython.kernel.warn
798 - IPython.kernel.warn
757 - IPython.lib.backgroundjobs
799 - IPython.lib.backgroundjobs
758 - IPython.lib.backgroundjobs.BackgroundJobBase
800 - IPython.lib.backgroundjobs.BackgroundJobBase
759 - IPython.lib.backgroundjobs.BackgroundJobBase.run
801 - IPython.lib.backgroundjobs.BackgroundJobBase.run
760 - IPython.lib.backgroundjobs.BackgroundJobBase.traceback
802 - IPython.lib.backgroundjobs.BackgroundJobBase.traceback
761 - IPython.lib.backgroundjobs.BackgroundJobExpr
803 - IPython.lib.backgroundjobs.BackgroundJobExpr
762 - IPython.lib.backgroundjobs.BackgroundJobExpr.call
804 - IPython.lib.backgroundjobs.BackgroundJobExpr.call
763 - IPython.lib.backgroundjobs.BackgroundJobFunc
805 - IPython.lib.backgroundjobs.BackgroundJobFunc
764 - IPython.lib.backgroundjobs.BackgroundJobFunc.call
806 - IPython.lib.backgroundjobs.BackgroundJobFunc.call
765 - IPython.lib.backgroundjobs.BackgroundJobManager
807 - IPython.lib.backgroundjobs.BackgroundJobManager
766 - IPython.lib.backgroundjobs.BackgroundJobManager.flush
808 - IPython.lib.backgroundjobs.BackgroundJobManager.flush
767 - IPython.lib.backgroundjobs.BackgroundJobManager.new
809 - IPython.lib.backgroundjobs.BackgroundJobManager.new
768 - IPython.lib.backgroundjobs.BackgroundJobManager.remove
810 - IPython.lib.backgroundjobs.BackgroundJobManager.remove
769 - IPython.lib.backgroundjobs.BackgroundJobManager.result
811 - IPython.lib.backgroundjobs.BackgroundJobManager.result
770 - IPython.lib.backgroundjobs.BackgroundJobManager.status
812 - IPython.lib.backgroundjobs.BackgroundJobManager.status
771 - IPython.lib.backgroundjobs.BackgroundJobManager.traceback
813 - IPython.lib.backgroundjobs.BackgroundJobManager.traceback
772 - IPython.lib.backgroundjobs.__builtins__
814 - IPython.lib.backgroundjobs.__builtins__
773 - IPython.lib.backgroundjobs.__cached__
815 - IPython.lib.backgroundjobs.__cached__
774 - IPython.lib.backgroundjobs.__doc__
816 - IPython.lib.backgroundjobs.__doc__
775 - IPython.lib.backgroundjobs.__file__
817 - IPython.lib.backgroundjobs.__file__
776 - IPython.lib.backgroundjobs.__loader__
818 - IPython.lib.backgroundjobs.__loader__
777 - IPython.lib.backgroundjobs.__name__
819 - IPython.lib.backgroundjobs.__name__
778 - IPython.lib.backgroundjobs.__package__
820 - IPython.lib.backgroundjobs.__package__
779 - IPython.lib.backgroundjobs.__spec__
821 - IPython.lib.backgroundjobs.__spec__
780 - IPython.lib.kernel.__builtins__
822 - IPython.lib.kernel.__builtins__
781 - IPython.lib.kernel.__cached__
823 - IPython.lib.kernel.__cached__
782 - IPython.lib.kernel.__doc__
824 - IPython.lib.kernel.__doc__
783 - IPython.lib.kernel.__file__
825 - IPython.lib.kernel.__file__
784 - IPython.lib.kernel.__loader__
826 - IPython.lib.kernel.__loader__
785 - IPython.lib.kernel.__name__
827 - IPython.lib.kernel.__name__
786 - IPython.lib.kernel.__package__
828 - IPython.lib.kernel.__package__
787 - IPython.lib.kernel.__spec__
829 - IPython.lib.kernel.__spec__
788 - IPython.lib.kernel.__warningregistry__
830 - IPython.lib.kernel.__warningregistry__
789 - IPython.paths.fs_encoding
831 - IPython.paths.fs_encoding
790 - IPython.terminal.debugger.DEFAULT_BUFFER
832 - IPython.terminal.debugger.DEFAULT_BUFFER
791 - IPython.terminal.debugger.cursor_in_leading_ws
833 - IPython.terminal.debugger.cursor_in_leading_ws
792 - IPython.terminal.debugger.emacs_insert_mode
834 - IPython.terminal.debugger.emacs_insert_mode
793 - IPython.terminal.debugger.has_selection
835 - IPython.terminal.debugger.has_selection
794 - IPython.terminal.debugger.vi_insert_mode
836 - IPython.terminal.debugger.vi_insert_mode
795 - IPython.terminal.interactiveshell.DISPLAY_BANNER_DEPRECATED
837 - IPython.terminal.interactiveshell.DISPLAY_BANNER_DEPRECATED
796 - IPython.terminal.ipapp.TerminalIPythonApp.parse_command_line
838 - IPython.terminal.ipapp.TerminalIPythonApp.parse_command_line
797 - IPython.testing.test
839 - IPython.testing.test
798 - IPython.utils.contexts.NoOpContext
840 - IPython.utils.contexts.NoOpContext
799 - IPython.utils.io.IOStream
841 - IPython.utils.io.IOStream
800 - IPython.utils.io.IOStream.close
842 - IPython.utils.io.IOStream.close
801 - IPython.utils.io.IOStream.write
843 - IPython.utils.io.IOStream.write
802 - IPython.utils.io.IOStream.writelines
844 - IPython.utils.io.IOStream.writelines
803 - IPython.utils.io.__warningregistry__
845 - IPython.utils.io.__warningregistry__
804 - IPython.utils.io.atomic_writing
846 - IPython.utils.io.atomic_writing
805 - IPython.utils.io.stderr
847 - IPython.utils.io.stderr
806 - IPython.utils.io.stdin
848 - IPython.utils.io.stdin
807 - IPython.utils.io.stdout
849 - IPython.utils.io.stdout
808 - IPython.utils.io.unicode_std_stream
850 - IPython.utils.io.unicode_std_stream
809 - IPython.utils.path.get_ipython_cache_dir
851 - IPython.utils.path.get_ipython_cache_dir
810 - IPython.utils.path.get_ipython_dir
852 - IPython.utils.path.get_ipython_dir
811 - IPython.utils.path.get_ipython_module_path
853 - IPython.utils.path.get_ipython_module_path
812 - IPython.utils.path.get_ipython_package_dir
854 - IPython.utils.path.get_ipython_package_dir
813 - IPython.utils.path.locate_profile
855 - IPython.utils.path.locate_profile
814 - IPython.utils.path.unquote_filename
856 - IPython.utils.path.unquote_filename
815 - IPython.utils.py3compat.PY2
857 - IPython.utils.py3compat.PY2
816 - IPython.utils.py3compat.PY3
858 - IPython.utils.py3compat.PY3
817 - IPython.utils.py3compat.buffer_to_bytes
859 - IPython.utils.py3compat.buffer_to_bytes
818 - IPython.utils.py3compat.builtin_mod_name
860 - IPython.utils.py3compat.builtin_mod_name
819 - IPython.utils.py3compat.cast_bytes
861 - IPython.utils.py3compat.cast_bytes
820 - IPython.utils.py3compat.getcwd
862 - IPython.utils.py3compat.getcwd
821 - IPython.utils.py3compat.isidentifier
863 - IPython.utils.py3compat.isidentifier
822 - IPython.utils.py3compat.u_format
864 - IPython.utils.py3compat.u_format
823
865
824 The following signatures differ between 7.x and 8.0::
866 The following signatures differ between 7.x and 8.0::
825
867
826 - IPython.core.completer.IPCompleter.unicode_name_matches(self, text)
868 - IPython.core.completer.IPCompleter.unicode_name_matches(self, text)
827 + IPython.core.completer.IPCompleter.unicode_name_matches(text)
869 + IPython.core.completer.IPCompleter.unicode_name_matches(text)
828
870
829 - IPython.core.completer.match_dict_keys(keys, prefix, delims)
871 - IPython.core.completer.match_dict_keys(keys, prefix, delims)
830 + IPython.core.completer.match_dict_keys(keys, prefix, delims, extra_prefix='None')
872 + IPython.core.completer.match_dict_keys(keys, prefix, delims, extra_prefix='None')
831
873
832 - IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0)
874 - IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0)
833 + IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0, omit_sections='()')
875 + IPython.core.interactiveshell.InteractiveShell.object_inspect_mime(self, oname, detail_level=0, omit_sections='()')
834
876
835 - IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None', _warn_deprecated=True)
877 - IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None', _warn_deprecated=True)
836 + IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None')
878 + IPython.core.interactiveshell.InteractiveShell.set_hook(self, name, hook, priority=50, str_key='None', re_key='None')
837
879
838 - IPython.core.oinspect.Inspector.info(self, obj, oname='', formatter='None', info='None', detail_level=0)
880 - IPython.core.oinspect.Inspector.info(self, obj, oname='', formatter='None', info='None', detail_level=0)
839 + IPython.core.oinspect.Inspector.info(self, obj, oname='', info='None', detail_level=0)
881 + IPython.core.oinspect.Inspector.info(self, obj, oname='', info='None', detail_level=0)
840
882
841 - IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True)
883 - IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True)
842 + IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True, omit_sections='()')
884 + IPython.core.oinspect.Inspector.pinfo(self, obj, oname='', formatter='None', info='None', detail_level=0, enable_html_pager=True, omit_sections='()')
843
885
844 - IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path='None', overwrite=False)
886 - IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path='None', overwrite=False)
845 + IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path, overwrite=False)
887 + IPython.core.profiledir.ProfileDir.copy_config_file(self, config_file, path, overwrite=False)
846
888
847 - IPython.core.ultratb.VerboseTB.format_record(self, frame, file, lnum, func, lines, index)
889 - IPython.core.ultratb.VerboseTB.format_record(self, frame, file, lnum, func, lines, index)
848 + IPython.core.ultratb.VerboseTB.format_record(self, frame_info)
890 + IPython.core.ultratb.VerboseTB.format_record(self, frame_info)
849
891
850 - IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, display_banner='None', global_ns='None', compile_flags='None')
892 - IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, display_banner='None', global_ns='None', compile_flags='None')
851 + IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, compile_flags='None')
893 + IPython.terminal.embed.InteractiveShellEmbed.mainloop(self, local_ns='None', module='None', stack_depth=0, compile_flags='None')
852
894
853 - IPython.terminal.embed.embed(**kwargs)
895 - IPython.terminal.embed.embed(**kwargs)
854 + IPython.terminal.embed.embed(*, header='', compile_flags='None', **kwargs)
896 + IPython.terminal.embed.embed(*, header='', compile_flags='None', **kwargs)
855
897
856 - IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self, display_banner='<object object at 0xffffff>')
898 - IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self, display_banner='<object object at 0xffffff>')
857 + IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self)
899 + IPython.terminal.interactiveshell.TerminalInteractiveShell.interact(self)
858
900
859 - IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self, display_banner='<object object at 0xffffff>')
901 - IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self, display_banner='<object object at 0xffffff>')
860 + IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self)
902 + IPython.terminal.interactiveshell.TerminalInteractiveShell.mainloop(self)
861
903
862 - IPython.utils.path.get_py_filename(name, force_win32='None')
904 - IPython.utils.path.get_py_filename(name, force_win32='None')
863 + IPython.utils.path.get_py_filename(name)
905 + IPython.utils.path.get_py_filename(name)
864
906
865 The following are new attributes (that might be inherited)::
907 The following are new attributes (that might be inherited)::
866
908
867 + IPython.core.completer.IPCompleter.unicode_names
909 + IPython.core.completer.IPCompleter.unicode_names
868 + IPython.core.debugger.InterruptiblePdb.precmd
910 + IPython.core.debugger.InterruptiblePdb.precmd
869 + IPython.core.debugger.Pdb.precmd
911 + IPython.core.debugger.Pdb.precmd
870 + IPython.core.ultratb.AutoFormattedTB.has_colors
912 + IPython.core.ultratb.AutoFormattedTB.has_colors
871 + IPython.core.ultratb.ColorTB.has_colors
913 + IPython.core.ultratb.ColorTB.has_colors
872 + IPython.core.ultratb.FormattedTB.has_colors
914 + IPython.core.ultratb.FormattedTB.has_colors
873 + IPython.core.ultratb.ListTB.has_colors
915 + IPython.core.ultratb.ListTB.has_colors
874 + IPython.core.ultratb.SyntaxTB.has_colors
916 + IPython.core.ultratb.SyntaxTB.has_colors
875 + IPython.core.ultratb.TBTools.has_colors
917 + IPython.core.ultratb.TBTools.has_colors
876 + IPython.core.ultratb.VerboseTB.has_colors
918 + IPython.core.ultratb.VerboseTB.has_colors
877 + IPython.terminal.debugger.TerminalPdb.do_interact
919 + IPython.terminal.debugger.TerminalPdb.do_interact
878 + IPython.terminal.debugger.TerminalPdb.precmd
920 + IPython.terminal.debugger.TerminalPdb.precmd
879
921
880 The following attribute/methods have been removed::
922 The following attribute/methods have been removed::
881
923
882 - IPython.core.application.BaseIPythonApplication.deprecated_subcommands
924 - IPython.core.application.BaseIPythonApplication.deprecated_subcommands
883 - IPython.core.ultratb.AutoFormattedTB.format_records
925 - IPython.core.ultratb.AutoFormattedTB.format_records
884 - IPython.core.ultratb.ColorTB.format_records
926 - IPython.core.ultratb.ColorTB.format_records
885 - IPython.core.ultratb.FormattedTB.format_records
927 - IPython.core.ultratb.FormattedTB.format_records
886 - IPython.terminal.embed.InteractiveShellEmbed.init_deprecation_warnings
928 - IPython.terminal.embed.InteractiveShellEmbed.init_deprecation_warnings
887 - IPython.terminal.embed.InteractiveShellEmbed.init_readline
929 - IPython.terminal.embed.InteractiveShellEmbed.init_readline
888 - IPython.terminal.embed.InteractiveShellEmbed.write
930 - IPython.terminal.embed.InteractiveShellEmbed.write
889 - IPython.terminal.embed.InteractiveShellEmbed.write_err
931 - IPython.terminal.embed.InteractiveShellEmbed.write_err
890 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_deprecation_warnings
932 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_deprecation_warnings
891 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_readline
933 - IPython.terminal.interactiveshell.TerminalInteractiveShell.init_readline
892 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write
934 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write
893 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write_err
935 - IPython.terminal.interactiveshell.TerminalInteractiveShell.write_err
894 - IPython.terminal.ipapp.LocateIPythonApp.deprecated_subcommands
936 - IPython.terminal.ipapp.LocateIPythonApp.deprecated_subcommands
895 - IPython.terminal.ipapp.LocateIPythonApp.initialize_subcommand
937 - IPython.terminal.ipapp.LocateIPythonApp.initialize_subcommand
896 - IPython.terminal.ipapp.TerminalIPythonApp.deprecated_subcommands
938 - IPython.terminal.ipapp.TerminalIPythonApp.deprecated_subcommands
897 - IPython.terminal.ipapp.TerminalIPythonApp.initialize_subcommand
939 - IPython.terminal.ipapp.TerminalIPythonApp.initialize_subcommand
General Comments 0
You need to be logged in to leave comments. Login now