yet another blog.

October 30, 2007

Using PythonTidy in pydev as code formatter.

Filed under: Uncategorized — bear330 @ 7:07 am

My favorite python ide is Eclipse + Pydev. Pydev is a good eclipse plugin to make develop with python efficiently. But you will find its Autoformat (code format) feature is too simple to make things work.

I worked with some python newbie, they are just learning python and don’t know what is PEP08 (Style Guide for Python Code). Usually, they are experts in some other languages like C++, Java or C# with powerful IDE. They rely on code completion and code format feature too much. When they use Eclipse + Pydev, the source code they written is terrible…

I searched python code formatter (beautifier) for a long time. Unfortunately, there is no good product or tool to do that. Finally, the tool which is the closest to what I want is PythonTidy. This script format your code to fulfill PEP08 and it can be customized to satisfy the coding standard in your team.

The problem is PythonTidy is a standalone script to run it. This is not very convenient for us to use it. We must make pydev to integrated with PythonTidy to enhance its code format feature.

Basically, the pydev is a extensible tool to make us integrated PythonTidy easily. You can write some Jython script to extend pydev if you familiar with Java and Eclipse also. I wrote a simple script to make PythonTidy work while we press Ctrl+Shift+F.

If you want to use it, save the code below in somewhere you want as pyedit_pythontidy.py (pyedit_ is required).

"""
This code is public domain.
The original author is Bear Huang (https://bear330.wordpress.com/).
"""
if False:
    from org.python.pydev.editor import PyEdit #@UnresolvedImport
    cmd = 'command string'
    editor = PyEdit

assert cmd is not None
assert editor is not None

if cmd == 'onCreateActions':
    # from org.eclipse.jface.action import Action
    from org.python.pydev.editor.actions import PyAction
    from org.python.pydev.core.docutils import PySelection
    from java.lang import Runnable
    from org.eclipse.swt.widgets import Display
    from org.eclipse.jface.text import IDocument
    from org.eclipse.jface.text import TextSelection

    from java.io import FileWriter
    import java.lang.Exception

    FORMAT_ACTION_DEFINITION_ID = "org.python.pydev.editor.actions.pyFormatStd"
    FORMAT_ACTION_ID = "org.python.pydev.editor.actions.navigation.pyFormatStd"

    class PythonTidyAction(PyAction):

        def __init__(self, *args, **kws):
            PyAction.__init__(self, *args, **kws)

        def run(self):
            import tempfile
            import os

            try:
                ps = PySelection(editor)
                doc = ps.getDoc()
                startLine = ps.getStartLineIndex()

                p1 = tempfile.mktemp()
                p2 = tempfile.mktemp()
                f1 = FileWriter(p1)

                formatAll = False
                if ps.getTextSelection().getLength() == 0:
                    # format all.
                    c = doc.get()
                    f1.write(c)
                    formatAll = True
                else:
                    # format selection.
                    #c = ps.getSelectedText()
                    #f1.write(ps.getSelectedText())
                    print "Format selected text is not supported yet."
                    f1.write("")
                    # A kind of solution is to insert a special comment in
                    # front and end of selection text, pythontidy it, and
                    # extract text according that comment. 

                f1.close()
                os.system('PythonTidy.py "%s" "%s"' % (p1, p2))
                f2 = open(p2, "r")
                result = f2.read()
                f2.close()

                os.remove(p1)
                os.remove(p2)

                if startLine >= doc.getNumberOfLines():
                    startLine = doc.getNumberOfLines() - 1

                if formatAll:
                    doc.set(result)
                else:
                    #doc.replace(doc.getLineOffset(startLine), 0, result)
                    pass

                sel = TextSelection(doc, doc.getLineOffset(startLine), 0)
                self.getTextEditor().getSelectionProvider().setSelection(sel)
            except java.lang.Exception, e:
                self.beep(e)

    def bindInInterface():
        act = PythonTidyAction()

        act.setActionDefinitionId(FORMAT_ACTION_DEFINITION_ID)
        act.setId(FORMAT_ACTION_ID)
        try:
            editor.setAction(FORMAT_ACTION_ID, act)
        except:
            pass

    class RunInUi(Runnable):
        '''Helper class that implements a Runnable (just so that we
        can pass it to the Java side). It simply calls some callable.
        '''

        def __init__(self, c):
            self.callable = c
        def run(self):
            self.callable ()

    def runInUi(callable):
        '''
        @param callable: the callable that will be run in the UI
        '''
        Display.getDefault().asyncExec(RunInUi(callable))

    runInUi(bindInInterface)

Next, go to eclipse pydev preferences page to specify the script location:

pydev_pythontidy.jpg

Now, you can simply press Ctrl+Shift+F while edit python code.

(Format selected text is not supported yet, this is because I am too lazy to implement it in this time. If I have time and wish to do that, I will publish it as soon as posible.)

Any contributions are appreciated. 🙂

8 Comments »

  1. send this to the pydev developer please!

    Comment by mic — February 29, 2012 @ 1:56 am | Reply

  2. Thanks! I’m very grateful that you took the time to write this up. It works perfectly.

    Comment by Tom Stratton — August 8, 2012 @ 2:11 pm | Reply

  3. Does PyDev have background PEP8 etc. check which would highlight these errors while typing?

    Comment by Mikko Ohtamaa — December 4, 2012 @ 3:08 pm | Reply

  4. Nice work!! I’m using autopep8 with the above method!


    """
    This code is public domain.
    The original author is Bear Huang (https://bear330.wordpress.com/).
    Uploaded to GIST and adapted for autopep8 by github/benjaoming
    """
    # Guide for installing a code formatter (like this one) in PyDev:
    # https://bear330.wordpress.com/2007/10/30/using-pythontidy-in-pydev-as-code-formatter/
    # Ensure that your autopep8.py is executable (chmod +x).
    ABS_PATH_TO_AUTOPEP8 = "/home/you/bin/autopep8.py"
    if False:
    from org.python.pydev.editor import PyEdit #@UnresolvedImport
    cmd = 'command string'
    editor = PyEdit
    assert cmd is not None
    assert editor is not None
    if cmd == 'onCreateActions':
    # from org.eclipse.jface.action import Action
    from org.python.pydev.editor.actions import PyAction
    from org.python.pydev.core.docutils import PySelection
    from java.lang import Runnable
    from org.eclipse.swt.widgets import Display
    from org.eclipse.jface.text import IDocument
    from org.eclipse.jface.text import TextSelection
    from java.io import FileWriter
    import java.lang.Exception
    FORMAT_ACTION_DEFINITION_ID = "org.python.pydev.editor.actions.pyFormatStd"
    FORMAT_ACTION_ID = "org.python.pydev.editor.actions.navigation.pyFormatStd"
    class PythonTidyAction(PyAction):
    def __init__(self, *args, **kws):
    PyAction.__init__(self, *args, **kws)
    def run(self):
    import tempfile
    import os
    try:
    ps = PySelection(editor)
    doc = ps.getDoc()
    startLine = ps.getStartLineIndex()
    p1 = tempfile.mktemp()
    p2 = tempfile.mktemp()
    f1 = FileWriter(p1)
    result = ""
    formatAll = False
    if ps.getTextSelection().getLength() == 0:
    # format all.
    c = doc.get()
    f1.write(c)
    formatAll = True
    else:
    # format selection.
    #c = ps.getSelectedText()
    #f1.write(ps.getSelectedText())
    print "Format selected text is not supported yet."
    f1.write("")
    # A kind of solution is to insert a special comment in
    # front and end of selection text, pythontidy it, and
    # extract text according that comment.
    f1.close()
    #os.system('/home/benjamin/bin/PythonTidy.py "%s" "%s"' % (p1, p2))
    os.system('%s –aggressive –aggressive –experimental "%s" > "%s"' % (ABS_PATH_TO_AUTOPEP8, p1, p2))
    f2 = open(p2, "r")
    result = f2.read()
    f2.close()
    os.remove(p1)
    os.remove(p2)
    if startLine >= doc.getNumberOfLines():
    startLine = doc.getNumberOfLines() – 1
    if formatAll:
    doc.set(result)
    else:
    #doc.replace(doc.getLineOffset(startLine), 0, result)
    pass
    sel = TextSelection(doc, doc.getLineOffset(startLine), 0)
    self.getTextEditor().getSelectionProvider().setSelection(sel)
    except java.lang.Exception, e:
    self.beep(e)
    def bindInInterface():
    act = PythonTidyAction()
    act.setActionDefinitionId(FORMAT_ACTION_DEFINITION_ID)
    act.setId(FORMAT_ACTION_ID)
    try:
    editor.setAction(FORMAT_ACTION_ID, act)
    except:
    pass
    class RunInUi(Runnable):
    '''Helper class that implements a Runnable (just so that we
    can pass it to the Java side). It simply calls some callable.
    '''
    def __init__(self, c):
    self.callable = c
    def run(self):
    self.callable ()
    def runInUi(callable):
    '''
    @param callable: the callable that will be run in the UI
    '''
    Display.getDefault().asyncExec(RunInUi(callable))
    runInUi(bindInInterface)

    Comment by benjaoming — April 1, 2014 @ 10:41 am | Reply

    • What is the trick to hooking into the PyDev editor actions?
      I notice the Eclipse Key shortcuts can be allocated to “org.python.pydev.actions.navigation.pyFormatStd”. Is this significant?
      I’m suing Eclipse (Kepler) and PyDev Aptana (3.4.1)

      Comment by John Harriott — May 29, 2014 @ 6:22 am | Reply

      • I have solved the problem using a different script. It was most likely PEBKAC

        Comment by John Harriott — May 30, 2014 @ 4:39 am

  5. Great post, how ever I got a nullpointer exception when I tried to use it. It was –
    :java.lang.NullPointerException
    at org.python.pydev.shared_ui.actions.BaseAction.getTextEditor(BaseAction.java:83):

    It was the getTextEditor method which was “broken?”. I finally fixed it, after having to learn a bunch of Jython etc. I hope this fix saves someone some time.

    Here is my fix: http://goo.gl/MuVUmj

    Comment by A humble TSE dev — July 30, 2014 @ 11:33 pm | Reply

  6. […] You can take a look at PythonTidy (external tool)… it’s possible to use it as defined in: https://bear330.wordpress.com/2007/10/30/using-pythontidy-in-pydev-as-code-formatter/ […]

    Pingback by Is there any way to fix PEP-8 issues with pydev? - Tutorial Guruji — September 25, 2021 @ 10:05 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a reply to A humble TSE dev Cancel reply

Blog at WordPress.com.