porterjamesj/virtualenvwrapper.el

mkvirtualenv hook does not work properly

Closed this issue · 14 comments

Wanted to check with you if you think this should work with python installed and configured using pyenv... and the pyenv.el mode, or are there issues to be aware of.

Pyenv stores virtualenvs under ~/.pyenv/versions/ and also provides a mechanism to automate activation of the virtualenvironment using a file called .python-version, in the root directory of the project.

The pyenv.el mode sets PYENV_ROOT and PYENV_VERSION inside emacs.

Hmmm I've never used pyenv so I'm not sure, I usually manage multiple python versions by installing them with a system package manager and then using the -p option to virtualenv.

I don't think there will be any conflict between this and pyenv by itself, but it definitely won't work with pyenv.el—they both set python-shell-virtualenv-path, and will clobber each other.

I'm curious what your workflow for using both pyenv and virtualenv is like? I'd like to interoperate smoothly with other tools in the community, but since I don't use pyenv I'm not sure what the best way to do that is.

cc @proofit404, since you might have insight here also.

I've compeletely removed pyenv.el and installed virtualenvwrapper.el.

Making sure I don't have python-mode and its hooks active just yet, I've created a new venv using venv-mkvirtualenv, with this setup in my init.el:

(add-hook 'venv-postmkvirtualenv-hook
          (lambda () (shell-command "pip install rope ropemacs pep8 flake8")))

These are the messages I can see in emacs, which indicate it's trying to reinstall these pip modules in the global venv, or in fact, if one is already active, in that one.

New python executable in /home/uri/.pyenv/versions/flask-test/bin/python
Installing setuptools, pip...done.
Requirement already satisfied (use --upgrade to upgrade): rope in ./.pyenv/versions/2.7.8/lib/python2.7/site-packages
Requirement already satisfied (use --upgrade to upgrade): ropemacs in ./.pyenv/versions/2.7.8/lib/python2.7/site-packages
Requirement already satisfied (use --upgrade to upgrade): pep8 in ./.pyenv/versions/2.7.8/lib/python2.7/site-packages
Requirement already satisfied (use --upgrade to upgrade): flake8 in ./.pyenv/versions/2.7.8/lib/python2.7/site-packages
Requirement already satisfied (use --upgrade to upgrade): ropemode>=0.2 in ./.pyenv/versions/2.7.8/lib/python2.7/site-packages (from ropemacs)
Cleaning up...
venv-mkvirtualenv: Invalid function: venv-with-virtualenv

Though a new venv was created, only w/o the modules pip tried to install.

 mbp in ~/labs/flask-user
○ → pip list
pip (1.5.6)
setuptools (3.6)
virtualenv (1.11.6)
wsgiref (0.1.2)

BTW, virtualenv is installed in the global pyenv environment.

 mbp in ~
○ → pyenv global
2.7.8
 mbp in ~
○ → pyenv local
pyenv: no local version configured for this directory
mbp in ~
○ → pip list
... [redacted]
virtualenv (1.11.6)
websocket-client (0.11.0)
wsgiref (0.1.2)

This is my init.el (python only):

(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\SConscript\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\SConstruct\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\wscript\\'" . python-mode))

(setq
 python-shell-interpreter-args ""
 python-shell-prompt-regexp "In \\[[0-9]+\\]: "
 python-shell-prompt-output-regexp "Out\\[[0-9]+\\]: "
 python-shell-completion-setup-code "from IPython.core.completerlib import module_completion"
 python-shell-completion-module-string-code "';'.join(module_completion('''%s'''))\n"
 python-shell-completion-string-code "';'.join(get_ipython().Completer.all_completions('''%s'''))\n")

(setq py-autopep8-options '("--max-line-length=100"))
(add-hook 'before-save-hook 'py-autopep8-before-save)

(defun proper-python-electric-indent ()
  "The default electric-indent behavior for Python is
stupid. This does the right thing."
  (interactive)
  (newline)
  (indent-according-to-mode))

(require 'virtualenvwrapper)
(venv-initialize-interactive-shells) 
(venv-initialize-eshell)
(setq venv-location (concat (getenv "PYENV_ROOT") "/versions"))
(setq eshell-prompt-function
      (lambda ()
        (concat venv-current-name " $ ")))

(defun python-hook ()
  (require 'pymacs)
  (setq python-indent-offset 4)
  (show-paren-mode 1)
  (electric-indent-mode -1)
  (local-set-key (kbd "RET") 'proper-python-electric-indent)

;  (global-pyenv-mode)
;  (pyenv-use-corresponding)
;  (setq pyenv-show-active-python-in-modeline t)

  (hack-local-variables)
  (when (boundp 'project-venv-name)
    (venv-workon project-venv-name))

  (pymacs-load "ropemacs" "rope-")
  (setq ropemacs-enable-autoimport t)
  )

(add-hook 'python-mode-hook 'python-hook)

(add-hook 'venv-postmkvirtualenv-hook
          (lambda () (shell-command "pip install rope ropemacs pep8 flake8")))


BTW, have you seen this API https://github.com/tkf/emacs-python-environment ? It might have the same issue with pyenv, but it's an API, not a standalone plugin.

hmmm this definitely looks like a bug. I'll try to repo and dig in when I have the time (probably tomorrow). thanks for reporting!

@usharf I've just pushed a change that I believe should fix this, can you try with the latest master and confirm that it works for you?

Thanks, I'll have a look and let you know.

On Wed, Sep 10, 2014 at 6:56 AM, James J Porter notifications@github.com
wrote:

@usharf https://github.com/usharf I've just pushed a change that I
believe should fix this, can you try with the latest master and confirm
that it works for you?


Reply to this email directly or view it on GitHub
#14 (comment)
.

U.

nvm, @kljohann reports this is still borked on master.

Clearly I don't really understand what the problem is here yet, will keep digging.

Hello. I was offline about two weeks, sorry.

pyenv is a tool for manage python versions, not virtualenvs. This allow you to lock python version for certain directory. Project root for example. But this doesn't solve package versions conflicts, so you still need virtualenv. There are two possible ways to solve this.

You can use pyenv-virtualenv or pyenv-virtualenvwrapper. First tool create virtualenv from specified pyenv's python version. You can use it as any other python installation in pyenv. For example pyenv shell foo-venv. This approach 100% compatible with pyenv-mode. I use it personally every day.

The second tool activate virtualenvwrapper for specific pyenv's python. I think you can make you package compatible with this pyenv plugin. There no need to use pyenv-mode for this. But user must setup PYENV_VERSION environment variable to change current python installation. Or make it local for project.

Hope this help.

@usharf, @kljohann: I believe latest master finally has this fixed now. Would one of you mind confirming that it works for you?

I've disabled elpy (which uses it's own pyvenv module, written by the same developer I think) and have this setup now:

(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\SConscript\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\SConstruct\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\wscript\\'" . python-mode))

(exec-path-from-shell-copy-env "WORKON_HOME")
;(exec-path-from-shell-copy-env "PYENV_VIRTUALENVWRAPPER_PREFER_PYVENV")
;(require 'pyenv-mode)

;; (when (require 'elpy nil t)
;;   (elpy-enable)
;;   (elpy-use-ipython)
;;                  ; (setq elpy-rpc-backend "jedi")
;;                  ;(elpy-clean-modeline)
;;   )

(when (require 'virtualenvwrapper)
  (venv-initialize-interactive-shells) 
  (venv-initialize-eshell)
  (setq venv-location (getenv "WORKON_HOME"))
)



(when (require 'flycheck nil t)
  (remove-hook 'elpy-modules 'elpy-module-flymake)
  (add-hook 'elpy-mode-hook 'flycheck-mode)
  )


(when (require 'py-autopep8)
  (setq py-autopep8-options '("--max-line-length=100"))
  (add-hook 'before-save-hook 'py-autopep8-before-save))

(defun python-hook ()
  (setq python-indent-offset 4)
  (show-paren-mode 1)
                    ; (electric-indent-local-mode -1)
                    ; (local-set-key (kbd "RET") 'new-and-indent)
  )

(add-hook 'python-mode-hook 'python-hook)

Virtualenvs seem to be picked up properly (with pyenv, as before) and I can use workon in eshell as well.

Runin venv-mkvirtualenv fails though with the message invalid virtualenv specified, also when run in eshell.

PS sorry about not being clear about pyenv, which is indeed used with the virtualenv plugin.

@usharf going to go ahead and move to a new issue: #15

@porterjamesj That seemed to fix the byte-compilation issue for me, thanks!
For the record those are the remaining warnings:

In venv-deactivate:
virtualenvwrapper.el:218:9:Warning: assignment to free variable
    `python-shell-virtualenv-path'
virtualenvwrapper.el:226:9:Warning: assignment to free variable
    `eshell-path-env'

In venv-workon:
virtualenvwrapper.el:257:9:Warning: assignment to free variable
    `python-shell-virtualenv-path'
virtualenvwrapper.el:263:9:Warning: assignment to free variable
    `eshell-path-env'

In venv-rmvirtualenv:
virtualenvwrapper.el:324:7:Warning: `mapcar' called for effect; use `mapc' or
    `dolist' instead

In venv-initialize-eshell:
virtualenvwrapper.el:478:9:Warning: assignment to free variable
    `eshell-modify-global-environment'
virtualenvwrapper.el:480:9:Warning: assignment to free variable
    `eshell-path-env'

In end of data:
virtualenvwrapper.el:499:1:Warning: the function `eshell-stringify-list' is
    not known to be defined.

@kljohann thanks for confirming! Yeah a lot of those warnings are unfortunately unavoidable given the nature of Emacs Lisp. The mapcar thing could be cleaned up though, thanks for pointing that out.