branch: externals/org
commit d0d838b02e44a40adca14d6eae39fd4c364730da
Author: Jack Kamm <[email protected]>
Commit: Jack Kamm <[email protected]>

    ob-python: Test and improve robustness for externally started python
    
    * lisp/ob-python.el (org-babel-python-initiate-session-by-key): Wait
    for first prompt for pre-existing python processes.  Document behavior
    for pre-existing python processes.
    (org-babel-python-initiate-session): Document behavior for
    pre-existing python processes.
    *
    testing/lisp/test-ob-python.el 
(test-ob-python/session-with-existing-inferior-python):
    New test for working with existing python processes.
---
 lisp/ob-python.el              | 19 ++++++++++++++++---
 testing/lisp/test-ob-python.el | 19 +++++++++++++++++++
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/lisp/ob-python.el b/lisp/ob-python.el
index 6002a28632..8963d2f24c 100644
--- a/lisp/ob-python.el
+++ b/lisp/ob-python.el
@@ -248,8 +248,12 @@ unless the Python session was created outside Org."
   (setq-local org-babel-python--initialized t))
 (defun org-babel-python-initiate-session-by-key (&optional session)
   "Initiate a python session.
-If there is not a current inferior-process-buffer in SESSION
-then create.  Return the initialized session."
+If there is not a current inferior-process-buffer matching
+SESSION then create it. If inferior process already
+exists (e.g. if it was manually started with `run-python'), make
+sure it's configured to work with ob-python.  If session has
+already been configured as such, do nothing.  Return the
+initialized session."
   (save-window-excursion
     (let* ((session (if session (intern session) :default))
            (py-buffer (or (org-babel-python-session-buffer session)
@@ -266,6 +270,10 @@ then create.  Return the initialized session."
             ;; Session was created outside Org.  Assume first prompt
             ;; already happened; run session setup code directly
             (unless org-babel-python--initialized
+              ;; Ensure first prompt. Based on python-tests.el
+              ;; (`python-tests-shell-wait-for-prompt')
+              (while (not (python-util-comint-end-of-output-p))
+                (sit-for 0.1))
               (org-babel-python--setup-session))
           ;; Adding to `python-shell-first-prompt-hook' immediately
           ;; after `run-python' should be safe from race conditions,
@@ -288,7 +296,12 @@ then create.  Return the initialized session."
       session)))
 
 (defun org-babel-python-initiate-session (&optional session _params)
-  "Create a session named SESSION according to PARAMS."
+  "Initiate Python session named SESSION according to PARAMS.
+If there is not a current inferior-process-buffer matching
+SESSION then create it. If inferior process already
+exists (e.g. if it was manually started with `run-python'), make
+sure it's configured to work with ob-python.  If session has
+already been configured as such, do nothing."
   (unless (string= session "none")
     (org-babel-python-session-buffer
      (org-babel-python-initiate-session-by-key session))))
diff --git a/testing/lisp/test-ob-python.el b/testing/lisp/test-ob-python.el
index 18861444e7..e3c6a40096 100644
--- a/testing/lisp/test-ob-python.el
+++ b/testing/lisp/test-ob-python.el
@@ -329,6 +329,25 @@ print('success')
 #+end_src"
                                     (org-babel-execute-src-block))))))
 
+(ert-deftest test-ob-python/session-with-existing-inferior-python ()
+  ;; Disable the test on older Emacs as built-in python.el sometimes
+  ;; fail to initialize session.
+  (skip-unless (version<= "28" emacs-version))
+  (let ((session-name
+         "test-ob-python/session-with-existing-inferior-python"))
+    (let ((python-shell-buffer-name session-name))
+      (run-python))
+    (unwind-protect
+        (should (equal "success"
+                       (org-test-with-temp-text
+                        (format "#+begin_src python :session %s :results value
+'success'
+#+end_src"
+                                session-name)
+                       (org-babel-execute-src-block))))
+      (let (kill-buffer-hook kill-buffer-query-functions)
+        (kill-buffer (format "*%s*" session-name))))))
+
 (provide 'test-ob-python)
 
 ;;; test-ob-python.el ends here

Reply via email to