##// END OF EJS Templates
Removed another of the tweaks, and added a note in that it is largely untested.
Doug Blank -
Show More
@@ -1,147 +1,144 b''
1 1 """Compiler tools with improved interactive support.
2 2
3 3 Provides compilation machinery similar to codeop, but with caching support so
4 4 we can provide interactive tracebacks.
5 5
6 6 Authors
7 7 -------
8 8 * Robert Kern
9 9 * Fernando Perez
10 10 * Thomas Kluyver
11 11 """
12 12
13 13 # Note: though it might be more natural to name this module 'compiler', that
14 14 # name is in the stdlib and name collisions with the stdlib tend to produce
15 15 # weird problems (often with third-party tools).
16 16
17 17 #-----------------------------------------------------------------------------
18 18 # Copyright (C) 2010-2011 The IPython Development Team.
19 19 #
20 20 # Distributed under the terms of the BSD License.
21 21 #
22 22 # The full license is in the file COPYING.txt, distributed with this software.
23 23 #-----------------------------------------------------------------------------
24 24
25 25 #-----------------------------------------------------------------------------
26 26 # Imports
27 27 #-----------------------------------------------------------------------------
28 28 from __future__ import print_function
29 29
30 30 # Stdlib imports
31 31 import __future__
32 32 from ast import PyCF_ONLY_AST
33 33 import codeop
34 34 import functools
35 35 import hashlib
36 36 import linecache
37 37 import operator
38 38 import time
39 39
40 40 #-----------------------------------------------------------------------------
41 41 # Constants
42 42 #-----------------------------------------------------------------------------
43 43
44 44 # Roughtly equal to PyCF_MASK | PyCF_MASK_OBSOLETE as defined in pythonrun.h,
45 45 # this is used as a bitmask to extract future-related code flags.
46 try:
47 46 PyCF_MASK = functools.reduce(operator.or_,
48 47 (getattr(__future__, fname).compiler_flag
49 48 for fname in __future__.all_feature_names))
50 except AttributeError: # IronPython __future__'s are non-standard, 2/8/2014
51 PyCF_MASK = 0
52 49
53 50 #-----------------------------------------------------------------------------
54 51 # Local utilities
55 52 #-----------------------------------------------------------------------------
56 53
57 54 def code_name(code, number=0):
58 55 """ Compute a (probably) unique name for code for caching.
59 56
60 57 This now expects code to be unicode.
61 58 """
62 59 hash_digest = hashlib.md5(code.encode("utf-8")).hexdigest()
63 60 # Include the number and 12 characters of the hash in the name. It's
64 61 # pretty much impossible that in a single session we'll have collisions
65 62 # even with truncated hashes, and the full one makes tracebacks too long
66 63 return '<ipython-input-{0}-{1}>'.format(number, hash_digest[:12])
67 64
68 65 #-----------------------------------------------------------------------------
69 66 # Classes and functions
70 67 #-----------------------------------------------------------------------------
71 68
72 69 class CachingCompiler(codeop.Compile):
73 70 """A compiler that caches code compiled from interactive statements.
74 71 """
75 72
76 73 def __init__(self):
77 74 codeop.Compile.__init__(self)
78 75
79 76 # This is ugly, but it must be done this way to allow multiple
80 77 # simultaneous ipython instances to coexist. Since Python itself
81 78 # directly accesses the data structures in the linecache module, and
82 79 # the cache therein is global, we must work with that data structure.
83 80 # We must hold a reference to the original checkcache routine and call
84 81 # that in our own check_cache() below, but the special IPython cache
85 82 # must also be shared by all IPython instances. If we were to hold
86 83 # separate caches (one in each CachingCompiler instance), any call made
87 84 # by Python itself to linecache.checkcache() would obliterate the
88 85 # cached data from the other IPython instances.
89 86 if not hasattr(linecache, '_ipython_cache'):
90 87 linecache._ipython_cache = {}
91 88 if not hasattr(linecache, '_checkcache_ori'):
92 89 linecache._checkcache_ori = linecache.checkcache
93 90 # Now, we must monkeypatch the linecache directly so that parts of the
94 91 # stdlib that call it outside our control go through our codepath
95 92 # (otherwise we'd lose our tracebacks).
96 93 linecache.checkcache = check_linecache_ipython
97 94
98 95 def ast_parse(self, source, filename='<unknown>', symbol='exec'):
99 96 """Parse code to an AST with the current compiler flags active.
100 97
101 98 Arguments are exactly the same as ast.parse (in the standard library),
102 99 and are passed to the built-in compile function."""
103 100 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
104 101
105 102 def reset_compiler_flags(self):
106 103 """Reset compiler flags to default state."""
107 104 # This value is copied from codeop.Compile.__init__, so if that ever
108 105 # changes, it will need to be updated.
109 106 self.flags = codeop.PyCF_DONT_IMPLY_DEDENT
110 107
111 108 @property
112 109 def compiler_flags(self):
113 110 """Flags currently active in the compilation process.
114 111 """
115 112 return self.flags
116 113
117 114 def cache(self, code, number=0):
118 115 """Make a name for a block of code, and cache the code.
119 116
120 117 Parameters
121 118 ----------
122 119 code : str
123 120 The Python source code to cache.
124 121 number : int
125 122 A number which forms part of the code's name. Used for the execution
126 123 counter.
127 124
128 125 Returns
129 126 -------
130 127 The name of the cached code (as a string). Pass this as the filename
131 128 argument to compilation, so that tracebacks are correctly hooked up.
132 129 """
133 130 name = code_name(code, number)
134 131 entry = (len(code), time.time(),
135 132 [line+'\n' for line in code.splitlines()], name)
136 133 linecache.cache[name] = entry
137 134 linecache._ipython_cache[name] = entry
138 135 return name
139 136
140 137 def check_linecache_ipython(*args):
141 138 """Call linecache.checkcache() safely protecting our cached values.
142 139 """
143 140 # First call the orignal checkcache as intended
144 141 linecache._checkcache_ori(*args)
145 142 # Then, update back the cache with our data, so that tracebacks related
146 143 # to our compiled codes can be produced.
147 144 linecache.cache.update(linecache._ipython_cache)
@@ -1,60 +1,63 b''
1 """
2 cli-specific implementation of process utilities.
1 """cli-specific implementation of process utilities.
3 2
4 3 cli - Common Language Infrastructure for IronPython. Code
5 4 can run on any operating system. Check os.name for os-
6 5 specific settings.
7 6
8 7 This file is only meant to be imported by process.py, not by end-users.
8
9 This file is largely untested. To become a full drop-in process
10 interface for IronPython will probably require you to help fill
11 in the details.
9 12 """
10 13
11 14 # Import cli libraries:
12 15 import clr
13 16 import System
14 17
15 18 # Import Python libraries:
16 19 import os
17 20
18 21 # Import IPython libraries:
19 22 from IPython.utils import py3compat
20 23 from ._process_common import arg_split
21 24
22 25 def _find_cmd(cmd):
23 26 """Find the full path to a command using which."""
24 27 paths = System.Environment.GetEnvironmentVariable("PATH").Split(os.pathsep)
25 28 for path in paths:
26 29 filename = os.path.join(path, cmd)
27 30 if System.IO.File.Exists(filename):
28 31 return py3compat.bytes_to_str(filename)
29 32 raise OSError("command %r not found" % cmd)
30 33
31 34 def system(cmd):
32 35 """
33 36 system(cmd) should work in a cli environment on Mac OSX, Linux,
34 37 and Windows
35 38 """
36 39 psi = System.Diagnostics.ProcessStartInfo(cmd)
37 40 psi.RedirectStandardOutput = True
38 41 psi.RedirectStandardError = True
39 42 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
40 43 psi.UseShellExecute = False
41 44 # Start up process:
42 45 reg = System.Diagnostics.Process.Start(psi)
43 46
44 47 def getoutput(cmd):
45 48 """
46 49 getoutput(cmd) should work in a cli environment on Mac OSX, Linux,
47 50 and Windows
48 51 """
49 52 psi = System.Diagnostics.ProcessStartInfo(cmd)
50 53 psi.RedirectStandardOutput = True
51 54 psi.RedirectStandardError = True
52 55 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
53 56 psi.UseShellExecute = False
54 57 # Start up process:
55 58 reg = System.Diagnostics.Process.Start(psi)
56 59 myOutput = reg.StandardOutput
57 60 output = myOutput.ReadToEnd()
58 61 myError = reg.StandardError
59 62 error = myError.ReadToEnd()
60 63 return output
General Comments 0
You need to be logged in to leave comments. Login now