📄 Page
1
(This page has no text content)
📄 Page
2
Hypermodern Python Tooling Building Reliable Workflows for an Evolving Python Ecosystem With Early Release ebooks, you get books in their earliest form—the author’s raw and unedited content as they write—so you can take advantage of these technologies long before the official release of these titles. Claudio Jolowicz
📄 Page
3
Hypermodern Python Tooling by Claudio Jolowicz Copyright © 2024 Claudio Jolowicz. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (https://oreilly.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: Brian Guerin Development Editor: Sarah Grey Production Editor: Gregory Hyman Interior Designer: David Futato Cover Designer: Karen Montgomery Illustrator: Kate Dullea April 2024: First Edition Revision History for the Early Release 2022-11-01: First Release 2023-01-31: Second Release See https://oreilly.com/catalog/errata.csp?isbn=9781098139582 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Hypermodern Python Tooling, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the author, and do not represent the publisher’s views. While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. 978-1-098-13958-2
📄 Page
4
Chapter 1. Installing Python A NOTE FOR EARLY RELEASE READERS With Early Release ebooks, you get books in their earliest form—the author’s raw and unedited content as they write—so you can take advantage of these technologies long before the official release of these titles. This will be the first chapter of the final book. Please note that the GitHub repo will be made active later on. If you have comments about how we might improve the content and/or examples in this book, or if you notice missing material within this chapter, please reach out to the author at mail@claudiojolowicz.com. If you’ve picked up this book, you likely have Python installed on your machine already. Most common operating systems ship with a python or python3 command. This can be the interpreter used by the system itself or a shim that installs Python for you when you invoke it for the first time. Why dedicate an entire chapter to the topic if it’s so easy to get Python onto a new machine? The answer is that installing Python for long-term development can be a complex matter, and there are several reasons for this: You generally need multiple versions of Python installed side-by-side. (If you’re wondering why, we’ll get to that shortly.) There are a few different ways to install Python across the common platforms, each with unique advantages, tradeoffs, and sometimes pitfalls. Python is a moving target: You need to keep existing installations up-to-date with the latest maintenance release, add installations when a new feature version is published, and remove versions that are no longer supported. You may even need to test a prerelease of the next Python. You may want your code to run on multiple platforms. While Python makes it easy to write portable programs, setting up a developer environment requires some familiarity with the idiosyncrasies of each platform. You may want to run your code with an alternative implementation of Python. In this first chapter, I’ll show you how to install multiple Python versions on some of the major operating systems in a sustainable way, and how to keep your little snake farm in good shape. 1
📄 Page
5
TIP If you only develop for a single platform, feel free to skip ahead to your preferred platform. I’d encourage you to learn about working with Python on other operating systems though. It’s fun— and familiarity with other platforms enables you to provide a better experience to the contributors and users of your software. Supporting Multiple Versions of Python Python programs often target several versions of the language and standard library at once. This may come as a surprise. Why would you run your code with anything but the latest Python? After all, this lets your programs benefit from new language features and library improvements immediately. As it turns out, runtime environments often come with a variety of older versions of Python. Even if you have tight control over your deployment environments, you may want to get into the habit of testing against multiple versions. The day the trusty Python in your production environment features in a security advisory better not be the day you start porting your code to newer releases. For these reasons, it is common to support both current and past versions of Python until their official end-of-life date, and to set up installations for them side-by-side on a developer machine. With new feature versions coming out every year and support extending over five years, this gives you a testing matrix of five actively supported versions (see Figure 1-1). If that sounds like a lot of work, don’t worry: the Python ecosystem comes with tooling that makes this a breeze. 2
📄 Page
6
THE PYTHON RELEASE CYCLE Python has an annual release cycle: feature releases happen every October. Each feature release gets a new minor version in Python’s major.minor.micro scheme. By contrast, new major versions are rare and reserved for strongly incompatible changes— at the time of writing this book, a Python 4 is not in sight. Python’s backward compatibility policy allows incompatible changes in minor releases when preceded by a two-year deprecation period. Feature versions are maintained for five years, after which they reach end-of-life. Bugfix releases for a feature version occur roughly every other month during the first 18 months after its initial release. This is followed by security updates whenever necessary during the remainder of the five- year support period. Each maintenance release bumps the micro version. Prereleases for upcoming Python feature releases happen throughout the year before their publication. These prereleases fall into three consecutive phases: alphas, betas, and release candidates. You can recognize them by the suffix that gets appended to the upcoming Python version, indicating the release status and sequence number, such as a1, b3, rc2. Figure 1-1. Timeline of Python Releases Locating Python Interpreters How do you select the correct Python interpreter if you have multiple ones on your system? Let’s look at a concrete example. When you type python at the command line, the shell searches the directories in the PATH environment variable from left to right and invokes the first executable file named python. Most Python installations also provide versioned commands named python3.x, letting you disambiguate between different feature versions. NOTE On Windows, PATH-based interpreter discovery is far less relevant because Python installations can be located via the Windows Registry (see “The Python Launcher for Windows”).
📄 Page
7
A common default for the PATH variable is /usr/local/bin:/usr/bin:/bin on Unix-like systems. You can modify the variable using the export builtin of many shells. Here’s how you would add a Python installation in /usr/local/opt/python using the Bash shell: export PATH="/usr/local/opt/python/bin:$PATH" Note that you’re adding the bin subdirectory instead of the installation root, because that’s where the interpreter is normally located on these systems. We’ll take a closer look at the layout of Python installations in Chapter 2. The line above also works with the Zsh shell, which is the default on macOS. That said, there’s a more idiomatic way to manipulate the search path on Zsh: typeset -U path path=(/usr/local/opt/python/bin $path) This instructs the shell to remove duplicate entries from the search path.e shell keeps the path array synchroniz d with the PATH variable. The Fish shell offers a function to uniquely and persistently prepend an entry to the search path: fish_add_path /usr/local/opt/python/bin It would be tedious to set up the search path manually at the start of every shell session. Instead, you can place the commands above in your shell profile—this is a file in your home directory that is read by the shell on startup. Table 1-1 shows the most common ones: Table 1-1. The startup files of some common shells Shell Startup file Bash .bash_profile or .profile (Debian and Ubuntu) Zsh .zshrc Fish .config/fish/fish.config The order of directories on the search path matters because earlier entries take precedence over, or “shadow”, later ones. You’ll often add Python versions against a backdrop of existing installations, such as the interpreter used by the operating system, and you want the shell to choose your installations over those present elsewhere.
📄 Page
8
TIP Unless your system already comes with a well-curated and up-to-date selection of interpreters, prepend Python installations to the PATH environment variable, with the latest stable version at the very front. Figure 1-2 shows a macOS machine with several Python installations. Starting from the bottom, the first interpreter is located in /usr/bin and part of Apple’s Command Line Tools (Python 3.8). Next up, in /usr/local/bin, are several interpreters from the Homebrew distribution; the python3 command here is its main interpreter (Python 3.10). The Homebrew interpreters are followed by a prerelease from python.org (Python 3.12). The top entries contain the current release (Python 3.11), also from Homebrew.
📄 Page
9
(This page has no text content)
📄 Page
10
Figure 1-2. A developer system with multiple Python installations. The search path is displayed as a stack of directories; commands at the top shadow those further down. A SHORT HISTORY OF PATH Curiously, the PATH mechanism has remained essentially the same since the 1970s. In the original design of the Unix operating system, the shell still looked up commands entered by the user in a directory named /bin. With the 3rd edition of Unix (1973), this directory—or rather, the 256K drive that backed it— became too small to hold all available programs. Researchers at Bell Labs introduced an additional filesystem hierarchy rooted at /usr, allowing a second disk to be mounted. But now the shell had to search for programs across multiple directories—/bin and /usr/bin. Eventually, the Unix designers settled on storing the list of directories in an environment variable named PATH. Since every process inherits its own copy of the environment, users can customize their search path without affecting system processes. Installing Python on Windows The core Python team provides official binary installers in the Downloads for Windows section of the Python website. Locate the latest release of each Python version you wish to support, and download the 64-bit Windows installer for each. NOTE Depending on your domain and target environment, you may prefer to use the Windows Subsystem for Linux (WSL) for Python development. In this case, please refer to the section “Installing Python on Linux” instead. In general, there should be little need to customize the installation—with one exception: When installing the latest stable release (and only then), enable the option to add Python to your PATH environment variable on the first page of the installer dialog. This ensures that your default python command uses a well-known and up-to-date Python. The python.org installers are an efficient way to set up multi-version Python environments on Windows, for several reasons: They register each Python installation with the Windows Registry, making it easy for developer tools to discover interpreters on the system (see “The Python Launcher for Windows”.) They don’t have some disadvantages of redistributed versions of Python, such as lagging behind the official release, or being subject to downstream modifications. They don’t require you to build the Python interpreter, which—apart from taking precious time— involves setting up Python’s build dependencies on your system. Binary installers are only provided up to the last bugfix release of each Python version, which occurs around 18 months after the initial release. Security updates for older versions, on the other hand, are 3
📄 Page
11
provided as source distributions only. For these, you’ll need to build Python from source or use an alternative installer such as Conda (see “Installing Python from Anaconda”). Keeping Python installations up-to-date falls on your shoulders when you’re using the binary installers from python.org. New releases are announced in many places, including the Python blog and the Python Discourse. When you install a bugfix release for a Python version that is already present on the system, it will replace the existing installation. This preserves virtual environments and developer tools on the upgraded Python version and should be a seamless experience. When you install a new feature release of Python, there are some additional steps to be mindful of: Enable the option to add the new Python to the PATH environment variable. Remove the previous Python release from PATH. Instead of modifying the environment variable manually, you can re-run its installer in maintenance mode, using the Apps and Features tool that is part of Windows. Locate the entry for the previous Python in the list of installed software, and choose the Modify action from the context menu. You may also wish to reinstall some of your developer tooling, to ensure that it runs on the latest Python version. Eventually, a Python version will reach its end of life, and you may wish to uninstall it to free up resources. You can remove an existing installation using the Apps and Features tool. Choose the Uninstall action for its entry in the list of installed software. Beware that removing a Python version will break virtual environments and developer tools that are still using it, so you should upgrade those beforehand. MICROSOFT STORE PYTHON Windows systems ship with a python stub that redirects the user to the latest Python package on the Microsoft Store. The Microsoft Store package is intended mainly for educational purposes, and does not have full write access to some shared locations on the filesystem and the registry. While it’s useful for teaching Python to beginners, I would not recommend it for most intermediate and advanced Python development. The Python Launcher for Windows Python development on Windows is special in that tooling can locate Python installations via the Windows Registry. The Python Launcher for Windows leverages this to provide a single entry point to interpreters on the system. It is a utility included with every python.org release and associated with Python file extensions, allowing you to launch scripts from the Windows File Explorer. Running applications with a double-click is handy, but the Python Launcher is at its most powerful when you invoke it from a command-line prompt. Open a Powershell window and run the py command to start an interactive session: > py 3
📄 Page
12
Python 3.10.5 (tags/v3.10.6:f377153, Jun 6 2022, 16:14:13) [...] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> By default, the Python Launcher selects the most recent version of Python installed on the system. It’s worth noting that this may not be the same as the most recently installed version on the system. This is good—you don’t want your default Python to change when you install a bugfix release for an older version. If you want to launch a specific version of the interpreter, you can pass the feature version as a command-line option: > py -3.9 Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [...] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> Any remaining arguments to py are forwarded to the selected interpreter. Let’s see how you would display the versions of two interpreters on the system: > py -V Python 3.10.5 > py -3.9 -V Python 3.9.13 Using the same mechanism, you can run a script on a specific interpreter: > py -3.9 path\to\script.py If you don’t specify a version, py inspects the first line of the script to see if a version is specified there, in the form #!python3.x. Both the line itself and the version inside are optional; when omitted, py defaults to the latest interpreter. You can also include a leading path as in #!/usr/bin/python (a standard location on Unix systems) and py will conveniently ignore this part; this lets you install the same script on Windows and Unix-like systems. NOTE You may have recognized the #! line as what’s known as a shebang on Unix-like operating systems. On these systems, the program loader uses it to locate and launch the interpreter for the script. If the script is installed as a module, you can also pass its import name to the -m interpreter option: > py -m module Perhaps the most important example of this technique is installing a third-party package with Pip, the Python package installer:
📄 Page
13
> py -m pip install package Pip installs packages into its own environment, so invoking it via the Python Launcher lets you control where a package is installed. The explicit form is almost always what you want, so you should prefer it over the shorter pip install as a matter of routine. As you have seen, the Python Launcher defaults to the newest version on the system. There is an exception to this rule if a virtual environment is active. In this case, py defaults to the interpreter in the virtual environment. (You can think of virtual environments as lightweight satellites of a full Python installation; I’ll talk more about them in Chapter 2.) In the following example session using Powershell, you create and activate a virtual environment using an older interpreter version, then switch back to the global environment: > py -V Python 3.10.5 > py -3.9 -m venv venv-3.9 > venv-3.9\Scripts\activate (venv-3.9) > py -V Python 3.9.13 (venv-3.9) > deactivate > py -V Python 3.10.5 WARNING Do not pass the version to py when you have a virtual environment activated. This would cause py to select the global Python installation, even if the version matches the interpreter inside the active environment. The Python Launcher defaults to the latest Python version on the system even if that happens to be a prerelease. You can override this default persistently by setting the PY_PYTHON and PY_PYTHON3 environment variables to the current stable release: > setx PY_PYTHON 3.x > setx PY_PYTHON3 3.x Restart the console for the setting to take effect. Don’t forget to remove these variables once you upgrade to the final release. To conclude our short tour of the Python Launcher, use the command py --list to enumerate the interpreters on your system: > py --list -V:3.11 Python 3.11 (64-bit) -V:3.10 * Python 3.10 (64-bit) -V:3.9 Python 3.9 (64-bit) In this listing, the asterisk marks the default version of Python. 4
📄 Page
14
Installing Python on macOS You can install Python on macOS in several ways. In this section, I’ll take a look at the Homebrew package manager and the official python.org installers. Both provide multi-version binary distributions of Python. Some installation methods that are common on Linux—such as Pyenv—also work on macOS. The Conda package manager even supports Windows, macOS, and Linux. I’ll talk about them in later sections. PYTHON FROM APPLE’S COMMAND LINE TOOLS macOS ships with a python3 stub that installs Apple’s Command Line Tools when you run it for the first time, including an older version of Python. While it’s good to know about Python commands on your system, other distributions will serve you better; they allow you to develop with Python versions of your choice. Homebrew Python Homebrew is a third-party package manager for macOS and Linux. It provides an overlay distribution, an open-source software collection that you install on top of the existing operating system. Installing the package manager is straightforward; refer to the official website for instructions. Homebrew distributes packages for every maintained feature version of Python. Use the brew command-line interface to manage them: brew install python@3.x Install a new Python version. brew upgrade python@3.x Upgrade a Python version to a maintenance release. brew uninstall python@3.x Uninstall a Python version. You may find that you already have some Python versions installed for other Homebrew packages that depend on them. Nonetheless, it’s important that you install every version explicitly. Automatically installed packages may get deleted when you run brew autoremove to clean up resources. Homebrew places a python3.x command for each version on your PATH, as well as a python3 command for its main Python package—which may be either the current or the previous stable release. You should override this to ensure both python and python3 point to the latest version. First, query the package manager for the installation root (which is platform-dependent): $ brew --prefix python@3.10 /opt/homebrew/opt/python@3.10
📄 Page
15
Next, prepend the bin and libexec/bin directories from this installation to your PATH. Here’s an example that works on the Bash shell: export PATH="/opt/homebrew/opt/python@3.10/bin:$PATH" export PATH="/opt/homebrew/opt/python@3.10/libexec/bin:$PATH" Homebrew has some advantages over the official python.org installers: You can use the command line to install, upgrade, and uninstall Python versions. Homebrew includes security releases for older versions—by contrast, python.org installers are provided up to the last bugfix release only. Homebrew Python is tightly integrated with the rest of the distribution. In particular, the package manager can satisfy Python dependencies like OpenSSL. This gives you the option to upgrade them independently when needed. On the other hand, Homebrew Python also comes with some limitations and caveats: Homebrew Python is used by some other packages in the distribution. Beware that using Pip to install or uninstall Python packages system-wide can affect—and, in the worst case, break—those packages. Packages generally lag a few days or weeks behind official releases. They also contain some downstream modifications, although these are quite reasonable. For example, Homebrew separates modules related to graphical user interfaces (GUI) from the main Python package. Homebrew does not package prereleases of upcoming Python versions. By default, Homebrew upgrades Python to maintenance releases automatically. This won’t break virtual environments and developer tools, though: They reference the interpreter using a symbolic link—a special kind of file that points to another file, much like a shortcut in Windows—that remains stable for all releases of the same feature version. TIP Personally, I recommend Homebrew for managing Python on macOS—it’s well-integrated with the rest of the system and easy to keep up-to-date. Use the python.org installers to test your code against prereleases, which are not available from Homebrew. The python.org Installers The core Python team provides official binary installers in the Downloads for macOS section of the Python website. Download the 64-bit universal2 installer for the release you wish to install. The universal2 binaries of the interpreter run natively on both Apple Silicon and Intel chips. For multi-version development, I recommend a custom install—watch out for the Customize button in the installer dialog. In the ensuing list of installable components, disable the UNIX command-line tools
📄 Page
16
and the Shell profile updater. Both options are designed to put the interpreter and some other commands on your PATH. Instead, you should edit your shell profile manually. Prepend the directory /Library/Frameworks/Python.framework/Versions/3.x/bin to PATH, replacing 3.x with the actual feature version. Make sure that the current stable release stays at the front of PATH. NOTE After installing a Python version, run the Install Certificates command located in the /Applications/Python 3.x/ folder. This command installs Mozilla’s curated collection of root certificates. When you install a bugfix release for a Python version that is already present on the system, it will replace the existing installation. Uninstalling a Python version is done by removing these two directories: /Library/Frameworks/Python.framework/Versions/3.x/ /Applications/Python 3.x/ FRAMEWORK BUILDS ON MACOS Most Python installations on a Mac are so-called framework builds. Frameworks are a macOS concept for a “versioned bundle of shared resources.” You may have come across bundles before, in the form of apps in the Applications folder. A bundle is just a directory with a standard layout, keeping all the files in one place. Frameworks contain multiple versions side-by-side in directories named Versions/3.x. One of these is designated as the current version using a Versions/Current symlink. Under each version in a Python Framework, you can find a conventional Python installation layout with bin and lib directories. Installing Python on Linux The core Python team does not provide binary installers for Linux. Generally, the preferred way to install software on Linux distributions is using the official package manager. However, this is not unequivocally true when installing Python for development—here are some important caveats: The system Python in a Linux distribution may be quite old, and not every distribution includes alternate Python versions in their main package repositories. Linux distributions have mandatory rules about how applications and libraries may be packaged. For example, Debian’s Python Policy mandates that the standard ensurepip module must be shipped in a separate package; as a result, you can’t create virtual environments on a default Debian system (a situation commonly fixed by installing the python3-full package.) The main Python package in a Linux distribution serves as the foundation for other packages that 5
📄 Page
17
require a Python interpreter. These packages may include critical parts of the system, such as Fedora’s package manager dnf. Distributions therefore apply safeguards to protect the integrity of the system; for example, they often limit your ability to use Pip outside of a virtual environment. In the next sections, I’ll take a look at installing Python on two major Linux distributions, Fedora and Ubuntu. Afterwards, I’ll cover some generic installation methods that don’t use the official package manager. I’ll also introduce you to the Python Launcher for Unix, a third-party package that aims to bring the py utility to Linux, macOS, and similar systems. Fedora Linux Fedora is an open-source Linux distribution, sponsored primarily by Red Hat, and the upstream source for Red Hat Enterprise Linux (RHEL). It aims to stay close to upstream projects and uses a rapid release cycle to foster innovation. Fedora is renowned for its excellent Python support, with Red Hat employing several Python core developers. Python comes pre-installed on Fedora, and you can install additional Python versions using dnf, its package manager: sudo dnf install python3.x Install a new Python version. sudo dnf upgrade python3.x Upgrade a Python version to a maintenance release. sudo dnf remove python3.x Uninstall a Python version. Fedora has packages for all active feature versions and prereleases of CPython, the reference implementation of Python, as well as packages with alternative implementations like PyPy. A convenient shorthand to install all of these at once is to install tox: $ sudo dnf install tox In case you’re wondering, tox is a test automation tool that makes it easy to run a test suite against multiple versions of Python (see [Link to Come]); its Fedora package pulls in most available interpreters as recommended dependencies. Ubuntu Linux Ubuntu is a popular Linux distribution based on Debian and funded by Canonical Ltd. Ubuntu only ships a single version of Python in its main repositories; other versions of Python, including prereleases, are provided by a Personal Package Archive (PPA). A PPA is a community-maintained software repository on Launchpad, the software collaboration platform run by Canonical.
📄 Page
18
Your first step on an Ubuntu system should be to add the deadsnakes PPA: $ sudo apt update && sudo apt install software-properties-common $ sudo add-apt-repository ppa:deadsnakes/ppa && sudo apt update You can now install Python versions using the apt package manager: sudo apt install python3.x-full Install a new Python version. sudo apt upgrade python3.x-full Upgrade a Python version to a maintenance release. sudo apt remove python3.x-full Uninstall a Python version. TIP Always remember to include the -full suffix when installing Python on Debian and Ubuntu. The python3.x-full packages pull in the entire standard library and up-to-date root certificates. In particular, they ensure you’re able to create virtual environments. Other Linux Distributions What do you do if your Linux distribution does not package multiple versions of Python? The traditional answer is “roll your own Python”. This may seem scary, but we’ll see how straightforward building Python has become these days in “Installing Python with Pyenv”. However, it turns out that building from source is not your only option. Several cross-platform package managers provide binary packages of Python; in fact, we’ve already seen one of them. The Homebrew distribution (see “Homebrew Python”) is available on macOS and Linux, and most of what we said above applies to Linux as well. The main difference between both platforms is the installation root: Homebrew on Linux installs packages under /home/linuxbrew/.linuxbrew by default instead of /opt/homebrew. Keep this in mind when adding Homebrew’s Python installations to your PATH. A popular cross-platform way to install Python is the Anaconda distribution, which is targeted at scientific computing and supports Windows, macOS, and Linux. We’ll cover Anaconda in a separate section at the end of this chapter (see “Installing Python from Anaconda”).
📄 Page
19
THE NIX PACKAGE MANAGER Another fascinating option for both macOS and Linux is Nix, a purely functional package manager with reproducible builds of thousands of software packages. Nix makes it easy and fast to set up isolated environments with arbitrary versions of software packages. Here’s how you would set up a development environment with two Python versions: $ nix-shell --packages python310 python39 [nix-shell]$ python -V 3.10.6 [nix-shell]$ python3.9 -V 3.9.13 [nix-shell]$ exit Before dropping you into the environment, Nix transparently downloads pre-built Python binaries from the Nix Packages Collection and adds them to your PATH. Each package gets a unique subdirectory on the local filesystem, using a cryptographic hash that captures all its dependencies. I won’t go into the details of installing and using Nix in this book. If you have Docker installed, you can get a taste of what’s possible using the Docker image for NixOS, a Linux distribution built entirely using Nix: $ docker run -it nixos/nix The Python Launcher for Unix The Python Launcher for Unix is a port of the official py utility to Linux and macOS, as well as any other operating system supporting the Rust programming language. You can install the python- launcher package with a number of package managers, including brew, dnf, and cargo. Generally, it works much like its Windows counterpart (see “The Python Launcher for Windows”): $ py -V 3.10.6 $ py -3.9 -V 3.9.13 $ py --list 3.10 │ /usr/local/opt/python@3.10/bin/python3.10 3.9 │ /usr/local/opt/python@3.9/bin/python3.9 3.8 │ /usr/local/opt/python@3.8/bin/python3.8 3.7 │ /usr/local/opt/python@3.7/bin/python3.7 The Python Launcher for Unix discovers interpreters by scanning the PATH environment variable for pythonX.Y commands; in other words, invoking py -X.Y is equivalent to running pythonX.Y. The main benefit of py is to provide a cross-platform way to launch Python, with a well-defined default when no version is specified: the newest interpreter on the system or the interpreter in the active virtual environment.
📄 Page
20
The Python Launcher for Unix also defaults to the interpreter in a virtual environment if the environment is named .venv and located in the current directory or one of its parents. Unlike with the Windows Launcher, you don’t need to activate the environment for this to work. For example, here’s a quick way to get an interactive session with the rich console library installed: $ py -m venv .venv $ py -m pip install rich $ py >>> from rich import print >>> print("[u]Hey, universe![/]") Hey, universe! If you invoke py with a Python script, it inspects the shebang to determine the appropriate Python version. Note that this mechanism bypasses the program loader. For example, the following script may produce different results when run stand-alone versus when invoked with py: #!/usr/bin/python3 import sys print(sys.executable) Entry points are a more sustainable way to create scripts that does not rely on handcrafting shebang lines. We’ll cover them in Chapter 3. Installing Python with Pyenv Pyenv is a Python version manager for macOS and Linux. It includes a build tool—also available as a stand-alone program named python-build—that downloads, builds, and installs Python versions in your home directory. Pyenv allows you to activate and deactivate these installations globally, per project directory, or per shell session. NOTE In this section, we’ll use Pyenv as a build tool. If you’re interested in using Pyenv as a version manager, please refer to the official documentation for additional setup steps. The best way to install Pyenv on macOS and Linux is using Homebrew: $ brew install pyenv One great benefit of installing Pyenv from Homebrew is that you’ll also get the build dependencies of Python. If you use a different installation method, check the Pyenv wiki for platform-specific instructions on how to set up your build environment. Display the available Python versions using the following command: $ pyenv install --list