<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us"><generator uri="https://gohugo.io/" version="0.101.0">Hugo</generator><title type="html">python on A Scripter's Notes</title><subtitle type="html">Emacs, scripting and anything text oriented.</subtitle><link href="https://scripter.co/tags/python/" rel="alternate" type="text/html" title="HTML"/><link href="https://scripter.co/tags/python/index.xml" rel="alternate" type="application/rss+xml" title="RSS"/><link href="https://scripter.co/tags/python/atom.xml" rel="self" type="application/atom+xml" title="Atom"/><link href="https://scripter.co/tags/python/jf2feed.json" rel="alternate" type="application/jf2feed+json" title="jf2feed"/><updated>2026-04-22T08:24:58-04:00</updated><author><name>Kaushal Modi</name><email>kaushal.modi@gmail.com</email></author><id>https://scripter.co/tags/python/</id><entry><title type="html">Saving Python pip dependencies</title><link href="https://scripter.co/saving-python-pip-dependencies/?utm_source=atom_feed" rel="alternate" type="text/html"/><link href="https://scripter.co/zero-html-validation-errors/?utm_source=atom_feed" rel="related" type="text/html" title="Zero HTML Validation Errors!"/><link href="https://scripter.co/offline-html5-validator/?utm_source=atom_feed" rel="related" type="text/html" title="Offline HTML5 Validator"/><link href="https://scripter.co/disarming-the-tar-bomb-in-10-seconds/?utm_source=atom_feed" rel="related" type="text/html" title="Disarming the 'tar' bomb in 10 seconds"/><link href="https://scripter.co/unclutter-a-better-reader-view-for-browsers/?utm_source=atom_feed" rel="related" type="text/html" title="Unclutter: A better Reader View for browsers"/><link href="https://scripter.co/hugo-modules-importing-a-theme/?utm_source=atom_feed" rel="related" type="text/html" title="Hugo Modules: Importing a Theme"/><id>https://scripter.co/saving-python-pip-dependencies/</id><author><name>Kaushal Modi</name></author><published>2022-06-14T00:38:00-04:00</published><updated>2022-06-14T00:38:00-04:00</updated><content type="html"><![CDATA[<blockquote>How I generated the Python dependencies file <code>requirements.txt</code> so
that Netlify can install and run the HTML5 Validator before deploying
this site.</blockquote><div class="ox-hugo-toc toc">
<div class="heading">Table of Contents</div>
<ul>
<li><a href="#create-a-virtual-environment"><span class="section-num">1</span> Create a <em>virtual environment</em></a></li>
<li><a href="#activate-the-virtual-environment"><span class="section-num">2</span> Activate the <em>virtual environment</em></a></li>
<li><a href="#install-the-packages-using-pip"><span class="section-num">3</span> Install the packages using <code>pip</code></a></li>
<li><a href="#generate-requirements-dot-txt"><span class="section-num">4</span> Generate <code>requirements.txt</code></a></li>
<li><a href="#netlify-deployment">Netlify deployment</a></li>
<li><a href="#summary">Summary</a></li>
</ul>
</div>
<!--endtoc-->
<p>Recently I learned about the Python tool <code>html5validator</code> tool and
used it to run HTML5 validation on local HTML files. You can read more
about that in the <a href="/offline-html5-validator/">Offline HTML5 Validator</a> post.</p>
<p>But then I wondered .. &ldquo;Wouldn&rsquo;t it be awesome if I run this
validation step <strong>each time</strong> after Hugo generates this site on <a href="https://netlify.com">Netlify</a>,
but <span class="underline">before</span> it gets deployed?&rdquo;. That curiosity led me to <a href="https://docs.netlify.com/configure-builds/manage-dependencies/#python-dependencies">Netlify&rsquo;s
documentation on Python dependencies</a>, and I learned that Netlify will
run <code>pip install</code> to install the dependencies in <code>requirements.txt</code>
present in the repository&rsquo;s base directory.</p>
<p><span class="org-target" id="netlify-pip-freeze"></span> I followed the <code>pip freeze &gt; requirements.txt</code>
step in that documentation but that ended up listing <strong>all</strong> my <code>pip</code>
installed packages in that file! I needed the <code>requirements.txt</code> to
include the dependencies only for <code>html5validator</code>. This post was born
in my quest to achieve that.</p>
<p>The solution to this problem was to first create a Python <em>virtual
environment</em> in my site directory, and <em>then</em> do all the <code>pip</code>
operations in there. I learned about this <em>virtual environment</em> step
from <a href="https://medium.com/python-pandemonium/better-python-dependency-and-package-management-b5d8ea29dff1">this Python Pandemonium post</a>.</p>
<p>The <a href="https://docs.python.org/3/library/venv.html"><strong>venv</strong> documentation</a> has a lot of details &mdash; I&rsquo;ll just list the
key steps in this post.</p>

<h2 id="create-a-virtual-environment"><span class="section-num">1</span> Create a <em>virtual environment</em>&nbsp;<a class="headline-hash no-text-decoration" href="#create-a-virtual-environment">#</a></h2>


<p><em>cd</em> to your site directory and run the below command create a
virtualenv directory named <code>pyenv</code> in there.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">python3 -m venv pyenv
</span></span></code></pre></div><div class="note">
<p>As we are creating this <em>virtual environment</em> just for the sake of
creating a <code>requirements.txt</code>, we don&rsquo;t need to commit this
directory to <em>git</em>.</p>
</div>

<h2 id="activate-the-virtual-environment"><span class="section-num">2</span> Activate the <em>virtual environment</em>&nbsp;<a class="headline-hash no-text-decoration" href="#activate-the-virtual-environment">#</a></h2>


<p>The virtualenv directory <code>pyenv/bin/</code> will have multiple flavors of
shell scripts to activate your virtualenv. I am using
<code>activate.csh</code> here as my shell is <em>tcsh</em> 🙄.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="nb">source</span> pyenv/bin/activate.csh
</span></span></code></pre></div><p>Just to emphasize, it is important to use the <strong><code>source</code></strong> command here,
and not just call the shell script directly.</p>
<p>Once you activate this virtualenv, you should see something like
<em>[pyenv]</em> in the shell prompt.</p>

<h2 id="install-the-packages-using-pip"><span class="section-num">3</span> Install the packages using <code>pip</code>&nbsp;<a class="headline-hash no-text-decoration" href="#install-the-packages-using-pip">#</a></h2>


<p>Install all the project-specific packages. In this case it was just
this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">pip install html5validator
</span></span></code></pre></div><p>The package (and its dependencies) will be installed in
<code>pyenv/lib/python3.7/site-packages/</code>. Here, the <code>python3.7/</code>
sub-directory name will match the version of Python you have
installed.</p>

<h2 id="generate-requirements-dot-txt"><span class="section-num">4</span> Generate <code>requirements.txt</code>&nbsp;<a class="headline-hash no-text-decoration" href="#generate-requirements-dot-txt">#</a></h2>


<p>Finally, we run the <code>pip freeze</code> command <a href="#netlify-pip-freeze">mentioned</a> in Netlify docs,
but with the <strong><code>--local</code></strong> switch:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">pip freeze --local &gt; requirements.txt
</span></span></code></pre></div><div class="note">
<p>The <code>--local</code> option ensures that globally-installed packages are not
listed even if the virtualenv has global access.</p>
</div>
<p>Here&rsquo;s the <code>requirements.txt</code> created by that command:</p>
<p><a id="code-snippet--netlify-requirements.txt"></a></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">html5validator==0.4.2
</span></span><span class="line"><span class="cl">PyYAML==6.0
</span></span></code></pre></div><div class="src-block-caption">
  <span class="src-block-number"><a href="#code-snippet--netlify-requirements.txt">Code Snippet 1</a>:</span>
  The <code>requirements.txt</code> for Netlify
</div>
<p>Now, I could have just manually typed <code>html5validator==0.4.2</code> in a
<code>requirements.txt</code> and committed that, and that would work too. But
then, I wouldn&rsquo;t have learned how to create a project-specific <em>pip
dependency file</em> 😄.</p>

<h2 id="netlify-deployment">Netlify deployment&nbsp;<a class="headline-hash no-text-decoration" href="#netlify-deployment">#</a></h2>


<p>The <code>html5validator</code> has a dependency on Java 8. Luckily the Netlify
environment already comes with that installed. So the only extra setup
needed to make this package work on Netlify was to set the
<code>PYTHON_VERSION</code> environment variable to <strong>3.8</strong>
<span class="sidenote-number"><small class="sidenote">
The version number should be one of the values listed in <a href="https://github.com/netlify/build-image/blob/focal/included_software.md">Netlify&rsquo;s
<em>included software</em> list</a>.
</small></span>
.</p>

<h2 id="summary">Summary&nbsp;<a class="headline-hash no-text-decoration" href="#summary">#</a></h2>


<p>The numbered headings in this post already summarize the steps needed
to create a project-specific <code>requirements.txt</code>.</p>
<p>With these in place:</p>
<div class="verse">
<p>✅ <code>requirements.txt</code> committed in site directory root<br />
✅ Netlify environment variable <code>PYTHON_VERSION</code> set to 3.8<br /></p>
</div>
<p>my Netlify deployment script now does HTML5 Validation along with few
other checks before this site gets deployed 🎉.</p>
<p>Here&rsquo;s the <a href="https://gitlab.com/kaushalmodi/kaushalmodi.gitlab.io/-/blob/master/build.sh">full <code>build.sh</code> script</a>.</p>
]]></content><category scheme="https://scripter.co/categories/web" term="web" label="web"/><category scheme="https://scripter.co/series/html5-validator" term="html5-validator" label="HTML5 Validator"/><category scheme="https://scripter.co/tags/html" term="html" label="html"/><category scheme="https://scripter.co/tags/validator" term="validator" label="validator"/><category scheme="https://scripter.co/tags/python" term="python" label="python"/><category scheme="https://scripter.co/tags/pip" term="pip" label="pip"/><category scheme="https://scripter.co/tags/100daystooffload" term="100daystooffload" label="100DaysToOffload"/><category scheme="https://scripter.co/tags/netlify" term="netlify" label="netlify"/></entry></feed>