GNU bug report logs - #79413
[PATCH] Fix path and environment in remote Python shell

Previous Next

Package: emacs;

Reported by: Liu Hui <liuhui1610 <at> gmail.com>

Date: Tue, 9 Sep 2025 09:54:01 UTC

Severity: normal

Tags: patch

Full log


View this message in rfc822 format

From: Liu Hui <liuhui1610 <at> gmail.com>
To: Michael Albinus <michael.albinus <at> gmx.de>
Cc: 79413 <at> debbugs.gnu.org
Subject: bug#79413: [PATCH] Fix path and environment in remote Python shell
Date: Thu, 11 Sep 2025 12:47:13 +0800
Michael Albinus <michael.albinus <at> gmx.de> writes:

> Liu Hui <liuhui1610 <at> gmail.com> writes:
>
> Hi,
>
>>> This is a Tramp feature. See this comment in tramp-handle-make-process,
>>> tramp-sh-handle-make-process and tramp-sh-handle-process-file:
>>>
>>> --8<---------------cut here---------------start------------->8---
>>> 	   ;; We use as environment the difference to toplevel
>>> 	   ;; `process-environment'.
>>> --8<---------------cut here---------------end--------------->8---
>>>
>>> The reason is, that often a local value of $FOO might be wrong on the
>>> remote host.
>>
>> Thanks for the explanation. Then let-binding process-environment is
>> not a reliable way if we want to ensure some environment variables,
>> python-shell-process-environment in this case, are applied to the
>> remote process.
>>
>> Could tramp add an option that disables this feature temporarily or
>> ensures specific environment variables are always applied in
>> tramp-sh-handle-make-process and tramp-sh-handle-process-file?
>
> You would run into the same problem why this feature exist. You don't
> want to expand local environment variables like DISPLAY, SSH_* or
> whatever to the remote host.

I agree local environment variables should not be applied on the
remote host. I meant to propagate specific environment variables (e.g.
"PYTHONPATH=/opt/mypackage") in python-shell-process-environment. The
problem is that "PYTHONPATH=/opt/mypackage" is skipped for remote
processes if it happens to exist in the default process environment
(e.g. it is added in local ~/.profile).

How about the following change? It doesn't change the default behavior
and allows the caller to override tramp-local-environment-variable-p
when necessary.

diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 9d13cdc3a2d..0a454fed69b 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -3052,8 +3052,7 @@ tramp-sh-handle-make-process
 	     ;; `process-environment'.
 	     env uenv
 	     (env (dolist (elt (cons prompt process-environment) env)
-		    (or (member
-			 elt (default-toplevel-value 'process-environment))
+		    (or (tramp-local-environment-variable-p elt)
 			(if (string-search "=" elt)
 			    (setq env (append env `(,elt)))
 			  (setq uenv (cons elt uenv))))))
@@ -3288,7 +3287,7 @@ tramp-sh-handle-process-file
 			       (cons program args) " "))
       ;; We use as environment the difference to toplevel `process-environment'.
       (dolist (elt process-environment)
-        (or (member elt (default-toplevel-value 'process-environment))
+        (or (tramp-local-environment-variable-p elt)
             (if (string-search "=" elt)
                 (setq env (append env `(,elt)))
               (setq uenv (cons elt uenv)))))
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 9bf1b4ae6c3..3ce25a5c663 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -5342,6 +5342,12 @@ tramp-direct-async-process-p
 	 (or (not (stringp buffer)) (not (tramp-tramp-file-p buffer)))
 	 (or (not (stringp stderr)) (not (tramp-tramp-file-p stderr))))))

+(defun tramp-local-environment-variable-p (arg)
+  "Return non-nil if ARG exists in default `process-environment'.
+Tramp does not propagate a local environment variable in remote
+processes."
+  (member arg (default-toplevel-value 'process-environment)))
+
 (defun tramp-handle-make-process (&rest args)
   "An alternative `make-process' implementation for Tramp files."
   (tramp-skeleton-make-process args nil nil
@@ -5360,9 +5366,7 @@ tramp-handle-make-process
 	   (env (dolist (elt process-environment env)
 		  (when (and
 			 (string-search "=" elt)
-			 (not
-			  (member
-			   elt (default-toplevel-value 'process-environment))))
+			 (not (tramp-local-environment-variable-p elt)))
 		    (setq env (cons elt env)))))
 	   ;; Add remote path if exists.
 	   (env (if-let* ((sh-file-name-handler-p)


> You could let-bind and modify tramp-remote-process-environment for
> tramp-sh-handle-make-process. Note, that this won't work for direct
> async processes, which use tramp-handle-make-process internally. And it
> won't work for tramp-sh-handle-process-file.
>
> Alternatively, you could call "env VAR1=VAL1 VAR2=VAL2 ... program ..."
> instead of "program ...".

Thanks for the suggestion. The problem is that
python-shell-with-environment is just a wrapper that temporarily sets
path and environment:

(defmacro python-shell-with-environment (&rest body)
   ...
  `(python-shell--with-environment
    (python-shell--calculate-process-environment)
    (lambda () ,@body)))

so we don't know what functions and programs users call.




This bug report was last modified 2 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.