Skip to content

Instantly share code, notes, and snippets.

@Integralist
Last active January 2, 2019 19:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Integralist/9e0c5ee9c2cc2568dd1961bf370716c9 to your computer and use it in GitHub Desktop.
Save Integralist/9e0c5ee9c2cc2568dd1961bf370716c9 to your computer and use it in GitHub Desktop.
[Python's Pipenv] #python #pip #pipenv #virtualenv

tl;dr

  • brew install pyenv
  • pip install pipenv
  • pipenv --python 3.7 (pyenv install --list)
  • pipenv shell
  • pipenv install tornado==5.0.2
  • pipenv install --dev mypy tox flake8
  • pipenv install -r requirements.txt (generate Pipfile from requirements.txt)
  • pipenv lock --requirements (generate a requirements.txt equivalent to a Pipfile)

Long explanation...

https://github.com/pypa/pipenv

First, make sure you're using your system install of Python (likely 2.7.x) and you have no other python environments installed, otherwise that may cause you confusion if things don't work as you expect (basically, have a spring clean of your previous/old python setup).

Next make sure you have pyenv installed (e.g. brew install pyenv) as Pipenv uses that for installing python versions.

Note: it's unclear if Pipenv will handle installing pyenv for you, so maybe try the following steps without installing pyenv and see if installing a new python version (as described below) works or not.

pip install pipenv

Note: also, if you try to install a new Python version, I've noticed it errors saying python-build definitions are out of date and need to be updated to install the new version. The python-build is used by pyenv so again, it's unclear if python-build is installed by Pipenv or if it has to be manually installed along with pyenv 🤔

Here's an example Dockerfile to try things out:

FROM python:3.6.5

# Jump into directory where our Pipfile will be found
WORKDIR /app

# Install pipenv for managing dependencies instead of pip
RUN pip install -U pipenv==10.*

# This pip.conf configures pip to use our internal pypi mirror when installing
# python packages. It's not in this service's directory, but is put in place
# the .rig/hooks/prebuild_setup_internal_packages global prebuild hook before
# the image is built.
COPY pip.conf /etc/pip.conf

# Copy over both Pipfile and Pipfile.lock
COPY ./Pipfile* /app/

# Install all dependencies to the system version (3.6.5)
RUN pipenv install --system --deploy

COPY . /app/

CMD ["/app/service.py"]

For me this installed pipenv-2018.5.18.

Here are the basic commands available with pipenv:

$ pipenv

Usage: pipenv [OPTIONS] COMMAND [ARGS]...

Options:
  --where          Output project home information.
  --venv           Output virtualenv information.
  --py             Output Python interpreter information.
  --envs           Output Environment Variable options.
  --rm             Remove the virtualenv.
  --bare           Minimal output.
  --completion     Output completion (to be eval'd).
  --man            Display manpage.
  --three / --two  Use Python 3/2 when creating virtualenv.
  --python TEXT    Specify which version of Python virtualenv should use.
  --site-packages  Enable site-packages for the virtualenv.
  --version        Show the version and exit.
  -h, --help       Show this message and exit.


Usage Examples:
   Create a new project using Python 3.6, specifically:
   $ pipenv --python 3.6

   Install all dependencies for a project (including dev):
   $ pipenv install --dev

   Create a lockfile containing pre-releases:
   $ pipenv lock --pre

   Show a graph of your installed dependencies:
   $ pipenv graph

   Check your installed dependencies for security vulnerabilities:
   $ pipenv check

   Install a local setup.py into your virtual environment/Pipfile:
   $ pipenv install -e .

   Use a lower-level pip command:
   $ pipenv run pip freeze

Commands:
  check      Checks for security vulnerabilities and against PEP 508 markers
             provided in Pipfile.
  clean      Uninstalls all packages not specified in Pipfile.lock.
  graph      Displays currently–installed dependency graph information.
  install    Installs provided packages and adds them to Pipfile, or (if none
             is given), installs all packages.
  lock       Generates Pipfile.lock.
  open       View a given module in your editor.
  run        Spawns a command installed into the virtualenv.
  shell      Spawns a shell within the virtualenv.
  sync       Installs all packages specified in Pipfile.lock.
  uninstall  Un-installs a provided package and removes it from Pipfile.
  update     Runs lock, then sync.

Let's create a new project using Python 3.6:

$ pipenv --python 3.6

Creating a virtualenv for this project…
Using /Users/markmcdonnell/.pyenv/versions/3.6.3/bin/python3.6m (3.6.3) to create virtualenv…
⠋Running virtualenv with interpreter /Users/markmcdonnell/.pyenv/versions/3.6.3/bin/python3.6m
Using base prefix '/Users/markmcdonnell/.pyenv/versions/3.6.3'
New python executable in /Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP/bin/python3.6m
Also creating executable in /Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP
Creating a Pipfile for this project…

This will create a Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]

[packages]

[requires]
python_version = "3.6"

But the current terminal/shell will be using the system Python still:

$ python --version

Python 2.7.10

In order to use the installed Python environment, you need to spin up a new shell:

$ pipenv shell

Spawning environment shell (/usr/local/bin/bash). Use 'exit' to leave.
. /Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP/bin/activate

$ python --version
Python 3.6.3

Note: when switching between git branches you might find odd things happen. I've found the best thing to do is to first check with python --version to see if you're using the system python or not and if you are using Pipenv still, to then exit so you leave the virtual environment shell that's running. Then change your git branch and move into whatever directory you need to and re-run pipenv shell.

Let's install two dependencies (we'll see the Pipfile is updated and a Pipfile.lock is generated):

$ pipenv install boto3

Installing boto3…
Collecting boto3
  Downloading https://files.pythonhosted.org/packages/b8/29/f35b0a055014296bf4188043e2cc1fd4ca041a085991765598842232c2f5/boto3-1.7.26-py2.py3-none-any.whl (128kB)
Collecting jmespath<1.0.0,>=0.7.1 (from boto3)
  Using cached https://files.pythonhosted.org/packages/b7/31/05c8d001f7f87f0f07289a5fc0fc3832e9a57f2dbd4d3b0fee70e0d51365/jmespath-0.9.3-py2.py3-none-any.whl
Collecting s3transfer<0.2.0,>=0.1.10 (from boto3)
  Using cached https://files.pythonhosted.org/packages/d7/14/2a0004d487464d120c9fb85313a75cd3d71a7506955be458eebfe19a6b1d/s3transfer-0.1.13-py2.py3-none-any.whl
Collecting botocore<1.11.0,>=1.10.26 (from boto3)
  Downloading https://files.pythonhosted.org/packages/87/c5/7ed94b700d30534f346bb55408ca8501325840bcdc371628cff10d7ba68d/botocore-1.10.26-py2.py3-none-any.whl (4.2MB)
Collecting docutils>=0.10 (from botocore<1.11.0,>=1.10.26->boto3)
  Downloading https://files.pythonhosted.org/packages/36/fa/08e9e6e0e3cbd1d362c3bbee8d01d0aedb2155c4ac112b19ef3cae8eed8d/docutils-0.14-py3-none-any.whl (543kB)
Collecting python-dateutil<3.0.0,>=2.1; python_version >= "2.7" (from botocore<1.11.0,>=1.10.26->boto3)
  Using cached https://files.pythonhosted.org/packages/cf/f5/af2b09c957ace60dcfac112b669c45c8c97e32f94aa8b56da4c6d1682825/python_dateutil-2.7.3-py2.py3-none-any.whl
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1; python_version >= "2.7"->botocore<1.11.0,>=1.10.26->boto3)
  Downloading https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
Installing collected packages: jmespath, docutils, six, python-dateutil, botocore, s3transfer, boto3
Successfully installed boto3-1.7.26 botocore-1.10.26 docutils-0.14 jmespath-0.9.3 python-dateutil-2.7.3 s3transfer-0.1.13 six-1.11.0

Adding boto3 to Pipfile's [packages]…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (00df60)!
Installing dependencies from Pipfile.lock (00df60)…
  🐍   ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 7/7 — 00:00:01
  
$ pipenv install ipython

...same sort of stuff..

$ pipenv install pyre-check --dev

...same sort of stuff..

Here's a look at the current Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
pyre-check = "*"

[packages]
"boto3" = "*"
ipython = "*"

[requires]
python_version = "3.6"

We can now utilise these dependencies:

$ which ipython

/Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP/bin/ipython

$ ipython

Python 3.6.3 (default, Oct 13 2017, 11:47:13)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import boto3

In [2]: type(boto3.client('cognito-idp'))
Out[2]: botocore.client.CognitoIdentityProvider

There are other ways to install dependencies:

  • Explicit versions: pipenv install flask==0.12.1
  • Git: pipenv install -e git+https://github.com/requests/requests.git#egg=requests
  • AWS Lambda zip generation: pipenv run pip install -r <(pipenv lock -r) --target dist/

You can also graph out all your dependencies:

$ pipenv graph

boto3==1.7.26
  - botocore [required: >=1.10.26,<1.11.0, installed: 1.10.26]
    - docutils [required: >=0.10, installed: 0.14]
    - jmespath [required: <1.0.0,>=0.7.1, installed: 0.9.3]
    - python-dateutil [required: >=2.1,<3.0.0, installed: 2.7.3]
      - six [required: >=1.5, installed: 1.11.0]
  - jmespath [required: <1.0.0,>=0.7.1, installed: 0.9.3]
  - s3transfer [required: <0.2.0,>=0.1.10, installed: 0.1.13]
    - botocore [required: >=1.3.0,<2.0.0, installed: 1.10.26]
      - docutils [required: >=0.10, installed: 0.14]
      - jmespath [required: <1.0.0,>=0.7.1, installed: 0.9.3]
      - python-dateutil [required: >=2.1,<3.0.0, installed: 2.7.3]
        - six [required: >=1.5, installed: 1.11.0]
ipython==6.4.0
  - appnope [required: Any, installed: 0.1.0]
  - backcall [required: Any, installed: 0.1.0]
  - decorator [required: Any, installed: 4.3.0]
  - jedi [required: >=0.10, installed: 0.12.0]
    - parso [required: >=0.2.0, installed: 0.2.1]
  - pexpect [required: Any, installed: 4.5.0]
    - ptyprocess [required: >=0.5, installed: 0.5.2]
  - pickleshare [required: Any, installed: 0.7.4]
  - prompt-toolkit [required: >=1.0.15,<2.0.0, installed: 1.0.15]
    - six [required: >=1.9.0, installed: 1.11.0]
    - wcwidth [required: Any, installed: 0.1.7]
  - pygments [required: Any, installed: 2.2.0]
  - setuptools [required: >=18.5, installed: 39.2.0]
  - simplegeneric [required: >0.8, installed: 0.8.1]
  - traitlets [required: >=4.2, installed: 4.3.2]
    - decorator [required: Any, installed: 4.3.0]
    - ipython-genutils [required: Any, installed: 0.2.0]
    - six [required: Any, installed: 1.11.0]
pyre-check==0.0.6
typed-ast==1.1.0

You can reverse the graph direction using the --reverse flag.

You can verify the security of your dependencies:

$ pipenv check

Checking PEP 508 requirements…
Passed!

Checking installed package safety…
All good!

You can also look at the code for any of your dependencies, and their code directory will be opened in whichever editor is assigned to the $EDITOR environment variable in your shell (for me this is vim):

$ pipenv open boto3

Opening '/Users/markmcdonnell/.local/share/virtualenvs/testing_pipenv-jvIwu3TP/lib/python3.6/site-packages/boto3' in your EDITOR.

Here's a look at our final Pipfile.lock:

{
    "_meta": {
        "hash": {
            "sha256": "e79d3c5ef5705053b19f7c653dc0adb3e99d75726138633ae95a5b3709f2e51c"
        },
        "pipfile-spec": 6,
        "requires": {
            "python_version": "3.6"
        },
        "sources": [
            {
                "name": "pypi",
                "url": "https://pypi.org/simple",
                "verify_ssl": true
            }
        ]
    },
    "default": {
        "appnope": {
            "hashes": [
                "sha256:5b26757dc6f79a3b7dc9fab95359328d5747fcb2409d331ea66d0272b90ab2a0",
                "sha256:8b995ffe925347a2138d7ac0fe77155e4311a0ea6d6da4f5128fe4b3cbe5ed71"
            ],
            "markers": "sys_platform == 'darwin'",
            "version": "==0.1.0"
        },
        "backcall": {
            "hashes": [
                "sha256:38ecd85be2c1e78f77fd91700c76e14667dc21e2713b63876c0eb901196e01e4",
                "sha256:bbbf4b1e5cd2bdb08f915895b51081c041bac22394fdfcfdfbe9f14b77c08bf2"
            ],
            "version": "==0.1.0"
        },
        "boto3": {
            "hashes": [
                "sha256:6dd9a6fe523c3e4d4fc28fe7030453ee5b4e75e778144cf22008c79dfc031bd3",
                "sha256:fccad296209cfbee668292d51bd3b258eb85d4bce1bf1a5dcb2e24942a00d48a"
            ],
            "index": "pypi",
            "version": "==1.7.26"
        },
        "botocore": {
            "hashes": [
                "sha256:c63c77e41cd514d80da06eb626f5e9f50c94c44b0206957aca23a20f889abb05",
                "sha256:ca23fb013a18584a3a7043c6cc0bf02250f2665937e73290f65f1f48ee9b4f78"
            ],
            "version": "==1.10.26"
        },
        "decorator": {
            "hashes": [
                "sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
                "sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"
            ],
            "version": "==4.3.0"
        },
        "docutils": {
            "hashes": [
                "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
                "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
                "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
            ],
            "version": "==0.14"
        },
        "ipython": {
            "hashes": [
                "sha256:a0c96853549b246991046f32d19db7140f5b1a644cc31f0dc1edc86713b7676f",
                "sha256:eca537aa61592aca2fef4adea12af8e42f5c335004dfa80c78caf80e8b525e5c"
            ],
            "index": "pypi",
            "version": "==6.4.0"
        },
        "ipython-genutils": {
            "hashes": [
                "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8",
                "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"
            ],
            "version": "==0.2.0"
        },
        "jedi": {
            "hashes": [
                "sha256:1972f694c6bc66a2fac8718299e2ab73011d653a6d8059790c3476d2353b99ad",
                "sha256:5861f6dc0c16e024cbb0044999f9cf8013b292c05f287df06d3d991a87a4eb89"
            ],
            "version": "==0.12.0"
        },
        "jmespath": {
            "hashes": [
                "sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64",
                "sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63"
            ],
            "version": "==0.9.3"
        },
        "parso": {
            "hashes": [
                "sha256:cdef26e8adc10d589f3ec4eb444bd0a29f3f1eb6d72a4292ab8afcb9d68976a6",
                "sha256:f0604a40b96e062b0fd99cf134cc2d5cdf66939d0902f8267d938b0d5b26707f"
            ],
            "version": "==0.2.1"
        },
        "pexpect": {
            "hashes": [
                "sha256:9783f4644a3ef8528a6f20374eeb434431a650c797ca6d8df0d81e30fffdfa24",
                "sha256:9f8eb3277716a01faafaba553d629d3d60a1a624c7cf45daa600d2148c30020c"
            ],
            "markers": "sys_platform != 'win32'",
            "version": "==4.5.0"
        },
        "pickleshare": {
            "hashes": [
                "sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b",
                "sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5"
            ],
            "version": "==0.7.4"
        },
        "prompt-toolkit": {
            "hashes": [
                "sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381",
                "sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
                "sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"
            ],
            "version": "==1.0.15"
        },
        "ptyprocess": {
            "hashes": [
                "sha256:e64193f0047ad603b71f202332ab5527c5e52aa7c8b609704fc28c0dc20c4365",
                "sha256:e8c43b5eee76b2083a9badde89fd1bbce6c8942d1045146e100b7b5e014f4f1a"
            ],
            "version": "==0.5.2"
        },
        "pygments": {
            "hashes": [
                "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
                "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
            ],
            "version": "==2.2.0"
        },
        "python-dateutil": {
            "hashes": [
                "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0",
                "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8"
            ],
            "markers": "python_version >= '2.7'",
            "version": "==2.7.3"
        },
        "s3transfer": {
            "hashes": [
                "sha256:90dc18e028989c609146e241ea153250be451e05ecc0c2832565231dacdf59c1",
                "sha256:c7a9ec356982d5e9ab2d4b46391a7d6a950e2b04c472419f5fdec70cc0ada72f"
            ],
            "version": "==0.1.13"
        },
        "simplegeneric": {
            "hashes": [
                "sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"
            ],
            "version": "==0.8.1"
        },
        "six": {
            "hashes": [
                "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
                "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
            ],
            "version": "==1.11.0"
        },
        "traitlets": {
            "hashes": [
                "sha256:9c4bd2d267b7153df9152698efb1050a5d84982d3384a37b2c1f7723ba3e7835",
                "sha256:c6cb5e6f57c5a9bdaa40fa71ce7b4af30298fbab9ece9815b5d995ab6217c7d9"
            ],
            "version": "==4.3.2"
        },
        "wcwidth": {
            "hashes": [
                "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e",
                "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"
            ],
            "version": "==0.1.7"
        }
    },
    "develop": {
        "pyre-check": {
            "hashes": [
                "sha256:2d631e00c15761bdeef0e3f70e3b54f8cfa2765018d42a841cbfe7373574db6d",
                "sha256:a05d569441a1eadc5acbb8574710d69171898a2c02fa196e1d162faf77dc4f02"
            ],
            "index": "pypi",
            "version": "==0.0.6"
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment