2.1. Tools

2.1.1. pyenv

  • pyenv lets you easily switch between multiple versions of Python

  • pyenv intercepts Python commands using shim executables injected into your PATH, determines which Python version has been specified by your application, and passes your commands along to the correct Python installation.

When you execute a shim, pyenv determines which Python version to use by reading it from the following sources, in this order:

  1. The PYENV_VERSION environment variable (if specified)

  2. The application-specific .python-version file in the current directory (if present)

  3. The first .python-version file found (if any) by searching each parent directory, until reaching the root of your filesystem

  4. The global $(pyenv root)/version file.

If the global version file is not present, pyenv assumes you want to use the "system" Python

Each Python version is installed into its own directory under $(pyenv root)/versions:

  • $(pyenv root)/versions/2.7.8/

  • $(pyenv root)/versions/3.4.2/

  • $(pyenv root)/versions/pypy-2.4.0/

Listing 403. Installation
curl https://pyenv.run | bash
Listing 404. Upgrade
pyenv update

2.1.2. Cookiecutter

  • template for a Python package

Listing 405. Installation
pip install cookiecutter

Generate a Python package project:

cookiecutter https://github.com/audreyr/cookiecutter-pypackage.git
  1. Create a repo and put it there.

  2. Add the repo to your Travis-CI account.

  3. Install the dev requirements into a virtualenv. (pip install -r requirements_dev.txt)

  4. Register your project with PyPI.

  5. Run the Travis CLI command travis encrypt --add deploy.password to encrypt your PyPI password in Travis config and activate automated deployment on PyPI when you push a new tag to master branch.

  6. Add the repo to your ReadTheDocs account + turn on the ReadTheDocs service hook.

  7. Release your package by pushing a new tag to master.

  8. Add a requirements.txt file that specifies the packages you will need for your project and their versions. For more info see the pip docs for requirements files.

  9. Activate your project on pyup.io.

2.1.3. pipenv

Pipenv is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world. Windows is a first-class citizen, in our world.

It automatically creates and manages a virtualenv for your projects, as well as adds/removes packages from your Pipfile as you install/uninstall packages. It also generates the ever-important Pipfile.lock, which is used to produce deterministic builds.

Pipenv is primarily meant to provide users and developers of applications with an easy method to setup a working environment. For the distinction between libraries and applications and the usage of setup.py vs Pipfile to define dependencies.

The problems that Pipenv seeks to solve are multi-faceted:

  1. You no longer need to use pip and virtualenv separately. They work together.

  2. Managing a requirements.txt file can be problematic, so Pipenv uses Pipfile and Pipfile.lock to separate abstract dependency declarations from the last tested combination.

  3. Hashes are used everywhere, always. Security. Automatically expose security vulnerabilities.

  4. Strongly encourage the use of the latest versions of dependencies to minimize security risks arising from outdated components.

  5. Give you insight into your dependency graph (e.g. pipenv graph).

  6. Streamline development workflow by loading .env files.

Listing 406. Installation
brew install pipenv

2.1.4. pip-tools

  • pip-tools = pip-compile + pip-sync

  • The pip-compile command lets you compile a requirements.txt file from your dependencies, specified in either setup.py or requirements.in.

pip-compile
# or
python -m piptools compile

pip-compile will produce your requirements.txt, with all dependencies (and all underlying dependencies) frozen. You should put requirements.txt under version control.

2.1.4.1. Example

Listing 407. requirements.in
Flask
pip-compile requirements.in
$ pip-compile requirements.in
#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile --output-file requirements.txt requirements.in
#
click==6.7                # via flask
flask==0.12.2
itsdangerous==0.24        # via flask
jinja2==2.9.6             # via flask
markupsafe==1.0           # via jinja2
werkzeug==0.12.2          # via flask
$ pip-compile --generate-hashes requirements.in
#
# This file is autogenerated by pip-compile
# To update, run:
#
#    pip-compile --generate-hashes --output-file requirements.txt requirements.in
#
click==6.7 \
    --hash=sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d \
    --hash=sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b \
    # via flask
flask==0.12.2 \
    --hash=sha256:0749df235e3ff61ac108f69ac178c9770caeaccad2509cb762ce1f65570a8856 \
    --hash=sha256:49f44461237b69ecd901cc7ce66feea0319b9158743dd27a2899962ab214dac1
itsdangerous==0.24 \
    --hash=sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519 \
    # via flask
jinja2==2.9.6 \
    --hash=sha256:2231bace0dfd8d2bf1e5d7e41239c06c9e0ded46e70cc1094a0aa64b0afeb054 \
    --hash=sha256:ddaa01a212cd6d641401cb01b605f4a4d9f37bfc93043d7f760ec70fb99ff9ff \
    # via flask
markupsafe==1.0 \
    --hash=sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665 \
    # via jinja2
werkzeug==0.12.2 \
    --hash=sha256:903a7b87b74635244548b30d30db4c8947fe64c5198f58899ddcd3a13c23bb26 \
    --hash=sha256:e8549c143af3ce6559699a01e26fa4174f4c591dbee0a499f3cd4c3781cdec3d \
    # via flask

2.1.4.2. Example 2

$ pip-compile --upgrade-package flask  # only update the flask package
$ pip-compile --upgrade-package flask --upgrade-package requests  # update both the flask and requests packages
$ pip-compile -P flask -P requests==2.0.0  # update the flask package to the latest, and requests to v2.0.0

2.1.4.3. pip-sync

pip-sync to update your virtual environment to reflect exactly what’s in there. This will install/upgrade/uninstall everything necessary to match the requirements.txt contents.

$ pip-sync
Uninstalling flake8-2.4.1:
  Successfully uninstalled flake8-2.4.1
Collecting click==4.1
  Downloading click-4.1-py2.py3-none-any.whl (62kB)
    100% |................................| 65kB 1.8MB/s
  Found existing installation: click 4.0
    Uninstalling click-4.0:
      Successfully uninstalled click-4.0
Successfully installed click-4.1

2.1.5. Conda