-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathvirtualenvs-for-node-devs.html
More file actions
189 lines (182 loc) · 8.16 KB
/
Copy pathvirtualenvs-for-node-devs.html
File metadata and controls
189 lines (182 loc) · 8.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<html>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<head>
<title>
leontrolski - virtualenvs for Node devs
</title>
<style>
body {margin: 5% auto; background: #fff7f7; color: #444444; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.8; max-width: 63%;}
@media screen and (max-width: 800px) {body {font-size: 14px; line-height: 1.4; max-width: 90%;}}
pre {width: 100%; border-top: 3px solid gray; border-bottom: 3px solid gray;}
a {border-bottom: 1px solid #444444; color: #444444; text-decoration: none; text-shadow: 0 1px 0 #ffffff; }
a:hover {border-bottom: 0;}
.inline {background: #b3b2b226; padding-left: 0.3em; padding-right: 0.3em; white-space: nowrap;}
blockquote {font-style: italic;color:black;background-color:#f2f2f2;padding:2em;}
details {border-bottom:solid 5px gray;}
</style>
<link href="https://unpkg.com/prism-themes@1.9.0/themes/prism-darcula.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js">
</script>
</head>
<body>
<a href="index.html">
<img src="pic.png" style="height:2em">
⇦
</a>
<p><i>2021-01-03</i></p>
<h1>
Python <code class="inline">virtualenv</code>
s for Node devs
</h1>
<p>
You've started doing some Python while working with another team, and they've told you to do everything in <code class="inline">virtualenv</code>
s as it's the right way. You've also been told Python's packaging system is a bit of a mess, let's try tame it somewhat.
</p>
<p>
We're going to compare <code class="inline">npm</code>
to the "modern classic" Python equivalent. I'm going to ignore more recent developments like <a href="https://python-poetry.org/">
poetry
</a>
and friends.
</p>
<p>
Let's install a python version with brew:
</p>
<pre class="language-bash"><code>brew install python@3.9</code>
</pre>
<p>
OK, so we've got a Python version that seems sane, let's set up a <code class="inline">virtualenv</code>
with the equivalent of <code class="inline">npm init</code>
.
</p>
<pre class="language-bash"><code>$(brew --prefix python@3.9)/libexec/bin/python -m venv .env</code>
</pre>
<p>
We now have a new folder in our current directory called <code class="inline">.env</code>
that contains symlinks to the Python that we just ran:
</p>
<pre class="language-bash"><code>.env
├── bin
│ ├── Activate.ps1
│ ├── activate
│ ├── activate.csh
│ ├── activate.fish
│ ├── easy_install
│ ├── easy_install-3.9
│ ├── pip
│ ├── pip3
│ ├── pip3.9
│ ├── python -> python3
│ ├── python3 -> /opt/homebrew/opt/python@3.11/bin/python3.11
│ └── python3.9 -> python3
├── include
├── lib
│ └── python3.9
│ └── site-packages
│ ├── __pycache__
│ ├── easy_install.py
│ ├── pip
│ ├── pip-20.2.3.dist-info
│ ├── pkg_resources
│ ├── setuptools
│ └── setuptools-49.2.1.dist-info
└── pyvenv.cfg</code>
</pre>
<p>
We could always run <code class="inline">.env/bin/python</code>
or <code class="inline">.env/bin/pip install flask</code>
or whatever, but <code class="inline">virtualenv</code>
s come with a special trick file to add <code class="inline">.env/bin</code>
to <code class="inline">bash</code>
's PATH. Let's run it:
</p>
<pre class="language-bash"><code>source .env/bin/activate</code>
</pre>
<p>
Now everything should be set up. Let's try:
</p>
<pre class="language-bash"><code>(.env) ➜ echo $PATH
/Users/user/src/my-special-project/.env/bin:/usr/local/bin:/usr/bin:/bin
(.env) ➜ which python
/Users/user/src/my-special-project/.env/bin/python
(.env) ➜ which pip
/Users/user/src/my-special-project/.env/bin/pip
(.env) ➜ python --version
Python 3.9.1</code>
</pre>
<p>
The main difference from <code class="inline">npm</code>
here is we don't have to run anything with <code class="inline">npm run ...</code>
as we've hacked with the PATH.
</p>
<h2 id="installing-stuff">
Installing stuff
</h2>
<p>
Let's install <code class="inline">flask</code>
:
</p>
<pre class="language-bash"><code>pip install flask</code>
</pre>
<p>
Now our directory should look like:
</p>
<pre class="language-bash"><code>.env
├── bin
│ ├── python -> python3
│ ├── flask
│ └── ...
├── lib
│ └── python3.9
│ └── site-packages
│ ├── click
│ ├── flask
│ └── ...</code>
</pre>
<p>
As you can see, <code class="inline">.env/lib/python3.9/site-packages</code>
is a lot like <code class="inline">node_modules</code>
. We can see all the library's files:
</p>
<pre class="language-bash"><code>(.env) ➜ ls .env/lib/python3.9/site-packages/flask
__init__.py _compat.py cli.py debughelpers.py json signals.py views.py
__main__.py app.py config.py globals.py logging.py templating.py wrappers.py
__pycache__ blueprints.py ctx.py helpers.py sessions.py testing.py</code>
</pre>
<p>
Now, what is the equivalent to the following in a <code class="inline">package.json</code>
?
</p>
<pre class="language-javascript"><code>{
...
"dependencies": {
"express": "^4.17.1"
}
}</code>
</pre>
<p>
Python is a fair bit different from Node in that only one version of a package can be installed in a <code class="inline">virtualenv</code>
at a time. This means you tend to have abstract requirements (that is to say with very limited version pinning) listed in <code class="inline">setup.py|requirements.in|pyproject.toml</code>
and pinned requirements (for testing/deployent if you're working on a service) in a <code class="inline">requirements.txt</code>
.
</p>
<p>
You can install a set of requirements with:
</p>
<pre class="language-bash"><code>pip install -r requirements.txt</code>
</pre>
<p>
Or whatever file it is you want to install from. This is the equivalent of <code class="inline">npm install</code>
.
</p>
<p>
In terms of pinning requirements in your own project a la <code class="inline">yarn lock</code>
or whatever the flavour of the month is, I've always been a fan of <a href="https://github.com/jazzband/pip-tools">
pip-tools
</a>
- using this means you can safely ignore the last few years of Python packaging excitement and get on with your life.
</p>
</body>
</html>