Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 ## vpython - simple and easy VirtualEnv Python | |
| 2 | |
| 3 `vpython` is a tool, written in Go, which enables the simple and easy invocation | |
| 4 of Python code in [VirtualEnv](https://virtualenv.pypa.io/en/stable/) | |
| 5 environments. | |
| 6 | |
| 7 For the standard case, employing `vpython` is as simple as: | |
| 8 | |
| 9 * Add `vpython` to `PATH`. | |
| 10 * Write an enviornment specification naming packages. | |
| 11 * Change tool invocation from `python` to `vpython`. | |
|
iannucci
2017/02/20 21:18:22
(set up cipd server, upload packages to cipd)? (ri
dnj
2017/02/22 06:39:10
Done.
| |
| 12 | |
| 13 Using `vpython` offers several benefits to standard Python, especially when | |
|
iannucci
2017/02/20 21:18:20
I think there's a missing section above this which
dnj
2017/02/22 06:39:10
Done.
| |
| 14 vendoring packages. Notably, with `vpython`: | |
|
iannucci
2017/02/20 21:18:29
I wouldn't contrast vpython v "standard python" it
dnj
2017/02/22 06:39:11
Done.
| |
| 15 | |
| 16 * It is trivially enable hermetic Python everywhere. | |
|
iannucci
2017/02/20 21:18:26
it trivially enables
dnj
2017/02/22 06:39:11
Done.
| |
| 17 * No `sys.path` manipulation is needed to load vendored or imported packages. | |
| 18 * Any tool can trivially define which package(s) it needs, without requiring | |
| 19 coordination or cooperation from other tools. | |
|
iannucci
2017/02/20 21:18:20
well... you need to upload the new packages to cip
dnj
2017/02/22 06:39:10
noted
| |
| 20 * Adding new Python dependencies to a project is non-invasive and immediate. | |
| 21 * Package downloading and deployment are baked into `vpython` and built on | |
| 22 fast and secure Google Cloud Platform technologies. | |
| 23 * No more custom bootstraps. Several projects and tools, including multiple | |
| 24 within the infra code base, have bootstrap scripts that vendor packages or | |
| 25 mimic a VirtualEnv. These are at best repetitive and, at worst, buggy and | |
| 26 insecure. | |
| 27 * Depenencies are explicitly stated, not assumed. | |
| 28 | |
| 29 ### Why VirtualEnv? | |
| 30 | |
| 31 VirtualEnv offers several benefits over system Python. Primarily, it is the | |
| 32 community-supported mechanism to vendor Python packages. This means that we're | |
| 33 using packages the way they are written and tested to be used, no hacks needed. | |
|
iannucci
2017/02/20 21:18:24
Is this written targeting external devs, or infra
dnj
2017/02/22 06:39:11
It's a paraphrase of the design doc, really.
| |
| 34 | |
| 35 By using the same environemnt everywhere, Python invocations become | |
| 36 reproducible. A tool run on a developer's system will load the same versions | |
| 37 of the same libraries as it will on a production system. A production system | |
| 38 will no longer fail because it is missing a package, or because it has the | |
| 39 wrong version. | |
| 40 | |
| 41 The classic mechanism for vendoring, `sys.path` manipulation, is nuanced, buggy, | |
|
iannucci
2017/02/20 21:18:27
I wouldn't really call this 'classic', unless you'
dnj
2017/02/22 06:39:10
Acknowledged.
| |
| 42 and unsupported by the Python community. It is difficult to get right on all | |
| 43 platforms in all environments for all packages. A notorious example of this is | |
| 44 `protobuf` and other domain-bound packages, which actively fight `sys.path` | |
| 45 inclusion. Using VirtualEnv means that any compliant Python package can | |
| 46 trivially be included into a project. | |
| 47 | |
| 48 ### Why CIPD? | |
| 49 | |
| 50 [CIPD](https://github.com/luci/luci-go/tree/master/cipd) is Chrome's | |
| 51 infrastructure package deployment system. It is simple, accessible, fast, and | |
| 52 backed by resilient systems such as Google Storage and AppEngine. | |
|
iannucci
2017/02/20 21:18:20
again, buzzwords about implementation details... t
dnj
2017/02/22 06:39:11
Done.
| |
| 53 | |
| 54 Unlike `pip`, a CIPD package is defined by its content, enabling precise package | |
| 55 matching instead of fuzzy version matching (e.g., `numpy >= 1.2`, and | |
| 56 `numpy == 1.2` both can match multiple `numpy` packages in `pip`). | |
| 57 | |
| 58 CIPD also supports ACLs, enabling privileged Python projects to easily vendor | |
| 59 sensitive packages. | |
| 60 | |
| 61 ### Why wheels? | |
| 62 | |
| 63 A Python [wheel](https://www.python.org/dev/peps/pep-0427/) is a simple binary | |
|
iannucci
2017/02/20 21:18:22
See? This is a good description. This is relativel
dnj
2017/02/22 06:39:10
A wheel is a bespoke mechanism that synergizes wit
| |
| 64 distrubition of Python code. A wheel can be generic (pure Python) or system- | |
| 65 and architecture-bound (e.g., 64-bit Mac OSX). | |
| 66 | |
| 67 Wheels are prefered over eggs because they come packaged with compiled binaries. | |
| 68 This makes their deployment simple (unpack via `pip`) and reduces system | |
| 69 requirements and variation, since local compilation is not needed. | |
| 70 | |
| 71 The increased management burden of maintaining separate wheels for the same | |
| 72 package, one for each architecture, is handled naturally by CIPD, removing the | |
| 73 only real pain point. | |
| 74 | |
| 75 ## Wheel Guidance | |
| 76 | |
| 77 This section contains recommendations for building or uploading wheel CIPD | |
| 78 packages, including platform-specific guidance. | |
| 79 | |
| 80 CIPD wheel packages are CIPD packages that contain Python wheels. A given CIPD | |
| 81 package can contain multiple wheels for multiple platforms, but should only | |
| 82 contain one version of any given package for any given architecture/platform. | |
| 83 | |
| 84 For example, you can bundle a Windows, Linux, and Mac OSX version of `numpy` and | |
| 85 `coverage` in the same CIPD package, but you should not bundle `numpy==1.11` and | |
|
iannucci
2017/02/20 21:18:28
oh... isn't this wasteful? Why not use the existin
dnj
2017/02/22 06:39:10
One can, but one is not required to. Your suggesti
| |
| 86 `numpy==1.12` in the same package. | |
| 87 | |
| 88 The reason for this is that `vpython` identifies which wheels to install by | |
| 89 scanning the contents of the CIPD package, and if multiple versions appear, | |
| 90 there is no clear guidance about which should be used. | |
| 91 | |
| 92 ### Mac OSX | |
| 93 | |
| 94 Use the `m` ABI suffix and the `macosx_...` platform. `vpython` installs wheels | |
| 95 with the `--force` flag, so slight binary incompatibilities (e.g., specific OSX | |
| 96 versions) can be glossed over. | |
| 97 | |
| 98 coverage-4.3.4-cp27-cp27m-macosx_10_10_x86_64.whl | |
|
iannucci
2017/02/20 21:18:19
I'd like it if we could add additional template pa
dnj
2017/02/22 06:39:10
Acknowledged. Let's solve this later.
| |
| 99 | |
| 100 ### Linux | |
| 101 | |
| 102 Use wheels with the `mu` ABI suffix and the `manylinux1` platform. For example: | |
| 103 | |
| 104 coverage-4.3.4-cp27-cp27mu-manylinux1_x86_64.whl | |
| 105 | |
| 106 ### Windows | |
| 107 | |
| 108 | |
|
iannucci
2017/02/20 21:18:19
No particular guidance, or just forgot to fill thi
dnj
2017/02/22 06:39:11
oops, I hadn't actually played with Windows when I
| |
| 109 | |
| 110 ## Setup and Invocation | |
| 111 | |
| 112 `vpython` can be invoked by replacing `python` in the command-line with | |
| 113 `vpython`. | |
| 114 | |
| 115 `vpython` works with a default Python environment out of the box. To add | |
| 116 vendored packges, you need to define an enviornment specification file that | |
| 117 describes which wheels to install. | |
| 118 | |
| 119 An enviornment specification file is a text protobuf defined as `Spec` | |
| 120 [here](./api/env/spec.proto). An example is: | |
| 121 | |
| 122 ``` | |
| 123 # Any 2.7 interpreter will do. | |
| 124 python_version: "2.7" | |
| 125 | |
| 126 # Include "numpy" for the current architecture. | |
| 127 wheel { | |
| 128 path: "infra/python/wheels/numpy/${platform}-${arch}" | |
| 129 version: "version:1.11.0" | |
| 130 } | |
| 131 | |
| 132 # Include "coverage" for the current architecture. | |
| 133 wheel { | |
| 134 path: "infra/python/wheels/coverage/${platform}-${arch}" | |
| 135 version: "version:4.1" | |
| 136 } | |
| 137 ``` | |
| 138 | |
| 139 This specification can be supplied in one of three ways: | |
| 140 | |
| 141 * Explicitly, as a command-line option to `vpython`. | |
|
iannucci
2017/02/20 21:18:25
name the option?
dnj
2017/02/22 06:39:10
Done.
| |
| 142 * Implicitly, as a file alongside your entry point. For example, if you are | |
| 143 running `test_runner.py`, `vpython` will look for `test_runner.py.vpython` | |
| 144 next to it and load the environment from there. | |
| 145 * Implicitly, inined in your main file. `vpython` will scan the main entry point | |
| 146 for sentinel text and, if present, load the specification from that. | |
|
iannucci
2017/02/20 21:18:23
can't it also get it from the environment too?
dnj
2017/02/22 06:39:10
Oh yeah. Didn't exist when I wrote this :P
| |
| 147 | |
| 148 ### Migration | |
| 149 | |
| 150 #### Command-line. | |
| 151 | |
| 152 `vpython` is a natural replacement for `python` in the command line: | |
| 153 | |
| 154 ```sh | |
| 155 python ./foo/bar/baz.py -d --flag value arg arg whatever | |
| 156 ``` | |
| 157 | |
| 158 Becomes: | |
| 159 ```sh | |
| 160 vpython ./foo/bar/baz.py -d --flag value arg arg whatever | |
| 161 ``` | |
| 162 | |
| 163 The `vpython` tool accepts its own command-line arguments. In this case, use | |
| 164 a `--` seprator to differentiate between `vpython` options and `python` options: | |
| 165 | |
| 166 ```sh | |
| 167 vpython -spec /path/to/spec.vpython -- ./foo/bar/baz.py | |
| 168 ``` | |
| 169 | |
| 170 #### Shebang (POSIX) | |
| 171 | |
| 172 If your script uses implicit specification (file or inline), replacing `python` | |
| 173 with `vpython` in your shebang line will automatically work. | |
| 174 | |
| 175 ```sh | |
| 176 #!/usr/bin/env vpython | |
| 177 ``` | |
| 178 | |
| OLD | NEW |