]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | """ |
2 | Utilities for end-users. | |
3 | """ | |
4 | ||
5 | import __main__ | |
6 | from collections import namedtuple | |
7 | import logging | |
8 | import traceback | |
9 | import re | |
10 | import os | |
11 | import sys | |
12 | ||
13 | from jedi import Interpreter | |
14 | ||
15 | ||
16 | READLINE_DEBUG = False | |
17 | ||
18 | ||
19 | def setup_readline(namespace_module=__main__, fuzzy=False): | |
20 | """ | |
21 | This function sets up :mod:`readline` to use Jedi in a Python interactive | |
22 | shell. | |
23 | ||
24 | If you want to use a custom ``PYTHONSTARTUP`` file (typically | |
25 | ``$HOME/.pythonrc.py``), you can add this piece of code:: | |
26 | ||
27 | try: | |
28 | from jedi.utils import setup_readline | |
29 | except ImportError: | |
30 | # Fallback to the stdlib readline completer if it is installed. | |
31 | # Taken from http://docs.python.org/2/library/rlcompleter.html | |
32 | print("Jedi is not installed, falling back to readline") | |
33 | try: | |
34 | import readline | |
35 | import rlcompleter | |
36 | readline.parse_and_bind("tab: complete") | |
37 | except ImportError: | |
38 | print("Readline is not installed either. No tab completion is enabled.") | |
39 | else: | |
40 | setup_readline() | |
41 | ||
42 | This will fallback to the readline completer if Jedi is not installed. | |
43 | The readline completer will only complete names in the global namespace, | |
44 | so for example:: | |
45 | ||
46 | ran<TAB> | |
47 | ||
48 | will complete to ``range``. | |
49 | ||
50 | With Jedi the following code:: | |
51 | ||
52 | range(10).cou<TAB> | |
53 | ||
54 | will complete to ``range(10).count``, this does not work with the default | |
55 | cPython :mod:`readline` completer. | |
56 | ||
57 | You will also need to add ``export PYTHONSTARTUP=$HOME/.pythonrc.py`` to | |
58 | your shell profile (usually ``.bash_profile`` or ``.profile`` if you use | |
59 | bash). | |
60 | """ | |
61 | if READLINE_DEBUG: | |
62 | logging.basicConfig( | |
63 | filename='/tmp/jedi.log', | |
64 | filemode='a', | |
65 | level=logging.DEBUG | |
66 | ) | |
67 | ||
68 | class JediRL: | |
69 | def complete(self, text, state): | |
70 | """ | |
71 | This complete stuff is pretty weird, a generator would make | |
72 | a lot more sense, but probably due to backwards compatibility | |
73 | this is still the way how it works. | |
74 | ||
75 | The only important part is stuff in the ``state == 0`` flow, | |
76 | everything else has been copied from the ``rlcompleter`` std. | |
77 | library module. | |
78 | """ | |
79 | if state == 0: | |
80 | sys.path.insert(0, os.getcwd()) | |
81 | # Calling python doesn't have a path, so add to sys.path. | |
82 | try: | |
83 | logging.debug("Start REPL completion: " + repr(text)) | |
84 | interpreter = Interpreter(text, [namespace_module.__dict__]) | |
85 | ||
86 | completions = interpreter.complete(fuzzy=fuzzy) | |
87 | logging.debug("REPL completions: %s", completions) | |
88 | ||
89 | self.matches = [ | |
90 | text[:len(text) - c._like_name_length] + c.name_with_symbols | |
91 | for c in completions | |
92 | ] | |
93 | except: | |
94 | logging.error("REPL Completion error:\n" + traceback.format_exc()) | |
95 | raise | |
96 | finally: | |
97 | sys.path.pop(0) | |
98 | try: | |
99 | return self.matches[state] | |
100 | except IndexError: | |
101 | return None | |
102 | ||
103 | try: | |
104 | # Need to import this one as well to make sure it's executed before | |
105 | # this code. This didn't use to be an issue until 3.3. Starting with | |
106 | # 3.4 this is different, it always overwrites the completer if it's not | |
107 | # already imported here. | |
108 | import rlcompleter # noqa: F401 | |
109 | import readline | |
110 | except ImportError: | |
111 | print("Jedi: Module readline not available.") | |
112 | else: | |
113 | readline.set_completer(JediRL().complete) | |
114 | readline.parse_and_bind("tab: complete") | |
115 | # jedi itself does the case matching | |
116 | readline.parse_and_bind("set completion-ignore-case on") | |
117 | # because it's easier to hit the tab just once | |
118 | readline.parse_and_bind("set show-all-if-unmodified") | |
119 | readline.parse_and_bind("set show-all-if-ambiguous on") | |
120 | # don't repeat all the things written in the readline all the time | |
121 | readline.parse_and_bind("set completion-prefix-display-length 2") | |
122 | # No delimiters, Jedi handles that. | |
123 | readline.set_completer_delims('') | |
124 | ||
125 | ||
126 | def version_info(): | |
127 | """ | |
128 | Returns a namedtuple of Jedi's version, similar to Python's | |
129 | ``sys.version_info``. | |
130 | """ | |
131 | Version = namedtuple('Version', 'major, minor, micro') | |
132 | from jedi import __version__ | |
133 | tupl = re.findall(r'[a-z]+|\d+', __version__) | |
134 | return Version(*[x if i == 3 else int(x) for i, x in enumerate(tupl)]) |