EMACS-DOCUMENT

=============>随便,谢谢

使用PyEnv等配置Emacs Python LSP

有许多文档描述了如何在Emacs中设置用于自动不全的Python语言服务器。然而,就我所看到的这些文档都缺少以下内容:

  • 如何在多个Python版本之间进行切换
  • 如何处理Python虚拟环境

我有一个简单但足够使用的工作流程,想与大家分享!

设置环境

用到的工具:

  • pyenv: 管理多个python版本
  • direnv: 处理项目相关的环境配置
  • venv: 在Python虚拟环境之间进行切换

设置 pyenv:

官方提供了一个自动安装脚本。我不太喜欢使用它来安装,因为存在安全风险,但我也没有要检查这个安装脚本的意思:

curl https://pyenv.run | bash

对于那些关注安全的人,请遵循其他安装说明

Now, I'm using zsh as my shell. Let's set up the pyenv configuration in the ~/.zshenv: 目前,我使用 zsh 作为日常使用shell. 让我们在 ~/.zshenv 中设置 pyenv 配置:

export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

注意,我在 ~/.zshenv 而不是在 ~/.zshrc 中执行该操作。这是因为 ~/.zshrc 仅被交互式shell加载。你也可以把这段内容放到 ~/.zprofile 中。 你可以在这个 很棒的stackoverflow帖子 中了解到 zsh 各个启动文件的不同作用。

现在,如果我们打开一个新的终端,输入 whereis pyenv 你应该得到类似下面的内容:

kota@kota-ThinkPad-P1> whereis pyenv ~
pyenv: /home/kota/.pyenv/bin/pyenv

:)

设置项目

我创建了一个非常简单的项目结构如下所示:

├── .envrc
├── foo
│ ├── app.py
│ ├── __init__.py
│ └── __main__.py
└── setup.py

这个应用程序要做的就是找出向量 (1,2,3) 的长度:

import numpy as np

def run():
arr = np.array([1, 2, 3])
print(np.linalg.norm(arr))

这里的关键是它使用了一个外部依赖项。

让我们再来看看 setup.py:

from setuptools import setup, find_packages
from foo import __version__
setup(
    name="foo",
    version=__version__,
    packages=find_packages(exclude=["tests"]),
    author="Kota Weaver",
    install_requires=[
        'numpy'
    ],
    extras_require={
        'dev': [
            'python-language-server[all]'
        ],
        'test': [
            'pytest', 'pyflakes'
        ]
    }
)

注意,我在 dev 依赖中列出了Python LSP服务器。

现在让我们建立Python开发环境!首先是我 .envrc:

export SIMENV_PYTHON=3.8.1

use pyenv $SIMENV_PYTHON

现在,如果我们进入项目目录,并执行 direnv allow,应该就能够通过下面命令安装正确的Python版本:

pyenv install $SIMENV_PYTHON

(注意: 您可能需要安装以下依赖项: libffi-dev libssl-dev libreadline-dev libsqlite3-dev libbz2-dev)

然后,离开并再次进入该目录,然后使用以下命令安装依赖项:

pip install -e .['dev','test']

(根据您的shell,您也许需要使用 == 来转义 [])

确保 which python 显示的位置是正确的! 这允许我们使用下面命令运行程序使用:

kota@kota-ThinkPad-P1> python -m foo ~/foo
3.7416573867739413

耶!

设置Emacs

现在,我们进入最重要的部分……让我们配置Emacs来使用它做一些聪明的事情!

我使用 use-package, 我设置成如果没有安装则自动进行安装。我将这个设置在一个非常简单的 ~/.emacs.d/init.el 中,你可以随意引用:

(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
("marmalade" . "https://marmalade-repo.org/packages/")
("melpa" . "https://melpa.org/packages/")))
(package-initialize)

(when (not (package-installed-p 'use-package)) (package-refresh-contents) (package-install 'use-package))
(require 'use-package)

; direnv mode allows automatic loading of direnv variables
(use-package direnv
:ensure t
:config
(direnv-mode))

; setup Emacs path from our ~/.zshenv
(use-package exec-path-from-shell
:ensure t
:config
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))

; we also should make sure we have flycheck installed
(use-package flycheck
:ensure t)

; Let's set up company! perhaps not necessary but this is what i like to use
(use-package company
:ensure t
:config
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 1))

; install lsp mode
(use-package lsp-mode
:ensure t
:hook (python-mode . lsp-deferred)
:commands (lsp lsp-deferred))

; let's add the lsp company backend
(use-package company-lsp
:ensure t
:config
(push 'company-lsp company-backends))

; also installs lsp as a dependency
(use-package lsp-ui
:ensure t
:hook (lsp-mode . lsp-ui-mode))

下面是我机器上的一些截图(这是我的正常设置的截图,而不是上面精简版的截图,但应该有相同的功能):

emacs-screenshot.png