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