File: test_prefilter.py

package info (click to toggle)
ipython 9.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 8,624 kB
  • sloc: python: 45,268; sh: 317; makefile: 168
file content (154 lines) | stat: -rw-r--r-- 4,852 bytes parent folder | download
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
"""Tests for input manipulation machinery."""

# -----------------------------------------------------------------------------
# Imports
# -----------------------------------------------------------------------------
import pytest

from IPython.core.prefilter import AutocallChecker

# -----------------------------------------------------------------------------
# Tests
# -----------------------------------------------------------------------------


def test_prefilter():
    """Test user input conversions"""

    # pairs of (raw, expected correct) input
    pairs = [
        ("2+2", "2+2"),
    ]

    for raw, correct in pairs:
        assert ip.prefilter(raw) == correct


def test_prefilter_shadowed():
    def dummy_magic(line):
        pass

    prev_automagic_state = ip.automagic
    ip.automagic = True
    ip.autocall = 0

    try:
        # These should not be transformed - they are shadowed by other names
        for name in ["if", "zip", "get_ipython"]:  # keyword, builtin, global
            ip.register_magic_function(dummy_magic, magic_name=name)
            res = ip.prefilter(name + " foo")
            assert res == name + " foo"
            del ip.magics_manager.magics["line"][name]

        # These should be transformed
        for name in ["fi", "piz", "nohtypi_teg"]:
            ip.register_magic_function(dummy_magic, magic_name=name)
            res = ip.prefilter(name + " foo")
            assert res != name + " foo"
            del ip.magics_manager.magics["line"][name]

    finally:
        ip.automagic = prev_automagic_state


def test_autocall_binops():
    """See https://github.com/ipython/ipython/issues/81"""
    ip.run_line_magic("autocall", "2")
    f = lambda x: x
    ip.user_ns["f"] = f
    try:
        assert ip.prefilter("f 1") == "f(1)"
        for t in ["f +1", "f -1"]:
            assert ip.prefilter(t) == t

        # Run tests again with a more permissive exclude_regexp, which will
        # allow transformation of binary operations ('f -1' -> 'f(-1)').
        pm = ip.prefilter_manager
        ac = AutocallChecker(shell=pm.shell, prefilter_manager=pm, config=pm.config)
        try:
            ac.priority = 1
            ac.exclude_regexp = r"^[,&^\|\*/]|^is |^not |^in |^and |^or "
            pm.sort_checkers()

            assert ip.prefilter("f -1") == "f(-1)"
            assert ip.prefilter("f +1") == "f(+1)"
        finally:
            pm.unregister_checker(ac)
    finally:
        ip.run_line_magic("autocall", "0")
        del ip.user_ns["f"]


def test_issue_114():
    """Check that multiline string literals don't expand as magic
    see http://github.com/ipython/ipython/issues/114"""

    template = '"""\n%s\n"""'
    # Store the current value of multi_line_specials and turn it off before
    # running test, since it could be true (case in which the test doesn't make
    # sense, as multiline string literals *will* expand as magic in that case).
    msp = ip.prefilter_manager.multi_line_specials
    ip.prefilter_manager.multi_line_specials = False
    try:
        for mgk in ip.magics_manager.lsmagic()["line"]:
            raw = template % mgk
            assert ip.prefilter(raw) == raw
    finally:
        ip.prefilter_manager.multi_line_specials = msp


def test_prefilter_attribute_errors():
    """Capture exceptions thrown by user objects on attribute access.

    See http://github.com/ipython/ipython/issues/988."""

    class X(object):
        def __getattr__(self, k):
            raise ValueError("broken object")

        def __call__(self, x):
            return x

    # Create a callable broken object
    ip.user_ns["x"] = X()
    ip.run_line_magic("autocall", "2")
    try:
        # Even if x throws an attribute error when looking at its rewrite
        # attribute, we should not crash.  So the test here is simply making
        # the prefilter call and not having an exception.
        ip.prefilter("x 1")
    finally:
        del ip.user_ns["x"]
        ip.run_line_magic("autocall", "0")


def test_autocall_type_ann():
    ip.run_cell("import collections.abc")
    ip.run_line_magic("autocall", "1")
    try:
        assert (
            ip.prefilter("collections.abc.Callable[[int], None]")
            == "collections.abc.Callable[[int], None]"
        )
    finally:
        ip.run_line_magic("autocall", "0")


def test_autocall_should_support_unicode():
    ip.run_line_magic("autocall", "2")
    ip.user_ns["π"] = lambda x: x
    try:
        assert ip.prefilter("π 3") == "π(3)"
    finally:
        ip.run_line_magic("autocall", "0")
        del ip.user_ns["π"]


def test_autocall_regression_gh_14513():
    ip.run_line_magic("autocall", "2")
    ip.user_ns["foo"] = dict()
    try:
        assert ip.prefilter("foo") == "foo"
    finally:
        ip.run_line_magic("autocall", "0")
        del ip.user_ns["foo"]