Table of Contents
1. Python Development Configuration
Configuration for Python development with modern tooling and best practices.
1.1. Overview
This module provides Python development support including:
- Language Support: python-mode with tree-sitter
- Virtual Environments: pyvenv for virtualenv management
- Code Quality: Black formatting, isort import sorting
- Testing: pytest integration
- REPL: Enhanced Python REPL
- LSP: Python Language Server support
1.2. Key Features
1.2.1. Python Mode & Tree-Sitter
- Syntax highlighting (enhanced with tree-sitter)
- Intelligent indentation
- Code navigation
- Integration with debugging tools
- Automatic mode selection based on tree-sitter availability
1.2.2. Virtual Environment Management
- Automatic venv detection
- Easy switching between environments
- Integration with project workflows
1.2.3. Code Formatting & Quality
| Tool | Purpose |
|---|---|
black |
Opinionated code formatter |
isort |
Import statement organizer |
flake8 |
Style guide enforcement |
pylint |
Code analysis |
1.2.4. Development Workflow
- Virtual environment activation
- LSP server connection
- Auto-formatting on save
- Test runner integration
1.3. Python
;;; prog-python-conf.el --- Python development configuration -*- lexical-binding: t; -*- ;;; Commentary: ;;; Configuration for Python development including LSP support, formatting, ;;; testing, virtual environments, and debugging. ;;; Code: ;; Python mode settings ;; (use-package python ;; :ensure nil ;; :mode ("\\.py\\'" . python-mode) ;; :interpreter ("python" "python3") ;; :custom ;; (python-indent-offset 4) ;; (python-indent-guess-indent-offset nil) ;; (python-shell-interpreter "python3") ;; (python-shell-completion-native-enable nil) ; Avoid readline issues ;; :config ;; ;; Remove trailing whitespace on save ;; (add-hook 'python-mode-hook ;; (lambda () ;; (add-hook 'before-save-hook #'delete-trailing-whitespace nil t)))) ;; Python Tree-Sitter mode configuration ;; Emacs 29+ includes built-in tree-sitter support (use-package python :ensure nil :mode ("\\.py\\'" . python-ts-mode) :interpreter ("python" . python-ts-mode) :custom (python-indent-offset 4) (python-indent-guess-indent-offset nil) (python-shell-interpreter "python3") (python-shell-completion-native-enable nil) ; Avoid readline issues :init ;; Remap python-mode to python-ts-mode when tree-sitter is available (when (and (fboundp 'treesit-available-p) (treesit-available-p)) (add-to-list 'major-mode-remap-alist '(python-mode . python-ts-mode))) :config ;; Ensure tree-sitter grammar is installed (defun fu-python-ensure-treesit-grammar () "Ensure Python tree-sitter grammar is installed." (when (and (fboundp 'treesit-available-p) (treesit-available-p) (not (treesit-language-available-p 'python))) (message "Python tree-sitter grammar not found. Install with M-x treesit-install-language-grammar RET python RET"))) (add-hook 'after-init-hook #'fu-python-ensure-treesit-grammar) ;; Common settings for both python-mode and python-ts-mode (defun fu-python-common-setup () "Common setup for Python modes." (setq-local tab-width 4) (setq-local indent-tabs-mode nil) ;; Remove trailing whitespace on save (add-hook 'before-save-hook #'delete-trailing-whitespace nil t)) (add-hook 'python-mode-hook #'fu-python-common-setup) (add-hook 'python-ts-mode-hook #'fu-python-common-setup)) ;; Virtual environment management (use-package pyvenv :defer t :config (setq pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:" pyvenv-virtual-env-name "] "))) ;; Automatically activate virtual environment (defun fu-python-auto-activate-venv () "Automatically activate Python virtual environment if found. Looks for .venv, venv, env directories or .python-version file." (interactive) (let* ((project-root (or (locate-dominating-file default-directory ".venv") (locate-dominating-file default-directory "venv") (locate-dominating-file default-directory "env") (locate-dominating-file default-directory ".python-version"))) (venv-path (when project-root (or (expand-file-name ".venv" project-root) (expand-file-name "venv" project-root) (expand-file-name "env" project-root))))) (when (and venv-path (file-directory-p venv-path)) (pyvenv-activate venv-path) (message "Activated virtual environment: %s" venv-path)))) (add-hook 'python-mode-hook #'fu-python-auto-activate-venv) (add-hook 'python-ts-mode-hook #'fu-python-auto-activate-venv)) ;; Python formatting with Black (use-package python-black :defer t :commands (python-black-buffer python-black-region python-black-on-save-mode) :hook ((python-mode python-ts-mode) . python-black-on-save-mode-enable-dwim) :config (defun python-black-on-save-mode-enable-dwim () "Enable python-black-on-save-mode if black is available." (when (executable-find "black") (python-black-on-save-mode 1)))) ;; Import sorting with isort (use-package py-isort :defer t :commands (py-isort-buffer py-isort-region) :hook (before-save . fu-python-isort-before-save) :config (defun fu-python-isort-before-save () "Run isort before saving if in python-mode or python-ts-mode and isort is available." (when (and (derived-mode-p 'python-mode 'python-ts-mode) (executable-find "isort")) (py-isort-buffer)))) ;; Python REPL enhancements (use-package python :ensure nil :config ;; Send region/buffer to Python REPL (defun fu-python-shell-send-region-or-buffer () "Send the current region to Python REPL, or whole buffer if no region is active." (interactive) (if (use-region-p) (python-shell-send-region (region-beginning) (region-end)) (python-shell-send-buffer))) (defun fu-python-shell-send-defun-and-step () "Send the current function to Python REPL and move to next function." (interactive) (python-shell-send-defun nil) (python-nav-forward-defun)) :bind ((:map python-mode-map ("C-c C-c" . fu-python-shell-send-region-or-buffer) ("C-c C-n" . fu-python-shell-send-defun-and-step) ("C-c C-r" . python-shell-send-region) ("C-c C-b" . python-shell-send-buffer) ("C-c C-z" . python-shell-switch-to-shell)) (:map python-ts-mode-map ("C-c C-c" . fu-python-shell-send-region-or-buffer) ("C-c C-n" . fu-python-shell-send-defun-and-step) ("C-c C-r" . python-shell-send-region) ("C-c C-b" . python-shell-send-buffer) ("C-c C-z" . python-shell-switch-to-shell)))) ;; Python debugger (pdb) integration (use-package realgud :defer t :commands (realgud:pdb)) ;; Optional: IPython integration ;; Uncomment if you prefer IPython over standard Python REPL ;; (use-package python ;; :config ;; (when (executable-find "ipython") ;; (setq python-shell-interpreter "ipython" ;; python-shell-interpreter-args "-i --simple-prompt --no-color-info" ;; 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"))) ;; LSP configuration with Eglot (with-eval-after-load 'eglot ;; Prefer pyright over pylsp if available (when (executable-find "pyright-langserver") (add-to-list 'eglot-server-programs '(python-mode . ("pyright-langserver" "--stdio")))) ;; Enable eglot for Python (add-hook 'python-mode-hook #'eglot-ensure) (add-hook 'python-ts-mode-hook #'eglot-ensure)) ;; Flycheck for additional linting (optional, alongside Flymake) ;; (use-package flycheck ;; :hook (python-mode . flycheck-mode) ;; :config ;; (setq flycheck-python-flake8-executable "python3" ;; flycheck-python-pycompile-executable "python3" ;; flycheck-python-pylint-executable "python3")) ;; Jupyter notebook support (optional) ;; (use-package ein ;; :defer t ;; :commands (ein:run ein:login)) (provide 'prog-python-conf) ;;; prog-python-conf.el ends here