##// END OF EJS Templates
Example of adding input transformers....
Thomas Kluyver -
Show More
@@ -1,129 +1,132 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 it gets added to both.
44 it gets added to both, e.g.::
45
46 ip.input_splitter.logical_line_transforms.append(my_transformer())
47 ip.input_transformer_manager.logical_line_transforms.append(my_transformer())
45 48
46 49 Stateless transformations
47 50 -------------------------
48 51
49 52 The simplest kind of transformations work one line at a time. Write a function
50 53 which takes a line and returns a line, and decorate it with
51 54 :meth:`StatelessInputTransformer.wrap`::
52 55
53 56 @StatelessInputTransformer.wrap
54 57 def my_special_commands(line):
55 58 if line.startswith("Β¬"):
56 59 return "specialcommand(" + repr(line) + ")"
57 60 return line
58 61
59 62 The decorator returns a factory function which will produce instances of
60 63 :class:`~IPython.core.inputtransformer.StatelessInputTransformer` using your
61 64 function.
62 65
63 66 Coroutine transformers
64 67 ----------------------
65 68
66 69 More advanced transformers can be written as coroutines. The coroutine will be
67 70 sent each line in turn, followed by ``None`` to reset it. It can yield lines, or
68 71 ``None`` if it is accumulating text to yield at a later point. When reset, it
69 72 should give up any code it has accumulated.
70 73
71 74 This code in IPython strips a constant amount of leading indentation from each
72 75 line in a cell::
73 76
74 77 @CoroutineInputTransformer.wrap
75 78 def leading_indent():
76 79 """Remove leading indentation.
77 80
78 81 If the first line starts with a spaces or tabs, the same whitespace will be
79 82 removed from each following line until it is reset.
80 83 """
81 84 space_re = re.compile(r'^[ \t]+')
82 85 line = ''
83 86 while True:
84 87 line = (yield line)
85 88
86 89 if line is None:
87 90 continue
88 91
89 92 m = space_re.match(line)
90 93 if m:
91 94 space = m.group(0)
92 95 while line is not None:
93 96 if line.startswith(space):
94 97 line = line[len(space):]
95 98 line = (yield line)
96 99 else:
97 100 # No leading spaces - wait for reset
98 101 while line is not None:
99 102 line = (yield line)
100 103
101 104 leading_indent.look_in_string = True
102 105
103 106 Token-based transformers
104 107 ------------------------
105 108
106 109 There is an experimental framework that takes care of tokenizing and
107 110 untokenizing lines of code. Define a function that accepts a list of tokens, and
108 111 returns an iterable of output tokens, and decorate it with
109 112 :meth:`TokenInputTransformer.wrap`. These should only be used in
110 113 ``python_line_transforms``.
111 114
112 115 AST transformations
113 116 ===================
114 117
115 118 After the code has been parsed as Python syntax, you can use Python's powerful
116 119 *Abstract Syntax Tree* tools to modify it. Subclass :class:`ast.NodeTransformer`,
117 120 and add an instance to ``shell.ast_transformers``.
118 121
119 122 This example wraps integer literals in an ``Integer`` class, which is useful for
120 123 mathematical frameworks that want to handle e.g. ``1/3`` as a precise fraction::
121 124
122 125
123 126 class IntegerWrapper(ast.NodeTransformer):
124 127 """Wraps all integers in a call to Integer()"""
125 128 def visit_Num(self, node):
126 129 if isinstance(node.n, int):
127 130 return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
128 131 args=[node], keywords=[])
129 132 return node
General Comments 0
You need to be logged in to leave comments. Login now