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