File: details.rst

package info (click to toggle)
ipython 8.35.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,696 kB
  • sloc: python: 42,461; sh: 376; makefile: 243
file content (416 lines) | stat: -rw-r--r-- 15,741 bytes parent folder | download | duplicates (2)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
==============================
Specific configuration details
==============================

.. _llm_suggestions:

LLM Suggestions
===============

Starting with 9.0, IPython will be able to use LLM providers to suggest code in
the terminal. This requires a recent version of prompt_toolkit in order to allow
multiline suggestions. There are currently a number of limitations, and feedback
on the API is welcome.

Unlike many of IPython features, this is not enabled by default and requires
multiple configuration options to be set to properly work:

 - Set a keybinding to trigger LLM suggestions. Due to terminal limitations
   across platforms and emulators, it is difficult to provide a default
   keybinding. Note that not all keybindings are availables, in particular all
   the `Ctrl-Enter`, `Alt-backslash` and `Ctrl-Shift-Enter` are not available
   without integration with your terminal emulator.

 - Chose a LLM `provider`, usually from Jupyter-AI. This will be the interface
   between IPython itself, and the LLM – that may be local or in on a server.

 - Configure said provider with models, API keys, etc – this will depend on the
   provider, and you will have to refer to Jupyter-AI documentation, and/or your
   LLM documenatation.


While setting up IPython to use a real LLM, you can refer to
``examples/auto_suggest_llm.py`` that both provide an example of how to set up
IPython to use a Fake LLM provider, this can help ensure that the full setup is
working before switching to a real LLM provider.


Setup a keybinding
------------------

You may want to refer on how to setup a keybinding in IPython, but in short you
want to bind the ``IPython:auto_suggest.llm_autosuggestion`` command to a
keybinding, and have it active only when the default buffer isi focused, and
when using the NavigableSuggestions suggestter (this is the default suggestter,
the one that is history and LLM aware). Thus the ``navigable_suggestions &
default_buffer_focused`` filter should be used.

Usually ``Ctrl-Q`` on macos is an available shortcut, note that is does use
``Ctrl``, and not ``Command``.

The following example will bind ``Ctrl-Q`` to the ``llm_autosuggestion``
command, with the suggested filter::

    c.TerminalInteractiveShell.shortcuts = [
        {
            "new_keys": ["c-q"],
            "command": "IPython:auto_suggest.llm_autosuggestion",
            "new_filter": "navigable_suggestions & default_buffer_focused",
            "create": True,
        },
    ]


Choose a LLM provider
---------------------

Set the  ``TerminalInteractiveShell.llm_provider_class`` trait to the fully
qualified name of the Provider you like, when testing from inside the IPython
source tree, you can use
``"examples.auto_suggest_llm.ExampleCompletionProvider"`` This will always
stream an extract of the Little Prince by Antoine de Saint-Exupéry, and will not
require any API key or real LLM.


In your configuration file adapt the following line to your needs:

.. code-block:: python

    c.TerminalInteractiveShell.llm_provider_class = "examples.auto_suggest_llm.ExampleCompletionProvider"

Configure the provider
----------------------

It the provider needs to be passed parameters at initialization, you can do so
by setting the ``llm_provider_kwargs`` traitlet.

.. code-block:: python

    c.TerminalInteractiveShell.llm_provider_kwargs = {"model": "skynet"}

This will depdend on the provider you chose, and you will have to refer to
the provider documentation.

Extra configuration may be needed by setting environment variables, this will
again depend on the provider you chose, and you will have to refer to the
provider documentation.



.. _custom_prompts:

Custom Prompts
==============

.. versionchanged:: 5.0

From IPython 5, prompts are produced as a list of Pygments tokens, which are
tuples of (token_type, text). You can customise prompts by writing a method
which generates a list of tokens.

There are four kinds of prompt:

* The **in** prompt is shown before the first line of input
  (default like ``In [1]:``).
* The **continuation** prompt is shown before further lines of input
  (default like ``...:``).
* The **rewrite** prompt is shown to highlight how special syntax has been
  interpreted (default like ``----->``).
* The **out** prompt is shown before the result from evaluating the input
  (default like ``Out[1]:``).

Custom prompts are supplied together as a class. If you want to customise only
some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`,
which defines the defaults. The required interface is like this:

.. class:: MyPrompts(shell)

   Prompt style definition. *shell* is a reference to the
   :class:`~.TerminalInteractiveShell` instance.

   .. method:: in_prompt_tokens()
               continuation_prompt_tokens(self, width=None)
               rewrite_prompt_tokens()
               out_prompt_tokens()

      Return the respective prompts as lists of ``(token_type, text)`` tuples.

      For continuation prompts, *width* is an integer representing the width of
      the prompt area in terminal columns.


Here is an example Prompt class that will show the current working directory
in the input prompt:

.. code-block:: python

    from IPython.terminal.prompts import Prompts, Token
    import os

    class MyPrompt(Prompts):
         def in_prompt_tokens(self):
             return [(Token, os.getcwd()),
                     (Token.Prompt, ' >>>')]

To set the new prompt, assign it to the ``prompts`` attribute of the IPython
shell:

.. code-block:: python

    In [2]: ip = get_ipython()
       ...: ip.prompts = MyPrompt(ip)

    /home/bob >>> # it works

See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write
extensions to customise prompts.

Inside IPython or in a startup script, you can use a custom prompts class
by setting ``get_ipython().prompts`` to an *instance* of the class.
In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to
either the class object, or a string of its full importable name.

To include invisible terminal control sequences in a prompt, use
``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored
when calculating the width.

Colours in the prompt are determined by the token types and the highlighting
style; see below for more details. The tokens used in the default prompts are
``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``.

.. _termcolour:

Terminal Colors
===============

.. versionchanged:: 5.0

There are two main configuration options controlling colours.

``InteractiveShell.colors`` sets the colour of tracebacks and object info (the
output from e.g. ``zip?``). It may also affect other things if the option below
is set to ``'legacy'``. It has four case-insensitive values:
``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which
should be legible on either dark or light terminal backgrounds. *linux* is
optimised for dark backgrounds and *lightbg* for light ones.

``TerminalInteractiveShell.highlighting_style`` determines prompt colours and
syntax highlighting. It takes the name (as a string) or class (as a subclass of
``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'``
to pick a style in accordance with ``InteractiveShell.colors``.

You can see the Pygments styles available on your system by running::

    from pygments.styles import get_all_styles
    list(get_all_styles())

Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override
specific styles in the highlighting. It should be a dictionary mapping Pygments
token types to strings defining the style. See `Pygments' documentation
<http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used
to define styles.

Colors in the pager
-------------------

On some systems, the default pager has problems with ANSI colour codes.
To configure your default pager to allow these:

1. Set the environment PAGER variable to ``less``.
2. Set the environment LESS variable to ``-r`` (plus any other options
   you always want to pass to less by default). This tells less to
   properly interpret control sequences, which is how color
   information is given to your terminal.

.. _editors:

Editor configuration
====================

IPython can integrate with text editors in a number of different ways:

* Editors (such as `(X)Emacs`_, vim_ and TextMate_) can
  send code to IPython for execution.

* IPython's ``%edit`` magic command can open an editor of choice to edit
  a code block.

The %edit command (and its alias %ed) will invoke the editor set in your
environment as :envvar:`EDITOR`. If this variable is not set, it will default
to vi under Linux/Unix and to notepad under Windows. You may want to set this
variable properly and to a lightweight editor which doesn't take too long to
start (that is, something other than a new instance of Emacs). This way you
can edit multi-line code quickly and with the power of a real editor right
inside IPython.

You can also control the editor by setting :attr:`TerminalInteractiveShell.editor`
in :file:`ipython_config.py`.

Vim
---

Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides
powerful IPython integration for vim.

.. _emacs:

(X)Emacs
--------

If you are a dedicated Emacs user, and want to use Emacs when IPython's
``%edit`` magic command is called you should set up the Emacs server so that
new requests are handled by the original process. This means that almost no
time is spent in handling the request (assuming an Emacs process is already
running). For this to work, you need to set your EDITOR environment variable
to 'emacsclient'. The code below, supplied by Francois Pinard, can then be
used in your :file:`.emacs` file to enable the server:

.. code-block:: common-lisp

    (defvar server-buffer-clients)
    (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm))
      (server-start)
      (defun fp-kill-server-with-buffer-routine ()
        (and server-buffer-clients (server-done)))
      (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine))

Thanks to the work of Alexander Schmolck and Prabhu Ramachandran,
currently (X)Emacs and IPython get along very well in other ways.

With (X)EMacs >= 24, You can enable IPython in python-mode with:

.. code-block:: common-lisp

    (require 'python)
    (setq python-shell-interpreter "ipython")

.. _`(X)Emacs`: http://www.gnu.org/software/emacs/
.. _TextMate: http://macromates.com/
.. _vim: http://www.vim.org/

.. _custom_keyboard_shortcuts:

Keyboard Shortcuts
==================

.. versionadded:: 8.11

You can modify, disable or modify keyboard shortcuts for IPython Terminal using
:std:configtrait:`TerminalInteractiveShell.shortcuts` traitlet.

The list of shortcuts is available in the Configuring IPython :ref:`terminal-shortcuts-list` section.

Advanced configuration
----------------------

.. versionchanged:: 5.0

Creating custom commands requires adding custom code to a
:ref:`startup file <startup_files>`::

    from IPython import get_ipython
    from prompt_toolkit.enums import DEFAULT_BUFFER
    from prompt_toolkit.keys import Keys
    from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode

    ip = get_ipython()
    insert_mode = ViInsertMode() | EmacsInsertMode()

    def insert_unexpected(event):
        buf = event.current_buffer
        buf.insert_text('The Spanish Inquisition')
    # Register the shortcut if IPython is using prompt_toolkit
    if getattr(ip, 'pt_app', None):
        registry = ip.pt_app.key_bindings
        registry.add_binding(Keys.ControlN,
                         filter=(HasFocus(DEFAULT_BUFFER)
                                 & ~HasSelection()
                                 & insert_mode))(insert_unexpected)


Here is a second example that bind the key sequence ``j``, ``k`` to switch to
VI input mode to ``Normal`` when in insert mode::

   from IPython import get_ipython
   from prompt_toolkit.enums import DEFAULT_BUFFER
   from prompt_toolkit.filters import HasFocus, ViInsertMode
   from prompt_toolkit.key_binding.vi_state import InputMode

   ip = get_ipython()

   def switch_to_navigation_mode(event):
      vi_state = event.cli.vi_state
      vi_state.input_mode = InputMode.NAVIGATION

   if getattr(ip, 'pt_app', None):
      registry = ip.pt_app.key_bindings
      registry.add_binding(u'j',u'k',
                           filter=(HasFocus(DEFAULT_BUFFER)
                                    & ViInsertMode()))(switch_to_navigation_mode)

For more information on filters and what you can do with the ``event`` object,
`see the prompt_toolkit docs
<https://python-prompt-toolkit.readthedocs.io/en/latest/pages/asking_for_input.html#adding-custom-key-bindings>`__.


Enter to execute
----------------

In the Terminal IPython shell – which by default uses the ``prompt_toolkit``
interface, the semantic meaning of pressing the :kbd:`Enter` key can be
ambiguous. In some case :kbd:`Enter` should execute code, and in others it
should add a new line. IPython uses heuristics to decide whether to execute or
insert a new line at cursor position. For example, if we detect that the current
code is not valid Python, then the user is likely editing code and the right
behavior is to likely to insert a new line. If the current code is a simple
statement like `ord('*')`, then the right behavior is likely to execute. Though
the exact desired semantics often varies from users to users.

As the exact behavior of :kbd:`Enter` is ambiguous, it has been special cased
to allow users to completely configure the behavior they like. Hence you can
have enter always execute code. If you prefer fancier behavior, you need to get
your hands dirty and read the ``prompt_toolkit`` and IPython documentation
though. See :ghpull:`10500`, set the
``c.TerminalInteractiveShell.handle_return`` option and get inspiration from the
following example that only auto-executes the input if it begins with a bang or
a modulo character (``!`` or ``%``). To use the following code, add it to your
IPython configuration::

    def custom_return(shell):

        """This function is required by the API. It takes a reference to
        the shell, which is the same thing `get_ipython()` evaluates to.
        This function must return a function that handles each keypress
        event. That function, named `handle` here, references `shell`
        by closure."""

        def handle(event):

            """This function is called each time `Enter` is pressed,
            and takes a reference to a Prompt Toolkit event object.
            If the current input starts with a bang or modulo, then
            the input is executed, otherwise a newline is entered,
            followed by any spaces needed to auto-indent."""

            # set up a few handy references to nested items...

            buffer = event.current_buffer
            document = buffer.document
            text = document.text

            if text.startswith('!') or text.startswith('%'): # execute the input...

                buffer.accept_action.validate_and_handle(event.cli, buffer)

            else: # insert a newline with auto-indentation...

                if document.line_count > 1: text = text[:document.cursor_position]
                indent = shell.check_complete(text)[1]
                buffer.insert_text('\n' + indent)
            
                # if you just wanted a plain newline without any indentation, you
                # could use `buffer.insert_text('\n')` instead of the lines above

        return handle

    c.TerminalInteractiveShell.handle_return = custom_return