macOS Monterey 12.3 will remove Python 2.7 (/usr/bin/python)

Standard

Hot on the heels of macOS Monterey 12.2, Apple have publicly released the macOS Monterey 12.3 Beta Release Notes.

Despite this being a point release, there are a few breaking changes.

The kernels for both the Dropbox Desktop Application and Microsoft OneDrive are called out as deprecated in the release notes, and as such both have updates and/or changes coming to overcome this change.

However, the more impactful change is the removal of Python 2 (/usr/bin/python).

This has a number of ramifications, and is really a very large change to drop in a point release.

See below for more details on this, and how it will likely affect every Mac Admin.

Why is this happening?

The /usr/bin/python binary is Python 2, which was sunset 2020-01-01.

So, from a security standpoint this change makes sense but removal in a point release of macOS is going to be painful.

Well, we were warned!

True, there have been prior warnings.

macOS Catalinas release notes stated:

Yet, when macOS Monterey was released, Python 2 (/usr/bin/python) was still included.

Instead, a warning was prompted when Python 2 (/usr/bin/python) was called, (see my prior blog post on this).

So yes, we have been warned. The surprise is more this change is coming in a point release, not macOS 13 (for example).

And, this change might surprise those whom have suppressed the deprecation prompts on Monterey too.

So, we can just run Python 3 as Apple recommend, right?

Nope! And for a few reasons.

First thing, Python 3 isn’t installed on macOS by default.

There is a file located at: /usr/bin/python3, but this is a stub and calling it will trigger the below (if Xcode hasn’t been installed and the developer tools installed):

Next, the path to the Python 3 which is installed by the above process is /usr/bin/python3 and Python 2 is located at: /usr/bin/python. And, /usr/bin/ cannot be modified by us mere mortals, as it’s protected by System Integrity Protection.

And, even if we could point /usr/bin/python to a Python 3 install:

Python 3 includes several changes which mean that backwards compatibility with Python 2 isn’t possible.

These changes are in part why Python 2 is still being used, despite Python 3 having been released on December 3, 2008.

What about #!/usr/bin/env python?

When things are calling #!/usr/bin/env python, they are telling the OS to traverse the directories shown in $PATH for a file named “python” and to then use that.

So, these will fail as they will likely not be able find a file or if they do find a file, it could be Python 3.

And, python -c?

This is the same as calling #!/usr/bin/env python, and as such as the same caveats.

What errors will we see?

It really depends on how the Python 2 was being invoked, but directly you’ll likely see something like:

/usr/bin/python: bad interpreter: No such file or directory

Ands maybe:

/usr/bin/python: command not found

So, now what?

Well, depends on what systems you’re using. But to generalise, you’ll want to check all your scripts and packages for occurrences of python -c , /usr/bin/python or /usr/bin/env python.

Below is some more specific guidance:

Jamf Pro

I’d once again recommend running Jamf Migrator against your Jamf Pro instance to download any scripts and Extension Attributes to check.

Munki

Download the “all” catalog (or each catalog separately), and check.

AutoPkg

Check your recipes and overrides for occurrences to /usr/bin/python or /usr/bin/env python.

General guidance:

Armin Briegel, aka scriptingosx, has a great script called pkgcheck which can traverse a directory looking for packages (of various formats, and even packages in DMG’s) and will advise if a packages preinstall or postinstall starts with a shebang of #!/usr/bin/python (amongst many other things).

So, pkgcheck is well worth running against your Munki Repo or Jamf Distribution Point (if you have a JCDS, you’ll need to replicate locally first).

Below is the output for Microsoft Teams 1.00.434557:

MSTeams-1.4.00.34557-434557
/Volumes/distribution/pkgs/Applications/Microsoft/MicrosoftTeams/MSTeams-1.4.00.34557-434557.pkg
Signature:      Developer ID Installer: Microsoft Corporation (UBF8T346G9)
Notarized:      Yes, Notarized Developer ID
Type:           Flat Distribution PKG
Version:        1.00.434557
Contains 1 component pkgs

    
    Type:           Flat Component PKG
    Identifier:     com.microsoft.teams
    Version:        1.00.434557
    Location:       /Applications
    Contains 9 resource files
    contextInstall.py has shebang #!/usr/bin/python
    fileLogger.py has shebang #!/usr/bin/python
    utility.py has shebang #!/usr/bin/python
    logger.py has shebang #!/usr/bin/python
    perfScenario.py has shebang #!/usr/bin/python
    startTeams.py has shebang #!/usr/bin/python

Anything else?

If you’re not running Monterey in production yet, spin up a VM on Monterey or update a Mac and run it through your deployment. Installing as many items as possible and running them too.

Make a note of any prompts you receive, and if you’re already running Monterey it might be worth deleting the below from your account to see if any prompts appear:

~/Library/PythonWrapper/promptedapps.plist

Next, update a few devices to 12.3 via Apple’s various beta programs.

Use this as your daily driver, there may be some surprises despite all the above checks:

It appears that the code binary is a simple bash script, with the below contents:

cat /usr/local/bin/code
#!/usr/bin/env bash
#
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.

function realpath() { python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" "$0"; }
CONTENTS="$(dirname "$(dirname "$(dirname "$(dirname "$(realpath "$0")")")")")"
ELECTRON="$CONTENTS/MacOS/Electron"
CLI="$CONTENTS/Resources/app/out/cli.js"
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --ms-enable-electron-run-as-node "$@"
exit $?

So, we found some Python 2 calls, now what?

This really depends on what and your organisations needs.

As an example, the Extension Attribute for jamJAR was ported from Python 2 to bash. This stopped the prompts on macOS Monterey 12.0-12.2, and means that for macOS Monterey 12.3 there is no change needed.

Whereas, this is a custom processor for an AutoPkg recipe which is written in Python 2. As AutoPkg ships it’s own Python 3, we can port the script to Python 3 and change the shebang to point to AutoPkg’s shipping Python.

When it comes to vendors products, reach out ASAP. As soon as you see that they are calling Python 2, point them to the macOS Monterey 12.3 release notes.

If it’s an open source project, I’d suggest raising an issue ASAP and ideally a PR soon after too.

What about Ruby and Perl?

Whilst macOS Catalinas release notes state that Ruby and Perl will not be included in future macOS in the same sentence as Python, there doesn’t appear to be any public timeline around their removal, but could be macOS 12.4!

18 thoughts on “macOS Monterey 12.3 will remove Python 2.7 (/usr/bin/python)

  1. Joss

    Couldn’t we install python 2.7.18 with MacPorts or Homebrew, then disable SIP, create a python symlink in /usr/bin, then reenable SIP? (Related question: does python@2 even come with arm64 support from MacPorts/Homebrew?)

    • Yes… and that’s great for your personal machine, or even a handful of machines. But have you tried automating that for hundreds or thousands of machine? If so I’m sure there are plenty of people who’d be happy. 😉

  2. That maybe could work.

    But you’re going through numerous hoops to really lessen the security of your Macs.

    Why is Python 2 still needed?

    • Joss

      Personally, I don’t need python2 in /usr/bin, so the whole SIP-on/off action wouldn’t be necessary. I am, however, still using two python2-based CLIs without any substitutes I know of, and they are way too complex for me to convert to python3. So for the time being I would have to continue to use python2 (via MacPorts). But it isn’t relevant anyway if you’re on arm64: python v3.9.1 seems to be the minimum supported version for that platform.

      • RA

        I tried the SIP on/off and creating the symlink but it seems like /usr/bin is read-only even after disabling the SIP and mount -uw / doesn’t work.

  3. Paul M

    it’s not like people haven’t had years and YEARS of notice of the end of py2.7. It was EOL in January 2020, and there were years of warnings before then!

  4. Paul M

    p.s. remember how after Y2K bug passed and people said “see, nothing bad happened”, and all of us in IT said “that’s because we prepared for it”. Well, this is the similar situation with python, and many people did nothing, and look where you are now. Sorry-not-sorry.

Leave a Reply to Paul MCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.