Definitive guide to python on Mac OSX
You should setup python on your Mac this way. I’m tired of having to look this up, or worse, describe it ineffectively to coworkers. So here it is, all in one place.
UPDATED for python 2 EOL: Many things have changed in python-land, including the retirement of python 2.7, so I updated this guide to reflect current best practices. Highlights: removed requirement to install Xcode, no longer uses the obsolete virtualenv
and virtualenvwrapper
, added pyenv
and poetry
for python version management and python package/venv management, respectively.
Why this way?
You have python on your Mac, can’t you use the built-in python? Isn’t any other method just for experts?
NO!
Here are the problems with using the built-in python:
- Installed PyPi packages pollute your system python, potentially causing system problems
- OpenSSL used by the system python is old and vulnerable. Old as in, doesn’t understand websites that require TLS 1.1 or later
- You’re stuck with whatever python 2.7 version comes pre-installed, and no python 3.x
Install Xcode (optional)
Xcode is not required to install Homebrew and Python, but it is required for some Homebrew packages. If you can spare the gigabytes, download it from the App Store. If not, you should be able to complete this guide without it on MacOS Mojave. No guarantee for future versions of MacOS.
Install Xcode Command Line Tools (required)
While Xcode is not required, the Xcode Command Line Tools are.
Open a terminal and type the following command to install Xcode Command Line Tools which are required for Homebrew:
xcode-select --install
If you’re using MacOS Mojave, you’ll need to install the MacOS system headers. This is not required for Catalina.
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
You’ll be prompted for your OSX user password to install this required SDK package.
If you chose not to install Xcode, you’ll need to add the SDKROOT
environment variable to your shell:
echo "export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk" >> ~/.bash_profile
If using zsh, change the end of that last command from ~/.bash_profile to ~/.zshrc .
Install Homebrew
Homebrew is a package manager for OSX. We’ll use it to install the dependencies to compile and install python. (Note: previous versions of this guide used Homebrew to install python, but this is not required. We’ll use pyenv to install python shortly.)
Go here: https://brew.sh/
Follow the directions to install Homebrew, which at the time of this writing is to paste this line into a terminal:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
Install pyenv
Now that Homebrew is installed, you can install pyenv and the required packages to install python.
Install pyenv:
brew install pyenv
Install python required packages:
brew install openssl readline sqlite3 xz zlib
Add pyenv to your shell:
echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n eval "$(pyenv init -)"\nfi' >> ~/.bash_profile
If using zsh, change the end of that last command from ~/.bash_profile
to ~/.zshrc
.
(Optional) You can also brew install pyenv-virtualenv
to add virtualenv support to pyenv, but it’s not required since most of the virtualenv work you’ll do with poetry
after we install it later. Some people like the pyenv-virtualenv
support anyway.
Install Python with Homebrew
This step is optional since we’ll never use this python in a project, but it’s recommended for two reasons:
- Reason 1: This Homebrew-installed python becomes a safety net in case we forget to switch to a pyenv-installed python, we won’t accidentally pollute the system python.
- Reason 2: It becomes a place to install global packages with pipx. This allows you to switch between python versions at-will using pyenv while maintaining a consistent set of global utilities like
flake8
andblack
that are always available and don’t pollute the global python.
Install latest python 3.x and pipx
(Optional, for global packages)
# Install python 3.x
brew install python# Install pipx to manage global packages
python3 -m pip install --user pipx
python3 -m userpath append ~/.local/bin# Install global packages
python3 -m pipx install flake8
python3 -m pipx install black
Install latest python 2.7
(Really optional, only to protect system python from mistakes)
brew install python@2
If you chose to install python 2.7, you will never use it (unless you have some legacy code you need to run). Python 2.7 end of life is at the end of 2019. See the Python 2.7 end-of-life countdown. It’s only acting as a safety net to protect the system python in case you make a mistake.
Install python!
Finally! Time to install python…
Let’s start with a fresh shell. Close your terminal and open it again to ensure pyenv has been loaded.
You can see a list of available python versions with pyenv:
$ pyenv install --list
...
3.6.1
3.6.2
3.6.3
3.6.4
3.6.5
3.6.6
3.6.7
3.6.8
3.7.0
3.7-dev
3.7.1
3.7.2
3.7.3
3.8-dev
3.9-dev
<snip>
anaconda3-5.0.0
anaconda3-5.0.1
anaconda3-5.1.0
anaconda3-5.2.0
anaconda3-5.3.0
anaconda3-5.3.1
anaconda3-2018.12
anaconda3-2019.03
...
Pick a version and install it:
pyenv install 3.7.3
Then set it as the global python version:
pyenv global 3.7.3
This should take effect right away. Verify that you’re on the right python version:
$ python -V
Python 3.7.3
Congratulations, you have python! Done, right?? Nope.
Install Poetry
Poetry is a fantastic python package manager that simplifies dependency management, virtual environment management, and building and publishing of python code.
Why you should use poetry:
- Obsoletes
virtualenv
,virtualenvwrapper
,pipenv
,setup.py
,requirements.txt
, and more. - Lives outside python, so you don’t need to install it with
pip
or worry about package conflicts. - Separates runtime dependencies like
requests
from development dependencies likepytest
. - It uses the simple and easy-to-understand
pypackage.toml
file from pep-518 to contain everything about the project. - CLI interface similar to well-known package managers like
npm
andyarn
.
Install poetry following the installation guide. At the time of this writing, simply run this command:
curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
Poetry creates all your virtual environments automatically on-demand in a single directory by default. If you prefer your virtual environments to live in the same directory with the code (like a .venv
directory in your project), you can run this command:
poetry config virtualenvs.in-project true
Prevent accidents
Now we’ll add a few important pieces to the terminal environment to ensure everything works together and keep from breaking our carefully constructed python development environment.
Open the file ~/.bash_profile
(or ~/.zshrc
for zsh). Create that file if it doesn’t exist and make sure it has the following lines:
Save the file, then close and re-open your terminal window to activate the changes.
You have now activated pipx, pyenv, poetry, and locked down pip to only work inside a virtual environment so you can’t accidentally install python packages to the global python environment. Don’t worry, if you still want to install a python package globally (you don’t!) you can use gpip
or gpip3
to override this protection and force a package to install globally.
Go forth!
You’re now ready to work with python!
You no longer need to create virtual environments or write confusing boilerplate.
Simply create a new python project:
poetry new myproject
cd myproject
Decide on a python version for this project:
pyenv local 3.7.3
Then add dependencies to the project, such as the requests
package:
poetry add requests
And your development dependencies:
poetry add --dev pytest
A virtual environment is automatically created with the python version you chose and the added python packages.
You never need to enter this virtual environment. No more .venv/bin/activate
or deactivate
. Although you can if you want to. You can also create your own unmanaged virtual environments by using the latest venv features built into python 3 to create your virtual environments. Don’t use virtualenv
.
To run your project in the virtual environment, do something like this:
poetry run python myscript.py
Or create a scripts section in pyproject.py
to make the entrypoint available outside the virtual environment.
See the documentation for the run command in poetry for various ways to run your python projects from the CLI.
Enjoy!
Further reading:
- poetry: https://poetry.eustace.io/docs
- pyenv: https://github.com/pyenv/pyenv
- pipx: https://pipxproject.github.io/pipx/
- Python Code Quality: Tools & Best Practices:
https://realpython.com/python-code-quality/