+++
title = "Setting up Python with Pyenv and Poetry on Debian"
date = 2021-08-22T00:00:00
lastmod = 2021-11-30T00:00:00
draft = false

# Authors. Comma separated list, e.g. `["Bob Smith", "David Jones"]`.
authors = ["Carl Pearson"]

tags = []

summary = ""

# Projects (optional).
#   Associate this post with one or more of your projects.
#   Simply enter your project's folder or file name without extension.
#   E.g. `projects = ["deep-learning"]` references 
#   `content/project/deep-learning/index.md`.
#   Otherwise, set `projects = []`.
projects = []

# Featured image
# To use, add an image named `featured.jpg/png` to your project's folder. 
[image]
  # Caption (optional)
  caption = ""

  # Focal point (optional)
  # Options: Smart, Center, TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight
  focal_point = "Center"

  # Show image only in page previews?
  preview_only = true


categories = []

# Set captions for image gallery.


+++

Setting up a python development environment is annoying.
We'd especially like to avoid:

* Using the system python: it may be way out of date, have special modifications, or be required for the system to function (and therefore we should avoid messing with it).
* Installing packages globally: different projects may require different versions, and the system may have it's own package requirements that conflict with ours.

The solution has two components:
1. install and use whatever version of python you like
2. create isolated environments using your preferred version of python for each project

## Pyenv

[pyenv](https://github.com/pyenv/pyenv) is a version manger for python.
It streamlines the installation and use of multiple python version on a single system.

On Debian, you can visit [pyenv-installer](https://github.com/pyenv/pyenv-installer) to install pyenv.

Then, I had to add to my `.zshrc`:
```bash
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```

To install new python versions using pyenv, you may need to install the python build dependencies:
```bash
sudo apt-get update; sudo apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

Basically, `pyenv` allows you to associate different python versions with different directories.

* `pyenv install -l`: list pythons available to install
* `pyenv install ...`: install a python
* `pyenv versions`: list installed pythons
* `pyenv shell ...`: use a python version in the current shell
* `pyenv local ...`: set the python to use in this directory

## Poetry

Poetry is a package manager for python.
It needs python to install, but once it is installed it will use whatever python is in your path (i.e., whatever you set with `pyenv`).
If the system python is new enough, it is fine to use the system python to install poetry.

```bash
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
```

This added `export PATH="$HOME/.poetry/bin:$PATH"` to my `.zshrc`.
You may need to follow the instructions to do something similar.

It's also nice to

```bash
poetry config virtualenvs.in-project true
```

This puts the virtualenv configuration files in the directory you use poetry in, as opposed to a centralized location.
The downside is you won't want to commit these files to your version control.


## Putting it together
An example of use

Outside of any particular project, you'll need some versions of python for whatever work you need.
```bash
pyenv install 3.9.6
```

Then, to create a new project
```bash
mkdir test && cd test
pyenv local 3.9.6 # when you cd into test, `python` will be python 3.9.6
poetry init 
poetry add numpy
echo "import numpy\nimport sys\nprint(sys.version)\nprint(numpy.version.version)" > test.py
poetry run python test.py
```