##// END OF EJS Templates
adds the optional parameter -s to the magic %load that loads specific function or classes from the python source given. forcing the patch ignoring whitespace changes
Martín Gaitán -
Show More
@@ -18,6 +18,7 b' import io'
18 18 import os
19 19 import re
20 20 import sys
21 import ast
21 22 from itertools import chain
22 23
23 24 # Our own packages
@@ -47,7 +48,6 b' range_re = re.compile(r"""'
47 48 (?P<end>\d+)?)?
48 49 $""", re.VERBOSE)
49 50
50
51 51 def extract_code_ranges(ranges_str):
52 52 """Turn a string of range for %%load into 2-tuples of (start, stop)
53 53 ready to use as a slice of the content splitted by lines.
@@ -76,6 +76,40 b' def extract_code_ranges(ranges_str):'
76 76 start = int(start) - 1
77 77 yield (start, end)
78 78
79 def extract_symbols(code, symbols):
80 """
81 Return a list of code fragments for each symbol parsed from code
82 For example, suppose code is::
83
84 a = 10
85
86 def b(): return 42
87
88 class A: pass
89
90 >>> extract_symbols(code, 'A,b'):
91 class A: pass
92
93 def b(): return 42
94 """
95 try:
96 py_code = ast.parse(code)
97 except SyntaxError:
98 return []
99 marks = [(getattr(s, 'name', None), s.lineno) for s in py_code.body]
100 end = None
101 symbols_lines = {}
102 for name, start in reversed(marks):
103 if name:
104 symbols_lines[name] = (start - 1, end)
105 end = start - 1
106 blocks = []
107 code = code.split('\n')
108 for symbol in symbols.split(','):
109 if symbol in symbols_lines:
110 blocks.append('\n'.join(code[slice(*symbols_lines[symbol])]))
111 return blocks
112
79 113
80 114 class InteractivelyDefined(Exception):
81 115 """Exception for interactively defined variable in magic_edit"""
@@ -217,6 +251,8 b' class CodeMagics(Magics):'
217 251 (x..(y-1)). Both limits x and y can be left blank (meaning the
218 252 beginning and end of the file, respectively).
219 253
254 -s <symbols>: Specify function or classes to load from python source. Could be
255
220 256 -y : Don't ask confirmation for loading source above 200 000 characters.
221 257
222 258 This magic command can either take a local filename, a URL, an history
@@ -230,8 +266,9 b' class CodeMagics(Magics):'
230 266 %load http://www.example.com/myscript.py
231 267 %load -r 5-10 myscript.py
232 268 %load -r 10-20,30,40: foo.py
269 %load -s MyClass,wonder_function myscript.py
233 270 """
234 opts,args = self.parse_options(arg_s,'yr:')
271 opts,args = self.parse_options(arg_s,'ys:r:')
235 272
236 273 if not args:
237 274 raise UsageError('Missing filename, URL, input history range, '
@@ -239,6 +276,9 b' class CodeMagics(Magics):'
239 276
240 277 contents = self.shell.find_user_code(args)
241 278
279 if 's' in opts:
280 contents = '\n'.join(extract_symbols(contents, opts['s']))
281
242 282 if 'r' in opts:
243 283 ranges = opts['r'].replace(',', ' ')
244 284 lines = contents.split('\n')
@@ -248,7 +288,6 b' class CodeMagics(Magics):'
248 288
249 289 l = len(contents)
250 290
251
252 291 # 200 000 is ~ 2500 full 80 caracter lines
253 292 # so in average, more than 5000 lines
254 293 if l > 200000 and 'y' not in opts:
@@ -60,6 +60,28 b' def test_extract_code_ranges():'
60 60 actual = list(code.extract_code_ranges(instr))
61 61 nt.assert_equal(actual, expected)
62 62
63
64 def test_extract_symbols():
65 source = """import foo\na = 10\ndef b():\n return 42\nclass A: pass\n"""
66 symbols_args = ["a", "b", "A", "A,b", "A,a", "z"]
67 expected = [[],
68 ["def b():\n return 42"],
69 ["class A: pass\n"],
70 ["class A: pass\n", "def b():\n return 42"],
71 ["class A: pass\n"],
72 []]
73 for symbols, exp in zip(symbols_args, expected):
74 nt.assert_equal(code.extract_symbols(source, symbols), exp)
75
76
77 def test_extract_symbols_ignores_non_python_code():
78 source = ("=begin A Ruby program :)=end\n"
79 "def hello\n"
80 "puts 'Hello world'\n"
81 "end")
82 nt.assert_equal(code.extract_symbols(source, "hello"), [])
83
84
63 85 def test_rehashx():
64 86 # clear up everything
65 87 _ip = get_ipython()
General Comments 0
You need to be logged in to leave comments. Login now