##// END OF EJS Templates
remove code deprecated since at least IPython 5.0
Matthias Bussonnier -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,60 +1,60 b''
1 name: Run tests
1 name: Run tests
2
2
3 on:
3 on:
4 push:
4 push:
5 pull_request:
5 pull_request:
6 # Run weekly on Monday at 1:23 UTC
6 # Run weekly on Monday at 1:23 UTC
7 schedule:
7 schedule:
8 - cron: '23 1 * * 1'
8 - cron: '23 1 * * 1'
9 workflow_dispatch:
9 workflow_dispatch:
10
10
11
11
12 jobs:
12 jobs:
13 test:
13 test:
14 runs-on: ${{ matrix.os }}
14 runs-on: ${{ matrix.os }}
15 strategy:
15 strategy:
16 matrix:
16 matrix:
17 os: [ubuntu-latest, windows-latest]
17 os: [ubuntu-latest, windows-latest]
18 python-version: ["3.8", "3.9", "3.10"]
18 python-version: ["3.8", "3.9", "3.10"]
19 deps: [test_extra]
19 deps: [test_extra]
20 # Test all on ubuntu, test ends on macos
20 # Test all on ubuntu, test ends on macos
21 include:
21 include:
22 - os: macos-latest
22 - os: macos-latest
23 python-version: "3.8"
23 python-version: "3.8"
24 deps: test_extra
24 deps: test_extra
25 - os: macos-latest
25 - os: macos-latest
26 python-version: "3.10"
26 python-version: "3.10"
27 deps: test_extra
27 deps: test_extra
28 # Tests minimal dependencies set
28 # Tests minimal dependencies set
29 - os: ubuntu-latest
29 - os: ubuntu-latest
30 python-version: "3.10"
30 python-version: "3.10"
31 deps: test
31 deps: test
32 # Tests latest development Python version
32 # Tests latest development Python version
33 - os: ubuntu-latest
33 - os: ubuntu-latest
34 python-version: "3.11-dev"
34 python-version: "3.11-dev"
35 deps: test
35 deps: test
36
36
37 steps:
37 steps:
38 - uses: actions/checkout@v2
38 - uses: actions/checkout@v2
39 - name: Set up Python ${{ matrix.python-version }}
39 - name: Set up Python ${{ matrix.python-version }}
40 uses: actions/setup-python@v2
40 uses: actions/setup-python@v2
41 with:
41 with:
42 python-version: ${{ matrix.python-version }}
42 python-version: ${{ matrix.python-version }}
43 - name: Install latex
43 - name: Install latex
44 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
44 if: runner.os == 'Linux' && matrix.deps == 'test_extra'
45 run: sudo apt-get -yq -o Acquire::Retries=3 --no-install-suggests --no-install-recommends install texlive dvipng
45 run: sudo apt-get -yq -o Acquire::Retries=3 --no-install-suggests --no-install-recommends install texlive dvipng
46 - name: Install and update Python dependencies
46 - name: Install and update Python dependencies
47 run: |
47 run: |
48 python -m pip install --upgrade pip setuptools wheel
48 python -m pip install --upgrade pip setuptools wheel
49 python -m pip install --upgrade -e .[${{ matrix.deps }}]
49 python -m pip install --upgrade -e .[${{ matrix.deps }}]
50 python -m pip install --upgrade check-manifest pytest-cov
50 python -m pip install --upgrade check-manifest pytest-cov
51 - name: Check manifest
51 - name: Check manifest
52 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
52 if: runner.os != 'Windows' # setup.py does not support sdist on Windows
53 run: check-manifest
53 run: check-manifest
54 - name: pytest
54 - name: pytest
55 env:
55 env:
56 COLUMNS: 120
56 COLUMNS: 120
57 run: |
57 run: |
58 pytest --color=yes -ra -v --cov --cov-report=xml
58 pytest --color=yes -raXxs --cov --cov-report=xml
59 - name: Upload coverage to Codecov
59 - name: Upload coverage to Codecov
60 uses: codecov/codecov-action@v2
60 uses: codecov/codecov-action@v2
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
@@ -1,187 +1,187 b''
1 """Tests for various magic functions specific to the terminal frontend."""
1 """Tests for various magic functions specific to the terminal frontend."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Imports
4 # Imports
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6
6
7 import sys
7 import sys
8 from io import StringIO
8 from io import StringIO
9 from unittest import TestCase
9 from unittest import TestCase
10
10
11 from IPython.testing import tools as tt
11 from IPython.testing import tools as tt
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Test functions begin
14 # Test functions begin
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 def check_cpaste(code, should_fail=False):
17 def check_cpaste(code, should_fail=False):
18 """Execute code via 'cpaste' and ensure it was executed, unless
18 """Execute code via 'cpaste' and ensure it was executed, unless
19 should_fail is set.
19 should_fail is set.
20 """
20 """
21 ip.user_ns['code_ran'] = False
21 ip.user_ns['code_ran'] = False
22
22
23 src = StringIO()
23 src = StringIO()
24 src.write(code)
24 src.write(code)
25 src.write('\n--\n')
25 src.write('\n--\n')
26 src.seek(0)
26 src.seek(0)
27
27
28 stdin_save = sys.stdin
28 stdin_save = sys.stdin
29 sys.stdin = src
29 sys.stdin = src
30
30
31 try:
31 try:
32 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
32 context = tt.AssertPrints if should_fail else tt.AssertNotPrints
33 with context("Traceback (most recent call last)"):
33 with context("Traceback (most recent call last)"):
34 ip.magic('cpaste')
34 ip.magic('cpaste')
35
35
36 if not should_fail:
36 if not should_fail:
37 assert ip.user_ns['code_ran'], "%r failed" % code
37 assert ip.user_ns['code_ran'], "%r failed" % code
38 finally:
38 finally:
39 sys.stdin = stdin_save
39 sys.stdin = stdin_save
40
40
41 def test_cpaste():
41 def test_cpaste():
42 """Test cpaste magic"""
42 """Test cpaste magic"""
43
43
44 def runf():
44 def runf():
45 """Marker function: sets a flag when executed.
45 """Marker function: sets a flag when executed.
46 """
46 """
47 ip.user_ns['code_ran'] = True
47 ip.user_ns['code_ran'] = True
48 return 'runf' # return string so '+ runf()' doesn't result in success
48 return 'runf' # return string so '+ runf()' doesn't result in success
49
49
50 tests = {'pass': ["runf()",
50 tests = {'pass': ["runf()",
51 "In [1]: runf()",
51 "In [1]: runf()",
52 "In [1]: if 1:\n ...: runf()",
52 "In [1]: if 1:\n ...: runf()",
53 "> > > runf()",
53 "> > > runf()",
54 ">>> runf()",
54 ">>> runf()",
55 " >>> runf()",
55 " >>> runf()",
56 ],
56 ],
57
57
58 'fail': ["1 + runf()",
58 'fail': ["1 + runf()",
59 "++ runf()",
59 "++ runf()",
60 ]}
60 ]}
61
61
62 ip.user_ns['runf'] = runf
62 ip.user_ns['runf'] = runf
63
63
64 for code in tests['pass']:
64 for code in tests['pass']:
65 check_cpaste(code)
65 check_cpaste(code)
66
66
67 for code in tests['fail']:
67 for code in tests['fail']:
68 check_cpaste(code, should_fail=True)
68 check_cpaste(code, should_fail=True)
69
69
70
70
71 class PasteTestCase(TestCase):
71 class PasteTestCase(TestCase):
72 """Multiple tests for clipboard pasting"""
72 """Multiple tests for clipboard pasting"""
73
73
74 def paste(self, txt, flags='-q'):
74 def paste(self, txt, flags='-q'):
75 """Paste input text, by default in quiet mode"""
75 """Paste input text, by default in quiet mode"""
76 ip.hooks.clipboard_get = lambda : txt
76 ip.hooks.clipboard_get = lambda : txt
77 ip.magic('paste '+flags)
77 ip.magic('paste '+flags)
78
78
79 def setUp(self):
79 def setUp(self):
80 # Inject fake clipboard hook but save original so we can restore it later
80 # Inject fake clipboard hook but save original so we can restore it later
81 self.original_clip = ip.hooks.clipboard_get
81 self.original_clip = ip.hooks.clipboard_get
82
82
83 def tearDown(self):
83 def tearDown(self):
84 # Restore original hook
84 # Restore original hook
85 ip.hooks.clipboard_get = self.original_clip
85 ip.hooks.clipboard_get = self.original_clip
86
86
87 def test_paste(self):
87 def test_paste(self):
88 ip.user_ns.pop("x", None)
88 ip.user_ns.pop("x", None)
89 self.paste("x = 1")
89 self.paste("x = 1")
90 self.assertEqual(ip.user_ns["x"], 1)
90 self.assertEqual(ip.user_ns["x"], 1)
91 ip.user_ns.pop("x")
91 ip.user_ns.pop("x")
92
92
93 def test_paste_pyprompt(self):
93 def test_paste_pyprompt(self):
94 ip.user_ns.pop("x", None)
94 ip.user_ns.pop("x", None)
95 self.paste(">>> x=2")
95 self.paste(">>> x=2")
96 self.assertEqual(ip.user_ns["x"], 2)
96 self.assertEqual(ip.user_ns["x"], 2)
97 ip.user_ns.pop("x")
97 ip.user_ns.pop("x")
98
98
99 def test_paste_py_multi(self):
99 def test_paste_py_multi(self):
100 self.paste("""
100 self.paste("""
101 >>> x = [1,2,3]
101 >>> x = [1,2,3]
102 >>> y = []
102 >>> y = []
103 >>> for i in x:
103 >>> for i in x:
104 ... y.append(i**2)
104 ... y.append(i**2)
105 ...
105 ...
106 """
106 """
107 )
107 )
108 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
108 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
109 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
109 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
110
110
111 def test_paste_py_multi_r(self):
111 def test_paste_py_multi_r(self):
112 "Now, test that self.paste -r works"
112 "Now, test that self.paste -r works"
113 self.test_paste_py_multi()
113 self.test_paste_py_multi()
114 self.assertEqual(ip.user_ns.pop("x"), [1, 2, 3])
114 self.assertEqual(ip.user_ns.pop("x"), [1, 2, 3])
115 self.assertEqual(ip.user_ns.pop("y"), [1, 4, 9])
115 self.assertEqual(ip.user_ns.pop("y"), [1, 4, 9])
116 self.assertFalse("x" in ip.user_ns)
116 self.assertFalse("x" in ip.user_ns)
117 ip.magic("paste -r")
117 ip.magic("paste -r")
118 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
118 self.assertEqual(ip.user_ns["x"], [1, 2, 3])
119 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
119 self.assertEqual(ip.user_ns["y"], [1, 4, 9])
120
120
121 def test_paste_email(self):
121 def test_paste_email(self):
122 "Test pasting of email-quoted contents"
122 "Test pasting of email-quoted contents"
123 self.paste("""\
123 self.paste("""\
124 >> def foo(x):
124 >> def foo(x):
125 >> return x + 1
125 >> return x + 1
126 >> xx = foo(1.1)"""
126 >> xx = foo(1.1)"""
127 )
127 )
128 self.assertEqual(ip.user_ns["xx"], 2.1)
128 self.assertEqual(ip.user_ns["xx"], 2.1)
129
129
130 def test_paste_email2(self):
130 def test_paste_email2(self):
131 "Email again; some programs add a space also at each quoting level"
131 "Email again; some programs add a space also at each quoting level"
132 self.paste("""\
132 self.paste("""\
133 > > def foo(x):
133 > > def foo(x):
134 > > return x + 1
134 > > return x + 1
135 > > yy = foo(2.1) """
135 > > yy = foo(2.1) """
136 )
136 )
137 self.assertEqual(ip.user_ns["yy"], 3.1)
137 self.assertEqual(ip.user_ns["yy"], 3.1)
138
138
139 def test_paste_email_py(self):
139 def test_paste_email_py(self):
140 "Email quoting of interactive input"
140 "Email quoting of interactive input"
141 self.paste("""\
141 self.paste("""\
142 >> >>> def f(x):
142 >> >>> def f(x):
143 >> ... return x+1
143 >> ... return x+1
144 >> ...
144 >> ...
145 >> >>> zz = f(2.5) """
145 >> >>> zz = f(2.5) """
146 )
146 )
147 self.assertEqual(ip.user_ns["zz"], 3.5)
147 self.assertEqual(ip.user_ns["zz"], 3.5)
148
148
149 def test_paste_echo(self):
149 def test_paste_echo(self):
150 "Also test self.paste echoing, by temporarily faking the writer"
150 "Also test self.paste echoing, by temporarily faking the writer"
151 w = StringIO()
151 w = StringIO()
152 writer = ip.write
152 old_write = sys.stdout.write
153 ip.write = w.write
153 sys.stdout.write = w.write
154 code = """
154 code = """
155 a = 100
155 a = 100
156 b = 200"""
156 b = 200"""
157 try:
157 try:
158 self.paste(code,'')
158 self.paste(code,'')
159 out = w.getvalue()
159 out = w.getvalue()
160 finally:
160 finally:
161 ip.write = writer
161 sys.stdout.write = old_write
162 self.assertEqual(ip.user_ns["a"], 100)
162 self.assertEqual(ip.user_ns["a"], 100)
163 self.assertEqual(ip.user_ns["b"], 200)
163 self.assertEqual(ip.user_ns["b"], 200)
164 assert out == code + "\n## -- End pasted text --\n"
164 assert out == code + "\n## -- End pasted text --\n"
165
165
166 def test_paste_leading_commas(self):
166 def test_paste_leading_commas(self):
167 "Test multiline strings with leading commas"
167 "Test multiline strings with leading commas"
168 tm = ip.magics_manager.registry['TerminalMagics']
168 tm = ip.magics_manager.registry['TerminalMagics']
169 s = '''\
169 s = '''\
170 a = """
170 a = """
171 ,1,2,3
171 ,1,2,3
172 """'''
172 """'''
173 ip.user_ns.pop("foo", None)
173 ip.user_ns.pop("foo", None)
174 tm.store_or_execute(s, "foo")
174 tm.store_or_execute(s, "foo")
175 self.assertIn("foo", ip.user_ns)
175 self.assertIn("foo", ip.user_ns)
176
176
177 def test_paste_trailing_question(self):
177 def test_paste_trailing_question(self):
178 "Test pasting sources with trailing question marks"
178 "Test pasting sources with trailing question marks"
179 tm = ip.magics_manager.registry['TerminalMagics']
179 tm = ip.magics_manager.registry['TerminalMagics']
180 s = '''\
180 s = '''\
181 def funcfoo():
181 def funcfoo():
182 if True: #am i true?
182 if True: #am i true?
183 return 'fooresult'
183 return 'fooresult'
184 '''
184 '''
185 ip.user_ns.pop('funcfoo', None)
185 ip.user_ns.pop('funcfoo', None)
186 self.paste(s)
186 self.paste(s)
187 self.assertEqual(ip.user_ns["funcfoo"](), "fooresult")
187 self.assertEqual(ip.user_ns["funcfoo"](), "fooresult")
@@ -1,215 +1,214 b''
1 """Extra magics for terminal use."""
1 """Extra magics for terminal use."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6
6
7 from logging import error
7 from logging import error
8 import os
8 import os
9 import sys
9 import sys
10
10
11 from IPython.core.error import TryNext, UsageError
11 from IPython.core.error import TryNext, UsageError
12 from IPython.core.magic import Magics, magics_class, line_magic
12 from IPython.core.magic import Magics, magics_class, line_magic
13 from IPython.lib.clipboard import ClipboardEmpty
13 from IPython.lib.clipboard import ClipboardEmpty
14 from IPython.testing.skipdoctest import skip_doctest
14 from IPython.testing.skipdoctest import skip_doctest
15 from IPython.utils.text import SList, strip_email_quotes
15 from IPython.utils.text import SList, strip_email_quotes
16 from IPython.utils import py3compat
16 from IPython.utils import py3compat
17
17
18 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
18 def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
19 """ Yield pasted lines until the user enters the given sentinel value.
19 """ Yield pasted lines until the user enters the given sentinel value.
20 """
20 """
21 if not quiet:
21 if not quiet:
22 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
22 print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
23 % sentinel)
23 % sentinel)
24 prompt = ":"
24 prompt = ":"
25 else:
25 else:
26 prompt = ""
26 prompt = ""
27 while True:
27 while True:
28 try:
28 try:
29 l = l_input(prompt)
29 l = l_input(prompt)
30 if l == sentinel:
30 if l == sentinel:
31 return
31 return
32 else:
32 else:
33 yield l
33 yield l
34 except EOFError:
34 except EOFError:
35 print('<EOF>')
35 print('<EOF>')
36 return
36 return
37
37
38
38
39 @magics_class
39 @magics_class
40 class TerminalMagics(Magics):
40 class TerminalMagics(Magics):
41 def __init__(self, shell):
41 def __init__(self, shell):
42 super(TerminalMagics, self).__init__(shell)
42 super(TerminalMagics, self).__init__(shell)
43
43
44 def store_or_execute(self, block, name):
44 def store_or_execute(self, block, name):
45 """ Execute a block, or store it in a variable, per the user's request.
45 """ Execute a block, or store it in a variable, per the user's request.
46 """
46 """
47 if name:
47 if name:
48 # If storing it for further editing
48 # If storing it for further editing
49 self.shell.user_ns[name] = SList(block.splitlines())
49 self.shell.user_ns[name] = SList(block.splitlines())
50 print("Block assigned to '%s'" % name)
50 print("Block assigned to '%s'" % name)
51 else:
51 else:
52 b = self.preclean_input(block)
52 b = self.preclean_input(block)
53 self.shell.user_ns['pasted_block'] = b
53 self.shell.user_ns['pasted_block'] = b
54 self.shell.using_paste_magics = True
54 self.shell.using_paste_magics = True
55 try:
55 try:
56 self.shell.run_cell(b)
56 self.shell.run_cell(b)
57 finally:
57 finally:
58 self.shell.using_paste_magics = False
58 self.shell.using_paste_magics = False
59
59
60 def preclean_input(self, block):
60 def preclean_input(self, block):
61 lines = block.splitlines()
61 lines = block.splitlines()
62 while lines and not lines[0].strip():
62 while lines and not lines[0].strip():
63 lines = lines[1:]
63 lines = lines[1:]
64 return strip_email_quotes('\n'.join(lines))
64 return strip_email_quotes('\n'.join(lines))
65
65
66 def rerun_pasted(self, name='pasted_block'):
66 def rerun_pasted(self, name='pasted_block'):
67 """ Rerun a previously pasted command.
67 """ Rerun a previously pasted command.
68 """
68 """
69 b = self.shell.user_ns.get(name)
69 b = self.shell.user_ns.get(name)
70
70
71 # Sanity checks
71 # Sanity checks
72 if b is None:
72 if b is None:
73 raise UsageError('No previous pasted block available')
73 raise UsageError('No previous pasted block available')
74 if not isinstance(b, str):
74 if not isinstance(b, str):
75 raise UsageError(
75 raise UsageError(
76 "Variable 'pasted_block' is not a string, can't execute")
76 "Variable 'pasted_block' is not a string, can't execute")
77
77
78 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
78 print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
79 self.shell.run_cell(b)
79 self.shell.run_cell(b)
80
80
81 @line_magic
81 @line_magic
82 def autoindent(self, parameter_s = ''):
82 def autoindent(self, parameter_s = ''):
83 """Toggle autoindent on/off (deprecated)"""
83 """Toggle autoindent on/off (deprecated)"""
84 self.shell.set_autoindent()
84 self.shell.set_autoindent()
85 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
85 print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
86
86
87 @skip_doctest
87 @skip_doctest
88 @line_magic
88 @line_magic
89 def cpaste(self, parameter_s=''):
89 def cpaste(self, parameter_s=''):
90 """Paste & execute a pre-formatted code block from clipboard.
90 """Paste & execute a pre-formatted code block from clipboard.
91
91
92 You must terminate the block with '--' (two minus-signs) or Ctrl-D
92 You must terminate the block with '--' (two minus-signs) or Ctrl-D
93 alone on the line. You can also provide your own sentinel with '%paste
93 alone on the line. You can also provide your own sentinel with '%paste
94 -s %%' ('%%' is the new sentinel for this operation).
94 -s %%' ('%%' is the new sentinel for this operation).
95
95
96 The block is dedented prior to execution to enable execution of method
96 The block is dedented prior to execution to enable execution of method
97 definitions. '>' and '+' characters at the beginning of a line are
97 definitions. '>' and '+' characters at the beginning of a line are
98 ignored, to allow pasting directly from e-mails, diff files and
98 ignored, to allow pasting directly from e-mails, diff files and
99 doctests (the '...' continuation prompt is also stripped). The
99 doctests (the '...' continuation prompt is also stripped). The
100 executed block is also assigned to variable named 'pasted_block' for
100 executed block is also assigned to variable named 'pasted_block' for
101 later editing with '%edit pasted_block'.
101 later editing with '%edit pasted_block'.
102
102
103 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
103 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
104 This assigns the pasted block to variable 'foo' as string, without
104 This assigns the pasted block to variable 'foo' as string, without
105 dedenting or executing it (preceding >>> and + is still stripped)
105 dedenting or executing it (preceding >>> and + is still stripped)
106
106
107 '%cpaste -r' re-executes the block previously entered by cpaste.
107 '%cpaste -r' re-executes the block previously entered by cpaste.
108 '%cpaste -q' suppresses any additional output messages.
108 '%cpaste -q' suppresses any additional output messages.
109
109
110 Do not be alarmed by garbled output on Windows (it's a readline bug).
110 Do not be alarmed by garbled output on Windows (it's a readline bug).
111 Just press enter and type -- (and press enter again) and the block
111 Just press enter and type -- (and press enter again) and the block
112 will be what was just pasted.
112 will be what was just pasted.
113
113
114 Shell escapes are not supported (yet).
114 Shell escapes are not supported (yet).
115
115
116 See also
116 See also
117 --------
117 --------
118 paste: automatically pull code from clipboard.
118 paste: automatically pull code from clipboard.
119
119
120 Examples
120 Examples
121 --------
121 --------
122 ::
122 ::
123
123
124 In [8]: %cpaste
124 In [8]: %cpaste
125 Pasting code; enter '--' alone on the line to stop.
125 Pasting code; enter '--' alone on the line to stop.
126 :>>> a = ["world!", "Hello"]
126 :>>> a = ["world!", "Hello"]
127 :>>> print(" ".join(sorted(a)))
127 :>>> print(" ".join(sorted(a)))
128 :--
128 :--
129 Hello world!
129 Hello world!
130
130
131 ::
131 ::
132 In [8]: %cpaste
132 In [8]: %cpaste
133 Pasting code; enter '--' alone on the line to stop.
133 Pasting code; enter '--' alone on the line to stop.
134 :>>> %alias_magic t timeit
134 :>>> %alias_magic t timeit
135 :>>> %t -n1 pass
135 :>>> %t -n1 pass
136 :--
136 :--
137 Created `%t` as an alias for `%timeit`.
137 Created `%t` as an alias for `%timeit`.
138 Created `%%t` as an alias for `%%timeit`.
138 Created `%%t` as an alias for `%%timeit`.
139 354 ns Β± 224 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
139 354 ns Β± 224 ns per loop (mean Β± std. dev. of 7 runs, 1 loop each)
140 """
140 """
141 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
141 opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
142 if 'r' in opts:
142 if 'r' in opts:
143 self.rerun_pasted()
143 self.rerun_pasted()
144 return
144 return
145
145
146 quiet = ('q' in opts)
146 quiet = ('q' in opts)
147
147
148 sentinel = opts.get('s', u'--')
148 sentinel = opts.get('s', u'--')
149 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
149 block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
150 self.store_or_execute(block, name)
150 self.store_or_execute(block, name)
151
151
152 @line_magic
152 @line_magic
153 def paste(self, parameter_s=''):
153 def paste(self, parameter_s=''):
154 """Paste & execute a pre-formatted code block from clipboard.
154 """Paste & execute a pre-formatted code block from clipboard.
155
155
156 The text is pulled directly from the clipboard without user
156 The text is pulled directly from the clipboard without user
157 intervention and printed back on the screen before execution (unless
157 intervention and printed back on the screen before execution (unless
158 the -q flag is given to force quiet mode).
158 the -q flag is given to force quiet mode).
159
159
160 The block is dedented prior to execution to enable execution of method
160 The block is dedented prior to execution to enable execution of method
161 definitions. '>' and '+' characters at the beginning of a line are
161 definitions. '>' and '+' characters at the beginning of a line are
162 ignored, to allow pasting directly from e-mails, diff files and
162 ignored, to allow pasting directly from e-mails, diff files and
163 doctests (the '...' continuation prompt is also stripped). The
163 doctests (the '...' continuation prompt is also stripped). The
164 executed block is also assigned to variable named 'pasted_block' for
164 executed block is also assigned to variable named 'pasted_block' for
165 later editing with '%edit pasted_block'.
165 later editing with '%edit pasted_block'.
166
166
167 You can also pass a variable name as an argument, e.g. '%paste foo'.
167 You can also pass a variable name as an argument, e.g. '%paste foo'.
168 This assigns the pasted block to variable 'foo' as string, without
168 This assigns the pasted block to variable 'foo' as string, without
169 executing it (preceding >>> and + is still stripped).
169 executing it (preceding >>> and + is still stripped).
170
170
171 Options:
171 Options:
172
172
173 -r: re-executes the block previously entered by cpaste.
173 -r: re-executes the block previously entered by cpaste.
174
174
175 -q: quiet mode: do not echo the pasted text back to the terminal.
175 -q: quiet mode: do not echo the pasted text back to the terminal.
176
176
177 IPython statements (magics, shell escapes) are not supported (yet).
177 IPython statements (magics, shell escapes) are not supported (yet).
178
178
179 See also
179 See also
180 --------
180 --------
181 cpaste: manually paste code into terminal until you mark its end.
181 cpaste: manually paste code into terminal until you mark its end.
182 """
182 """
183 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
183 opts, name = self.parse_options(parameter_s, 'rq', mode='string')
184 if 'r' in opts:
184 if 'r' in opts:
185 self.rerun_pasted()
185 self.rerun_pasted()
186 return
186 return
187 try:
187 try:
188 block = self.shell.hooks.clipboard_get()
188 block = self.shell.hooks.clipboard_get()
189 except TryNext as clipboard_exc:
189 except TryNext as clipboard_exc:
190 message = getattr(clipboard_exc, 'args')
190 message = getattr(clipboard_exc, 'args')
191 if message:
191 if message:
192 error(message[0])
192 error(message[0])
193 else:
193 else:
194 error('Could not get text from the clipboard.')
194 error('Could not get text from the clipboard.')
195 return
195 return
196 except ClipboardEmpty as e:
196 except ClipboardEmpty as e:
197 raise UsageError("The clipboard appears to be empty") from e
197 raise UsageError("The clipboard appears to be empty") from e
198
198
199 # By default, echo back to terminal unless quiet mode is requested
199 # By default, echo back to terminal unless quiet mode is requested
200 if 'q' not in opts:
200 if 'q' not in opts:
201 write = self.shell.write
201 sys.stdout.write(self.shell.pycolorize(block))
202 write(self.shell.pycolorize(block))
202 if not block.endswith("\n"):
203 if not block.endswith('\n'):
203 sys.stdout.write("\n")
204 write('\n')
204 sys.stdout.write("## -- End pasted text --\n")
205 write("## -- End pasted text --\n")
206
205
207 self.store_or_execute(block, name)
206 self.store_or_execute(block, name)
208
207
209 # Class-level: add a '%cls' magic only on Windows
208 # Class-level: add a '%cls' magic only on Windows
210 if sys.platform == 'win32':
209 if sys.platform == 'win32':
211 @line_magic
210 @line_magic
212 def cls(self, s):
211 def cls(self, s):
213 """Clear screen.
212 """Clear screen.
214 """
213 """
215 os.system("cls")
214 os.system("cls")
@@ -1,246 +1,241 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 IO related utilities.
3 IO related utilities.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9
9
10
10
11 import atexit
11 import atexit
12 import os
12 import os
13 import sys
13 import sys
14 import tempfile
14 import tempfile
15 import warnings
15 import warnings
16 from pathlib import Path
16 from pathlib import Path
17 from warnings import warn
17 from warnings import warn
18
18
19 from IPython.utils.decorators import undoc
19 from IPython.utils.decorators import undoc
20 from .capture import CapturedIO, capture_output
20 from .capture import CapturedIO, capture_output
21
21
22 @undoc
22 @undoc
23 class IOStream:
23 class IOStream:
24
24
25 def __init__(self, stream, fallback=None):
25 def __init__(self, stream, fallback=None):
26 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
26 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
27 DeprecationWarning, stacklevel=2)
27 DeprecationWarning, stacklevel=2)
28 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
28 if not hasattr(stream,'write') or not hasattr(stream,'flush'):
29 if fallback is not None:
29 if fallback is not None:
30 stream = fallback
30 stream = fallback
31 else:
31 else:
32 raise ValueError("fallback required, but not specified")
32 raise ValueError("fallback required, but not specified")
33 self.stream = stream
33 self.stream = stream
34 self._swrite = stream.write
34 self._swrite = stream.write
35
35
36 # clone all methods not overridden:
36 # clone all methods not overridden:
37 def clone(meth):
37 def clone(meth):
38 return not hasattr(self, meth) and not meth.startswith('_')
38 return not hasattr(self, meth) and not meth.startswith('_')
39 for meth in filter(clone, dir(stream)):
39 for meth in filter(clone, dir(stream)):
40 try:
40 try:
41 val = getattr(stream, meth)
41 val = getattr(stream, meth)
42 except AttributeError:
42 except AttributeError:
43 pass
43 pass
44 else:
44 else:
45 setattr(self, meth, val)
45 setattr(self, meth, val)
46
46
47 def __repr__(self):
47 def __repr__(self):
48 cls = self.__class__
48 cls = self.__class__
49 tpl = '{mod}.{cls}({args})'
49 tpl = '{mod}.{cls}({args})'
50 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
50 return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream)
51
51
52 def write(self,data):
52 def write(self,data):
53 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
53 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
54 DeprecationWarning, stacklevel=2)
54 DeprecationWarning, stacklevel=2)
55 try:
55 try:
56 self._swrite(data)
56 self._swrite(data)
57 except:
57 except:
58 try:
58 try:
59 # print handles some unicode issues which may trip a plain
59 # print handles some unicode issues which may trip a plain
60 # write() call. Emulate write() by using an empty end
60 # write() call. Emulate write() by using an empty end
61 # argument.
61 # argument.
62 print(data, end='', file=self.stream)
62 print(data, end='', file=self.stream)
63 except:
63 except:
64 # if we get here, something is seriously broken.
64 # if we get here, something is seriously broken.
65 print('ERROR - failed to write data to stream:', self.stream,
65 print('ERROR - failed to write data to stream:', self.stream,
66 file=sys.stderr)
66 file=sys.stderr)
67
67
68 def writelines(self, lines):
68 def writelines(self, lines):
69 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
69 warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead',
70 DeprecationWarning, stacklevel=2)
70 DeprecationWarning, stacklevel=2)
71 if isinstance(lines, str):
71 if isinstance(lines, str):
72 lines = [lines]
72 lines = [lines]
73 for line in lines:
73 for line in lines:
74 self.write(line)
74 self.write(line)
75
75
76 # This class used to have a writeln method, but regular files and streams
76 # This class used to have a writeln method, but regular files and streams
77 # in Python don't have this method. We need to keep this completely
77 # in Python don't have this method. We need to keep this completely
78 # compatible so we removed it.
78 # compatible so we removed it.
79
79
80 @property
80 @property
81 def closed(self):
81 def closed(self):
82 return self.stream.closed
82 return self.stream.closed
83
83
84 def close(self):
84 def close(self):
85 pass
85 pass
86
86
87 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
87 # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr
88 devnull = open(os.devnull, 'w')
88 devnull = open(os.devnull, 'w')
89 atexit.register(devnull.close)
89 atexit.register(devnull.close)
90
90
91 # io.std* are deprecated, but don't show our own deprecation warnings
91 # io.std* are deprecated, but don't show our own deprecation warnings
92 # during initialization of the deprecated API.
92 # during initialization of the deprecated API.
93 with warnings.catch_warnings():
93 with warnings.catch_warnings():
94 warnings.simplefilter('ignore', DeprecationWarning)
94 warnings.simplefilter('ignore', DeprecationWarning)
95 stdin = IOStream(sys.stdin, fallback=devnull)
95 stdin = IOStream(sys.stdin, fallback=devnull)
96 stdout = IOStream(sys.stdout, fallback=devnull)
96 stdout = IOStream(sys.stdout, fallback=devnull)
97 stderr = IOStream(sys.stderr, fallback=devnull)
97 stderr = IOStream(sys.stderr, fallback=devnull)
98
98
99 class Tee(object):
99 class Tee(object):
100 """A class to duplicate an output stream to stdout/err.
100 """A class to duplicate an output stream to stdout/err.
101
101
102 This works in a manner very similar to the Unix 'tee' command.
102 This works in a manner very similar to the Unix 'tee' command.
103
103
104 When the object is closed or deleted, it closes the original file given to
104 When the object is closed or deleted, it closes the original file given to
105 it for duplication.
105 it for duplication.
106 """
106 """
107 # Inspired by:
107 # Inspired by:
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
108 # http://mail.python.org/pipermail/python-list/2007-May/442737.html
109
109
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
110 def __init__(self, file_or_name, mode="w", channel='stdout'):
111 """Construct a new Tee object.
111 """Construct a new Tee object.
112
112
113 Parameters
113 Parameters
114 ----------
114 ----------
115 file_or_name : filename or open filehandle (writable)
115 file_or_name : filename or open filehandle (writable)
116 File that will be duplicated
116 File that will be duplicated
117 mode : optional, valid mode for open().
117 mode : optional, valid mode for open().
118 If a filename was give, open with this mode.
118 If a filename was give, open with this mode.
119 channel : str, one of ['stdout', 'stderr']
119 channel : str, one of ['stdout', 'stderr']
120 """
120 """
121 if channel not in ['stdout', 'stderr']:
121 if channel not in ['stdout', 'stderr']:
122 raise ValueError('Invalid channel spec %s' % channel)
122 raise ValueError('Invalid channel spec %s' % channel)
123
123
124 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
124 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
125 self.file = file_or_name
125 self.file = file_or_name
126 else:
126 else:
127 self.file = open(file_or_name, mode)
127 self.file = open(file_or_name, mode)
128 self.channel = channel
128 self.channel = channel
129 self.ostream = getattr(sys, channel)
129 self.ostream = getattr(sys, channel)
130 setattr(sys, channel, self)
130 setattr(sys, channel, self)
131 self._closed = False
131 self._closed = False
132
132
133 def close(self):
133 def close(self):
134 """Close the file and restore the channel."""
134 """Close the file and restore the channel."""
135 self.flush()
135 self.flush()
136 setattr(sys, self.channel, self.ostream)
136 setattr(sys, self.channel, self.ostream)
137 self.file.close()
137 self.file.close()
138 self._closed = True
138 self._closed = True
139
139
140 def write(self, data):
140 def write(self, data):
141 """Write data to both channels."""
141 """Write data to both channels."""
142 self.file.write(data)
142 self.file.write(data)
143 self.ostream.write(data)
143 self.ostream.write(data)
144 self.ostream.flush()
144 self.ostream.flush()
145
145
146 def flush(self):
146 def flush(self):
147 """Flush both channels."""
147 """Flush both channels."""
148 self.file.flush()
148 self.file.flush()
149 self.ostream.flush()
149 self.ostream.flush()
150
150
151 def __del__(self):
151 def __del__(self):
152 if not self._closed:
152 if not self._closed:
153 self.close()
153 self.close()
154
154
155
155
156 def ask_yes_no(prompt, default=None, interrupt=None):
156 def ask_yes_no(prompt, default=None, interrupt=None):
157 """Asks a question and returns a boolean (y/n) answer.
157 """Asks a question and returns a boolean (y/n) answer.
158
158
159 If default is given (one of 'y','n'), it is used if the user input is
159 If default is given (one of 'y','n'), it is used if the user input is
160 empty. If interrupt is given (one of 'y','n'), it is used if the user
160 empty. If interrupt is given (one of 'y','n'), it is used if the user
161 presses Ctrl-C. Otherwise the question is repeated until an answer is
161 presses Ctrl-C. Otherwise the question is repeated until an answer is
162 given.
162 given.
163
163
164 An EOF is treated as the default answer. If there is no default, an
164 An EOF is treated as the default answer. If there is no default, an
165 exception is raised to prevent infinite loops.
165 exception is raised to prevent infinite loops.
166
166
167 Valid answers are: y/yes/n/no (match is not case sensitive)."""
167 Valid answers are: y/yes/n/no (match is not case sensitive)."""
168
168
169 answers = {'y':True,'n':False,'yes':True,'no':False}
169 answers = {'y':True,'n':False,'yes':True,'no':False}
170 ans = None
170 ans = None
171 while ans not in answers.keys():
171 while ans not in answers.keys():
172 try:
172 try:
173 ans = input(prompt+' ').lower()
173 ans = input(prompt+' ').lower()
174 if not ans: # response was an empty string
174 if not ans: # response was an empty string
175 ans = default
175 ans = default
176 except KeyboardInterrupt:
176 except KeyboardInterrupt:
177 if interrupt:
177 if interrupt:
178 ans = interrupt
178 ans = interrupt
179 print("\r")
179 print("\r")
180 except EOFError:
180 except EOFError:
181 if default in answers.keys():
181 if default in answers.keys():
182 ans = default
182 ans = default
183 print()
183 print()
184 else:
184 else:
185 raise
185 raise
186
186
187 return answers[ans]
187 return answers[ans]
188
188
189
189
190 def temp_pyfile(src, ext='.py'):
190 def temp_pyfile(src, ext='.py'):
191 """Make a temporary python file, return filename and filehandle.
191 """Make a temporary python file, return filename and filehandle.
192
192
193 Parameters
193 Parameters
194 ----------
194 ----------
195 src : string or list of strings (no need for ending newlines if list)
195 src : string or list of strings (no need for ending newlines if list)
196 Source code to be written to the file.
196 Source code to be written to the file.
197 ext : optional, string
197 ext : optional, string
198 Extension for the generated file.
198 Extension for the generated file.
199
199
200 Returns
200 Returns
201 -------
201 -------
202 (filename, open filehandle)
202 (filename, open filehandle)
203 It is the caller's responsibility to close the open file and unlink it.
203 It is the caller's responsibility to close the open file and unlink it.
204 """
204 """
205 fname = tempfile.mkstemp(ext)[1]
205 fname = tempfile.mkstemp(ext)[1]
206 with open(Path(fname), "w") as f:
206 with open(Path(fname), "w") as f:
207 f.write(src)
207 f.write(src)
208 f.flush()
208 f.flush()
209 return fname
209 return fname
210
210
211 @undoc
211 @undoc
212 def atomic_writing(*args, **kwargs):
212 def atomic_writing(*args, **kwargs):
213 """DEPRECATED: moved to notebook.services.contents.fileio"""
213 """DEPRECATED: moved to notebook.services.contents.fileio"""
214 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio since IPython 4.0", DeprecationWarning, stacklevel=2)
214 warn("IPython.utils.io.atomic_writing has moved to notebook.services.contents.fileio since IPython 4.0", DeprecationWarning, stacklevel=2)
215 from notebook.services.contents.fileio import atomic_writing
215 from notebook.services.contents.fileio import atomic_writing
216 return atomic_writing(*args, **kwargs)
216 return atomic_writing(*args, **kwargs)
217
217
218 @undoc
218 @undoc
219 def raw_print(*args, **kw):
219 def raw_print(*args, **kw):
220 """DEPRECATED: Raw print to sys.__stdout__, otherwise identical interface to print()."""
220 """DEPRECATED: Raw print to sys.__stdout__, otherwise identical interface to print()."""
221 warn("IPython.utils.io.raw_print has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
221 warn("IPython.utils.io.raw_print has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
222
222
223 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
223 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
224 file=sys.__stdout__)
224 file=sys.__stdout__)
225 sys.__stdout__.flush()
225 sys.__stdout__.flush()
226
226
227 @undoc
227 @undoc
228 def raw_print_err(*args, **kw):
228 def raw_print_err(*args, **kw):
229 """DEPRECATED: Raw print to sys.__stderr__, otherwise identical interface to print()."""
229 """DEPRECATED: Raw print to sys.__stderr__, otherwise identical interface to print()."""
230 warn("IPython.utils.io.raw_print_err has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
230 warn("IPython.utils.io.raw_print_err has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
231
231
232 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
232 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
233 file=sys.__stderr__)
233 file=sys.__stderr__)
234 sys.__stderr__.flush()
234 sys.__stderr__.flush()
235
235
236 # used by IPykernel <- 4.9. Removed during IPython 7-dev period and re-added
237 # Keep for a version or two then should remove
238 rprint = raw_print
239 rprinte = raw_print_err
240
241 @undoc
236 @undoc
242 def unicode_std_stream(stream='stdout'):
237 def unicode_std_stream(stream='stdout'):
243 """DEPRECATED, moved to nbconvert.utils.io"""
238 """DEPRECATED, moved to nbconvert.utils.io"""
244 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io since IPython 4.0", DeprecationWarning, stacklevel=2)
239 warn("IPython.utils.io.unicode_std_stream has moved to nbconvert.utils.io since IPython 4.0", DeprecationWarning, stacklevel=2)
245 from nbconvert.utils.io import unicode_std_stream
240 from nbconvert.utils.io import unicode_std_stream
246 return unicode_std_stream(stream)
241 return unicode_std_stream(stream)
General Comments 0
You need to be logged in to leave comments. Login now