Show More
@@ -90,6 +90,9 b' def needs_local_scope(func):' | |||||
90 | func.needs_local_scope = True |
|
90 | func.needs_local_scope = True | |
91 | return func |
|
91 | return func | |
92 |
|
92 | |||
|
93 | # Used for exception handling in magic_edit | |||
|
94 | class MacroToEdit(ValueError): pass | |||
|
95 | ||||
93 | #*************************************************************************** |
|
96 | #*************************************************************************** | |
94 | # Main class implementing Magic functionality |
|
97 | # Main class implementing Magic functionality | |
95 |
|
98 | |||
@@ -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 | |
@@ -2112,6 +2127,126 b' Currently the magic system has the following functions:\\n"""' | |||||
2112 | content = open(arg_s).read() |
|
2127 | content = open(arg_s).read() | |
2113 | self.set_next_input(content) |
|
2128 | self.set_next_input(content) | |
2114 |
|
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 | |||
|
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""" | |
2117 | filename = self.shell.mktempfile(macro.value) |
|
2252 | filename = self.shell.mktempfile(macro.value) | |
@@ -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 |
|
||||
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: |
|
|||
2306 | last_call[0] = self.shell.displayhook.prompt_count |
|
|||
2307 | if not opts_prev: |
|
|||
2308 | last_call[1] = parameter_s |
|
|||
2309 | except: |
|
|||
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 |
|
2408 | |||
2348 | # For objects, try to edit the file where they are defined |
|
|||
2349 |
|
|
2409 | try: | |
2350 | filename = inspect.getabsfile(data) |
|
2410 | filename = self._find_edit_target(args, opts, last_call) | |
2351 | if 'fakemodule' in filename.lower() and inspect.isclass(data): |
|
2411 | except MacroToEdit as e: | |
2352 | # class created by %edit? Try to find source |
|
2412 | self._edit_macro(args, e.args[0]) | |
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 |
|
|
2413 | 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,132 +398,13 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 |
|
|
401 | try: | |
428 | lineno = int(lineno) |
|
402 | filename = self._find_edit_target(args, opts, last_call) | |
429 | except: |
|
403 | except MacroToEdit as e: | |
430 | warn("The -n argument must be an integer.") |
|
404 | # TODO: Implement macro editing over 2 processes. | |
|
405 | print "Macro editing not yet implemented in 2-process model." | |||
431 |
|
|
406 | return | |
432 |
|
407 | |||
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: |
|
|||
441 | last_call[0] = self.shell.displayhook.prompt_count |
|
|||
442 | if not opts_p: |
|
|||
443 | last_call[1] = parameter_s |
|
|||
444 | except: |
|
|||
445 | pass |
|
|||
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 |
|
||||
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 | |
529 | filename = os.path.abspath(filename) |
|
410 | filename = os.path.abspath(filename) |
General Comments 0
You need to be logged in to leave comments.
Login now