writing Python in Emacs

Discussion in 'Python' started by Richard Szopa, Jan 19, 2008.

  1. Hi All,

    I am a devoted Emacs user and I write a lot in Python. However, I
    never managed to get my Emacs configuration right for this purpose.
    There were some discussions on this, but the threads that show if I
    search the group are either old or not so relevant.

    I need the following features:

    0) Of course, syntax coloring and so on... But this works good enough
    ootb in the two most popular python-modes.

    1) Tab completion, ideally Slime like. That is, when there's not
    enough letters to unambiguously complete a symbol, I want it to show a
    buffer (w/o taking the focus) w/ the possible completions. In an ideal
    world, it would be able to complete fo.ba<TAB> to foo.bar. I imagine
    this would require quite tight Emacs-Python integration.

    2) Sending the toplevel definition (class or function) to the Python
    buffer.

    3) Hints on function/method arguments. IDLE has this done nearly
    right, but the hints are a bit too intrusive for me. I would like to
    see them in the minibuffer.

    4) (optional) I would like to see the definition of a function
    function or class by hitting M-. on its name. (I understand that this
    may be impossible for methods, as Emacs would have to automagically
    infer the type of the object).

    I have tried a couple of times both python-modes (the one shipped w/
    Python and the one shipped w/ Emacs), pymacs and stuff like that...
    And, as I said, never got it right. But, maybe I just cannot find the
    way to configure it, and some configuration hints will be enough...

    As for other editors, I have tried Eclipse and Komodo... But I cannot
    get used to them. As for non-emacs stuff, the most comfortable for me
    has been IDLE.

    Cheers and thanks in advance,

    -- Richard
    Richard Szopa, Jan 19, 2008
    #1
    1. Advertising

  2. Richard Szopa

    Terry Jones Guest

    >>>>> "Richard" == Richard Szopa <> writes:

    Richard> I am a devoted Emacs user and I write a lot in Python.

    Me too.

    Richard> I need the following features:

    Richard> 1) Tab completion, ideally Slime like. That is, when there's not
    Richard> enough letters to unambiguously complete a symbol, I want it to
    Richard> show a buffer (w/o taking the focus) w/ the possible
    Richard> completions. In an ideal world, it would be able to complete
    Richard> fo.ba<TAB> to foo.bar. I imagine this would require quite tight
    Richard> Emacs-Python integration.

    I know this is not what you want, but I use hippie expand (M-/) to cycle
    through possible completions. It's not Python aware, but it is of some use.

    Richard> 2) Sending the toplevel definition (class or function) to the Python
    Richard> buffer.

    I switched to IPython to have better interaction with a spawned Python.

    To use IPython you need to use the Python mode that is NOT the one from
    (endorsed?) by the FSF. It gives you some completion (at least in the
    *Python* buffer) and you can send pieces of the buffer to the python
    process, via py-send-region (C-c |), py-execute-def-or-class (M-C-x), etc.

    Richard> 3) Hints on function/method arguments. IDLE has this done nearly
    Richard> right, but the hints are a bit too intrusive for me. I would like to
    Richard> see them in the minibuffer.

    I don't have this.

    Richard> 4) (optional) I would like to see the definition of a function
    Richard> function or class by hitting M-. on its name. (I understand that
    Richard> this may be impossible for methods, as Emacs would have to
    Richard> automagically infer the type of the object).

    This is just an emacs tag file need. Have you googled for something like
    emacs tags python? The issue of methods might be overcome by just moving
    through tags with the same name. Yes, that requires _you_ to know when
    you've hit the right thing. That's not optimal, but it's better than
    nothing. Ideally you could send the definition to IPython, ask it for the
    class info, and use that to jump to the right tag.

    Richard> I have tried a couple of times both python-modes (the one shipped w/
    Richard> Python and the one shipped w/ Emacs), pymacs and stuff like that...
    Richard> And, as I said, never got it right. But, maybe I just cannot find the
    Richard> way to configure it, and some configuration hints will be enough...

    If you have the time, please summarize your findings. The emacs/python
    world has always seemed quite amorphous to me too.

    Terry
    Terry Jones, Jan 19, 2008
    #2
    1. Advertising

  3. I add just a note about ipython:
    if you use a version > 0.6.15 may be you will have a bad output
    on error like:

    == " ":
    instead of:
    if __name__ == "__main__":

    all the characters are missing.

    To avoid that, run in ipython:
    %upgrade -nolegacy

    uncomment in ~/.ipython/ipy_user_config.py:
    import ipy_defaults

    restart emacs and try a .py with some syntax errors.
    It should be ok now.

    Terry Jones <> writes:

    >>>>>> "Richard" == Richard Szopa <> writes:

    >
    > Richard> I am a devoted Emacs user and I write a lot in Python.
    >
    > Me too.
    >
    > Richard> I need the following features:
    >
    > Richard> 1) Tab completion, ideally Slime like. That is, when there's not
    > Richard> enough letters to unambiguously complete a symbol, I want it to
    > Richard> show a buffer (w/o taking the focus) w/ the possible
    > Richard> completions. In an ideal world, it would be able to complete
    > Richard> fo.ba<TAB> to foo.bar. I imagine this would require quite tight
    > Richard> Emacs-Python integration.
    >
    > I know this is not what you want, but I use hippie expand (M-/) to cycle
    > through possible completions. It's not Python aware, but it is of some use.
    >
    > Richard> 2) Sending the toplevel definition (class or function) to the Python
    > Richard> buffer.
    >
    > I switched to IPython to have better interaction with a spawned Python.
    >
    > To use IPython you need to use the Python mode that is NOT the one from
    > (endorsed?) by the FSF. It gives you some completion (at least in the
    > *Python* buffer) and you can send pieces of the buffer to the python
    > process, via py-send-region (C-c |), py-execute-def-or-class (M-C-x), etc.
    >
    > Richard> 3) Hints on function/method arguments. IDLE has this done nearly
    > Richard> right, but the hints are a bit too intrusive for me. I would like to
    > Richard> see them in the minibuffer.
    >
    > I don't have this.
    >
    > Richard> 4) (optional) I would like to see the definition of a function
    > Richard> function or class by hitting M-. on its name. (I understand that
    > Richard> this may be impossible for methods, as Emacs would have to
    > Richard> automagically infer the type of the object).
    >
    > This is just an emacs tag file need. Have you googled for something like
    > emacs tags python? The issue of methods might be overcome by just moving
    > through tags with the same name. Yes, that requires _you_ to know when
    > you've hit the right thing. That's not optimal, but it's better than
    > nothing. Ideally you could send the definition to IPython, ask it for the
    > class info, and use that to jump to the right tag.
    >
    > Richard> I have tried a couple of times both python-modes (the one shipped w/
    > Richard> Python and the one shipped w/ Emacs), pymacs and stuff like that...
    > Richard> And, as I said, never got it right. But, maybe I just cannot find the
    > Richard> way to configure it, and some configuration hints will be enough...
    >
    > If you have the time, please summarize your findings. The emacs/python
    > world has always seemed quite amorphous to me too.
    >
    > Terry
    > _______________________________________________
    > help-gnu-emacs mailing list
    >
    > http://lists.gnu.org/mailman/listinfo/help-gnu-emacs
    >


    --
    A + Thierry
    Pub key: http://pgp.mit.edu
    Thierry Volpiatto, Jan 19, 2008
    #3
  4. Richard Szopa

    Jorgen Grahn Guest

    ["Followup-To:" header set to comp.lang.python.]

    On Sat, 19 Jan 2008 17:51:50 +0100, Terry Jones <> wrote:
    >>>>>> "Richard" == Richard Szopa <> writes:

    >
    >Richard> I am a devoted Emacs user and I write a lot in Python.
    >
    > Me too.
    >
    >Richard> I need the following features:
    >
    >Richard> 1) Tab completion, ideally Slime like. That is, when there's not
    >Richard> enough letters to unambiguously complete a symbol, I want it to
    >Richard> show a buffer (w/o taking the focus) w/ the possible
    >Richard> completions. In an ideal world, it would be able to complete
    >Richard> fo.ba<TAB> to foo.bar. I imagine this would require quite tight
    >Richard> Emacs-Python integration.
    >
    > I know this is not what you want, but I use hippie expand (M-/) to cycle
    > through possible completions. It's not Python aware, but it is of some use.


    Also known as dabbrev-expand, and tied to Ctrl-TAB.

    I like it *a lot*, and I like it even more because it *isn't* Python
    aware. I can use the same function no matter what I am typing, often
    with files noone would dream of writing a mode for.

    ....
    >Richard> 4) (optional) I would like to see the definition of a function
    >Richard> function or class by hitting M-. on its name. (I understand that
    >Richard> this may be impossible for methods, as Emacs would have to
    >Richard> automagically infer the type of the object).
    >
    > This is just an emacs tag file need. Have you googled for something like
    > emacs tags python?


    Tags works fine, or at least as well as can be expected. I use the
    'etags' which comes with 'ctags', apparently.

    > If you have the time, please summarize your findings. The emacs/python
    > world has always seemed quite amorphous to me too.


    I don't know; python-mode colorizes well and it knows how to help me
    keep the indentation sane. The Eclipse users I have seen seem to have
    more problems than I have, for example.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
    \X/ snipabacken.se> R'lyeh wgah'nagl fhtagn!
    Jorgen Grahn, Jan 20, 2008
    #4
  5. Richard Szopa

    Rob Wolfe Guest

    Terry Jones <> writes:

    >>>>>> "Richard" == Richard Szopa <> writes:


    I don't see Richard's original post, so I reply to Terry.

    >
    > Richard> I am a devoted Emacs user and I write a lot in Python.
    >
    > Me too.


    The good news is that I managed to configure completion for Python
    in Emacs using pymacs, python-mode.el, pycomplete.el and pycomplete.py.
    For contents of my pycomplete.el, pycomplete.py and necessary
    settings in .emacs see below.

    >
    > Richard> I need the following features:
    >
    > Richard> 1) Tab completion, ideally Slime like. That is, when there's not
    > Richard> enough letters to unambiguously complete a symbol, I want it to
    > Richard> show a buffer (w/o taking the focus) w/ the possible
    > Richard> completions. In an ideal world, it would be able to complete
    > Richard> fo.ba<TAB> to foo.bar. I imagine this would require quite tight
    > Richard> Emacs-Python integration.


    Works for me.

    [...]

    > Richard> 2) Sending the toplevel definition (class or function) to the Python
    > Richard> buffer.


    That feature is defined in python-mode.el:
    "\e\C-x" 'py-execute-def-or-class
    "\C-c|" 'py-execute-region


    [...]

    > Richard> 3) Hints on function/method arguments. IDLE has this done nearly
    > Richard> right, but the hints are a bit too intrusive for me. I would like to
    > Richard> see them in the minibuffer.


    Works for me, but only for pure python functions
    (`inspect.getargspec` constraint).

    [...]

    > Richard> I have tried a couple of times both python-modes (the one shipped w/
    > Richard> Python and the one shipped w/ Emacs), pymacs and stuff like that...
    > Richard> And, as I said, never got it right. But, maybe I just cannot find the
    > Richard> way to configure it, and some configuration hints will be enough...


    I mixed solutions found around the net and finally got it working:
    - hitting TAB complete function/method name
    - f1 shows description of object at point
    - hitting '(' and ',' shows function parameters

    Copy `pycomplete.py` on your PYTHONPATH (e.g. /usr/lib/python2.5/site-packages)
    and `pycomplete.el` on your Emacs load_path (e.g. /usr/share/emacs/site-lisp).
    Copy my settings to your `.emacs` file and hopefully it will work. ;)

    My files:

    # .emacs
    (require 'pycomplete)
    (setq auto-mode-alist (cons '("\\.py$" . python-mode) auto-mode-alist))
    (autoload 'python-mode "python-mode" "Python editing mode." t)

    (autoload 'pymacs-load "pymacs" nil t)
    (autoload 'pymacs-eval "pymacs" nil t)
    (autoload 'pymacs-apply "pymacs")
    (autoload 'pymacs-call "pymacs")

    (setq interpreter-mode-alist(cons '("python" . python-mode)
    interpreter-mode-alist))
    (setq python-mode-hook
    '(lambda () (progn
    (set-variable 'py-python-command "/usr/bin/python2.5")
    (set-variable 'py-indent-offset 4)
    (set-variable 'py-smart-indentation nil)
    (set-variable 'indent-tabs-mode nil))))
    # end of .emacs


    # pycomplete.el
    (require 'pymacs)
    (require 'python-mode)

    (pymacs-load "pycomplete")


    ;;check if prev character is blank-type
    (defun char-before-blank ()
    (save-excursion
    (forward-char -1)
    (looking-at "[\n\t\r]")))

    (defun py-complete ()
    (interactive)
    (let ((pymacs-forget-mutability t))
    (if (and
    (and (eolp) (not (bolp))
    (not (char-before-blank))))
    (insert (pycomplete-pycomplete (py-symbol-near-point) (py-find-global-imports)))
    (indent-for-tab-command))))

    (defun py-find-global-imports ()
    (save-excursion
    (let ((imports nil))
    (goto-char (point-min))
    (while (re-search-forward
    "\\(import \\|from \\([A-Za-z_][A-Za-z_0-9\\.]*\\) import \\).*"
    nil t)
    (setq imports
    (append imports (list (buffer-substring
    (match-beginning 0)
    (match-end 0))))))
    imports)))


    (defun py-complete-python-dotexpr-begin nil
    (interactive)
    (re-search-backward "[^a-zA-Z_0-9\\.]")
    (forward-char))


    (defun py-complete-python-dotexpr-end nil
    (interactive)
    (re-search-forward "[a-zA-Z_0-9\\.]*"))

    (put 'python-dotexpr 'beginning-op 'py-complete-python-dotexpr-begin)
    (put 'python-dotexpr 'end-op 'py-complete-python-dotexpr-end)


    (defun py-complete-show (string)
    (display-message-or-buffer string "*PythonHelp*"))


    (defun py-complete-help (string)
    "get help on a python expression"
    (let ((help-string
    (pycomplete-pyhelp string (py-find-global-imports))))
    (if (and help-string (> (length help-string) 300))
    (with-output-to-temp-buffer "*Python Help*"
    (print help-string))
    (py-complete-show help-string))))


    (defun py-complete-help-thing-at-point nil
    (interactive)
    (require 'thingatpt)
    (let ((sym (thing-at-point 'python-dotexpr)))
    (if sym
    (py-complete-help sym))))


    (set 'py-complete-current-signature nil)

    (defun py-complete-signature (function)
    "get signature of a python function or method"
    (interactive)
    (set 'py-complete-current-signature
    (pycomplete-pysignature function)))


    (defun py-complete-signature-show nil
    (interactive)
    (require 'thingatpt)
    (let ((sym (thing-at-point 'python-dotexpr)))
    (if sym
    (progn
    (py-complete-show (py-complete-signature sym))))))


    (defun py-complete-signature-expr nil
    (interactive)
    (require 'thingatpt)
    (let ((dotexpr (read-string "signature on: "
    (thing-at-point 'python-dotexpr))))
    (if dotexpr
    (py-complete-show
    (py-complete-signature dotexpr)))))


    (defun py-complete-electric-lparen nil
    "electricly insert '(', and try to get a signature for the stuff to the left"
    (interactive)
    (py-complete-signature-show)
    (self-insert-command 1))


    (defun py-complete-electric-comma nil
    "electricly insert ',', and redisplay latest signature"
    (interactive)
    (self-insert-command 1)
    (if py-complete-current-signature
    (py-complete-show (format "%s" py-complete-current-signature))))


    (define-key py-mode-map "\M-\C-i" 'py-complete)
    (define-key py-mode-map "\t" 'py-complete)
    (define-key py-mode-map [f1] 'py-complete-help-thing-at-point)
    (define-key py-mode-map "(" 'py-complete-electric-lparen)
    (define-key py-mode-map "," 'py-complete-electric-comma)
    (define-key py-mode-map [f2] 'py-complete-signature-expr)

    (provide 'pycomplete)
    # end of pycomplete.el


    # pycomplete.py
    import sys
    import inspect
    from StringIO import StringIO
    import os.path

    try:
    x = set
    except NameError:
    from sets import Set as set
    else:
    del x

    from Pymacs import lisp


    sys.path.append('.')


    def pycomplete(s, imports=None, debug=False):
    """Display completion in Emacs window"""
    completions = _get_all_completions(s, imports)
    dots = s.split(".")
    result = os.path.commonprefix([k[len(dots[-1]):] for k in completions])

    if result == "":
    if completions:
    if debug:
    width = 80
    else:
    width = lisp.window_width() - 2

    column = width / 20
    white = " " * 20
    msg = ""

    counter = 0
    for completion in completions :
    if len(completion) < 20 :
    msg += completion + white[len(completion):]
    counter += 1
    else :
    msg += completion + white[len(completion) - 20:]
    counter += 2

    if counter >= column:
    counter = 0
    msg += '\n'

    else:
    msg = "no completions!"
    if debug:
    print msg
    else:
    lisp.message(msg)
    return result


    def pyhelp(s, imports=None):
    """Return object description"""
    _import_modules(imports, globals(), None)
    return _getdoc(s)


    def pysignature(s):
    """Return info about function parameters"""
    f = None
    try:
    f = eval(s)
    except Exception, ex:
    return "%s" % ex

    if inspect.ismethod(f):
    f = f.im_func
    if not inspect.isfunction(f):
    return ''
    (args, varargs, varkw, defaults) = inspect.getargspec(f)
    return('%s: %s'
    % (f.__name__, inspect.formatargspec(args,varargs,varkw,defaults)))


    def _getdoc(s):
    """Return string printed by `help` function"""
    obj = None
    try:
    obj = eval(s)
    except Exception, ex:
    return "%s" % ex
    out = StringIO()
    old = sys.stdout
    sys.stdout = out
    help(obj)
    sys.stdout = old
    return out.getvalue()


    def _import_modules(imports, dglobals, dlocals):
    """If given, execute import statements"""

    if imports is not None:
    for stmt in imports:
    try:
    exec stmt in dglobals, dlocals
    except TypeError:
    raise TypeError, 'invalid type: %s' % stmt
    except:
    continue


    def _get_all_completions(s, imports=None):
    """Return contextual completion of s (string of >= zero chars)"""

    dlocals = {}
    _import_modules(imports, globals(), dlocals)
    dots = s.split(".")
    if not s or len(dots) == 1:
    keys = set()
    keys.update(dlocals.keys())
    keys.update(globals().keys())
    import __builtin__
    keys.update(dir(__builtin__))
    keys = list(keys)
    keys.sort()
    if s:
    return [k for k in keys if k.startswith(s)]
    else:
    return keys

    sym = None
    for i in range(1, len(dots)):
    s = ".".join(dots[:i])
    try:
    sym = eval(s, globals(), dlocals)
    except NameError:
    try:
    sym = __import__(s, globals(), dlocals, [])
    except ImportError:
    return []
    if sym is not None:
    s = dots[-1]
    return [k for k in dir(sym) if k.startswith(s)]


    def _test():
    print ' ->', pycomplete('', debug=True)
    print 'sys.get ->', pycomplete('sys.get', debug=True)
    print 'settr ->', pycomplete('settr', debug=True)
    print 'settr (plat in context) ->',
    print pycomplete('settr', imports=['from sys import settrace'], debug=True)
    print 'foo. ->', pycomplete('foo.', debug=True)
    print 'Enc (email * imported) ->',
    print pycomplete('Enc', imports=['from email import *'], debug=True)
    print 'E (email * imported) ->',
    print pycomplete('E', imports=['from email import *'], debug=True)
    print 'Enc ->', pycomplete('Enc', debug=True)
    print 'E ->', pycomplete('E', debug=True)


    if __name__ == "__main__":
    _test()
    # end of pycomplete.py


    HTH,
    Rob
    Rob Wolfe, Jan 20, 2008
    #5
  6. Thanks Rob. Your code should basically do the trick.

    -- Richard
    Ryszard Szopa, Jan 31, 2008
    #6
  7. Richard Szopa

    Guest

    Rob Wolfe wrote:
    > The good news is that I managed to configure completion for Python
    > in Emacs using pymacs, python-mode.el, pycomplete.el and pycomplete.py.
    > For contents of my pycomplete.el, pycomplete.py and necessary
    > settings in .emacs see below.


    Thanks for that! I've been hoping something like this landed on my
    lap for years.
    , Jan 31, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Seweryn Kokot
    Replies:
    1
    Views:
    271
    Diez B. Roggisch
    Nov 12, 2006
  2. Replies:
    0
    Views:
    221
  3. Replies:
    0
    Views:
    86
  4. Adam Funk
    Replies:
    4
    Views:
    217
    Adam Funk
    Jan 29, 2007
  5. Replies:
    0
    Views:
    70
Loading...

Share This Page