Show More
@@ -17,6 +17,7 b' import inspect' | |||
|
17 | 17 | import io |
|
18 | 18 | import json |
|
19 | 19 | import os |
|
20 | import re | |
|
20 | 21 | import sys |
|
21 | 22 | from urllib2 import urlopen |
|
22 | 23 | |
@@ -39,6 +40,13 b' from IPython.utils.warn import warn' | |||
|
39 | 40 | # Used for exception handling in magic_edit |
|
40 | 41 | class MacroToEdit(ValueError): pass |
|
41 | 42 | |
|
43 | ipython_input_pat = re.compile(r"<ipython\-input\-(\d+)-[a-z\d]+>$") | |
|
44 | ||
|
45 | class InteractivelyDefined(Exception): | |
|
46 | """Exception for interactively defined variable in magic_edit""" | |
|
47 | def __init__(self, index): | |
|
48 | self.index = index | |
|
49 | ||
|
42 | 50 | |
|
43 | 51 | @magics_class |
|
44 | 52 | class CodeMagics(Magics): |
@@ -274,7 +282,7 b' class CodeMagics(Magics):' | |||
|
274 | 282 | if filename is None: |
|
275 | 283 | warn("Argument given (%s) can't be found as a variable " |
|
276 | 284 | "or as a filename." % args) |
|
277 | return | |
|
285 | return (None, None, None) | |
|
278 | 286 | use_temp = False |
|
279 | 287 | |
|
280 | 288 | except DataIsObject: |
@@ -302,10 +310,16 b' class CodeMagics(Magics):' | |||
|
302 | 310 | data = attr |
|
303 | 311 | break |
|
304 | 312 | |
|
313 | m = ipython_input_pat.match(os.path.basename(filename)) | |
|
314 | if m: | |
|
315 | raise InteractivelyDefined(int(m.groups()[0])) | |
|
316 | ||
|
305 | 317 | datafile = 1 |
|
306 | 318 | if filename is None: |
|
307 | 319 | filename = make_filename(args) |
|
308 | 320 | datafile = 1 |
|
321 | if filename is not None: | |
|
322 | # only warn about this if we get a real name | |
|
309 | 323 | warn('Could not find file where `%s` is defined.\n' |
|
310 | 324 | 'Opening a file named `%s`' % (args, filename)) |
|
311 | 325 | # Now, make sure we can actually read the source (if it was |
@@ -316,9 +330,9 b' class CodeMagics(Magics):' | |||
|
316 | 330 | if lineno is None: |
|
317 | 331 | filename = make_filename(args) |
|
318 | 332 | if filename is None: |
|
319 |
warn('The file |
|
|
320 |
'cannot be read.' % |
|
|
321 | return | |
|
333 | warn('The file where `%s` was defined ' | |
|
334 | 'cannot be read or found.' % data) | |
|
335 | return (None, None, None) | |
|
322 | 336 | use_temp = False |
|
323 | 337 | |
|
324 | 338 | if use_temp: |
@@ -491,6 +505,15 b' class CodeMagics(Magics):' | |||
|
491 | 505 | except MacroToEdit as e: |
|
492 | 506 | self._edit_macro(args, e.args[0]) |
|
493 | 507 | return |
|
508 | except InteractivelyDefined as e: | |
|
509 | print "Editing In[%i]" % e.index | |
|
510 | args = str(e.index) | |
|
511 | filename, lineno, is_temp = self._find_edit_target(self.shell, | |
|
512 | args, opts, last_call) | |
|
513 | if filename is None: | |
|
514 | # nothing was found, warnings have already been issued, | |
|
515 | # just give up. | |
|
516 | return | |
|
494 | 517 | |
|
495 | 518 | # do actual editing here |
|
496 | 519 | print 'Editing...', |
@@ -296,7 +296,7 b' def find_file(obj):' | |||
|
296 | 296 | pass |
|
297 | 297 | except: |
|
298 | 298 | pass |
|
299 | return fname | |
|
299 | return cast_unicode(fname) | |
|
300 | 300 | |
|
301 | 301 | |
|
302 | 302 | def find_source_lines(obj): |
@@ -326,6 +326,8 b' def find_source_lines(obj):' | |||
|
326 | 326 | # For instances, try the class object like getsource() does |
|
327 | 327 | if hasattr(obj, '__class__'): |
|
328 | 328 | lineno = inspect.getsourcelines(obj.__class__)[1] |
|
329 | else: | |
|
330 | lineno = None | |
|
329 | 331 | except: |
|
330 | 332 | return None |
|
331 | 333 |
@@ -28,7 +28,7 b' from IPython.core.magic import (Magics, magics_class, line_magic,' | |||
|
28 | 28 | cell_magic, line_cell_magic, |
|
29 | 29 | register_line_magic, register_cell_magic, |
|
30 | 30 | register_line_cell_magic) |
|
31 | from IPython.core.magics import execution, script | |
|
31 | from IPython.core.magics import execution, script, code | |
|
32 | 32 | from IPython.nbformat.v3.tests.nbexamples import nb0 |
|
33 | 33 | from IPython.nbformat import current |
|
34 | 34 | from IPython.testing import decorators as dec |
@@ -792,3 +792,49 b' def test_store():' | |||
|
792 | 792 | ip.user_ns['var'] = 39 |
|
793 | 793 | ip.run_line_magic('store' , '-r') |
|
794 | 794 | nt.assert_equal(ip.user_ns['var'], 39) |
|
795 | ||
|
796 | ||
|
797 | def _run_edit_test(arg_s, exp_filename=None, | |
|
798 | exp_lineno=-1, | |
|
799 | exp_contents=None, | |
|
800 | exp_is_temp=None): | |
|
801 | ip = get_ipython() | |
|
802 | M = code.CodeMagics(ip) | |
|
803 | last_call = ['',''] | |
|
804 | opts,args = M.parse_options(arg_s,'prxn:') | |
|
805 | filename, lineno, is_temp = M._find_edit_target(ip, args, opts, last_call) | |
|
806 | ||
|
807 | if exp_filename is not None: | |
|
808 | nt.assert_equal(exp_filename, filename) | |
|
809 | if exp_contents is not None: | |
|
810 | with io.open(filename, 'r') as f: | |
|
811 | contents = f.read() | |
|
812 | nt.assert_equal(exp_contents, contents) | |
|
813 | if exp_lineno != -1: | |
|
814 | nt.assert_equal(exp_lineno, lineno) | |
|
815 | if exp_is_temp is not None: | |
|
816 | nt.assert_equal(exp_is_temp, is_temp) | |
|
817 | ||
|
818 | ||
|
819 | def test_edit_interactive(): | |
|
820 | """%edit on interactively defined objects""" | |
|
821 | ip = get_ipython() | |
|
822 | n = ip.execution_count | |
|
823 | ip.run_cell(u"def foo(): return 1", store_history=True) | |
|
824 | ||
|
825 | try: | |
|
826 | _run_edit_test("foo") | |
|
827 | except code.InteractivelyDefined as e: | |
|
828 | nt.assert_equal(e.index, n) | |
|
829 | else: | |
|
830 | nt.fail("Should have raised InteractivelyDefined") | |
|
831 | ||
|
832 | ||
|
833 | def test_edit_cell(): | |
|
834 | """%edit [cell id]""" | |
|
835 | ip = get_ipython() | |
|
836 | ||
|
837 | ip.run_cell(u"def foo(): return 1", store_history=True) | |
|
838 | ||
|
839 | # test | |
|
840 | _run_edit_test("1", exp_contents=ip.user_ns['In'][1], exp_is_temp=True) |
General Comments 0
You need to be logged in to leave comments.
Login now