<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>virtualenv &amp;mdash; Nat Knight</title>
    <link>http://natknight.xyz/tag:virtualenv</link>
    <description>Reflections, diversions, and opinions from a progressive ex-physicist programmer dad with a sore back.</description>
    <pubDate>Sat, 02 May 2026 02:58:52 -0700</pubDate>
    <item>
      <title>What&#39;s in a virtualenv?</title>
      <link>http://natknight.xyz/whats-in-a-virtualenv</link>
      <description>&lt;![CDATA[#python #virtualenv&#xA;&#xA;A useful question for understanding software tools is to peel back a layer of abstraction and ask what the thing underneath  is. For example:&#xA;&#xA;On a computer, text is a sequence of numbers (and a system to interpret that as letters).&#xA;An HTTP request is a blob of text with a particular format.&#xA;An interpreter (like the Python or Ruby interpreters) is a program, whose function is to execute other programs.&#xA;&#xA;Knowing this sort of thing is useful when the abstractions break (e.g. when you open a text file with the wrong encoding) or when thinking about the fundamental contours of a system&#39;s possibility space. For example, if you know that programs can be configured with environment variables and CLI flags, knowing that the Python interpreter is a program means you know where to start looking if you need to configure it.&#xA;&#xA;While there are many, many articles on the internet explaining how and why to use them, there&#39;s less information about what a Python virtual environment (or &#34;virtualenv&#34;) is. Luckily for us, it ends up not being very difficult to investigate.&#xA;&#xA;!--more--&#xA;&#xA;Looking inside a virtualenv&#xA;&#xA;Creating a virtualenv is the work of a moment. If you have Python installed, you can get one of your very own like so:&#xA;&#xA;  python -m venv ./venv&#xA;&#xA;This creates a directory called venv. Let&#39;s see what&#39;s in it!&#xA;&#xA;  cd venv&#xA;  ls&#xA;...&#xA;&#xA;Listing the directory&#39;s contents reveals three directories and a file:&#xA;&#xA;Include/, which appears to be empty,&#xA;Lib/, which contains a directory called site-packages,&#xA;Scripts/, which contains a bunch of executables, including the Python interpreter and the activate/deactivate scripts for this virtualenv, and&#xA;pyvenv.cfg, a config file with the Python version the path to my system Python interpreter.&#xA;&#xA;(Note: This was run on a Windows machine; you&#39;ll get different-but-analogous results if you run it on Linux or MacOS).&#xA;&#xA;I know from prior experience that site-packages is where Python packages get installed, that &#34;include&#34; is probably something to do with compiled extensions. It also makes sense that there would be a central place to put scripts, so that the virtualenv&#39;s activation script can add it to your shell&#39;s PATH. So a virtualenv is a directory full of things for Python to import or execute. But how does it work?&#xA;&#xA;Understanding virtualenvs&#xA;&#xA;The documentation of virtualenvironments is, again, very helpful if you want to understand how to use a virtualenvironment, but not particularly illuminating on the topic of its inner workings.&#xA;&#xA;Instead the answer is in the documentation for the site package: it turns out that when the Python interpreter starts up it looks for a pyvenv.cfg file one directory above itself. If it finds one, it knows its in a virtualenv and configures itself accordingly.&#xA;&#xA;Now we know a few things about virtualenvs:&#xA;&#xA;You can use the Python interpreter at venv/scripts/python without activating the virtualenv.&#xA;&#xA;If you need to find the source code of a dependency (for debugging, say) you can find it in venv/Lib/site-packages/.&#xA;&#xA;You can ruin your virtualenv by messing with the pyvenv.cfg file (or, possibly, un-mess it to fix a ruined virtualenv).&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p><a href="http://natknight.xyz/tag:python" class="hashtag"><span>#</span><span class="p-category">python</span></a> <a href="http://natknight.xyz/tag:virtualenv" class="hashtag"><span>#</span><span class="p-category">virtualenv</span></a></p>

<p>A useful question for understanding software tools is to peel back a layer of abstraction and ask what the thing underneath  <em>is</em>. For example:</p>
<ul><li>On a computer, text <em>is</em> a sequence of numbers (and a <a href="https://en.wikipedia.org/wiki/UTF-8">system to interpret that as letters</a>).</li>
<li>An HTTP request <em>is</em> a blob of text with a <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Example_session">particular format</a>.</li>
<li>An interpreter (like the Python or Ruby interpreters) <em>is</em> a program, whose function is to execute other programs.</li></ul>

<p>Knowing this sort of thing is useful when the abstractions break (e.g. when you open a text file with the wrong encoding) or when thinking about the fundamental contours of a system&#39;s possibility space. For example, if you know that programs can be configured with environment variables and CLI flags, knowing that the Python interpreter is a program means you know where to start looking if you need to configure it.</p>

<p>While there are many, many articles on the internet explaining how and why to <em>use</em> them, there&#39;s less information about what a Python virtual environment (or “virtualenv”) <em>is</em>. Luckily for us, it ends up not being very difficult to investigate.</p>



<h2 id="looking-inside-a-virtualenv" id="looking-inside-a-virtualenv">Looking inside a virtualenv</h2>

<p>Creating a virtualenv is the <a href="https://docs.python.org/3/library/venv.html#creating-virtual-environments">work of a moment</a>. If you have Python installed, you can get one of your very own like so:</p>

<pre><code class="language-shell">&gt; python -m venv ./venv
</code></pre>

<p>This creates a directory called <code>venv</code>. Let&#39;s see what&#39;s in it!</p>

<pre><code class="language-shell">&gt; cd venv
&gt; ls
...
</code></pre>

<p>Listing the directory&#39;s contents reveals three directories and a file:</p>
<ul><li><code>Include/</code>, which appears to be empty,</li>
<li><code>Lib/</code>, which contains a directory called <code>site-packages</code>,</li>
<li><code>Scripts/</code>, which contains a bunch of executables, including the Python interpreter and the activate/deactivate scripts for this virtualenv, and</li>
<li><code>pyvenv.cfg</code>, a config file with the Python version the path to my system Python interpreter.</li></ul>

<p>(Note: This was run on a Windows machine; you&#39;ll get different-but-analogous results if you run it on Linux or MacOS).</p>

<p>I know from prior experience that <code>site-packages</code> is where Python packages get installed, that “include” is probably something to do with compiled extensions. It also makes sense that there would be a central place to put scripts, so that the virtualenv&#39;s activation script can add it to your shell&#39;s PATH. So a virtualenv is a directory full of things for Python to import or execute. But how does it <em>work</em>?</p>

<h2 id="understanding-virtualenvs" id="understanding-virtualenvs">Understanding virtualenvs</h2>

<p>The documentation of virtualenvironments is, again, very helpful if you want to understand how to use a virtualenvironment, but not particularly illuminating on the topic of its inner workings.</p>

<p>Instead the answer is in the documentation for the <a href="https://docs.python.org/3/library/site.html?highlight=pyvenv%20cfg"><code>site</code> package</a>: it turns out that when the Python interpreter starts up it looks for a <code>pyvenv.cfg</code> file one directory above itself. If it finds one, it knows its in a virtualenv and configures itself accordingly.</p>

<p>Now we know a few things about virtualenvs:</p>
<ul><li><p>You can use the Python interpreter at <code>venv/scripts/python</code> without activating the virtualenv.</p></li>

<li><p>If you need to find the source code of a dependency (for debugging, say) you can find it in <code>venv/Lib/site-packages/</code>.</p></li>

<li><p>You can ruin your virtualenv by messing with the <code>pyvenv.cfg</code> file (or, possibly, un-mess it to fix a ruined virtualenv).</p></li></ul>
]]></content:encoded>
      <guid>http://natknight.xyz/whats-in-a-virtualenv</guid>
      <pubDate>Tue, 04 May 2021 07:00:00 +0000</pubDate>
    </item>
  </channel>
</rss>