#+TITLE: Configuring Python in Emacs #+AUTHOR: Howard X. Abrams #+DATE: 2021-11-16 #+FILETAGS: :emacs: A literate programming file for configuring Python. #+BEGIN_SRC emacs-lisp :exports none ;;; ha-programming-python.el --- A literate programming file for configuring Python. -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2021 Howard X. Abrams ;; ;; Author: Howard X. Abrams ;; Maintainer: Howard X. Abrams ;; Created: November 16, 2021 ;; ;; This file is not part of GNU Emacs. ;; ;; *NB:* Do not edit this file. Instead, edit the original literate file at: ;; /Users/howard.abrams/other/hamacs/ha-programming-python.org ;; And tangle the file to recreate this one. ;; ;;; Code: #+END_SRC * Introduction The critical part of Python integration with Emacs is running LSP in Python using [[file:ha-programming.org::*direnv][direnv]]. And the only question to ask is if the Python we run it in Docker or in a virtual environment. ** Virtual Environment For a local virtual machine, simply put the following in your =.envrc= file: #+begin_src conf layout_python3 #+end_src That is pretty slick and simple. The old way, that we still use if you need a particular version of Python, is to install [[https://github.com/pyenv/pyenv][pyenv]] globally: #+BEGIN_SRC sh pip install pyenv #+END_SRC And have this in your =.envrc= file: #+begin_src conf use python 3.7.1 #+end_src Also, you need the following in your =~/.config/direnv/direnvrc= file (which I have): #+begin_src shell use_python() { local python_root=$(pyenv root)/versions/$1 load_prefix "$python_root" if [[ -x "$python_root/bin/python" ]]; then layout python "$python_root/bin/python" else echo "Error: $python_root/bin/python can't be executed." exit fi } #+end_src ** Docker Environment Docker really allows you to isolate your project's environment. The downside is that you are using Docker and probably a bloated container. On my work laptop, a Mac, this creates a behemoth virtual machine that immediately spins the fans like a wind tunnel. But, but... think of the dependencies! Enough of the rant (I go back and forth), after getting Docker installed and running (ooo Podman ... shiny), and you've created a =Dockerfile= for your project, let's install [[https://github.com/snbuback/container-env][container-env]]. Your project's =.envrc= file would contain something like: #+begin_src shell CONTAINER_NAME=my-docker-container CONTAINER_WRAPPERS=(python3 pip3 yamllint) CONTAINER_EXTRA_ARGS="--env SOME_ENV_VAR=${SOME_ENV_VAR}" container_layout #+end_src ** Python Dependencies Whew. Each Python project's =requirements-dev.txt= file would reference the [[https://pypi.org/project/python-lsp-server/][python-lsp-server]] (not the /unmaintained/ =python-language-server=): #+begin_src conf python-lsp-server[all] #+end_src *Note:* This does mean, you would have a =tox.ini= with this line: #+BEGIN_SRC conf [tox] minversion = 1.6 skipsdist = True envlist = linters ignore_basepython_conflict = True [testenv] basepython = python3 install_command = pip install {opts} {packages} deps = -r{toxinidir}/test-requirements.txt commands = stestr run {posargs} stestr slowest # ... #+END_SRC *** Using Jedi Instead Do we want to use the Jedi version of LSP? Not sure what it buys us. #+BEGIN_SRC emacs-lisp :tangle no (use-package lsp-jedi :config (with-eval-after-load "lsp-mode" (add-to-list 'lsp-disabled-clients 'pyls) (add-to-list 'lsp-enabled-clients 'jedi))) #+END_SRC * LSP Integration of Python Now that the [[file:ha-programming.org::*Language Server Protocol (LSP) Integration][LSP Integration]] is complete, we can stitch the two projects together: #+BEGIN_SRC emacs-lisp (use-package lsp-mode :hook ((python-mode . lsp))) #+END_SRC And we're done. * Technical Artifacts :noexport: Let's =provide= a name so we can =require= this file: #+BEGIN_SRC emacs-lisp :exports none (provide 'ha-programming-python) ;;; ha-programming-python.el ends here #+END_SRC #+DESCRIPTION: A literate programming file for configuring Python. #+PROPERTY: header-args:sh :tangle no #+PROPERTY: header-args:emacs-lisp :tangle yes #+PROPERTY: header-args :results none :eval no-export :comments no mkdirp yes #+OPTIONS: num:nil toc:nil todo:nil tasks:nil tags:nil date:nil #+OPTIONS: skip:nil author:nil email:nil creator:nil timestamp:nil #+INFOJS_OPT: view:nil toc:nil ltoc:t mouse:underline buttons:0 path:http://orgmode.org/org-info.js