Show More
@@ -89,6 +89,9 b' def needs_local_scope(func):' | |||
|
89 | 89 | """Decorator to mark magic functions which need to local scope to run.""" |
|
90 | 90 | func.needs_local_scope = True |
|
91 | 91 | return func |
|
92 | ||
|
93 | # Used for exception handling in magic_edit | |
|
94 | class MacroToEdit(ValueError): pass | |
|
92 | 95 | |
|
93 | 96 | #*************************************************************************** |
|
94 | 97 | # Main class implementing Magic functionality |
@@ -2020,6 +2023,18 b' Currently the magic system has the following functions:\\n"""' | |||
|
2020 | 2023 | 'print macro_name'. |
|
2021 | 2024 | |
|
2022 | 2025 | """ |
|
2026 | # FIXME: This function has become a convoluted mess. It needs a | |
|
2027 | # ground-up rewrite with clean, simple logic. | |
|
2028 | def make_filename(arg): | |
|
2029 | "Make a filename from the given args" | |
|
2030 | try: | |
|
2031 | filename = get_py_filename(arg) | |
|
2032 | except IOError: | |
|
2033 | if args.endswith('.py'): | |
|
2034 | filename = arg | |
|
2035 | else: | |
|
2036 | filename = None | |
|
2037 | return filename | |
|
2023 | 2038 | |
|
2024 | 2039 | opts,args = self.parse_options(parameter_s,'r',mode='list') |
|
2025 | 2040 | if not args: # List existing macros |
@@ -2111,6 +2126,126 b' Currently the magic system has the following functions:\\n"""' | |||
|
2111 | 2126 | else: |
|
2112 | 2127 | content = open(arg_s).read() |
|
2113 | 2128 | self.set_next_input(content) |
|
2129 | ||
|
2130 | def _find_edit_target(self, args, opts, last_call): | |
|
2131 | """Utility method used by magic_edit to find what to edit.""" | |
|
2132 | ||
|
2133 | def make_filename(arg): | |
|
2134 | "Make a filename from the given args" | |
|
2135 | try: | |
|
2136 | filename = get_py_filename(arg) | |
|
2137 | except IOError: | |
|
2138 | # If it ends with .py but doesn't already exist, assume we want | |
|
2139 | # a new file. | |
|
2140 | if args.endswith('.py'): | |
|
2141 | filename = arg | |
|
2142 | else: | |
|
2143 | filename = None | |
|
2144 | return filename | |
|
2145 | ||
|
2146 | # Set a few locals from the options for convenience: | |
|
2147 | opts_prev = 'p' in opts | |
|
2148 | opts_raw = 'r' in opts | |
|
2149 | ||
|
2150 | # custom exceptions | |
|
2151 | class DataIsObject(Exception): pass | |
|
2152 | ||
|
2153 | # Default line number value | |
|
2154 | lineno = opts.get('n',None) | |
|
2155 | ||
|
2156 | if opts_prev: | |
|
2157 | args = '_%s' % last_call[0] | |
|
2158 | if not self.shell.user_ns.has_key(args): | |
|
2159 | args = last_call[1] | |
|
2160 | ||
|
2161 | # use last_call to remember the state of the previous call, but don't | |
|
2162 | # let it be clobbered by successive '-p' calls. | |
|
2163 | try: | |
|
2164 | last_call[0] = self.shell.displayhook.prompt_count | |
|
2165 | if not opts_prev: | |
|
2166 | last_call[1] = parameter_s | |
|
2167 | except: | |
|
2168 | pass | |
|
2169 | ||
|
2170 | # by default this is done with temp files, except when the given | |
|
2171 | # arg is a filename | |
|
2172 | use_temp = True | |
|
2173 | ||
|
2174 | data = '' | |
|
2175 | ||
|
2176 | # First, see if the arguments should be a filename. | |
|
2177 | filename = make_filename(args) | |
|
2178 | if filename: | |
|
2179 | use_temp = False | |
|
2180 | elif args: | |
|
2181 | # Mode where user specifies ranges of lines, like in %macro. | |
|
2182 | data = self.extract_input_lines(args, opts_raw) | |
|
2183 | if not data: | |
|
2184 | try: | |
|
2185 | # Load the parameter given as a variable. If not a string, | |
|
2186 | # process it as an object instead (below) | |
|
2187 | ||
|
2188 | #print '*** args',args,'type',type(args) # dbg | |
|
2189 | data = eval(args, self.shell.user_ns) | |
|
2190 | if not isinstance(data, basestring): | |
|
2191 | raise DataIsObject | |
|
2192 | ||
|
2193 | except (NameError,SyntaxError): | |
|
2194 | # given argument is not a variable, try as a filename | |
|
2195 | filename = make_filename(args) | |
|
2196 | if filename is None: | |
|
2197 | warn("Argument given (%s) can't be found as a variable " | |
|
2198 | "or as a filename." % args) | |
|
2199 | return | |
|
2200 | use_temp = False | |
|
2201 | ||
|
2202 | except DataIsObject: | |
|
2203 | # macros have a special edit function | |
|
2204 | if isinstance(data, Macro): | |
|
2205 | raise MacroToEdit(data) | |
|
2206 | ||
|
2207 | # For objects, try to edit the file where they are defined | |
|
2208 | try: | |
|
2209 | filename = inspect.getabsfile(data) | |
|
2210 | if 'fakemodule' in filename.lower() and inspect.isclass(data): | |
|
2211 | # class created by %edit? Try to find source | |
|
2212 | # by looking for method definitions instead, the | |
|
2213 | # __module__ in those classes is FakeModule. | |
|
2214 | attrs = [getattr(data, aname) for aname in dir(data)] | |
|
2215 | for attr in attrs: | |
|
2216 | if not inspect.ismethod(attr): | |
|
2217 | continue | |
|
2218 | filename = inspect.getabsfile(attr) | |
|
2219 | if filename and 'fakemodule' not in filename.lower(): | |
|
2220 | # change the attribute to be the edit target instead | |
|
2221 | data = attr | |
|
2222 | break | |
|
2223 | ||
|
2224 | datafile = 1 | |
|
2225 | except TypeError: | |
|
2226 | filename = make_filename(args) | |
|
2227 | datafile = 1 | |
|
2228 | warn('Could not find file where `%s` is defined.\n' | |
|
2229 | 'Opening a file named `%s`' % (args,filename)) | |
|
2230 | # Now, make sure we can actually read the source (if it was in | |
|
2231 | # a temp file it's gone by now). | |
|
2232 | if datafile: | |
|
2233 | try: | |
|
2234 | if lineno is None: | |
|
2235 | lineno = inspect.getsourcelines(data)[1] | |
|
2236 | except IOError: | |
|
2237 | filename = make_filename(args) | |
|
2238 | if filename is None: | |
|
2239 | warn('The file `%s` where `%s` was defined cannot ' | |
|
2240 | 'be read.' % (filename,data)) | |
|
2241 | return | |
|
2242 | use_temp = False | |
|
2243 | ||
|
2244 | if use_temp: | |
|
2245 | filename = self.shell.mktempfile(data) | |
|
2246 | print 'IPython will make a temporary file named:',filename | |
|
2247 | ||
|
2248 | return filename | |
|
2114 | 2249 | |
|
2115 | 2250 | def _edit_macro(self,mname,macro): |
|
2116 | 2251 | """open an editor with the macro data in a file""" |
@@ -2126,7 +2261,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
2126 | 2261 | def magic_ed(self,parameter_s=''): |
|
2127 | 2262 | """Alias to %edit.""" |
|
2128 | 2263 | return self.magic_edit(parameter_s) |
|
2129 | ||
|
2264 | ||
|
2130 | 2265 | @skip_doctest |
|
2131 | 2266 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
2132 | 2267 | """Bring up an editor and execute the resulting code. |
@@ -2269,122 +2404,13 b' Currently the magic system has the following functions:\\n"""' | |||
|
2269 | 2404 | starting example for further modifications. That file also has |
|
2270 | 2405 | general instructions on how to set a new hook for use once you've |
|
2271 | 2406 | defined it.""" |
|
2272 | ||
|
2273 | # FIXME: This function has become a convoluted mess. It needs a | |
|
2274 | # ground-up rewrite with clean, simple logic. | |
|
2275 | ||
|
2276 | def make_filename(arg): | |
|
2277 | "Make a filename from the given args" | |
|
2278 | try: | |
|
2279 | filename = get_py_filename(arg) | |
|
2280 | except IOError: | |
|
2281 | if args.endswith('.py'): | |
|
2282 | filename = arg | |
|
2283 | else: | |
|
2284 | filename = None | |
|
2285 | return filename | |
|
2286 | ||
|
2287 | # custom exceptions | |
|
2288 | class DataIsObject(Exception): pass | |
|
2289 | ||
|
2290 | 2407 | opts,args = self.parse_options(parameter_s,'prxn:') |
|
2291 | # Set a few locals from the options for convenience: | |
|
2292 | opts_prev = 'p' in opts | |
|
2293 | opts_raw = 'r' in opts | |
|
2294 | 2408 | |
|
2295 | # Default line number value | |
|
2296 | lineno = opts.get('n',None) | |
|
2297 | ||
|
2298 | if opts_prev: | |
|
2299 | args = '_%s' % last_call[0] | |
|
2300 | if not self.shell.user_ns.has_key(args): | |
|
2301 | args = last_call[1] | |
|
2302 | ||
|
2303 | # use last_call to remember the state of the previous call, but don't | |
|
2304 | # let it be clobbered by successive '-p' calls. | |
|
2305 | 2409 | try: |
|
2306 | last_call[0] = self.shell.displayhook.prompt_count | |
|
2307 | if not opts_prev: | |
|
2308 | last_call[1] = parameter_s | |
|
2309 |
|
|
|
2310 | pass | |
|
2311 | ||
|
2312 | # by default this is done with temp files, except when the given | |
|
2313 | # arg is a filename | |
|
2314 | use_temp = True | |
|
2315 | ||
|
2316 | data = '' | |
|
2317 | if args.endswith('.py'): | |
|
2318 | filename = make_filename(args) | |
|
2319 | use_temp = False | |
|
2320 | elif args: | |
|
2321 | # Mode where user specifies ranges of lines, like in %macro. | |
|
2322 | data = self.extract_input_lines(args, opts_raw) | |
|
2323 | if not data: | |
|
2324 | try: | |
|
2325 | # Load the parameter given as a variable. If not a string, | |
|
2326 | # process it as an object instead (below) | |
|
2327 | ||
|
2328 | #print '*** args',args,'type',type(args) # dbg | |
|
2329 | data = eval(args, self.shell.user_ns) | |
|
2330 | if not isinstance(data, basestring): | |
|
2331 | raise DataIsObject | |
|
2332 | ||
|
2333 | except (NameError,SyntaxError): | |
|
2334 | # given argument is not a variable, try as a filename | |
|
2335 | filename = make_filename(args) | |
|
2336 | if filename is None: | |
|
2337 | warn("Argument given (%s) can't be found as a variable " | |
|
2338 | "or as a filename." % args) | |
|
2339 | return | |
|
2340 | use_temp = False | |
|
2341 | ||
|
2342 | except DataIsObject: | |
|
2343 | # macros have a special edit function | |
|
2344 | if isinstance(data, Macro): | |
|
2345 | self._edit_macro(args,data) | |
|
2346 | return | |
|
2347 | ||
|
2348 | # For objects, try to edit the file where they are defined | |
|
2349 | try: | |
|
2350 | filename = inspect.getabsfile(data) | |
|
2351 | if 'fakemodule' in filename.lower() and inspect.isclass(data): | |
|
2352 | # class created by %edit? Try to find source | |
|
2353 | # by looking for method definitions instead, the | |
|
2354 | # __module__ in those classes is FakeModule. | |
|
2355 | attrs = [getattr(data, aname) for aname in dir(data)] | |
|
2356 | for attr in attrs: | |
|
2357 | if not inspect.ismethod(attr): | |
|
2358 | continue | |
|
2359 | filename = inspect.getabsfile(attr) | |
|
2360 | if filename and 'fakemodule' not in filename.lower(): | |
|
2361 | # change the attribute to be the edit target instead | |
|
2362 | data = attr | |
|
2363 | break | |
|
2364 | ||
|
2365 | datafile = 1 | |
|
2366 | except TypeError: | |
|
2367 | filename = make_filename(args) | |
|
2368 | datafile = 1 | |
|
2369 | warn('Could not find file where `%s` is defined.\n' | |
|
2370 | 'Opening a file named `%s`' % (args,filename)) | |
|
2371 | # Now, make sure we can actually read the source (if it was in | |
|
2372 | # a temp file it's gone by now). | |
|
2373 | if datafile: | |
|
2374 | try: | |
|
2375 | if lineno is None: | |
|
2376 | lineno = inspect.getsourcelines(data)[1] | |
|
2377 | except IOError: | |
|
2378 | filename = make_filename(args) | |
|
2379 | if filename is None: | |
|
2380 | warn('The file `%s` where `%s` was defined cannot ' | |
|
2381 | 'be read.' % (filename,data)) | |
|
2382 | return | |
|
2383 | use_temp = False | |
|
2384 | ||
|
2385 | if use_temp: | |
|
2386 | filename = self.shell.mktempfile(data) | |
|
2387 | print 'IPython will make a temporary file named:',filename | |
|
2410 | filename = self._find_edit_target(args, opts, last_call) | |
|
2411 | except MacroToEdit as e: | |
|
2412 | self._edit_macro(args, e.args[0]) | |
|
2413 | return | |
|
2388 | 2414 | |
|
2389 | 2415 | # do actual editing here |
|
2390 | 2416 | print 'Editing...', |
@@ -2392,7 +2418,7 b' Currently the magic system has the following functions:\\n"""' | |||
|
2392 | 2418 | try: |
|
2393 | 2419 | # Quote filenames that may have spaces in them |
|
2394 | 2420 | if ' ' in filename: |
|
2395 | filename = "%s" % filename | |
|
2421 | filename = "'%s'" % filename | |
|
2396 | 2422 | self.shell.hooks.editor(filename,lineno) |
|
2397 | 2423 | except TryNext: |
|
2398 | 2424 | warn('Could not open editor') |
@@ -398,131 +398,12 b' class ZMQInteractiveShell(InteractiveShell):' | |||
|
398 | 398 | starting example for further modifications. That file also has |
|
399 | 399 | general instructions on how to set a new hook for use once you've |
|
400 | 400 | defined it.""" |
|
401 | ||
|
402 | # FIXME: This function has become a convoluted mess. It needs a | |
|
403 | # ground-up rewrite with clean, simple logic. | |
|
404 | ||
|
405 | def make_filename(arg): | |
|
406 | "Make a filename from the given args" | |
|
407 | try: | |
|
408 | filename = get_py_filename(arg) | |
|
409 | except IOError: | |
|
410 | if args.endswith('.py'): | |
|
411 | filename = arg | |
|
412 | else: | |
|
413 | filename = None | |
|
414 | return filename | |
|
415 | ||
|
416 | # custom exceptions | |
|
417 | class DataIsObject(Exception): pass | |
|
418 | ||
|
419 | opts,args = self.parse_options(parameter_s,'prn:') | |
|
420 | # Set a few locals from the options for convenience: | |
|
421 | opts_p = opts.has_key('p') | |
|
422 | opts_r = opts.has_key('r') | |
|
423 | ||
|
424 | # Default line number value | |
|
425 | lineno = opts.get('n',None) | |
|
426 | if lineno is not None: | |
|
427 | try: | |
|
428 | lineno = int(lineno) | |
|
429 | except: | |
|
430 | warn("The -n argument must be an integer.") | |
|
431 | return | |
|
432 | ||
|
433 | if opts_p: | |
|
434 | args = '_%s' % last_call[0] | |
|
435 | if not self.shell.user_ns.has_key(args): | |
|
436 | args = last_call[1] | |
|
437 | ||
|
438 | # use last_call to remember the state of the previous call, but don't | |
|
439 | # let it be clobbered by successive '-p' calls. | |
|
440 | 401 | try: |
|
441 | last_call[0] = self.shell.displayhook.prompt_count | |
|
442 | if not opts_p: | |
|
443 | last_call[1] = parameter_s | |
|
444 | except: | |
|
445 |
|
|
|
446 | ||
|
447 | # by default this is done with temp files, except when the given | |
|
448 | # arg is a filename | |
|
449 | use_temp = True | |
|
450 | ||
|
451 | data = '' | |
|
452 | if args[0].isdigit(): | |
|
453 | # Mode where user specifies ranges of lines, like in %macro. | |
|
454 | # This means that you can't edit files whose names begin with | |
|
455 | # numbers this way. Tough. | |
|
456 | ranges = args.split() | |
|
457 | data = ''.join(self.extract_input_slices(ranges,opts_r)) | |
|
458 | elif args.endswith('.py'): | |
|
459 | filename = make_filename(args) | |
|
460 | use_temp = False | |
|
461 | elif args: | |
|
462 | try: | |
|
463 | # Load the parameter given as a variable. If not a string, | |
|
464 | # process it as an object instead (below) | |
|
465 | ||
|
466 | #print '*** args',args,'type',type(args) # dbg | |
|
467 | data = eval(args, self.shell.user_ns) | |
|
468 | if not isinstance(data, basestring): | |
|
469 | raise DataIsObject | |
|
470 | ||
|
471 | except (NameError,SyntaxError): | |
|
472 | # given argument is not a variable, try as a filename | |
|
473 | filename = make_filename(args) | |
|
474 | if filename is None: | |
|
475 | warn("Argument given (%s) can't be found as a variable " | |
|
476 | "or as a filename." % args) | |
|
477 | return | |
|
478 | use_temp = False | |
|
479 | ||
|
480 | except DataIsObject: | |
|
481 | # macros have a special edit function | |
|
482 | if isinstance(data, Macro): | |
|
483 | self._edit_macro(args,data) | |
|
484 | return | |
|
485 | ||
|
486 | # For objects, try to edit the file where they are defined | |
|
487 | try: | |
|
488 | filename = inspect.getabsfile(data) | |
|
489 | if 'fakemodule' in filename.lower() and inspect.isclass(data): | |
|
490 | # class created by %edit? Try to find source | |
|
491 | # by looking for method definitions instead, the | |
|
492 | # __module__ in those classes is FakeModule. | |
|
493 | attrs = [getattr(data, aname) for aname in dir(data)] | |
|
494 | for attr in attrs: | |
|
495 | if not inspect.ismethod(attr): | |
|
496 | continue | |
|
497 | filename = inspect.getabsfile(attr) | |
|
498 | if filename and 'fakemodule' not in filename.lower(): | |
|
499 | # change the attribute to be the edit target instead | |
|
500 | data = attr | |
|
501 | break | |
|
502 | ||
|
503 | datafile = 1 | |
|
504 | except TypeError: | |
|
505 | filename = make_filename(args) | |
|
506 | datafile = 1 | |
|
507 | warn('Could not find file where `%s` is defined.\n' | |
|
508 | 'Opening a file named `%s`' % (args,filename)) | |
|
509 | # Now, make sure we can actually read the source (if it was in | |
|
510 | # a temp file it's gone by now). | |
|
511 | if datafile: | |
|
512 | try: | |
|
513 | if lineno is None: | |
|
514 | lineno = inspect.getsourcelines(data)[1] | |
|
515 | except IOError: | |
|
516 | filename = make_filename(args) | |
|
517 | if filename is None: | |
|
518 | warn('The file `%s` where `%s` was defined cannot ' | |
|
519 | 'be read.' % (filename,data)) | |
|
520 | return | |
|
521 | use_temp = False | |
|
522 | ||
|
523 | if use_temp: | |
|
524 | filename = self.shell.mktempfile(data) | |
|
525 | print('IPython will make a temporary file named:', filename) | |
|
402 | filename = self._find_edit_target(args, opts, last_call) | |
|
403 | except MacroToEdit as e: | |
|
404 | # TODO: Implement macro editing over 2 processes. | |
|
405 | print "Macro editing not yet implemented in 2-process model." | |
|
406 | return | |
|
526 | 407 | |
|
527 | 408 | # Make sure we send to the client an absolute path, in case the working |
|
528 | 409 | # directory of client and kernel don't match |
General Comments 0
You need to be logged in to leave comments.
Login now