diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 54bf6de..d8fa23e 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -3045,11 +3045,11 @@ Defaulting color scheme to 'NoColor'""" dir_s = self.shell.dir_stack tgt = os.path.expanduser(unquote_filename(parameter_s)) - cwd = os.getcwdu().replace(self.home_dir,'~') + cwd = os.getcwdu().replace(self.shell.home_dir,'~') if tgt: self.magic_cd(parameter_s) dir_s.insert(0,cwd) - return self.magic_dirs() + return self.shell.magic('dirs') def magic_popd(self, parameter_s=''): """Change to directory popped off the top of the stack. @@ -3417,7 +3417,7 @@ Defaulting color scheme to 'NoColor'""" ptformatter.pprint = False disp_formatter.plain_text_only = True - shell.magic_xmode('Plain') + shell.magic('xmode Plain') else: # turn off pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates @@ -3432,7 +3432,7 @@ Defaulting color scheme to 'NoColor'""" ptformatter.pprint = dstore.rc_pprint disp_formatter.plain_text_only = dstore.rc_plain_text_only - shell.magic_xmode(dstore.xmode) + shell.magic('xmode ' + dstore.xmode) # Store new mode and inform dstore.mode = bool(1-int(mode)) @@ -3487,7 +3487,8 @@ Defaulting color scheme to 'NoColor'""" """ opts, args = self.parse_options(parameter_s, 'n:') try: - filename = self.extension_manager.install_extension(args, opts.get('n')) + filename = self.shell.extension_manager.install_extension(args, + opts.get('n')) except ValueError as e: print e return @@ -3499,15 +3500,15 @@ Defaulting color scheme to 'NoColor'""" def magic_load_ext(self, module_str): """Load an IPython extension by its module name.""" - return self.extension_manager.load_extension(module_str) + return self.shell.extension_manager.load_extension(module_str) def magic_unload_ext(self, module_str): """Unload an IPython extension by its module name.""" - self.extension_manager.unload_extension(module_str) + self.shell.extension_manager.unload_extension(module_str) def magic_reload_ext(self, module_str): """Reload an IPython extension by its module name.""" - self.extension_manager.reload_extension(module_str) + self.shell.extension_manager.reload_extension(module_str) def magic_install_profiles(self, s): """%install_profiles has been deprecated.""" @@ -3681,9 +3682,10 @@ Defaulting color scheme to 'NoColor'""" if args.export: fname, name, format = current.parse_filename(args.filename) cells = [] - hist = list(self.history_manager.get_range()) + hist = list(self.shell.history_manager.get_range()) for session, prompt_number, input in hist[:-1]: - cells.append(current.new_code_cell(prompt_number=prompt_number, input=input)) + cells.append(current.new_code_cell(prompt_number=prompt_number, + input=input)) worksheet = current.new_worksheet(cells=cells) nb = current.new_notebook(name=name,worksheets=[worksheet]) with io.open(fname, 'w', encoding='utf-8') as f: diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 21008e7..2ae07cf 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -343,7 +343,7 @@ class TestSafeExecfileNonAsciiPath(unittest.TestCase): def test_1(self): """Test safe_execfile with non-ascii path """ - _ip.shell.safe_execfile(self.fname, {}, raise_exceptions=True) + _ip.safe_execfile(self.fname, {}, raise_exceptions=True) class TestSystemRaw(unittest.TestCase): @@ -351,7 +351,7 @@ class TestSystemRaw(unittest.TestCase): """Test system_raw with non-ascii cmd """ cmd = ur'''python -c "'åäö'" ''' - _ip.shell.system_raw(cmd) + _ip.system_raw(cmd) def test__IPYTHON__(): diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 530085a..0466474 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -51,7 +51,7 @@ def test_magic_parse_options(): """Test that we don't mangle paths when parsing magic options.""" ip = get_ipython() path = 'c:\\x' - opts = ip.parse_options('-f %s' % path,'f:')[0] + opts = ip._magic.parse_options('-f %s' % path,'f:')[0] # argv splitting is os-dependent if os.name == 'posix': expected = 'c:x' @@ -284,8 +284,8 @@ def test_parse_options(): """Tests for basic options parsing in magics.""" # These are only the most minimal of tests, more should be added later. At # the very least we check that basic text/unicode calls work OK. - nt.assert_equal(_ip.parse_options('foo', '')[1], 'foo') - nt.assert_equal(_ip.parse_options(u'foo', '')[1], u'foo') + nt.assert_equal(_ip._magic.parse_options('foo', '')[1], 'foo') + nt.assert_equal(_ip._magic.parse_options(u'foo', '')[1], u'foo') def test_dirops(): @@ -326,7 +326,7 @@ def test_reset_hard(): _ip.run_cell("a") nt.assert_equal(monitor, []) - _ip.magic_reset("-f") + _ip.magic("reset -f") nt.assert_equal(monitor, [1]) class TestXdel(tt.TempFileMixin): @@ -388,7 +388,7 @@ def test_whos(): def doctest_precision(): """doctest for %precision - In [1]: f = get_ipython().shell.display_formatter.formatters['text/plain'] + In [1]: f = get_ipython().display_formatter.formatters['text/plain'] In [2]: %precision 5 Out[2]: {u}'%.5f' @@ -422,7 +422,7 @@ def test_timeit_arguments(): "Test valid timeit arguments, should not cause SyntaxError (GH #1269)" _ip.magic("timeit ('#')") -@dec.skipif(_ip.magic_prun == _ip.profile_missing_notice) +@dec.skipif(_ip._magic.magic_prun == _ip._magic.profile_missing_notice) def test_prun_quotes(): "Test that prun does not clobber string escapes (GH #1302)" _ip.magic("prun -q x = '\t'") diff --git a/IPython/core/tests/test_prefilter.py b/IPython/core/tests/test_prefilter.py index 4da06b8..d14aba1 100644 --- a/IPython/core/tests/test_prefilter.py +++ b/IPython/core/tests/test_prefilter.py @@ -79,7 +79,7 @@ def test_issue_114(): msp = ip.prefilter_manager.multi_line_specials ip.prefilter_manager.multi_line_specials = False try: - for mgk in ip.lsmagic(): + for mgk in ip._magic.lsmagic(): raw = template % mgk yield nt.assert_equals(ip.prefilter(raw), raw) finally: diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py index 49c88dd..58732fb 100644 --- a/IPython/frontend/terminal/interactiveshell.py +++ b/IPython/frontend/terminal/interactiveshell.py @@ -120,6 +120,133 @@ def rerun_pasted(shell, name='pasted_block'): shell.run_cell(b) +#------------------------------------------------------------------------ +# Terminal-specific magics +#------------------------------------------------------------------------ + +def magic_autoindent(self, parameter_s = ''): + """Toggle autoindent on/off (if available).""" + + self.shell.set_autoindent() + print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] + +@skip_doctest +def magic_cpaste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + You must terminate the block with '--' (two minus-signs) or Ctrl-D + alone on the line. You can also provide your own sentinel with '%paste + -s %%' ('%%' is the new sentinel for this operation) + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%cpaste foo'. + This assigns the pasted block to variable 'foo' as string, without + dedenting or executing it (preceding >>> and + is still stripped) + + '%cpaste -r' re-executes the block previously entered by cpaste. + + Do not be alarmed by garbled output on Windows (it's a readline bug). + Just press enter and type -- (and press enter again) and the block + will be what was just pasted. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + paste: automatically pull code from clipboard. + + Examples + -------- + :: + + In [8]: %cpaste + Pasting code; enter '--' alone on the line to stop. + :>>> a = ["world!", "Hello"] + :>>> print " ".join(sorted(a)) + :-- + Hello world! + """ + + opts, name = self.parse_options(parameter_s, 'rs:', mode='string') + if 'r' in opts: + rerun_pasted(self.shell) + return + + sentinel = opts.get('s', '--') + block = strip_email_quotes(get_pasted_lines(sentinel)) + store_or_execute(self.shell, block, name) + + +def magic_paste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + The text is pulled directly from the clipboard without user + intervention and printed back on the screen before execution (unless + the -q flag is given to force quiet mode). + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%paste foo'. + This assigns the pasted block to variable 'foo' as string, without + dedenting or executing it (preceding >>> and + is still stripped) + + Options + ------- + + -r: re-executes the block previously entered by cpaste. + + -q: quiet mode: do not echo the pasted text back to the terminal. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + cpaste: manually paste code into terminal until you mark its end. + """ + opts, name = self.parse_options(parameter_s, 'rq', mode='string') + if 'r' in opts: + rerun_pasted(self.shell) + return + try: + text = self.shell.hooks.clipboard_get() + block = strip_email_quotes(text.splitlines()) + except TryNext as clipboard_exc: + message = getattr(clipboard_exc, 'args') + if message: + error(message[0]) + else: + error('Could not get text from the clipboard.') + return + + # By default, echo back to terminal unless quiet mode is requested + if 'q' not in opts: + write = self.shell.write + write(self.shell.pycolorize(block)) + if not block.endswith('\n'): + write('\n') + write("## -- End pasted text --\n") + + store_or_execute(self.shell, block, name) + + +# Class-level: add a '%cls' magic only on Windows +if sys.platform == 'win32': + def magic_cls(self, s): + """Clear screen. + """ + os.system("cls") + #----------------------------------------------------------------------------- # Main class #----------------------------------------------------------------------------- @@ -531,134 +658,21 @@ class TerminalInteractiveShell(InteractiveShell): else: self.ask_exit() - #------------------------------------------------------------------------ - # Magic overrides - #------------------------------------------------------------------------ - # Once the base class stops inheriting from magic, this code needs to be - # moved into a separate machinery as well. For now, at least isolate here - # the magics which this class needs to implement differently from the base - # class, or that are unique to it. - - def magic_autoindent(self, parameter_s = ''): - """Toggle autoindent on/off (if available).""" - - self.shell.set_autoindent() - print "Automatic indentation is:",['OFF','ON'][self.shell.autoindent] - - @skip_doctest - def magic_cpaste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - You must terminate the block with '--' (two minus-signs) or Ctrl-D - alone on the line. You can also provide your own sentinel with '%paste - -s %%' ('%%' is the new sentinel for this operation) - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%cpaste foo'. - This assigns the pasted block to variable 'foo' as string, without - dedenting or executing it (preceding >>> and + is still stripped) - - '%cpaste -r' re-executes the block previously entered by cpaste. - - Do not be alarmed by garbled output on Windows (it's a readline bug). - Just press enter and type -- (and press enter again) and the block - will be what was just pasted. - - IPython statements (magics, shell escapes) are not supported (yet). - - See also - -------- - paste: automatically pull code from clipboard. - - Examples - -------- - :: - - In [8]: %cpaste - Pasting code; enter '--' alone on the line to stop. - :>>> a = ["world!", "Hello"] - :>>> print " ".join(sorted(a)) - :-- - Hello world! - """ - - opts, name = self.parse_options(parameter_s, 'rs:', mode='string') - if 'r' in opts: - rerun_pasted(self.shell) - return - - sentinel = opts.get('s', '--') - block = strip_email_quotes(get_pasted_lines(sentinel)) - store_or_execute(self.shell, block, name) - - def magic_paste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - The text is pulled directly from the clipboard without user - intervention and printed back on the screen before execution (unless - the -q flag is given to force quiet mode). - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%paste foo'. - This assigns the pasted block to variable 'foo' as string, without - dedenting or executing it (preceding >>> and + is still stripped) - - Options - ------- - - -r: re-executes the block previously entered by cpaste. - - -q: quiet mode: do not echo the pasted text back to the terminal. - - IPython statements (magics, shell escapes) are not supported (yet). + #------------------------------------------------------------------------- + # Things related to magics + #------------------------------------------------------------------------- - See also - -------- - cpaste: manually paste code into terminal until you mark its end. - """ - opts, name = self.parse_options(parameter_s, 'rq', mode='string') - if 'r' in opts: - rerun_pasted(self.shell) - return + def init_magics(self): + super(TerminalInteractiveShell, self).init_magics() + self.define_magic('autoindent', magic_autoindent) + self.define_magic('cpaste', magic_cpaste) + self.define_magic('paste', magic_paste) try: - text = self.shell.hooks.clipboard_get() - block = strip_email_quotes(text.splitlines()) - except TryNext as clipboard_exc: - message = getattr(clipboard_exc, 'args') - if message: - error(message[0]) - else: - error('Could not get text from the clipboard.') - return - - # By default, echo back to terminal unless quiet mode is requested - if 'q' not in opts: - write = self.shell.write - write(self.shell.pycolorize(block)) - if not block.endswith('\n'): - write('\n') - write("## -- End pasted text --\n") - - store_or_execute(self.shell, block, name) - - # Class-level: add a '%cls' magic only on Windows - if sys.platform == 'win32': - def magic_cls(self, s): - """Clear screen. - """ - os.system("cls") + magic_cls + except NameError: + pass + else: + self.define_magic('cls', magic_cls) def showindentationerror(self): super(TerminalInteractiveShell, self).showindentationerror() diff --git a/IPython/parallel/client/view.py b/IPython/parallel/client/view.py index ca29e84..90c73e4 100644 --- a/IPython/parallel/client/view.py +++ b/IPython/parallel/client/view.py @@ -815,7 +815,7 @@ class DirectView(View): else: pmagic = ip.plugin_manager.get_plugin('parallelmagic') if pmagic is None: - ip.magic_load_ext('parallelmagic') + ip.magic('load_ext parallelmagic') pmagic = ip.plugin_manager.get_plugin('parallelmagic') pmagic.active_view = self diff --git a/IPython/parallel/tests/test_view.py b/IPython/parallel/tests/test_view.py index 6c1a7a0..d8cc803 100644 --- a/IPython/parallel/tests/test_view.py +++ b/IPython/parallel/tests/test_view.py @@ -374,21 +374,21 @@ class TestView(ClusterTestCase, ParametricTestCase): v.activate() v.block=True - ip.magic_px('a=5') + ip.magic('px a=5') self.assertEquals(v['a'], 5) - ip.magic_px('a=10') + ip.magic('px a=10') self.assertEquals(v['a'], 10) sio = StringIO() savestdout = sys.stdout sys.stdout = sio # just 'print a' worst ~99% of the time, but this ensures that # the stdout message has arrived when the result is finished: - ip.magic_px('import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)') + ip.magic('px import sys,time;print (a); sys.stdout.flush();time.sleep(0.2)') sys.stdout = savestdout buf = sio.getvalue() self.assertTrue('[stdout:' in buf, buf) self.assertTrue(buf.rstrip().endswith('10')) - self.assertRaisesRemote(ZeroDivisionError, ip.magic_px, '1/0') + self.assertRaisesRemote(ZeroDivisionError, ip.magic, 'px 1/0') def test_magic_px_nonblocking(self): ip = get_ipython() @@ -396,18 +396,18 @@ class TestView(ClusterTestCase, ParametricTestCase): v.activate() v.block=False - ip.magic_px('a=5') + ip.magic('px a=5') self.assertEquals(v['a'], 5) - ip.magic_px('a=10') + ip.magic('px a=10') self.assertEquals(v['a'], 10) sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_px('print a') + ip.magic('px print a') sys.stdout = savestdout buf = sio.getvalue() self.assertFalse('[stdout:%i]'%v.targets in buf) - ip.magic_px('1/0') + ip.magic('px 1/0') ar = v.get_result(-1) self.assertRaisesRemote(ZeroDivisionError, ar.get) @@ -420,12 +420,12 @@ class TestView(ClusterTestCase, ParametricTestCase): sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_autopx() + ip.magic('autopx') ip.run_cell('\n'.join(('a=5','b=10','c=0'))) ip.run_cell('b*=2') ip.run_cell('print (b)') ip.run_cell("b/c") - ip.magic_autopx() + ip.magic('autopx') sys.stdout = savestdout output = sio.getvalue().strip() self.assertTrue(output.startswith('%autopx enabled')) @@ -445,13 +445,13 @@ class TestView(ClusterTestCase, ParametricTestCase): sio = StringIO() savestdout = sys.stdout sys.stdout = sio - ip.magic_autopx() + ip.magic('autopx') ip.run_cell('\n'.join(('a=5','b=10','c=0'))) ip.run_cell('print (b)') ip.run_cell('import time; time.sleep(0.1)') ip.run_cell("b/c") ip.run_cell('b*=2') - ip.magic_autopx() + ip.magic('autopx') sys.stdout = savestdout output = sio.getvalue().strip() self.assertTrue(output.startswith('%autopx enabled')) @@ -472,10 +472,10 @@ class TestView(ClusterTestCase, ParametricTestCase): v['a'] = 111 ra = v['a'] - ar = ip.magic_result() + ar = ip.magic('result') self.assertEquals(ar.msg_ids, [v.history[-1]]) self.assertEquals(ar.get(), 111) - ar = ip.magic_result('-2') + ar = ip.magic('result -2') self.assertEquals(ar.msg_ids, [v.history[-2]]) def test_unicode_execute(self):