aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/python.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/python.el')
-rw-r--r--lisp/progmodes/python.el95
1 files changed, 93 insertions, 2 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index acb5b40165f..50dc293a955 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -32,8 +32,8 @@
32 32
33;; Implements Syntax highlighting, Indentation, Movement, Shell 33;; Implements Syntax highlighting, Indentation, Movement, Shell
34;; interaction, Shell completion, Shell virtualenv support, Shell 34;; interaction, Shell completion, Shell virtualenv support, Shell
35;; syntax highlighting, Pdb tracking, Symbol completion, Skeletons, 35;; package support, Shell syntax highlighting, Pdb tracking, Symbol
36;; FFAP, Code Check, Eldoc, Imenu. 36;; completion, Skeletons, FFAP, Code Check, Eldoc, Imenu.
37 37
38;; Syntax highlighting: Fontification of code is provided and supports 38;; Syntax highlighting: Fontification of code is provided and supports
39;; python's triple quoted strings properly. 39;; python's triple quoted strings properly.
@@ -170,6 +170,10 @@
170;; introduced as simple way of adding paths to the PYTHONPATH without 170;; introduced as simple way of adding paths to the PYTHONPATH without
171;; affecting existing values. 171;; affecting existing values.
172 172
173;; Shell package support: you can enable a package in the current
174;; shell so that relative imports work properly using the
175;; `python-shell-package-enable' command.
176
173;; Shell syntax highlighting: when enabled current input in shell is 177;; Shell syntax highlighting: when enabled current input in shell is
174;; highlighted. The variable `python-shell-font-lock-enable' controls 178;; highlighted. The variable `python-shell-font-lock-enable' controls
175;; activation of this feature globally when shells are started. 179;; activation of this feature globally when shells are started.
@@ -2100,6 +2104,31 @@ uniqueness for different types of configurations."
2100 (directory-file-name python-shell-virtualenv-path)) 2104 (directory-file-name python-shell-virtualenv-path))
2101 path)))) 2105 path))))
2102 2106
2107(defvar python-shell--package-depth 10)
2108
2109(defun python-shell-package-enable (directory package)
2110 "Add DIRECTORY parent to $PYTHONPATH and enable PACKAGE."
2111 (interactive
2112 (let* ((dir (expand-file-name
2113 (read-directory-name
2114 "Package root: "
2115 (file-name-directory
2116 (or (buffer-file-name) default-directory)))))
2117 (name (completing-read
2118 "Package: "
2119 (python-util-list-packages
2120 dir python-shell--package-depth))))
2121 (list dir name)))
2122 (python-shell-send-string
2123 (format
2124 (concat
2125 "import os.path;import sys;"
2126 "sys.path.append(os.path.dirname(os.path.dirname('''%s''')));"
2127 "__package__ = '''%s''';"
2128 "import %s")
2129 directory package package)
2130 (python-shell-get-process)))
2131
2103(defun python-shell-comint-end-of-output-p (output) 2132(defun python-shell-comint-end-of-output-p (output)
2104 "Return non-nil if OUTPUT is ends with input prompt." 2133 "Return non-nil if OUTPUT is ends with input prompt."
2105 (string-match 2134 (string-match
@@ -4070,6 +4099,68 @@ Optional argument DIRECTION defines the direction to move to."
4070 (goto-char comment-start)) 4099 (goto-char comment-start))
4071 (forward-comment factor))) 4100 (forward-comment factor)))
4072 4101
4102(defun python-util-list-directories (directory &optional predicate max-depth)
4103 "List DIRECTORY subdirs, filtered by PREDICATE and limited by MAX-DEPTH.
4104Argument PREDICATE defaults to `identity' and must be a function
4105that takes one argument (a full path) and returns non-nil for
4106allowed files. When optional argument MAX-DEPTH is non-nil, stop
4107searching when depth is reached, else don't limit."
4108 (let* ((dir (expand-file-name directory))
4109 (dir-length (length dir))
4110 (predicate (or predicate #'identity))
4111 (to-scan (list dir))
4112 (tally nil))
4113 (while to-scan
4114 (let ((current-dir (car to-scan)))
4115 (when (funcall predicate current-dir)
4116 (setq tally (cons current-dir tally)))
4117 (setq to-scan (append (cdr to-scan)
4118 (python-util-list-files
4119 current-dir #'file-directory-p)
4120 nil))
4121 (when (and max-depth
4122 (<= max-depth
4123 (length (split-string
4124 (substring current-dir dir-length)
4125 "/\\|\\\\" t))))
4126 (setq to-scan nil))))
4127 (nreverse tally)))
4128
4129(defun python-util-list-files (dir &optional predicate)
4130 "List files in DIR, filtering with PREDICATE.
4131Argument PREDICATE defaults to `identity' and must be a function
4132that takes one argument (a full path) and returns non-nil for
4133allowed files."
4134 (let ((dir-name (file-name-as-directory dir)))
4135 (apply #'nconc
4136 (mapcar (lambda (file-name)
4137 (let ((full-file-name (expand-file-name file-name dir-name)))
4138 (when (and
4139 (not (member file-name '("." "..")))
4140 (funcall (or predicate #'identity) full-file-name))
4141 (list full-file-name))))
4142 (directory-files dir-name)))))
4143
4144(defun python-util-list-packages (dir &optional max-depth)
4145 "List packages in DIR, limited by MAX-DEPTH.
4146When optional argument MAX-DEPTH is non-nil, stop searching when
4147depth is reached, else don't limit."
4148 (let* ((dir (expand-file-name dir))
4149 (parent-dir (file-name-directory
4150 (directory-file-name
4151 (file-name-directory
4152 (file-name-as-directory dir)))))
4153 (subpath-length (length parent-dir)))
4154 (mapcar
4155 (lambda (file-name)
4156 (replace-regexp-in-string
4157 (rx (or ?\\ ?/)) "." (substring file-name subpath-length)))
4158 (python-util-list-directories
4159 (directory-file-name dir)
4160 (lambda (dir)
4161 (file-exists-p (expand-file-name "__init__.py" dir)))
4162 max-depth))))
4163
4073(defun python-util-popn (lst n) 4164(defun python-util-popn (lst n)
4074 "Return LST first N elements. 4165 "Return LST first N elements.
4075N should be an integer, when negative its opposite is used. 4166N should be an integer, when negative its opposite is used.