Setting up editors

Sublime

The “supported” editor of choice for working on this project is Sublime Text 2 (sublime), though these instructions will likely also work for Sublime Text 3. Of course you’re free to use whichever editor helps you be the most productive, but the preponderance of Sublime users on the team make it the most useful target for our development environment setup documentation.

Getting Started

Get sublime

To begin, sublime must be installed. It is distributed via a tarball from the sublime download page. This tarball can be extracted anywhere. A likely place is in your home folder. Once extracted, run the sublime_text executable in the new directory to start the editor.

Configure sublime for Python

By default, sublime will attempt to autodetect indentation. When this autodetection fails, it will fall back to using 4-space tab stops, but using tabs instead of spaces. To easily address this, open any .py in the editor, and then select Preferences > Settings - More > Syntax Specific - User from the menu. This should open up Python.sublime-settings. In this file, enter the following options and save:

{
    "detect_indentation": false,
    "rulers": [100],
    "tab_size": 4,
    "translate_tabs_to_spaces": true,
    "use_tab_stops": true
}

This will force python files to match our code style guidelines, which use spaces instead of tabs with an indentation of 4 spaces.

The rulers option will also draw a vertical line at 100 characters as a visual aid to keep lines from getting too long. Additional integer values can be added to the rulers list; it might be useful to also have a rule at 80 columns as a “soft limit”, for example.

Package Control

Once sublime is up and running, we’ll need to install some package management, which we’ll be using hereafter to bring in sublime extensions. Follow the installation instructions. Be sure to follow the instructions for Sublime Text 2, unless you’re beta testing Sublime Text 3.

Note

When installing packages, it is sometimes necessary to restart sublime for the installed packages to initialize. For simplicity, it is probably easiest to restart sublime after installing any package. Restarting sublime after changing configuration files should not be necessary.

SublimeCodeIntel

Install the SublimeCodeIntel package. Select Preferences > Package Control from the program menu, then choose “Install Package”. Enter “SublimeCodeIntel”. Once installed, SublimeCodeIntel will provide autocompletion for imports and function/method calls.

SublimeCodeIntel will autodetect python names from project directories (visible in the sidebar) for autocompletion, but it won’t detect builtins or installed libraries. To enable this, SublimeCodeIntel needs to be given a hint. It looks for config files in .codeintel directories inside of project directories, so we’ll be putting the hint there. The cfme_tests directory is the perfect place for the .codeintel directory, so ensure that the cfme_tests directory has been added to your current project. If not, Project > Add Folder to Project..., and select your cfme_tests directory.

Using your tool of choice (for example, a shell or sublime itself), make the .codeintel directory under cfme_tests. Inside that directory, create and edit the file config (cfme_tests/.codeintel/config). Like most sublime configuration files, the content of this file is a python dictionary. It looks very similar to JSON, which is used in most sublime configuration files, so be mindful of the different syntax.

Insert the following:

{
    "Python":
    {
        "codeintel_scan_files_in_project": True,
        "python": "/path/to/virtualenv/bin/python",
        "pythonExtraPaths":
        [
            "/path/to/virtualenv/lib/python2.7/site-packages"
        ]
    }
}

Remember to change the /path/to/virtualenv strings to be the actual path to your virtualenv. python should point to the virtualenv’s python interpreter.

Relative paths can be used here, and will be relative to the project folder (in this case, cfme_tests), not the location of this config file. So, if cfme_tests is in the same directory as the virtualenv’s bin and lib directory, The paths for python and pythonExtraPaths could start with ../bin and ../lib, respectively.

Flake8 Lint

Using Package Control, install the “Python Flake8 Lint” package. To apply our specific style exceptions to this package, edit the configuration. Via the menu, choose Preferences > Package Settings > Python Flake8 Lint > Settings - User. In the settings file that opens, enter our exceptions:

{
      "pep8_max_line_length": 100,
      "ignore": ["E128"]
}

Flake8 lint will pop up every time you save a file, and does an excellent job of keeping you linted while you code.

Trailing Spaces

Using Package Control, install the “Trailing Spaces” plugin. This highlights trailing spaces so you can clean them up before flake8 sees them.

Sublime Text 3

Sublime Text 3 is currently in beta, but it is perfectly usable for python development. I will show you my setup here (mfalesni). Prerequisities are the same as for ST2 (Package Control).

emacs

So far the best emacs setup I’ve (jweiss) found is iPython notebook, combined with the ein emacs package (emacs iPython notebook).

Installing iPython and its Emacs client

iPython

See the install docs.

ein

Emacs iPython Notebook is the emacs client for iPython.

The official ein package does not work with the latest ipython. I built a package from the fork of ein that does work. You can get the package from the internal repository listed below. You should also add the Melpa repository.

(add-to-list 'package-archives
  '("melpa" . "http://melpa.milkbox.net/packages/") t)
(add-to-list 'package-archives
  '("jweiss" . "http://qeblade5.rhq.lab.eng.bos/isos/emacs-package-archive/") t)

You can then run M-x package-install, ein in emacs to install ein.

Then in a shell somewhere, you can start up iPython notebook process. This is the python process that will intepret all the code you will be sending it.

$ source ~/my-virtual-env/bin/activate
$ cd ~/my-project
$ ipython notebook

Then in emacs, run M-x ein:notebooklist-open. It will prompt you for a port (default 8888). This will bring up the EIN environment, where you can evaluate python snippets (and edit them and evaluate them again). You can also save the notebook to use your snippets again later. The outputs are also saved.

Starting iPython from within Emacs

I wrote a little bit of elisp to start a iPython notebook process for you from within emacs. It’s easier than having to type shell commands every time. It requires the magit package, which I highly recommend (it is a git client for emacs).

(autoload 'magit-get-top-dir "magit" nil t)

(defun magit-project-dir ()
  (magit-get-top-dir (file-name-directory (or (buffer-file-name) default-directory))))

(defun start-ipython-current-project (virtualenv-dir)
  (interactive
   (let ((d (read-directory-name "VirtualEnv dir: " "~/.virtualenvs/" nil t)))
     (list d)))
  (save-excursion
    (let ((buf (get-buffer-create
                (generate-new-buffer-name (file-name-nondirectory
                                           (directory-file-name (file-name-directory (magit-project-dir))))))))
      (shell buf)
      (process-send-string buf (format ". %s/bin/activate\n" virtualenv-dir))
      (process-send-string buf (format "cd %s;ipython notebook\n" (magit-project-dir))))))

To use the above snippet,

  • Go to any buffer that’s visiting any file in your project (or any buffer whose pwd is in your project)
  • M-x start-ipython-current-project
  • At the prompt, input the directory where your virtualenv lives

It will start ipython in emacs’ shell buffer.

Autosave Notebooks

Unlike the iPython web interface, ein does not autosave notebooks by default. Here is a snippet that will enable autosave (notebooks are saved every time you execute a cell)

;; ein save worksheet after running cell
(eval-after-load 'ein-multilang
  '(defadvice ein:cell-execute (after ein:save-worksheet-after-execute activate)
     (ein:notebook-save-notebook-command)))

Flake8 Lint

Flycheck is recommended because it highlights the column where the problem occurs instead of just the line.

Run M-x package-install, flycheck, and see the Flycheck homepage.

You can use the global mode as described on the homepage, or to just enable flymake for python files

(autoload 'flycheck "flycheck-mode")
(eval-after-load 'python
  '(add-hook 'python-mode-hook 'flycheck-mode))

PyCharm

PyCharm is a very powerful python IDE. However, it comes with a price - it’s also quite resource-heavy. It has a community edition that is open-source since 2013. You can get it here. Some of its best out-of-the-box features are:

  • Code inspections with PEP8 support
  • Git integration with diff preview and other tools
  • Easy per-project configuration including code style
  • Symbol navigation and code completion
  • Support for html, json, xml and yaml
  • Powerful degugging tool
  • Many others

Following examples and settings were tested on PyCharm Community Edition 2017.2.3

Useful plugins

PyCharm has a library of many useful plugins. To install them, go to File -> Settings -> Plugins -> Install JetBrains plugin.

Some plugins you might find useful are:

BashSupport:Supports syntax highlighting, rename refactoring, inspections and many more.
IdeaVim:Very good Vim emulation. If you have been using Vim for some time, you will feel at home.

Code style compliance

You can set up PyCharm in such a way that it takes care about code style for you. You can go very much in-depth with this, but here are the basics of whay you can do:

100 characters maximum line length:
 Set File -> Settings -> Editor -> Code Style -> Right margin (columns) to 100
PEP 8 revisions:
 Add E128 to File -> Settigns -> Editor -> Inspections -> Python -> PEP 8 coding style violation -> Ignore errors
Problems with pytest fixtures:
 PyCharm is unfortunately ignorant of pytest inner workings. It means that it will mark fixtures passed to test methods as ununsed parameters. In order to get rid of those warnings, you can disable following inspection: File -> Settigns -> Editor -> Inspections -> Python -> Unused local If a fixture is specified in the same module as your test method, you will get other warning when using it. Disable File -> Settigns -> Editor -> Inspections -> Python -> Shadowing names from outer scopes.

Feel free to add any other tips & tricks you come up with.