##// END OF EJS Templates
Simplify color definition. (#14291)...
M Bussonnier -
r28588:b14df380 merge
parent child Browse files
Show More
@@ -1,258 +1,264 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 System command aliases.
3 System command aliases.
4
4
5 Authors:
5 Authors:
6
6
7 * Fernando Perez
7 * Fernando Perez
8 * Brian Granger
8 * Brian Granger
9 """
9 """
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
13 #
14 # Distributed under the terms of the BSD License.
14 # Distributed under the terms of the BSD License.
15 #
15 #
16 # The full license is in the file COPYING.txt, distributed with this software.
16 # The full license is in the file COPYING.txt, distributed with this software.
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Imports
20 # Imports
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22
22
23 import os
23 import os
24 import re
24 import re
25 import sys
25 import sys
26
26
27 from traitlets.config.configurable import Configurable
27 from traitlets.config.configurable import Configurable
28 from .error import UsageError
28 from .error import UsageError
29
29
30 from traitlets import List, Instance
30 from traitlets import List, Instance
31 from logging import error
31 from logging import error
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Utilities
34 # Utilities
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 # This is used as the pattern for calls to split_user_input.
37 # This is used as the pattern for calls to split_user_input.
38 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
38 shell_line_split = re.compile(r'^(\s*)()(\S+)(.*$)')
39
39
40 def default_aliases():
40 def default_aliases():
41 """Return list of shell aliases to auto-define.
41 """Return list of shell aliases to auto-define.
42 """
42 """
43 # Note: the aliases defined here should be safe to use on a kernel
43 # Note: the aliases defined here should be safe to use on a kernel
44 # regardless of what frontend it is attached to. Frontends that use a
44 # regardless of what frontend it is attached to. Frontends that use a
45 # kernel in-process can define additional aliases that will only work in
45 # kernel in-process can define additional aliases that will only work in
46 # their case. For example, things like 'less' or 'clear' that manipulate
46 # their case. For example, things like 'less' or 'clear' that manipulate
47 # the terminal should NOT be declared here, as they will only work if the
47 # the terminal should NOT be declared here, as they will only work if the
48 # kernel is running inside a true terminal, and not over the network.
48 # kernel is running inside a true terminal, and not over the network.
49
49
50 if os.name == 'posix':
50 if os.name == 'posix':
51 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
51 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
52 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
52 ('mv', 'mv'), ('rm', 'rm'), ('cp', 'cp'),
53 ('cat', 'cat'),
53 ('cat', 'cat'),
54 ]
54 ]
55 # Useful set of ls aliases. The GNU and BSD options are a little
55 # Useful set of ls aliases. The GNU and BSD options are a little
56 # different, so we make aliases that provide as similar as possible
56 # different, so we make aliases that provide as similar as possible
57 # behavior in ipython, by passing the right flags for each platform
57 # behavior in ipython, by passing the right flags for each platform
58 if sys.platform.startswith('linux'):
58 if sys.platform.startswith('linux'):
59 ls_aliases = [('ls', 'ls -F --color'),
59 ls_aliases = [('ls', 'ls -F --color'),
60 # long ls
60 # long ls
61 ('ll', 'ls -F -o --color'),
61 ('ll', 'ls -F -o --color'),
62 # ls normal files only
62 # ls normal files only
63 ('lf', 'ls -F -o --color %l | grep ^-'),
63 ('lf', 'ls -F -o --color %l | grep ^-'),
64 # ls symbolic links
64 # ls symbolic links
65 ('lk', 'ls -F -o --color %l | grep ^l'),
65 ('lk', 'ls -F -o --color %l | grep ^l'),
66 # directories or links to directories,
66 # directories or links to directories,
67 ('ldir', 'ls -F -o --color %l | grep /$'),
67 ('ldir', 'ls -F -o --color %l | grep /$'),
68 # things which are executable
68 # things which are executable
69 ('lx', 'ls -F -o --color %l | grep ^-..x'),
69 ('lx', 'ls -F -o --color %l | grep ^-..x'),
70 ]
70 ]
71 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
71 elif sys.platform.startswith('openbsd') or sys.platform.startswith('netbsd'):
72 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
72 # OpenBSD, NetBSD. The ls implementation on these platforms do not support
73 # the -G switch and lack the ability to use colorized output.
73 # the -G switch and lack the ability to use colorized output.
74 ls_aliases = [('ls', 'ls -F'),
74 ls_aliases = [('ls', 'ls -F'),
75 # long ls
75 # long ls
76 ('ll', 'ls -F -l'),
76 ('ll', 'ls -F -l'),
77 # ls normal files only
77 # ls normal files only
78 ('lf', 'ls -F -l %l | grep ^-'),
78 ('lf', 'ls -F -l %l | grep ^-'),
79 # ls symbolic links
79 # ls symbolic links
80 ('lk', 'ls -F -l %l | grep ^l'),
80 ('lk', 'ls -F -l %l | grep ^l'),
81 # directories or links to directories,
81 # directories or links to directories,
82 ('ldir', 'ls -F -l %l | grep /$'),
82 ('ldir', 'ls -F -l %l | grep /$'),
83 # things which are executable
83 # things which are executable
84 ('lx', 'ls -F -l %l | grep ^-..x'),
84 ('lx', 'ls -F -l %l | grep ^-..x'),
85 ]
85 ]
86 else:
86 else:
87 # BSD, OSX, etc.
87 # BSD, OSX, etc.
88 ls_aliases = [('ls', 'ls -F -G'),
88 ls_aliases = [('ls', 'ls -F -G'),
89 # long ls
89 # long ls
90 ('ll', 'ls -F -l -G'),
90 ('ll', 'ls -F -l -G'),
91 # ls normal files only
91 # ls normal files only
92 ('lf', 'ls -F -l -G %l | grep ^-'),
92 ('lf', 'ls -F -l -G %l | grep ^-'),
93 # ls symbolic links
93 # ls symbolic links
94 ('lk', 'ls -F -l -G %l | grep ^l'),
94 ('lk', 'ls -F -l -G %l | grep ^l'),
95 # directories or links to directories,
95 # directories or links to directories,
96 ('ldir', 'ls -F -G -l %l | grep /$'),
96 ('ldir', 'ls -F -G -l %l | grep /$'),
97 # things which are executable
97 # things which are executable
98 ('lx', 'ls -F -l -G %l | grep ^-..x'),
98 ('lx', 'ls -F -l -G %l | grep ^-..x'),
99 ]
99 ]
100 default_aliases = default_aliases + ls_aliases
100 default_aliases = default_aliases + ls_aliases
101 elif os.name in ['nt', 'dos']:
101 elif os.name in ['nt', 'dos']:
102 default_aliases = [('ls', 'dir /on'),
102 default_aliases = [('ls', 'dir /on'),
103 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
103 ('ddir', 'dir /ad /on'), ('ldir', 'dir /ad /on'),
104 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
104 ('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
105 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
105 ('echo', 'echo'), ('ren', 'ren'), ('copy', 'copy'),
106 ]
106 ]
107 else:
107 else:
108 default_aliases = []
108 default_aliases = []
109
109
110 return default_aliases
110 return default_aliases
111
111
112
112
113 class AliasError(Exception):
113 class AliasError(Exception):
114 pass
114 pass
115
115
116
116
117 class InvalidAliasError(AliasError):
117 class InvalidAliasError(AliasError):
118 pass
118 pass
119
119
120 class Alias(object):
120 class Alias(object):
121 """Callable object storing the details of one alias.
121 """Callable object storing the details of one alias.
122
122
123 Instances are registered as magic functions to allow use of aliases.
123 Instances are registered as magic functions to allow use of aliases.
124 """
124 """
125
125
126 # Prepare blacklist
126 # Prepare blacklist
127 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
127 blacklist = {'cd','popd','pushd','dhist','alias','unalias'}
128
128
129 def __init__(self, shell, name, cmd):
129 def __init__(self, shell, name, cmd):
130 self.shell = shell
130 self.shell = shell
131 self.name = name
131 self.name = name
132 self.cmd = cmd
132 self.cmd = cmd
133 self.__doc__ = "Alias for `!{}`".format(cmd)
133 self.__doc__ = "Alias for `!{}`".format(cmd)
134 self.nargs = self.validate()
134 self.nargs = self.validate()
135
135
136 def validate(self):
136 def validate(self):
137 """Validate the alias, and return the number of arguments."""
137 """Validate the alias, and return the number of arguments."""
138 if self.name in self.blacklist:
138 if self.name in self.blacklist:
139 raise InvalidAliasError("The name %s can't be aliased "
139 raise InvalidAliasError("The name %s can't be aliased "
140 "because it is a keyword or builtin." % self.name)
140 "because it is a keyword or builtin." % self.name)
141 try:
141 try:
142 caller = self.shell.magics_manager.magics['line'][self.name]
142 caller = self.shell.magics_manager.magics['line'][self.name]
143 except KeyError:
143 except KeyError:
144 pass
144 pass
145 else:
145 else:
146 if not isinstance(caller, Alias):
146 if not isinstance(caller, Alias):
147 raise InvalidAliasError("The name %s can't be aliased "
147 raise InvalidAliasError("The name %s can't be aliased "
148 "because it is another magic command." % self.name)
148 "because it is another magic command." % self.name)
149
149
150 if not (isinstance(self.cmd, str)):
150 if not (isinstance(self.cmd, str)):
151 raise InvalidAliasError("An alias command must be a string, "
151 raise InvalidAliasError("An alias command must be a string, "
152 "got: %r" % self.cmd)
152 "got: %r" % self.cmd)
153
153
154 nargs = self.cmd.count('%s') - self.cmd.count('%%s')
154 nargs = self.cmd.count('%s') - self.cmd.count('%%s')
155
155
156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
156 if (nargs > 0) and (self.cmd.find('%l') >= 0):
157 raise InvalidAliasError('The %s and %l specifiers are mutually '
157 raise InvalidAliasError('The %s and %l specifiers are mutually '
158 'exclusive in alias definitions.')
158 'exclusive in alias definitions.')
159
159
160 return nargs
160 return nargs
161
161
162 def __repr__(self):
162 def __repr__(self):
163 return "<alias {} for {!r}>".format(self.name, self.cmd)
163 return "<alias {} for {!r}>".format(self.name, self.cmd)
164
164
165 def __call__(self, rest=''):
165 def __call__(self, rest=''):
166 cmd = self.cmd
166 cmd = self.cmd
167 nargs = self.nargs
167 nargs = self.nargs
168 # Expand the %l special to be the user's input line
168 # Expand the %l special to be the user's input line
169 if cmd.find('%l') >= 0:
169 if cmd.find('%l') >= 0:
170 cmd = cmd.replace('%l', rest)
170 cmd = cmd.replace('%l', rest)
171 rest = ''
171 rest = ''
172
172
173 if nargs==0:
173 if nargs==0:
174 if cmd.find('%%s') >= 1:
174 if cmd.find('%%s') >= 1:
175 cmd = cmd.replace('%%s', '%s')
175 cmd = cmd.replace('%%s', '%s')
176 # Simple, argument-less aliases
176 # Simple, argument-less aliases
177 cmd = '%s %s' % (cmd, rest)
177 cmd = '%s %s' % (cmd, rest)
178 else:
178 else:
179 # Handle aliases with positional arguments
179 # Handle aliases with positional arguments
180 args = rest.split(None, nargs)
180 args = rest.split(None, nargs)
181 if len(args) < nargs:
181 if len(args) < nargs:
182 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
182 raise UsageError('Alias <%s> requires %s arguments, %s given.' %
183 (self.name, nargs, len(args)))
183 (self.name, nargs, len(args)))
184 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
184 cmd = '%s %s' % (cmd % tuple(args[:nargs]),' '.join(args[nargs:]))
185
185
186 self.shell.system(cmd)
186 self.shell.system(cmd)
187
187
188 #-----------------------------------------------------------------------------
188 #-----------------------------------------------------------------------------
189 # Main AliasManager class
189 # Main AliasManager class
190 #-----------------------------------------------------------------------------
190 #-----------------------------------------------------------------------------
191
191
192 class AliasManager(Configurable):
192 class AliasManager(Configurable):
193
193 default_aliases: List = List(default_aliases()).tag(config=True)
194 default_aliases = List(default_aliases()).tag(config=True)
194 user_aliases: List = List(default_value=[]).tag(config=True)
195 user_aliases = List(default_value=[]).tag(config=True)
195 shell = Instance(
196 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
196 "IPython.core.interactiveshell.InteractiveShellABC", allow_none=True
197 )
197
198
198 def __init__(self, shell=None, **kwargs):
199 def __init__(self, shell=None, **kwargs):
199 super(AliasManager, self).__init__(shell=shell, **kwargs)
200 super(AliasManager, self).__init__(shell=shell, **kwargs)
200 # For convenient access
201 # For convenient access
201 self.linemagics = self.shell.magics_manager.magics['line']
202 if self.shell is not None:
202 self.init_aliases()
203 self.linemagics = self.shell.magics_manager.magics["line"]
204 self.init_aliases()
203
205
204 def init_aliases(self):
206 def init_aliases(self):
205 # Load default & user aliases
207 # Load default & user aliases
206 for name, cmd in self.default_aliases + self.user_aliases:
208 for name, cmd in self.default_aliases + self.user_aliases:
207 if cmd.startswith('ls ') and self.shell.colors == 'NoColor':
209 if (
208 cmd = cmd.replace(' --color', '')
210 cmd.startswith("ls ")
211 and self.shell is not None
212 and self.shell.colors == "NoColor"
213 ):
214 cmd = cmd.replace(" --color", "")
209 self.soft_define_alias(name, cmd)
215 self.soft_define_alias(name, cmd)
210
216
211 @property
217 @property
212 def aliases(self):
218 def aliases(self):
213 return [(n, func.cmd) for (n, func) in self.linemagics.items()
219 return [(n, func.cmd) for (n, func) in self.linemagics.items()
214 if isinstance(func, Alias)]
220 if isinstance(func, Alias)]
215
221
216 def soft_define_alias(self, name, cmd):
222 def soft_define_alias(self, name, cmd):
217 """Define an alias, but don't raise on an AliasError."""
223 """Define an alias, but don't raise on an AliasError."""
218 try:
224 try:
219 self.define_alias(name, cmd)
225 self.define_alias(name, cmd)
220 except AliasError as e:
226 except AliasError as e:
221 error("Invalid alias: %s" % e)
227 error("Invalid alias: %s" % e)
222
228
223 def define_alias(self, name, cmd):
229 def define_alias(self, name, cmd):
224 """Define a new alias after validating it.
230 """Define a new alias after validating it.
225
231
226 This will raise an :exc:`AliasError` if there are validation
232 This will raise an :exc:`AliasError` if there are validation
227 problems.
233 problems.
228 """
234 """
229 caller = Alias(shell=self.shell, name=name, cmd=cmd)
235 caller = Alias(shell=self.shell, name=name, cmd=cmd)
230 self.shell.magics_manager.register_function(caller, magic_kind='line',
236 self.shell.magics_manager.register_function(caller, magic_kind='line',
231 magic_name=name)
237 magic_name=name)
232
238
233 def get_alias(self, name):
239 def get_alias(self, name):
234 """Return an alias, or None if no alias by that name exists."""
240 """Return an alias, or None if no alias by that name exists."""
235 aname = self.linemagics.get(name, None)
241 aname = self.linemagics.get(name, None)
236 return aname if isinstance(aname, Alias) else None
242 return aname if isinstance(aname, Alias) else None
237
243
238 def is_alias(self, name):
244 def is_alias(self, name):
239 """Return whether or not a given name has been defined as an alias"""
245 """Return whether or not a given name has been defined as an alias"""
240 return self.get_alias(name) is not None
246 return self.get_alias(name) is not None
241
247
242 def undefine_alias(self, name):
248 def undefine_alias(self, name):
243 if self.is_alias(name):
249 if self.is_alias(name):
244 del self.linemagics[name]
250 del self.linemagics[name]
245 else:
251 else:
246 raise ValueError('%s is not an alias' % name)
252 raise ValueError('%s is not an alias' % name)
247
253
248 def clear_aliases(self):
254 def clear_aliases(self):
249 for name, cmd in self.aliases:
255 for name, _ in self.aliases:
250 self.undefine_alias(name)
256 self.undefine_alias(name)
251
257
252 def retrieve_alias(self, name):
258 def retrieve_alias(self, name):
253 """Retrieve the command to which an alias expands."""
259 """Retrieve the command to which an alias expands."""
254 caller = self.get_alias(name)
260 caller = self.get_alias(name)
255 if caller:
261 if caller:
256 return caller.cmd
262 return caller.cmd
257 else:
263 else:
258 raise ValueError('%s is not an alias' % name)
264 raise ValueError('%s is not an alias' % name)
@@ -1,165 +1,175 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Color schemes for exception handling code in IPython.
3 Color schemes for exception handling code in IPython.
4 """
4 """
5
5
6 import os
6 import os
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2005-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 from IPython.utils.coloransi import ColorSchemeTable, TermColors, ColorScheme
15 from IPython.utils.coloransi import ColorSchemeTable, TermColors, ColorScheme
16
16
17 def exception_colors():
17 def exception_colors():
18 """Return a color table with fields for exception reporting.
18 """Return a color table with fields for exception reporting.
19
19
20 The table is an instance of ColorSchemeTable with schemes added for
20 The table is an instance of ColorSchemeTable with schemes added for
21 'Neutral', 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
21 'Neutral', 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled
22 in.
22 in.
23
23
24 Examples:
24 Examples:
25
25
26 >>> ec = exception_colors()
26 >>> ec = exception_colors()
27 >>> ec.active_scheme_name
27 >>> ec.active_scheme_name
28 ''
28 ''
29 >>> print(ec.active_colors)
29 >>> print(ec.active_colors)
30 None
30 None
31
31
32 Now we activate a color scheme:
32 Now we activate a color scheme:
33 >>> ec.set_active_scheme('NoColor')
33 >>> ec.set_active_scheme('NoColor')
34 >>> ec.active_scheme_name
34 >>> ec.active_scheme_name
35 'NoColor'
35 'NoColor'
36 >>> sorted(ec.active_colors.keys())
36 >>> sorted(ec.active_colors.keys())
37 ['Normal', 'caret', 'em', 'excName', 'filename', 'filenameEm', 'line',
37 ['Normal', 'caret', 'em', 'excName', 'filename', 'filenameEm', 'line',
38 'lineno', 'linenoEm', 'name', 'nameEm', 'normalEm', 'topline', 'vName',
38 'lineno', 'linenoEm', 'name', 'nameEm', 'normalEm', 'topline', 'vName',
39 'val', 'valEm']
39 'val', 'valEm']
40 """
40 """
41
41
42 ex_colors = ColorSchemeTable()
42 ex_colors = ColorSchemeTable()
43
43
44 # Populate it with color schemes
44 # Populate it with color schemes
45 C = TermColors # shorthand and local lookup
45 C = TermColors # shorthand and local lookup
46 ex_colors.add_scheme(ColorScheme(
46 ex_colors.add_scheme(
47 'NoColor',
47 ColorScheme(
48 # The color to be used for the top line
48 "NoColor",
49 topline = C.NoColor,
49 {
50
50 # The color to be used for the top line
51 # The colors to be used in the traceback
51 "topline": C.NoColor,
52 filename = C.NoColor,
52
53 lineno = C.NoColor,
53 # The colors to be used in the traceback
54 name = C.NoColor,
54 "filename": C.NoColor,
55 vName = C.NoColor,
55 "lineno": C.NoColor,
56 val = C.NoColor,
56 "name": C.NoColor,
57 em = C.NoColor,
57 "vName": C.NoColor,
58
58 "val": C.NoColor,
59 # Emphasized colors for the last frame of the traceback
59 "em": C.NoColor,
60 normalEm = C.NoColor,
60
61 filenameEm = C.NoColor,
61 # Emphasized colors for the last frame of the traceback
62 linenoEm = C.NoColor,
62 "normalEm": C.NoColor,
63 nameEm = C.NoColor,
63 "filenameEm": C.NoColor,
64 valEm = C.NoColor,
64 "linenoEm": C.NoColor,
65
65 "nameEm": C.NoColor,
66 # Colors for printing the exception
66 "valEm": C.NoColor,
67 excName = C.NoColor,
67
68 line = C.NoColor,
68 # Colors for printing the exception
69 caret = C.NoColor,
69 "excName": C.NoColor,
70 Normal = C.NoColor
70 "line": C.NoColor,
71 ))
71 "caret": C.NoColor,
72 "Normal": C.NoColor,
73 },
74 )
75 )
72
76
73 # make some schemes as instances so we can copy them for modification easily
77 # make some schemes as instances so we can copy them for modification easily
74 ex_colors.add_scheme(ColorScheme(
78 ex_colors.add_scheme(
75 'Linux',
79 ColorScheme(
76 # The color to be used for the top line
80 "Linux",
77 topline = C.LightRed,
81 {
78
82 # The color to be used for the top line
79 # The colors to be used in the traceback
83 "topline": C.LightRed,
80 filename = C.Green,
84 # The colors to be used in the traceback
81 lineno = C.Green,
85 "filename": C.Green,
82 name = C.Purple,
86 "lineno": C.Green,
83 vName = C.Cyan,
87 "name": C.Purple,
84 val = C.Green,
88 "vName": C.Cyan,
85 em = C.LightCyan,
89 "val": C.Green,
86
90 "em": C.LightCyan,
87 # Emphasized colors for the last frame of the traceback
91 # Emphasized colors for the last frame of the traceback
88 normalEm = C.LightCyan,
92 "normalEm": C.LightCyan,
89 filenameEm = C.LightGreen,
93 "filenameEm": C.LightGreen,
90 linenoEm = C.LightGreen,
94 "linenoEm": C.LightGreen,
91 nameEm = C.LightPurple,
95 "nameEm": C.LightPurple,
92 valEm = C.LightBlue,
96 "valEm": C.LightBlue,
93
97 # Colors for printing the exception
94 # Colors for printing the exception
98 "excName": C.LightRed,
95 excName = C.LightRed,
99 "line": C.Yellow,
96 line = C.Yellow,
100 "caret": C.White,
97 caret = C.White,
101 "Normal": C.Normal,
98 Normal = C.Normal
102 },
99 ))
103 )
104 )
100
105
101 # For light backgrounds, swap dark/light colors
106 # For light backgrounds, swap dark/light colors
102 ex_colors.add_scheme(ColorScheme(
107 ex_colors.add_scheme(
103 'LightBG',
108 ColorScheme(
104 # The color to be used for the top line
109 "LightBG",
105 topline = C.Red,
110 {
106
111 # The color to be used for the top line
107 # The colors to be used in the traceback
112 "topline": C.Red,
108 filename = C.LightGreen,
113
109 lineno = C.LightGreen,
114 # The colors to be used in the traceback
110 name = C.LightPurple,
115 "filename": C.LightGreen,
111 vName = C.Cyan,
116 "lineno": C.LightGreen,
112 val = C.LightGreen,
117 "name": C.LightPurple,
113 em = C.Cyan,
118 "vName": C.Cyan,
114
119 "val": C.LightGreen,
115 # Emphasized colors for the last frame of the traceback
120 "em": C.Cyan,
116 normalEm = C.Cyan,
121
117 filenameEm = C.Green,
122 # Emphasized colors for the last frame of the traceback
118 linenoEm = C.Green,
123 "normalEm": C.Cyan,
119 nameEm = C.Purple,
124 "filenameEm": C.Green,
120 valEm = C.Blue,
125 "linenoEm": C.Green,
121
126 "nameEm": C.Purple,
122 # Colors for printing the exception
127 "valEm": C.Blue,
123 excName = C.Red,
128
124 #line = C.Brown, # brown often is displayed as yellow
129 # Colors for printing the exception
125 line = C.Red,
130 "excName": C.Red,
126 caret = C.Normal,
131 # "line": C.Brown, # brown often is displayed as yellow
127 Normal = C.Normal,
132 "line": C.Red,
128 ))
133 "caret": C.Normal,
129
134 "Normal": C.Normal,
130 ex_colors.add_scheme(ColorScheme(
135 },
131 'Neutral',
136 )
132 # The color to be used for the top line
137 )
133 topline = C.Red,
138
134
139 ex_colors.add_scheme(
135 # The colors to be used in the traceback
140 ColorScheme(
136 filename = C.LightGreen,
141 "Neutral",
137 lineno = C.LightGreen,
142 {
138 name = C.LightPurple,
143 # The color to be used for the top line
139 vName = C.Cyan,
144 "topline": C.Red,
140 val = C.LightGreen,
145 # The colors to be used in the traceback
141 em = C.Cyan,
146 "filename": C.LightGreen,
142
147 "lineno": C.LightGreen,
143 # Emphasized colors for the last frame of the traceback
148 "name": C.LightPurple,
144 normalEm = C.Cyan,
149 "vName": C.Cyan,
145 filenameEm = C.Green,
150 "val": C.LightGreen,
146 linenoEm = C.Green,
151 "em": C.Cyan,
147 nameEm = C.Purple,
152 # Emphasized colors for the last frame of the traceback
148 valEm = C.Blue,
153 "normalEm": C.Cyan,
149
154 "filenameEm": C.Green,
150 # Colors for printing the exception
155 "linenoEm": C.Green,
151 excName = C.Red,
156 "nameEm": C.Purple,
152 #line = C.Brown, # brown often is displayed as yellow
157 "valEm": C.Blue,
153 line = C.Red,
158 # Colors for printing the exception
154 caret = C.Normal,
159 "excName": C.Red,
155 Normal = C.Normal,
160 # line = C.Brown, # brown often is displayed as yellow
156 ))
161 "line": C.Red,
162 "caret": C.Normal,
163 "Normal": C.Normal,
164 },
165 )
166 )
157
167
158 # Hack: the 'neutral' colours are not very visible on a dark background on
168 # Hack: the 'neutral' colours are not very visible on a dark background on
159 # Windows. Since Windows command prompts have a dark background by default, and
169 # Windows. Since Windows command prompts have a dark background by default, and
160 # relatively few users are likely to alter that, we will use the 'Linux' colours,
170 # relatively few users are likely to alter that, we will use the 'Linux' colours,
161 # designed for a dark background, as the default on Windows.
171 # designed for a dark background, as the default on Windows.
162 if os.name == "nt":
172 if os.name == "nt":
163 ex_colors.add_scheme(ex_colors['Linux'].copy('Neutral'))
173 ex_colors.add_scheme(ex_colors['Linux'].copy('Neutral'))
164
174
165 return ex_colors
175 return ex_colors
@@ -1,151 +1,150 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """A class for managing IPython extensions."""
2 """A class for managing IPython extensions."""
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 os.path
8 import os.path
9 import sys
9 import sys
10 from importlib import import_module, reload
10 from importlib import import_module, reload
11
11
12 from traitlets.config.configurable import Configurable
12 from traitlets.config.configurable import Configurable
13 from IPython.utils.path import ensure_dir_exists, compress_user
13 from IPython.utils.path import ensure_dir_exists
14 from IPython.utils.decorators import undoc
15 from traitlets import Instance
14 from traitlets import Instance
16
15
17
16
18 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
19 # Main class
18 # Main class
20 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
21
20
22 BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
21 BUILTINS_EXTS = {"storemagic": False, "autoreload": False}
23
22
24
23
25 class ExtensionManager(Configurable):
24 class ExtensionManager(Configurable):
26 """A class to manage IPython extensions.
25 """A class to manage IPython extensions.
27
26
28 An IPython extension is an importable Python module that has
27 An IPython extension is an importable Python module that has
29 a function with the signature::
28 a function with the signature::
30
29
31 def load_ipython_extension(ipython):
30 def load_ipython_extension(ipython):
32 # Do things with ipython
31 # Do things with ipython
33
32
34 This function is called after your extension is imported and the
33 This function is called after your extension is imported and the
35 currently active :class:`InteractiveShell` instance is passed as
34 currently active :class:`InteractiveShell` instance is passed as
36 the only argument. You can do anything you want with IPython at
35 the only argument. You can do anything you want with IPython at
37 that point, including defining new magic and aliases, adding new
36 that point, including defining new magic and aliases, adding new
38 components, etc.
37 components, etc.
39
38
40 You can also optionally define an :func:`unload_ipython_extension(ipython)`
39 You can also optionally define an :func:`unload_ipython_extension(ipython)`
41 function, which will be called if the user unloads or reloads the extension.
40 function, which will be called if the user unloads or reloads the extension.
42 The extension manager will only call :func:`load_ipython_extension` again
41 The extension manager will only call :func:`load_ipython_extension` again
43 if the extension is reloaded.
42 if the extension is reloaded.
44
43
45 You can put your extension modules anywhere you want, as long as
44 You can put your extension modules anywhere you want, as long as
46 they can be imported by Python's standard import mechanism. However,
45 they can be imported by Python's standard import mechanism. However,
47 to make it easy to write extensions, you can also put your extensions
46 to make it easy to write extensions, you can also put your extensions
48 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
47 in ``os.path.join(self.ipython_dir, 'extensions')``. This directory
49 is added to ``sys.path`` automatically.
48 is added to ``sys.path`` automatically.
50 """
49 """
51
50
52 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
51 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True)
53
52
54 def __init__(self, shell=None, **kwargs):
53 def __init__(self, shell=None, **kwargs):
55 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
54 super(ExtensionManager, self).__init__(shell=shell, **kwargs)
56 self.shell.observe(
55 self.shell.observe(
57 self._on_ipython_dir_changed, names=('ipython_dir',)
56 self._on_ipython_dir_changed, names=('ipython_dir',)
58 )
57 )
59 self.loaded = set()
58 self.loaded = set()
60
59
61 @property
60 @property
62 def ipython_extension_dir(self):
61 def ipython_extension_dir(self):
63 return os.path.join(self.shell.ipython_dir, u'extensions')
62 return os.path.join(self.shell.ipython_dir, u'extensions')
64
63
65 def _on_ipython_dir_changed(self, change):
64 def _on_ipython_dir_changed(self, change):
66 ensure_dir_exists(self.ipython_extension_dir)
65 ensure_dir_exists(self.ipython_extension_dir)
67
66
68 def load_extension(self, module_str: str):
67 def load_extension(self, module_str: str):
69 """Load an IPython extension by its module name.
68 """Load an IPython extension by its module name.
70
69
71 Returns the string "already loaded" if the extension is already loaded,
70 Returns the string "already loaded" if the extension is already loaded,
72 "no load function" if the module doesn't have a load_ipython_extension
71 "no load function" if the module doesn't have a load_ipython_extension
73 function, or None if it succeeded.
72 function, or None if it succeeded.
74 """
73 """
75 try:
74 try:
76 return self._load_extension(module_str)
75 return self._load_extension(module_str)
77 except ModuleNotFoundError:
76 except ModuleNotFoundError:
78 if module_str in BUILTINS_EXTS:
77 if module_str in BUILTINS_EXTS:
79 BUILTINS_EXTS[module_str] = True
78 BUILTINS_EXTS[module_str] = True
80 return self._load_extension("IPython.extensions." + module_str)
79 return self._load_extension("IPython.extensions." + module_str)
81 raise
80 raise
82
81
83 def _load_extension(self, module_str: str):
82 def _load_extension(self, module_str: str):
84 if module_str in self.loaded:
83 if module_str in self.loaded:
85 return "already loaded"
84 return "already loaded"
86
85
87 from IPython.utils.syspathcontext import prepended_to_syspath
86 assert self.shell is not None
88
87
89 with self.shell.builtin_trap:
88 with self.shell.builtin_trap:
90 if module_str not in sys.modules:
89 if module_str not in sys.modules:
91 mod = import_module(module_str)
90 mod = import_module(module_str)
92 mod = sys.modules[module_str]
91 mod = sys.modules[module_str]
93 if self._call_load_ipython_extension(mod):
92 if self._call_load_ipython_extension(mod):
94 self.loaded.add(module_str)
93 self.loaded.add(module_str)
95 else:
94 else:
96 return "no load function"
95 return "no load function"
97
96
98 def unload_extension(self, module_str: str):
97 def unload_extension(self, module_str: str):
99 """Unload an IPython extension by its module name.
98 """Unload an IPython extension by its module name.
100
99
101 This function looks up the extension's name in ``sys.modules`` and
100 This function looks up the extension's name in ``sys.modules`` and
102 simply calls ``mod.unload_ipython_extension(self)``.
101 simply calls ``mod.unload_ipython_extension(self)``.
103
102
104 Returns the string "no unload function" if the extension doesn't define
103 Returns the string "no unload function" if the extension doesn't define
105 a function to unload itself, "not loaded" if the extension isn't loaded,
104 a function to unload itself, "not loaded" if the extension isn't loaded,
106 otherwise None.
105 otherwise None.
107 """
106 """
108 if BUILTINS_EXTS.get(module_str, False) is True:
107 if BUILTINS_EXTS.get(module_str, False) is True:
109 module_str = "IPython.extensions." + module_str
108 module_str = "IPython.extensions." + module_str
110 if module_str not in self.loaded:
109 if module_str not in self.loaded:
111 return "not loaded"
110 return "not loaded"
112
111
113 if module_str in sys.modules:
112 if module_str in sys.modules:
114 mod = sys.modules[module_str]
113 mod = sys.modules[module_str]
115 if self._call_unload_ipython_extension(mod):
114 if self._call_unload_ipython_extension(mod):
116 self.loaded.discard(module_str)
115 self.loaded.discard(module_str)
117 else:
116 else:
118 return "no unload function"
117 return "no unload function"
119
118
120 def reload_extension(self, module_str: str):
119 def reload_extension(self, module_str: str):
121 """Reload an IPython extension by calling reload.
120 """Reload an IPython extension by calling reload.
122
121
123 If the module has not been loaded before,
122 If the module has not been loaded before,
124 :meth:`InteractiveShell.load_extension` is called. Otherwise
123 :meth:`InteractiveShell.load_extension` is called. Otherwise
125 :func:`reload` is called and then the :func:`load_ipython_extension`
124 :func:`reload` is called and then the :func:`load_ipython_extension`
126 function of the module, if it exists is called.
125 function of the module, if it exists is called.
127 """
126 """
128 from IPython.utils.syspathcontext import prepended_to_syspath
127 from IPython.utils.syspathcontext import prepended_to_syspath
129
128
130 if BUILTINS_EXTS.get(module_str, False) is True:
129 if BUILTINS_EXTS.get(module_str, False) is True:
131 module_str = "IPython.extensions." + module_str
130 module_str = "IPython.extensions." + module_str
132
131
133 if (module_str in self.loaded) and (module_str in sys.modules):
132 if (module_str in self.loaded) and (module_str in sys.modules):
134 self.unload_extension(module_str)
133 self.unload_extension(module_str)
135 mod = sys.modules[module_str]
134 mod = sys.modules[module_str]
136 with prepended_to_syspath(self.ipython_extension_dir):
135 with prepended_to_syspath(self.ipython_extension_dir):
137 reload(mod)
136 reload(mod)
138 if self._call_load_ipython_extension(mod):
137 if self._call_load_ipython_extension(mod):
139 self.loaded.add(module_str)
138 self.loaded.add(module_str)
140 else:
139 else:
141 self.load_extension(module_str)
140 self.load_extension(module_str)
142
141
143 def _call_load_ipython_extension(self, mod):
142 def _call_load_ipython_extension(self, mod):
144 if hasattr(mod, 'load_ipython_extension'):
143 if hasattr(mod, 'load_ipython_extension'):
145 mod.load_ipython_extension(self.shell)
144 mod.load_ipython_extension(self.shell)
146 return True
145 return True
147
146
148 def _call_unload_ipython_extension(self, mod):
147 def _call_unload_ipython_extension(self, mod):
149 if hasattr(mod, 'unload_ipython_extension'):
148 if hasattr(mod, 'unload_ipython_extension'):
150 mod.unload_ipython_extension(self.shell)
149 mod.unload_ipython_extension(self.shell)
151 return True
150 return True
@@ -1,55 +1,54 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Payload system for IPython.
2 """Payload system for IPython.
3
3
4 Authors:
4 Authors:
5
5
6 * Fernando Perez
6 * Fernando Perez
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2011 The IPython Development Team
11 # Copyright (C) 2008-2011 The IPython Development Team
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Imports
18 # Imports
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 from traitlets.config.configurable import Configurable
21 from traitlets.config.configurable import Configurable
22 from traitlets import List
22 from traitlets import List
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Main payload class
25 # Main payload class
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 class PayloadManager(Configurable):
28 class PayloadManager(Configurable):
29
29 _payload: List = List([])
30 _payload = List([])
31
30
32 def write_payload(self, data, single=True):
31 def write_payload(self, data, single=True):
33 """Include or update the specified `data` payload in the PayloadManager.
32 """Include or update the specified `data` payload in the PayloadManager.
34
33
35 If a previous payload with the same source exists and `single` is True,
34 If a previous payload with the same source exists and `single` is True,
36 it will be overwritten with the new one.
35 it will be overwritten with the new one.
37 """
36 """
38
37
39 if not isinstance(data, dict):
38 if not isinstance(data, dict):
40 raise TypeError('Each payload write must be a dict, got: %r' % data)
39 raise TypeError('Each payload write must be a dict, got: %r' % data)
41
40
42 if single and 'source' in data:
41 if single and 'source' in data:
43 source = data['source']
42 source = data['source']
44 for i, pl in enumerate(self._payload):
43 for i, pl in enumerate(self._payload):
45 if 'source' in pl and pl['source'] == source:
44 if 'source' in pl and pl['source'] == source:
46 self._payload[i] = data
45 self._payload[i] = data
47 return
46 return
48
47
49 self._payload.append(data)
48 self._payload.append(data)
50
49
51 def read_payload(self):
50 def read_payload(self):
52 return self._payload
51 return self._payload
53
52
54 def clear_payload(self):
53 def clear_payload(self):
55 self._payload = []
54 self._payload = []
@@ -1,127 +1,128 b''
1 """Terminal input and output prompts."""
1 """Terminal input and output prompts."""
2
2
3 from pygments.token import Token
3 from pygments.token import Token
4 import sys
4 import sys
5
5
6 from IPython.core.displayhook import DisplayHook
6 from IPython.core.displayhook import DisplayHook
7
7
8 from prompt_toolkit.formatted_text import fragment_list_width, PygmentsTokens
8 from prompt_toolkit.formatted_text import fragment_list_width, PygmentsTokens
9 from prompt_toolkit.shortcuts import print_formatted_text
9 from prompt_toolkit.shortcuts import print_formatted_text
10 from prompt_toolkit.enums import EditingMode
10 from prompt_toolkit.enums import EditingMode
11
11
12
12
13 class Prompts(object):
13 class Prompts(object):
14 def __init__(self, shell):
14 def __init__(self, shell):
15 self.shell = shell
15 self.shell = shell
16
16
17 def vi_mode(self):
17 def vi_mode(self):
18 if (getattr(self.shell.pt_app, 'editing_mode', None) == EditingMode.VI
18 if (getattr(self.shell.pt_app, 'editing_mode', None) == EditingMode.VI
19 and self.shell.prompt_includes_vi_mode):
19 and self.shell.prompt_includes_vi_mode):
20 mode = str(self.shell.pt_app.app.vi_state.input_mode)
20 mode = str(self.shell.pt_app.app.vi_state.input_mode)
21 if mode.startswith('InputMode.'):
21 if mode.startswith('InputMode.'):
22 mode = mode[10:13].lower()
22 mode = mode[10:13].lower()
23 elif mode.startswith('vi-'):
23 elif mode.startswith('vi-'):
24 mode = mode[3:6]
24 mode = mode[3:6]
25 return '['+mode+'] '
25 return '['+mode+'] '
26 return ''
26 return ''
27
27
28 def current_line(self) -> int:
28 def current_line(self) -> int:
29 if self.shell.pt_app is not None:
29 if self.shell.pt_app is not None:
30 return self.shell.pt_app.default_buffer.document.cursor_position_row or 0
30 return self.shell.pt_app.default_buffer.document.cursor_position_row or 0
31 return 0
31 return 0
32
32
33 def in_prompt_tokens(self):
33 def in_prompt_tokens(self):
34 return [
34 return [
35 (Token.Prompt, self.vi_mode()),
35 (Token.Prompt, self.vi_mode()),
36 (
36 (
37 Token.Prompt,
37 Token.Prompt,
38 self.shell.prompt_line_number_format.format(
38 self.shell.prompt_line_number_format.format(
39 line=1, rel_line=-self.current_line()
39 line=1, rel_line=-self.current_line()
40 ),
40 ),
41 ),
41 ),
42 (Token.Prompt, "In ["),
42 (Token.Prompt, "In ["),
43 (Token.PromptNum, str(self.shell.execution_count)),
43 (Token.PromptNum, str(self.shell.execution_count)),
44 (Token.Prompt, ']: '),
44 (Token.Prompt, ']: '),
45 ]
45 ]
46
46
47 def _width(self):
47 def _width(self):
48 return fragment_list_width(self.in_prompt_tokens())
48 return fragment_list_width(self.in_prompt_tokens())
49
49
50 def continuation_prompt_tokens(self, width=None, *, lineno=None):
50 def continuation_prompt_tokens(self, width=None, *, lineno=None):
51 if width is None:
51 if width is None:
52 width = self._width()
52 width = self._width()
53 line = lineno + 1 if lineno is not None else 0
53 line = lineno + 1 if lineno is not None else 0
54 prefix = " " * len(
54 prefix = " " * len(
55 self.vi_mode()
55 self.vi_mode()
56 ) + self.shell.prompt_line_number_format.format(
56 ) + self.shell.prompt_line_number_format.format(
57 line=line, rel_line=line - self.current_line() - 1
57 line=line, rel_line=line - self.current_line() - 1
58 )
58 )
59 return [
59 return [
60 (
60 (
61 Token.Prompt,
61 Token.Prompt,
62 prefix + (" " * (width - len(prefix) - 5)) + "...: ",
62 prefix + (" " * (width - len(prefix) - 5)) + "...: ",
63 ),
63 ),
64 ]
64 ]
65
65
66 def rewrite_prompt_tokens(self):
66 def rewrite_prompt_tokens(self):
67 width = self._width()
67 width = self._width()
68 return [
68 return [
69 (Token.Prompt, ('-' * (width - 2)) + '> '),
69 (Token.Prompt, ('-' * (width - 2)) + '> '),
70 ]
70 ]
71
71
72 def out_prompt_tokens(self):
72 def out_prompt_tokens(self):
73 return [
73 return [
74 (Token.OutPrompt, 'Out['),
74 (Token.OutPrompt, 'Out['),
75 (Token.OutPromptNum, str(self.shell.execution_count)),
75 (Token.OutPromptNum, str(self.shell.execution_count)),
76 (Token.OutPrompt, ']: '),
76 (Token.OutPrompt, ']: '),
77 ]
77 ]
78
78
79 class ClassicPrompts(Prompts):
79 class ClassicPrompts(Prompts):
80 def in_prompt_tokens(self):
80 def in_prompt_tokens(self):
81 return [
81 return [
82 (Token.Prompt, '>>> '),
82 (Token.Prompt, '>>> '),
83 ]
83 ]
84
84
85 def continuation_prompt_tokens(self, width=None):
85 def continuation_prompt_tokens(self, width=None):
86 return [
86 return [
87 (Token.Prompt, '... ')
87 (Token.Prompt, '... ')
88 ]
88 ]
89
89
90 def rewrite_prompt_tokens(self):
90 def rewrite_prompt_tokens(self):
91 return []
91 return []
92
92
93 def out_prompt_tokens(self):
93 def out_prompt_tokens(self):
94 return []
94 return []
95
95
96 class RichPromptDisplayHook(DisplayHook):
96 class RichPromptDisplayHook(DisplayHook):
97 """Subclass of base display hook using coloured prompt"""
97 """Subclass of base display hook using coloured prompt"""
98 def write_output_prompt(self):
98 def write_output_prompt(self):
99 sys.stdout.write(self.shell.separate_out)
99 sys.stdout.write(self.shell.separate_out)
100 # If we're not displaying a prompt, it effectively ends with a newline,
100 # If we're not displaying a prompt, it effectively ends with a newline,
101 # because the output will be left-aligned.
101 # because the output will be left-aligned.
102 self.prompt_end_newline = True
102 self.prompt_end_newline = True
103
103
104 if self.do_full_cache:
104 if self.do_full_cache:
105 tokens = self.shell.prompts.out_prompt_tokens()
105 tokens = self.shell.prompts.out_prompt_tokens()
106 prompt_txt = ''.join(s for t, s in tokens)
106 prompt_txt = "".join(s for _, s in tokens)
107 if prompt_txt and not prompt_txt.endswith('\n'):
107 if prompt_txt and not prompt_txt.endswith("\n"):
108 # Ask for a newline before multiline output
108 # Ask for a newline before multiline output
109 self.prompt_end_newline = False
109 self.prompt_end_newline = False
110
110
111 if self.shell.pt_app:
111 if self.shell.pt_app:
112 print_formatted_text(PygmentsTokens(tokens),
112 print_formatted_text(PygmentsTokens(tokens),
113 style=self.shell.pt_app.app.style, end='',
113 style=self.shell.pt_app.app.style, end='',
114 )
114 )
115 else:
115 else:
116 sys.stdout.write(prompt_txt)
116 sys.stdout.write(prompt_txt)
117
117
118 def write_format_data(self, format_dict, md_dict=None) -> None:
118 def write_format_data(self, format_dict, md_dict=None) -> None:
119 assert self.shell is not None
119 if self.shell.mime_renderers:
120 if self.shell.mime_renderers:
120
121
121 for mime, handler in self.shell.mime_renderers.items():
122 for mime, handler in self.shell.mime_renderers.items():
122 if mime in format_dict:
123 if mime in format_dict:
123 handler(format_dict[mime], None)
124 handler(format_dict[mime], None)
124 return
125 return
125
126
126 super().write_format_data(format_dict, md_dict)
127 super().write_format_data(format_dict, md_dict)
127
128
@@ -1,187 +1,191 b''
1 # -*- coding: utf-8 -*-
2 """Tools for coloring text in ANSI terminals.
1 """Tools for coloring text in ANSI terminals.
3 """
2 """
4
3
5 #*****************************************************************************
4 #*****************************************************************************
6 # Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
5 # Copyright (C) 2002-2006 Fernando Perez. <fperez@colorado.edu>
7 #
6 #
8 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
9 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
10 #*****************************************************************************
9 #*****************************************************************************
11
10
12 __all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable']
13
11
14 import os
12 import os
15
13
16 from IPython.utils.ipstruct import Struct
14 from IPython.utils.ipstruct import Struct
17
15
16 __all__ = ["TermColors", "InputTermColors", "ColorScheme", "ColorSchemeTable"]
17
18 color_templates = (
18 color_templates = (
19 # Dark colors
19 # Dark colors
20 ("Black" , "0;30"),
20 ("Black" , "0;30"),
21 ("Red" , "0;31"),
21 ("Red" , "0;31"),
22 ("Green" , "0;32"),
22 ("Green" , "0;32"),
23 ("Brown" , "0;33"),
23 ("Brown" , "0;33"),
24 ("Blue" , "0;34"),
24 ("Blue" , "0;34"),
25 ("Purple" , "0;35"),
25 ("Purple" , "0;35"),
26 ("Cyan" , "0;36"),
26 ("Cyan" , "0;36"),
27 ("LightGray" , "0;37"),
27 ("LightGray" , "0;37"),
28 # Light colors
28 # Light colors
29 ("DarkGray" , "1;30"),
29 ("DarkGray" , "1;30"),
30 ("LightRed" , "1;31"),
30 ("LightRed" , "1;31"),
31 ("LightGreen" , "1;32"),
31 ("LightGreen" , "1;32"),
32 ("Yellow" , "1;33"),
32 ("Yellow" , "1;33"),
33 ("LightBlue" , "1;34"),
33 ("LightBlue" , "1;34"),
34 ("LightPurple" , "1;35"),
34 ("LightPurple" , "1;35"),
35 ("LightCyan" , "1;36"),
35 ("LightCyan" , "1;36"),
36 ("White" , "1;37"),
36 ("White" , "1;37"),
37 # Blinking colors. Probably should not be used in anything serious.
37 # Blinking colors. Probably should not be used in anything serious.
38 ("BlinkBlack" , "5;30"),
38 ("BlinkBlack" , "5;30"),
39 ("BlinkRed" , "5;31"),
39 ("BlinkRed" , "5;31"),
40 ("BlinkGreen" , "5;32"),
40 ("BlinkGreen" , "5;32"),
41 ("BlinkYellow" , "5;33"),
41 ("BlinkYellow" , "5;33"),
42 ("BlinkBlue" , "5;34"),
42 ("BlinkBlue" , "5;34"),
43 ("BlinkPurple" , "5;35"),
43 ("BlinkPurple" , "5;35"),
44 ("BlinkCyan" , "5;36"),
44 ("BlinkCyan" , "5;36"),
45 ("BlinkLightGray", "5;37"),
45 ("BlinkLightGray", "5;37"),
46 )
46 )
47
47
48 def make_color_table(in_class):
48 def make_color_table(in_class):
49 """Build a set of color attributes in a class.
49 """Build a set of color attributes in a class.
50
50
51 Helper function for building the :class:`TermColors` and
51 Helper function for building the :class:`TermColors` and
52 :class`InputTermColors`.
52 :class`InputTermColors`.
53 """
53 """
54 for name,value in color_templates:
54 for name,value in color_templates:
55 setattr(in_class,name,in_class._base % value)
55 setattr(in_class,name,in_class._base % value)
56
56
57 class TermColors:
57 class TermColors:
58 """Color escape sequences.
58 """Color escape sequences.
59
59
60 This class defines the escape sequences for all the standard (ANSI?)
60 This class defines the escape sequences for all the standard (ANSI?)
61 colors in terminals. Also defines a NoColor escape which is just the null
61 colors in terminals. Also defines a NoColor escape which is just the null
62 string, suitable for defining 'dummy' color schemes in terminals which get
62 string, suitable for defining 'dummy' color schemes in terminals which get
63 confused by color escapes.
63 confused by color escapes.
64
64
65 This class should be used as a mixin for building color schemes."""
65 This class should be used as a mixin for building color schemes."""
66
66
67 NoColor = '' # for color schemes in color-less terminals.
67 NoColor = '' # for color schemes in color-less terminals.
68 Normal = '\033[0m' # Reset normal coloring
68 Normal = '\033[0m' # Reset normal coloring
69 _base = '\033[%sm' # Template for all other colors
69 _base = '\033[%sm' # Template for all other colors
70
70
71 # Build the actual color table as a set of class attributes:
71 # Build the actual color table as a set of class attributes:
72 make_color_table(TermColors)
72 make_color_table(TermColors)
73
73
74 class InputTermColors:
74 class InputTermColors:
75 """Color escape sequences for input prompts.
75 """Color escape sequences for input prompts.
76
76
77 This class is similar to TermColors, but the escapes are wrapped in \\001
77 This class is similar to TermColors, but the escapes are wrapped in \\001
78 and \\002 so that readline can properly know the length of each line and
78 and \\002 so that readline can properly know the length of each line and
79 can wrap lines accordingly. Use this class for any colored text which
79 can wrap lines accordingly. Use this class for any colored text which
80 needs to be used in input prompts, such as in calls to raw_input().
80 needs to be used in input prompts, such as in calls to raw_input().
81
81
82 This class defines the escape sequences for all the standard (ANSI?)
82 This class defines the escape sequences for all the standard (ANSI?)
83 colors in terminals. Also defines a NoColor escape which is just the null
83 colors in terminals. Also defines a NoColor escape which is just the null
84 string, suitable for defining 'dummy' color schemes in terminals which get
84 string, suitable for defining 'dummy' color schemes in terminals which get
85 confused by color escapes.
85 confused by color escapes.
86
86
87 This class should be used as a mixin for building color schemes."""
87 This class should be used as a mixin for building color schemes."""
88
88
89 NoColor = '' # for color schemes in color-less terminals.
89 NoColor = '' # for color schemes in color-less terminals.
90
90
91 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
91 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
92 # (X)emacs on W32 gets confused with \001 and \002 so we remove them
92 # (X)emacs on W32 gets confused with \001 and \002 so we remove them
93 Normal = '\033[0m' # Reset normal coloring
93 Normal = '\033[0m' # Reset normal coloring
94 _base = '\033[%sm' # Template for all other colors
94 _base = '\033[%sm' # Template for all other colors
95 else:
95 else:
96 Normal = '\001\033[0m\002' # Reset normal coloring
96 Normal = '\001\033[0m\002' # Reset normal coloring
97 _base = '\001\033[%sm\002' # Template for all other colors
97 _base = '\001\033[%sm\002' # Template for all other colors
98
98
99 # Build the actual color table as a set of class attributes:
99 # Build the actual color table as a set of class attributes:
100 make_color_table(InputTermColors)
100 make_color_table(InputTermColors)
101
101
102 class NoColors:
102 class NoColors:
103 """This defines all the same names as the colour classes, but maps them to
103 """This defines all the same names as the colour classes, but maps them to
104 empty strings, so it can easily be substituted to turn off colours."""
104 empty strings, so it can easily be substituted to turn off colours."""
105 NoColor = ''
105 NoColor = ''
106 Normal = ''
106 Normal = ''
107
107
108 for name, value in color_templates:
108 for name, value in color_templates:
109 setattr(NoColors, name, '')
109 setattr(NoColors, name, '')
110
110
111 class ColorScheme:
111 class ColorScheme:
112 """Generic color scheme class. Just a name and a Struct."""
112 """Generic color scheme class. Just a name and a Struct."""
113
114 name: str
115 colors: Struct
116
113 def __init__(self,__scheme_name_,colordict=None,**colormap):
117 def __init__(self,__scheme_name_,colordict=None,**colormap):
114 self.name = __scheme_name_
118 self.name = __scheme_name_
115 if colordict is None:
119 if colordict is None:
116 self.colors = Struct(**colormap)
120 self.colors = Struct(**colormap)
117 else:
121 else:
118 self.colors = Struct(colordict)
122 self.colors = Struct(colordict)
119
123
120 def copy(self,name=None):
124 def copy(self,name=None):
121 """Return a full copy of the object, optionally renaming it."""
125 """Return a full copy of the object, optionally renaming it."""
122 if name is None:
126 if name is None:
123 name = self.name
127 name = self.name
124 return ColorScheme(name, self.colors.dict())
128 return ColorScheme(name, self.colors.dict())
125
129
126 class ColorSchemeTable(dict):
130 class ColorSchemeTable(dict):
127 """General class to handle tables of color schemes.
131 """General class to handle tables of color schemes.
128
132
129 It's basically a dict of color schemes with a couple of shorthand
133 It's basically a dict of color schemes with a couple of shorthand
130 attributes and some convenient methods.
134 attributes and some convenient methods.
131
135
132 active_scheme_name -> obvious
136 active_scheme_name -> obvious
133 active_colors -> actual color table of the active scheme"""
137 active_colors -> actual color table of the active scheme"""
134
138
135 def __init__(self, scheme_list=None, default_scheme=''):
139 def __init__(self, scheme_list=None, default_scheme=''):
136 """Create a table of color schemes.
140 """Create a table of color schemes.
137
141
138 The table can be created empty and manually filled or it can be
142 The table can be created empty and manually filled or it can be
139 created with a list of valid color schemes AND the specification for
143 created with a list of valid color schemes AND the specification for
140 the default active scheme.
144 the default active scheme.
141 """
145 """
142
146
143 # create object attributes to be set later
147 # create object attributes to be set later
144 self.active_scheme_name = ''
148 self.active_scheme_name = ''
145 self.active_colors = None
149 self.active_colors = None
146
150
147 if scheme_list:
151 if scheme_list:
148 if default_scheme == '':
152 if default_scheme == '':
149 raise ValueError('you must specify the default color scheme')
153 raise ValueError('you must specify the default color scheme')
150 for scheme in scheme_list:
154 for scheme in scheme_list:
151 self.add_scheme(scheme)
155 self.add_scheme(scheme)
152 self.set_active_scheme(default_scheme)
156 self.set_active_scheme(default_scheme)
153
157
154 def copy(self):
158 def copy(self):
155 """Return full copy of object"""
159 """Return full copy of object"""
156 return ColorSchemeTable(self.values(),self.active_scheme_name)
160 return ColorSchemeTable(self.values(),self.active_scheme_name)
157
161
158 def add_scheme(self,new_scheme):
162 def add_scheme(self,new_scheme):
159 """Add a new color scheme to the table."""
163 """Add a new color scheme to the table."""
160 if not isinstance(new_scheme,ColorScheme):
164 if not isinstance(new_scheme,ColorScheme):
161 raise ValueError('ColorSchemeTable only accepts ColorScheme instances')
165 raise ValueError('ColorSchemeTable only accepts ColorScheme instances')
162 self[new_scheme.name] = new_scheme
166 self[new_scheme.name] = new_scheme
163
167
164 def set_active_scheme(self,scheme,case_sensitive=0):
168 def set_active_scheme(self,scheme,case_sensitive=0):
165 """Set the currently active scheme.
169 """Set the currently active scheme.
166
170
167 Names are by default compared in a case-insensitive way, but this can
171 Names are by default compared in a case-insensitive way, but this can
168 be changed by setting the parameter case_sensitive to true."""
172 be changed by setting the parameter case_sensitive to true."""
169
173
170 scheme_names = list(self.keys())
174 scheme_names = list(self.keys())
171 if case_sensitive:
175 if case_sensitive:
172 valid_schemes = scheme_names
176 valid_schemes = scheme_names
173 scheme_test = scheme
177 scheme_test = scheme
174 else:
178 else:
175 valid_schemes = [s.lower() for s in scheme_names]
179 valid_schemes = [s.lower() for s in scheme_names]
176 scheme_test = scheme.lower()
180 scheme_test = scheme.lower()
177 try:
181 try:
178 scheme_idx = valid_schemes.index(scheme_test)
182 scheme_idx = valid_schemes.index(scheme_test)
179 except ValueError as e:
183 except ValueError as e:
180 raise ValueError('Unrecognized color scheme: ' + scheme + \
184 raise ValueError('Unrecognized color scheme: ' + scheme + \
181 '\nValid schemes: '+str(scheme_names).replace("'', ",'')) from e
185 '\nValid schemes: '+str(scheme_names).replace("'', ",'')) from e
182 else:
186 else:
183 active = scheme_names[scheme_idx]
187 active = scheme_names[scheme_idx]
184 self.active_scheme_name = active
188 self.active_scheme_name = active
185 self.active_colors = self[active].colors
189 self.active_colors = self[active].colors
186 # Now allow using '' as an index for the current active scheme
190 # Now allow using '' as an index for the current active scheme
187 self[''] = self[active]
191 self[''] = self[active]
@@ -1,81 +1,84 b''
1 [build-system]
1 [build-system]
2 requires = ["setuptools >= 51.0.0"]
2 requires = ["setuptools >= 51.0.0"]
3 build-backend = "setuptools.build_meta"
3 build-backend = "setuptools.build_meta"
4
4
5 [tool.mypy]
5 [tool.mypy]
6 python_version = 3.10
6 python_version = "3.10"
7 ignore_missing_imports = true
7 ignore_missing_imports = true
8 follow_imports = 'silent'
8 follow_imports = 'silent'
9 exclude = [
9 exclude = [
10 'test_\.+\.py',
10 'test_\.+\.py',
11 'IPython.utils.tests.test_wildcard',
11 'IPython.utils.tests.test_wildcard',
12 'testing',
12 'testing',
13 'tests',
13 'tests',
14 'PyColorize.py',
14 'PyColorize.py',
15 '_process_win32_controller.py',
15 '_process_win32_controller.py',
16 'IPython/core/application.py',
16 'IPython/core/application.py',
17 'IPython/core/completerlib.py',
17 'IPython/core/completerlib.py',
18 'IPython/core/displaypub.py',
18 'IPython/core/displaypub.py',
19 'IPython/core/historyapp.py',
19 'IPython/core/historyapp.py',
20 #'IPython/core/interactiveshell.py',
20 #'IPython/core/interactiveshell.py',
21 'IPython/core/magic.py',
21 'IPython/core/magic.py',
22 'IPython/core/profileapp.py',
22 'IPython/core/profileapp.py',
23 # 'IPython/core/ultratb.py',
23 # 'IPython/core/ultratb.py',
24 'IPython/lib/deepreload.py',
24 'IPython/lib/deepreload.py',
25 'IPython/lib/pretty.py',
25 'IPython/lib/pretty.py',
26 'IPython/sphinxext/ipython_directive.py',
26 'IPython/sphinxext/ipython_directive.py',
27 'IPython/terminal/ipapp.py',
27 'IPython/terminal/ipapp.py',
28 'IPython/utils/_process_win32.py',
28 'IPython/utils/_process_win32.py',
29 'IPython/utils/path.py',
29 'IPython/utils/path.py',
30 'IPython/utils/timing.py',
30 'IPython/utils/timing.py',
31 'IPython/utils/text.py'
31 'IPython/utils/text.py'
32 ]
32 ]
33
33
34 [tool.pytest.ini_options]
34 [tool.pytest.ini_options]
35 addopts = [
35 addopts = [
36 "--durations=10",
36 "--durations=10",
37 "-pIPython.testing.plugin.pytest_ipdoctest",
37 "-pIPython.testing.plugin.pytest_ipdoctest",
38 "--ipdoctest-modules",
38 "--ipdoctest-modules",
39 "--ignore=docs",
39 "--ignore=docs",
40 "--ignore=examples",
40 "--ignore=examples",
41 "--ignore=htmlcov",
41 "--ignore=htmlcov",
42 "--ignore=ipython_kernel",
42 "--ignore=ipython_kernel",
43 "--ignore=ipython_parallel",
43 "--ignore=ipython_parallel",
44 "--ignore=results",
44 "--ignore=results",
45 "--ignore=tmp",
45 "--ignore=tmp",
46 "--ignore=tools",
46 "--ignore=tools",
47 "--ignore=traitlets",
47 "--ignore=traitlets",
48 "--ignore=IPython/core/tests/daft_extension",
48 "--ignore=IPython/core/tests/daft_extension",
49 "--ignore=IPython/sphinxext",
49 "--ignore=IPython/sphinxext",
50 "--ignore=IPython/terminal/pt_inputhooks",
50 "--ignore=IPython/terminal/pt_inputhooks",
51 "--ignore=IPython/__main__.py",
51 "--ignore=IPython/__main__.py",
52 "--ignore=IPython/external/qt_for_kernel.py",
52 "--ignore=IPython/external/qt_for_kernel.py",
53 "--ignore=IPython/html/widgets/widget_link.py",
53 "--ignore=IPython/html/widgets/widget_link.py",
54 "--ignore=IPython/html/widgets/widget_output.py",
54 "--ignore=IPython/html/widgets/widget_output.py",
55 "--ignore=IPython/terminal/console.py",
55 "--ignore=IPython/terminal/console.py",
56 "--ignore=IPython/utils/_process_cli.py",
56 "--ignore=IPython/utils/_process_cli.py",
57 "--ignore=IPython/utils/_process_posix.py",
57 "--ignore=IPython/utils/_process_posix.py",
58 "--ignore=IPython/utils/_process_win32.py",
58 "--ignore=IPython/utils/_process_win32.py",
59 "--ignore=IPython/utils/_process_win32_controller.py",
59 "--ignore=IPython/utils/_process_win32_controller.py",
60 "--ignore=IPython/utils/daemonize.py",
60 "--ignore=IPython/utils/daemonize.py",
61 "--ignore=IPython/utils/eventful.py",
61 "--ignore=IPython/utils/eventful.py",
62 "--ignore=IPython/kernel",
62 "--ignore=IPython/kernel",
63 "--ignore=IPython/consoleapp.py",
63 "--ignore=IPython/consoleapp.py",
64 "--ignore=IPython/core/inputsplitter.py",
64 "--ignore=IPython/core/inputsplitter.py",
65 "--ignore=IPython/lib/kernel.py",
65 "--ignore=IPython/lib/kernel.py",
66 "--ignore=IPython/utils/jsonutil.py",
66 "--ignore=IPython/utils/jsonutil.py",
67 "--ignore=IPython/utils/localinterfaces.py",
67 "--ignore=IPython/utils/localinterfaces.py",
68 "--ignore=IPython/utils/log.py",
68 "--ignore=IPython/utils/log.py",
69 "--ignore=IPython/utils/signatures.py",
69 "--ignore=IPython/utils/signatures.py",
70 "--ignore=IPython/utils/traitlets.py",
70 "--ignore=IPython/utils/traitlets.py",
71 "--ignore=IPython/utils/version.py"
71 "--ignore=IPython/utils/version.py"
72 ]
72 ]
73 doctest_optionflags = [
73 doctest_optionflags = [
74 "NORMALIZE_WHITESPACE",
74 "NORMALIZE_WHITESPACE",
75 "ELLIPSIS"
75 "ELLIPSIS"
76 ]
76 ]
77 ipdoctest_optionflags = [
77 ipdoctest_optionflags = [
78 "NORMALIZE_WHITESPACE",
78 "NORMALIZE_WHITESPACE",
79 "ELLIPSIS"
79 "ELLIPSIS"
80 ]
80 ]
81 asyncio_mode = "strict"
81 asyncio_mode = "strict"
82
83 [tool.pyright]
84 pythonPlatform="All"
General Comments 0
You need to be logged in to leave comments. Login now