elpy-goto-definition not working for simple case

Created on 11 Aug 2016  路  7Comments  路  Source: jorgenschaefer/elpy

I'm new to python & elpy, and I'm trying to get a basic dev setup going.

I have a simple multi-file project set up:

/Users/stebro/automation/tests/alpha.py

class BailOut(Exception):
    pass


def validate(queens):
    left = right = col = queens[-1]
    for r in reversed(queens[:-1]):
        left, right = left-1, right+1
        if r in (left, col, right):
            raise BailOut

/Users/stebro/automation/tests/beta.py

from tests.alpha import validate
from tests.alpha import BailOut

BOARD_SIZE = 8


def add_queen(queens):
    for i in range(BOARD_SIZE):
        test_queens = queens + [i]
        try:
            validate(test_queens)
            if len(test_queens) == BOARD_SIZE:
                return test_queens
            else:
                return add_queen(test_queens)
        except BailOut:
            pass
    raise BailOut

/Users/stebro/automation/tests/app/sample.py:

from tests.beta import add_queen

queens = add_queen([])
print(queens)
print("\n".join(". "*q + "Q " + ". "*(BOARD_SIZE-q-1) for q in queens))

If I open sample.py and M-. on add_queen, I get "No definition found". If I M-x eval-expression for (elpy-project-root) in sample.py, I get "/Users/stebro/automation".

In the Python Fast buffer, I see:

... 
';'.join(__COMPLETER_all_completions('''.join('''))
... ... ... ... ... ... ... ... ... ... ... ... ... >>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named tests.beta
>>> >>> ''
>>> 

I believe I've installed elpy correctly and configured it. In my init.el:

(setq python-python-command "/usr/local/bin/python3.5")
(setq elpy-rpc-python-command "/usr/local/bin/python3.5")
(require 'python-mode)
(require 'projectile)
(require 'python)

(elpy-enable)

Output of elpy-config:

Elpy Configuration

Virtualenv........: None
RPC Python........: 3.5.1 (/usr/local/bin/python3.5)
Interactive Python: python (/usr/bin/python)
Emacs.............: 24.5.1
Elpy..............: 1.12.0
Jedi..............: 0.9.0
Rope..............: 0.10.3
Importmagic.......: 0.1.7
Autopep8..........: 1.2.4
Yapf..............: 0.11.0
Syntax checker....: flake8 (/usr/local/bin/flake8)

You have not activated a virtual env. While Elpy supports this, it is
often a good idea to work inside a virtual env. You can use M-x
pyvenv-activate or M-x pyvenv-workon to activate a virtual env.

The directory ~/.local/bin/ is not in your PATH. As there is no active
virtualenv, installing Python packages locally will place executables
in that directory, so Emacs won't find them. If you are missing some
commands, do add this directory to your PATH.

Options

`Raised' text indicates buttons; type RET or click mouse-1 on a button
to invoke its action.  Invoke [+] to expand a group, and [-] to
collapse an expanded group.  Invoke the [Group], [Face], and [Option]
buttons below to edit that item in another window.

[+]-- Group Elpy
[+]-- Group Python
[+]-- Group Virtual Environments (Pyvenv)
[+]-- Group Completion (Company)
[+]-- Group Call Signatures (ElDoc)
[+]-- Group Inline Errors (Flymake)
[+]-- Group Snippets (YASnippet)
[+]-- Group Directory Grep (rgrep)
[+]-- Group Search as You Type (ido)

Question

Most helpful comment

@sbroberg Jedi works like a charm with go-to-definition. You can try setting backend to jedi.

(setq elpy-rpc-backend "jedi")

All 7 comments

Some more information: I'm running on OSX and it appears this may be related to problems regarding how environment variables get passed into emacs when it is launched as an OSX application (short answer: they aren't, but the exec-path-from-shell is supposed to take care of most of these problems).

I see that sys.path does not include "/Users/stebro/automation" when python is invoked from within emacs, but it is when invoked from my Terminal shell.

Given that elpy is aware of the project root (from the (elpy-project-root) output above), shouldn't this project root path be included in the sys.path that is seen by the spawned python process? If not, is there some configuration I should be doing to make it so?

Yet more information:

Using a feature of exec-path-from-shell, I was able to get elpy working (with the proper path in the sys.path variable), by doing:

(exec-path-from-shell-copy-env "PYTHONPATH")

where PYTHONPATH is set to point to /Users/stebro/automation. This feels like a workaround, however - I don't want to set PYTHONPATH every time I want to start working on a different python project.

One more issue:

With the sys.path set correctly, elpy-goto-definition works for symbols defined in other files, but it doesn't appear to be working to navigate to a function defined within the same file.

For example, doing a M-. on "create_account" in the test_foo function below gives "No definition found"

import json
import time

from tests.tests_new.ui.base_test import BaseTest


class TestCreateAccount(BaseTest):

    @classmethod
    def setUpClass(cls):
        '''
        # setup toolset
        '''
        BaseTest.setUpClass()

    def create_account(self, firstname, lastname, email, password):
        '''
        Create account given firstname,lastname,email,password
        :param firstname: Firstname field of create account
        :param lastname: Lastname field of create account
        :param email: email field of create account
        :param password:  password field of create account
        '''
        self.firstname.send_keys(firstname)
        self.lastname.send_keys(lastname)
        self.emailid.send_keys(email)
        self.password.send_keys(password)
        self.remote.find_element_by_id("createAccountButton").click()

    def test_foo(self):
        """Ensure that creating account with existing email and different password would give out an error

        self.create_account('testuser', 'backup',
                            '[email protected]', 'invalidpassword')
        assert self.remote.find_element_by_id(
            "spanCreateAccountError").text == "Email is already in use"

Hello, and thanks for the report!

Given that elpy is aware of the project root (from the (elpy-project-root) output above), shouldn't this project root path be included in the sys.path that is seen by the spawned python process?

Tricky. The project root is not always the right path to add to sys.path. It's difficult to find a default configuration that works for everyone. I usually just make sure that my virtualenv includes the right directories (using add2virtualenv from virtualenvwrapper). Elpy's pyvenv mode sets environment variables when switching virtualenvs.

If (exec-path-from-shell-copy-env "PYTHONPATH") works, how do you set PYTHONPATH in your shell so that it works there?

Right now I'm just setting PYTHONPATH in my .bashrc / .bash_profile, which is obviously not a good long term solution (but I'm only working on one python project, so it gets me started).

I think the long term solution would be to put a .dir-locals.el in the directory of my project that corresponds to PYTHONPATH (in this case, the root of the automation repository). Then I can use this trick to set the variable "my-project-path" to be the directory where the .dir-locals.el file lives:

.dir-locals.el:

((nil . ((eval . (set (make-local-variable 'my-project-path)
                      (file-name-directory
                       (let ((d (dir-locals-find-file ".")))
                         (if (stringp d) d (car d))))))
)))

At this point, I'd want to get "my-project-path" into sys.path of my python environment. Is there a good way of doing this? I know nothing about virtual environments, but the name sounds like that's what I want. Ideally, I'd like to put logic into that .dir-locals.el that creates the virtualenv for that project.

Any ideas?

@sbroberg Jedi works like a charm with go-to-definition. You can try setting backend to jedi.

(setq elpy-rpc-backend "jedi")

Thank, @ChillarAnand - that seems to have fixed the problem!

Was this page helpful?
0 / 5 - 0 ratings