##// END OF EJS Templates
Refactor magic_edit code somewhat.
Thomas Kluyver -
Show More
@@ -89,6 +89,9 b' def needs_local_scope(func):'
89 """Decorator to mark magic functions which need to local scope to run."""
89 """Decorator to mark magic functions which need to local scope to run."""
90 func.needs_local_scope = True
90 func.needs_local_scope = True
91 return func
91 return func
92
93 # Used for exception handling in magic_edit
94 class MacroToEdit(ValueError): pass
92
95
93 #***************************************************************************
96 #***************************************************************************
94 # Main class implementing Magic functionality
97 # Main class implementing Magic functionality
@@ -2020,6 +2023,18 b' Currently the magic system has the following functions:\\n"""'
2020 'print macro_name'.
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 opts,args = self.parse_options(parameter_s,'r',mode='list')
2039 opts,args = self.parse_options(parameter_s,'r',mode='list')
2025 if not args: # List existing macros
2040 if not args: # List existing macros
@@ -2111,6 +2126,126 b' Currently the magic system has the following functions:\\n"""'
2111 else:
2126 else:
2112 content = open(arg_s).read()
2127 content = open(arg_s).read()
2113 self.set_next_input(content)
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 def _edit_macro(self,mname,macro):
2250 def _edit_macro(self,mname,macro):
2116 """open an editor with the macro data in a file"""
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 def magic_ed(self,parameter_s=''):
2261 def magic_ed(self,parameter_s=''):
2127 """Alias to %edit."""
2262 """Alias to %edit."""
2128 return self.magic_edit(parameter_s)
2263 return self.magic_edit(parameter_s)
2129
2264
2130 @skip_doctest
2265 @skip_doctest
2131 def magic_edit(self,parameter_s='',last_call=['','']):
2266 def magic_edit(self,parameter_s='',last_call=['','']):
2132 """Bring up an editor and execute the resulting code.
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 starting example for further modifications. That file also has
2404 starting example for further modifications. That file also has
2270 general instructions on how to set a new hook for use once you've
2405 general instructions on how to set a new hook for use once you've
2271 defined it."""
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 opts,args = self.parse_options(parameter_s,'prxn:')
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 try:
2409 try:
2306 last_call[0] = self.shell.displayhook.prompt_count
2410 filename = self._find_edit_target(args, opts, last_call)
2307 if not opts_prev:
2411 except MacroToEdit as e:
2308 last_call[1] = parameter_s
2412 self._edit_macro(args, e.args[0])
2309 except:
2413 return
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
2388
2414
2389 # do actual editing here
2415 # do actual editing here
2390 print 'Editing...',
2416 print 'Editing...',
@@ -2392,7 +2418,7 b' Currently the magic system has the following functions:\\n"""'
2392 try:
2418 try:
2393 # Quote filenames that may have spaces in them
2419 # Quote filenames that may have spaces in them
2394 if ' ' in filename:
2420 if ' ' in filename:
2395 filename = "%s" % filename
2421 filename = "'%s'" % filename
2396 self.shell.hooks.editor(filename,lineno)
2422 self.shell.hooks.editor(filename,lineno)
2397 except TryNext:
2423 except TryNext:
2398 warn('Could not open editor')
2424 warn('Could not open editor')
@@ -398,131 +398,12 b' class ZMQInteractiveShell(InteractiveShell):'
398 starting example for further modifications. That file also has
398 starting example for further modifications. That file also has
399 general instructions on how to set a new hook for use once you've
399 general instructions on how to set a new hook for use once you've
400 defined it."""
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 try:
401 try:
441 last_call[0] = self.shell.displayhook.prompt_count
402 filename = self._find_edit_target(args, opts, last_call)
442 if not opts_p:
403 except MacroToEdit as e:
443 last_call[1] = parameter_s
404 # TODO: Implement macro editing over 2 processes.
444 except:
405 print "Macro editing not yet implemented in 2-process model."
445 pass
406 return
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)
526
407
527 # Make sure we send to the client an absolute path, in case the working
408 # Make sure we send to the client an absolute path, in case the working
528 # directory of client and kernel don't match
409 # directory of client and kernel don't match
General Comments 0
You need to be logged in to leave comments. Login now