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 |
|
|
194 | user_aliases: List = List(default_value=[]).tag(config=True) | |
195 | user_aliases = List(default_value=[]).tag(config=True) |
|
195 | shell = Instance( | |
196 |
|
|
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, |
|
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( |
|
46 | ex_colors.add_scheme( | |
47 |
|
|
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 |
|
|
54 | "filename": C.NoColor, | |
55 |
|
|
55 | "lineno": C.NoColor, | |
56 |
|
|
56 | "name": C.NoColor, | |
57 |
|
|
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 |
|
|
62 | "normalEm": C.NoColor, | |
63 |
nameEm |
|
63 | "filenameEm": C.NoColor, | |
64 |
|
|
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 |
|
|
69 | "excName": C.NoColor, | |
70 |
|
|
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( |
|
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 |
|
|
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 |
|
92 | "normalEm": C.LightCyan, | |
89 |
filenameEm |
|
93 | "filenameEm": C.LightGreen, | |
90 |
linenoEm |
|
94 | "linenoEm": C.LightGreen, | |
91 |
nameEm |
|
95 | "nameEm": C.LightPurple, | |
92 |
valEm |
|
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( |
|
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 |
|
|
115 | "filename": C.LightGreen, | |
111 | vName = C.Cyan, |
|
116 | "lineno": C.LightGreen, | |
112 |
|
|
117 | "name": C.LightPurple, | |
113 |
|
|
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 |
|
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 |
|
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 = |
|
106 | prompt_txt = "".join(s for _, s in tokens) | |
107 |
if prompt_txt and not prompt_txt.endswith( |
|
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 |
|
|
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