File size: 8,276 Bytes
4a51346
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# -*- coding: utf-8 -*-
"""Tests for the TerminalInteractiveShell and related pieces."""
# Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.

import sys
import unittest
import os

from prompt_toolkit.auto_suggest import AutoSuggestFromHistory


from IPython.testing import tools as tt

from IPython.terminal.ptutils import _elide, _adjust_completion_text_based_on_context
from IPython.terminal.shortcuts.auto_suggest import NavigableAutoSuggestFromHistory


class TestAutoSuggest(unittest.TestCase):
    def test_changing_provider(self):
        ip = get_ipython()
        ip.autosuggestions_provider = None
        self.assertEqual(ip.auto_suggest, None)
        ip.autosuggestions_provider = "AutoSuggestFromHistory"
        self.assertIsInstance(ip.auto_suggest, AutoSuggestFromHistory)
        ip.autosuggestions_provider = "NavigableAutoSuggestFromHistory"
        self.assertIsInstance(ip.auto_suggest, NavigableAutoSuggestFromHistory)


class TestElide(unittest.TestCase):
    def test_elide(self):
        _elide("concatenate((a1, a2, ...), axis", "")  # do not raise
        _elide("concatenate((a1, a2, ..), . axis", "")  # do not raise
        self.assertEqual(
            _elide("aaaa.bbbb.ccccc.dddddd.eeeee.fffff.gggggg.hhhhhh", ""),
            "aaaa.b…g.hhhhhh",
        )

        test_string = os.sep.join(["", 10 * "a", 10 * "b", 10 * "c", ""])
        expect_string = (
            os.sep + "a" + "\N{HORIZONTAL ELLIPSIS}" + "b" + os.sep + 10 * "c"
        )
        self.assertEqual(_elide(test_string, ""), expect_string)

    def test_elide_typed_normal(self):
        self.assertEqual(
            _elide(
                "the quick brown fox jumped over the lazy dog",
                "the quick brown fox",
                min_elide=10,
            ),
            "the…fox jumped over the lazy dog",
        )

    def test_elide_typed_short_match(self):
        """
        if the match is too short we don't elide.
        avoid the "the...the"
        """
        self.assertEqual(
            _elide("the quick brown fox jumped over the lazy dog", "the", min_elide=10),
            "the quick brown fox jumped over the lazy dog",
        )

    def test_elide_typed_no_match(self):
        """
        if the match is too short we don't elide.
        avoid the "the...the"
        """
        # here we typed red instead of brown
        self.assertEqual(
            _elide(
                "the quick brown fox jumped over the lazy dog",
                "the quick red fox",
                min_elide=10,
            ),
            "the quick brown fox jumped over the lazy dog",
        )


class TestContextAwareCompletion(unittest.TestCase):
    def test_adjust_completion_text_based_on_context(self):
        # Adjusted case
        self.assertEqual(
            _adjust_completion_text_based_on_context("arg1=", "func1(a=)", 7), "arg1"
        )

        # Untouched cases
        self.assertEqual(
            _adjust_completion_text_based_on_context("arg1=", "func1(a)", 7), "arg1="
        )
        self.assertEqual(
            _adjust_completion_text_based_on_context("arg1=", "func1(a", 7), "arg1="
        )
        self.assertEqual(
            _adjust_completion_text_based_on_context("%magic", "func1(a=)", 7), "%magic"
        )
        self.assertEqual(
            _adjust_completion_text_based_on_context("func2", "func1(a=)", 7), "func2"
        )


# Decorator for interaction loop tests -----------------------------------------


class mock_input_helper(object):
    """Machinery for tests of the main interact loop.

    Used by the mock_input decorator.
    """
    def __init__(self, testgen):
        self.testgen = testgen
        self.exception = None
        self.ip = get_ipython()

    def __enter__(self):
        self.orig_prompt_for_code = self.ip.prompt_for_code
        self.ip.prompt_for_code = self.fake_input
        return self

    def __exit__(self, etype, value, tb):
        self.ip.prompt_for_code = self.orig_prompt_for_code

    def fake_input(self):
        try:
            return next(self.testgen)
        except StopIteration:
            self.ip.keep_running = False
            return u''
        except:
            self.exception = sys.exc_info()
            self.ip.keep_running = False
            return u''

def mock_input(testfunc):
    """Decorator for tests of the main interact loop.

    Write the test as a generator, yield-ing the input strings, which IPython
    will see as if they were typed in at the prompt.
    """
    def test_method(self):
        testgen = testfunc(self)
        with mock_input_helper(testgen) as mih:
            mih.ip.interact()

        if mih.exception is not None:
            # Re-raise captured exception
            etype, value, tb = mih.exception
            import traceback
            traceback.print_tb(tb, file=sys.stdout)
            del tb  # Avoid reference loop
            raise value

    return test_method

# Test classes -----------------------------------------------------------------

class InteractiveShellTestCase(unittest.TestCase):
    def rl_hist_entries(self, rl, n):
        """Get last n readline history entries as a list"""
        return [rl.get_history_item(rl.get_current_history_length() - x)
                for x in range(n - 1, -1, -1)]
    
    @mock_input
    def test_inputtransformer_syntaxerror(self):
        ip = get_ipython()
        ip.input_transformers_post.append(syntax_error_transformer)

        try:
            #raise Exception
            with tt.AssertPrints('4', suppress=False):
                yield u'print(2*2)'

            with tt.AssertPrints('SyntaxError: input contains', suppress=False):
                yield u'print(2345) # syntaxerror'

            with tt.AssertPrints('16', suppress=False):
                yield u'print(4*4)'

        finally:
            ip.input_transformers_post.remove(syntax_error_transformer)

    def test_repl_not_plain_text(self):
        ip = get_ipython()
        formatter = ip.display_formatter
        assert formatter.active_types == ['text/plain']

        # terminal may have arbitrary mimetype handler to open external viewer
        # or inline images.
        assert formatter.ipython_display_formatter.enabled

        class Test(object):
            def __repr__(self):
                return "<Test %i>" % id(self)

            def _repr_html_(self):
                return '<html>'

        # verify that HTML repr isn't computed
        obj = Test()
        data, _ = formatter.format(obj)
        self.assertEqual(data, {'text/plain': repr(obj)})

        class Test2(Test):
            def _ipython_display_(self):
                from IPython.display import display, HTML

                display(HTML("<custom>"))

        # verify that mimehandlers are called
        called = False

        def handler(data, metadata):
            print("Handler called")
            nonlocal called
            called = True

        ip.display_formatter.active_types.append("text/html")
        ip.display_formatter.formatters["text/html"].enabled = True
        ip.mime_renderers["text/html"] = handler
        try:
            obj = Test()
            display(obj)
        finally:
            ip.display_formatter.formatters["text/html"].enabled = False
            del ip.mime_renderers["text/html"]

        assert called == True


def syntax_error_transformer(lines):
    """Transformer that throws SyntaxError if 'syntaxerror' is in the code."""
    for line in lines:
        pos = line.find('syntaxerror')
        if pos >= 0:
            e = SyntaxError('input contains "syntaxerror"')
            e.text = line
            e.offset = pos + 1
            raise e
    return lines


class TerminalMagicsTestCase(unittest.TestCase):
    def test_paste_magics_blankline(self):
        """Test that code with a blank line doesn't get split (gh-3246)."""
        ip = get_ipython()
        s = ('def pasted_func(a):\n'
             '    b = a+1\n'
             '\n'
             '    return b')
        
        tm = ip.magics_manager.registry['TerminalMagics']
        tm.store_or_execute(s, name=None)
        
        self.assertEqual(ip.user_ns['pasted_func'](54), 55)