Friday, August 31, 2012

Python development with Sublime Text 2 tips and tricks

For quite some time I have used Eclipse + PyDev for Python development. Pydev makes definitively Eclipse a good IDE for Python, it has a great debugger and build system, the autocompletion works well, it is mature and read out of the box.

I decided to change searching for a more lightweight IDE and because I became simply addicted to the huge editing capabilities of Sublime Text 2, like selection management or editing several regions at the same time. The outline on the right is simply great... basically I find sublime extremely productive.

Now besides the (relatively not) interesting reasons why I started using sublime for python development, the goal of this post is to explain what and how to install to ease python development providing sublime things like python autocompletion, lint support, pdb support, etc, etc....

Python developmnt with Sublime Text alone

The first nice surprise with Sublime is that it is already a somewhat reasonable python IDE (without autocompletion). We already have syntax highlighting (quite common indeed), and a flexible build system.

The build system (discussed in bigger detail later) allows to un simple python scripts with no configuration at all just choosing python build system from Tools menu and build. It is easy to configure a your proper build system as discussed later on.

One of the most interesting out of the box features related with python is the presence of code templates as Sublime commands, thus reachable from the menu with cmd+shift+P.
By the way, the amount of languages Sublime provides snippets for is huge, just check Preferences - Browse Packages menu.

Now let's see what can we install as packages to provide python autocompletion, debugger support etc. Just to start with, a good way to install packages is through Sublime Package Control (downloadable here: http://wbond.net/sublime_packages/package_control) This provides a full package manager and helps discoverin, installing and updating packages.

Python autocompletion

For python autocompletion I installed a Sublime adaptation of Rope library: SublimeRope (https://github.com/JulianEberius/SublimeRope).

In terms of autocompletion, this package plugs into default Sublime default completion system adding python symbols at the default ones.

The easiest way to install it is through package control, Shift-Cmd-P,  choose Package Control: Install Package command and select SublimeRope. The installation won't require Sublime Text to be restarted.

Once Rope installed, each python file will profit of autocompletion. As it is at this stage, autocompletion will search for symbols declared in the file you are editing, all default python symbols and all installed modules and python symbols accessible from PYTHONPATH.

Still Rope won't be able to find symbols declared in separate files of the same project. To fix this issue, a Rope project needs to be created explicitly. This can be done through Rope: New Project command from the command palette.

Refactor and source management

Every reasonable IDE provides some kind of support for refactoring and some abilities to navigate through the sources of a project. SublimeRope provides these capabilities as well.

Once you install SublimeRope you have three commands for source navigation:
  • Rope: Go  to definition. Which opens the definition of the symbol under the cursor
  • Rope: Show Documentaiton. Shows python documentation for the symbol under the cursor:
  • Rope: Jump to Global.
Show Documentation output
SublimeRope provides an access through Sublime command palette to most of refactoring provided by Rope library like method extraction, inlining or extraction of variables, etc.

These functionalities come without a dedicated set of key bindings. These can be easily added modifying Sublime keybindings through Preferences - User Keybindings menu.
For example this maps "show documentation" on cmd + R +D:
 //Rope key bindings
    { "keys": ["super+r", "super+d"], "command": "python_get_documentation", "context":
        [
            { "key": "selector", "operator": "equal", "operand": "source.python" }
        ]
    }


Python lint

There are several python linters, for pyflakes and pep8 there is a Sublime package (SublimeLint) that highlights potential issues in your code while editing. It can be installed from Package manager while source and documentation can be found here: https://github.com/SublimeLinter/SublimeLinter.
Issues are highlighted directly in the code while a description is present on the status bar.

Sometimes for (more or less) good reasons we want to disable some of linter checks (personally I found the limitation to 86 characters to max line width a bit too strict). This can be done with sublimeLint by editing Sublimelinter.sublime-settings (Preferences - Package Settings - SublimeLinter - Settings - User menu). Pay attention always to modify user settings and not default ones which will be overwritten at every update.

Here are my settings:
{
    //I don't want to be bothered by issues on spaces around oeprators
    "pep8_ignore":
    [
        "E251","E501","W191","E303"
    ]
}

Debugging

What I miss most about Eclipse + PyDev is the great Eclipse debugger. Which is perfectly integrated with pdb  through PyDev.

Still pdb is not that hard to use alone, what is needed is a proper integration in Sublime Text. I found a good one in Sublime REPL (https://github.com/wuub/SublimeREPL) which allows running a lot of interactive interpreters into a Sublime Text buffer.

These interpreters include pdb (a command is ready out of the box to run the current python file with pdb - REPL: PDB current file command):
At this point you are running a classical pdb session.

A couple of words about build systems

For simple scripts, out of the box build systems are great as it is the scrupt ran through REPL. What happens instead when we want to provide input parameters to our script or change environemnt variables?

For running the scripts Subilme Text allows you to configure your own build system in a very flexible way, documented here: http://sublime-text-unofficial-documentation.readthedocs.org/en/latest/reference/build_systems.html.

I find useful adding the root of the project to PYTHONPATH in order to allow test scripts access the modules of my project no matter if they are in different directories and they are not yet installed in my python distribution.

To do so I created my build systems inside my project configuration instead of making them available to the whole IDE: in PROJECTNAME.sublime-project:

"build_systems":
    [
        {
            "cmd": ["python","${file}","command1"],
            "env": {"PYTHONPATH":"/Users/pyppo/Documents/workspacepython/pyCmdLiner/"},
            "name": "pythonProjectTestBase"
        }
    ]

creates a build system called pythonProjectTestBase that invokes python on the currently open file, passing a command argument (command1) and adding project root directory to PYTHONPATH before running the project.

Things are a bit more complex when debugging with REPL. I am not aware as of today of a project specific way to provide REPL configuration.

As a workaround I provided my PYTHONPATH as REPL user configuration in sublimeREPL.sublime-settings:

{
    "default_extend_env": {"PYTHONPATH":"/Users/pyppo/Documents/workspacepython/pyCmdLiner/"}
}

This is accessible from Preferences - Package settings - SublimeREPL - Settings User menu.

For additional flexibility it is always possible to modify SublimeREPL command definition or to create additional ones. This configuration is accessible from Preferences - Browse Packages - SublimeREPL menu, under python directory:
  • Default.sublime-commands lists the commands and points to the definition file
  • Main.sublime-menu contains commands definition.
Run python script with pdb is defined by default in this way:
{"command": "repl_open",
                     "caption": "Python - PDB current file",
                     "id": "repl_python_pdb",
                     "mnemonic": "d",
                     "args": {
                        "type": "subprocess",
                        "encoding": "utf8",
                        "cmd": ["python", "-i", "-u", "-m", "pdb", "$file_basename"],
                        "cwd": "$file_path",
                        "syntax": "Packages/Python/Python.tmLanguage",
                        "external_id": "python"
                        }
                    }

I never tried to provide a user based command configuration for REPL instead of tweaking the default one, so I cannot say if it is possible or not.

Conclusion

Here are my 2 cents on how to set up a python development environment with Sublime Text. I am pretty sure there are plenty of other useful packages to be installed to have a better IDE, this is just a starting point .....