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