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