;;; python-settings.el --- Python settings -*- mode: emacs-lisp; lexical-binding: t -*- ;;; Commentary: ;; Requirements: ;; program: python ;; Emacs packages: anaconda-mode company-anaconda sphinx-doc ;; Language Server Support, Emacs built-in package `eglot' ;; https://github.com/joaotavora/eglot ;; connects to LSP ;; activate with `eglot' ;; after changing configurations run `eglot-reconnect' ;; follow documentation at point `eldoc-doc-buffer' / `display-local-help' ;; Language Server Protocol (LSP), python package `python-lsp-server' ;; https://github.com/python-lsp/python-lsp-server ;; install via: pip install "python-lsp-server[all]" ;; arch linux: extra/python-lsp-server ;; - pycodestyle (formerly called pep8) - Python style guide checker ;; https://pycodestyle.pycqa.org/en/latest/ ;; to ignore violations see: ;; - https://flake8.pycqa.org/en/latest/user/violations.html ;; - https://flake8.pycqa.org/en/latest/user/configuration.html#configuration ;; arch linux: extra/python-pycodestyle ;; config via ~/.config/pycodestyle ;; - pylsp-mypy: pylsp plugin, type checking for Python >=3.8 ;; https://mypy-lang.org/ ;; pip install pylsp-mypy ;; arch linux: aur/python-pylsp-mypy ;; Syntax Checking, Emacs built-in package `flymake' ;; (flymake-running-backends) -> (eglot-flymake-backend) ;;; Code: (use-package python :delight (python-mode "Py") ;; "Py " "\u1F15F" :commands (python-mode) :bind (:map python-mode-map ;; swap C-u C-c C-c with C-c C-c, so C-c C-c sends __main__ ("C-c C-c" . my-python-shell-send-buffer-w-main) ("C-u C-c C-c" . my-python-shell-send-buffer) ("M-m m c c" . my-python-execute-file) ("M-m m c C" . my-python-execute-file-switch) ("M-m m s b" . my-python-shell-send-buffer-w-main)) :config (setq python-indent-offset 2) ; python-indent is obsolete since 24.3; use python-indent-offset instead. (setq python-indent-guess-indent-offset nil) ; default t. nil to use the config value python-indent-offset (setq python-indent-guess-indent-offset-verbose nil) ; hide message like: Can’t guess python-indent-offset, using defaults: 2 ;;(setq python-shell-interpreter "ipython") ;;(setq python-shell-interpreter-args "-i") (defun my-pyenv-executable-find (command) "Find executable taking pyenv shims into account. If the executable is a system executable and not in the same path as the pyenv version then also return nil. This works around https://github.com/pyenv/pyenv-which-ext " (if (executable-find "pyenv") (progn (let ((pyenv-string (shell-command-to-string (concat "pyenv which " command))) (pyenv-version-names (split-string (string-trim (shell-command-to-string "pyenv version-name")) ":")) (executable nil) (i 0)) (if (not (string-match "not found" pyenv-string)) (while (and (not executable) (< i (length pyenv-version-names))) (if (string-match (elt pyenv-version-names i) (string-trim pyenv-string)) (setq executable (string-trim pyenv-string))) (if (string-match (elt pyenv-version-names i) "system") (setq executable (string-trim (executable-find command)))) (setq i (1+ i)))) executable)) (executable-find command))) (defun my-python-execute-file (arg) "Execute a python script in a shell." (interactive "P") ;; set compile command to buffer-file-name ;; universal argument put compile buffer in comint mode (let ((universal-argument t) (compile-command (format "%s %s" (my-pyenv-executable-find python-shell-interpreter) (shell-quote-argument (file-name-nondirectory buffer-file-name))))) (if arg (call-interactively 'compile) (compile compile-command t) (with-current-buffer (get-buffer "*compilation*") (inferior-python-mode))))) (defun my-python-execute-file-switch (arg) "Execute a python script in a shell and switch to the shell buffer in `insert state'." (interactive "P") (my-python-execute-file arg) (switch-to-buffer-other-window "*compilation*") (end-of-buffer) (evil-insert-state)) (defun my-python-shell-send-buffer (&optional send-main) "Send buffer content to shell." (interactive) (let ((python-mode-hook nil)) ;; TODO: why? (python-shell-send-buffer send-main))) (defun my-python-shell-send-buffer-w-main () "Send buffer content to shell with main." (interactive) (my-python-shell-send-buffer t)) (defadvice run-python (after my-advice-run-python activate) "set flag to allow exit without query on any active python process." (set-process-query-on-exit-flag ad-return-value nil)) (defun my-python-shell-send-buffer-w-args (args) "Send buffer content to shell with main and arguments." (interactive "sPython arguments: ") (let ((source-buffer (current-buffer))) (with-temp-buffer (insert "import sys; sys.argv = '''" args "'''.split()\n") (insert-buffer-substring source-buffer) (my-python-shell-send-buffer-w-main)))) ) ;; needs system package python-jedi ;; (use-package anaconda-mode ;; works with company-mode via company-anaconda ;; :after python ;; :delight (anaconda-mode "A") ;; \u24B6 a ;; :bind (([remap anaconda-mode-show-doc] . my-anaconda-mode-show-doc)) ;; M-? ;; :hook (python-mode ;; (python-mode . anaconda-eldoc-mode)) ;; if cursor is between function's parenthesis show parameter in echo area ;; :config ;; (setq anaconda-mode-installation-directory (concat user-cache-directory "anaconda-mode")) ;; ;; compared to `anaconda-mode-show-doc' using `my-anaconda-mode-show-doc-callback' ;; (defun my-anaconda-mode-show-doc () ;; "Show documentation for context at point." ;; (interactive) ;; ;;(anaconda-mode-call "show_doc" 'anaconda-mode-show-doc-callback) ;; removed ;; (anaconda-mode-call "show_doc" 'my-anaconda-mode-show-doc-callback) ;; instead ;; ) ;; ;; compared to `anaconda-mode-show-doc-callback' no change of focus ;; (defun my-anaconda-mode-show-doc-callback (result) ;; "Process view doc RESULT." ;; (if (> (length result) 0) ;; (if (and anaconda-mode-use-posframe-show-doc ;; (require 'posframe nil 'noerror) ;; (posframe-workable-p)) ;; (anaconda-mode-documentation-posframe-view result) ;; ;;(pop-to-buffer (anaconda-mode-documentation-view result) t) ;; removed ;; (anaconda-mode-documentation-view result) ;; instead ;; ) ;; (message "No documentation available"))) ;; ) ;; (use-package company-anaconda ;; :after (python anaconda-mode company) ;; :bind (([remap anaconda-mode-complete] . company-anaconda)) ;; :config ;; (add-to-list 'company-backends '(company-anaconda :with company-capf))) ;; to see anaconda-mode completions together with ones comes from inferior python process ;; https://melpa.org/#/sphinx-doc ;; https://github.com/naiquevin/sphinx-doc.el ;; enable the sphinx-doc-mode and bind the interactive function sphinx-doc to C-c M-d. (use-package sphinx-doc :delight (sphinx-doc-mode "Sph") ;; \u24C8 s :hook (python-mode . sphinx-doc-mode)) ;; jupyter repl ;; optional markdown-mode ;; optional company-mode ;; emacs-websocket ;; simple-httpd ;; zmq (use-package jupyter :commands (;; launch a new local kernel and displays a REPL buffer jupyter-run-repl ;; connect to an existing kernel using the kernel’s connection ;; file, which is supplied by the user, and displays a REPL buffer jupyter-connect-repl ;; associate the buffer to an existing emacs-jupyter REPL or create a new one choosing the appropriate Jupyter kernel jupyter-repl-associate-buffer) :init (setq jupyter-use-zmq nil) :config (add-to-list 'org-structure-template-alist '("py" . "src jupyter-python")) ;; emacs-jupyter will always use the Python kernel found on startup (defun my-jupyter-refresh-kernelspecs () "Refresh Jupyter kernelspecs" (interactive) (jupyter-available-kernelspecs t)) ) ;; https://github.com/astoff/code-cells.el ;; .ipynb (use-package code-cells :commands (code-cells-mode code-cells-convert-ipynb) ;;:mode ("\\.ipynb\\'" . code-cells-mode) :hook (code-cells-mode . code-cells-convert-ipynb) :config (setq code-cells-convert-ipynb-style '(("pandoc" "--to" "ipynb" "--from" "org") ("pandoc" "--to" "org" "--from" "ipynb") (lambda () #'org-mode))) ) (use-package ox-ipynb :after ox) ;; https://millejoh.github.io/emacs-ipython-notebook/ ;; requires: anaphora dash deferred polymode request websocket with-editor (use-package ein :commands (ein:run ein:jupyter-server-start ein:notebooklist-open) :config (require 'ein-jupyter) (require 'ein-notebook) (setq ein:output-area-inlined-images t)) (provide 'python-settings) ;;; python-settings.el ends here