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,7 +2023,6 b' Currently the magic system has the following functions:\\n"""' | |||||
2020 | 'print macro_name'. |
|
2023 | 'print macro_name'. | |
2021 |
|
2024 | |||
2022 | """ |
|
2025 | """ | |
2023 |
|
||||
2024 | opts,args = self.parse_options(parameter_s,'r',mode='list') |
|
2026 | opts,args = self.parse_options(parameter_s,'r',mode='list') | |
2025 | if not args: # List existing macros |
|
2027 | if not args: # List existing macros | |
2026 | return sorted(k for k,v in self.shell.user_ns.iteritems() if\ |
|
2028 | return sorted(k for k,v in self.shell.user_ns.iteritems() if\ | |
@@ -2111,6 +2113,126 b' Currently the magic system has the following functions:\\n"""' | |||||
2111 | else: |
|
2113 | else: | |
2112 | content = open(arg_s).read() |
|
2114 | content = open(arg_s).read() | |
2113 | self.set_next_input(content) |
|
2115 | self.set_next_input(content) | |
|
2116 | ||||
|
2117 | def _find_edit_target(self, args, opts, last_call): | |||
|
2118 | """Utility method used by magic_edit to find what to edit.""" | |||
|
2119 | ||||
|
2120 | def make_filename(arg): | |||
|
2121 | "Make a filename from the given args" | |||
|
2122 | try: | |||
|
2123 | filename = get_py_filename(arg) | |||
|
2124 | except IOError: | |||
|
2125 | # If it ends with .py but doesn't already exist, assume we want | |||
|
2126 | # a new file. | |||
|
2127 | if args.endswith('.py'): | |||
|
2128 | filename = arg | |||
|
2129 | else: | |||
|
2130 | filename = None | |||
|
2131 | return filename | |||
|
2132 | ||||
|
2133 | # Set a few locals from the options for convenience: | |||
|
2134 | opts_prev = 'p' in opts | |||
|
2135 | opts_raw = 'r' in opts | |||
|
2136 | ||||
|
2137 | # custom exceptions | |||
|
2138 | class DataIsObject(Exception): pass | |||
|
2139 | ||||
|
2140 | # Default line number value | |||
|
2141 | lineno = opts.get('n',None) | |||
|
2142 | ||||
|
2143 | if opts_prev: | |||
|
2144 | args = '_%s' % last_call[0] | |||
|
2145 | if not self.shell.user_ns.has_key(args): | |||
|
2146 | args = last_call[1] | |||
|
2147 | ||||
|
2148 | # use last_call to remember the state of the previous call, but don't | |||
|
2149 | # let it be clobbered by successive '-p' calls. | |||
|
2150 | try: | |||
|
2151 | last_call[0] = self.shell.displayhook.prompt_count | |||
|
2152 | if not opts_prev: | |||
|
2153 | last_call[1] = parameter_s | |||
|
2154 | except: | |||
|
2155 | pass | |||
|
2156 | ||||
|
2157 | # by default this is done with temp files, except when the given | |||
|
2158 | # arg is a filename | |||
|
2159 | use_temp = True | |||
|
2160 | ||||
|
2161 | data = '' | |||
|
2162 | ||||
|
2163 | # First, see if the arguments should be a filename. | |||
|
2164 | filename = make_filename(args) | |||
|
2165 | if filename: | |||
|
2166 | use_temp = False | |||
|
2167 | elif args: | |||
|
2168 | # Mode where user specifies ranges of lines, like in %macro. | |||
|
2169 | data = self.extract_input_lines(args, opts_raw) | |||
|
2170 | if not data: | |||
|
2171 | try: | |||
|
2172 | # Load the parameter given as a variable. If not a string, | |||
|
2173 | # process it as an object instead (below) | |||
|
2174 | ||||
|
2175 | #print '*** args',args,'type',type(args) # dbg | |||
|
2176 | data = eval(args, self.shell.user_ns) | |||
|
2177 | if not isinstance(data, basestring): | |||
|
2178 | raise DataIsObject | |||
|
2179 | ||||
|
2180 | except (NameError,SyntaxError): | |||
|
2181 | # given argument is not a variable, try as a filename | |||
|
2182 | filename = make_filename(args) | |||
|
2183 | if filename is None: | |||
|
2184 | warn("Argument given (%s) can't be found as a variable " | |||
|
2185 | "or as a filename." % args) | |||
|
2186 | return | |||
|
2187 | use_temp = False | |||
|
2188 | ||||
|
2189 | except DataIsObject: | |||
|
2190 | # macros have a special edit function | |||
|
2191 | if isinstance(data, Macro): | |||
|
2192 | raise MacroToEdit(data) | |||
|
2193 | ||||
|
2194 | # For objects, try to edit the file where they are defined | |||
|
2195 | try: | |||
|
2196 | filename = inspect.getabsfile(data) | |||
|
2197 | if 'fakemodule' in filename.lower() and inspect.isclass(data): | |||
|
2198 | # class created by %edit? Try to find source | |||
|
2199 | # by looking for method definitions instead, the | |||
|
2200 | # __module__ in those classes is FakeModule. | |||
|
2201 | attrs = [getattr(data, aname) for aname in dir(data)] | |||
|
2202 | for attr in attrs: | |||
|
2203 | if not inspect.ismethod(attr): | |||
|
2204 | continue | |||
|
2205 | filename = inspect.getabsfile(attr) | |||
|
2206 | if filename and 'fakemodule' not in filename.lower(): | |||
|
2207 | # change the attribute to be the edit target instead | |||
|
2208 | data = attr | |||
|
2209 | break | |||
|
2210 | ||||
|
2211 | datafile = 1 | |||
|
2212 | except TypeError: | |||
|
2213 | filename = make_filename(args) | |||
|
2214 | datafile = 1 | |||
|
2215 | warn('Could not find file where `%s` is defined.\n' | |||
|
2216 | 'Opening a file named `%s`' % (args,filename)) | |||
|
2217 | # Now, make sure we can actually read the source (if it was in | |||
|
2218 | # a temp file it's gone by now). | |||
|
2219 | if datafile: | |||
|
2220 | try: | |||
|
2221 | if lineno is None: | |||
|
2222 | lineno = inspect.getsourcelines(data)[1] | |||
|
2223 | except IOError: | |||
|
2224 | filename = make_filename(args) | |||
|
2225 | if filename is None: | |||
|
2226 | warn('The file `%s` where `%s` was defined cannot ' | |||
|
2227 | 'be read.' % (filename,data)) | |||
|
2228 | return | |||
|
2229 | use_temp = False | |||
|
2230 | ||||
|
2231 | if use_temp: | |||
|
2232 | filename = self.shell.mktempfile(data) | |||
|
2233 | print 'IPython will make a temporary file named:',filename | |||
|
2234 | ||||
|
2235 | return filename, lineno, use_temp | |||
2114 |
|
2236 | |||
2115 | def _edit_macro(self,mname,macro): |
|
2237 | def _edit_macro(self,mname,macro): | |
2116 | """open an editor with the macro data in a file""" |
|
2238 | """open an editor with the macro data in a file""" | |
@@ -2126,7 +2248,7 b' Currently the magic system has the following functions:\\n"""' | |||||
2126 | def magic_ed(self,parameter_s=''): |
|
2248 | def magic_ed(self,parameter_s=''): | |
2127 | """Alias to %edit.""" |
|
2249 | """Alias to %edit.""" | |
2128 | return self.magic_edit(parameter_s) |
|
2250 | return self.magic_edit(parameter_s) | |
2129 |
|
2251 | |||
2130 | @skip_doctest |
|
2252 | @skip_doctest | |
2131 | def magic_edit(self,parameter_s='',last_call=['','']): |
|
2253 | def magic_edit(self,parameter_s='',last_call=['','']): | |
2132 | """Bring up an editor and execute the resulting code. |
|
2254 | """Bring up an editor and execute the resulting code. | |
@@ -2269,122 +2391,13 b' Currently the magic system has the following functions:\\n"""' | |||||
2269 | starting example for further modifications. That file also has |
|
2391 | starting example for further modifications. That file also has | |
2270 | general instructions on how to set a new hook for use once you've |
|
2392 | general instructions on how to set a new hook for use once you've | |
2271 | defined it.""" |
|
2393 | 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:') |
|
2394 | 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 |
|
2395 | |||
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: |
|
2396 | try: | |
2306 | last_call[0] = self.shell.displayhook.prompt_count |
|
2397 | filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) | |
2307 | if not opts_prev: |
|
2398 | except MacroToEdit as e: | |
2308 | last_call[1] = parameter_s |
|
2399 | self._edit_macro(args, e.args[0]) | |
2309 |
|
|
2400 | 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 |
|
2401 | |||
2389 | # do actual editing here |
|
2402 | # do actual editing here | |
2390 | print 'Editing...', |
|
2403 | print 'Editing...', | |
@@ -2392,7 +2405,7 b' Currently the magic system has the following functions:\\n"""' | |||||
2392 | try: |
|
2405 | try: | |
2393 | # Quote filenames that may have spaces in them |
|
2406 | # Quote filenames that may have spaces in them | |
2394 | if ' ' in filename: |
|
2407 | if ' ' in filename: | |
2395 | filename = "%s" % filename |
|
2408 | filename = "'%s'" % filename | |
2396 | self.shell.hooks.editor(filename,lineno) |
|
2409 | self.shell.hooks.editor(filename,lineno) | |
2397 | except TryNext: |
|
2410 | except TryNext: | |
2398 | warn('Could not open editor') |
|
2411 | warn('Could not open editor') | |
@@ -2407,15 +2420,14 b' Currently the magic system has the following functions:\\n"""' | |||||
2407 |
|
2420 | |||
2408 | else: |
|
2421 | else: | |
2409 | print 'done. Executing edited code...' |
|
2422 | print 'done. Executing edited code...' | |
2410 | if opts_raw: |
|
2423 | if 'r' in opts: # Untranslated IPython code | |
2411 | self.shell.run_cell(file_read(filename), |
|
2424 | self.shell.run_cell(file_read(filename), | |
2412 | store_history=False) |
|
2425 | store_history=False) | |
2413 | else: |
|
2426 | else: | |
2414 | self.shell.safe_execfile(filename,self.shell.user_ns, |
|
2427 | self.shell.safe_execfile(filename,self.shell.user_ns, | |
2415 | self.shell.user_ns) |
|
2428 | self.shell.user_ns) | |
2416 |
|
||||
2417 |
|
2429 | |||
2418 |
if |
|
2430 | if is_temp: | |
2419 | try: |
|
2431 | try: | |
2420 | return open(filename).read() |
|
2432 | return open(filename).read() | |
2421 | except IOError,msg: |
|
2433 | except IOError,msg: |
@@ -29,6 +29,7 b' from IPython.core.autocall import ZMQExitAutocall' | |||||
29 | from IPython.core.displayhook import DisplayHook |
|
29 | from IPython.core.displayhook import DisplayHook | |
30 | from IPython.core.displaypub import DisplayPublisher |
|
30 | from IPython.core.displaypub import DisplayPublisher | |
31 | from IPython.core.macro import Macro |
|
31 | from IPython.core.macro import Macro | |
|
32 | from IPython.core.magic import MacroToEdit | |||
32 | from IPython.core.payloadpage import install_payload_page |
|
33 | from IPython.core.payloadpage import install_payload_page | |
33 | from IPython.utils import io |
|
34 | from IPython.utils import io | |
34 | from IPython.utils.path import get_py_filename |
|
35 | from IPython.utils.path import get_py_filename | |
@@ -399,130 +400,14 b' class ZMQInteractiveShell(InteractiveShell):' | |||||
399 | general instructions on how to set a new hook for use once you've |
|
400 | general instructions on how to set a new hook for use once you've | |
400 | defined it.""" |
|
401 | defined it.""" | |
401 |
|
402 | |||
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:') |
|
403 | 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 |
|
404 | |||
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: |
|
405 | try: | |
441 | last_call[0] = self.shell.displayhook.prompt_count |
|
406 | filename, lineno, _ = self._find_edit_target(args, opts, last_call) | |
442 | if not opts_p: |
|
407 | except MacroToEdit as e: | |
443 | last_call[1] = parameter_s |
|
408 | # TODO: Implement macro editing over 2 processes. | |
444 | except: |
|
409 | print("Macro editing not yet implemented in 2-process model.") | |
445 |
|
|
410 | 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 |
|
411 | |||
527 | # Make sure we send to the client an absolute path, in case the working |
|
412 | # Make sure we send to the client an absolute path, in case the working | |
528 | # directory of client and kernel don't match |
|
413 | # directory of client and kernel don't match |
General Comments 0
You need to be logged in to leave comments.
Login now