Skip to content

Latest commit

 

History

History
333 lines (251 loc) · 11.5 KB

emacs-python.org

File metadata and controls

333 lines (251 loc) · 11.5 KB

Emacs Settings for Python

For learning Python, read the basic tutorial. If you already know Python, perhaps check out some best practices. I initially stole my Emacs setup from Gabriel Elanaro’s git project, but now it mostly revolves around the Elpy Project.

Virtual Environments

Development for Python should be isolated in virtual environments, where Project A doesn’t need to change the dependencies for Project B. First, some background (feel free to skip this section).

First, we used virtualenv, which created a venv in every project’s directory. However, after using it a while…

you might end up with a lot of virtual environments littered across your system, and its possible you’ll forget their names or where they were placed.

So, we moved to the virtualenvwrapper project, as it…

provides a set of commands which makes working with virtual environments much more pleasant. It also places all your virtual environments in one place.

Note: To use this, you’d call, mkvirtualenv venv to create an environment, and work on a virtual environment, with workon venv.

In my day job, project often have a different version of Python (like 2.7.5 for Project B, and 2.6.6 for some legacy Project A). To solve this, I now use pyenv for all my Pythonic virtualization needs.

Installation

Begin with installing these packages on a Mac:

brew install pyenv pyenv-virtualenv pyenv-virtualwrapper

Or, if on Linux, let’s do it neckbeard-style:

git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

Next, use pip to install virtualenv globally.

sudo pip install virtualenv

Finally, change the .profile to add these to the basic shell:

export PYENV_ROOT="${HOME}/.pyenv"

if [ -d "${PYENV_ROOT}" ]; then
    export PATH="${PYENV_ROOT}/bin:${PATH}"
    eval "$(pyenv init -)"
fi

Each project will have its own collection of pip libraries, called an environment. Each environment, however, can have a particular version of Python…

Installing a Python Version

For a given project, we first install a particular Python version for it using the pyenv command:

pyenv install 2.6.6

What versions are installed? Run:

pyenv versions

Creating a Python Environment

For a new project, create a new environment, and optionally specify the version of Python you want to use:

pyenv global 3.4.2       # Step 1. Set the version
pyenv virtualenv foobar  # Step 2. Create environment
pyenv activate foobar    # STep 3. Use environment

Now commands like pip will isolate the module for this particular environment.

Note: To get all the lovelies found in this configuration file, run the following for each new virtual environment:

pip install --upgrade jedi flake8 pep8 importmagic autopep8 yapf nose

Using a Python Environment

To use an environment you previously created, run:

pyenv activate foobar

And deactivate it with:

pyenv deactivate

Want to set up a default version that isn’t the one that came with your computer:

pyenv global 2.7.5

Or set up a default environment:

pyenv global foobar

Typically, you will have an environment tied to a particular project, and since each project has its own directory, tie a directory to a virtual environment:

pyenv local 2.6.6@foobar

While, the Elpy Project deals with the virtualenvwrapper (using the pyvenv-workon function), we need to install pyenv-mode for Emacs:

(use-package pyenv-mode
  :ensure t
  :config
    (defun projectile-pyenv-mode-set ()
      "Set pyenv version matching project name."
      (let ((project (projectile-project-name)))
        (if (member project (pyenv-mode-versions))
            (pyenv-mode-set project)
          (pyenv-mode-unset))))

    (add-hook 'projectile-switch-project-hook 'projectile-pyenv-mode-set)
    (add-hook 'python-mode-hook 'pyenv-mode))

To automatically use the correct virtual environment (based on the contents of a projects, .python-version file, use pyenv-mode-auto:

(use-package pyenv-mode-auto
   :ensure t)

Note: Since Elpy runs Python in the home directory, it doesn’t deal with any local environment, so only use pyenv global.

Basics

WSGI files are just Python files in disguise, so tell them to use the Python environment.

Careful with the tabs, my friend.

(use-package python
  :mode ("\\.py\\'" . python-mode)
        ("\\.wsgi$" . python-mode)
  :interpreter ("python" . python-mode)

  :init
  (setq-default indent-tabs-mode nil)

  :config
  (setq python-indent-offset 4)
  (add-hook 'python-mode-hook 'smartparens-mode)
  (add-hook 'python-mode-hook 'color-identifiers-mode))

Lint

Standardized on the pep8 project, just make sure you’ve install the Flake8 library.

pip install --upgrade flake8

Flycheck automatically supports Python with Flake8. To use it, set the virtual environment, and the errors should appear automatically.

Unit Testing

Unit test and code coverage tool for Python now comes to Emacs with Python Nose.

The ELPY project automatically adds support for testing.

Jedi

For auto-completion (and refactoring) for Python, you get two choices: Rope or Jedi. Rope, while claiming more features, seems to crash and not work. Besides, Jedi is a better name. See this article, and maybe these instructions.

Elpy will automatically use either, however, I want to hook Jedi to Company mode:

(use-package jedi
  :ensure t
  :init
  (add-to-list 'company-backends 'company-jedi)
  :config
  (use-package company-jedi
    :ensure t
    :init
    (add-hook 'python-mode-hook (lambda () (add-to-list 'company-backends 'company-jedi)))
    (setq company-jedi-python-bin "python")))

Anaconda

While ELPY tries to be the all-in-one Python IDE, Anaconda is thinner wrapper around Jedi, which seems to work a bit better for me and the fact that I need to use pyenv (instead of pyvenv).

(use-package anaconda-mode
  :ensure t
  :init (add-hook 'python-mode-hook 'anaconda-mode)
        (add-hook 'python-mode-hook 'anaconda-eldoc-mode)
  :config (use-package company-anaconda
            :ensure t
            :init (add-hook 'python-mode-hook 'anaconda-mode)
            (eval-after-load "company"
              '(add-to-list 'company-backends '(company-anaconda :with company-capf)))))

Oh, make sure we have Company-Anaconda configured too.

ELPY

According to the ELPY Web Site, grab the latest version:

(add-to-list 'package-archives
           '("elpy" . "http://jorgenschaefer.github.io/packages/"))

Then call:

  • M-x package-initialize
  • M-x package-installelpy

Once this has been installed, we can enable it:

(use-package elpy
  :ensure t
  :commands elpy-enable
  :init (with-eval-after-load 'python (elpy-enable))

  :config
  (electric-indent-local-mode -1)
  (delete 'elpy-module-highlight-indentation elpy-modules)
  (delete 'elpy-module-flymake elpy-modules)

  (defun ha/elpy-goto-definition ()
    (interactive)
    (condition-case err
        (elpy-goto-definition)
      ('error (xref-find-definitions (symbol-name (symbol-at-point))))))

  :bind (:map elpy-mode-map ([remap elpy-goto-definition] .
                             ha/elpy-goto-definition)))

Since ELPY is not a simple mode, but a collection of smaller modes stitched together, we have to call with-eval-after-load (see this discussion)

As the final bit of customization, first activate a virtual environment with M-x pyvenv-workon, and then run: M-x elpy-config

See the documentation for details, but:

C-c C-f
Find Python file
C-c C-s
Grep for a Python symbol
C-c C-z
Switch to the Python Shell
C-c C-c
Send region to the Python interpreter

Note: The elpy-goto-definition is nice and all if you have a full project with a running interpreter, but I want to use tags as a fallback. However, since the function throws an error, I can’t simply advice the function, like:

(advice-add 'elpy-goto-definition :after-until 'find-tag)

Instead, I had to create a function wrapper.

Technical Artifacts

Make sure that we can simply require this library.

(provide 'init-python)

Before you can build this on a new system, make sure that you put the cursor over any of these properties, and hit: C-c C-c