https://github.com/python/cpython/commit/9cfa4dfe05539479a6aa652ee7df0691f39b3cc7
commit: 9cfa4dfe05539479a6aa652ee7df0691f39b3cc7
branch: 3.13
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: ned-deily <n...@python.org>
date: 2025-08-06T07:43:54-04:00
summary:

[3.13] gh-137450: macOS installer shell path management improvements 
(GH-137451) (#137452)

Separate the installer `Shell profile updater` postinstall script from the 
`Update Shell Profile.command` to enable more robust error handling.
(cherry picked from commit 781eb1a688e0575a38c79575493f3ff83208a33e)

Co-authored-by: Ned Deily <n...@python.org>

files:
A Mac/BuildScript/resources/update_shell_profile.command
A Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst
M Mac/BuildScript/build-installer.py
M Mac/BuildScript/scripts/postflight.patch-profile

diff --git a/Mac/BuildScript/build-installer.py 
b/Mac/BuildScript/build-installer.py
index b31cb766a468f4..17d258dd98f174 100755
--- a/Mac/BuildScript/build-installer.py
+++ b/Mac/BuildScript/build-installer.py
@@ -1747,7 +1747,7 @@ def main():
     fn = os.path.join(folder, "ReadMe.rtf")
     patchFile("resources/ReadMe.rtf",  fn)
     fn = os.path.join(folder, "Update Shell Profile.command")
-    patchScript("scripts/postflight.patch-profile",  fn)
+    patchScript("resources/update_shell_profile.command",  fn)
     fn = os.path.join(folder, "Install Certificates.command")
     patchScript("resources/install_certificates.command",  fn)
     os.chmod(folder, STAT_0o755)
diff --git a/Mac/BuildScript/resources/update_shell_profile.command 
b/Mac/BuildScript/resources/update_shell_profile.command
new file mode 100755
index 00000000000000..3cf4d74de9f09a
--- /dev/null
+++ b/Mac/BuildScript/resources/update_shell_profile.command
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+echo "This script will update your shell profile when the 'bin' directory"
+echo "of python is not early enough of the PATH of your shell."
+echo "These changes will be effective only in shell windows that you open"
+echo "after running this script."
+
+PYVER=@PYVER@
+PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
+
+if [ `id -ur` = 0 ]; then
+       # Run from the installer, do some trickery to fetch the information
+       # we need.
+       theShell="`finger $USER | grep Shell: | head  -1 | awk '{ print $NF }'`"
+
+else
+       theShell="${SHELL}"
+fi
+
+# Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
+BSH="`basename "${theShell}"`"
+case "${BSH}" in
+bash|ksh|sh|*csh|zsh|fish)
+       if [ `id -ur` = 0 ]; then
+               P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 
'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'`
+       else
+               P="`(exec -l ${theShell} -c 'echo $PATH')`"
+       fi
+       ;;
+*)
+       echo "Sorry, I don't know how to patch $BSH shells"
+       exit 0
+       ;;
+esac
+
+# Now ensure that our bin directory is on $P and before /usr/bin at that
+for elem in `echo $P | tr ':' ' '`
+do
+       if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
+               echo "All right, you're a python lover already"
+               exit 0
+       elif [ "${elem}" = "/usr/bin" ]; then
+               break
+       fi
+done
+
+echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
+case "${BSH}" in
+*csh)
+       if [ -f "${HOME}/.tcshrc" ]; then
+               RC="${HOME}/.tcshrc"
+       else
+               RC="${HOME}/.cshrc"
+       fi
+       # Create backup copy before patching
+       if [ -f "${RC}" ]; then
+               cp -fp "${RC}" "${RC}.pysave"
+       fi
+       echo "" >> "${RC}"
+       echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
+       echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
+       echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
+       if [ `id -ur` = 0 ]; then
+               chown -h "${USER}" "${RC}"
+       fi
+       exit 0
+       ;;
+bash)
+       if [ -e "${HOME}/.bash_profile" ]; then
+               PR="${HOME}/.bash_profile"
+       elif [ -e "${HOME}/.bash_login" ]; then
+               PR="${HOME}/.bash_login"
+       elif [ -e "${HOME}/.profile" ]; then
+               PR="${HOME}/.profile"
+       else
+               PR="${HOME}/.bash_profile"
+       fi
+       ;;
+fish)
+       CONFIG_DIR="${HOME}/.config/fish/conf.d/"
+       RC="${CONFIG_DIR}/python-${PYVER}.fish"
+       mkdir -p "$CONFIG_DIR"
+       if [ -f "${RC}" ]; then
+               cp -fp "${RC}" "${RC}.pysave"
+       fi
+       echo "# Setting PATH for Python ${PYVER}" > "${RC}"
+       if [ -f "${RC}.pysave" ]; then
+               echo "# The original version is saved in ${RC}.pysave" >> 
"${RC}"
+       fi
+       echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
+       if [ `id -ur` = 0 ]; then
+               chown -h "${USER}" "${RC}"
+       fi
+       exit 0
+       ;;
+zsh)
+        PR="${HOME}/.zprofile"
+        ;;
+*sh)
+       PR="${HOME}/.profile"
+       ;;
+esac
+
+# Create backup copy before patching
+if [ -f "${PR}" ]; then
+       cp -fp "${PR}" "${PR}.pysave"
+fi
+echo "" >> "${PR}"
+echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
+echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
+echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
+echo 'export PATH' >> "${PR}"
+if [ `id -ur` = 0 ]; then
+       chown -h "${USER}" "${PR}"
+fi
+exit 0
diff --git a/Mac/BuildScript/scripts/postflight.patch-profile 
b/Mac/BuildScript/scripts/postflight.patch-profile
index 9caf62211ddd16..ce8720f895d1b5 100755
--- a/Mac/BuildScript/scripts/postflight.patch-profile
+++ b/Mac/BuildScript/scripts/postflight.patch-profile
@@ -1,116 +1,104 @@
 #!/bin/sh
 
-echo "This script will update your shell profile when the 'bin' directory"
-echo "of python is not early enough of the PATH of your shell."
-echo "These changes will be effective only in shell windows that you open"
-echo "after running this script."
-
 PYVER=@PYVER@
 PYTHON_ROOT="/Library/Frameworks/Python.framework/Versions/@PYVER@"
 
-if [ `id -ur` = 0 ]; then
-       # Run from the installer, do some trickery to fetch the information
-       # we need.
-       theShell="`finger $USER | grep Shell: | head  -1 | awk '{ print $NF }'`"
 
-else
-       theShell="${SHELL}"
-fi
+# Run from the installer, do some trickery to fetch the information
+# we need.
+theShell="`finger $USER | grep Shell: | head  -1 | awk '{ print $NF }'`"
 
 # Make sure the directory ${PYTHON_ROOT}/bin is on the users PATH.
 BSH="`basename "${theShell}"`"
 case "${BSH}" in
 bash|ksh|sh|*csh|zsh|fish)
-       if [ `id -ur` = 0 ]; then
-               P=`su - ${USER} -c 'echo A-X-4-X@@$PATH@@X-4-X-A' | grep 
'A-X-4-X@@.*@@X-4-X-A' | sed -e 's/^A-X-4-X@@//g' -e 's/@@X-4-X-A$//g'`
-       else
-               P="`(exec -l ${theShell} -c 'echo $PATH')`"
-       fi
-       ;;
+    true
+    ;;
 *)
-       echo "Sorry, I don't know how to patch $BSH shells"
-       exit 0
-       ;;
+    exit 0
+    ;;
 esac
 
-# Now ensure that our bin directory is on $P and before /usr/bin at that
-for elem in `echo $P | tr ':' ' '`
-do
-       if [ "${elem}" = "${PYTHON_ROOT}/bin" ]; then
-               echo "All right, you're a python lover already"
-               exit 0
-       elif [ "${elem}" = "/usr/bin" ]; then
-               break
-       fi
-done
-
-echo "${PYTHON_ROOT}/bin is not on your PATH or at least not early enough"
 case "${BSH}" in
 *csh)
-       if [ -f "${HOME}/.tcshrc" ]; then
-               RC="${HOME}/.tcshrc"
-       else
-               RC="${HOME}/.cshrc"
-       fi
-       # Create backup copy before patching
-       if [ -f "${RC}" ]; then
-               cp -fp "${RC}" "${RC}.pysave"
-       fi
-       echo "" >> "${RC}"
-       echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
-       echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
-       echo "set path=(${PYTHON_ROOT}/bin "'$path'")" >> "${RC}"
-       if [ `id -ur` = 0 ]; then
-               chown "${USER}" "${RC}"
-       fi
-       exit 0
-       ;;
+    if [ -f "${HOME}/.tcshrc" ]; then
+        RC="${HOME}/.tcshrc"
+    else
+        RC="${HOME}/.cshrc"
+    fi
+
+    # Drop privileges while writing files.
+    su -m ${USER} <<EOFC
+    # Create backup copy before patching
+    if [ -f "${RC}" ]; then
+        cp -fp "${RC}" "${RC}.pysave"
+    fi
+    echo "" >> "${RC}"
+    echo "# Setting PATH for Python ${PYVER}" >> "${RC}"
+    echo "# The original version is saved in .cshrc.pysave" >> "${RC}"
+    echo "set path=(${PYTHON_ROOT}/bin "'\$path'")" >> "${RC}"
+EOFC
+
+    if [ `id -ur` = 0 ]; then
+        chown -h "${USER}" "${RC}"
+    fi
+    exit 0
+    ;;
 bash)
-       if [ -e "${HOME}/.bash_profile" ]; then
-               PR="${HOME}/.bash_profile"
-       elif [ -e "${HOME}/.bash_login" ]; then
-               PR="${HOME}/.bash_login"
-       elif [ -e "${HOME}/.profile" ]; then
-               PR="${HOME}/.profile"
-       else
-               PR="${HOME}/.bash_profile"
-       fi
-       ;;
+    if [ -e "${HOME}/.bash_profile" ]; then
+        PR="${HOME}/.bash_profile"
+    elif [ -e "${HOME}/.bash_login" ]; then
+        PR="${HOME}/.bash_login"
+    elif [ -e "${HOME}/.profile" ]; then
+        PR="${HOME}/.profile"
+    else
+        PR="${HOME}/.bash_profile"
+    fi
+    ;;
 fish)
-       CONFIG_DIR="${HOME}/.config/fish/conf.d/"
-       RC="${CONFIG_DIR}/python-${PYVER}.fish"
-       mkdir -p "$CONFIG_DIR"
-       if [ -f "${RC}" ]; then
-               cp -fp "${RC}" "${RC}.pysave"
-       fi
-       echo "# Setting PATH for Python ${PYVER}" > "${RC}"
-       if [ -f "${RC}.pysave" ]; then
-               echo "# The original version is saved in ${RC}.pysave" >> 
"${RC}"
-       fi
-       echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
-       if [ `id -ur` = 0 ]; then
-               chown "${USER}" "${RC}"
-       fi
-       exit 0
-       ;;
+    CONFIG_DIR="${HOME}/.config/fish/conf.d/"
+    RC="${CONFIG_DIR}/python-${PYVER}.fish"
+
+    # Drop privileges while writing files.
+    su -m ${USER} <<EOFF
+    mkdir -p "$CONFIG_DIR"
+    if [ -f "${RC}" ]; then
+        cp -fp "${RC}" "${RC}.pysave"
+    fi
+    echo "# Setting PATH for Python ${PYVER}" > "${RC}"
+    if [ -f "${RC}.pysave" ]; then
+        echo "# The original version is saved in ${RC}.pysave" >> "${RC}"
+    fi
+    echo "fish_add_path -g \"${PYTHON_ROOT}/bin\"" >> "${RC}"
+EOFF
+
+    if [ `id -ur` = 0 ]; then
+        chown -h "${USER}" "${RC}"
+    fi
+    exit 0
+    ;;
 zsh)
-        PR="${HOME}/.zprofile"
-        ;;
+    PR="${HOME}/.zprofile"
+    ;;
 *sh)
-       PR="${HOME}/.profile"
-       ;;
+    PR="${HOME}/.profile"
+    ;;
 esac
 
+# Drop privileges while writing files.
+su -m ${USER} <<EOFS
 # Create backup copy before patching
 if [ -f "${PR}" ]; then
-       cp -fp "${PR}" "${PR}.pysave"
+    cp -fp "${PR}" "${PR}.pysave"
 fi
 echo "" >> "${PR}"
 echo "# Setting PATH for Python ${PYVER}" >> "${PR}"
 echo "# The original version is saved in `basename ${PR}`.pysave" >> "${PR}"
-echo 'PATH="'"${PYTHON_ROOT}/bin"':${PATH}"' >> "${PR}"
+echo 'PATH="'"${PYTHON_ROOT}/bin"':\${PATH}"' >> "${PR}"
 echo 'export PATH' >> "${PR}"
+EOFS
+
 if [ `id -ur` = 0 ]; then
-       chown "${USER}" "${PR}"
+    chown -h "${USER}" "${PR}"
 fi
 exit 0
diff --git 
a/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst 
b/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst
new file mode 100644
index 00000000000000..5efd74660c95d2
--- /dev/null
+++ b/Misc/NEWS.d/next/macOS/2025-08-06-06-29-12.gh-issue-137450.JZypb7.rst
@@ -0,0 +1,3 @@
+macOS installer shell path management improvements: separate the installer
+``Shell profile updater`` postinstall script from the
+``Update Shell Profile.command`` to enable more robust error handling.

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to