##// END OF EJS Templates
Cleaning up old code to simplify 2to3 conversion.
Thomas Kluyver -
Show More
@@ -1,1014 +1,1014 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 Prefiltering components.
4 Prefiltering components.
5
5
6 Prefilters transform user input before it is exec'd by Python. These
6 Prefilters transform user input before it is exec'd by Python. These
7 transforms are used to implement additional syntax such as !ls and %magic.
7 transforms are used to implement additional syntax such as !ls and %magic.
8
8
9 Authors:
9 Authors:
10
10
11 * Brian Granger
11 * Brian Granger
12 * Fernando Perez
12 * Fernando Perez
13 * Dan Milstein
13 * Dan Milstein
14 * Ville Vainio
14 * Ville Vainio
15 """
15 """
16
16
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18 # Copyright (C) 2008-2009 The IPython Development Team
18 # Copyright (C) 2008-2009 The IPython Development Team
19 #
19 #
20 # Distributed under the terms of the BSD License. The full license is in
20 # Distributed under the terms of the BSD License. The full license is in
21 # the file COPYING, distributed as part of this software.
21 # the file COPYING, distributed as part of this software.
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Imports
25 # Imports
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27
27
28 import __builtin__
28 import __builtin__
29 import codeop
29 import codeop
30 import re
30 import re
31
31
32 from IPython.core.alias import AliasManager
32 from IPython.core.alias import AliasManager
33 from IPython.core.autocall import IPyAutocall
33 from IPython.core.autocall import IPyAutocall
34 from IPython.config.configurable import Configurable
34 from IPython.config.configurable import Configurable
35 from IPython.core.splitinput import split_user_input
35 from IPython.core.splitinput import split_user_input
36 from IPython.core import page
36 from IPython.core import page
37
37
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
38 from IPython.utils.traitlets import List, Int, Any, Str, CBool, Bool, Instance
39 import IPython.utils.io
39 import IPython.utils.io
40 from IPython.utils.text import make_quoted_expr
40 from IPython.utils.text import make_quoted_expr
41 from IPython.utils.autoattr import auto_attr
41 from IPython.utils.autoattr import auto_attr
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Global utilities, errors and constants
44 # Global utilities, errors and constants
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 # Warning, these cannot be changed unless various regular expressions
47 # Warning, these cannot be changed unless various regular expressions
48 # are updated in a number of places. Not great, but at least we told you.
48 # are updated in a number of places. Not great, but at least we told you.
49 ESC_SHELL = '!'
49 ESC_SHELL = '!'
50 ESC_SH_CAP = '!!'
50 ESC_SH_CAP = '!!'
51 ESC_HELP = '?'
51 ESC_HELP = '?'
52 ESC_MAGIC = '%'
52 ESC_MAGIC = '%'
53 ESC_QUOTE = ','
53 ESC_QUOTE = ','
54 ESC_QUOTE2 = ';'
54 ESC_QUOTE2 = ';'
55 ESC_PAREN = '/'
55 ESC_PAREN = '/'
56
56
57
57
58 class PrefilterError(Exception):
58 class PrefilterError(Exception):
59 pass
59 pass
60
60
61
61
62 # RegExp to identify potential function names
62 # RegExp to identify potential function names
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
63 re_fun_name = re.compile(r'[a-zA-Z_]([a-zA-Z0-9_.]*) *$')
64
64
65 # RegExp to exclude strings with this start from autocalling. In
65 # RegExp to exclude strings with this start from autocalling. In
66 # particular, all binary operators should be excluded, so that if foo is
66 # particular, all binary operators should be excluded, so that if foo is
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
67 # callable, foo OP bar doesn't become foo(OP bar), which is invalid. The
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
68 # characters '!=()' don't need to be checked for, as the checkPythonChars
69 # routine explicitely does so, to catch direct calls and rebindings of
69 # routine explicitely does so, to catch direct calls and rebindings of
70 # existing names.
70 # existing names.
71
71
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
72 # Warning: the '-' HAS TO BE AT THE END of the first group, otherwise
73 # it affects the rest of the group in square brackets.
73 # it affects the rest of the group in square brackets.
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
74 re_exclude_auto = re.compile(r'^[,&^\|\*/\+-]'
75 r'|^is |^not |^in |^and |^or ')
75 r'|^is |^not |^in |^and |^or ')
76
76
77 # try to catch also methods for stuff in lists/tuples/dicts: off
77 # try to catch also methods for stuff in lists/tuples/dicts: off
78 # (experimental). For this to work, the line_split regexp would need
78 # (experimental). For this to work, the line_split regexp would need
79 # to be modified so it wouldn't break things at '['. That line is
79 # to be modified so it wouldn't break things at '['. That line is
80 # nasty enough that I shouldn't change it until I can test it _well_.
80 # nasty enough that I shouldn't change it until I can test it _well_.
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
81 #self.re_fun_name = re.compile (r'[a-zA-Z_]([a-zA-Z0-9_.\[\]]*) ?$')
82
82
83
83
84 # Handler Check Utilities
84 # Handler Check Utilities
85 def is_shadowed(identifier, ip):
85 def is_shadowed(identifier, ip):
86 """Is the given identifier defined in one of the namespaces which shadow
86 """Is the given identifier defined in one of the namespaces which shadow
87 the alias and magic namespaces? Note that an identifier is different
87 the alias and magic namespaces? Note that an identifier is different
88 than ifun, because it can not contain a '.' character."""
88 than ifun, because it can not contain a '.' character."""
89 # This is much safer than calling ofind, which can change state
89 # This is much safer than calling ofind, which can change state
90 return (identifier in ip.user_ns \
90 return (identifier in ip.user_ns \
91 or identifier in ip.internal_ns \
91 or identifier in ip.internal_ns \
92 or identifier in ip.ns_table['builtin'])
92 or identifier in ip.ns_table['builtin'])
93
93
94
94
95 #-----------------------------------------------------------------------------
95 #-----------------------------------------------------------------------------
96 # The LineInfo class used throughout
96 # The LineInfo class used throughout
97 #-----------------------------------------------------------------------------
97 #-----------------------------------------------------------------------------
98
98
99
99
100 class LineInfo(object):
100 class LineInfo(object):
101 """A single line of input and associated info.
101 """A single line of input and associated info.
102
102
103 Includes the following as properties:
103 Includes the following as properties:
104
104
105 line
105 line
106 The original, raw line
106 The original, raw line
107
107
108 continue_prompt
108 continue_prompt
109 Is this line a continuation in a sequence of multiline input?
109 Is this line a continuation in a sequence of multiline input?
110
110
111 pre
111 pre
112 The initial esc character or whitespace.
112 The initial esc character or whitespace.
113
113
114 pre_char
114 pre_char
115 The escape character(s) in pre or the empty string if there isn't one.
115 The escape character(s) in pre or the empty string if there isn't one.
116 Note that '!!' is a possible value for pre_char. Otherwise it will
116 Note that '!!' is a possible value for pre_char. Otherwise it will
117 always be a single character.
117 always be a single character.
118
118
119 pre_whitespace
119 pre_whitespace
120 The leading whitespace from pre if it exists. If there is a pre_char,
120 The leading whitespace from pre if it exists. If there is a pre_char,
121 this is just ''.
121 this is just ''.
122
122
123 ifun
123 ifun
124 The 'function part', which is basically the maximal initial sequence
124 The 'function part', which is basically the maximal initial sequence
125 of valid python identifiers and the '.' character. This is what is
125 of valid python identifiers and the '.' character. This is what is
126 checked for alias and magic transformations, used for auto-calling,
126 checked for alias and magic transformations, used for auto-calling,
127 etc.
127 etc.
128
128
129 the_rest
129 the_rest
130 Everything else on the line.
130 Everything else on the line.
131 """
131 """
132 def __init__(self, line, continue_prompt):
132 def __init__(self, line, continue_prompt):
133 self.line = line
133 self.line = line
134 self.continue_prompt = continue_prompt
134 self.continue_prompt = continue_prompt
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
135 self.pre, self.ifun, self.the_rest = split_user_input(line)
136
136
137 self.pre_char = self.pre.strip()
137 self.pre_char = self.pre.strip()
138 if self.pre_char:
138 if self.pre_char:
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
139 self.pre_whitespace = '' # No whitespace allowd before esc chars
140 else:
140 else:
141 self.pre_whitespace = self.pre
141 self.pre_whitespace = self.pre
142
142
143 self._oinfo = None
143 self._oinfo = None
144
144
145 def ofind(self, ip):
145 def ofind(self, ip):
146 """Do a full, attribute-walking lookup of the ifun in the various
146 """Do a full, attribute-walking lookup of the ifun in the various
147 namespaces for the given IPython InteractiveShell instance.
147 namespaces for the given IPython InteractiveShell instance.
148
148
149 Return a dict with keys: found,obj,ospace,ismagic
149 Return a dict with keys: found,obj,ospace,ismagic
150
150
151 Note: can cause state changes because of calling getattr, but should
151 Note: can cause state changes because of calling getattr, but should
152 only be run if autocall is on and if the line hasn't matched any
152 only be run if autocall is on and if the line hasn't matched any
153 other, less dangerous handlers.
153 other, less dangerous handlers.
154
154
155 Does cache the results of the call, so can be called multiple times
155 Does cache the results of the call, so can be called multiple times
156 without worrying about *further* damaging state.
156 without worrying about *further* damaging state.
157 """
157 """
158 if not self._oinfo:
158 if not self._oinfo:
159 # ip.shell._ofind is actually on the Magic class!
159 # ip.shell._ofind is actually on the Magic class!
160 self._oinfo = ip.shell._ofind(self.ifun)
160 self._oinfo = ip.shell._ofind(self.ifun)
161 return self._oinfo
161 return self._oinfo
162
162
163 def __str__(self):
163 def __str__(self):
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
164 return "Lineinfo [%s|%s|%s]" %(self.pre, self.ifun, self.the_rest)
165
165
166
166
167 #-----------------------------------------------------------------------------
167 #-----------------------------------------------------------------------------
168 # Main Prefilter manager
168 # Main Prefilter manager
169 #-----------------------------------------------------------------------------
169 #-----------------------------------------------------------------------------
170
170
171
171
172 class PrefilterManager(Configurable):
172 class PrefilterManager(Configurable):
173 """Main prefilter component.
173 """Main prefilter component.
174
174
175 The IPython prefilter is run on all user input before it is run. The
175 The IPython prefilter is run on all user input before it is run. The
176 prefilter consumes lines of input and produces transformed lines of
176 prefilter consumes lines of input and produces transformed lines of
177 input.
177 input.
178
178
179 The iplementation consists of two phases:
179 The iplementation consists of two phases:
180
180
181 1. Transformers
181 1. Transformers
182 2. Checkers and handlers
182 2. Checkers and handlers
183
183
184 Over time, we plan on deprecating the checkers and handlers and doing
184 Over time, we plan on deprecating the checkers and handlers and doing
185 everything in the transformers.
185 everything in the transformers.
186
186
187 The transformers are instances of :class:`PrefilterTransformer` and have
187 The transformers are instances of :class:`PrefilterTransformer` and have
188 a single method :meth:`transform` that takes a line and returns a
188 a single method :meth:`transform` that takes a line and returns a
189 transformed line. The transformation can be accomplished using any
189 transformed line. The transformation can be accomplished using any
190 tool, but our current ones use regular expressions for speed. We also
190 tool, but our current ones use regular expressions for speed. We also
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
191 ship :mod:`pyparsing` in :mod:`IPython.external` for use in transformers.
192
192
193 After all the transformers have been run, the line is fed to the checkers,
193 After all the transformers have been run, the line is fed to the checkers,
194 which are instances of :class:`PrefilterChecker`. The line is passed to
194 which are instances of :class:`PrefilterChecker`. The line is passed to
195 the :meth:`check` method, which either returns `None` or a
195 the :meth:`check` method, which either returns `None` or a
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
196 :class:`PrefilterHandler` instance. If `None` is returned, the other
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
197 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
198 the line is passed to the :meth:`handle` method of the returned
198 the line is passed to the :meth:`handle` method of the returned
199 handler and no further checkers are tried.
199 handler and no further checkers are tried.
200
200
201 Both transformers and checkers have a `priority` attribute, that determines
201 Both transformers and checkers have a `priority` attribute, that determines
202 the order in which they are called. Smaller priorities are tried first.
202 the order in which they are called. Smaller priorities are tried first.
203
203
204 Both transformers and checkers also have `enabled` attribute, which is
204 Both transformers and checkers also have `enabled` attribute, which is
205 a boolean that determines if the instance is used.
205 a boolean that determines if the instance is used.
206
206
207 Users or developers can change the priority or enabled attribute of
207 Users or developers can change the priority or enabled attribute of
208 transformers or checkers, but they must call the :meth:`sort_checkers`
208 transformers or checkers, but they must call the :meth:`sort_checkers`
209 or :meth:`sort_transformers` method after changing the priority.
209 or :meth:`sort_transformers` method after changing the priority.
210 """
210 """
211
211
212 multi_line_specials = CBool(True, config=True)
212 multi_line_specials = CBool(True, config=True)
213 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
213 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
214
214
215 def __init__(self, shell=None, config=None):
215 def __init__(self, shell=None, config=None):
216 super(PrefilterManager, self).__init__(shell=shell, config=config)
216 super(PrefilterManager, self).__init__(shell=shell, config=config)
217 self.shell = shell
217 self.shell = shell
218 self.init_transformers()
218 self.init_transformers()
219 self.init_handlers()
219 self.init_handlers()
220 self.init_checkers()
220 self.init_checkers()
221
221
222 #-------------------------------------------------------------------------
222 #-------------------------------------------------------------------------
223 # API for managing transformers
223 # API for managing transformers
224 #-------------------------------------------------------------------------
224 #-------------------------------------------------------------------------
225
225
226 def init_transformers(self):
226 def init_transformers(self):
227 """Create the default transformers."""
227 """Create the default transformers."""
228 self._transformers = []
228 self._transformers = []
229 for transformer_cls in _default_transformers:
229 for transformer_cls in _default_transformers:
230 transformer_cls(
230 transformer_cls(
231 shell=self.shell, prefilter_manager=self, config=self.config
231 shell=self.shell, prefilter_manager=self, config=self.config
232 )
232 )
233
233
234 def sort_transformers(self):
234 def sort_transformers(self):
235 """Sort the transformers by priority.
235 """Sort the transformers by priority.
236
236
237 This must be called after the priority of a transformer is changed.
237 This must be called after the priority of a transformer is changed.
238 The :meth:`register_transformer` method calls this automatically.
238 The :meth:`register_transformer` method calls this automatically.
239 """
239 """
240 self._transformers.sort(cmp=lambda x,y: x.priority-y.priority)
240 self._transformers.sort(key=lambda x: x.priority)
241
241
242 @property
242 @property
243 def transformers(self):
243 def transformers(self):
244 """Return a list of checkers, sorted by priority."""
244 """Return a list of checkers, sorted by priority."""
245 return self._transformers
245 return self._transformers
246
246
247 def register_transformer(self, transformer):
247 def register_transformer(self, transformer):
248 """Register a transformer instance."""
248 """Register a transformer instance."""
249 if transformer not in self._transformers:
249 if transformer not in self._transformers:
250 self._transformers.append(transformer)
250 self._transformers.append(transformer)
251 self.sort_transformers()
251 self.sort_transformers()
252
252
253 def unregister_transformer(self, transformer):
253 def unregister_transformer(self, transformer):
254 """Unregister a transformer instance."""
254 """Unregister a transformer instance."""
255 if transformer in self._transformers:
255 if transformer in self._transformers:
256 self._transformers.remove(transformer)
256 self._transformers.remove(transformer)
257
257
258 #-------------------------------------------------------------------------
258 #-------------------------------------------------------------------------
259 # API for managing checkers
259 # API for managing checkers
260 #-------------------------------------------------------------------------
260 #-------------------------------------------------------------------------
261
261
262 def init_checkers(self):
262 def init_checkers(self):
263 """Create the default checkers."""
263 """Create the default checkers."""
264 self._checkers = []
264 self._checkers = []
265 for checker in _default_checkers:
265 for checker in _default_checkers:
266 checker(
266 checker(
267 shell=self.shell, prefilter_manager=self, config=self.config
267 shell=self.shell, prefilter_manager=self, config=self.config
268 )
268 )
269
269
270 def sort_checkers(self):
270 def sort_checkers(self):
271 """Sort the checkers by priority.
271 """Sort the checkers by priority.
272
272
273 This must be called after the priority of a checker is changed.
273 This must be called after the priority of a checker is changed.
274 The :meth:`register_checker` method calls this automatically.
274 The :meth:`register_checker` method calls this automatically.
275 """
275 """
276 self._checkers.sort(cmp=lambda x,y: x.priority-y.priority)
276 self._checkers.sort(key=lambda x: x.priority)
277
277
278 @property
278 @property
279 def checkers(self):
279 def checkers(self):
280 """Return a list of checkers, sorted by priority."""
280 """Return a list of checkers, sorted by priority."""
281 return self._checkers
281 return self._checkers
282
282
283 def register_checker(self, checker):
283 def register_checker(self, checker):
284 """Register a checker instance."""
284 """Register a checker instance."""
285 if checker not in self._checkers:
285 if checker not in self._checkers:
286 self._checkers.append(checker)
286 self._checkers.append(checker)
287 self.sort_checkers()
287 self.sort_checkers()
288
288
289 def unregister_checker(self, checker):
289 def unregister_checker(self, checker):
290 """Unregister a checker instance."""
290 """Unregister a checker instance."""
291 if checker in self._checkers:
291 if checker in self._checkers:
292 self._checkers.remove(checker)
292 self._checkers.remove(checker)
293
293
294 #-------------------------------------------------------------------------
294 #-------------------------------------------------------------------------
295 # API for managing checkers
295 # API for managing checkers
296 #-------------------------------------------------------------------------
296 #-------------------------------------------------------------------------
297
297
298 def init_handlers(self):
298 def init_handlers(self):
299 """Create the default handlers."""
299 """Create the default handlers."""
300 self._handlers = {}
300 self._handlers = {}
301 self._esc_handlers = {}
301 self._esc_handlers = {}
302 for handler in _default_handlers:
302 for handler in _default_handlers:
303 handler(
303 handler(
304 shell=self.shell, prefilter_manager=self, config=self.config
304 shell=self.shell, prefilter_manager=self, config=self.config
305 )
305 )
306
306
307 @property
307 @property
308 def handlers(self):
308 def handlers(self):
309 """Return a dict of all the handlers."""
309 """Return a dict of all the handlers."""
310 return self._handlers
310 return self._handlers
311
311
312 def register_handler(self, name, handler, esc_strings):
312 def register_handler(self, name, handler, esc_strings):
313 """Register a handler instance by name with esc_strings."""
313 """Register a handler instance by name with esc_strings."""
314 self._handlers[name] = handler
314 self._handlers[name] = handler
315 for esc_str in esc_strings:
315 for esc_str in esc_strings:
316 self._esc_handlers[esc_str] = handler
316 self._esc_handlers[esc_str] = handler
317
317
318 def unregister_handler(self, name, handler, esc_strings):
318 def unregister_handler(self, name, handler, esc_strings):
319 """Unregister a handler instance by name with esc_strings."""
319 """Unregister a handler instance by name with esc_strings."""
320 try:
320 try:
321 del self._handlers[name]
321 del self._handlers[name]
322 except KeyError:
322 except KeyError:
323 pass
323 pass
324 for esc_str in esc_strings:
324 for esc_str in esc_strings:
325 h = self._esc_handlers.get(esc_str)
325 h = self._esc_handlers.get(esc_str)
326 if h is handler:
326 if h is handler:
327 del self._esc_handlers[esc_str]
327 del self._esc_handlers[esc_str]
328
328
329 def get_handler_by_name(self, name):
329 def get_handler_by_name(self, name):
330 """Get a handler by its name."""
330 """Get a handler by its name."""
331 return self._handlers.get(name)
331 return self._handlers.get(name)
332
332
333 def get_handler_by_esc(self, esc_str):
333 def get_handler_by_esc(self, esc_str):
334 """Get a handler by its escape string."""
334 """Get a handler by its escape string."""
335 return self._esc_handlers.get(esc_str)
335 return self._esc_handlers.get(esc_str)
336
336
337 #-------------------------------------------------------------------------
337 #-------------------------------------------------------------------------
338 # Main prefiltering API
338 # Main prefiltering API
339 #-------------------------------------------------------------------------
339 #-------------------------------------------------------------------------
340
340
341 def prefilter_line_info(self, line_info):
341 def prefilter_line_info(self, line_info):
342 """Prefilter a line that has been converted to a LineInfo object.
342 """Prefilter a line that has been converted to a LineInfo object.
343
343
344 This implements the checker/handler part of the prefilter pipe.
344 This implements the checker/handler part of the prefilter pipe.
345 """
345 """
346 # print "prefilter_line_info: ", line_info
346 # print "prefilter_line_info: ", line_info
347 handler = self.find_handler(line_info)
347 handler = self.find_handler(line_info)
348 return handler.handle(line_info)
348 return handler.handle(line_info)
349
349
350 def find_handler(self, line_info):
350 def find_handler(self, line_info):
351 """Find a handler for the line_info by trying checkers."""
351 """Find a handler for the line_info by trying checkers."""
352 for checker in self.checkers:
352 for checker in self.checkers:
353 if checker.enabled:
353 if checker.enabled:
354 handler = checker.check(line_info)
354 handler = checker.check(line_info)
355 if handler:
355 if handler:
356 return handler
356 return handler
357 return self.get_handler_by_name('normal')
357 return self.get_handler_by_name('normal')
358
358
359 def transform_line(self, line, continue_prompt):
359 def transform_line(self, line, continue_prompt):
360 """Calls the enabled transformers in order of increasing priority."""
360 """Calls the enabled transformers in order of increasing priority."""
361 for transformer in self.transformers:
361 for transformer in self.transformers:
362 if transformer.enabled:
362 if transformer.enabled:
363 line = transformer.transform(line, continue_prompt)
363 line = transformer.transform(line, continue_prompt)
364 return line
364 return line
365
365
366 def prefilter_line(self, line, continue_prompt=False):
366 def prefilter_line(self, line, continue_prompt=False):
367 """Prefilter a single input line as text.
367 """Prefilter a single input line as text.
368
368
369 This method prefilters a single line of text by calling the
369 This method prefilters a single line of text by calling the
370 transformers and then the checkers/handlers.
370 transformers and then the checkers/handlers.
371 """
371 """
372
372
373 # print "prefilter_line: ", line, continue_prompt
373 # print "prefilter_line: ", line, continue_prompt
374 # All handlers *must* return a value, even if it's blank ('').
374 # All handlers *must* return a value, even if it's blank ('').
375
375
376 # Lines are NOT logged here. Handlers should process the line as
376 # Lines are NOT logged here. Handlers should process the line as
377 # needed, update the cache AND log it (so that the input cache array
377 # needed, update the cache AND log it (so that the input cache array
378 # stays synced).
378 # stays synced).
379
379
380 # save the line away in case we crash, so the post-mortem handler can
380 # save the line away in case we crash, so the post-mortem handler can
381 # record it
381 # record it
382 self.shell._last_input_line = line
382 self.shell._last_input_line = line
383
383
384 if not line:
384 if not line:
385 # Return immediately on purely empty lines, so that if the user
385 # Return immediately on purely empty lines, so that if the user
386 # previously typed some whitespace that started a continuation
386 # previously typed some whitespace that started a continuation
387 # prompt, he can break out of that loop with just an empty line.
387 # prompt, he can break out of that loop with just an empty line.
388 # This is how the default python prompt works.
388 # This is how the default python prompt works.
389
389
390 # Only return if the accumulated input buffer was just whitespace!
390 # Only return if the accumulated input buffer was just whitespace!
391 if ''.join(self.shell.buffer).isspace():
391 if ''.join(self.shell.buffer).isspace():
392 self.shell.buffer[:] = []
392 self.shell.buffer[:] = []
393 return ''
393 return ''
394
394
395 # At this point, we invoke our transformers.
395 # At this point, we invoke our transformers.
396 if not continue_prompt or (continue_prompt and self.multi_line_specials):
396 if not continue_prompt or (continue_prompt and self.multi_line_specials):
397 line = self.transform_line(line, continue_prompt)
397 line = self.transform_line(line, continue_prompt)
398
398
399 # Now we compute line_info for the checkers and handlers
399 # Now we compute line_info for the checkers and handlers
400 line_info = LineInfo(line, continue_prompt)
400 line_info = LineInfo(line, continue_prompt)
401
401
402 # the input history needs to track even empty lines
402 # the input history needs to track even empty lines
403 stripped = line.strip()
403 stripped = line.strip()
404
404
405 normal_handler = self.get_handler_by_name('normal')
405 normal_handler = self.get_handler_by_name('normal')
406 if not stripped:
406 if not stripped:
407 if not continue_prompt:
407 if not continue_prompt:
408 self.shell.displayhook.prompt_count -= 1
408 self.shell.displayhook.prompt_count -= 1
409
409
410 return normal_handler.handle(line_info)
410 return normal_handler.handle(line_info)
411
411
412 # special handlers are only allowed for single line statements
412 # special handlers are only allowed for single line statements
413 if continue_prompt and not self.multi_line_specials:
413 if continue_prompt and not self.multi_line_specials:
414 return normal_handler.handle(line_info)
414 return normal_handler.handle(line_info)
415
415
416 prefiltered = self.prefilter_line_info(line_info)
416 prefiltered = self.prefilter_line_info(line_info)
417 # print "prefiltered line: %r" % prefiltered
417 # print "prefiltered line: %r" % prefiltered
418 return prefiltered
418 return prefiltered
419
419
420 def prefilter_lines(self, lines, continue_prompt=False):
420 def prefilter_lines(self, lines, continue_prompt=False):
421 """Prefilter multiple input lines of text.
421 """Prefilter multiple input lines of text.
422
422
423 This is the main entry point for prefiltering multiple lines of
423 This is the main entry point for prefiltering multiple lines of
424 input. This simply calls :meth:`prefilter_line` for each line of
424 input. This simply calls :meth:`prefilter_line` for each line of
425 input.
425 input.
426
426
427 This covers cases where there are multiple lines in the user entry,
427 This covers cases where there are multiple lines in the user entry,
428 which is the case when the user goes back to a multiline history
428 which is the case when the user goes back to a multiline history
429 entry and presses enter.
429 entry and presses enter.
430 """
430 """
431 llines = lines.rstrip('\n').split('\n')
431 llines = lines.rstrip('\n').split('\n')
432 # We can get multiple lines in one shot, where multiline input 'blends'
432 # We can get multiple lines in one shot, where multiline input 'blends'
433 # into one line, in cases like recalling from the readline history
433 # into one line, in cases like recalling from the readline history
434 # buffer. We need to make sure that in such cases, we correctly
434 # buffer. We need to make sure that in such cases, we correctly
435 # communicate downstream which line is first and which are continuation
435 # communicate downstream which line is first and which are continuation
436 # ones.
436 # ones.
437 if len(llines) > 1:
437 if len(llines) > 1:
438 out = '\n'.join([self.prefilter_line(line, lnum>0)
438 out = '\n'.join([self.prefilter_line(line, lnum>0)
439 for lnum, line in enumerate(llines) ])
439 for lnum, line in enumerate(llines) ])
440 else:
440 else:
441 out = self.prefilter_line(llines[0], continue_prompt)
441 out = self.prefilter_line(llines[0], continue_prompt)
442
442
443 return out
443 return out
444
444
445 #-----------------------------------------------------------------------------
445 #-----------------------------------------------------------------------------
446 # Prefilter transformers
446 # Prefilter transformers
447 #-----------------------------------------------------------------------------
447 #-----------------------------------------------------------------------------
448
448
449
449
450 class PrefilterTransformer(Configurable):
450 class PrefilterTransformer(Configurable):
451 """Transform a line of user input."""
451 """Transform a line of user input."""
452
452
453 priority = Int(100, config=True)
453 priority = Int(100, config=True)
454 # Transformers don't currently use shell or prefilter_manager, but as we
454 # Transformers don't currently use shell or prefilter_manager, but as we
455 # move away from checkers and handlers, they will need them.
455 # move away from checkers and handlers, they will need them.
456 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
456 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
457 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
457 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
458 enabled = Bool(True, config=True)
458 enabled = Bool(True, config=True)
459
459
460 def __init__(self, shell=None, prefilter_manager=None, config=None):
460 def __init__(self, shell=None, prefilter_manager=None, config=None):
461 super(PrefilterTransformer, self).__init__(
461 super(PrefilterTransformer, self).__init__(
462 shell=shell, prefilter_manager=prefilter_manager, config=config
462 shell=shell, prefilter_manager=prefilter_manager, config=config
463 )
463 )
464 self.prefilter_manager.register_transformer(self)
464 self.prefilter_manager.register_transformer(self)
465
465
466 def transform(self, line, continue_prompt):
466 def transform(self, line, continue_prompt):
467 """Transform a line, returning the new one."""
467 """Transform a line, returning the new one."""
468 return None
468 return None
469
469
470 def __repr__(self):
470 def __repr__(self):
471 return "<%s(priority=%r, enabled=%r)>" % (
471 return "<%s(priority=%r, enabled=%r)>" % (
472 self.__class__.__name__, self.priority, self.enabled)
472 self.__class__.__name__, self.priority, self.enabled)
473
473
474
474
475 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
475 _assign_system_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
476 r'\s*=\s*!(?P<cmd>.*)')
476 r'\s*=\s*!(?P<cmd>.*)')
477
477
478
478
479 class AssignSystemTransformer(PrefilterTransformer):
479 class AssignSystemTransformer(PrefilterTransformer):
480 """Handle the `files = !ls` syntax."""
480 """Handle the `files = !ls` syntax."""
481
481
482 priority = Int(100, config=True)
482 priority = Int(100, config=True)
483
483
484 def transform(self, line, continue_prompt):
484 def transform(self, line, continue_prompt):
485 m = _assign_system_re.match(line)
485 m = _assign_system_re.match(line)
486 if m is not None:
486 if m is not None:
487 cmd = m.group('cmd')
487 cmd = m.group('cmd')
488 lhs = m.group('lhs')
488 lhs = m.group('lhs')
489 expr = make_quoted_expr("sc =%s" % cmd)
489 expr = make_quoted_expr("sc =%s" % cmd)
490 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
490 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
491 return new_line
491 return new_line
492 return line
492 return line
493
493
494
494
495 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
495 _assign_magic_re = re.compile(r'(?P<lhs>(\s*)([\w\.]+)((\s*,\s*[\w\.]+)*))'
496 r'\s*=\s*%(?P<cmd>.*)')
496 r'\s*=\s*%(?P<cmd>.*)')
497
497
498 class AssignMagicTransformer(PrefilterTransformer):
498 class AssignMagicTransformer(PrefilterTransformer):
499 """Handle the `a = %who` syntax."""
499 """Handle the `a = %who` syntax."""
500
500
501 priority = Int(200, config=True)
501 priority = Int(200, config=True)
502
502
503 def transform(self, line, continue_prompt):
503 def transform(self, line, continue_prompt):
504 m = _assign_magic_re.match(line)
504 m = _assign_magic_re.match(line)
505 if m is not None:
505 if m is not None:
506 cmd = m.group('cmd')
506 cmd = m.group('cmd')
507 lhs = m.group('lhs')
507 lhs = m.group('lhs')
508 expr = make_quoted_expr(cmd)
508 expr = make_quoted_expr(cmd)
509 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
509 new_line = '%s = get_ipython().magic(%s)' % (lhs, expr)
510 return new_line
510 return new_line
511 return line
511 return line
512
512
513
513
514 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
514 _classic_prompt_re = re.compile(r'(^[ \t]*>>> |^[ \t]*\.\.\. )')
515
515
516 class PyPromptTransformer(PrefilterTransformer):
516 class PyPromptTransformer(PrefilterTransformer):
517 """Handle inputs that start with '>>> ' syntax."""
517 """Handle inputs that start with '>>> ' syntax."""
518
518
519 priority = Int(50, config=True)
519 priority = Int(50, config=True)
520
520
521 def transform(self, line, continue_prompt):
521 def transform(self, line, continue_prompt):
522
522
523 if not line or line.isspace() or line.strip() == '...':
523 if not line or line.isspace() or line.strip() == '...':
524 # This allows us to recognize multiple input prompts separated by
524 # This allows us to recognize multiple input prompts separated by
525 # blank lines and pasted in a single chunk, very common when
525 # blank lines and pasted in a single chunk, very common when
526 # pasting doctests or long tutorial passages.
526 # pasting doctests or long tutorial passages.
527 return ''
527 return ''
528 m = _classic_prompt_re.match(line)
528 m = _classic_prompt_re.match(line)
529 if m:
529 if m:
530 return line[len(m.group(0)):]
530 return line[len(m.group(0)):]
531 else:
531 else:
532 return line
532 return line
533
533
534
534
535 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
535 _ipy_prompt_re = re.compile(r'(^[ \t]*In \[\d+\]: |^[ \t]*\ \ \ \.\.\.+: )')
536
536
537 class IPyPromptTransformer(PrefilterTransformer):
537 class IPyPromptTransformer(PrefilterTransformer):
538 """Handle inputs that start classic IPython prompt syntax."""
538 """Handle inputs that start classic IPython prompt syntax."""
539
539
540 priority = Int(50, config=True)
540 priority = Int(50, config=True)
541
541
542 def transform(self, line, continue_prompt):
542 def transform(self, line, continue_prompt):
543
543
544 if not line or line.isspace() or line.strip() == '...':
544 if not line or line.isspace() or line.strip() == '...':
545 # This allows us to recognize multiple input prompts separated by
545 # This allows us to recognize multiple input prompts separated by
546 # blank lines and pasted in a single chunk, very common when
546 # blank lines and pasted in a single chunk, very common when
547 # pasting doctests or long tutorial passages.
547 # pasting doctests or long tutorial passages.
548 return ''
548 return ''
549 m = _ipy_prompt_re.match(line)
549 m = _ipy_prompt_re.match(line)
550 if m:
550 if m:
551 return line[len(m.group(0)):]
551 return line[len(m.group(0)):]
552 else:
552 else:
553 return line
553 return line
554
554
555 #-----------------------------------------------------------------------------
555 #-----------------------------------------------------------------------------
556 # Prefilter checkers
556 # Prefilter checkers
557 #-----------------------------------------------------------------------------
557 #-----------------------------------------------------------------------------
558
558
559
559
560 class PrefilterChecker(Configurable):
560 class PrefilterChecker(Configurable):
561 """Inspect an input line and return a handler for that line."""
561 """Inspect an input line and return a handler for that line."""
562
562
563 priority = Int(100, config=True)
563 priority = Int(100, config=True)
564 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
564 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
565 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
565 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
566 enabled = Bool(True, config=True)
566 enabled = Bool(True, config=True)
567
567
568 def __init__(self, shell=None, prefilter_manager=None, config=None):
568 def __init__(self, shell=None, prefilter_manager=None, config=None):
569 super(PrefilterChecker, self).__init__(
569 super(PrefilterChecker, self).__init__(
570 shell=shell, prefilter_manager=prefilter_manager, config=config
570 shell=shell, prefilter_manager=prefilter_manager, config=config
571 )
571 )
572 self.prefilter_manager.register_checker(self)
572 self.prefilter_manager.register_checker(self)
573
573
574 def check(self, line_info):
574 def check(self, line_info):
575 """Inspect line_info and return a handler instance or None."""
575 """Inspect line_info and return a handler instance or None."""
576 return None
576 return None
577
577
578 def __repr__(self):
578 def __repr__(self):
579 return "<%s(priority=%r, enabled=%r)>" % (
579 return "<%s(priority=%r, enabled=%r)>" % (
580 self.__class__.__name__, self.priority, self.enabled)
580 self.__class__.__name__, self.priority, self.enabled)
581
581
582
582
583 class EmacsChecker(PrefilterChecker):
583 class EmacsChecker(PrefilterChecker):
584
584
585 priority = Int(100, config=True)
585 priority = Int(100, config=True)
586 enabled = Bool(False, config=True)
586 enabled = Bool(False, config=True)
587
587
588 def check(self, line_info):
588 def check(self, line_info):
589 "Emacs ipython-mode tags certain input lines."
589 "Emacs ipython-mode tags certain input lines."
590 if line_info.line.endswith('# PYTHON-MODE'):
590 if line_info.line.endswith('# PYTHON-MODE'):
591 return self.prefilter_manager.get_handler_by_name('emacs')
591 return self.prefilter_manager.get_handler_by_name('emacs')
592 else:
592 else:
593 return None
593 return None
594
594
595
595
596 class ShellEscapeChecker(PrefilterChecker):
596 class ShellEscapeChecker(PrefilterChecker):
597
597
598 priority = Int(200, config=True)
598 priority = Int(200, config=True)
599
599
600 def check(self, line_info):
600 def check(self, line_info):
601 if line_info.line.lstrip().startswith(ESC_SHELL):
601 if line_info.line.lstrip().startswith(ESC_SHELL):
602 return self.prefilter_manager.get_handler_by_name('shell')
602 return self.prefilter_manager.get_handler_by_name('shell')
603
603
604
604
605 class IPyAutocallChecker(PrefilterChecker):
605 class IPyAutocallChecker(PrefilterChecker):
606
606
607 priority = Int(300, config=True)
607 priority = Int(300, config=True)
608
608
609 def check(self, line_info):
609 def check(self, line_info):
610 "Instances of IPyAutocall in user_ns get autocalled immediately"
610 "Instances of IPyAutocall in user_ns get autocalled immediately"
611 obj = self.shell.user_ns.get(line_info.ifun, None)
611 obj = self.shell.user_ns.get(line_info.ifun, None)
612 if isinstance(obj, IPyAutocall):
612 if isinstance(obj, IPyAutocall):
613 obj.set_ip(self.shell)
613 obj.set_ip(self.shell)
614 return self.prefilter_manager.get_handler_by_name('auto')
614 return self.prefilter_manager.get_handler_by_name('auto')
615 else:
615 else:
616 return None
616 return None
617
617
618
618
619 class MultiLineMagicChecker(PrefilterChecker):
619 class MultiLineMagicChecker(PrefilterChecker):
620
620
621 priority = Int(400, config=True)
621 priority = Int(400, config=True)
622
622
623 def check(self, line_info):
623 def check(self, line_info):
624 "Allow ! and !! in multi-line statements if multi_line_specials is on"
624 "Allow ! and !! in multi-line statements if multi_line_specials is on"
625 # Note that this one of the only places we check the first character of
625 # Note that this one of the only places we check the first character of
626 # ifun and *not* the pre_char. Also note that the below test matches
626 # ifun and *not* the pre_char. Also note that the below test matches
627 # both ! and !!.
627 # both ! and !!.
628 if line_info.continue_prompt \
628 if line_info.continue_prompt \
629 and self.prefilter_manager.multi_line_specials:
629 and self.prefilter_manager.multi_line_specials:
630 if line_info.ifun.startswith(ESC_MAGIC):
630 if line_info.ifun.startswith(ESC_MAGIC):
631 return self.prefilter_manager.get_handler_by_name('magic')
631 return self.prefilter_manager.get_handler_by_name('magic')
632 else:
632 else:
633 return None
633 return None
634
634
635
635
636 class EscCharsChecker(PrefilterChecker):
636 class EscCharsChecker(PrefilterChecker):
637
637
638 priority = Int(500, config=True)
638 priority = Int(500, config=True)
639
639
640 def check(self, line_info):
640 def check(self, line_info):
641 """Check for escape character and return either a handler to handle it,
641 """Check for escape character and return either a handler to handle it,
642 or None if there is no escape char."""
642 or None if there is no escape char."""
643 if line_info.line[-1] == ESC_HELP \
643 if line_info.line[-1] == ESC_HELP \
644 and line_info.pre_char != ESC_SHELL \
644 and line_info.pre_char != ESC_SHELL \
645 and line_info.pre_char != ESC_SH_CAP:
645 and line_info.pre_char != ESC_SH_CAP:
646 # the ? can be at the end, but *not* for either kind of shell escape,
646 # the ? can be at the end, but *not* for either kind of shell escape,
647 # because a ? can be a vaild final char in a shell cmd
647 # because a ? can be a vaild final char in a shell cmd
648 return self.prefilter_manager.get_handler_by_name('help')
648 return self.prefilter_manager.get_handler_by_name('help')
649 else:
649 else:
650 # This returns None like it should if no handler exists
650 # This returns None like it should if no handler exists
651 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
651 return self.prefilter_manager.get_handler_by_esc(line_info.pre_char)
652
652
653
653
654 class AssignmentChecker(PrefilterChecker):
654 class AssignmentChecker(PrefilterChecker):
655
655
656 priority = Int(600, config=True)
656 priority = Int(600, config=True)
657
657
658 def check(self, line_info):
658 def check(self, line_info):
659 """Check to see if user is assigning to a var for the first time, in
659 """Check to see if user is assigning to a var for the first time, in
660 which case we want to avoid any sort of automagic / autocall games.
660 which case we want to avoid any sort of automagic / autocall games.
661
661
662 This allows users to assign to either alias or magic names true python
662 This allows users to assign to either alias or magic names true python
663 variables (the magic/alias systems always take second seat to true
663 variables (the magic/alias systems always take second seat to true
664 python code). E.g. ls='hi', or ls,that=1,2"""
664 python code). E.g. ls='hi', or ls,that=1,2"""
665 if line_info.the_rest:
665 if line_info.the_rest:
666 if line_info.the_rest[0] in '=,':
666 if line_info.the_rest[0] in '=,':
667 return self.prefilter_manager.get_handler_by_name('normal')
667 return self.prefilter_manager.get_handler_by_name('normal')
668 else:
668 else:
669 return None
669 return None
670
670
671
671
672 class AutoMagicChecker(PrefilterChecker):
672 class AutoMagicChecker(PrefilterChecker):
673
673
674 priority = Int(700, config=True)
674 priority = Int(700, config=True)
675
675
676 def check(self, line_info):
676 def check(self, line_info):
677 """If the ifun is magic, and automagic is on, run it. Note: normal,
677 """If the ifun is magic, and automagic is on, run it. Note: normal,
678 non-auto magic would already have been triggered via '%' in
678 non-auto magic would already have been triggered via '%' in
679 check_esc_chars. This just checks for automagic. Also, before
679 check_esc_chars. This just checks for automagic. Also, before
680 triggering the magic handler, make sure that there is nothing in the
680 triggering the magic handler, make sure that there is nothing in the
681 user namespace which could shadow it."""
681 user namespace which could shadow it."""
682 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
682 if not self.shell.automagic or not hasattr(self.shell,'magic_'+line_info.ifun):
683 return None
683 return None
684
684
685 # We have a likely magic method. Make sure we should actually call it.
685 # We have a likely magic method. Make sure we should actually call it.
686 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
686 if line_info.continue_prompt and not self.prefilter_manager.multi_line_specials:
687 return None
687 return None
688
688
689 head = line_info.ifun.split('.',1)[0]
689 head = line_info.ifun.split('.',1)[0]
690 if is_shadowed(head, self.shell):
690 if is_shadowed(head, self.shell):
691 return None
691 return None
692
692
693 return self.prefilter_manager.get_handler_by_name('magic')
693 return self.prefilter_manager.get_handler_by_name('magic')
694
694
695
695
696 class AliasChecker(PrefilterChecker):
696 class AliasChecker(PrefilterChecker):
697
697
698 priority = Int(800, config=True)
698 priority = Int(800, config=True)
699
699
700 def check(self, line_info):
700 def check(self, line_info):
701 "Check if the initital identifier on the line is an alias."
701 "Check if the initital identifier on the line is an alias."
702 # Note: aliases can not contain '.'
702 # Note: aliases can not contain '.'
703 head = line_info.ifun.split('.',1)[0]
703 head = line_info.ifun.split('.',1)[0]
704 if line_info.ifun not in self.shell.alias_manager \
704 if line_info.ifun not in self.shell.alias_manager \
705 or head not in self.shell.alias_manager \
705 or head not in self.shell.alias_manager \
706 or is_shadowed(head, self.shell):
706 or is_shadowed(head, self.shell):
707 return None
707 return None
708
708
709 return self.prefilter_manager.get_handler_by_name('alias')
709 return self.prefilter_manager.get_handler_by_name('alias')
710
710
711
711
712 class PythonOpsChecker(PrefilterChecker):
712 class PythonOpsChecker(PrefilterChecker):
713
713
714 priority = Int(900, config=True)
714 priority = Int(900, config=True)
715
715
716 def check(self, line_info):
716 def check(self, line_info):
717 """If the 'rest' of the line begins with a function call or pretty much
717 """If the 'rest' of the line begins with a function call or pretty much
718 any python operator, we should simply execute the line (regardless of
718 any python operator, we should simply execute the line (regardless of
719 whether or not there's a possible autocall expansion). This avoids
719 whether or not there's a possible autocall expansion). This avoids
720 spurious (and very confusing) geattr() accesses."""
720 spurious (and very confusing) geattr() accesses."""
721 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
721 if line_info.the_rest and line_info.the_rest[0] in '!=()<>,+*/%^&|':
722 return self.prefilter_manager.get_handler_by_name('normal')
722 return self.prefilter_manager.get_handler_by_name('normal')
723 else:
723 else:
724 return None
724 return None
725
725
726
726
727 class AutocallChecker(PrefilterChecker):
727 class AutocallChecker(PrefilterChecker):
728
728
729 priority = Int(1000, config=True)
729 priority = Int(1000, config=True)
730
730
731 def check(self, line_info):
731 def check(self, line_info):
732 "Check if the initial word/function is callable and autocall is on."
732 "Check if the initial word/function is callable and autocall is on."
733 if not self.shell.autocall:
733 if not self.shell.autocall:
734 return None
734 return None
735
735
736 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
736 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
737 if not oinfo['found']:
737 if not oinfo['found']:
738 return None
738 return None
739
739
740 if callable(oinfo['obj']) \
740 if callable(oinfo['obj']) \
741 and (not re_exclude_auto.match(line_info.the_rest)) \
741 and (not re_exclude_auto.match(line_info.the_rest)) \
742 and re_fun_name.match(line_info.ifun):
742 and re_fun_name.match(line_info.ifun):
743 return self.prefilter_manager.get_handler_by_name('auto')
743 return self.prefilter_manager.get_handler_by_name('auto')
744 else:
744 else:
745 return None
745 return None
746
746
747
747
748 #-----------------------------------------------------------------------------
748 #-----------------------------------------------------------------------------
749 # Prefilter handlers
749 # Prefilter handlers
750 #-----------------------------------------------------------------------------
750 #-----------------------------------------------------------------------------
751
751
752
752
753 class PrefilterHandler(Configurable):
753 class PrefilterHandler(Configurable):
754
754
755 handler_name = Str('normal')
755 handler_name = Str('normal')
756 esc_strings = List([])
756 esc_strings = List([])
757 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
757 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
758 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
758 prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager')
759
759
760 def __init__(self, shell=None, prefilter_manager=None, config=None):
760 def __init__(self, shell=None, prefilter_manager=None, config=None):
761 super(PrefilterHandler, self).__init__(
761 super(PrefilterHandler, self).__init__(
762 shell=shell, prefilter_manager=prefilter_manager, config=config
762 shell=shell, prefilter_manager=prefilter_manager, config=config
763 )
763 )
764 self.prefilter_manager.register_handler(
764 self.prefilter_manager.register_handler(
765 self.handler_name,
765 self.handler_name,
766 self,
766 self,
767 self.esc_strings
767 self.esc_strings
768 )
768 )
769
769
770 def handle(self, line_info):
770 def handle(self, line_info):
771 # print "normal: ", line_info
771 # print "normal: ", line_info
772 """Handle normal input lines. Use as a template for handlers."""
772 """Handle normal input lines. Use as a template for handlers."""
773
773
774 # With autoindent on, we need some way to exit the input loop, and I
774 # With autoindent on, we need some way to exit the input loop, and I
775 # don't want to force the user to have to backspace all the way to
775 # don't want to force the user to have to backspace all the way to
776 # clear the line. The rule will be in this case, that either two
776 # clear the line. The rule will be in this case, that either two
777 # lines of pure whitespace in a row, or a line of pure whitespace but
777 # lines of pure whitespace in a row, or a line of pure whitespace but
778 # of a size different to the indent level, will exit the input loop.
778 # of a size different to the indent level, will exit the input loop.
779 line = line_info.line
779 line = line_info.line
780 continue_prompt = line_info.continue_prompt
780 continue_prompt = line_info.continue_prompt
781
781
782 if (continue_prompt and
782 if (continue_prompt and
783 self.shell.autoindent and
783 self.shell.autoindent and
784 line.isspace() and
784 line.isspace() and
785
785
786 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
786 (0 < abs(len(line) - self.shell.indent_current_nsp) <= 2
787 or
787 or
788 not self.shell.buffer
788 not self.shell.buffer
789 or
789 or
790 (self.shell.buffer[-1]).isspace()
790 (self.shell.buffer[-1]).isspace()
791 )
791 )
792 ):
792 ):
793 line = ''
793 line = ''
794
794
795 self.shell.log(line, line, continue_prompt)
795 self.shell.log(line, line, continue_prompt)
796 return line
796 return line
797
797
798 def __str__(self):
798 def __str__(self):
799 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
799 return "<%s(name=%s)>" % (self.__class__.__name__, self.handler_name)
800
800
801
801
802 class AliasHandler(PrefilterHandler):
802 class AliasHandler(PrefilterHandler):
803
803
804 handler_name = Str('alias')
804 handler_name = Str('alias')
805
805
806 def handle(self, line_info):
806 def handle(self, line_info):
807 """Handle alias input lines. """
807 """Handle alias input lines. """
808 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
808 transformed = self.shell.alias_manager.expand_aliases(line_info.ifun,line_info.the_rest)
809 # pre is needed, because it carries the leading whitespace. Otherwise
809 # pre is needed, because it carries the leading whitespace. Otherwise
810 # aliases won't work in indented sections.
810 # aliases won't work in indented sections.
811 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
811 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
812 make_quoted_expr(transformed))
812 make_quoted_expr(transformed))
813
813
814 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
814 self.shell.log(line_info.line, line_out, line_info.continue_prompt)
815 return line_out
815 return line_out
816
816
817
817
818 class ShellEscapeHandler(PrefilterHandler):
818 class ShellEscapeHandler(PrefilterHandler):
819
819
820 handler_name = Str('shell')
820 handler_name = Str('shell')
821 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
821 esc_strings = List([ESC_SHELL, ESC_SH_CAP])
822
822
823 def handle(self, line_info):
823 def handle(self, line_info):
824 """Execute the line in a shell, empty return value"""
824 """Execute the line in a shell, empty return value"""
825 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
825 magic_handler = self.prefilter_manager.get_handler_by_name('magic')
826
826
827 line = line_info.line
827 line = line_info.line
828 if line.lstrip().startswith(ESC_SH_CAP):
828 if line.lstrip().startswith(ESC_SH_CAP):
829 # rewrite LineInfo's line, ifun and the_rest to properly hold the
829 # rewrite LineInfo's line, ifun and the_rest to properly hold the
830 # call to %sx and the actual command to be executed, so
830 # call to %sx and the actual command to be executed, so
831 # handle_magic can work correctly. Note that this works even if
831 # handle_magic can work correctly. Note that this works even if
832 # the line is indented, so it handles multi_line_specials
832 # the line is indented, so it handles multi_line_specials
833 # properly.
833 # properly.
834 new_rest = line.lstrip()[2:]
834 new_rest = line.lstrip()[2:]
835 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
835 line_info.line = '%ssx %s' % (ESC_MAGIC, new_rest)
836 line_info.ifun = 'sx'
836 line_info.ifun = 'sx'
837 line_info.the_rest = new_rest
837 line_info.the_rest = new_rest
838 return magic_handler.handle(line_info)
838 return magic_handler.handle(line_info)
839 else:
839 else:
840 cmd = line.lstrip().lstrip(ESC_SHELL)
840 cmd = line.lstrip().lstrip(ESC_SHELL)
841 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
841 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
842 make_quoted_expr(cmd))
842 make_quoted_expr(cmd))
843 # update cache/log and return
843 # update cache/log and return
844 self.shell.log(line, line_out, line_info.continue_prompt)
844 self.shell.log(line, line_out, line_info.continue_prompt)
845 return line_out
845 return line_out
846
846
847
847
848 class MagicHandler(PrefilterHandler):
848 class MagicHandler(PrefilterHandler):
849
849
850 handler_name = Str('magic')
850 handler_name = Str('magic')
851 esc_strings = List([ESC_MAGIC])
851 esc_strings = List([ESC_MAGIC])
852
852
853 def handle(self, line_info):
853 def handle(self, line_info):
854 """Execute magic functions."""
854 """Execute magic functions."""
855 ifun = line_info.ifun
855 ifun = line_info.ifun
856 the_rest = line_info.the_rest
856 the_rest = line_info.the_rest
857 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
857 cmd = '%sget_ipython().magic(%s)' % (line_info.pre_whitespace,
858 make_quoted_expr(ifun + " " + the_rest))
858 make_quoted_expr(ifun + " " + the_rest))
859 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
859 self.shell.log(line_info.line, cmd, line_info.continue_prompt)
860 return cmd
860 return cmd
861
861
862
862
863 class AutoHandler(PrefilterHandler):
863 class AutoHandler(PrefilterHandler):
864
864
865 handler_name = Str('auto')
865 handler_name = Str('auto')
866 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
866 esc_strings = List([ESC_PAREN, ESC_QUOTE, ESC_QUOTE2])
867
867
868 def handle(self, line_info):
868 def handle(self, line_info):
869 """Handle lines which can be auto-executed, quoting if requested."""
869 """Handle lines which can be auto-executed, quoting if requested."""
870 line = line_info.line
870 line = line_info.line
871 ifun = line_info.ifun
871 ifun = line_info.ifun
872 the_rest = line_info.the_rest
872 the_rest = line_info.the_rest
873 pre = line_info.pre
873 pre = line_info.pre
874 continue_prompt = line_info.continue_prompt
874 continue_prompt = line_info.continue_prompt
875 obj = line_info.ofind(self)['obj']
875 obj = line_info.ofind(self)['obj']
876 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
876 #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg
877
877
878 # This should only be active for single-line input!
878 # This should only be active for single-line input!
879 if continue_prompt:
879 if continue_prompt:
880 self.shell.log(line,line,continue_prompt)
880 self.shell.log(line,line,continue_prompt)
881 return line
881 return line
882
882
883 force_auto = isinstance(obj, IPyAutocall)
883 force_auto = isinstance(obj, IPyAutocall)
884 auto_rewrite = True
884 auto_rewrite = True
885
885
886 if pre == ESC_QUOTE:
886 if pre == ESC_QUOTE:
887 # Auto-quote splitting on whitespace
887 # Auto-quote splitting on whitespace
888 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
888 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
889 elif pre == ESC_QUOTE2:
889 elif pre == ESC_QUOTE2:
890 # Auto-quote whole string
890 # Auto-quote whole string
891 newcmd = '%s("%s")' % (ifun,the_rest)
891 newcmd = '%s("%s")' % (ifun,the_rest)
892 elif pre == ESC_PAREN:
892 elif pre == ESC_PAREN:
893 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
893 newcmd = '%s(%s)' % (ifun,",".join(the_rest.split()))
894 else:
894 else:
895 # Auto-paren.
895 # Auto-paren.
896 # We only apply it to argument-less calls if the autocall
896 # We only apply it to argument-less calls if the autocall
897 # parameter is set to 2. We only need to check that autocall is <
897 # parameter is set to 2. We only need to check that autocall is <
898 # 2, since this function isn't called unless it's at least 1.
898 # 2, since this function isn't called unless it's at least 1.
899 if not the_rest and (self.shell.autocall < 2) and not force_auto:
899 if not the_rest and (self.shell.autocall < 2) and not force_auto:
900 newcmd = '%s %s' % (ifun,the_rest)
900 newcmd = '%s %s' % (ifun,the_rest)
901 auto_rewrite = False
901 auto_rewrite = False
902 else:
902 else:
903 if not force_auto and the_rest.startswith('['):
903 if not force_auto and the_rest.startswith('['):
904 if hasattr(obj,'__getitem__'):
904 if hasattr(obj,'__getitem__'):
905 # Don't autocall in this case: item access for an object
905 # Don't autocall in this case: item access for an object
906 # which is BOTH callable and implements __getitem__.
906 # which is BOTH callable and implements __getitem__.
907 newcmd = '%s %s' % (ifun,the_rest)
907 newcmd = '%s %s' % (ifun,the_rest)
908 auto_rewrite = False
908 auto_rewrite = False
909 else:
909 else:
910 # if the object doesn't support [] access, go ahead and
910 # if the object doesn't support [] access, go ahead and
911 # autocall
911 # autocall
912 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
912 newcmd = '%s(%s)' % (ifun.rstrip(),the_rest)
913 elif the_rest.endswith(';'):
913 elif the_rest.endswith(';'):
914 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
914 newcmd = '%s(%s);' % (ifun.rstrip(),the_rest[:-1])
915 else:
915 else:
916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
916 newcmd = '%s(%s)' % (ifun.rstrip(), the_rest)
917
917
918 if auto_rewrite:
918 if auto_rewrite:
919 self.shell.auto_rewrite_input(newcmd)
919 self.shell.auto_rewrite_input(newcmd)
920
920
921 # log what is now valid Python, not the actual user input (without the
921 # log what is now valid Python, not the actual user input (without the
922 # final newline)
922 # final newline)
923 self.shell.log(line,newcmd,continue_prompt)
923 self.shell.log(line,newcmd,continue_prompt)
924 return newcmd
924 return newcmd
925
925
926
926
927 class HelpHandler(PrefilterHandler):
927 class HelpHandler(PrefilterHandler):
928
928
929 handler_name = Str('help')
929 handler_name = Str('help')
930 esc_strings = List([ESC_HELP])
930 esc_strings = List([ESC_HELP])
931
931
932 def handle(self, line_info):
932 def handle(self, line_info):
933 """Try to get some help for the object.
933 """Try to get some help for the object.
934
934
935 obj? or ?obj -> basic information.
935 obj? or ?obj -> basic information.
936 obj?? or ??obj -> more details.
936 obj?? or ??obj -> more details.
937 """
937 """
938 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
938 normal_handler = self.prefilter_manager.get_handler_by_name('normal')
939 line = line_info.line
939 line = line_info.line
940 # We need to make sure that we don't process lines which would be
940 # We need to make sure that we don't process lines which would be
941 # otherwise valid python, such as "x=1 # what?"
941 # otherwise valid python, such as "x=1 # what?"
942 try:
942 try:
943 codeop.compile_command(line)
943 codeop.compile_command(line)
944 except SyntaxError:
944 except SyntaxError:
945 # We should only handle as help stuff which is NOT valid syntax
945 # We should only handle as help stuff which is NOT valid syntax
946 if line[0]==ESC_HELP:
946 if line[0]==ESC_HELP:
947 line = line[1:]
947 line = line[1:]
948 elif line[-1]==ESC_HELP:
948 elif line[-1]==ESC_HELP:
949 line = line[:-1]
949 line = line[:-1]
950 self.shell.log(line, '#?'+line, line_info.continue_prompt)
950 self.shell.log(line, '#?'+line, line_info.continue_prompt)
951 if line:
951 if line:
952 #print 'line:<%r>' % line # dbg
952 #print 'line:<%r>' % line # dbg
953 self.shell.magic_pinfo(line)
953 self.shell.magic_pinfo(line)
954 else:
954 else:
955 self.shell.show_usage()
955 self.shell.show_usage()
956 return '' # Empty string is needed here!
956 return '' # Empty string is needed here!
957 except:
957 except:
958 raise
958 raise
959 # Pass any other exceptions through to the normal handler
959 # Pass any other exceptions through to the normal handler
960 return normal_handler.handle(line_info)
960 return normal_handler.handle(line_info)
961 else:
961 else:
962 # If the code compiles ok, we should handle it normally
962 # If the code compiles ok, we should handle it normally
963 return normal_handler.handle(line_info)
963 return normal_handler.handle(line_info)
964
964
965
965
966 class EmacsHandler(PrefilterHandler):
966 class EmacsHandler(PrefilterHandler):
967
967
968 handler_name = Str('emacs')
968 handler_name = Str('emacs')
969 esc_strings = List([])
969 esc_strings = List([])
970
970
971 def handle(self, line_info):
971 def handle(self, line_info):
972 """Handle input lines marked by python-mode."""
972 """Handle input lines marked by python-mode."""
973
973
974 # Currently, nothing is done. Later more functionality can be added
974 # Currently, nothing is done. Later more functionality can be added
975 # here if needed.
975 # here if needed.
976
976
977 # The input cache shouldn't be updated
977 # The input cache shouldn't be updated
978 return line_info.line
978 return line_info.line
979
979
980
980
981 #-----------------------------------------------------------------------------
981 #-----------------------------------------------------------------------------
982 # Defaults
982 # Defaults
983 #-----------------------------------------------------------------------------
983 #-----------------------------------------------------------------------------
984
984
985
985
986 _default_transformers = [
986 _default_transformers = [
987 AssignSystemTransformer,
987 AssignSystemTransformer,
988 AssignMagicTransformer,
988 AssignMagicTransformer,
989 PyPromptTransformer,
989 PyPromptTransformer,
990 IPyPromptTransformer,
990 IPyPromptTransformer,
991 ]
991 ]
992
992
993 _default_checkers = [
993 _default_checkers = [
994 EmacsChecker,
994 EmacsChecker,
995 ShellEscapeChecker,
995 ShellEscapeChecker,
996 IPyAutocallChecker,
996 IPyAutocallChecker,
997 MultiLineMagicChecker,
997 MultiLineMagicChecker,
998 EscCharsChecker,
998 EscCharsChecker,
999 AssignmentChecker,
999 AssignmentChecker,
1000 AutoMagicChecker,
1000 AutoMagicChecker,
1001 AliasChecker,
1001 AliasChecker,
1002 PythonOpsChecker,
1002 PythonOpsChecker,
1003 AutocallChecker
1003 AutocallChecker
1004 ]
1004 ]
1005
1005
1006 _default_handlers = [
1006 _default_handlers = [
1007 PrefilterHandler,
1007 PrefilterHandler,
1008 AliasHandler,
1008 AliasHandler,
1009 ShellEscapeHandler,
1009 ShellEscapeHandler,
1010 MagicHandler,
1010 MagicHandler,
1011 AutoHandler,
1011 AutoHandler,
1012 HelpHandler,
1012 HelpHandler,
1013 EmacsHandler
1013 EmacsHandler
1014 ]
1014 ]
@@ -1,276 +1,275 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
2 """String interpolation for Python (by Ka-Ping Yee, 14 Feb 2000).
3
3
4 This module lets you quickly and conveniently interpolate values into
4 This module lets you quickly and conveniently interpolate values into
5 strings (in the flavour of Perl or Tcl, but with less extraneous
5 strings (in the flavour of Perl or Tcl, but with less extraneous
6 punctuation). You get a bit more power than in the other languages,
6 punctuation). You get a bit more power than in the other languages,
7 because this module allows subscripting, slicing, function calls,
7 because this module allows subscripting, slicing, function calls,
8 attribute lookup, or arbitrary expressions. Variables and expressions
8 attribute lookup, or arbitrary expressions. Variables and expressions
9 are evaluated in the namespace of the caller.
9 are evaluated in the namespace of the caller.
10
10
11 The itpl() function returns the result of interpolating a string, and
11 The itpl() function returns the result of interpolating a string, and
12 printpl() prints out an interpolated string. Here are some examples:
12 printpl() prints out an interpolated string. Here are some examples:
13
13
14 from Itpl import printpl
14 from Itpl import printpl
15 printpl("Here is a $string.")
15 printpl("Here is a $string.")
16 printpl("Here is a $module.member.")
16 printpl("Here is a $module.member.")
17 printpl("Here is an $object.member.")
17 printpl("Here is an $object.member.")
18 printpl("Here is a $functioncall(with, arguments).")
18 printpl("Here is a $functioncall(with, arguments).")
19 printpl("Here is an ${arbitrary + expression}.")
19 printpl("Here is an ${arbitrary + expression}.")
20 printpl("Here is an $array[3] member.")
20 printpl("Here is an $array[3] member.")
21 printpl("Here is a $dictionary['member'].")
21 printpl("Here is a $dictionary['member'].")
22
22
23 The filter() function filters a file object so that output through it
23 The filter() function filters a file object so that output through it
24 is interpolated. This lets you produce the illusion that Python knows
24 is interpolated. This lets you produce the illusion that Python knows
25 how to do interpolation:
25 how to do interpolation:
26
26
27 import Itpl
27 import Itpl
28 sys.stdout = Itpl.filter()
28 sys.stdout = Itpl.filter()
29 f = "fancy"
29 f = "fancy"
30 print "Is this not $f?"
30 print "Is this not $f?"
31 print "Standard output has been replaced with a $sys.stdout object."
31 print "Standard output has been replaced with a $sys.stdout object."
32 sys.stdout = Itpl.unfilter()
32 sys.stdout = Itpl.unfilter()
33 print "Okay, back $to $normal."
33 print "Okay, back $to $normal."
34
34
35 Under the hood, the Itpl class represents a string that knows how to
35 Under the hood, the Itpl class represents a string that knows how to
36 interpolate values. An instance of the class parses the string once
36 interpolate values. An instance of the class parses the string once
37 upon initialization; the evaluation and substitution can then be done
37 upon initialization; the evaluation and substitution can then be done
38 each time the instance is evaluated with str(instance). For example:
38 each time the instance is evaluated with str(instance). For example:
39
39
40 from Itpl import Itpl
40 from Itpl import Itpl
41 s = Itpl("Here is $foo.")
41 s = Itpl("Here is $foo.")
42 foo = 5
42 foo = 5
43 print str(s)
43 print str(s)
44 foo = "bar"
44 foo = "bar"
45 print str(s)
45 print str(s)
46 """
46 """
47
47
48 #*****************************************************************************
48 #*****************************************************************************
49 #
49 #
50 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
50 # Copyright (c) 2001 Ka-Ping Yee <ping@lfw.org>
51 #
51 #
52 #
52 #
53 # Published under the terms of the MIT license, hereby reproduced:
53 # Published under the terms of the MIT license, hereby reproduced:
54 #
54 #
55 # Permission is hereby granted, free of charge, to any person obtaining a copy
55 # Permission is hereby granted, free of charge, to any person obtaining a copy
56 # of this software and associated documentation files (the "Software"), to
56 # of this software and associated documentation files (the "Software"), to
57 # deal in the Software without restriction, including without limitation the
57 # deal in the Software without restriction, including without limitation the
58 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
58 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
59 # sell copies of the Software, and to permit persons to whom the Software is
59 # sell copies of the Software, and to permit persons to whom the Software is
60 # furnished to do so, subject to the following conditions:
60 # furnished to do so, subject to the following conditions:
61 #
61 #
62 # The above copyright notice and this permission notice shall be included in
62 # The above copyright notice and this permission notice shall be included in
63 # all copies or substantial portions of the Software.
63 # all copies or substantial portions of the Software.
64 #
64 #
65 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
67 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
69 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
70 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
70 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
71 # IN THE SOFTWARE.
71 # IN THE SOFTWARE.
72 #
72 #
73 #*****************************************************************************
73 #*****************************************************************************
74
74
75 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
75 __author__ = 'Ka-Ping Yee <ping@lfw.org>'
76 __license__ = 'MIT'
76 __license__ = 'MIT'
77
77
78 import string
78 import string
79 import sys
79 import sys
80 from tokenize import tokenprog
80 from tokenize import tokenprog
81 from types import StringType
82
81
83 class ItplError(ValueError):
82 class ItplError(ValueError):
84 def __init__(self, text, pos):
83 def __init__(self, text, pos):
85 self.text = text
84 self.text = text
86 self.pos = pos
85 self.pos = pos
87 def __str__(self):
86 def __str__(self):
88 return "unfinished expression in %s at char %d" % (
87 return "unfinished expression in %s at char %d" % (
89 repr(self.text), self.pos)
88 repr(self.text), self.pos)
90
89
91 def matchorfail(text, pos):
90 def matchorfail(text, pos):
92 match = tokenprog.match(text, pos)
91 match = tokenprog.match(text, pos)
93 if match is None:
92 if match is None:
94 raise ItplError(text, pos)
93 raise ItplError(text, pos)
95 return match, match.end()
94 return match, match.end()
96
95
97 class Itpl:
96 class Itpl:
98 """Class representing a string with interpolation abilities.
97 """Class representing a string with interpolation abilities.
99
98
100 Upon creation, an instance works out what parts of the format
99 Upon creation, an instance works out what parts of the format
101 string are literal and what parts need to be evaluated. The
100 string are literal and what parts need to be evaluated. The
102 evaluation and substitution happens in the namespace of the
101 evaluation and substitution happens in the namespace of the
103 caller when str(instance) is called."""
102 caller when str(instance) is called."""
104
103
105 def __init__(self, format,codec='utf_8',encoding_errors='backslashreplace'):
104 def __init__(self, format,codec='utf_8',encoding_errors='backslashreplace'):
106 """The single mandatory argument to this constructor is a format
105 """The single mandatory argument to this constructor is a format
107 string.
106 string.
108
107
109 The format string is parsed according to the following rules:
108 The format string is parsed according to the following rules:
110
109
111 1. A dollar sign and a name, possibly followed by any of:
110 1. A dollar sign and a name, possibly followed by any of:
112 - an open-paren, and anything up to the matching paren
111 - an open-paren, and anything up to the matching paren
113 - an open-bracket, and anything up to the matching bracket
112 - an open-bracket, and anything up to the matching bracket
114 - a period and a name
113 - a period and a name
115 any number of times, is evaluated as a Python expression.
114 any number of times, is evaluated as a Python expression.
116
115
117 2. A dollar sign immediately followed by an open-brace, and
116 2. A dollar sign immediately followed by an open-brace, and
118 anything up to the matching close-brace, is evaluated as
117 anything up to the matching close-brace, is evaluated as
119 a Python expression.
118 a Python expression.
120
119
121 3. Outside of the expressions described in the above two rules,
120 3. Outside of the expressions described in the above two rules,
122 two dollar signs in a row give you one literal dollar sign.
121 two dollar signs in a row give you one literal dollar sign.
123
122
124 Optional arguments:
123 Optional arguments:
125
124
126 - codec('utf_8'): a string containing the name of a valid Python
125 - codec('utf_8'): a string containing the name of a valid Python
127 codec.
126 codec.
128
127
129 - encoding_errors('backslashreplace'): a string with a valid error handling
128 - encoding_errors('backslashreplace'): a string with a valid error handling
130 policy. See the codecs module documentation for details.
129 policy. See the codecs module documentation for details.
131
130
132 These are used to encode the format string if a call to str() fails on
131 These are used to encode the format string if a call to str() fails on
133 the expanded result."""
132 the expanded result."""
134
133
135 if not isinstance(format,basestring):
134 if not isinstance(format,basestring):
136 raise TypeError, "needs string initializer"
135 raise TypeError, "needs string initializer"
137 self.format = format
136 self.format = format
138 self.codec = codec
137 self.codec = codec
139 self.encoding_errors = encoding_errors
138 self.encoding_errors = encoding_errors
140
139
141 namechars = "abcdefghijklmnopqrstuvwxyz" \
140 namechars = "abcdefghijklmnopqrstuvwxyz" \
142 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
141 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
143 chunks = []
142 chunks = []
144 pos = 0
143 pos = 0
145
144
146 while 1:
145 while 1:
147 dollar = string.find(format, "$", pos)
146 dollar = format.find("$", pos)
148 if dollar < 0: break
147 if dollar < 0: break
149 nextchar = format[dollar+1]
148 nextchar = format[dollar+1]
150
149
151 if nextchar == "{":
150 if nextchar == "{":
152 chunks.append((0, format[pos:dollar]))
151 chunks.append((0, format[pos:dollar]))
153 pos, level = dollar+2, 1
152 pos, level = dollar+2, 1
154 while level:
153 while level:
155 match, pos = matchorfail(format, pos)
154 match, pos = matchorfail(format, pos)
156 tstart, tend = match.regs[3]
155 tstart, tend = match.regs[3]
157 token = format[tstart:tend]
156 token = format[tstart:tend]
158 if token == "{": level = level+1
157 if token == "{": level = level+1
159 elif token == "}": level = level-1
158 elif token == "}": level = level-1
160 chunks.append((1, format[dollar+2:pos-1]))
159 chunks.append((1, format[dollar+2:pos-1]))
161
160
162 elif nextchar in namechars:
161 elif nextchar in namechars:
163 chunks.append((0, format[pos:dollar]))
162 chunks.append((0, format[pos:dollar]))
164 match, pos = matchorfail(format, dollar+1)
163 match, pos = matchorfail(format, dollar+1)
165 while pos < len(format):
164 while pos < len(format):
166 if format[pos] == "." and \
165 if format[pos] == "." and \
167 pos+1 < len(format) and format[pos+1] in namechars:
166 pos+1 < len(format) and format[pos+1] in namechars:
168 match, pos = matchorfail(format, pos+1)
167 match, pos = matchorfail(format, pos+1)
169 elif format[pos] in "([":
168 elif format[pos] in "([":
170 pos, level = pos+1, 1
169 pos, level = pos+1, 1
171 while level:
170 while level:
172 match, pos = matchorfail(format, pos)
171 match, pos = matchorfail(format, pos)
173 tstart, tend = match.regs[3]
172 tstart, tend = match.regs[3]
174 token = format[tstart:tend]
173 token = format[tstart:tend]
175 if token[0] in "([": level = level+1
174 if token[0] in "([": level = level+1
176 elif token[0] in ")]": level = level-1
175 elif token[0] in ")]": level = level-1
177 else: break
176 else: break
178 chunks.append((1, format[dollar+1:pos]))
177 chunks.append((1, format[dollar+1:pos]))
179
178
180 else:
179 else:
181 chunks.append((0, format[pos:dollar+1]))
180 chunks.append((0, format[pos:dollar+1]))
182 pos = dollar + 1 + (nextchar == "$")
181 pos = dollar + 1 + (nextchar == "$")
183
182
184 if pos < len(format): chunks.append((0, format[pos:]))
183 if pos < len(format): chunks.append((0, format[pos:]))
185 self.chunks = chunks
184 self.chunks = chunks
186
185
187 def __repr__(self):
186 def __repr__(self):
188 return "<Itpl %s >" % repr(self.format)
187 return "<Itpl %s >" % repr(self.format)
189
188
190 def _str(self,glob,loc):
189 def _str(self,glob,loc):
191 """Evaluate to a string in the given globals/locals.
190 """Evaluate to a string in the given globals/locals.
192
191
193 The final output is built by calling str(), but if this fails, the
192 The final output is built by calling str(), but if this fails, the
194 result is encoded with the instance's codec and error handling policy,
193 result is encoded with the instance's codec and error handling policy,
195 via a call to out.encode(self.codec,self.encoding_errors)"""
194 via a call to out.encode(self.codec,self.encoding_errors)"""
196 result = []
195 result = []
197 app = result.append
196 app = result.append
198 for live, chunk in self.chunks:
197 for live, chunk in self.chunks:
199 if live: app(str(eval(chunk,glob,loc)))
198 if live: app(str(eval(chunk,glob,loc)))
200 else: app(chunk)
199 else: app(chunk)
201 out = ''.join(result)
200 out = ''.join(result)
202 try:
201 try:
203 return str(out)
202 return str(out)
204 except UnicodeError:
203 except UnicodeError:
205 return out.encode(self.codec,self.encoding_errors)
204 return out.encode(self.codec,self.encoding_errors)
206
205
207 def __str__(self):
206 def __str__(self):
208 """Evaluate and substitute the appropriate parts of the string."""
207 """Evaluate and substitute the appropriate parts of the string."""
209
208
210 # We need to skip enough frames to get to the actual caller outside of
209 # We need to skip enough frames to get to the actual caller outside of
211 # Itpl.
210 # Itpl.
212 frame = sys._getframe(1)
211 frame = sys._getframe(1)
213 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
212 while frame.f_globals["__name__"] == __name__: frame = frame.f_back
214 loc, glob = frame.f_locals, frame.f_globals
213 loc, glob = frame.f_locals, frame.f_globals
215
214
216 return self._str(glob,loc)
215 return self._str(glob,loc)
217
216
218 class ItplNS(Itpl):
217 class ItplNS(Itpl):
219 """Class representing a string with interpolation abilities.
218 """Class representing a string with interpolation abilities.
220
219
221 This inherits from Itpl, but at creation time a namespace is provided
220 This inherits from Itpl, but at creation time a namespace is provided
222 where the evaluation will occur. The interpolation becomes a bit more
221 where the evaluation will occur. The interpolation becomes a bit more
223 efficient, as no traceback needs to be extracte. It also allows the
222 efficient, as no traceback needs to be extracte. It also allows the
224 caller to supply a different namespace for the interpolation to occur than
223 caller to supply a different namespace for the interpolation to occur than
225 its own."""
224 its own."""
226
225
227 def __init__(self, format,globals,locals=None,
226 def __init__(self, format,globals,locals=None,
228 codec='utf_8',encoding_errors='backslashreplace'):
227 codec='utf_8',encoding_errors='backslashreplace'):
229 """ItplNS(format,globals[,locals]) -> interpolating string instance.
228 """ItplNS(format,globals[,locals]) -> interpolating string instance.
230
229
231 This constructor, besides a format string, takes a globals dictionary
230 This constructor, besides a format string, takes a globals dictionary
232 and optionally a locals (which defaults to globals if not provided).
231 and optionally a locals (which defaults to globals if not provided).
233
232
234 For further details, see the Itpl constructor."""
233 For further details, see the Itpl constructor."""
235
234
236 if locals is None:
235 if locals is None:
237 locals = globals
236 locals = globals
238 self.globals = globals
237 self.globals = globals
239 self.locals = locals
238 self.locals = locals
240 Itpl.__init__(self,format,codec,encoding_errors)
239 Itpl.__init__(self,format,codec,encoding_errors)
241
240
242 def __str__(self):
241 def __str__(self):
243 """Evaluate and substitute the appropriate parts of the string."""
242 """Evaluate and substitute the appropriate parts of the string."""
244 return self._str(self.globals,self.locals)
243 return self._str(self.globals,self.locals)
245
244
246 def __repr__(self):
245 def __repr__(self):
247 return "<ItplNS %s >" % repr(self.format)
246 return "<ItplNS %s >" % repr(self.format)
248
247
249 # utilities for fast printing
248 # utilities for fast printing
250 def itpl(text): return str(Itpl(text))
249 def itpl(text): return str(Itpl(text))
251 def printpl(text): print itpl(text)
250 def printpl(text): print itpl(text)
252 # versions with namespace
251 # versions with namespace
253 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
252 def itplns(text,globals,locals=None): return str(ItplNS(text,globals,locals))
254 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
253 def printplns(text,globals,locals=None): print itplns(text,globals,locals)
255
254
256 class ItplFile:
255 class ItplFile:
257 """A file object that filters each write() through an interpolator."""
256 """A file object that filters each write() through an interpolator."""
258 def __init__(self, file): self.file = file
257 def __init__(self, file): self.file = file
259 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
258 def __repr__(self): return "<interpolated " + repr(self.file) + ">"
260 def __getattr__(self, attr): return getattr(self.file, attr)
259 def __getattr__(self, attr): return getattr(self.file, attr)
261 def write(self, text): self.file.write(str(Itpl(text)))
260 def write(self, text): self.file.write(str(Itpl(text)))
262
261
263 def filter(file=sys.stdout):
262 def filter(file=sys.stdout):
264 """Return an ItplFile that filters writes to the given file object.
263 """Return an ItplFile that filters writes to the given file object.
265
264
266 'file = filter(file)' replaces 'file' with a filtered object that
265 'file = filter(file)' replaces 'file' with a filtered object that
267 has a write() method. When called with no argument, this creates
266 has a write() method. When called with no argument, this creates
268 a filter to sys.stdout."""
267 a filter to sys.stdout."""
269 return ItplFile(file)
268 return ItplFile(file)
270
269
271 def unfilter(ifile=None):
270 def unfilter(ifile=None):
272 """Return the original file that corresponds to the given ItplFile.
271 """Return the original file that corresponds to the given ItplFile.
273
272
274 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
273 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
275 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
274 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
276 return ifile and ifile.file or sys.stdout.file
275 return ifile and ifile.file or sys.stdout.file
@@ -1,973 +1,944 b''
1 """ path.py - An object representing a path to a file or directory.
1 """ path.py - An object representing a path to a file or directory.
2
2
3 Example:
3 Example:
4
4
5 from IPython.external.path import path
5 from IPython.external.path import path
6 d = path('/home/guido/bin')
6 d = path('/home/guido/bin')
7 for f in d.files('*.py'):
7 for f in d.files('*.py'):
8 f.chmod(0755)
8 f.chmod(0755)
9
9
10 This module requires Python 2.2 or later.
10 This module requires Python 2.5 or later.
11
11
12
12
13 URL: http://www.jorendorff.com/articles/python/path
13 URL: http://www.jorendorff.com/articles/python/path
14 Author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
14 Author: Jason Orendorff <jason.orendorff\x40gmail\x2ecom> (and others - see the url!)
15 Date: 9 Mar 2007
15 Date: 9 Mar 2007
16 """
16 """
17
17
18
18
19 # TODO
19 # TODO
20 # - Tree-walking functions don't avoid symlink loops. Matt Harrison
20 # - Tree-walking functions don't avoid symlink loops. Matt Harrison
21 # sent me a patch for this.
21 # sent me a patch for this.
22 # - Bug in write_text(). It doesn't support Universal newline mode.
22 # - Bug in write_text(). It doesn't support Universal newline mode.
23 # - Better error message in listdir() when self isn't a
23 # - Better error message in listdir() when self isn't a
24 # directory. (On Windows, the error message really sucks.)
24 # directory. (On Windows, the error message really sucks.)
25 # - Make sure everything has a good docstring.
25 # - Make sure everything has a good docstring.
26 # - Add methods for regex find and replace.
26 # - Add methods for regex find and replace.
27 # - guess_content_type() method?
27 # - guess_content_type() method?
28 # - Perhaps support arguments to touch().
28 # - Perhaps support arguments to touch().
29
29
30 from __future__ import generators
30 from __future__ import generators
31
31
32 import sys, warnings, os, fnmatch, glob, shutil, codecs
32 import sys, warnings, os, fnmatch, glob, shutil, codecs
33 # deprecated in python 2.6
33 from hashlib import md5
34 warnings.filterwarnings('ignore', r'.*md5.*')
35 import md5
36
34
37 __version__ = '2.2'
35 __version__ = '2.2'
38 __all__ = ['path']
36 __all__ = ['path']
39
37
40 # Platform-specific support for path.owner
38 # Platform-specific support for path.owner
41 if os.name == 'nt':
39 if os.name == 'nt':
42 try:
40 try:
43 import win32security
41 import win32security
44 except ImportError:
42 except ImportError:
45 win32security = None
43 win32security = None
46 else:
44 else:
47 try:
45 try:
48 import pwd
46 import pwd
49 except ImportError:
47 except ImportError:
50 pwd = None
48 pwd = None
51
49
52 # Pre-2.3 support. Are unicode filenames supported?
53 _base = str
54 _getcwd = os.getcwd
55 try:
56 if os.path.supports_unicode_filenames:
57 _base = unicode
58 _getcwd = os.getcwdu
59 except AttributeError:
60 pass
61
62 # Pre-2.3 workaround for booleans
63 try:
64 True, False
65 except NameError:
66 True, False = 1, 0
67
68 # Pre-2.3 workaround for basestring.
69 try:
70 basestring
71 except NameError:
72 basestring = (str, unicode)
73
74 # Universal newline support
75 _textmode = 'r'
76 if hasattr(file, 'newlines'):
77 _textmode = 'U'
78
79
50
80 class TreeWalkWarning(Warning):
51 class TreeWalkWarning(Warning):
81 pass
52 pass
82
53
83 class path(_base):
54 class path(unicode):
84 """ Represents a filesystem path.
55 """ Represents a filesystem path.
85
56
86 For documentation on individual methods, consult their
57 For documentation on individual methods, consult their
87 counterparts in os.path.
58 counterparts in os.path.
88 """
59 """
89
60
90 # --- Special Python methods.
61 # --- Special Python methods.
91
62
92 def __repr__(self):
63 def __repr__(self):
93 return 'path(%s)' % _base.__repr__(self)
64 return 'path(%s)' % unicode.__repr__(self)
94
65
95 # Adding a path and a string yields a path.
66 # Adding a path and a string yields a path.
96 def __add__(self, more):
67 def __add__(self, more):
97 try:
68 try:
98 resultStr = _base.__add__(self, more)
69 resultStr = unicode.__add__(self, more)
99 except TypeError: #Python bug
70 except TypeError: #Python bug
100 resultStr = NotImplemented
71 resultStr = NotImplemented
101 if resultStr is NotImplemented:
72 if resultStr is NotImplemented:
102 return resultStr
73 return resultStr
103 return self.__class__(resultStr)
74 return self.__class__(resultStr)
104
75
105 def __radd__(self, other):
76 def __radd__(self, other):
106 if isinstance(other, basestring):
77 if isinstance(other, basestring):
107 return self.__class__(other.__add__(self))
78 return self.__class__(other.__add__(self))
108 else:
79 else:
109 return NotImplemented
80 return NotImplemented
110
81
111 # The / operator joins paths.
82 # The / operator joins paths.
112 def __div__(self, rel):
83 def __div__(self, rel):
113 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
84 """ fp.__div__(rel) == fp / rel == fp.joinpath(rel)
114
85
115 Join two path components, adding a separator character if
86 Join two path components, adding a separator character if
116 needed.
87 needed.
117 """
88 """
118 return self.__class__(os.path.join(self, rel))
89 return self.__class__(os.path.join(self, rel))
119
90
120 # Make the / operator work even when true division is enabled.
91 # Make the / operator work even when true division is enabled.
121 __truediv__ = __div__
92 __truediv__ = __div__
122
93
123 def getcwd(cls):
94 def getcwd(cls):
124 """ Return the current working directory as a path object. """
95 """ Return the current working directory as a path object. """
125 return cls(_getcwd())
96 return cls(os.getcwdu())
126 getcwd = classmethod(getcwd)
97 getcwd = classmethod(getcwd)
127
98
128
99
129 # --- Operations on path strings.
100 # --- Operations on path strings.
130
101
131 isabs = os.path.isabs
102 isabs = os.path.isabs
132 def abspath(self): return self.__class__(os.path.abspath(self))
103 def abspath(self): return self.__class__(os.path.abspath(self))
133 def normcase(self): return self.__class__(os.path.normcase(self))
104 def normcase(self): return self.__class__(os.path.normcase(self))
134 def normpath(self): return self.__class__(os.path.normpath(self))
105 def normpath(self): return self.__class__(os.path.normpath(self))
135 def realpath(self): return self.__class__(os.path.realpath(self))
106 def realpath(self): return self.__class__(os.path.realpath(self))
136 def expanduser(self): return self.__class__(os.path.expanduser(self))
107 def expanduser(self): return self.__class__(os.path.expanduser(self))
137 def expandvars(self): return self.__class__(os.path.expandvars(self))
108 def expandvars(self): return self.__class__(os.path.expandvars(self))
138 def dirname(self): return self.__class__(os.path.dirname(self))
109 def dirname(self): return self.__class__(os.path.dirname(self))
139 basename = os.path.basename
110 basename = os.path.basename
140
111
141 def expand(self):
112 def expand(self):
142 """ Clean up a filename by calling expandvars(),
113 """ Clean up a filename by calling expandvars(),
143 expanduser(), and normpath() on it.
114 expanduser(), and normpath() on it.
144
115
145 This is commonly everything needed to clean up a filename
116 This is commonly everything needed to clean up a filename
146 read from a configuration file, for example.
117 read from a configuration file, for example.
147 """
118 """
148 return self.expandvars().expanduser().normpath()
119 return self.expandvars().expanduser().normpath()
149
120
150 def _get_namebase(self):
121 def _get_namebase(self):
151 base, ext = os.path.splitext(self.name)
122 base, ext = os.path.splitext(self.name)
152 return base
123 return base
153
124
154 def _get_ext(self):
125 def _get_ext(self):
155 f, ext = os.path.splitext(_base(self))
126 f, ext = os.path.splitext(unicode(self))
156 return ext
127 return ext
157
128
158 def _get_drive(self):
129 def _get_drive(self):
159 drive, r = os.path.splitdrive(self)
130 drive, r = os.path.splitdrive(self)
160 return self.__class__(drive)
131 return self.__class__(drive)
161
132
162 parent = property(
133 parent = property(
163 dirname, None, None,
134 dirname, None, None,
164 """ This path's parent directory, as a new path object.
135 """ This path's parent directory, as a new path object.
165
136
166 For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
137 For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib')
167 """)
138 """)
168
139
169 name = property(
140 name = property(
170 basename, None, None,
141 basename, None, None,
171 """ The name of this file or directory without the full path.
142 """ The name of this file or directory without the full path.
172
143
173 For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
144 For example, path('/usr/local/lib/libpython.so').name == 'libpython.so'
174 """)
145 """)
175
146
176 namebase = property(
147 namebase = property(
177 _get_namebase, None, None,
148 _get_namebase, None, None,
178 """ The same as path.name, but with one file extension stripped off.
149 """ The same as path.name, but with one file extension stripped off.
179
150
180 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
151 For example, path('/home/guido/python.tar.gz').name == 'python.tar.gz',
181 but path('/home/guido/python.tar.gz').namebase == 'python.tar'
152 but path('/home/guido/python.tar.gz').namebase == 'python.tar'
182 """)
153 """)
183
154
184 ext = property(
155 ext = property(
185 _get_ext, None, None,
156 _get_ext, None, None,
186 """ The file extension, for example '.py'. """)
157 """ The file extension, for example '.py'. """)
187
158
188 drive = property(
159 drive = property(
189 _get_drive, None, None,
160 _get_drive, None, None,
190 """ The drive specifier, for example 'C:'.
161 """ The drive specifier, for example 'C:'.
191 This is always empty on systems that don't use drive specifiers.
162 This is always empty on systems that don't use drive specifiers.
192 """)
163 """)
193
164
194 def splitpath(self):
165 def splitpath(self):
195 """ p.splitpath() -> Return (p.parent, p.name). """
166 """ p.splitpath() -> Return (p.parent, p.name). """
196 parent, child = os.path.split(self)
167 parent, child = os.path.split(self)
197 return self.__class__(parent), child
168 return self.__class__(parent), child
198
169
199 def splitdrive(self):
170 def splitdrive(self):
200 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
171 """ p.splitdrive() -> Return (p.drive, <the rest of p>).
201
172
202 Split the drive specifier from this path. If there is
173 Split the drive specifier from this path. If there is
203 no drive specifier, p.drive is empty, so the return value
174 no drive specifier, p.drive is empty, so the return value
204 is simply (path(''), p). This is always the case on Unix.
175 is simply (path(''), p). This is always the case on Unix.
205 """
176 """
206 drive, rel = os.path.splitdrive(self)
177 drive, rel = os.path.splitdrive(self)
207 return self.__class__(drive), rel
178 return self.__class__(drive), rel
208
179
209 def splitext(self):
180 def splitext(self):
210 """ p.splitext() -> Return (p.stripext(), p.ext).
181 """ p.splitext() -> Return (p.stripext(), p.ext).
211
182
212 Split the filename extension from this path and return
183 Split the filename extension from this path and return
213 the two parts. Either part may be empty.
184 the two parts. Either part may be empty.
214
185
215 The extension is everything from '.' to the end of the
186 The extension is everything from '.' to the end of the
216 last path segment. This has the property that if
187 last path segment. This has the property that if
217 (a, b) == p.splitext(), then a + b == p.
188 (a, b) == p.splitext(), then a + b == p.
218 """
189 """
219 filename, ext = os.path.splitext(self)
190 filename, ext = os.path.splitext(self)
220 return self.__class__(filename), ext
191 return self.__class__(filename), ext
221
192
222 def stripext(self):
193 def stripext(self):
223 """ p.stripext() -> Remove one file extension from the path.
194 """ p.stripext() -> Remove one file extension from the path.
224
195
225 For example, path('/home/guido/python.tar.gz').stripext()
196 For example, path('/home/guido/python.tar.gz').stripext()
226 returns path('/home/guido/python.tar').
197 returns path('/home/guido/python.tar').
227 """
198 """
228 return self.splitext()[0]
199 return self.splitext()[0]
229
200
230 if hasattr(os.path, 'splitunc'):
201 if hasattr(os.path, 'splitunc'):
231 def splitunc(self):
202 def splitunc(self):
232 unc, rest = os.path.splitunc(self)
203 unc, rest = os.path.splitunc(self)
233 return self.__class__(unc), rest
204 return self.__class__(unc), rest
234
205
235 def _get_uncshare(self):
206 def _get_uncshare(self):
236 unc, r = os.path.splitunc(self)
207 unc, r = os.path.splitunc(self)
237 return self.__class__(unc)
208 return self.__class__(unc)
238
209
239 uncshare = property(
210 uncshare = property(
240 _get_uncshare, None, None,
211 _get_uncshare, None, None,
241 """ The UNC mount point for this path.
212 """ The UNC mount point for this path.
242 This is empty for paths on local drives. """)
213 This is empty for paths on local drives. """)
243
214
244 def joinpath(self, *args):
215 def joinpath(self, *args):
245 """ Join two or more path components, adding a separator
216 """ Join two or more path components, adding a separator
246 character (os.sep) if needed. Returns a new path
217 character (os.sep) if needed. Returns a new path
247 object.
218 object.
248 """
219 """
249 return self.__class__(os.path.join(self, *args))
220 return self.__class__(os.path.join(self, *args))
250
221
251 def splitall(self):
222 def splitall(self):
252 r""" Return a list of the path components in this path.
223 r""" Return a list of the path components in this path.
253
224
254 The first item in the list will be a path. Its value will be
225 The first item in the list will be a path. Its value will be
255 either os.curdir, os.pardir, empty, or the root directory of
226 either os.curdir, os.pardir, empty, or the root directory of
256 this path (for example, '/' or 'C:\\'). The other items in
227 this path (for example, '/' or 'C:\\'). The other items in
257 the list will be strings.
228 the list will be strings.
258
229
259 path.path.joinpath(*result) will yield the original path.
230 path.path.joinpath(*result) will yield the original path.
260 """
231 """
261 parts = []
232 parts = []
262 loc = self
233 loc = self
263 while loc != os.curdir and loc != os.pardir:
234 while loc != os.curdir and loc != os.pardir:
264 prev = loc
235 prev = loc
265 loc, child = prev.splitpath()
236 loc, child = prev.splitpath()
266 if loc == prev:
237 if loc == prev:
267 break
238 break
268 parts.append(child)
239 parts.append(child)
269 parts.append(loc)
240 parts.append(loc)
270 parts.reverse()
241 parts.reverse()
271 return parts
242 return parts
272
243
273 def relpath(self):
244 def relpath(self):
274 """ Return this path as a relative path,
245 """ Return this path as a relative path,
275 based from the current working directory.
246 based from the current working directory.
276 """
247 """
277 cwd = self.__class__(os.getcwd())
248 cwd = self.__class__(os.getcwd())
278 return cwd.relpathto(self)
249 return cwd.relpathto(self)
279
250
280 def relpathto(self, dest):
251 def relpathto(self, dest):
281 """ Return a relative path from self to dest.
252 """ Return a relative path from self to dest.
282
253
283 If there is no relative path from self to dest, for example if
254 If there is no relative path from self to dest, for example if
284 they reside on different drives in Windows, then this returns
255 they reside on different drives in Windows, then this returns
285 dest.abspath().
256 dest.abspath().
286 """
257 """
287 origin = self.abspath()
258 origin = self.abspath()
288 dest = self.__class__(dest).abspath()
259 dest = self.__class__(dest).abspath()
289
260
290 orig_list = origin.normcase().splitall()
261 orig_list = origin.normcase().splitall()
291 # Don't normcase dest! We want to preserve the case.
262 # Don't normcase dest! We want to preserve the case.
292 dest_list = dest.splitall()
263 dest_list = dest.splitall()
293
264
294 if orig_list[0] != os.path.normcase(dest_list[0]):
265 if orig_list[0] != os.path.normcase(dest_list[0]):
295 # Can't get here from there.
266 # Can't get here from there.
296 return dest
267 return dest
297
268
298 # Find the location where the two paths start to differ.
269 # Find the location where the two paths start to differ.
299 i = 0
270 i = 0
300 for start_seg, dest_seg in zip(orig_list, dest_list):
271 for start_seg, dest_seg in zip(orig_list, dest_list):
301 if start_seg != os.path.normcase(dest_seg):
272 if start_seg != os.path.normcase(dest_seg):
302 break
273 break
303 i += 1
274 i += 1
304
275
305 # Now i is the point where the two paths diverge.
276 # Now i is the point where the two paths diverge.
306 # Need a certain number of "os.pardir"s to work up
277 # Need a certain number of "os.pardir"s to work up
307 # from the origin to the point of divergence.
278 # from the origin to the point of divergence.
308 segments = [os.pardir] * (len(orig_list) - i)
279 segments = [os.pardir] * (len(orig_list) - i)
309 # Need to add the diverging part of dest_list.
280 # Need to add the diverging part of dest_list.
310 segments += dest_list[i:]
281 segments += dest_list[i:]
311 if len(segments) == 0:
282 if len(segments) == 0:
312 # If they happen to be identical, use os.curdir.
283 # If they happen to be identical, use os.curdir.
313 relpath = os.curdir
284 relpath = os.curdir
314 else:
285 else:
315 relpath = os.path.join(*segments)
286 relpath = os.path.join(*segments)
316 return self.__class__(relpath)
287 return self.__class__(relpath)
317
288
318 # --- Listing, searching, walking, and matching
289 # --- Listing, searching, walking, and matching
319
290
320 def listdir(self, pattern=None):
291 def listdir(self, pattern=None):
321 """ D.listdir() -> List of items in this directory.
292 """ D.listdir() -> List of items in this directory.
322
293
323 Use D.files() or D.dirs() instead if you want a listing
294 Use D.files() or D.dirs() instead if you want a listing
324 of just files or just subdirectories.
295 of just files or just subdirectories.
325
296
326 The elements of the list are path objects.
297 The elements of the list are path objects.
327
298
328 With the optional 'pattern' argument, this only lists
299 With the optional 'pattern' argument, this only lists
329 items whose names match the given pattern.
300 items whose names match the given pattern.
330 """
301 """
331 names = os.listdir(self)
302 names = os.listdir(self)
332 if pattern is not None:
303 if pattern is not None:
333 names = fnmatch.filter(names, pattern)
304 names = fnmatch.filter(names, pattern)
334 return [self / child for child in names]
305 return [self / child for child in names]
335
306
336 def dirs(self, pattern=None):
307 def dirs(self, pattern=None):
337 """ D.dirs() -> List of this directory's subdirectories.
308 """ D.dirs() -> List of this directory's subdirectories.
338
309
339 The elements of the list are path objects.
310 The elements of the list are path objects.
340 This does not walk recursively into subdirectories
311 This does not walk recursively into subdirectories
341 (but see path.walkdirs).
312 (but see path.walkdirs).
342
313
343 With the optional 'pattern' argument, this only lists
314 With the optional 'pattern' argument, this only lists
344 directories whose names match the given pattern. For
315 directories whose names match the given pattern. For
345 example, d.dirs('build-*').
316 example, d.dirs('build-*').
346 """
317 """
347 return [p for p in self.listdir(pattern) if p.isdir()]
318 return [p for p in self.listdir(pattern) if p.isdir()]
348
319
349 def files(self, pattern=None):
320 def files(self, pattern=None):
350 """ D.files() -> List of the files in this directory.
321 """ D.files() -> List of the files in this directory.
351
322
352 The elements of the list are path objects.
323 The elements of the list are path objects.
353 This does not walk into subdirectories (see path.walkfiles).
324 This does not walk into subdirectories (see path.walkfiles).
354
325
355 With the optional 'pattern' argument, this only lists files
326 With the optional 'pattern' argument, this only lists files
356 whose names match the given pattern. For example,
327 whose names match the given pattern. For example,
357 d.files('*.pyc').
328 d.files('*.pyc').
358 """
329 """
359
330
360 return [p for p in self.listdir(pattern) if p.isfile()]
331 return [p for p in self.listdir(pattern) if p.isfile()]
361
332
362 def walk(self, pattern=None, errors='strict'):
333 def walk(self, pattern=None, errors='strict'):
363 """ D.walk() -> iterator over files and subdirs, recursively.
334 """ D.walk() -> iterator over files and subdirs, recursively.
364
335
365 The iterator yields path objects naming each child item of
336 The iterator yields path objects naming each child item of
366 this directory and its descendants. This requires that
337 this directory and its descendants. This requires that
367 D.isdir().
338 D.isdir().
368
339
369 This performs a depth-first traversal of the directory tree.
340 This performs a depth-first traversal of the directory tree.
370 Each directory is returned just before all its children.
341 Each directory is returned just before all its children.
371
342
372 The errors= keyword argument controls behavior when an
343 The errors= keyword argument controls behavior when an
373 error occurs. The default is 'strict', which causes an
344 error occurs. The default is 'strict', which causes an
374 exception. The other allowed values are 'warn', which
345 exception. The other allowed values are 'warn', which
375 reports the error via warnings.warn(), and 'ignore'.
346 reports the error via warnings.warn(), and 'ignore'.
376 """
347 """
377 if errors not in ('strict', 'warn', 'ignore'):
348 if errors not in ('strict', 'warn', 'ignore'):
378 raise ValueError("invalid errors parameter")
349 raise ValueError("invalid errors parameter")
379
350
380 try:
351 try:
381 childList = self.listdir()
352 childList = self.listdir()
382 except Exception:
353 except Exception:
383 if errors == 'ignore':
354 if errors == 'ignore':
384 return
355 return
385 elif errors == 'warn':
356 elif errors == 'warn':
386 warnings.warn(
357 warnings.warn(
387 "Unable to list directory '%s': %s"
358 "Unable to list directory '%s': %s"
388 % (self, sys.exc_info()[1]),
359 % (self, sys.exc_info()[1]),
389 TreeWalkWarning)
360 TreeWalkWarning)
390 return
361 return
391 else:
362 else:
392 raise
363 raise
393
364
394 for child in childList:
365 for child in childList:
395 if pattern is None or child.fnmatch(pattern):
366 if pattern is None or child.fnmatch(pattern):
396 yield child
367 yield child
397 try:
368 try:
398 isdir = child.isdir()
369 isdir = child.isdir()
399 except Exception:
370 except Exception:
400 if errors == 'ignore':
371 if errors == 'ignore':
401 isdir = False
372 isdir = False
402 elif errors == 'warn':
373 elif errors == 'warn':
403 warnings.warn(
374 warnings.warn(
404 "Unable to access '%s': %s"
375 "Unable to access '%s': %s"
405 % (child, sys.exc_info()[1]),
376 % (child, sys.exc_info()[1]),
406 TreeWalkWarning)
377 TreeWalkWarning)
407 isdir = False
378 isdir = False
408 else:
379 else:
409 raise
380 raise
410
381
411 if isdir:
382 if isdir:
412 for item in child.walk(pattern, errors):
383 for item in child.walk(pattern, errors):
413 yield item
384 yield item
414
385
415 def walkdirs(self, pattern=None, errors='strict'):
386 def walkdirs(self, pattern=None, errors='strict'):
416 """ D.walkdirs() -> iterator over subdirs, recursively.
387 """ D.walkdirs() -> iterator over subdirs, recursively.
417
388
418 With the optional 'pattern' argument, this yields only
389 With the optional 'pattern' argument, this yields only
419 directories whose names match the given pattern. For
390 directories whose names match the given pattern. For
420 example, mydir.walkdirs('*test') yields only directories
391 example, mydir.walkdirs('*test') yields only directories
421 with names ending in 'test'.
392 with names ending in 'test'.
422
393
423 The errors= keyword argument controls behavior when an
394 The errors= keyword argument controls behavior when an
424 error occurs. The default is 'strict', which causes an
395 error occurs. The default is 'strict', which causes an
425 exception. The other allowed values are 'warn', which
396 exception. The other allowed values are 'warn', which
426 reports the error via warnings.warn(), and 'ignore'.
397 reports the error via warnings.warn(), and 'ignore'.
427 """
398 """
428 if errors not in ('strict', 'warn', 'ignore'):
399 if errors not in ('strict', 'warn', 'ignore'):
429 raise ValueError("invalid errors parameter")
400 raise ValueError("invalid errors parameter")
430
401
431 try:
402 try:
432 dirs = self.dirs()
403 dirs = self.dirs()
433 except Exception:
404 except Exception:
434 if errors == 'ignore':
405 if errors == 'ignore':
435 return
406 return
436 elif errors == 'warn':
407 elif errors == 'warn':
437 warnings.warn(
408 warnings.warn(
438 "Unable to list directory '%s': %s"
409 "Unable to list directory '%s': %s"
439 % (self, sys.exc_info()[1]),
410 % (self, sys.exc_info()[1]),
440 TreeWalkWarning)
411 TreeWalkWarning)
441 return
412 return
442 else:
413 else:
443 raise
414 raise
444
415
445 for child in dirs:
416 for child in dirs:
446 if pattern is None or child.fnmatch(pattern):
417 if pattern is None or child.fnmatch(pattern):
447 yield child
418 yield child
448 for subsubdir in child.walkdirs(pattern, errors):
419 for subsubdir in child.walkdirs(pattern, errors):
449 yield subsubdir
420 yield subsubdir
450
421
451 def walkfiles(self, pattern=None, errors='strict'):
422 def walkfiles(self, pattern=None, errors='strict'):
452 """ D.walkfiles() -> iterator over files in D, recursively.
423 """ D.walkfiles() -> iterator over files in D, recursively.
453
424
454 The optional argument, pattern, limits the results to files
425 The optional argument, pattern, limits the results to files
455 with names that match the pattern. For example,
426 with names that match the pattern. For example,
456 mydir.walkfiles('*.tmp') yields only files with the .tmp
427 mydir.walkfiles('*.tmp') yields only files with the .tmp
457 extension.
428 extension.
458 """
429 """
459 if errors not in ('strict', 'warn', 'ignore'):
430 if errors not in ('strict', 'warn', 'ignore'):
460 raise ValueError("invalid errors parameter")
431 raise ValueError("invalid errors parameter")
461
432
462 try:
433 try:
463 childList = self.listdir()
434 childList = self.listdir()
464 except Exception:
435 except Exception:
465 if errors == 'ignore':
436 if errors == 'ignore':
466 return
437 return
467 elif errors == 'warn':
438 elif errors == 'warn':
468 warnings.warn(
439 warnings.warn(
469 "Unable to list directory '%s': %s"
440 "Unable to list directory '%s': %s"
470 % (self, sys.exc_info()[1]),
441 % (self, sys.exc_info()[1]),
471 TreeWalkWarning)
442 TreeWalkWarning)
472 return
443 return
473 else:
444 else:
474 raise
445 raise
475
446
476 for child in childList:
447 for child in childList:
477 try:
448 try:
478 isfile = child.isfile()
449 isfile = child.isfile()
479 isdir = not isfile and child.isdir()
450 isdir = not isfile and child.isdir()
480 except:
451 except:
481 if errors == 'ignore':
452 if errors == 'ignore':
482 continue
453 continue
483 elif errors == 'warn':
454 elif errors == 'warn':
484 warnings.warn(
455 warnings.warn(
485 "Unable to access '%s': %s"
456 "Unable to access '%s': %s"
486 % (self, sys.exc_info()[1]),
457 % (self, sys.exc_info()[1]),
487 TreeWalkWarning)
458 TreeWalkWarning)
488 continue
459 continue
489 else:
460 else:
490 raise
461 raise
491
462
492 if isfile:
463 if isfile:
493 if pattern is None or child.fnmatch(pattern):
464 if pattern is None or child.fnmatch(pattern):
494 yield child
465 yield child
495 elif isdir:
466 elif isdir:
496 for f in child.walkfiles(pattern, errors):
467 for f in child.walkfiles(pattern, errors):
497 yield f
468 yield f
498
469
499 def fnmatch(self, pattern):
470 def fnmatch(self, pattern):
500 """ Return True if self.name matches the given pattern.
471 """ Return True if self.name matches the given pattern.
501
472
502 pattern - A filename pattern with wildcards,
473 pattern - A filename pattern with wildcards,
503 for example '*.py'.
474 for example '*.py'.
504 """
475 """
505 return fnmatch.fnmatch(self.name, pattern)
476 return fnmatch.fnmatch(self.name, pattern)
506
477
507 def glob(self, pattern):
478 def glob(self, pattern):
508 """ Return a list of path objects that match the pattern.
479 """ Return a list of path objects that match the pattern.
509
480
510 pattern - a path relative to this directory, with wildcards.
481 pattern - a path relative to this directory, with wildcards.
511
482
512 For example, path('/users').glob('*/bin/*') returns a list
483 For example, path('/users').glob('*/bin/*') returns a list
513 of all the files users have in their bin directories.
484 of all the files users have in their bin directories.
514 """
485 """
515 cls = self.__class__
486 cls = self.__class__
516 return [cls(s) for s in glob.glob(_base(self / pattern))]
487 return [cls(s) for s in glob.glob(unicode(self / pattern))]
517
488
518
489
519 # --- Reading or writing an entire file at once.
490 # --- Reading or writing an entire file at once.
520
491
521 def open(self, mode='r'):
492 def open(self, mode='r'):
522 """ Open this file. Return a file object. """
493 """ Open this file. Return a file object. """
523 return file(self, mode)
494 return open(self, mode)
524
495
525 def bytes(self):
496 def bytes(self):
526 """ Open this file, read all bytes, return them as a string. """
497 """ Open this file, read all bytes, return them as a string. """
527 f = self.open('rb')
498 f = self.open('rb')
528 try:
499 try:
529 return f.read()
500 return f.read()
530 finally:
501 finally:
531 f.close()
502 f.close()
532
503
533 def write_bytes(self, bytes, append=False):
504 def write_bytes(self, bytes, append=False):
534 """ Open this file and write the given bytes to it.
505 """ Open this file and write the given bytes to it.
535
506
536 Default behavior is to overwrite any existing file.
507 Default behavior is to overwrite any existing file.
537 Call p.write_bytes(bytes, append=True) to append instead.
508 Call p.write_bytes(bytes, append=True) to append instead.
538 """
509 """
539 if append:
510 if append:
540 mode = 'ab'
511 mode = 'ab'
541 else:
512 else:
542 mode = 'wb'
513 mode = 'wb'
543 f = self.open(mode)
514 f = self.open(mode)
544 try:
515 try:
545 f.write(bytes)
516 f.write(bytes)
546 finally:
517 finally:
547 f.close()
518 f.close()
548
519
549 def text(self, encoding=None, errors='strict'):
520 def text(self, encoding=None, errors='strict'):
550 r""" Open this file, read it in, return the content as a string.
521 r""" Open this file, read it in, return the content as a string.
551
522
552 This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r'
523 This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r'
553 are automatically translated to '\n'.
524 are automatically translated to '\n'.
554
525
555 Optional arguments:
526 Optional arguments:
556
527
557 encoding - The Unicode encoding (or character set) of
528 encoding - The Unicode encoding (or character set) of
558 the file. If present, the content of the file is
529 the file. If present, the content of the file is
559 decoded and returned as a unicode object; otherwise
530 decoded and returned as a unicode object; otherwise
560 it is returned as an 8-bit str.
531 it is returned as an 8-bit str.
561 errors - How to handle Unicode errors; see help(str.decode)
532 errors - How to handle Unicode errors; see help(str.decode)
562 for the options. Default is 'strict'.
533 for the options. Default is 'strict'.
563 """
534 """
564 if encoding is None:
535 if encoding is None:
565 # 8-bit
536 # 8-bit
566 f = self.open(_textmode)
537 f = self.open('U')
567 try:
538 try:
568 return f.read()
539 return f.read()
569 finally:
540 finally:
570 f.close()
541 f.close()
571 else:
542 else:
572 # Unicode
543 # Unicode
573 f = codecs.open(self, 'r', encoding, errors)
544 f = codecs.open(self, 'r', encoding, errors)
574 # (Note - Can't use 'U' mode here, since codecs.open
545 # (Note - Can't use 'U' mode here, since codecs.open
575 # doesn't support 'U' mode, even in Python 2.3.)
546 # doesn't support 'U' mode, even in Python 2.3.)
576 try:
547 try:
577 t = f.read()
548 t = f.read()
578 finally:
549 finally:
579 f.close()
550 f.close()
580 return (t.replace(u'\r\n', u'\n')
551 return (t.replace(u'\r\n', u'\n')
581 .replace(u'\r\x85', u'\n')
552 .replace(u'\r\x85', u'\n')
582 .replace(u'\r', u'\n')
553 .replace(u'\r', u'\n')
583 .replace(u'\x85', u'\n')
554 .replace(u'\x85', u'\n')
584 .replace(u'\u2028', u'\n'))
555 .replace(u'\u2028', u'\n'))
585
556
586 def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
557 def write_text(self, text, encoding=None, errors='strict', linesep=os.linesep, append=False):
587 r""" Write the given text to this file.
558 r""" Write the given text to this file.
588
559
589 The default behavior is to overwrite any existing file;
560 The default behavior is to overwrite any existing file;
590 to append instead, use the 'append=True' keyword argument.
561 to append instead, use the 'append=True' keyword argument.
591
562
592 There are two differences between path.write_text() and
563 There are two differences between path.write_text() and
593 path.write_bytes(): newline handling and Unicode handling.
564 path.write_bytes(): newline handling and Unicode handling.
594 See below.
565 See below.
595
566
596 Parameters:
567 Parameters:
597
568
598 - text - str/unicode - The text to be written.
569 - text - str/unicode - The text to be written.
599
570
600 - encoding - str - The Unicode encoding that will be used.
571 - encoding - str - The Unicode encoding that will be used.
601 This is ignored if 'text' isn't a Unicode string.
572 This is ignored if 'text' isn't a Unicode string.
602
573
603 - errors - str - How to handle Unicode encoding errors.
574 - errors - str - How to handle Unicode encoding errors.
604 Default is 'strict'. See help(unicode.encode) for the
575 Default is 'strict'. See help(unicode.encode) for the
605 options. This is ignored if 'text' isn't a Unicode
576 options. This is ignored if 'text' isn't a Unicode
606 string.
577 string.
607
578
608 - linesep - keyword argument - str/unicode - The sequence of
579 - linesep - keyword argument - str/unicode - The sequence of
609 characters to be used to mark end-of-line. The default is
580 characters to be used to mark end-of-line. The default is
610 os.linesep. You can also specify None; this means to
581 os.linesep. You can also specify None; this means to
611 leave all newlines as they are in 'text'.
582 leave all newlines as they are in 'text'.
612
583
613 - append - keyword argument - bool - Specifies what to do if
584 - append - keyword argument - bool - Specifies what to do if
614 the file already exists (True: append to the end of it;
585 the file already exists (True: append to the end of it;
615 False: overwrite it.) The default is False.
586 False: overwrite it.) The default is False.
616
587
617
588
618 --- Newline handling.
589 --- Newline handling.
619
590
620 write_text() converts all standard end-of-line sequences
591 write_text() converts all standard end-of-line sequences
621 ('\n', '\r', and '\r\n') to your platform's default end-of-line
592 ('\n', '\r', and '\r\n') to your platform's default end-of-line
622 sequence (see os.linesep; on Windows, for example, the
593 sequence (see os.linesep; on Windows, for example, the
623 end-of-line marker is '\r\n').
594 end-of-line marker is '\r\n').
624
595
625 If you don't like your platform's default, you can override it
596 If you don't like your platform's default, you can override it
626 using the 'linesep=' keyword argument. If you specifically want
597 using the 'linesep=' keyword argument. If you specifically want
627 write_text() to preserve the newlines as-is, use 'linesep=None'.
598 write_text() to preserve the newlines as-is, use 'linesep=None'.
628
599
629 This applies to Unicode text the same as to 8-bit text, except
600 This applies to Unicode text the same as to 8-bit text, except
630 there are three additional standard Unicode end-of-line sequences:
601 there are three additional standard Unicode end-of-line sequences:
631 u'\x85', u'\r\x85', and u'\u2028'.
602 u'\x85', u'\r\x85', and u'\u2028'.
632
603
633 (This is slightly different from when you open a file for
604 (This is slightly different from when you open a file for
634 writing with fopen(filename, "w") in C or file(filename, 'w')
605 writing with fopen(filename, "w") in C or file(filename, 'w')
635 in Python.)
606 in Python.)
636
607
637
608
638 --- Unicode
609 --- Unicode
639
610
640 If 'text' isn't Unicode, then apart from newline handling, the
611 If 'text' isn't Unicode, then apart from newline handling, the
641 bytes are written verbatim to the file. The 'encoding' and
612 bytes are written verbatim to the file. The 'encoding' and
642 'errors' arguments are not used and must be omitted.
613 'errors' arguments are not used and must be omitted.
643
614
644 If 'text' is Unicode, it is first converted to bytes using the
615 If 'text' is Unicode, it is first converted to bytes using the
645 specified 'encoding' (or the default encoding if 'encoding'
616 specified 'encoding' (or the default encoding if 'encoding'
646 isn't specified). The 'errors' argument applies only to this
617 isn't specified). The 'errors' argument applies only to this
647 conversion.
618 conversion.
648
619
649 """
620 """
650 if isinstance(text, unicode):
621 if isinstance(text, unicode):
651 if linesep is not None:
622 if linesep is not None:
652 # Convert all standard end-of-line sequences to
623 # Convert all standard end-of-line sequences to
653 # ordinary newline characters.
624 # ordinary newline characters.
654 text = (text.replace(u'\r\n', u'\n')
625 text = (text.replace(u'\r\n', u'\n')
655 .replace(u'\r\x85', u'\n')
626 .replace(u'\r\x85', u'\n')
656 .replace(u'\r', u'\n')
627 .replace(u'\r', u'\n')
657 .replace(u'\x85', u'\n')
628 .replace(u'\x85', u'\n')
658 .replace(u'\u2028', u'\n'))
629 .replace(u'\u2028', u'\n'))
659 text = text.replace(u'\n', linesep)
630 text = text.replace(u'\n', linesep)
660 if encoding is None:
631 if encoding is None:
661 encoding = sys.getdefaultencoding()
632 encoding = sys.getdefaultencoding()
662 bytes = text.encode(encoding, errors)
633 bytes = text.encode(encoding, errors)
663 else:
634 else:
664 # It is an error to specify an encoding if 'text' is
635 # It is an error to specify an encoding if 'text' is
665 # an 8-bit string.
636 # an 8-bit string.
666 assert encoding is None
637 assert encoding is None
667
638
668 if linesep is not None:
639 if linesep is not None:
669 text = (text.replace('\r\n', '\n')
640 text = (text.replace('\r\n', '\n')
670 .replace('\r', '\n'))
641 .replace('\r', '\n'))
671 bytes = text.replace('\n', linesep)
642 bytes = text.replace('\n', linesep)
672
643
673 self.write_bytes(bytes, append)
644 self.write_bytes(bytes, append)
674
645
675 def lines(self, encoding=None, errors='strict', retain=True):
646 def lines(self, encoding=None, errors='strict', retain=True):
676 r""" Open this file, read all lines, return them in a list.
647 r""" Open this file, read all lines, return them in a list.
677
648
678 Optional arguments:
649 Optional arguments:
679 encoding - The Unicode encoding (or character set) of
650 encoding - The Unicode encoding (or character set) of
680 the file. The default is None, meaning the content
651 the file. The default is None, meaning the content
681 of the file is read as 8-bit characters and returned
652 of the file is read as 8-bit characters and returned
682 as a list of (non-Unicode) str objects.
653 as a list of (non-Unicode) str objects.
683 errors - How to handle Unicode errors; see help(str.decode)
654 errors - How to handle Unicode errors; see help(str.decode)
684 for the options. Default is 'strict'
655 for the options. Default is 'strict'
685 retain - If true, retain newline characters; but all newline
656 retain - If true, retain newline characters; but all newline
686 character combinations ('\r', '\n', '\r\n') are
657 character combinations ('\r', '\n', '\r\n') are
687 translated to '\n'. If false, newline characters are
658 translated to '\n'. If false, newline characters are
688 stripped off. Default is True.
659 stripped off. Default is True.
689
660
690 This uses 'U' mode in Python 2.3 and later.
661 This uses 'U' mode in Python 2.3 and later.
691 """
662 """
692 if encoding is None and retain:
663 if encoding is None and retain:
693 f = self.open(_textmode)
664 f = self.open('U')
694 try:
665 try:
695 return f.readlines()
666 return f.readlines()
696 finally:
667 finally:
697 f.close()
668 f.close()
698 else:
669 else:
699 return self.text(encoding, errors).splitlines(retain)
670 return self.text(encoding, errors).splitlines(retain)
700
671
701 def write_lines(self, lines, encoding=None, errors='strict',
672 def write_lines(self, lines, encoding=None, errors='strict',
702 linesep=os.linesep, append=False):
673 linesep=os.linesep, append=False):
703 r""" Write the given lines of text to this file.
674 r""" Write the given lines of text to this file.
704
675
705 By default this overwrites any existing file at this path.
676 By default this overwrites any existing file at this path.
706
677
707 This puts a platform-specific newline sequence on every line.
678 This puts a platform-specific newline sequence on every line.
708 See 'linesep' below.
679 See 'linesep' below.
709
680
710 lines - A list of strings.
681 lines - A list of strings.
711
682
712 encoding - A Unicode encoding to use. This applies only if
683 encoding - A Unicode encoding to use. This applies only if
713 'lines' contains any Unicode strings.
684 'lines' contains any Unicode strings.
714
685
715 errors - How to handle errors in Unicode encoding. This
686 errors - How to handle errors in Unicode encoding. This
716 also applies only to Unicode strings.
687 also applies only to Unicode strings.
717
688
718 linesep - The desired line-ending. This line-ending is
689 linesep - The desired line-ending. This line-ending is
719 applied to every line. If a line already has any
690 applied to every line. If a line already has any
720 standard line ending ('\r', '\n', '\r\n', u'\x85',
691 standard line ending ('\r', '\n', '\r\n', u'\x85',
721 u'\r\x85', u'\u2028'), that will be stripped off and
692 u'\r\x85', u'\u2028'), that will be stripped off and
722 this will be used instead. The default is os.linesep,
693 this will be used instead. The default is os.linesep,
723 which is platform-dependent ('\r\n' on Windows, '\n' on
694 which is platform-dependent ('\r\n' on Windows, '\n' on
724 Unix, etc.) Specify None to write the lines as-is,
695 Unix, etc.) Specify None to write the lines as-is,
725 like file.writelines().
696 like file.writelines().
726
697
727 Use the keyword argument append=True to append lines to the
698 Use the keyword argument append=True to append lines to the
728 file. The default is to overwrite the file. Warning:
699 file. The default is to overwrite the file. Warning:
729 When you use this with Unicode data, if the encoding of the
700 When you use this with Unicode data, if the encoding of the
730 existing data in the file is different from the encoding
701 existing data in the file is different from the encoding
731 you specify with the encoding= parameter, the result is
702 you specify with the encoding= parameter, the result is
732 mixed-encoding data, which can really confuse someone trying
703 mixed-encoding data, which can really confuse someone trying
733 to read the file later.
704 to read the file later.
734 """
705 """
735 if append:
706 if append:
736 mode = 'ab'
707 mode = 'ab'
737 else:
708 else:
738 mode = 'wb'
709 mode = 'wb'
739 f = self.open(mode)
710 f = self.open(mode)
740 try:
711 try:
741 for line in lines:
712 for line in lines:
742 isUnicode = isinstance(line, unicode)
713 isUnicode = isinstance(line, unicode)
743 if linesep is not None:
714 if linesep is not None:
744 # Strip off any existing line-end and add the
715 # Strip off any existing line-end and add the
745 # specified linesep string.
716 # specified linesep string.
746 if isUnicode:
717 if isUnicode:
747 if line[-2:] in (u'\r\n', u'\x0d\x85'):
718 if line[-2:] in (u'\r\n', u'\x0d\x85'):
748 line = line[:-2]
719 line = line[:-2]
749 elif line[-1:] in (u'\r', u'\n',
720 elif line[-1:] in (u'\r', u'\n',
750 u'\x85', u'\u2028'):
721 u'\x85', u'\u2028'):
751 line = line[:-1]
722 line = line[:-1]
752 else:
723 else:
753 if line[-2:] == '\r\n':
724 if line[-2:] == '\r\n':
754 line = line[:-2]
725 line = line[:-2]
755 elif line[-1:] in ('\r', '\n'):
726 elif line[-1:] in ('\r', '\n'):
756 line = line[:-1]
727 line = line[:-1]
757 line += linesep
728 line += linesep
758 if isUnicode:
729 if isUnicode:
759 if encoding is None:
730 if encoding is None:
760 encoding = sys.getdefaultencoding()
731 encoding = sys.getdefaultencoding()
761 line = line.encode(encoding, errors)
732 line = line.encode(encoding, errors)
762 f.write(line)
733 f.write(line)
763 finally:
734 finally:
764 f.close()
735 f.close()
765
736
766 def read_md5(self):
737 def read_md5(self):
767 """ Calculate the md5 hash for this file.
738 """ Calculate the md5 hash for this file.
768
739
769 This reads through the entire file.
740 This reads through the entire file.
770 """
741 """
771 f = self.open('rb')
742 f = self.open('rb')
772 try:
743 try:
773 m = md5.new()
744 m = md5()
774 while True:
745 while True:
775 d = f.read(8192)
746 d = f.read(8192)
776 if not d:
747 if not d:
777 break
748 break
778 m.update(d)
749 m.update(d)
779 finally:
750 finally:
780 f.close()
751 f.close()
781 return m.digest()
752 return m.digest()
782
753
783 # --- Methods for querying the filesystem.
754 # --- Methods for querying the filesystem.
784
755
785 exists = os.path.exists
756 exists = os.path.exists
786 isdir = os.path.isdir
757 isdir = os.path.isdir
787 isfile = os.path.isfile
758 isfile = os.path.isfile
788 islink = os.path.islink
759 islink = os.path.islink
789 ismount = os.path.ismount
760 ismount = os.path.ismount
790
761
791 if hasattr(os.path, 'samefile'):
762 if hasattr(os.path, 'samefile'):
792 samefile = os.path.samefile
763 samefile = os.path.samefile
793
764
794 getatime = os.path.getatime
765 getatime = os.path.getatime
795 atime = property(
766 atime = property(
796 getatime, None, None,
767 getatime, None, None,
797 """ Last access time of the file. """)
768 """ Last access time of the file. """)
798
769
799 getmtime = os.path.getmtime
770 getmtime = os.path.getmtime
800 mtime = property(
771 mtime = property(
801 getmtime, None, None,
772 getmtime, None, None,
802 """ Last-modified time of the file. """)
773 """ Last-modified time of the file. """)
803
774
804 if hasattr(os.path, 'getctime'):
775 if hasattr(os.path, 'getctime'):
805 getctime = os.path.getctime
776 getctime = os.path.getctime
806 ctime = property(
777 ctime = property(
807 getctime, None, None,
778 getctime, None, None,
808 """ Creation time of the file. """)
779 """ Creation time of the file. """)
809
780
810 getsize = os.path.getsize
781 getsize = os.path.getsize
811 size = property(
782 size = property(
812 getsize, None, None,
783 getsize, None, None,
813 """ Size of the file, in bytes. """)
784 """ Size of the file, in bytes. """)
814
785
815 if hasattr(os, 'access'):
786 if hasattr(os, 'access'):
816 def access(self, mode):
787 def access(self, mode):
817 """ Return true if current user has access to this path.
788 """ Return true if current user has access to this path.
818
789
819 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
790 mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK
820 """
791 """
821 return os.access(self, mode)
792 return os.access(self, mode)
822
793
823 def stat(self):
794 def stat(self):
824 """ Perform a stat() system call on this path. """
795 """ Perform a stat() system call on this path. """
825 return os.stat(self)
796 return os.stat(self)
826
797
827 def lstat(self):
798 def lstat(self):
828 """ Like path.stat(), but do not follow symbolic links. """
799 """ Like path.stat(), but do not follow symbolic links. """
829 return os.lstat(self)
800 return os.lstat(self)
830
801
831 def get_owner(self):
802 def get_owner(self):
832 r""" Return the name of the owner of this file or directory.
803 r""" Return the name of the owner of this file or directory.
833
804
834 This follows symbolic links.
805 This follows symbolic links.
835
806
836 On Windows, this returns a name of the form ur'DOMAIN\User Name'.
807 On Windows, this returns a name of the form ur'DOMAIN\User Name'.
837 On Windows, a group can own a file or directory.
808 On Windows, a group can own a file or directory.
838 """
809 """
839 if os.name == 'nt':
810 if os.name == 'nt':
840 if win32security is None:
811 if win32security is None:
841 raise Exception("path.owner requires win32all to be installed")
812 raise Exception("path.owner requires win32all to be installed")
842 desc = win32security.GetFileSecurity(
813 desc = win32security.GetFileSecurity(
843 self, win32security.OWNER_SECURITY_INFORMATION)
814 self, win32security.OWNER_SECURITY_INFORMATION)
844 sid = desc.GetSecurityDescriptorOwner()
815 sid = desc.GetSecurityDescriptorOwner()
845 account, domain, typecode = win32security.LookupAccountSid(None, sid)
816 account, domain, typecode = win32security.LookupAccountSid(None, sid)
846 return domain + u'\\' + account
817 return domain + u'\\' + account
847 else:
818 else:
848 if pwd is None:
819 if pwd is None:
849 raise NotImplementedError("path.owner is not implemented on this platform.")
820 raise NotImplementedError("path.owner is not implemented on this platform.")
850 st = self.stat()
821 st = self.stat()
851 return pwd.getpwuid(st.st_uid).pw_name
822 return pwd.getpwuid(st.st_uid).pw_name
852
823
853 owner = property(
824 owner = property(
854 get_owner, None, None,
825 get_owner, None, None,
855 """ Name of the owner of this file or directory. """)
826 """ Name of the owner of this file or directory. """)
856
827
857 if hasattr(os, 'statvfs'):
828 if hasattr(os, 'statvfs'):
858 def statvfs(self):
829 def statvfs(self):
859 """ Perform a statvfs() system call on this path. """
830 """ Perform a statvfs() system call on this path. """
860 return os.statvfs(self)
831 return os.statvfs(self)
861
832
862 if hasattr(os, 'pathconf'):
833 if hasattr(os, 'pathconf'):
863 def pathconf(self, name):
834 def pathconf(self, name):
864 return os.pathconf(self, name)
835 return os.pathconf(self, name)
865
836
866
837
867 # --- Modifying operations on files and directories
838 # --- Modifying operations on files and directories
868
839
869 def utime(self, times):
840 def utime(self, times):
870 """ Set the access and modified times of this file. """
841 """ Set the access and modified times of this file. """
871 os.utime(self, times)
842 os.utime(self, times)
872
843
873 def chmod(self, mode):
844 def chmod(self, mode):
874 os.chmod(self, mode)
845 os.chmod(self, mode)
875
846
876 if hasattr(os, 'chown'):
847 if hasattr(os, 'chown'):
877 def chown(self, uid, gid):
848 def chown(self, uid, gid):
878 os.chown(self, uid, gid)
849 os.chown(self, uid, gid)
879
850
880 def rename(self, new):
851 def rename(self, new):
881 os.rename(self, new)
852 os.rename(self, new)
882
853
883 def renames(self, new):
854 def renames(self, new):
884 os.renames(self, new)
855 os.renames(self, new)
885
856
886
857
887 # --- Create/delete operations on directories
858 # --- Create/delete operations on directories
888
859
889 def mkdir(self, mode=0777):
860 def mkdir(self, mode=0777):
890 os.mkdir(self, mode)
861 os.mkdir(self, mode)
891
862
892 def makedirs(self, mode=0777):
863 def makedirs(self, mode=0777):
893 os.makedirs(self, mode)
864 os.makedirs(self, mode)
894
865
895 def rmdir(self):
866 def rmdir(self):
896 os.rmdir(self)
867 os.rmdir(self)
897
868
898 def removedirs(self):
869 def removedirs(self):
899 os.removedirs(self)
870 os.removedirs(self)
900
871
901
872
902 # --- Modifying operations on files
873 # --- Modifying operations on files
903
874
904 def touch(self):
875 def touch(self):
905 """ Set the access/modified times of this file to the current time.
876 """ Set the access/modified times of this file to the current time.
906 Create the file if it does not exist.
877 Create the file if it does not exist.
907 """
878 """
908 fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
879 fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666)
909 os.close(fd)
880 os.close(fd)
910 os.utime(self, None)
881 os.utime(self, None)
911
882
912 def remove(self):
883 def remove(self):
913 os.remove(self)
884 os.remove(self)
914
885
915 def unlink(self):
886 def unlink(self):
916 os.unlink(self)
887 os.unlink(self)
917
888
918
889
919 # --- Links
890 # --- Links
920
891
921 if hasattr(os, 'link'):
892 if hasattr(os, 'link'):
922 def link(self, newpath):
893 def link(self, newpath):
923 """ Create a hard link at 'newpath', pointing to this file. """
894 """ Create a hard link at 'newpath', pointing to this file. """
924 os.link(self, newpath)
895 os.link(self, newpath)
925
896
926 if hasattr(os, 'symlink'):
897 if hasattr(os, 'symlink'):
927 def symlink(self, newlink):
898 def symlink(self, newlink):
928 """ Create a symbolic link at 'newlink', pointing here. """
899 """ Create a symbolic link at 'newlink', pointing here. """
929 os.symlink(self, newlink)
900 os.symlink(self, newlink)
930
901
931 if hasattr(os, 'readlink'):
902 if hasattr(os, 'readlink'):
932 def readlink(self):
903 def readlink(self):
933 """ Return the path to which this symbolic link points.
904 """ Return the path to which this symbolic link points.
934
905
935 The result may be an absolute or a relative path.
906 The result may be an absolute or a relative path.
936 """
907 """
937 return self.__class__(os.readlink(self))
908 return self.__class__(os.readlink(self))
938
909
939 def readlinkabs(self):
910 def readlinkabs(self):
940 """ Return the path to which this symbolic link points.
911 """ Return the path to which this symbolic link points.
941
912
942 The result is always an absolute path.
913 The result is always an absolute path.
943 """
914 """
944 p = self.readlink()
915 p = self.readlink()
945 if p.isabs():
916 if p.isabs():
946 return p
917 return p
947 else:
918 else:
948 return (self.parent / p).abspath()
919 return (self.parent / p).abspath()
949
920
950
921
951 # --- High-level functions from shutil
922 # --- High-level functions from shutil
952
923
953 copyfile = shutil.copyfile
924 copyfile = shutil.copyfile
954 copymode = shutil.copymode
925 copymode = shutil.copymode
955 copystat = shutil.copystat
926 copystat = shutil.copystat
956 copy = shutil.copy
927 copy = shutil.copy
957 copy2 = shutil.copy2
928 copy2 = shutil.copy2
958 copytree = shutil.copytree
929 copytree = shutil.copytree
959 if hasattr(shutil, 'move'):
930 if hasattr(shutil, 'move'):
960 move = shutil.move
931 move = shutil.move
961 rmtree = shutil.rmtree
932 rmtree = shutil.rmtree
962
933
963
934
964 # --- Special stuff from os
935 # --- Special stuff from os
965
936
966 if hasattr(os, 'chroot'):
937 if hasattr(os, 'chroot'):
967 def chroot(self):
938 def chroot(self):
968 os.chroot(self)
939 os.chroot(self)
969
940
970 if hasattr(os, 'startfile'):
941 if hasattr(os, 'startfile'):
971 def startfile(self):
942 def startfile(self):
972 os.startfile(self)
943 os.startfile(self)
973
944
@@ -1,31 +1,36 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 A simple utility to import something by its string name.
3 A simple utility to import something by its string name.
4
4
5 Authors:
5 Authors:
6
6
7 * Brian Granger
7 * Brian Granger
8 """
8 """
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Copyright (C) 2008-2009 The IPython Development Team
11 # Copyright (C) 2008-2009 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 # Functions and classes
18 # Functions and classes
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20
20
21 def import_item(name):
21 def import_item(name):
22 """Import and return bar given the string foo.bar."""
22 """Import and return bar given the string foo.bar."""
23 package = '.'.join(name.split('.')[0:-1])
23 package = '.'.join(name.split('.')[0:-1])
24 obj = name.split('.')[-1]
24 obj = name.split('.')[-1]
25 execString = 'from %s import %s' % (package, obj)
25 # execString = 'from %s import %s' % (package, obj)
26 try:
26 # try:
27 exec execString
27 # exec execString
28 except SyntaxError:
28 # except SyntaxError:
29 raise ImportError("Invalid class specification: %s" % name)
29 # raise ImportError("Invalid class specification: %s" % name)
30 exec 'temp = %s' % obj
30 # exec 'temp = %s' % obj
31 return temp
31 # return temp
32 if package:
33 module = __import__(package,fromlist=[obj])
34 return module.__dict__[obj]
35 else:
36 return __import__(obj)
@@ -1,1062 +1,1050 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A lightweight Traits like module.
4 A lightweight Traits like module.
5
5
6 This is designed to provide a lightweight, simple, pure Python version of
6 This is designed to provide a lightweight, simple, pure Python version of
7 many of the capabilities of enthought.traits. This includes:
7 many of the capabilities of enthought.traits. This includes:
8
8
9 * Validation
9 * Validation
10 * Type specification with defaults
10 * Type specification with defaults
11 * Static and dynamic notification
11 * Static and dynamic notification
12 * Basic predefined types
12 * Basic predefined types
13 * An API that is similar to enthought.traits
13 * An API that is similar to enthought.traits
14
14
15 We don't support:
15 We don't support:
16
16
17 * Delegation
17 * Delegation
18 * Automatic GUI generation
18 * Automatic GUI generation
19 * A full set of trait types. Most importantly, we don't provide container
19 * A full set of trait types. Most importantly, we don't provide container
20 traits (list, dict, tuple) that can trigger notifications if their
20 traits (list, dict, tuple) that can trigger notifications if their
21 contents change.
21 contents change.
22 * API compatibility with enthought.traits
22 * API compatibility with enthought.traits
23
23
24 There are also some important difference in our design:
24 There are also some important difference in our design:
25
25
26 * enthought.traits does not validate default values. We do.
26 * enthought.traits does not validate default values. We do.
27
27
28 We choose to create this module because we need these capabilities, but
28 We choose to create this module because we need these capabilities, but
29 we need them to be pure Python so they work in all Python implementations,
29 we need them to be pure Python so they work in all Python implementations,
30 including Jython and IronPython.
30 including Jython and IronPython.
31
31
32 Authors:
32 Authors:
33
33
34 * Brian Granger
34 * Brian Granger
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
35 * Enthought, Inc. Some of the code in this file comes from enthought.traits
36 and is licensed under the BSD license. Also, many of the ideas also come
36 and is licensed under the BSD license. Also, many of the ideas also come
37 from enthought.traits even though our implementation is very different.
37 from enthought.traits even though our implementation is very different.
38 """
38 """
39
39
40 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
41 # Copyright (C) 2008-2009 The IPython Development Team
41 # Copyright (C) 2008-2009 The IPython Development Team
42 #
42 #
43 # Distributed under the terms of the BSD License. The full license is in
43 # Distributed under the terms of the BSD License. The full license is in
44 # the file COPYING, distributed as part of this software.
44 # the file COPYING, distributed as part of this software.
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Imports
48 # Imports
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50
50
51
51
52 import inspect
52 import inspect
53 import sys
53 import sys
54 import types
54 import types
55 from types import (
55 from types import (
56 InstanceType, ClassType, FunctionType,
56 InstanceType, ClassType, FunctionType,
57 ListType, TupleType
57 ListType, TupleType
58 )
58 )
59
59 from .importstring import import_item
60 def import_item(name):
61 """Import and return bar given the string foo.bar."""
62 package = '.'.join(name.split('.')[0:-1])
63 obj = name.split('.')[-1]
64 execString = 'from %s import %s' % (package, obj)
65 try:
66 exec execString
67 except SyntaxError:
68 raise ImportError("Invalid class specification: %s" % name)
69 exec 'temp = %s' % obj
70 return temp
71
72
60
73 ClassTypes = (ClassType, type)
61 ClassTypes = (ClassType, type)
74
62
75 SequenceTypes = (ListType, TupleType)
63 SequenceTypes = (ListType, TupleType)
76
64
77 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
78 # Basic classes
66 # Basic classes
79 #-----------------------------------------------------------------------------
67 #-----------------------------------------------------------------------------
80
68
81
69
82 class NoDefaultSpecified ( object ): pass
70 class NoDefaultSpecified ( object ): pass
83 NoDefaultSpecified = NoDefaultSpecified()
71 NoDefaultSpecified = NoDefaultSpecified()
84
72
85
73
86 class Undefined ( object ): pass
74 class Undefined ( object ): pass
87 Undefined = Undefined()
75 Undefined = Undefined()
88
76
89 class TraitError(Exception):
77 class TraitError(Exception):
90 pass
78 pass
91
79
92 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
93 # Utilities
81 # Utilities
94 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
95
83
96
84
97 def class_of ( object ):
85 def class_of ( object ):
98 """ Returns a string containing the class name of an object with the
86 """ Returns a string containing the class name of an object with the
99 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
87 correct indefinite article ('a' or 'an') preceding it (e.g., 'an Image',
100 'a PlotValue').
88 'a PlotValue').
101 """
89 """
102 if isinstance( object, basestring ):
90 if isinstance( object, basestring ):
103 return add_article( object )
91 return add_article( object )
104
92
105 return add_article( object.__class__.__name__ )
93 return add_article( object.__class__.__name__ )
106
94
107
95
108 def add_article ( name ):
96 def add_article ( name ):
109 """ Returns a string containing the correct indefinite article ('a' or 'an')
97 """ Returns a string containing the correct indefinite article ('a' or 'an')
110 prefixed to the specified string.
98 prefixed to the specified string.
111 """
99 """
112 if name[:1].lower() in 'aeiou':
100 if name[:1].lower() in 'aeiou':
113 return 'an ' + name
101 return 'an ' + name
114
102
115 return 'a ' + name
103 return 'a ' + name
116
104
117
105
118 def repr_type(obj):
106 def repr_type(obj):
119 """ Return a string representation of a value and its type for readable
107 """ Return a string representation of a value and its type for readable
120 error messages.
108 error messages.
121 """
109 """
122 the_type = type(obj)
110 the_type = type(obj)
123 if the_type is InstanceType:
111 if the_type is InstanceType:
124 # Old-style class.
112 # Old-style class.
125 the_type = obj.__class__
113 the_type = obj.__class__
126 msg = '%r %r' % (obj, the_type)
114 msg = '%r %r' % (obj, the_type)
127 return msg
115 return msg
128
116
129
117
130 def parse_notifier_name(name):
118 def parse_notifier_name(name):
131 """Convert the name argument to a list of names.
119 """Convert the name argument to a list of names.
132
120
133 Examples
121 Examples
134 --------
122 --------
135
123
136 >>> parse_notifier_name('a')
124 >>> parse_notifier_name('a')
137 ['a']
125 ['a']
138 >>> parse_notifier_name(['a','b'])
126 >>> parse_notifier_name(['a','b'])
139 ['a', 'b']
127 ['a', 'b']
140 >>> parse_notifier_name(None)
128 >>> parse_notifier_name(None)
141 ['anytrait']
129 ['anytrait']
142 """
130 """
143 if isinstance(name, str):
131 if isinstance(name, str):
144 return [name]
132 return [name]
145 elif name is None:
133 elif name is None:
146 return ['anytrait']
134 return ['anytrait']
147 elif isinstance(name, (list, tuple)):
135 elif isinstance(name, (list, tuple)):
148 for n in name:
136 for n in name:
149 assert isinstance(n, str), "names must be strings"
137 assert isinstance(n, str), "names must be strings"
150 return name
138 return name
151
139
152
140
153 class _SimpleTest:
141 class _SimpleTest:
154 def __init__ ( self, value ): self.value = value
142 def __init__ ( self, value ): self.value = value
155 def __call__ ( self, test ):
143 def __call__ ( self, test ):
156 return test == self.value
144 return test == self.value
157 def __repr__(self):
145 def __repr__(self):
158 return "<SimpleTest(%r)" % self.value
146 return "<SimpleTest(%r)" % self.value
159 def __str__(self):
147 def __str__(self):
160 return self.__repr__()
148 return self.__repr__()
161
149
162
150
163 def getmembers(object, predicate=None):
151 def getmembers(object, predicate=None):
164 """A safe version of inspect.getmembers that handles missing attributes.
152 """A safe version of inspect.getmembers that handles missing attributes.
165
153
166 This is useful when there are descriptor based attributes that for
154 This is useful when there are descriptor based attributes that for
167 some reason raise AttributeError even though they exist. This happens
155 some reason raise AttributeError even though they exist. This happens
168 in zope.inteface with the __provides__ attribute.
156 in zope.inteface with the __provides__ attribute.
169 """
157 """
170 results = []
158 results = []
171 for key in dir(object):
159 for key in dir(object):
172 try:
160 try:
173 value = getattr(object, key)
161 value = getattr(object, key)
174 except AttributeError:
162 except AttributeError:
175 pass
163 pass
176 else:
164 else:
177 if not predicate or predicate(value):
165 if not predicate or predicate(value):
178 results.append((key, value))
166 results.append((key, value))
179 results.sort()
167 results.sort()
180 return results
168 return results
181
169
182
170
183 #-----------------------------------------------------------------------------
171 #-----------------------------------------------------------------------------
184 # Base TraitType for all traits
172 # Base TraitType for all traits
185 #-----------------------------------------------------------------------------
173 #-----------------------------------------------------------------------------
186
174
187
175
188 class TraitType(object):
176 class TraitType(object):
189 """A base class for all trait descriptors.
177 """A base class for all trait descriptors.
190
178
191 Notes
179 Notes
192 -----
180 -----
193 Our implementation of traits is based on Python's descriptor
181 Our implementation of traits is based on Python's descriptor
194 prototol. This class is the base class for all such descriptors. The
182 prototol. This class is the base class for all such descriptors. The
195 only magic we use is a custom metaclass for the main :class:`HasTraits`
183 only magic we use is a custom metaclass for the main :class:`HasTraits`
196 class that does the following:
184 class that does the following:
197
185
198 1. Sets the :attr:`name` attribute of every :class:`TraitType`
186 1. Sets the :attr:`name` attribute of every :class:`TraitType`
199 instance in the class dict to the name of the attribute.
187 instance in the class dict to the name of the attribute.
200 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
188 2. Sets the :attr:`this_class` attribute of every :class:`TraitType`
201 instance in the class dict to the *class* that declared the trait.
189 instance in the class dict to the *class* that declared the trait.
202 This is used by the :class:`This` trait to allow subclasses to
190 This is used by the :class:`This` trait to allow subclasses to
203 accept superclasses for :class:`This` values.
191 accept superclasses for :class:`This` values.
204 """
192 """
205
193
206
194
207 metadata = {}
195 metadata = {}
208 default_value = Undefined
196 default_value = Undefined
209 info_text = 'any value'
197 info_text = 'any value'
210
198
211 def __init__(self, default_value=NoDefaultSpecified, **metadata):
199 def __init__(self, default_value=NoDefaultSpecified, **metadata):
212 """Create a TraitType.
200 """Create a TraitType.
213 """
201 """
214 if default_value is not NoDefaultSpecified:
202 if default_value is not NoDefaultSpecified:
215 self.default_value = default_value
203 self.default_value = default_value
216
204
217 if len(metadata) > 0:
205 if len(metadata) > 0:
218 if len(self.metadata) > 0:
206 if len(self.metadata) > 0:
219 self._metadata = self.metadata.copy()
207 self._metadata = self.metadata.copy()
220 self._metadata.update(metadata)
208 self._metadata.update(metadata)
221 else:
209 else:
222 self._metadata = metadata
210 self._metadata = metadata
223 else:
211 else:
224 self._metadata = self.metadata
212 self._metadata = self.metadata
225
213
226 self.init()
214 self.init()
227
215
228 def init(self):
216 def init(self):
229 pass
217 pass
230
218
231 def get_default_value(self):
219 def get_default_value(self):
232 """Create a new instance of the default value."""
220 """Create a new instance of the default value."""
233 return self.default_value
221 return self.default_value
234
222
235 def instance_init(self, obj):
223 def instance_init(self, obj):
236 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
224 """This is called by :meth:`HasTraits.__new__` to finish init'ing.
237
225
238 Some stages of initialization must be delayed until the parent
226 Some stages of initialization must be delayed until the parent
239 :class:`HasTraits` instance has been created. This method is
227 :class:`HasTraits` instance has been created. This method is
240 called in :meth:`HasTraits.__new__` after the instance has been
228 called in :meth:`HasTraits.__new__` after the instance has been
241 created.
229 created.
242
230
243 This method trigger the creation and validation of default values
231 This method trigger the creation and validation of default values
244 and also things like the resolution of str given class names in
232 and also things like the resolution of str given class names in
245 :class:`Type` and :class`Instance`.
233 :class:`Type` and :class`Instance`.
246
234
247 Parameters
235 Parameters
248 ----------
236 ----------
249 obj : :class:`HasTraits` instance
237 obj : :class:`HasTraits` instance
250 The parent :class:`HasTraits` instance that has just been
238 The parent :class:`HasTraits` instance that has just been
251 created.
239 created.
252 """
240 """
253 self.set_default_value(obj)
241 self.set_default_value(obj)
254
242
255 def set_default_value(self, obj):
243 def set_default_value(self, obj):
256 """Set the default value on a per instance basis.
244 """Set the default value on a per instance basis.
257
245
258 This method is called by :meth:`instance_init` to create and
246 This method is called by :meth:`instance_init` to create and
259 validate the default value. The creation and validation of
247 validate the default value. The creation and validation of
260 default values must be delayed until the parent :class:`HasTraits`
248 default values must be delayed until the parent :class:`HasTraits`
261 class has been instantiated.
249 class has been instantiated.
262 """
250 """
263 dv = self.get_default_value()
251 dv = self.get_default_value()
264 newdv = self._validate(obj, dv)
252 newdv = self._validate(obj, dv)
265 obj._trait_values[self.name] = newdv
253 obj._trait_values[self.name] = newdv
266
254
267 def __get__(self, obj, cls=None):
255 def __get__(self, obj, cls=None):
268 """Get the value of the trait by self.name for the instance.
256 """Get the value of the trait by self.name for the instance.
269
257
270 Default values are instantiated when :meth:`HasTraits.__new__`
258 Default values are instantiated when :meth:`HasTraits.__new__`
271 is called. Thus by the time this method gets called either the
259 is called. Thus by the time this method gets called either the
272 default value or a user defined value (they called :meth:`__set__`)
260 default value or a user defined value (they called :meth:`__set__`)
273 is in the :class:`HasTraits` instance.
261 is in the :class:`HasTraits` instance.
274 """
262 """
275 if obj is None:
263 if obj is None:
276 return self
264 return self
277 else:
265 else:
278 try:
266 try:
279 value = obj._trait_values[self.name]
267 value = obj._trait_values[self.name]
280 except:
268 except:
281 # HasTraits should call set_default_value to populate
269 # HasTraits should call set_default_value to populate
282 # this. So this should never be reached.
270 # this. So this should never be reached.
283 raise TraitError('Unexpected error in TraitType: '
271 raise TraitError('Unexpected error in TraitType: '
284 'default value not set properly')
272 'default value not set properly')
285 else:
273 else:
286 return value
274 return value
287
275
288 def __set__(self, obj, value):
276 def __set__(self, obj, value):
289 new_value = self._validate(obj, value)
277 new_value = self._validate(obj, value)
290 old_value = self.__get__(obj)
278 old_value = self.__get__(obj)
291 if old_value != new_value:
279 if old_value != new_value:
292 obj._trait_values[self.name] = new_value
280 obj._trait_values[self.name] = new_value
293 obj._notify_trait(self.name, old_value, new_value)
281 obj._notify_trait(self.name, old_value, new_value)
294
282
295 def _validate(self, obj, value):
283 def _validate(self, obj, value):
296 if hasattr(self, 'validate'):
284 if hasattr(self, 'validate'):
297 return self.validate(obj, value)
285 return self.validate(obj, value)
298 elif hasattr(self, 'is_valid_for'):
286 elif hasattr(self, 'is_valid_for'):
299 valid = self.is_valid_for(value)
287 valid = self.is_valid_for(value)
300 if valid:
288 if valid:
301 return value
289 return value
302 else:
290 else:
303 raise TraitError('invalid value for type: %r' % value)
291 raise TraitError('invalid value for type: %r' % value)
304 elif hasattr(self, 'value_for'):
292 elif hasattr(self, 'value_for'):
305 return self.value_for(value)
293 return self.value_for(value)
306 else:
294 else:
307 return value
295 return value
308
296
309 def info(self):
297 def info(self):
310 return self.info_text
298 return self.info_text
311
299
312 def error(self, obj, value):
300 def error(self, obj, value):
313 if obj is not None:
301 if obj is not None:
314 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
302 e = "The '%s' trait of %s instance must be %s, but a value of %s was specified." \
315 % (self.name, class_of(obj),
303 % (self.name, class_of(obj),
316 self.info(), repr_type(value))
304 self.info(), repr_type(value))
317 else:
305 else:
318 e = "The '%s' trait must be %s, but a value of %r was specified." \
306 e = "The '%s' trait must be %s, but a value of %r was specified." \
319 % (self.name, self.info(), repr_type(value))
307 % (self.name, self.info(), repr_type(value))
320 raise TraitError(e)
308 raise TraitError(e)
321
309
322 def get_metadata(self, key):
310 def get_metadata(self, key):
323 return getattr(self, '_metadata', {}).get(key, None)
311 return getattr(self, '_metadata', {}).get(key, None)
324
312
325 def set_metadata(self, key, value):
313 def set_metadata(self, key, value):
326 getattr(self, '_metadata', {})[key] = value
314 getattr(self, '_metadata', {})[key] = value
327
315
328
316
329 #-----------------------------------------------------------------------------
317 #-----------------------------------------------------------------------------
330 # The HasTraits implementation
318 # The HasTraits implementation
331 #-----------------------------------------------------------------------------
319 #-----------------------------------------------------------------------------
332
320
333
321
334 class MetaHasTraits(type):
322 class MetaHasTraits(type):
335 """A metaclass for HasTraits.
323 """A metaclass for HasTraits.
336
324
337 This metaclass makes sure that any TraitType class attributes are
325 This metaclass makes sure that any TraitType class attributes are
338 instantiated and sets their name attribute.
326 instantiated and sets their name attribute.
339 """
327 """
340
328
341 def __new__(mcls, name, bases, classdict):
329 def __new__(mcls, name, bases, classdict):
342 """Create the HasTraits class.
330 """Create the HasTraits class.
343
331
344 This instantiates all TraitTypes in the class dict and sets their
332 This instantiates all TraitTypes in the class dict and sets their
345 :attr:`name` attribute.
333 :attr:`name` attribute.
346 """
334 """
347 # print "MetaHasTraitlets (mcls, name): ", mcls, name
335 # print "MetaHasTraitlets (mcls, name): ", mcls, name
348 # print "MetaHasTraitlets (bases): ", bases
336 # print "MetaHasTraitlets (bases): ", bases
349 # print "MetaHasTraitlets (classdict): ", classdict
337 # print "MetaHasTraitlets (classdict): ", classdict
350 for k,v in classdict.iteritems():
338 for k,v in classdict.iteritems():
351 if isinstance(v, TraitType):
339 if isinstance(v, TraitType):
352 v.name = k
340 v.name = k
353 elif inspect.isclass(v):
341 elif inspect.isclass(v):
354 if issubclass(v, TraitType):
342 if issubclass(v, TraitType):
355 vinst = v()
343 vinst = v()
356 vinst.name = k
344 vinst.name = k
357 classdict[k] = vinst
345 classdict[k] = vinst
358 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
346 return super(MetaHasTraits, mcls).__new__(mcls, name, bases, classdict)
359
347
360 def __init__(cls, name, bases, classdict):
348 def __init__(cls, name, bases, classdict):
361 """Finish initializing the HasTraits class.
349 """Finish initializing the HasTraits class.
362
350
363 This sets the :attr:`this_class` attribute of each TraitType in the
351 This sets the :attr:`this_class` attribute of each TraitType in the
364 class dict to the newly created class ``cls``.
352 class dict to the newly created class ``cls``.
365 """
353 """
366 for k, v in classdict.iteritems():
354 for k, v in classdict.iteritems():
367 if isinstance(v, TraitType):
355 if isinstance(v, TraitType):
368 v.this_class = cls
356 v.this_class = cls
369 super(MetaHasTraits, cls).__init__(name, bases, classdict)
357 super(MetaHasTraits, cls).__init__(name, bases, classdict)
370
358
371 class HasTraits(object):
359 class HasTraits(object):
372
360
373 __metaclass__ = MetaHasTraits
361 __metaclass__ = MetaHasTraits
374
362
375 def __new__(cls, **kw):
363 def __new__(cls, **kw):
376 # This is needed because in Python 2.6 object.__new__ only accepts
364 # This is needed because in Python 2.6 object.__new__ only accepts
377 # the cls argument.
365 # the cls argument.
378 new_meth = super(HasTraits, cls).__new__
366 new_meth = super(HasTraits, cls).__new__
379 if new_meth is object.__new__:
367 if new_meth is object.__new__:
380 inst = new_meth(cls)
368 inst = new_meth(cls)
381 else:
369 else:
382 inst = new_meth(cls, **kw)
370 inst = new_meth(cls, **kw)
383 inst._trait_values = {}
371 inst._trait_values = {}
384 inst._trait_notifiers = {}
372 inst._trait_notifiers = {}
385 # Here we tell all the TraitType instances to set their default
373 # Here we tell all the TraitType instances to set their default
386 # values on the instance.
374 # values on the instance.
387 for key in dir(cls):
375 for key in dir(cls):
388 # Some descriptors raise AttributeError like zope.interface's
376 # Some descriptors raise AttributeError like zope.interface's
389 # __provides__ attributes even though they exist. This causes
377 # __provides__ attributes even though they exist. This causes
390 # AttributeErrors even though they are listed in dir(cls).
378 # AttributeErrors even though they are listed in dir(cls).
391 try:
379 try:
392 value = getattr(cls, key)
380 value = getattr(cls, key)
393 except AttributeError:
381 except AttributeError:
394 pass
382 pass
395 else:
383 else:
396 if isinstance(value, TraitType):
384 if isinstance(value, TraitType):
397 value.instance_init(inst)
385 value.instance_init(inst)
398
386
399 return inst
387 return inst
400
388
401 def __init__(self, **kw):
389 def __init__(self, **kw):
402 # Allow trait values to be set using keyword arguments.
390 # Allow trait values to be set using keyword arguments.
403 # We need to use setattr for this to trigger validation and
391 # We need to use setattr for this to trigger validation and
404 # notifications.
392 # notifications.
405 for key, value in kw.iteritems():
393 for key, value in kw.iteritems():
406 setattr(self, key, value)
394 setattr(self, key, value)
407
395
408 def _notify_trait(self, name, old_value, new_value):
396 def _notify_trait(self, name, old_value, new_value):
409
397
410 # First dynamic ones
398 # First dynamic ones
411 callables = self._trait_notifiers.get(name,[])
399 callables = self._trait_notifiers.get(name,[])
412 more_callables = self._trait_notifiers.get('anytrait',[])
400 more_callables = self._trait_notifiers.get('anytrait',[])
413 callables.extend(more_callables)
401 callables.extend(more_callables)
414
402
415 # Now static ones
403 # Now static ones
416 try:
404 try:
417 cb = getattr(self, '_%s_changed' % name)
405 cb = getattr(self, '_%s_changed' % name)
418 except:
406 except:
419 pass
407 pass
420 else:
408 else:
421 callables.append(cb)
409 callables.append(cb)
422
410
423 # Call them all now
411 # Call them all now
424 for c in callables:
412 for c in callables:
425 # Traits catches and logs errors here. I allow them to raise
413 # Traits catches and logs errors here. I allow them to raise
426 if callable(c):
414 if callable(c):
427 argspec = inspect.getargspec(c)
415 argspec = inspect.getargspec(c)
428 nargs = len(argspec[0])
416 nargs = len(argspec[0])
429 # Bound methods have an additional 'self' argument
417 # Bound methods have an additional 'self' argument
430 # I don't know how to treat unbound methods, but they
418 # I don't know how to treat unbound methods, but they
431 # can't really be used for callbacks.
419 # can't really be used for callbacks.
432 if isinstance(c, types.MethodType):
420 if isinstance(c, types.MethodType):
433 offset = -1
421 offset = -1
434 else:
422 else:
435 offset = 0
423 offset = 0
436 if nargs + offset == 0:
424 if nargs + offset == 0:
437 c()
425 c()
438 elif nargs + offset == 1:
426 elif nargs + offset == 1:
439 c(name)
427 c(name)
440 elif nargs + offset == 2:
428 elif nargs + offset == 2:
441 c(name, new_value)
429 c(name, new_value)
442 elif nargs + offset == 3:
430 elif nargs + offset == 3:
443 c(name, old_value, new_value)
431 c(name, old_value, new_value)
444 else:
432 else:
445 raise TraitError('a trait changed callback '
433 raise TraitError('a trait changed callback '
446 'must have 0-3 arguments.')
434 'must have 0-3 arguments.')
447 else:
435 else:
448 raise TraitError('a trait changed callback '
436 raise TraitError('a trait changed callback '
449 'must be callable.')
437 'must be callable.')
450
438
451
439
452 def _add_notifiers(self, handler, name):
440 def _add_notifiers(self, handler, name):
453 if not self._trait_notifiers.has_key(name):
441 if not self._trait_notifiers.has_key(name):
454 nlist = []
442 nlist = []
455 self._trait_notifiers[name] = nlist
443 self._trait_notifiers[name] = nlist
456 else:
444 else:
457 nlist = self._trait_notifiers[name]
445 nlist = self._trait_notifiers[name]
458 if handler not in nlist:
446 if handler not in nlist:
459 nlist.append(handler)
447 nlist.append(handler)
460
448
461 def _remove_notifiers(self, handler, name):
449 def _remove_notifiers(self, handler, name):
462 if self._trait_notifiers.has_key(name):
450 if self._trait_notifiers.has_key(name):
463 nlist = self._trait_notifiers[name]
451 nlist = self._trait_notifiers[name]
464 try:
452 try:
465 index = nlist.index(handler)
453 index = nlist.index(handler)
466 except ValueError:
454 except ValueError:
467 pass
455 pass
468 else:
456 else:
469 del nlist[index]
457 del nlist[index]
470
458
471 def on_trait_change(self, handler, name=None, remove=False):
459 def on_trait_change(self, handler, name=None, remove=False):
472 """Setup a handler to be called when a trait changes.
460 """Setup a handler to be called when a trait changes.
473
461
474 This is used to setup dynamic notifications of trait changes.
462 This is used to setup dynamic notifications of trait changes.
475
463
476 Static handlers can be created by creating methods on a HasTraits
464 Static handlers can be created by creating methods on a HasTraits
477 subclass with the naming convention '_[traitname]_changed'. Thus,
465 subclass with the naming convention '_[traitname]_changed'. Thus,
478 to create static handler for the trait 'a', create the method
466 to create static handler for the trait 'a', create the method
479 _a_changed(self, name, old, new) (fewer arguments can be used, see
467 _a_changed(self, name, old, new) (fewer arguments can be used, see
480 below).
468 below).
481
469
482 Parameters
470 Parameters
483 ----------
471 ----------
484 handler : callable
472 handler : callable
485 A callable that is called when a trait changes. Its
473 A callable that is called when a trait changes. Its
486 signature can be handler(), handler(name), handler(name, new)
474 signature can be handler(), handler(name), handler(name, new)
487 or handler(name, old, new).
475 or handler(name, old, new).
488 name : list, str, None
476 name : list, str, None
489 If None, the handler will apply to all traits. If a list
477 If None, the handler will apply to all traits. If a list
490 of str, handler will apply to all names in the list. If a
478 of str, handler will apply to all names in the list. If a
491 str, the handler will apply just to that name.
479 str, the handler will apply just to that name.
492 remove : bool
480 remove : bool
493 If False (the default), then install the handler. If True
481 If False (the default), then install the handler. If True
494 then unintall it.
482 then unintall it.
495 """
483 """
496 if remove:
484 if remove:
497 names = parse_notifier_name(name)
485 names = parse_notifier_name(name)
498 for n in names:
486 for n in names:
499 self._remove_notifiers(handler, n)
487 self._remove_notifiers(handler, n)
500 else:
488 else:
501 names = parse_notifier_name(name)
489 names = parse_notifier_name(name)
502 for n in names:
490 for n in names:
503 self._add_notifiers(handler, n)
491 self._add_notifiers(handler, n)
504
492
505 def trait_names(self, **metadata):
493 def trait_names(self, **metadata):
506 """Get a list of all the names of this classes traits."""
494 """Get a list of all the names of this classes traits."""
507 return self.traits(**metadata).keys()
495 return self.traits(**metadata).keys()
508
496
509 def traits(self, **metadata):
497 def traits(self, **metadata):
510 """Get a list of all the traits of this class.
498 """Get a list of all the traits of this class.
511
499
512 The TraitTypes returned don't know anything about the values
500 The TraitTypes returned don't know anything about the values
513 that the various HasTrait's instances are holding.
501 that the various HasTrait's instances are holding.
514
502
515 This follows the same algorithm as traits does and does not allow
503 This follows the same algorithm as traits does and does not allow
516 for any simple way of specifying merely that a metadata name
504 for any simple way of specifying merely that a metadata name
517 exists, but has any value. This is because get_metadata returns
505 exists, but has any value. This is because get_metadata returns
518 None if a metadata key doesn't exist.
506 None if a metadata key doesn't exist.
519 """
507 """
520 traits = dict([memb for memb in getmembers(self.__class__) if \
508 traits = dict([memb for memb in getmembers(self.__class__) if \
521 isinstance(memb[1], TraitType)])
509 isinstance(memb[1], TraitType)])
522
510
523 if len(metadata) == 0:
511 if len(metadata) == 0:
524 return traits
512 return traits
525
513
526 for meta_name, meta_eval in metadata.items():
514 for meta_name, meta_eval in metadata.items():
527 if type(meta_eval) is not FunctionType:
515 if type(meta_eval) is not FunctionType:
528 metadata[meta_name] = _SimpleTest(meta_eval)
516 metadata[meta_name] = _SimpleTest(meta_eval)
529
517
530 result = {}
518 result = {}
531 for name, trait in traits.items():
519 for name, trait in traits.items():
532 for meta_name, meta_eval in metadata.items():
520 for meta_name, meta_eval in metadata.items():
533 if not meta_eval(trait.get_metadata(meta_name)):
521 if not meta_eval(trait.get_metadata(meta_name)):
534 break
522 break
535 else:
523 else:
536 result[name] = trait
524 result[name] = trait
537
525
538 return result
526 return result
539
527
540 def trait_metadata(self, traitname, key):
528 def trait_metadata(self, traitname, key):
541 """Get metadata values for trait by key."""
529 """Get metadata values for trait by key."""
542 try:
530 try:
543 trait = getattr(self.__class__, traitname)
531 trait = getattr(self.__class__, traitname)
544 except AttributeError:
532 except AttributeError:
545 raise TraitError("Class %s does not have a trait named %s" %
533 raise TraitError("Class %s does not have a trait named %s" %
546 (self.__class__.__name__, traitname))
534 (self.__class__.__name__, traitname))
547 else:
535 else:
548 return trait.get_metadata(key)
536 return trait.get_metadata(key)
549
537
550 #-----------------------------------------------------------------------------
538 #-----------------------------------------------------------------------------
551 # Actual TraitTypes implementations/subclasses
539 # Actual TraitTypes implementations/subclasses
552 #-----------------------------------------------------------------------------
540 #-----------------------------------------------------------------------------
553
541
554 #-----------------------------------------------------------------------------
542 #-----------------------------------------------------------------------------
555 # TraitTypes subclasses for handling classes and instances of classes
543 # TraitTypes subclasses for handling classes and instances of classes
556 #-----------------------------------------------------------------------------
544 #-----------------------------------------------------------------------------
557
545
558
546
559 class ClassBasedTraitType(TraitType):
547 class ClassBasedTraitType(TraitType):
560 """A trait with error reporting for Type, Instance and This."""
548 """A trait with error reporting for Type, Instance and This."""
561
549
562 def error(self, obj, value):
550 def error(self, obj, value):
563 kind = type(value)
551 kind = type(value)
564 if kind is InstanceType:
552 if kind is InstanceType:
565 msg = 'class %s' % value.__class__.__name__
553 msg = 'class %s' % value.__class__.__name__
566 else:
554 else:
567 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
555 msg = '%s (i.e. %s)' % ( str( kind )[1:-1], repr( value ) )
568
556
569 super(ClassBasedTraitType, self).error(obj, msg)
557 super(ClassBasedTraitType, self).error(obj, msg)
570
558
571
559
572 class Type(ClassBasedTraitType):
560 class Type(ClassBasedTraitType):
573 """A trait whose value must be a subclass of a specified class."""
561 """A trait whose value must be a subclass of a specified class."""
574
562
575 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
563 def __init__ (self, default_value=None, klass=None, allow_none=True, **metadata ):
576 """Construct a Type trait
564 """Construct a Type trait
577
565
578 A Type trait specifies that its values must be subclasses of
566 A Type trait specifies that its values must be subclasses of
579 a particular class.
567 a particular class.
580
568
581 If only ``default_value`` is given, it is used for the ``klass`` as
569 If only ``default_value`` is given, it is used for the ``klass`` as
582 well.
570 well.
583
571
584 Parameters
572 Parameters
585 ----------
573 ----------
586 default_value : class, str or None
574 default_value : class, str or None
587 The default value must be a subclass of klass. If an str,
575 The default value must be a subclass of klass. If an str,
588 the str must be a fully specified class name, like 'foo.bar.Bah'.
576 the str must be a fully specified class name, like 'foo.bar.Bah'.
589 The string is resolved into real class, when the parent
577 The string is resolved into real class, when the parent
590 :class:`HasTraits` class is instantiated.
578 :class:`HasTraits` class is instantiated.
591 klass : class, str, None
579 klass : class, str, None
592 Values of this trait must be a subclass of klass. The klass
580 Values of this trait must be a subclass of klass. The klass
593 may be specified in a string like: 'foo.bar.MyClass'.
581 may be specified in a string like: 'foo.bar.MyClass'.
594 The string is resolved into real class, when the parent
582 The string is resolved into real class, when the parent
595 :class:`HasTraits` class is instantiated.
583 :class:`HasTraits` class is instantiated.
596 allow_none : boolean
584 allow_none : boolean
597 Indicates whether None is allowed as an assignable value. Even if
585 Indicates whether None is allowed as an assignable value. Even if
598 ``False``, the default value may be ``None``.
586 ``False``, the default value may be ``None``.
599 """
587 """
600 if default_value is None:
588 if default_value is None:
601 if klass is None:
589 if klass is None:
602 klass = object
590 klass = object
603 elif klass is None:
591 elif klass is None:
604 klass = default_value
592 klass = default_value
605
593
606 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
594 if not (inspect.isclass(klass) or isinstance(klass, basestring)):
607 raise TraitError("A Type trait must specify a class.")
595 raise TraitError("A Type trait must specify a class.")
608
596
609 self.klass = klass
597 self.klass = klass
610 self._allow_none = allow_none
598 self._allow_none = allow_none
611
599
612 super(Type, self).__init__(default_value, **metadata)
600 super(Type, self).__init__(default_value, **metadata)
613
601
614 def validate(self, obj, value):
602 def validate(self, obj, value):
615 """Validates that the value is a valid object instance."""
603 """Validates that the value is a valid object instance."""
616 try:
604 try:
617 if issubclass(value, self.klass):
605 if issubclass(value, self.klass):
618 return value
606 return value
619 except:
607 except:
620 if (value is None) and (self._allow_none):
608 if (value is None) and (self._allow_none):
621 return value
609 return value
622
610
623 self.error(obj, value)
611 self.error(obj, value)
624
612
625 def info(self):
613 def info(self):
626 """ Returns a description of the trait."""
614 """ Returns a description of the trait."""
627 if isinstance(self.klass, basestring):
615 if isinstance(self.klass, basestring):
628 klass = self.klass
616 klass = self.klass
629 else:
617 else:
630 klass = self.klass.__name__
618 klass = self.klass.__name__
631 result = 'a subclass of ' + klass
619 result = 'a subclass of ' + klass
632 if self._allow_none:
620 if self._allow_none:
633 return result + ' or None'
621 return result + ' or None'
634 return result
622 return result
635
623
636 def instance_init(self, obj):
624 def instance_init(self, obj):
637 self._resolve_classes()
625 self._resolve_classes()
638 super(Type, self).instance_init(obj)
626 super(Type, self).instance_init(obj)
639
627
640 def _resolve_classes(self):
628 def _resolve_classes(self):
641 if isinstance(self.klass, basestring):
629 if isinstance(self.klass, basestring):
642 self.klass = import_item(self.klass)
630 self.klass = import_item(self.klass)
643 if isinstance(self.default_value, basestring):
631 if isinstance(self.default_value, basestring):
644 self.default_value = import_item(self.default_value)
632 self.default_value = import_item(self.default_value)
645
633
646 def get_default_value(self):
634 def get_default_value(self):
647 return self.default_value
635 return self.default_value
648
636
649
637
650 class DefaultValueGenerator(object):
638 class DefaultValueGenerator(object):
651 """A class for generating new default value instances."""
639 """A class for generating new default value instances."""
652
640
653 def __init__(self, *args, **kw):
641 def __init__(self, *args, **kw):
654 self.args = args
642 self.args = args
655 self.kw = kw
643 self.kw = kw
656
644
657 def generate(self, klass):
645 def generate(self, klass):
658 return klass(*self.args, **self.kw)
646 return klass(*self.args, **self.kw)
659
647
660
648
661 class Instance(ClassBasedTraitType):
649 class Instance(ClassBasedTraitType):
662 """A trait whose value must be an instance of a specified class.
650 """A trait whose value must be an instance of a specified class.
663
651
664 The value can also be an instance of a subclass of the specified class.
652 The value can also be an instance of a subclass of the specified class.
665 """
653 """
666
654
667 def __init__(self, klass=None, args=None, kw=None,
655 def __init__(self, klass=None, args=None, kw=None,
668 allow_none=True, **metadata ):
656 allow_none=True, **metadata ):
669 """Construct an Instance trait.
657 """Construct an Instance trait.
670
658
671 This trait allows values that are instances of a particular
659 This trait allows values that are instances of a particular
672 class or its sublclasses. Our implementation is quite different
660 class or its sublclasses. Our implementation is quite different
673 from that of enthough.traits as we don't allow instances to be used
661 from that of enthough.traits as we don't allow instances to be used
674 for klass and we handle the ``args`` and ``kw`` arguments differently.
662 for klass and we handle the ``args`` and ``kw`` arguments differently.
675
663
676 Parameters
664 Parameters
677 ----------
665 ----------
678 klass : class, str
666 klass : class, str
679 The class that forms the basis for the trait. Class names
667 The class that forms the basis for the trait. Class names
680 can also be specified as strings, like 'foo.bar.Bar'.
668 can also be specified as strings, like 'foo.bar.Bar'.
681 args : tuple
669 args : tuple
682 Positional arguments for generating the default value.
670 Positional arguments for generating the default value.
683 kw : dict
671 kw : dict
684 Keyword arguments for generating the default value.
672 Keyword arguments for generating the default value.
685 allow_none : bool
673 allow_none : bool
686 Indicates whether None is allowed as a value.
674 Indicates whether None is allowed as a value.
687
675
688 Default Value
676 Default Value
689 -------------
677 -------------
690 If both ``args`` and ``kw`` are None, then the default value is None.
678 If both ``args`` and ``kw`` are None, then the default value is None.
691 If ``args`` is a tuple and ``kw`` is a dict, then the default is
679 If ``args`` is a tuple and ``kw`` is a dict, then the default is
692 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
680 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
693 not (but not both), None is replace by ``()`` or ``{}``.
681 not (but not both), None is replace by ``()`` or ``{}``.
694 """
682 """
695
683
696 self._allow_none = allow_none
684 self._allow_none = allow_none
697
685
698 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
686 if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, basestring))):
699 raise TraitError('The klass argument must be a class'
687 raise TraitError('The klass argument must be a class'
700 ' you gave: %r' % klass)
688 ' you gave: %r' % klass)
701 self.klass = klass
689 self.klass = klass
702
690
703 # self.klass is a class, so handle default_value
691 # self.klass is a class, so handle default_value
704 if args is None and kw is None:
692 if args is None and kw is None:
705 default_value = None
693 default_value = None
706 else:
694 else:
707 if args is None:
695 if args is None:
708 # kw is not None
696 # kw is not None
709 args = ()
697 args = ()
710 elif kw is None:
698 elif kw is None:
711 # args is not None
699 # args is not None
712 kw = {}
700 kw = {}
713
701
714 if not isinstance(kw, dict):
702 if not isinstance(kw, dict):
715 raise TraitError("The 'kw' argument must be a dict or None.")
703 raise TraitError("The 'kw' argument must be a dict or None.")
716 if not isinstance(args, tuple):
704 if not isinstance(args, tuple):
717 raise TraitError("The 'args' argument must be a tuple or None.")
705 raise TraitError("The 'args' argument must be a tuple or None.")
718
706
719 default_value = DefaultValueGenerator(*args, **kw)
707 default_value = DefaultValueGenerator(*args, **kw)
720
708
721 super(Instance, self).__init__(default_value, **metadata)
709 super(Instance, self).__init__(default_value, **metadata)
722
710
723 def validate(self, obj, value):
711 def validate(self, obj, value):
724 if value is None:
712 if value is None:
725 if self._allow_none:
713 if self._allow_none:
726 return value
714 return value
727 self.error(obj, value)
715 self.error(obj, value)
728
716
729 if isinstance(value, self.klass):
717 if isinstance(value, self.klass):
730 return value
718 return value
731 else:
719 else:
732 self.error(obj, value)
720 self.error(obj, value)
733
721
734 def info(self):
722 def info(self):
735 if isinstance(self.klass, basestring):
723 if isinstance(self.klass, basestring):
736 klass = self.klass
724 klass = self.klass
737 else:
725 else:
738 klass = self.klass.__name__
726 klass = self.klass.__name__
739 result = class_of(klass)
727 result = class_of(klass)
740 if self._allow_none:
728 if self._allow_none:
741 return result + ' or None'
729 return result + ' or None'
742
730
743 return result
731 return result
744
732
745 def instance_init(self, obj):
733 def instance_init(self, obj):
746 self._resolve_classes()
734 self._resolve_classes()
747 super(Instance, self).instance_init(obj)
735 super(Instance, self).instance_init(obj)
748
736
749 def _resolve_classes(self):
737 def _resolve_classes(self):
750 if isinstance(self.klass, basestring):
738 if isinstance(self.klass, basestring):
751 self.klass = import_item(self.klass)
739 self.klass = import_item(self.klass)
752
740
753 def get_default_value(self):
741 def get_default_value(self):
754 """Instantiate a default value instance.
742 """Instantiate a default value instance.
755
743
756 This is called when the containing HasTraits classes'
744 This is called when the containing HasTraits classes'
757 :meth:`__new__` method is called to ensure that a unique instance
745 :meth:`__new__` method is called to ensure that a unique instance
758 is created for each HasTraits instance.
746 is created for each HasTraits instance.
759 """
747 """
760 dv = self.default_value
748 dv = self.default_value
761 if isinstance(dv, DefaultValueGenerator):
749 if isinstance(dv, DefaultValueGenerator):
762 return dv.generate(self.klass)
750 return dv.generate(self.klass)
763 else:
751 else:
764 return dv
752 return dv
765
753
766
754
767 class This(ClassBasedTraitType):
755 class This(ClassBasedTraitType):
768 """A trait for instances of the class containing this trait.
756 """A trait for instances of the class containing this trait.
769
757
770 Because how how and when class bodies are executed, the ``This``
758 Because how how and when class bodies are executed, the ``This``
771 trait can only have a default value of None. This, and because we
759 trait can only have a default value of None. This, and because we
772 always validate default values, ``allow_none`` is *always* true.
760 always validate default values, ``allow_none`` is *always* true.
773 """
761 """
774
762
775 info_text = 'an instance of the same type as the receiver or None'
763 info_text = 'an instance of the same type as the receiver or None'
776
764
777 def __init__(self, **metadata):
765 def __init__(self, **metadata):
778 super(This, self).__init__(None, **metadata)
766 super(This, self).__init__(None, **metadata)
779
767
780 def validate(self, obj, value):
768 def validate(self, obj, value):
781 # What if value is a superclass of obj.__class__? This is
769 # What if value is a superclass of obj.__class__? This is
782 # complicated if it was the superclass that defined the This
770 # complicated if it was the superclass that defined the This
783 # trait.
771 # trait.
784 if isinstance(value, self.this_class) or (value is None):
772 if isinstance(value, self.this_class) or (value is None):
785 return value
773 return value
786 else:
774 else:
787 self.error(obj, value)
775 self.error(obj, value)
788
776
789
777
790 #-----------------------------------------------------------------------------
778 #-----------------------------------------------------------------------------
791 # Basic TraitTypes implementations/subclasses
779 # Basic TraitTypes implementations/subclasses
792 #-----------------------------------------------------------------------------
780 #-----------------------------------------------------------------------------
793
781
794
782
795 class Any(TraitType):
783 class Any(TraitType):
796 default_value = None
784 default_value = None
797 info_text = 'any value'
785 info_text = 'any value'
798
786
799
787
800 class Int(TraitType):
788 class Int(TraitType):
801 """A integer trait."""
789 """A integer trait."""
802
790
803 default_value = 0
791 default_value = 0
804 info_text = 'an integer'
792 info_text = 'an integer'
805
793
806 def validate(self, obj, value):
794 def validate(self, obj, value):
807 if isinstance(value, int):
795 if isinstance(value, int):
808 return value
796 return value
809 self.error(obj, value)
797 self.error(obj, value)
810
798
811 class CInt(Int):
799 class CInt(Int):
812 """A casting version of the int trait."""
800 """A casting version of the int trait."""
813
801
814 def validate(self, obj, value):
802 def validate(self, obj, value):
815 try:
803 try:
816 return int(value)
804 return int(value)
817 except:
805 except:
818 self.error(obj, value)
806 self.error(obj, value)
819
807
820
808
821 class Long(TraitType):
809 class Long(TraitType):
822 """A long integer trait."""
810 """A long integer trait."""
823
811
824 default_value = 0L
812 default_value = 0L
825 info_text = 'a long'
813 info_text = 'a long'
826
814
827 def validate(self, obj, value):
815 def validate(self, obj, value):
828 if isinstance(value, long):
816 if isinstance(value, long):
829 return value
817 return value
830 if isinstance(value, int):
818 if isinstance(value, int):
831 return long(value)
819 return long(value)
832 self.error(obj, value)
820 self.error(obj, value)
833
821
834
822
835 class CLong(Long):
823 class CLong(Long):
836 """A casting version of the long integer trait."""
824 """A casting version of the long integer trait."""
837
825
838 def validate(self, obj, value):
826 def validate(self, obj, value):
839 try:
827 try:
840 return long(value)
828 return long(value)
841 except:
829 except:
842 self.error(obj, value)
830 self.error(obj, value)
843
831
844
832
845 class Float(TraitType):
833 class Float(TraitType):
846 """A float trait."""
834 """A float trait."""
847
835
848 default_value = 0.0
836 default_value = 0.0
849 info_text = 'a float'
837 info_text = 'a float'
850
838
851 def validate(self, obj, value):
839 def validate(self, obj, value):
852 if isinstance(value, float):
840 if isinstance(value, float):
853 return value
841 return value
854 if isinstance(value, int):
842 if isinstance(value, int):
855 return float(value)
843 return float(value)
856 self.error(obj, value)
844 self.error(obj, value)
857
845
858
846
859 class CFloat(Float):
847 class CFloat(Float):
860 """A casting version of the float trait."""
848 """A casting version of the float trait."""
861
849
862 def validate(self, obj, value):
850 def validate(self, obj, value):
863 try:
851 try:
864 return float(value)
852 return float(value)
865 except:
853 except:
866 self.error(obj, value)
854 self.error(obj, value)
867
855
868 class Complex(TraitType):
856 class Complex(TraitType):
869 """A trait for complex numbers."""
857 """A trait for complex numbers."""
870
858
871 default_value = 0.0 + 0.0j
859 default_value = 0.0 + 0.0j
872 info_text = 'a complex number'
860 info_text = 'a complex number'
873
861
874 def validate(self, obj, value):
862 def validate(self, obj, value):
875 if isinstance(value, complex):
863 if isinstance(value, complex):
876 return value
864 return value
877 if isinstance(value, (float, int)):
865 if isinstance(value, (float, int)):
878 return complex(value)
866 return complex(value)
879 self.error(obj, value)
867 self.error(obj, value)
880
868
881
869
882 class CComplex(Complex):
870 class CComplex(Complex):
883 """A casting version of the complex number trait."""
871 """A casting version of the complex number trait."""
884
872
885 def validate (self, obj, value):
873 def validate (self, obj, value):
886 try:
874 try:
887 return complex(value)
875 return complex(value)
888 except:
876 except:
889 self.error(obj, value)
877 self.error(obj, value)
890
878
891
879
892 class Str(TraitType):
880 class Str(TraitType):
893 """A trait for strings."""
881 """A trait for strings."""
894
882
895 default_value = ''
883 default_value = ''
896 info_text = 'a string'
884 info_text = 'a string'
897
885
898 def validate(self, obj, value):
886 def validate(self, obj, value):
899 if isinstance(value, str):
887 if isinstance(value, str):
900 return value
888 return value
901 self.error(obj, value)
889 self.error(obj, value)
902
890
903
891
904 class CStr(Str):
892 class CStr(Str):
905 """A casting version of the string trait."""
893 """A casting version of the string trait."""
906
894
907 def validate(self, obj, value):
895 def validate(self, obj, value):
908 try:
896 try:
909 return str(value)
897 return str(value)
910 except:
898 except:
911 try:
899 try:
912 return unicode(value)
900 return unicode(value)
913 except:
901 except:
914 self.error(obj, value)
902 self.error(obj, value)
915
903
916
904
917 class Unicode(TraitType):
905 class Unicode(TraitType):
918 """A trait for unicode strings."""
906 """A trait for unicode strings."""
919
907
920 default_value = u''
908 default_value = u''
921 info_text = 'a unicode string'
909 info_text = 'a unicode string'
922
910
923 def validate(self, obj, value):
911 def validate(self, obj, value):
924 if isinstance(value, unicode):
912 if isinstance(value, unicode):
925 return value
913 return value
926 if isinstance(value, str):
914 if isinstance(value, str):
927 return unicode(value)
915 return unicode(value)
928 self.error(obj, value)
916 self.error(obj, value)
929
917
930
918
931 class CUnicode(Unicode):
919 class CUnicode(Unicode):
932 """A casting version of the unicode trait."""
920 """A casting version of the unicode trait."""
933
921
934 def validate(self, obj, value):
922 def validate(self, obj, value):
935 try:
923 try:
936 return unicode(value)
924 return unicode(value)
937 except:
925 except:
938 self.error(obj, value)
926 self.error(obj, value)
939
927
940
928
941 class Bool(TraitType):
929 class Bool(TraitType):
942 """A boolean (True, False) trait."""
930 """A boolean (True, False) trait."""
943
931
944 default_value = False
932 default_value = False
945 info_text = 'a boolean'
933 info_text = 'a boolean'
946
934
947 def validate(self, obj, value):
935 def validate(self, obj, value):
948 if isinstance(value, bool):
936 if isinstance(value, bool):
949 return value
937 return value
950 self.error(obj, value)
938 self.error(obj, value)
951
939
952
940
953 class CBool(Bool):
941 class CBool(Bool):
954 """A casting version of the boolean trait."""
942 """A casting version of the boolean trait."""
955
943
956 def validate(self, obj, value):
944 def validate(self, obj, value):
957 try:
945 try:
958 return bool(value)
946 return bool(value)
959 except:
947 except:
960 self.error(obj, value)
948 self.error(obj, value)
961
949
962
950
963 class Enum(TraitType):
951 class Enum(TraitType):
964 """An enum that whose value must be in a given sequence."""
952 """An enum that whose value must be in a given sequence."""
965
953
966 def __init__(self, values, default_value=None, allow_none=True, **metadata):
954 def __init__(self, values, default_value=None, allow_none=True, **metadata):
967 self.values = values
955 self.values = values
968 self._allow_none = allow_none
956 self._allow_none = allow_none
969 super(Enum, self).__init__(default_value, **metadata)
957 super(Enum, self).__init__(default_value, **metadata)
970
958
971 def validate(self, obj, value):
959 def validate(self, obj, value):
972 if value is None:
960 if value is None:
973 if self._allow_none:
961 if self._allow_none:
974 return value
962 return value
975
963
976 if value in self.values:
964 if value in self.values:
977 return value
965 return value
978 self.error(obj, value)
966 self.error(obj, value)
979
967
980 def info(self):
968 def info(self):
981 """ Returns a description of the trait."""
969 """ Returns a description of the trait."""
982 result = 'any of ' + repr(self.values)
970 result = 'any of ' + repr(self.values)
983 if self._allow_none:
971 if self._allow_none:
984 return result + ' or None'
972 return result + ' or None'
985 return result
973 return result
986
974
987 class CaselessStrEnum(Enum):
975 class CaselessStrEnum(Enum):
988 """An enum of strings that are caseless in validate."""
976 """An enum of strings that are caseless in validate."""
989
977
990 def validate(self, obj, value):
978 def validate(self, obj, value):
991 if value is None:
979 if value is None:
992 if self._allow_none:
980 if self._allow_none:
993 return value
981 return value
994
982
995 if not isinstance(value, str):
983 if not isinstance(value, str):
996 self.error(obj, value)
984 self.error(obj, value)
997
985
998 for v in self.values:
986 for v in self.values:
999 if v.lower() == value.lower():
987 if v.lower() == value.lower():
1000 return v
988 return v
1001 self.error(obj, value)
989 self.error(obj, value)
1002
990
1003
991
1004 class List(Instance):
992 class List(Instance):
1005 """An instance of a Python list."""
993 """An instance of a Python list."""
1006
994
1007 def __init__(self, default_value=None, allow_none=True, **metadata):
995 def __init__(self, default_value=None, allow_none=True, **metadata):
1008 """Create a list trait type from a list or tuple.
996 """Create a list trait type from a list or tuple.
1009
997
1010 The default value is created by doing ``list(default_value)``,
998 The default value is created by doing ``list(default_value)``,
1011 which creates a copy of the ``default_value``.
999 which creates a copy of the ``default_value``.
1012 """
1000 """
1013 if default_value is None:
1001 if default_value is None:
1014 args = ((),)
1002 args = ((),)
1015 elif isinstance(default_value, SequenceTypes):
1003 elif isinstance(default_value, SequenceTypes):
1016 args = (default_value,)
1004 args = (default_value,)
1017 else:
1005 else:
1018 raise TypeError('default value of List was %s' % default_value)
1006 raise TypeError('default value of List was %s' % default_value)
1019
1007
1020 super(List,self).__init__(klass=list, args=args,
1008 super(List,self).__init__(klass=list, args=args,
1021 allow_none=allow_none, **metadata)
1009 allow_none=allow_none, **metadata)
1022
1010
1023
1011
1024 class Dict(Instance):
1012 class Dict(Instance):
1025 """An instance of a Python dict."""
1013 """An instance of a Python dict."""
1026
1014
1027 def __init__(self, default_value=None, allow_none=True, **metadata):
1015 def __init__(self, default_value=None, allow_none=True, **metadata):
1028 """Create a dict trait type from a dict.
1016 """Create a dict trait type from a dict.
1029
1017
1030 The default value is created by doing ``dict(default_value)``,
1018 The default value is created by doing ``dict(default_value)``,
1031 which creates a copy of the ``default_value``.
1019 which creates a copy of the ``default_value``.
1032 """
1020 """
1033 if default_value is None:
1021 if default_value is None:
1034 args = ((),)
1022 args = ((),)
1035 elif isinstance(default_value, dict):
1023 elif isinstance(default_value, dict):
1036 args = (default_value,)
1024 args = (default_value,)
1037 elif isinstance(default_value, SequenceTypes):
1025 elif isinstance(default_value, SequenceTypes):
1038 args = (default_value,)
1026 args = (default_value,)
1039 else:
1027 else:
1040 raise TypeError('default value of Dict was %s' % default_value)
1028 raise TypeError('default value of Dict was %s' % default_value)
1041
1029
1042 super(Dict,self).__init__(klass=dict, args=args,
1030 super(Dict,self).__init__(klass=dict, args=args,
1043 allow_none=allow_none, **metadata)
1031 allow_none=allow_none, **metadata)
1044
1032
1045
1033
1046 class TCPAddress(TraitType):
1034 class TCPAddress(TraitType):
1047 """A trait for an (ip, port) tuple.
1035 """A trait for an (ip, port) tuple.
1048
1036
1049 This allows for both IPv4 IP addresses as well as hostnames.
1037 This allows for both IPv4 IP addresses as well as hostnames.
1050 """
1038 """
1051
1039
1052 default_value = ('127.0.0.1', 0)
1040 default_value = ('127.0.0.1', 0)
1053 info_text = 'an (ip, port) tuple'
1041 info_text = 'an (ip, port) tuple'
1054
1042
1055 def validate(self, obj, value):
1043 def validate(self, obj, value):
1056 if isinstance(value, tuple):
1044 if isinstance(value, tuple):
1057 if len(value) == 2:
1045 if len(value) == 2:
1058 if isinstance(value[0], basestring) and isinstance(value[1], int):
1046 if isinstance(value[0], basestring) and isinstance(value[1], int):
1059 port = value[1]
1047 port = value[1]
1060 if port >= 0 and port <= 65535:
1048 if port >= 0 and port <= 65535:
1061 return value
1049 return value
1062 self.error(obj, value)
1050 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now