##// END OF EJS Templates
move safe_unicode to py3compat
MinRK -
Show More
@@ -1,618 +1,597 b''
1 1 """A ZMQ-based subclass of InteractiveShell.
2 2
3 3 This code is meant to ease the refactoring of the base InteractiveShell into
4 4 something with a cleaner architecture for 2-process use, without actually
5 5 breaking InteractiveShell itself. So we're doing something a bit ugly, where
6 6 we subclass and override what we want to fix. Once this is working well, we
7 7 can go back to the base class and refactor the code for a cleaner inheritance
8 8 implementation that doesn't rely on so much monkeypatching.
9 9
10 10 But this lets us maintain a fully working IPython as we develop the new
11 11 machinery. This should thus be thought of as scaffolding.
12 12 """
13 13 #-----------------------------------------------------------------------------
14 14 # Imports
15 15 #-----------------------------------------------------------------------------
16 16 from __future__ import print_function
17 17
18 18 # Stdlib
19 19 import os
20 20 import sys
21 21 import time
22 22
23 23 # System library imports
24 24 from zmq.eventloop import ioloop
25 25
26 26 # Our own
27 27 from IPython.core.interactiveshell import (
28 28 InteractiveShell, InteractiveShellABC
29 29 )
30 30 from IPython.core import page
31 31 from IPython.core.autocall import ZMQExitAutocall
32 32 from IPython.core.displaypub import DisplayPublisher
33 33 from IPython.core.error import UsageError
34 34 from IPython.core.magics import MacroToEdit, CodeMagics
35 35 from IPython.core.magic import magics_class, line_magic, Magics
36 36 from IPython.core.payloadpage import install_payload_page
37 37 from IPython.display import display, Javascript
38 38 from IPython.kernel.inprocess.socket import SocketABC
39 39 from IPython.kernel import (
40 40 get_connection_file, get_connection_info, connect_qtconsole
41 41 )
42 42 from IPython.testing.skipdoctest import skip_doctest
43 43 from IPython.utils import io, openpy
44 44 from IPython.utils.jsonutil import json_clean, encode_images
45 45 from IPython.utils.process import arg_split
46 46 from IPython.utils import py3compat
47 47 from IPython.utils.traitlets import Instance, Type, Dict, CBool, CBytes
48 48 from IPython.utils.warn import warn, error
49 49 from IPython.kernel.zmq.displayhook import ZMQShellDisplayHook
50 50 from IPython.kernel.zmq.datapub import ZMQDataPublisher
51 51 from IPython.kernel.zmq.session import extract_header
52 52 from session import Session
53 53
54 54 #-----------------------------------------------------------------------------
55 55 # Functions and classes
56 56 #-----------------------------------------------------------------------------
57 57
58 58 class ZMQDisplayPublisher(DisplayPublisher):
59 59 """A display publisher that publishes data using a ZeroMQ PUB socket."""
60 60
61 61 session = Instance(Session)
62 62 pub_socket = Instance(SocketABC)
63 63 parent_header = Dict({})
64 64 topic = CBytes(b'displaypub')
65 65
66 66 def set_parent(self, parent):
67 67 """Set the parent for outbound messages."""
68 68 self.parent_header = extract_header(parent)
69 69
70 70 def _flush_streams(self):
71 71 """flush IO Streams prior to display"""
72 72 sys.stdout.flush()
73 73 sys.stderr.flush()
74 74
75 75 def publish(self, source, data, metadata=None):
76 76 self._flush_streams()
77 77 if metadata is None:
78 78 metadata = {}
79 79 self._validate_data(source, data, metadata)
80 80 content = {}
81 81 content['source'] = source
82 82 content['data'] = encode_images(data)
83 83 content['metadata'] = metadata
84 84 self.session.send(
85 85 self.pub_socket, u'display_data', json_clean(content),
86 86 parent=self.parent_header, ident=self.topic,
87 87 )
88 88
89 89 def clear_output(self, stdout=True, stderr=True, other=True):
90 90 content = dict(stdout=stdout, stderr=stderr, other=other)
91 91
92 92 if stdout:
93 93 print('\r', file=sys.stdout, end='')
94 94 if stderr:
95 95 print('\r', file=sys.stderr, end='')
96 96
97 97 self._flush_streams()
98 98
99 99 self.session.send(
100 100 self.pub_socket, u'clear_output', content,
101 101 parent=self.parent_header, ident=self.topic,
102 102 )
103 103
104 104 @magics_class
105 105 class KernelMagics(Magics):
106 106 #------------------------------------------------------------------------
107 107 # Magic overrides
108 108 #------------------------------------------------------------------------
109 109 # Once the base class stops inheriting from magic, this code needs to be
110 110 # moved into a separate machinery as well. For now, at least isolate here
111 111 # the magics which this class needs to implement differently from the base
112 112 # class, or that are unique to it.
113 113
114 114 @line_magic
115 115 def doctest_mode(self, parameter_s=''):
116 116 """Toggle doctest mode on and off.
117 117
118 118 This mode is intended to make IPython behave as much as possible like a
119 119 plain Python shell, from the perspective of how its prompts, exceptions
120 120 and output look. This makes it easy to copy and paste parts of a
121 121 session into doctests. It does so by:
122 122
123 123 - Changing the prompts to the classic ``>>>`` ones.
124 124 - Changing the exception reporting mode to 'Plain'.
125 125 - Disabling pretty-printing of output.
126 126
127 127 Note that IPython also supports the pasting of code snippets that have
128 128 leading '>>>' and '...' prompts in them. This means that you can paste
129 129 doctests from files or docstrings (even if they have leading
130 130 whitespace), and the code will execute correctly. You can then use
131 131 '%history -t' to see the translated history; this will give you the
132 132 input after removal of all the leading prompts and whitespace, which
133 133 can be pasted back into an editor.
134 134
135 135 With these features, you can switch into this mode easily whenever you
136 136 need to do testing and changes to doctests, without having to leave
137 137 your existing IPython session.
138 138 """
139 139
140 140 from IPython.utils.ipstruct import Struct
141 141
142 142 # Shorthands
143 143 shell = self.shell
144 144 disp_formatter = self.shell.display_formatter
145 145 ptformatter = disp_formatter.formatters['text/plain']
146 146 # dstore is a data store kept in the instance metadata bag to track any
147 147 # changes we make, so we can undo them later.
148 148 dstore = shell.meta.setdefault('doctest_mode', Struct())
149 149 save_dstore = dstore.setdefault
150 150
151 151 # save a few values we'll need to recover later
152 152 mode = save_dstore('mode', False)
153 153 save_dstore('rc_pprint', ptformatter.pprint)
154 154 save_dstore('rc_active_types',disp_formatter.active_types)
155 155 save_dstore('xmode', shell.InteractiveTB.mode)
156 156
157 157 if mode == False:
158 158 # turn on
159 159 ptformatter.pprint = False
160 160 disp_formatter.active_types = ['text/plain']
161 161 shell.magic('xmode Plain')
162 162 else:
163 163 # turn off
164 164 ptformatter.pprint = dstore.rc_pprint
165 165 disp_formatter.active_types = dstore.rc_active_types
166 166 shell.magic("xmode " + dstore.xmode)
167 167
168 168 # Store new mode and inform on console
169 169 dstore.mode = bool(1-int(mode))
170 170 mode_label = ['OFF','ON'][dstore.mode]
171 171 print('Doctest mode is:', mode_label)
172 172
173 173 # Send the payload back so that clients can modify their prompt display
174 174 payload = dict(
175 175 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.doctest_mode',
176 176 mode=dstore.mode)
177 177 shell.payload_manager.write_payload(payload)
178 178
179 179
180 180 _find_edit_target = CodeMagics._find_edit_target
181 181
182 182 @skip_doctest
183 183 @line_magic
184 184 def edit(self, parameter_s='', last_call=['','']):
185 185 """Bring up an editor and execute the resulting code.
186 186
187 187 Usage:
188 188 %edit [options] [args]
189 189
190 190 %edit runs an external text editor. You will need to set the command for
191 191 this editor via the ``TerminalInteractiveShell.editor`` option in your
192 192 configuration file before it will work.
193 193
194 194 This command allows you to conveniently edit multi-line code right in
195 195 your IPython session.
196 196
197 197 If called without arguments, %edit opens up an empty editor with a
198 198 temporary file and will execute the contents of this file when you
199 199 close it (don't forget to save it!).
200 200
201 201
202 202 Options:
203 203
204 204 -n <number>: open the editor at a specified line number. By default,
205 205 the IPython editor hook uses the unix syntax 'editor +N filename', but
206 206 you can configure this by providing your own modified hook if your
207 207 favorite editor supports line-number specifications with a different
208 208 syntax.
209 209
210 210 -p: this will call the editor with the same data as the previous time
211 211 it was used, regardless of how long ago (in your current session) it
212 212 was.
213 213
214 214 -r: use 'raw' input. This option only applies to input taken from the
215 215 user's history. By default, the 'processed' history is used, so that
216 216 magics are loaded in their transformed version to valid Python. If
217 217 this option is given, the raw input as typed as the command line is
218 218 used instead. When you exit the editor, it will be executed by
219 219 IPython's own processor.
220 220
221 221 -x: do not execute the edited code immediately upon exit. This is
222 222 mainly useful if you are editing programs which need to be called with
223 223 command line arguments, which you can then do using %run.
224 224
225 225
226 226 Arguments:
227 227
228 228 If arguments are given, the following possibilites exist:
229 229
230 230 - The arguments are numbers or pairs of colon-separated numbers (like
231 231 1 4:8 9). These are interpreted as lines of previous input to be
232 232 loaded into the editor. The syntax is the same of the %macro command.
233 233
234 234 - If the argument doesn't start with a number, it is evaluated as a
235 235 variable and its contents loaded into the editor. You can thus edit
236 236 any string which contains python code (including the result of
237 237 previous edits).
238 238
239 239 - If the argument is the name of an object (other than a string),
240 240 IPython will try to locate the file where it was defined and open the
241 241 editor at the point where it is defined. You can use `%edit function`
242 242 to load an editor exactly at the point where 'function' is defined,
243 243 edit it and have the file be executed automatically.
244 244
245 245 If the object is a macro (see %macro for details), this opens up your
246 246 specified editor with a temporary file containing the macro's data.
247 247 Upon exit, the macro is reloaded with the contents of the file.
248 248
249 249 Note: opening at an exact line is only supported under Unix, and some
250 250 editors (like kedit and gedit up to Gnome 2.8) do not understand the
251 251 '+NUMBER' parameter necessary for this feature. Good editors like
252 252 (X)Emacs, vi, jed, pico and joe all do.
253 253
254 254 - If the argument is not found as a variable, IPython will look for a
255 255 file with that name (adding .py if necessary) and load it into the
256 256 editor. It will execute its contents with execfile() when you exit,
257 257 loading any code in the file into your interactive namespace.
258 258
259 259 After executing your code, %edit will return as output the code you
260 260 typed in the editor (except when it was an existing file). This way
261 261 you can reload the code in further invocations of %edit as a variable,
262 262 via _<NUMBER> or Out[<NUMBER>], where <NUMBER> is the prompt number of
263 263 the output.
264 264
265 265 Note that %edit is also available through the alias %ed.
266 266
267 267 This is an example of creating a simple function inside the editor and
268 268 then modifying it. First, start up the editor:
269 269
270 270 In [1]: ed
271 271 Editing... done. Executing edited code...
272 272 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
273 273
274 274 We can then call the function foo():
275 275
276 276 In [2]: foo()
277 277 foo() was defined in an editing session
278 278
279 279 Now we edit foo. IPython automatically loads the editor with the
280 280 (temporary) file where foo() was previously defined:
281 281
282 282 In [3]: ed foo
283 283 Editing... done. Executing edited code...
284 284
285 285 And if we call foo() again we get the modified version:
286 286
287 287 In [4]: foo()
288 288 foo() has now been changed!
289 289
290 290 Here is an example of how to edit a code snippet successive
291 291 times. First we call the editor:
292 292
293 293 In [5]: ed
294 294 Editing... done. Executing edited code...
295 295 hello
296 296 Out[5]: "print 'hello'n"
297 297
298 298 Now we call it again with the previous output (stored in _):
299 299
300 300 In [6]: ed _
301 301 Editing... done. Executing edited code...
302 302 hello world
303 303 Out[6]: "print 'hello world'n"
304 304
305 305 Now we call it with the output #8 (stored in _8, also as Out[8]):
306 306
307 307 In [7]: ed _8
308 308 Editing... done. Executing edited code...
309 309 hello again
310 310 Out[7]: "print 'hello again'n"
311 311 """
312 312
313 313 opts,args = self.parse_options(parameter_s,'prn:')
314 314
315 315 try:
316 316 filename, lineno, _ = CodeMagics._find_edit_target(self.shell, args, opts, last_call)
317 317 except MacroToEdit as e:
318 318 # TODO: Implement macro editing over 2 processes.
319 319 print("Macro editing not yet implemented in 2-process model.")
320 320 return
321 321
322 322 # Make sure we send to the client an absolute path, in case the working
323 323 # directory of client and kernel don't match
324 324 filename = os.path.abspath(filename)
325 325
326 326 payload = {
327 327 'source' : 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.edit_magic',
328 328 'filename' : filename,
329 329 'line_number' : lineno
330 330 }
331 331 self.shell.payload_manager.write_payload(payload)
332 332
333 333 # A few magics that are adapted to the specifics of using pexpect and a
334 334 # remote terminal
335 335
336 336 @line_magic
337 337 def clear(self, arg_s):
338 338 """Clear the terminal."""
339 339 if os.name == 'posix':
340 340 self.shell.system("clear")
341 341 else:
342 342 self.shell.system("cls")
343 343
344 344 if os.name == 'nt':
345 345 # This is the usual name in windows
346 346 cls = line_magic('cls')(clear)
347 347
348 348 # Terminal pagers won't work over pexpect, but we do have our own pager
349 349
350 350 @line_magic
351 351 def less(self, arg_s):
352 352 """Show a file through the pager.
353 353
354 354 Files ending in .py are syntax-highlighted."""
355 355 if not arg_s:
356 356 raise UsageError('Missing filename.')
357 357
358 358 cont = open(arg_s).read()
359 359 if arg_s.endswith('.py'):
360 360 cont = self.shell.pycolorize(openpy.read_py_file(arg_s, skip_encoding_cookie=False))
361 361 else:
362 362 cont = open(arg_s).read()
363 363 page.page(cont)
364 364
365 365 more = line_magic('more')(less)
366 366
367 367 # Man calls a pager, so we also need to redefine it
368 368 if os.name == 'posix':
369 369 @line_magic
370 370 def man(self, arg_s):
371 371 """Find the man page for the given command and display in pager."""
372 372 page.page(self.shell.getoutput('man %s | col -b' % arg_s,
373 373 split=False))
374 374
375 375 @line_magic
376 376 def connect_info(self, arg_s):
377 377 """Print information for connecting other clients to this kernel
378 378
379 379 It will print the contents of this session's connection file, as well as
380 380 shortcuts for local clients.
381 381
382 382 In the simplest case, when called from the most recently launched kernel,
383 383 secondary clients can be connected, simply with:
384 384
385 385 $> ipython <app> --existing
386 386
387 387 """
388 388
389 389 from IPython.core.application import BaseIPythonApplication as BaseIPApp
390 390
391 391 if BaseIPApp.initialized():
392 392 app = BaseIPApp.instance()
393 393 security_dir = app.profile_dir.security_dir
394 394 profile = app.profile
395 395 else:
396 396 profile = 'default'
397 397 security_dir = ''
398 398
399 399 try:
400 400 connection_file = get_connection_file()
401 401 info = get_connection_info(unpack=False)
402 402 except Exception as e:
403 403 error("Could not get connection info: %r" % e)
404 404 return
405 405
406 406 # add profile flag for non-default profile
407 407 profile_flag = "--profile %s" % profile if profile != 'default' else ""
408 408
409 409 # if it's in the security dir, truncate to basename
410 410 if security_dir == os.path.dirname(connection_file):
411 411 connection_file = os.path.basename(connection_file)
412 412
413 413
414 414 print (info + '\n')
415 415 print ("Paste the above JSON into a file, and connect with:\n"
416 416 " $> ipython <app> --existing <file>\n"
417 417 "or, if you are local, you can connect with just:\n"
418 418 " $> ipython <app> --existing {0} {1}\n"
419 419 "or even just:\n"
420 420 " $> ipython <app> --existing {1}\n"
421 421 "if this is the most recent IPython session you have started.".format(
422 422 connection_file, profile_flag
423 423 )
424 424 )
425 425
426 426 @line_magic
427 427 def qtconsole(self, arg_s):
428 428 """Open a qtconsole connected to this kernel.
429 429
430 430 Useful for connecting a qtconsole to running notebooks, for better
431 431 debugging.
432 432 """
433 433
434 434 # %qtconsole should imply bind_kernel for engines:
435 435 try:
436 436 from IPython.parallel import bind_kernel
437 437 except ImportError:
438 438 # technically possible, because parallel has higher pyzmq min-version
439 439 pass
440 440 else:
441 441 bind_kernel()
442 442
443 443 try:
444 444 p = connect_qtconsole(argv=arg_split(arg_s, os.name=='posix'))
445 445 except Exception as e:
446 446 error("Could not start qtconsole: %r" % e)
447 447 return
448 448
449 449 @line_magic
450 450 def autosave(self, arg_s):
451 451 """Set the autosave interval in the notebook (in seconds).
452 452
453 453 The default value is 120, or two minutes.
454 454 ``%autosave 0`` will disable autosave.
455 455
456 456 This magic only has an effect when called from the notebook interface.
457 457 It has no effect when called in a startup file.
458 458 """
459 459
460 460 try:
461 461 interval = int(arg_s)
462 462 except ValueError:
463 463 raise UsageError("%%autosave requires an integer, got %r" % arg_s)
464 464
465 465 # javascript wants milliseconds
466 466 milliseconds = 1000 * interval
467 467 display(Javascript("IPython.notebook.set_autosave_interval(%i)" % milliseconds),
468 468 include=['application/javascript']
469 469 )
470 470 if interval:
471 471 print("Autosaving every %i seconds" % interval)
472 472 else:
473 473 print("Autosave disabled")
474 474
475 def safe_unicode(e):
476 """unicode(e) with various fallbacks. Used for exceptions, which may not be
477 safe to call unicode() on.
478 """
479 try:
480 return unicode(e)
481 except UnicodeError:
482 pass
483
484 try:
485 return py3compat.str_to_unicode(str(e))
486 except UnicodeError:
487 pass
488
489 try:
490 return py3compat.str_to_unicode(repr(e))
491 except UnicodeError:
492 pass
493
494 return u'Unrecoverably corrupt evalue'
495
496 475
497 476 class ZMQInteractiveShell(InteractiveShell):
498 477 """A subclass of InteractiveShell for ZMQ."""
499 478
500 479 displayhook_class = Type(ZMQShellDisplayHook)
501 480 display_pub_class = Type(ZMQDisplayPublisher)
502 481 data_pub_class = Type(ZMQDataPublisher)
503 482
504 483 # Override the traitlet in the parent class, because there's no point using
505 484 # readline for the kernel. Can be removed when the readline code is moved
506 485 # to the terminal frontend.
507 486 colors_force = CBool(True)
508 487 readline_use = CBool(False)
509 488 # autoindent has no meaning in a zmqshell, and attempting to enable it
510 489 # will print a warning in the absence of readline.
511 490 autoindent = CBool(False)
512 491
513 492 exiter = Instance(ZMQExitAutocall)
514 493 def _exiter_default(self):
515 494 return ZMQExitAutocall(self)
516 495
517 496 def _exit_now_changed(self, name, old, new):
518 497 """stop eventloop when exit_now fires"""
519 498 if new:
520 499 loop = ioloop.IOLoop.instance()
521 500 loop.add_timeout(time.time()+0.1, loop.stop)
522 501
523 502 keepkernel_on_exit = None
524 503
525 504 # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no
526 505 # interactive input being read; we provide event loop support in ipkernel
527 506 from .eventloops import enable_gui
528 507 enable_gui = staticmethod(enable_gui)
529 508
530 509 def init_environment(self):
531 510 """Configure the user's environment.
532 511
533 512 """
534 513 env = os.environ
535 514 # These two ensure 'ls' produces nice coloring on BSD-derived systems
536 515 env['TERM'] = 'xterm-color'
537 516 env['CLICOLOR'] = '1'
538 517 # Since normal pagers don't work at all (over pexpect we don't have
539 518 # single-key control of the subprocess), try to disable paging in
540 519 # subprocesses as much as possible.
541 520 env['PAGER'] = 'cat'
542 521 env['GIT_PAGER'] = 'cat'
543 522
544 523 # And install the payload version of page.
545 524 install_payload_page()
546 525
547 526 def auto_rewrite_input(self, cmd):
548 527 """Called to show the auto-rewritten input for autocall and friends.
549 528
550 529 FIXME: this payload is currently not correctly processed by the
551 530 frontend.
552 531 """
553 532 new = self.prompt_manager.render('rewrite') + cmd
554 533 payload = dict(
555 534 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.auto_rewrite_input',
556 535 transformed_input=new,
557 536 )
558 537 self.payload_manager.write_payload(payload)
559 538
560 539 def ask_exit(self):
561 540 """Engage the exit actions."""
562 541 self.exit_now = True
563 542 payload = dict(
564 543 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.ask_exit',
565 544 exit=True,
566 545 keepkernel=self.keepkernel_on_exit,
567 546 )
568 547 self.payload_manager.write_payload(payload)
569 548
570 549 def _showtraceback(self, etype, evalue, stb):
571 550
572 551 exc_content = {
573 552 u'traceback' : stb,
574 553 u'ename' : unicode(etype.__name__),
575 u'evalue' : safe_unicode(evalue)
554 u'evalue' : py3compat.safe_unicode(evalue),
576 555 }
577 556
578 557 dh = self.displayhook
579 558 # Send exception info over pub socket for other clients than the caller
580 559 # to pick up
581 560 topic = None
582 561 if dh.topic:
583 562 topic = dh.topic.replace(b'pyout', b'pyerr')
584 563
585 564 exc_msg = dh.session.send(dh.pub_socket, u'pyerr', json_clean(exc_content), dh.parent_header, ident=topic)
586 565
587 566 # FIXME - Hack: store exception info in shell object. Right now, the
588 567 # caller is reading this info after the fact, we need to fix this logic
589 568 # to remove this hack. Even uglier, we need to store the error status
590 569 # here, because in the main loop, the logic that sets it is being
591 570 # skipped because runlines swallows the exceptions.
592 571 exc_content[u'status'] = u'error'
593 572 self._reply_content = exc_content
594 573 # /FIXME
595 574
596 575 return exc_content
597 576
598 577 def set_next_input(self, text):
599 578 """Send the specified text to the frontend to be presented at the next
600 579 input cell."""
601 580 payload = dict(
602 581 source='IPython.kernel.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
603 582 text=text
604 583 )
605 584 self.payload_manager.write_payload(payload)
606 585
607 586 #-------------------------------------------------------------------------
608 587 # Things related to magics
609 588 #-------------------------------------------------------------------------
610 589
611 590 def init_magics(self):
612 591 super(ZMQInteractiveShell, self).init_magics()
613 592 self.register_magics(KernelMagics)
614 593 self.magics_manager.register_alias('ed', 'edit')
615 594
616 595
617 596
618 597 InteractiveShellABC.register(ZMQInteractiveShell)
@@ -1,183 +1,204 b''
1 1 # coding: utf-8
2 2 """Compatibility tricks for Python 3. Mainly to do with unicode."""
3 3 import __builtin__
4 4 import functools
5 5 import sys
6 6 import re
7 7 import types
8 8
9 9 from .encoding import DEFAULT_ENCODING
10 10
11 11 orig_open = open
12 12
13 13 def no_code(x, encoding=None):
14 14 return x
15 15
16 16 def decode(s, encoding=None):
17 17 encoding = encoding or DEFAULT_ENCODING
18 18 return s.decode(encoding, "replace")
19 19
20 20 def encode(u, encoding=None):
21 21 encoding = encoding or DEFAULT_ENCODING
22 22 return u.encode(encoding, "replace")
23 23
24 24
25 25 def cast_unicode(s, encoding=None):
26 26 if isinstance(s, bytes):
27 27 return decode(s, encoding)
28 28 return s
29 29
30 30 def cast_bytes(s, encoding=None):
31 31 if not isinstance(s, bytes):
32 32 return encode(s, encoding)
33 33 return s
34 34
35 35 def _modify_str_or_docstring(str_change_func):
36 36 @functools.wraps(str_change_func)
37 37 def wrapper(func_or_str):
38 38 if isinstance(func_or_str, basestring):
39 39 func = None
40 40 doc = func_or_str
41 41 else:
42 42 func = func_or_str
43 43 doc = func.__doc__
44 44
45 45 doc = str_change_func(doc)
46 46
47 47 if func:
48 48 func.__doc__ = doc
49 49 return func
50 50 return doc
51 51 return wrapper
52 52
53 def safe_unicode(e):
54 """unicode(e) with various fallbacks. Used for exceptions, which may not be
55 safe to call unicode() on.
56 """
57 try:
58 return unicode(e)
59 except UnicodeError:
60 pass
61
62 try:
63 return py3compat.str_to_unicode(str(e))
64 except UnicodeError:
65 pass
66
67 try:
68 return py3compat.str_to_unicode(repr(e))
69 except UnicodeError:
70 pass
71
72 return u'Unrecoverably corrupt evalue'
73
53 74 if sys.version_info[0] >= 3:
54 75 PY3 = True
55 76
56 77 input = input
57 78 builtin_mod_name = "builtins"
58 79
59 80 str_to_unicode = no_code
60 81 unicode_to_str = no_code
61 82 str_to_bytes = encode
62 83 bytes_to_str = decode
63 84 cast_bytes_py2 = no_code
64 85
65 86 string_types = (str,)
66 87
67 88 def isidentifier(s, dotted=False):
68 89 if dotted:
69 90 return all(isidentifier(a) for a in s.split("."))
70 91 return s.isidentifier()
71 92
72 93 open = orig_open
73 94
74 95 MethodType = types.MethodType
75 96
76 97 def execfile(fname, glob, loc=None):
77 98 loc = loc if (loc is not None) else glob
78 99 with open(fname, 'rb') as f:
79 100 exec compile(f.read(), fname, 'exec') in glob, loc
80 101
81 102 # Refactor print statements in doctests.
82 103 _print_statement_re = re.compile(r"\bprint (?P<expr>.*)$", re.MULTILINE)
83 104 def _print_statement_sub(match):
84 105 expr = match.groups('expr')
85 106 return "print(%s)" % expr
86 107
87 108 @_modify_str_or_docstring
88 109 def doctest_refactor_print(doc):
89 110 """Refactor 'print x' statements in a doctest to print(x) style. 2to3
90 111 unfortunately doesn't pick up on our doctests.
91 112
92 113 Can accept a string or a function, so it can be used as a decorator."""
93 114 return _print_statement_re.sub(_print_statement_sub, doc)
94 115
95 116 # Abstract u'abc' syntax:
96 117 @_modify_str_or_docstring
97 118 def u_format(s):
98 119 """"{u}'abc'" --> "'abc'" (Python 3)
99 120
100 121 Accepts a string or a function, so it can be used as a decorator."""
101 122 return s.format(u='')
102 123
103 124 else:
104 125 PY3 = False
105 126
106 127 input = raw_input
107 128 builtin_mod_name = "__builtin__"
108 129
109 130 str_to_unicode = decode
110 131 unicode_to_str = encode
111 132 str_to_bytes = no_code
112 133 bytes_to_str = no_code
113 134 cast_bytes_py2 = cast_bytes
114 135
115 136 string_types = (str, unicode)
116 137
117 138 import re
118 139 _name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$")
119 140 def isidentifier(s, dotted=False):
120 141 if dotted:
121 142 return all(isidentifier(a) for a in s.split("."))
122 143 return bool(_name_re.match(s))
123 144
124 145 class open(object):
125 146 """Wrapper providing key part of Python 3 open() interface."""
126 147 def __init__(self, fname, mode="r", encoding="utf-8"):
127 148 self.f = orig_open(fname, mode)
128 149 self.enc = encoding
129 150
130 151 def write(self, s):
131 152 return self.f.write(s.encode(self.enc))
132 153
133 154 def read(self, size=-1):
134 155 return self.f.read(size).decode(self.enc)
135 156
136 157 def close(self):
137 158 return self.f.close()
138 159
139 160 def __enter__(self):
140 161 return self
141 162
142 163 def __exit__(self, etype, value, traceback):
143 164 self.f.close()
144 165
145 166 def MethodType(func, instance):
146 167 return types.MethodType(func, instance, type(instance))
147 168
148 169 # don't override system execfile on 2.x:
149 170 execfile = execfile
150 171
151 172 def doctest_refactor_print(func_or_str):
152 173 return func_or_str
153 174
154 175
155 176 # Abstract u'abc' syntax:
156 177 @_modify_str_or_docstring
157 178 def u_format(s):
158 179 """"{u}'abc'" --> "u'abc'" (Python 2)
159 180
160 181 Accepts a string or a function, so it can be used as a decorator."""
161 182 return s.format(u='u')
162 183
163 184 if sys.platform == 'win32':
164 185 def execfile(fname, glob=None, loc=None):
165 186 loc = loc if (loc is not None) else glob
166 187 # The rstrip() is necessary b/c trailing whitespace in files will
167 188 # cause an IndentationError in Python 2.6 (this was fixed in 2.7,
168 189 # but we still support 2.6). See issue 1027.
169 190 scripttext = __builtin__.open(fname).read().rstrip() + '\n'
170 191 # compile converts unicode filename to str assuming
171 192 # ascii. Let's do the conversion before calling compile
172 193 if isinstance(fname, unicode):
173 194 filename = unicode_to_str(fname)
174 195 else:
175 196 filename = fname
176 197 exec compile(scripttext, filename, 'exec') in glob, loc
177 198 else:
178 199 def execfile(fname, *where):
179 200 if isinstance(fname, unicode):
180 201 filename = fname.encode(sys.getfilesystemencoding())
181 202 else:
182 203 filename = fname
183 204 __builtin__.execfile(filename, *where)
General Comments 0
You need to be logged in to leave comments. Login now