##// END OF EJS Templates
Document changes to input transformers
Thomas Kluyver -
Show More
@@ -0,0 +1,6 b''
1 * :class:`IPython.core.inputsplitter.IPythonInputSplitter` no longer has a method
2 ``source_raw_reset()``, but gains :meth:`~IPython.core.inputsplitter.IPythonInputSplitter.raw_reset`
3 instead. Use of ``source_raw_reset`` can be replaced with::
4
5 raw = isp.source_raw
6 transformed = isp.source_reset()
@@ -0,0 +1,4 b''
1 * Input transformers (see :doc:`/config/inputtransforms`) may now raise
2 :exc:`SyntaxError` if they determine that input is invalid. The input
3 transformation machinery in IPython will handle displaying the exception to
4 the user and resetting state.
@@ -1,129 +1,137 b''
1 1
2 2 ===========================
3 3 Custom input transformation
4 4 ===========================
5 5
6 6 IPython extends Python syntax to allow things like magic commands, and help with
7 7 the ``?`` syntax. There are several ways to customise how the user's input is
8 8 processed into Python code to be executed.
9 9
10 10 These hooks are mainly for other projects using IPython as the core of their
11 11 interactive interface. Using them carelessly can easily break IPython!
12 12
13 13 String based transformations
14 14 ============================
15 15
16 16 .. currentmodule:: IPython.core.inputtransforms
17 17
18 18 When the user enters a line of code, it is first processed as a string. By the
19 19 end of this stage, it must be valid Python syntax.
20 20
21 21 These transformers all subclass :class:`IPython.core.inputtransformer.InputTransformer`,
22 22 and are used by :class:`IPython.core.inputsplitter.IPythonInputSplitter`.
23 23
24 24 These transformers act in three groups, stored separately as lists of instances
25 25 in attributes of :class:`~IPython.core.inputsplitter.IPythonInputSplitter`:
26 26
27 27 * ``physical_line_transforms`` act on the lines as the user enters them. For
28 28 example, these strip Python prompts from examples pasted in.
29 29 * ``logical_line_transforms`` act on lines as connected by explicit line
30 30 continuations, i.e. ``\`` at the end of physical lines. They are skipped
31 31 inside multiline Python statements. This is the point where IPython recognises
32 32 ``%magic`` commands, for instance.
33 33 * ``python_line_transforms`` act on blocks containing complete Python statements.
34 34 Multi-line strings, lists and function calls are reassembled before being
35 35 passed to these, but note that function and class *definitions* are still a
36 36 series of separate statements. IPython does not use any of these by default.
37 37
38 38 An InteractiveShell instance actually has two
39 39 :class:`~IPython.core.inputsplitter.IPythonInputSplitter` instances, as the
40 40 attributes :attr:`~IPython.core.interactiveshell.InteractiveShell.input_splitter`,
41 41 to tell when a block of input is complete, and
42 42 :attr:`~IPython.core.interactiveshell.InteractiveShell.input_transformer_manager`,
43 43 to transform complete cells. If you add a transformer, you should make sure that
44 44 it gets added to both.
45 45
46 These transformers may raise :exc:`SyntaxError` if the input code is invalid, but
47 in most cases it is clearer to pass unrecognised code through unmodified and let
48 Python's own parser decide whether it is valid.
49
50 .. versionchanged:: 2.0
51
52 Added the option to raise :exc:`SyntaxError`.
53
46 54 Stateless transformations
47 55 -------------------------
48 56
49 57 The simplest kind of transformations work one line at a time. Write a function
50 58 which takes a line and returns a line, and decorate it with
51 59 :meth:`StatelessInputTransformer.wrap`::
52 60
53 61 @StatelessInputTransformer.wrap
54 62 def my_special_commands(line):
55 63 if line.startswith("Β¬"):
56 64 return "specialcommand(" + repr(line) + ")"
57 65 return line
58 66
59 67 The decorator returns a factory function which will produce instances of
60 68 :class:`~IPython.core.inputtransformer.StatelessInputTransformer` using your
61 69 function.
62 70
63 71 Coroutine transformers
64 72 ----------------------
65 73
66 74 More advanced transformers can be written as coroutines. The coroutine will be
67 75 sent each line in turn, followed by ``None`` to reset it. It can yield lines, or
68 76 ``None`` if it is accumulating text to yield at a later point. When reset, it
69 77 should give up any code it has accumulated.
70 78
71 79 This code in IPython strips a constant amount of leading indentation from each
72 80 line in a cell::
73 81
74 82 @CoroutineInputTransformer.wrap
75 83 def leading_indent():
76 84 """Remove leading indentation.
77 85
78 86 If the first line starts with a spaces or tabs, the same whitespace will be
79 87 removed from each following line until it is reset.
80 88 """
81 89 space_re = re.compile(r'^[ \t]+')
82 90 line = ''
83 91 while True:
84 92 line = (yield line)
85 93
86 94 if line is None:
87 95 continue
88 96
89 97 m = space_re.match(line)
90 98 if m:
91 99 space = m.group(0)
92 100 while line is not None:
93 101 if line.startswith(space):
94 102 line = line[len(space):]
95 103 line = (yield line)
96 104 else:
97 105 # No leading spaces - wait for reset
98 106 while line is not None:
99 107 line = (yield line)
100 108
101 109 leading_indent.look_in_string = True
102 110
103 111 Token-based transformers
104 112 ------------------------
105 113
106 114 There is an experimental framework that takes care of tokenizing and
107 115 untokenizing lines of code. Define a function that accepts a list of tokens, and
108 116 returns an iterable of output tokens, and decorate it with
109 117 :meth:`TokenInputTransformer.wrap`. These should only be used in
110 118 ``python_line_transforms``.
111 119
112 120 AST transformations
113 121 ===================
114 122
115 123 After the code has been parsed as Python syntax, you can use Python's powerful
116 124 *Abstract Syntax Tree* tools to modify it. Subclass :class:`ast.NodeTransformer`,
117 125 and add an instance to ``shell.ast_transformers``.
118 126
119 127 This example wraps integer literals in an ``Integer`` class, which is useful for
120 128 mathematical frameworks that want to handle e.g. ``1/3`` as a precise fraction::
121 129
122 130
123 131 class IntegerWrapper(ast.NodeTransformer):
124 132 """Wraps all integers in a call to Integer()"""
125 133 def visit_Num(self, node):
126 134 if isinstance(node.n, int):
127 135 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
128 136 args=[node], keywords=[])
129 137 return node
General Comments 0
You need to be logged in to leave comments. Login now