<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Posts about guide</title><link>https://chriswarrick.com/</link><atom:link href="https://chriswarrick.com/blog/tags/guide.xml" rel="self" type="application/rss+xml" /><description>A rarely updated blog, mostly about programming.</description><lastBuildDate>Sun, 20 Feb 2022 22:00:00 GMT</lastBuildDate><generator>https://github.com/Kwpolska/YetAnotherBlogGenerator</generator><item><title>Python Virtual Environments in Five Minutes</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/</link><pubDate>Tue, 04 Sep 2018 18:15:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/</guid><description>
In Python, virtual environments are used to isolate projects from each other
(if they require different versions of the same library, for example). They let
you install and manage packages without administrative privileges, and without
conflicting with the system package manager.  They also allow to quickly create
an environment somewhere else with the same dependencies.
Virtual environments are a crucial tool for any Python developer. And at that,
a very simple tool to work with.
</description><content:encoded><![CDATA[
<p>In Python, virtual environments are used to isolate projects from each other
(if they require different versions of the same library, for example). They let
you install and manage packages without administrative privileges, and without
conflicting with the system package manager.  They also allow to quickly create
an environment somewhere else with the same dependencies.</p>
<p>Virtual environments are a crucial tool for any Python developer. And at that,
a very simple tool to work with.</p>



<p>Let’s get started!</p>
<section id="install">
<h1>Install</h1>
<p>The best tool that can be used to create virtual environments is the
<a class="reference external" href="https://docs.python.org/3/library/venv.html">venv</a> module, which is part of
the standard library since Python 3.3.</p>
<p><code class="docutils literal">venv</code> is built into Python, and most users don’t need to install anything.
However, Debian/Ubuntu users will need to run <code class="docutils literal">sudo <span class="pre">apt-get</span> install <span class="pre">python3-venv</span></code> to make it work (due to Debian not installing some components
that <code class="docutils literal">venv</code> needs by default). <a class="brackets" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a></p>
<p>The alternative (and original, and previously standard) virtual environment tool is <a class="reference external" href="https://virtualenv.pypa.io/">virtualenv</a>. It works with Python 2.7, and has a couple
extra fetures (that you generally won’t need). virtualenv can be installed with your system package manager, or <code class="docutils literal">pip install <span class="pre">--user</span> virtualenv</code>.</p>
<p>Which one to use? Probably <code class="docutils literal">venv</code>. Both tools achieve the same goal in similar
ways. And if one of them does not work, you can try the other and it might just
work better.</p>
<p><em>(Terminology note: most of the time, the names of both tools are used
interchargeably, “venv” was often used as an abbreviation for “virtualenv”
before the stdlib tool was created)</em></p>
</section>
<section id="create">
<h1>Create</h1>
<p>To create a virtual environment named <code class="docutils literal">env</code>, you need to run the <code class="docutils literal">venv</code>
tool with the Python you want to use in that environment.</p>
<div class="code"><pre class="code text"><a id="rest_code_1fb767790a68420a97f0697df45d2e92-1" name="rest_code_1fb767790a68420a97f0697df45d2e92-1" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_1fb767790a68420a97f0697df45d2e92-1"></a>Linux:   $ python3 -m venv env
<a id="rest_code_1fb767790a68420a97f0697df45d2e92-2" name="rest_code_1fb767790a68420a97f0697df45d2e92-2" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_1fb767790a68420a97f0697df45d2e92-2"></a>Windows: &gt; py -m venv env
</pre></div>
<p>or, if you’re using <code class="docutils literal">virtualenv</code>:</p>
<div class="code"><pre class="code text"><a id="rest_code_d2d40ad9883b450e9264cf578d6f68af-1" name="rest_code_d2d40ad9883b450e9264cf578d6f68af-1" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d2d40ad9883b450e9264cf578d6f68af-1"></a>$ python3 -m virtualenv env
<a id="rest_code_d2d40ad9883b450e9264cf578d6f68af-2" name="rest_code_d2d40ad9883b450e9264cf578d6f68af-2" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d2d40ad9883b450e9264cf578d6f68af-2"></a>&gt; py -m virtualenv env
</pre></div>
<p>Afterwards, you will end up with a folder named <code class="docutils literal">env</code> that contains folders
named <code class="docutils literal">bin</code> (<code class="docutils literal">Scripts</code> on Windows — contains executables and scripts
installed by packages, including
<code class="docutils literal">python</code>), <code class="docutils literal">lib</code> (contains code), and <code class="docutils literal">include</code> (contains C headers).</p>
<p>Both tools install <code class="docutils literal">pip</code> and <code class="docutils literal">setuptools</code>, but <code class="docutils literal">venv</code> does not ship with
<code class="docutils literal">wheel</code>. In addition, the default versions tend to be more-or-less outdated.
Let’s upgrade them real quick: <a class="brackets" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a></p>
<div class="code"><pre class="code text"><a id="rest_code_39b9e0a93e0746fbac8d7b7f11734578-1" name="rest_code_39b9e0a93e0746fbac8d7b7f11734578-1" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_39b9e0a93e0746fbac8d7b7f11734578-1"></a>$ env/bin/python -m pip install --upgrade pip setuptools wheel
<a id="rest_code_39b9e0a93e0746fbac8d7b7f11734578-2" name="rest_code_39b9e0a93e0746fbac8d7b7f11734578-2" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_39b9e0a93e0746fbac8d7b7f11734578-2"></a>&gt; env\Scripts\python -m pip install --upgrade pip setuptools wheel
</pre></div>
<section id="where-to-store-virtual-environments">
<h2>Where to store virtual environments?</h2>
<p>While the tools allow you to put your virtual environments anywhere in the
system, it is not a desirable thing to do. There are two options:</p>
<ol class="arabic simple">
<li><p>Have one global place for them, like <code class="docutils literal">~/virtualenvs</code>.</p></li>
<li><p>Store them in each project’s directory, like <code class="docutils literal"><span class="pre">~/git/foobar/.venv</span></code>.</p></li>
</ol>
<p>The first option can be easier to manage, there are tools that can help manage
those (eg. <code class="docutils literal">virtualenvwrapper</code>, shell auto-activation scripts, or the
<code class="docutils literal">workon</code> functions described below).  The second option is equally easy to
work with, but comes with one caveat — you must add the venv directory to your
<code class="docutils literal">.gitignore</code> file (or <code class="docutils literal">.git/info/exclude</code> if you don’t want to commit
changes to <code class="docutils literal">.gitignore</code>), since you don’t want it in your repository (it’s
binary bloat, and works only on your machine).</p>
<p>If you pick the global virtual environment store option, you can use the following short
function (put it in <code class="docutils literal">.bashrc</code> / <code class="docutils literal">.zshrc</code> / your shell configuration file)
to get a simple way to activate an environment (by running <code class="docutils literal">workon foo</code>).
<code class="docutils literal">virtualenvwrapper</code> also has a <code class="docutils literal">workon</code> feature, although I don’t think
<code class="docutils literal">virtualenvwrapper</code> is really necessary and too helpful — the <code class="docutils literal">workon</code>
feature is handy though, and so here’s a way to do it without
<code class="docutils literal">virtualenvwrapper</code>:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-1" name="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-1"></a><span class="w"> </span><span class="nb">export</span><span class="w"> </span><span class="nv">WORKON_HOME</span><span class="o">=</span>~/virtualenvs
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-2" name="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-3" name="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-3"></a><span class="w"> </span><span class="k">function</span><span class="w"> </span>workon<span class="w"> </span><span class="o">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-4" name="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-4"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="nb">source</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$WORKON_HOME</span><span class="s2">/</span><span class="nv">$1</span><span class="s2">/bin/activate&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-5" name="rest_code_d4c94a5f476e4e5ab3fe0a7682a1bdb7-5"></a><span class="w"> </span><span class="o">}</span>
</code></td></tr></table></div><p>And for PowerShell fans, here’s a <code class="docutils literal">workon.ps1</code> script:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_33d18c86da274b70953d97d327e4e0e7-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="rest_code_33d18c86da274b70953d97d327e4e0e7-1" name="rest_code_33d18c86da274b70953d97d327e4e0e7-1"></a> <span class="nv">$WORKON_HOME</span> <span class="p">=</span> <span class="s2">&quot;$home\virtualenvs&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_33d18c86da274b70953d97d327e4e0e7-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="rest_code_33d18c86da274b70953d97d327e4e0e7-2" name="rest_code_33d18c86da274b70953d97d327e4e0e7-2"></a> <span class="p">&amp;</span> <span class="s2">&quot;$WORKON_HOME\</span><span class="p">$(</span><span class="nv">$args</span><span class="p">[</span><span class="n">0</span><span class="p">])</span><span class="s2">\Scripts\activate.ps1&quot;</span>
</code></td></tr></table></div><p>And for cmd.exe fans… you should switch to PowerShell, it’s a very nice and
friendly shell (though perhaps requiring some effort to learn how to be
productive with it).</p>
</section>
</section>
<section id="use">
<h1>Use</h1>
<p>There are three ways of working with virtual environments interactively (in a
shell):</p>
<ul class="simple">
<li><p>activation (run <code class="docutils literal">source env/bin/activate</code> on *nix;
<code class="docutils literal">env\Scripts\activate</code> on Windows) — it simplifies work and requires less
typing, although it can sometimes fail to work properly. (After installing
scripts, <code class="docutils literal">hash <span class="pre">-r</span></code> may be necessary on *nix to use them.)</p></li>
<li><p>executing <code class="docutils literal">env/bin/python</code> (<code class="docutils literal">env\Scripts\python</code>) and other scripts directly, as
activation only changes <code class="docutils literal">$PATH</code> and some helper variables — those variables
are not mandatory for operation, running the correct <code class="docutils literal">python</code> is, and that
method is failsafe.</p></li>
<li><p><a class="reference external" href="https://gist.github.com/datagrok/2199506">in subshells</a> (IMO, it’s bad UX)</p></li>
</ul>
<p>Whichever method you use, you must remember that without doing any of these
things, you will still be working with the system Python.</p>
<p>For non-interactive work (eg. crontab entries, system services, etc.),
activation and subshells are not viable solutions. In these cases, you must
always use the full path to Python.</p>
<p>Here are some usage examples (paths can be relative, of course):</p>
<div class="code"><pre class="code text"><a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-1" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-1" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-1"></a>## *nix, activation ##
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-2" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-2" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-2"></a>$ source /path/to/env/bin/activate
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-3" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-3" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-3"></a>(env)$ pip install Django
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-4" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-4" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-4"></a>(env)$ deactivate
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-5" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-5" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-5"></a>
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-6" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-6" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-6"></a>## *nix, manual execution ##
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-7" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-7" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-7"></a>$ /path/to/env/bin/pip install Django
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-8" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-8" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-8"></a>
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-9" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-9" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-9"></a>## Windows, activation ##
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-10" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-10" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-10"></a>&gt; C:\path\to\env\Scripts\activate
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-11" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-11" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-11"></a>(venv)&gt; pip install Django
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-12" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-12" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-12"></a>(venv)&gt; deactivate
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-13" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-13" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-13"></a>
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-14" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-14" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-14"></a>## Windows, manual execution ##
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-15" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-15" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-15"></a>&gt; C:\path\to\env\Scripts\pip install Django
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-16" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-16" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-16"></a>
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-17" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-17" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-17"></a>## Windows, updating pip/setuptools/wheel ##
<a id="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-18" name="rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-18" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_99f32ee1312e43b19d00feb1c5e6ae7f-18"></a>&gt; C:\path\to\env\Scripts\python -m pip install -U pip setuptools wheel
</pre></div>
<p>The same principle applies to running Python itself, or any other script
installed by a package. (With Django’s <code class="docutils literal">manage.py</code>, calling it as
<code class="docutils literal">./manage.py</code> requires activation, or you can run
<code class="docutils literal">venv/bin/python manage.py</code>.)</p>
<section id="moving-renaming-copying-environments">
<h2>Moving/renaming/copying environments?</h2>
<p>If you try to copy or rename a virtual environment, you will discover that the
copied environment does not work. This is because a virtual environment is
closely tied to both the Python it was created with, and the location it was
created in. (The “relocatable” option of <code class="docutils literal">virtualenv</code> does not work and is deprecated.) <a class="brackets" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-3" id="footnote-reference-3" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a></p>
<p>However, this is very easy to fix. Instead of moving/copying, just create a new
environment in the new location. Then, run <code class="docutils literal">pip freeze &gt; requirements.txt</code> in
the old environment to create a list of packages installed in it. With that,
you can just run <code class="docutils literal">pip install <span class="pre">-r</span> requirements.txt</code> in the new environment to
install packages from the saved list. (Of course, you can copy <code class="docutils literal">requirements.txt</code>
between machines. In many cases, it will just work; sometimes, you might need a few
modifications to <code class="docutils literal">requirements.txt</code> to remove OS-specific stuff.)</p>
<div class="code"><pre class="code text"><a id="rest_code_118b2d54954242548dd7d3e590824a4c-1" name="rest_code_118b2d54954242548dd7d3e590824a4c-1" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_118b2d54954242548dd7d3e590824a4c-1"></a>$ oldenv/bin/pip freeze &gt; requirements.txt
<a id="rest_code_118b2d54954242548dd7d3e590824a4c-2" name="rest_code_118b2d54954242548dd7d3e590824a4c-2" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_118b2d54954242548dd7d3e590824a4c-2"></a>$ python3 -m venv newenv
<a id="rest_code_118b2d54954242548dd7d3e590824a4c-3" name="rest_code_118b2d54954242548dd7d3e590824a4c-3" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_118b2d54954242548dd7d3e590824a4c-3"></a>$ newenv/bin/pip install -r requirements.txt
<a id="rest_code_118b2d54954242548dd7d3e590824a4c-4" name="rest_code_118b2d54954242548dd7d3e590824a4c-4" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#rest_code_118b2d54954242548dd7d3e590824a4c-4"></a>(You may rm -rf oldenv now if you desire)
</pre></div>
<p>Note that it might also be necessary to re-create your virtual environment
after a Python upgrade, <a class="brackets" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-4" id="footnote-reference-4" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a> so it might be handy to keep an up-to-date
<code class="docutils literal">requirements.txt</code> for your virtual environments (for many projects, it makes
sense to put that in the repository).</p>
<p>To manage those <code class="docutils literal">requirements.txt</code> files in a more orgnized yet still simple
way, you might be interested in <a class="reference external" href="https://github.com/jazzband/pip-tools">pip-tools</a>.</p>
</section>
</section>
<section id="frequently-asked-questions">
<h1>Frequently Asked Questions</h1>
<section id="im-using-virtualenv-do-i-need-to-install-it-for-each-python-i-want-to-use-it-with">
<h2>I’m using virtualenv. Do I need to install it for each Python I want to use it with?</h2>
<p>In most cases, you can use <code class="docutils literal">virtualenv <span class="pre">-p</span> pythonX env</code> to specify a different
Python version, but with some Python version combinations, that approach might
be unsuccessful. (The <code class="docutils literal">venv</code> module is tied to the Python version it’s
installed in.)</p>
</section>
<section id="im-the-only-user-on-my-system-do-i-still-need-virtual-environments">
<h2>I’m the only user on my system. Do I still need virtual environments?</h2>
<p>Yes, you do. First, you will still need separation between projects, sooner or
later.  Moreover, if you were to install packages system-wide with pip, you
might end up causing conflicts between packages installed by the system package
manager and by pip. Running <code class="docutils literal">sudo pip</code> is never a good idea because of this.</p>
</section>
<section id="im-using-docker-do-i-still-need-virtual-environments">
<h2>I’m using Docker. Do I still need virtual environments?</h2>
<p>They are still a good idea in that case. They protect you against any bad
system-wide Python packages your OS image might have (and one popular base OS
is famous for those). They don’t introduce any extra overhead, while allowing
to have a clean environment and the ability to re-create it outside of Docker
(eg. for local development without Docker)</p>
</section>
<section id="what-about-pipenv">
<h2>What about Pipenv?</h2>
<p>Pipenv is a dependency management tool. It isn’t compatible with most workflows, and comes with many issues. In my opinion, it’s not worth using (Also, that thing about it being an officially recommended tool? Turns out it’s not true.)</p>
<p>I also wrote a blog post detailing concerns with that tool, titled <a class="reference external" href="https://chriswarrick.com/blog/2018/07/17/pipenv-promises-a-lot-delivers-very-little/">Pipenv: promises a lot, delivers very little</a>.</p>
<p>Consider using <a class="reference external" href="https://github.com/jazzband/pip-tools">pip-tools</a> instead.</p>
</section>
</section>
<section id="footnotes">
<h1>Footnotes</h1>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="footnote-1" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-reference-1">1</a><span class="fn-bracket">]</span></span>
<p>The thing you’re actually installing is <code class="docutils literal">ensurepip</code>. In general, Debian isn’t exactly friendly with Python packaging.</p>
</aside>
<aside class="footnote brackets" id="footnote-2" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-reference-2">2</a><span class="fn-bracket">]</span></span>
<p>On Windows, you <em>must</em> run <code class="docutils literal">python <span class="pre">-m</span> pip</code> instead of <code class="docutils literal">pip</code> if you want to upgrade the package manager itself.</p>
</aside>
<aside class="footnote brackets" id="footnote-3" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-reference-3">3</a><span class="fn-bracket">]</span></span>
<p>All script shebangs contain the direct path to the environment’s Python executable.  Many things in the virtual environment are symlinks that point to the original Python.</p>
</aside>
<aside class="footnote brackets" id="footnote-4" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/#footnote-reference-4">4</a><span class="fn-bracket">]</span></span>
<p>Definitely after a minor version (3.x → 3.y) upgrade, sometimes (I’m looking at you Homebrew) after a patch version upgrade (3.x.y → 3.x.z) as well.</p>
</aside>
</aside>
</section>
]]></content:encoded><category>Python</category><category>best practices</category><category>devel</category><category>guide</category><category>Python</category><category>venv</category><category>virtual environments</category><category>virtualenv</category></item><item><title>Spawning subprocesses smartly and securely</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/</link><pubDate>Sat, 02 Sep 2017 18:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/</guid><description>
As part of your code, you may be inclined to call a command to do
something. But is it always a good idea? How to do it safely? What happens
behind the scenes?
</description><content:encoded><![CDATA[
<p>As part of your code, you may be inclined to call a command to do
something. But is it always a good idea? How to do it safely? What happens
behind the scenes?</p>



<p>This article is written from a general perspective, with a Unix/C bias and a
very slight Python bias. The problems mentioned apply to all languages in most
environments, including Windows.</p>
<section id="use-the-right-tool-for-the-job">
<h1>Use the right tool for the job</h1>
<p>By calling another process, you introduce a third-party dependency.
That dependency isn’t controlled by your code, and your code becomes more fragile.
The problems include:</p>
<ul class="simple">
<li><p>the program is not installed, or even available, for the user’s OS of choice</p></li>
<li><p>the program is not in the <code class="docutils literal">$PATH</code> your process gets</p></li>
<li><p>the hard-coded path is not correct on the end user’s system</p></li>
<li><p>the program is in a different version (eg. GNU vs. BSD, updates/patches),
which means different option names or other behaviors</p></li>
<li><p>the program’s output is not what you expected due to user config (including
locale)</p></li>
<li><p>error reporting is based on numeric exit codes, and the meaning of those
differs between programs (<em>if</em> they have meaning besides 0/1 in the first
place)</p></li>
</ul>
<p>On the other hand, if your code uses a lot of subprocesses, perhaps you should
stay with Bash. You can do the harder parts with Python, Ruby, or some other
language by calling them from within your Bash script.</p>
</section>
<section id="dont-spawn-subprocesses-if-theres-an-alternative">
<h1>Don’t spawn subprocesses if there’s an alternative</h1>
<p>Spawning a subprocess always incurs a (minor) <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a> performance hit minor
compared to the alternatives. With that in mind, and the resiliency issues
listed above, you should always try to find an alternative for the
external command.</p>
<p>The simplest ones are the basic Unix utilities. Replace <code class="docutils literal">grep</code>, <code class="docutils literal">sed</code> and
<code class="docutils literal">awk</code> with string operations and regular expressions. Filesystem utilities
will have equivalents — for Python, in <code class="docutils literal">os</code> or <code class="docutils literal">shutil</code>. Your language of
choice can also handle things like networking (don’t call <code class="docutils literal">curl</code>), file
compression, working with date/time…</p>
<p>Similarly, you should check if there are packages available that already do
what you want — library bindings or re-implementations. And if there isn’t,
perhaps you could help the world by writing one of those and sharing it?</p>
<p>One more important thing: if the program uses the same language as your code,
then you should try to import the code and run it from the same process instead
of spawning a process, if this is feasible.</p>
</section>
<section id="security-considerations-shells-spaces-and-command-injection">
<h1>Security considerations: shells, spaces, and command injection</h1>
<p>We come to the most important part of this article: how to spawn subprocesses
without compromising your system. When you spawn a subprocess on a typical Unix
system,  <code class="docutils literal">fork()</code> is called, and your process is copied. Many modern Unix
systems have a copy-on-write implementation of that syscall, meaning that the
operation does not result in copying all the memory of the host process over.
Forking is (almost) immediately followed by calling <code class="docutils literal">execve()</code> (or a helper
function from the exec family) <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-2" id="footnote-reference-2" role="doc-noteref"><span class="fn-bracket">[</span>2<span class="fn-bracket">]</span></a> in the child process — that function
<em>transforms the calling process into a new process</em> <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-3" id="footnote-reference-3" role="doc-noteref"><span class="fn-bracket">[</span>3<span class="fn-bracket">]</span></a>. This technique is
called <em>fork-exec</em> and is the typical way to spawn a new process on Unix. <a class="brackets" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-4" id="footnote-reference-4" role="doc-noteref"><span class="fn-bracket">[</span>4<span class="fn-bracket">]</span></a></p>
<p>There are two ways to access this API, from the C perspective:</p>
<ul>
<li><p>directly, by calling <code class="docutils literal">fork()</code> and <code class="docutils literal"><span class="pre">exec*()</span></code> (or <code class="docutils literal">posix_spawn()</code>), and providing an array of
arguments passed to the process, or</p></li>
<li><p>through the shell (<code class="docutils literal">sh</code>), usually by calling <code class="docutils literal">system()</code>. As Linux’s
manpage for <code class="docutils literal">system(3)</code> puts it,</p>
<blockquote>
<p>The <code class="docutils literal">system()</code> library function uses <code class="docutils literal">fork(2)</code> to create a child process that executes the shell command specified in command using <code class="docutils literal">execl(3)</code> as follows:</p>
<div class="code"><pre class="code c"><a id="rest_code_ba3def1e6d134f318af0424fea199c9a-1" name="rest_code_ba3def1e6d134f318af0424fea199c9a-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ba3def1e6d134f318af0424fea199c9a-1"></a><span class="n">execl</span><span class="p">(</span><span class="s">&quot;/bin/sh&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;sh&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;-c&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">command</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
</pre></div>
</blockquote>
</li>
</ul>
<p>If you go through the shell, you pass one string argument, whereas <code class="docutils literal"><span class="pre">exec*()</span></code> demands you to specify arguments separately. Let’s write a sample program to print all the arguments it receives. I’ll do it in Python to get a more readable output.</p>
<div class="code"><pre class="code python"><a id="rest_code_ce72efbf58624ae598862ad3319d5d48-1" name="rest_code_ce72efbf58624ae598862ad3319d5d48-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-1"></a><span class="ch">#!/usr/bin/env python3</span>
<a id="rest_code_ce72efbf58624ae598862ad3319d5d48-2" name="rest_code_ce72efbf58624ae598862ad3319d5d48-2" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-2"></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
<a id="rest_code_ce72efbf58624ae598862ad3319d5d48-3" name="rest_code_ce72efbf58624ae598862ad3319d5d48-3" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_ce72efbf58624ae598862ad3319d5d48-3"></a><span class="nb">print</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>
</pre></div>
<p>Let’s see what appears:</p>
<div class="code"><pre class="code text"><a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-1"></a>$ ./argv.py foo bar
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-2"></a>[&#39;./argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-3"></a>$ ./argv.py &#39;foo bar&#39;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-4"></a>[&#39;./argv.py&#39;, &#39;foo bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-5"></a>$ ./argv.py foo\ bar baz
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-6"></a>[&#39;./argv.py&#39;, &#39;foo bar&#39;, &#39;baz&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-7"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-8"></a>$ ./argv.py $(date)
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-9"></a>[&#39;./argv.py&#39;, &#39;Sat&#39;, &#39;Sep&#39;, &#39;2&#39;, &#39;16:54:52&#39;, &#39;CEST&#39;, &#39;2017&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-10"></a>$ ./argv.py &quot;$(date)&quot;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-11"></a>[&#39;./argv.py&#39;, &#39;Sat Sep  2 16:54:52 CEST 2017&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-12"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-13"></a>$ ./argv.py /usr/*
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-14"></a>[&#39;./argv.py&#39;, &#39;/usr/X11&#39;, &#39;/usr/X11R6&#39;, &#39;/usr/bin&#39;, &#39;/usr/include&#39;, &#39;/usr/lib&#39;, &#39;/usr/libexec&#39;, &#39;/usr/local&#39;, &#39;/usr/sbin&#39;, &#39;/usr/share&#39;, &#39;/usr/standalone&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-15"></a>$ ./argv.py &quot;/usr/*&quot;
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-16"></a>[&#39;./argv.py&#39;, &#39;/usr/*&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-17"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-18"></a>$ ./argv.py $EDITOR
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-19"></a>[&#39;./argv.py&#39;, &#39;nvim&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-20"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-21"></a>$ $PWD/argv.py foo bar
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-22"></a>[&#39;/Users/kwpolska/Desktop/blog/subprocess/argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-23"></a>$ ./argv.py a{b,c}d
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-24"></a>[&#39;./argv.py&#39;, &#39;abd&#39;, &#39;acd&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-25"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-26"></a>$ python argv.py foo bar | cat
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-27"></a>[&#39;argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-28"></a>$ python argv.py foo bar &gt; foo.txt
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-29"></a>$ cat foo.txt
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-30"></a>[&#39;argv.py&#39;, &#39;foo&#39;, &#39;bar&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-31"></a>
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-32"></a>$ ./argv.py foo; ls /usr
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-33"></a>[&#39;./argv.py&#39;, &#39;foo&#39;]
<a id="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34" name="rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#rest_code_8db936d5a5784d2eba2d26845ebcc5c4-34"></a>X11@        X11R6@      bin/        include/    lib/        libexec/    local/      sbin/       share/      standalone/
</pre></div>
<p>As you can see, the following things are handled by the shell (the process is unaware of this occurring):</p>
<ul class="simple">
<li><p>quotes and escapes</p></li>
<li><p>expanding expressions in braces</p></li>
<li><p>expanding variables</p></li>
<li><p>wildcards (glob, <code class="docutils literal">*</code>)</p></li>
<li><p>redirections and pipes (<code class="docutils literal">&gt; &gt;&gt; |</code>)</p></li>
<li><p>command substitution (backticks or <code class="docutils literal"><span class="pre">$(…)</span></code>)</p></li>
<li><p>running multiple commands on the same line (<code class="docutils literal">; &amp;&amp; || &amp;</code>)</p></li>
</ul>
<p>The list is full of potential vulnerabilities. If end users are in control of
the arguments passed, and you go through the shell, they can
<strong>execute arbitrary commands</strong> or even <strong>get full shell access</strong>. Even in other
cases, you’ll have to <em>depend on the shell’s parsing</em>, which introduces an
unnecessary indirection.</p>
</section>
<section id="tl-dr-how-to-do-this-properly-in-your-language-of-choice">
<h1>TL;DR: How to do this properly in your language of choice</h1>
<p>To ensure spawning subprocess is done securely, <strong>do not use the shell in between</strong>. If you need any of the operations I listed above as part of your command — wildcards, pipes, etc. — you will need to take care of them in your code; most languages have those features built-in.</p>
<dl class="simple dl-horizontal">
<dt>In C (Unix)</dt>
<dd><p>Perform fork-exec by yourself, or use <code class="docutils literal">posix_spawn()</code>. This also lets you communicate with the process if you open a pipe and make it stdout of the child process. Never use <code class="docutils literal">system()</code>.</p>
</dd>
<dt>In Python</dt>
<dd><p>Use the subprocess module. Always pass <code class="docutils literal">shell=False</code> and give it a <em>list</em> of arguments. With asyncio, use <code class="docutils literal">asyncio.create_subprocess_exec</code> (and not <code class="docutils literal">_shell</code>), but note it takes <code class="docutils literal">*args</code> and not a list. Never use <code class="docutils literal">os.system</code> and <code class="docutils literal">os.popen</code>.</p>
</dd>
<dt>In Ruby</dt>
<dd><p>Pass arrays to <code class="docutils literal">IO.popen</code>. Pass multiple arguments to <code class="docutils literal">system()</code> (<code class="docutils literal"><span class="pre">system([&quot;ls&quot;,</span> <span class="pre">&quot;ls&quot;])</span></code> or <code class="docutils literal"><span class="pre">system(&quot;ls&quot;,</span> <span class="pre">&quot;-l&quot;)</span></code>). Never use <code class="docutils literal">%x{command}</code> or backticks.</p>
</dd>
<dt>In Java</dt>
<dd><p>Pass arrays to <code class="docutils literal">Runtime.exec</code>. Pass multiple arguments or list to <code class="docutils literal">ProcessBuilder</code>.</p>
</dd>
<dt>In PHP</dt>
<dd><p>All the standard methods go through the shell. Try <code class="docutils literal">escapeshellcmd()</code>, <code class="docutils literal">escapeshellarg()</code> — or better, switch to Python. Or anything, really.</p>
</dd>
<dt>In Go</dt>
<dd><p><code class="docutils literal">os/exec</code> and <code class="docutils literal">os.StartProcess</code> are safe.</p>
</dd>
<dt>In Node.js</dt>
<dd><p>Use <code class="docutils literal">child_process.execFile</code> or <code class="docutils literal">child_process.spawn</code> with <code class="docutils literal">shell</code> set to false.</p>
</dd>
<dt>Elsewhere</dt>
<dd><p>You should be able to specify multiple strings (using variadic arguments,
arrays, or otherwise standard data structures of your language of choice) as
the command line. Otherwise, you might be running into something
shell-related.</p>
</dd>
</dl>
</section>
<section id="the-part-where-i-pretend-i-know-something-about-windows">
<h1>The part where I pretend I know something about Windows</h1>
<p>On Windows, argument lists are always passed to processes as strings (Python
joins them semi-intelligently if it gets a list). Redirections and variables
work in shell mode, but globs (asterisks) are always left for the called
process to handle.</p>
<p>Some useful functions are implemented as shell built-ins — in that case, you
need to call it via the shell.</p>
<p>Internals: There is no <code class="docutils literal">fork()</code> on Windows. Instead, <code class="docutils literal">CreateProcess()</code>,
<code class="docutils literal">ShellExecute()</code>, or lower-level <code class="docutils literal"><span class="pre">spawn*()</span></code> functions are used. <code class="docutils literal">cmd.exe
/c</code> is called in shell calls.</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="footnote-1" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-1">1</a><span class="fn-bracket">]</span></span>
<p>Unless your operating system does not implement copy-on-write forking — in that case, you might even run out of memory if you use too much of it.</p>
</aside>
<aside class="footnote brackets" id="footnote-2" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-2">2</a><span class="fn-bracket">]</span></span>
<p>The function that does the real work is <code class="docutils literal">execve()</code>, which takes an exact path, an array of arguments, and takes environment variables as input. Other variants can also perform a <code class="docutils literal">$PATH</code> search, take argv as variadic arguments, and inherit environment from the current process. <code class="docutils literal">execl()</code> does the last two.</p>
</aside>
<aside class="footnote brackets" id="footnote-3" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-3">3</a><span class="fn-bracket">]</span></span>
<p>Quoted from <code class="docutils literal">execve(2)</code> <a class="reference external" href="https://www.freebsd.org/cgi/man.cgi?query=execve&amp;sektion=2">man page</a> from FreeBSD.</p>
</aside>
<aside class="footnote brackets" id="footnote-4" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2017/09/02/spawning-subprocesses-smartly-and-securely/#footnote-reference-4">4</a><span class="fn-bracket">]</span></span>
<p>An alternative is <code class="docutils literal">posix_spawn()</code>, but it usually does fork-exec, unless your platform does not support forking.</p>
</aside>
</aside>
</section>
]]></content:encoded><category>Programming</category><category>best practices</category><category>C</category><category>devel</category><category>guide</category><category>Linux</category><category>Python</category><category>security</category><category>subprocess</category><category>Unix</category></item><item><title>Setting up a Python development environment</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/</link><pubDate>Mon, 03 Jul 2017 10:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/</guid><description>
Setting up Python is usually simple, but there are some places where newcomers
(and experienced users) need to be careful. What versions are there? What’s the
difference between Python, CPython, Anaconda, PyPy? Those and many other
questions may stump new developers, or people wanting to use Python.
</description><content:encoded><![CDATA[
<p>Setting up Python is usually simple, but there are some places where newcomers
(and experienced users) need to be careful. What versions are there? What’s the
difference between Python, CPython, Anaconda, PyPy? Those and many other
questions may stump new developers, or people wanting to use Python.</p>



<p>Note: this guide is opinionated.</p>
<section id="glossary-and-questions">
<h1>Glossary and questions</h1>
<section id="python-versions-2-vs-3">
<h2>Python versions: 2 vs 3</h2>
<p>The Python community has undergone sort of a <em>schism</em> in recent years. Python
3, released in 2008, broke backwards compatibility: deprecated some bad
constructs and libraries (eg. <code class="docutils literal">raw_input()</code> became <code class="docutils literal">input()</code> and the
original Python 2 function that ran code input by users is gone; <code class="docutils literal">print()</code>
became a function; many things that returned lists now are iterators — <code class="docutils literal">zip</code>,
<code class="docutils literal">range</code>), and completely remodelled strings (which are now Unicode by
default, and the interpreter behavior is stricter when the wrong type is used)</p>
<p>For new code, you should use Python 3. <a class="reference external" href="https://python3wos.appspot.com/">Most popular packages support Python 3</a>, and many of them support both Pythons at
the same time. The early bugs were ironed out in the first few point releases,
some features that made porting easier were added (back).</p>
<p>But what if you end up needing Python 2 later? No problem: you can learn the
differences in a short time, and with the help of a few libraries (eg. <code class="docutils literal">six</code>)
you can easily write code that is compatible with Python 2 and 3 at the same
time, using the same codebase (most libraries out there do that).</p>
<p>Python 2 will go EOL and lose official support and updates in 2020.</p>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/Python2orPython3">Python 2 or Python 3 on Python Wiki</a></p>
</section>
<section id="can-i-run-multiple-pythons-on-the-same-machine">
<h2>Can I run multiple Pythons on the same machine?</h2>
<p>Yes. Note that multiple Python interpreters are completely separate: they have
their own pip and packages, and you can’t run Python 2 code in a Python 3
interpreter. You need to specify which interpreter to use when installing
packages and running some scripts (eg. <code class="docutils literal">pip2</code>, <code class="docutils literal">pip3</code> or <code class="docutils literal">python3 <span class="pre">-m</span> pip</code>).</p>
<p>It’s best to limit yourself to the latest Python 2 and 3 versions. Python is
backwards-compatible within the major release, so Python 2.7 runs code
written with older 2.x versions in mind.</p>
</section>
<section id="implementations">
<h2>Implementations</h2>
<p>A programming language is an abstract construct. To run code written in that
language, an interpreter or compiler needs to be written. In Python’s case,
there’s a plethora of implementations. Some of them are:</p>
<ul class="simple">
<li><p><strong>CPython</strong> is the reference implementation. This is the implementation
distributed on <a class="reference external" href="https://python.org/">https://python.org/</a> and as part of many operating systems.
Most Python features are first implemented in CPython, and then they are
ported to other implementations.  If you don’t know what to choose, use
CPython.</p></li>
<li><p><strong>PyPy</strong> is a fast implementation, written in a subset of Python. It’s compatible with
Python 2.7 and 3.5 (beta support). It can run all pure Python code, and many
extension libraries that use CFFI.</p></li>
<li><p><strong>IronPython</strong> is a .NET CLR implementation. It can integrate with .NET code.</p></li>
<li><p><strong>Jython</strong> is a Java JVM implementation. It can integrate with Java code, as
well as other JVM languages.</p></li>
</ul>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/PythonImplementations">Python Implementations on Python Wiki</a></p>
</section>
<section id="distributions">
<h2>Distributions</h2>
<p>There are also Python (CPython) distributions. They ship the CPython
interpreter and add some extra packages/features.  They are maintained by other
communities or corporate entities.</p>
<p>The most popular third-party distribution is <a class="reference external" href="https://www.continuum.io/downloads">Anaconda</a> from Continuum Analytics. It’s popular
for data scientists, and includes over 100 packages, with extra pre-built
binaries available from the <code class="docutils literal">conda</code> package manager.</p>
<p>I personally recommend to avoid Anaconda:</p>
<ul class="simple">
<li><p>Most packages have binary wheels for Windows, macOS and Linux (yes, Linux!)
making the installation as simple as <code class="docutils literal">pip install numpy</code>.</p></li>
<li><p>You waste disk space for packages Anaconda installs that you won’t ever need.</p></li>
<li><p>It’s provided by some random for-profit company.</p></li>
<li><p>I’ve seen bugs that were not reproducible outside of Anaconda.</p></li>
<li><p>You can still do data science using the official distribution. There’s
nothing special about Anaconda.</p></li>
</ul>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/PythonDistributions">Python distributions on Python Wiki</a></p>
</section>
<section id="can-i-make-exe-files-from-python-programs">
<h2>Can I make .exe files from Python programs?</h2>
<p>Yes, you can. There are tools for this — <a class="reference external" href="http://www.pyinstaller.org/">PyInstaller</a> is the best one. Note that you usually need to
run it on the destination operating system. And remember that “compiling” to
exe files like that <strong>is not</strong> a security measure — your source code is still
easily recoverable. (It’s not a security measure in other languages either,
even if getting source code back might be more expensive/tricky in those.)</p>
</section>
<section id="where-to-learn-python-where-to-get-help">
<h2>Where to learn Python? Where to get help?</h2>
<p>The choice of learning material is important. If you get a bad book, it might
discourage you from learning (because it’s boring), or may teach you
bad/outdated practices.</p>
<p>If you can already program in another language, I recommend the <a class="reference external" href="https://docs.python.org/3/tutorial/">official
Python tutorial</a>. For newcomers to
programming, I recommend <a class="reference external" href="http://greenteapress.com/wp/think-python-2e/">Think Python</a> or <a class="reference external" href="https://automatetheboringstuff.com/">Automate the Boring Stuff
with Python</a>.  They teach Python 3, and
(mostly) best practices.</p>
<p>If you need help, try <code class="docutils literal">#python</code> on freenode IRC, the <a class="reference external" href="https://mail.python.org/mailman/listinfo/tutor">Tutor</a> or <a class="reference external" href="https://mail.python.org/mailman/listinfo/python-list">Python-list</a> mailing lists, or a bunch of other communities. (I’m a regular on <code class="docutils literal">#python</code>)</p>
</section>
</section>
<section id="installing-python">
<h1>Installing Python</h1>
<p>This guide will focus on installing CPython 2.7 and 3.x (latest), using the standard
distribution. This choice is satisfactory for most people. Third-party
distributions, while handy in some cases, are not needed for most. (See
<a class="reference internal" href="https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/#distributions">Distributions</a> for arguments)</p>
<p>Throughout this guide, I’ll refer to the Python interpreter executable as
<code class="docutils literal">python</code>. The exact name depends on your system and desired version. On most
OSes, <code class="docutils literal">python</code> is Python 2 and <code class="docutils literal">python3</code> is 3; <code class="docutils literal">python2</code> should also
exist.  On Arch Linux, <code class="docutils literal">python</code> is Python 3. On Windows, use the <code class="docutils literal">py</code>
launcher.</p>
<section id="windows">
<h2>Windows</h2>
<p>Download the installer(s): <a class="reference external" href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></p>
<p>Those installers come with <code class="docutils literal">pip</code>, and modern Python 3.x versions come with
the <code class="docutils literal">py</code> launcher.  You can use that launcher to pick a specific Python
version, eg.:</p>
<ul class="simple">
<li><p><code class="docutils literal">py <span class="pre">-3</span> <span class="pre">-m</span> pip install &lt;package&gt;</code></p></li>
<li><p><code class="docutils literal">py <span class="pre">-2</span> somefile.py</code></p></li>
<li><p><code class="docutils literal">py <span class="pre">-2.7</span></code></p></li>
<li><p><code class="docutils literal">py</code> (default system version)</p></li>
</ul>
<p>It’s recommended for most use, and mandatory for upgrading pip.</p>
<p>The 32-bit versions are more versatile. Most packages support both (the only
exception I’m aware of is Tensorflow, which only allows 64-bit Python 3.5 as of
now).</p>
</section>
<section id="macos">
<h2>macOS</h2>
<p>macOS ships with Python 2.7.10 (as of macOS Sierra). It’s not the latest
version; it’s good enough for most people, but I still recommend installing
your own (the system Python doesn’t include <code class="docutils literal">pip</code>, for example). You can
install the latest 2.7 version, as well as Python 3, using a package manager. I
recommend Homebrew — it’s the most popular solution, and lets you install many
other packages.</p>
<p><strong>DO NOT</strong> use the python.org installers: they do not have uninstallers, so you
will have outdated versions lying around after some time. There is no
auto-update as well.  <strong>DO NOT</strong> attempt to remove the system-installed Python,
this will only damage your system and you’ll need to reinstall.</p>
<p>If you already have a package manager installed (MacPorts, Fink), don’t install
a new one and just use the existing one.</p>
<ol class="arabic simple">
<li><p>Install <a class="reference external" href="https://brew.sh/">Homebrew</a>.</p></li>
<li><p>Run <code class="docutils literal">brew install python python3</code>.</p></li>
<li><p>You should now have <code class="docutils literal">python</code>, <code class="docutils literal">python3</code>, <code class="docutils literal">pip</code> and <code class="docutils literal">pip3</code>.</p></li>
</ol>
<p>To update Homebrew and Python, run <code class="docutils literal">brew update</code>.</p>
</section>
<section id="linux-and-other-unix-like-oses">
<h2>Linux (and other Unix-like OSes)</h2>
<p>On Linux, there usually are good enough packages in your OS repositories. You
should be able to install the appropriate package for Python (2 and/or 3).
Most (if not all) distributions require Python — <strong>do not</strong> remove the
pre-installed packages, and be careful not to overwrite them with something
newer.</p>
<p>If the version that ships with your distribution is too old, there are some
options. There might be some repositories with better versions, eg. the
<a class="reference external" href="https://launchpad.net/~fkrull/+archive/ubuntu/deadsnakes">deadsnakes PPA</a>
for Ubuntu. Then there’s the other option of compiling Python. There
are some tools to help with this, like <code class="docutils literal">pyenv</code> or <code class="docutils literal">pythonz</code> (they can also
manage multiple Python versions), or you can do it manually.
The instructions depend on your exact requirements, but here’s a summary:</p>
<ol class="arabic simple">
<li><p>Download the <a class="reference external" href="https://www.python.org/downloads/source/">source distribution from Python.org</a> and unpack it. Go into the unpacked source directory.</p></li>
<li><p>Ensure you’ve got a functional C compiler and Python’s dependencies. You can
usually use your system’s package manager to install the build dependencies
of your system Python. Some dependencies are optional (eg. <code class="docutils literal">sqlite3</code>
requires SQLite headers).</p></li>
<li><p>Run <code class="docutils literal">./configure <span class="pre">--prefix=/opt/python3.6</span></code> and then <code class="docutils literal">make</code>. (You may add other options to both. It will
take a while.)</p></li>
<li><p>Run <code class="docutils literal">make altinstall</code> as root. Avoid <code class="docutils literal">make install</code>, as it can override
<code class="docutils literal">python</code> executables.</p></li>
</ol>
<p>Remember: compiling Python should be considered a <strong>last resort</strong>, unless you
have very specific Python version requirements.</p>
</section>
</section>
<section id="installing-packages">
<h1>Installing packages</h1>
<p>To install third-party packages, you should use pip, the Python package
manager. If you’re using Windows or macOS (from Homebrew), pip is included with
your copy of Python.  If you’re on Linux and installed Python from a system
repository, install the correct system package (<code class="docutils literal"><span class="pre">python-pip</span></code>,
<code class="docutils literal"><span class="pre">python3-pip</span></code>). If you compiled your own Python, pip is also included.</p>
<p>To run pip, use <code class="docutils literal">py <span class="pre">-m</span> pip</code> (Windows), <code class="docutils literal">python <span class="pre">-m</span> pip</code> (other platforms),
or the short <code class="docutils literal">pip</code>/<code class="docutils literal">pip3</code> commands.</p>
<p><strong>NEVER use sudo pip.</strong> This can cause numerous problems:</p>
<ul class="simple">
<li><p>conflicts between packages installed by pip and your system package
manager</p></li>
<li><p>pip modifying system packages, leading to issues when updating them, or
breaking dependencies</p></li>
<li><p>no isolation between package versions, which is sometimes needed to satisfy
dependencies</p></li>
</ul>
<p>Note that a package install is specific to the Python interpreter used to run
<code class="docutils literal">pip</code>. Packages installed to a virtualenv are separate from system packages;
packages installed for “global” Python 2.7 are separate from 3.6 packages.
Virtual environments generally don’t use the system packages, unless
specifically enabled during creation.</p>
<p>Some distros have popular packages in their repositories. Sometimes they’re
good; in other cases they’re terribly outdated or they lack important
components, making package managers angry and sick of supporting a 2-year-old
version. (Especially since most bugs are closed with “we’ve fixed that long
ago”)</p>
<section id="user-installs">
<h2>User installs</h2>
<p>At a small scale, you can install packages with pip for a single user.  Use
<code class="docutils literal">pip install <span class="pre">--user</span> PACKAGE</code> to do this. If your package installs <a class="reference external" href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/">scripts</a>,
they will be installed to <code class="docutils literal"><span class="pre">~/.local/bin</span></code> on Linux, and
<code class="docutils literal">~/Library/Python/X.Y/bin</code> on macOS (X.Y is Python version), or you can use
<code class="docutils literal">python <span class="pre">-m</span></code> if the package supports it.</p>
<p>For most people and projects, virtual environments are better. There are,
however, use cases for putting some packages user-wide — if you don’t work on
projects, but instead are doing one-off research projects, those are better
suited by user-wide installs.</p>
</section>
<section id="virtual-environments">
<h2>Virtual environments</h2>
<p class="lead">I wrote a newer, more detailed post about virtualenvs: <a class="reference external" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/">Python Virtual
Environments in Five Minutes</a></p>
<p>Virtual environments are the best way to install and manage Python packages.
Advantages include:</p>
<ul class="simple">
<li><p>Isolation of projects and their requirements: if one app/package requires
library version X, but another requires version Y, they can live in separate
virtual environments</p></li>
<li><p>Independent from system-wide packages</p></li>
<li><p>Lightweight (an empty virtualenv is about 10 MB)</p></li>
<li><p>Simple to re-create in any place (<code class="docutils literal">pip freeze &gt; requirements.txt</code> → <code class="docutils literal">pip install <span class="pre">-r</span> requirements.txt</code>)</p></li>
</ul>
<section id="tools-and-management">
<h3>Tools and management</h3>
<p>There are two tools to facilitate creation of virtual environments: the older
<a class="reference external" href="https://virtualenv.pypa.io/en/stable/">virtualenv</a> project, and the newer
<code class="docutils literal">venv</code> module. The <code class="docutils literal">venv</code> module is shipped with Python 3.x; some
distributions may put it in a separate package or remove it altogether. Use
whichever works for you.  Virtualenv is compatible with more Python versions
and cannot be broken by incompetent OS package maintainers (<code class="docutils literal">venv</code> requires
an extra package on Debian).</p>
<p>There are multiple schools of thought regarding virtualenv placement and
content. Myself, I use <a class="reference external" href="https://virtualenvwrapper.readthedocs.io/en/latest/">virtualenvwrapper</a> to manage virtualenvs
and put them in <code class="docutils literal">~/virtualenvs</code>. Other people put virtualenvs inside their
git repositories (but they <em>must</em> be in <code class="docutils literal">.gitignore</code>) Virtualenvs should only contain packages
installed with <code class="docutils literal">pip</code> so they can be recreated quickly.</p>
<p>I also use the <code class="docutils literal">virtualenvwrapper</code> plugin for Oh My Zsh, which also
activates virtualenvs with the same name as a git repo, or the environment
named by a <code class="docutils literal">.venv</code> file.</p>
</section>
<section id="installation-and-usage">
<h3>Installation and usage</h3>
<p>To install virtualenv user-wide, use <code class="docutils literal">pip install <span class="pre">--user</span> virtualenv</code>. You can
then use it with <code class="docutils literal">python <span class="pre">-m</span> virtualenv DIRECTORY</code>. You may pass extra
options, eg. interpreter to use (<code class="docutils literal"><span class="pre">-p</span> python3</code>). Sometimes you need to install
virtualenv for every Python version; usually, one copy is enough.</p>
<p>How to use them? This is a subject of heated debate in the Python community.</p>
<ul class="simple">
<li><p>Some people believe that activating (<code class="docutils literal">source bin/activate</code> on *nix;
<code class="docutils literal">Scripts\activate</code> on Windows) is the right thing to do and simplifies work.</p></li>
<li><p>Others think that you should use <code class="docutils literal">bin/python</code> (or other scripts in that
directory) directly, as activation only changes <code class="docutils literal">$PATH</code> and some helper
variables — those variables are not mandatory for operation, running
the correct <code class="docutils literal">python</code> is.</p></li>
<li><p>Others still think <a class="reference external" href="https://gist.github.com/datagrok/2199506">virtualenvs should be used in subshells</a>.</p></li>
</ul>
<p>In my opinion, if activating virtualenvs works in your environment, you should
do it — it’s the most convenient option. There are, however, cases when
activation fails, or is otherwise impossible — calling <code class="docutils literal">bin/python</code> directly
is your best bet in that case. If you are working inside shell scripts, do not
activate virtualenvs.  I’m not a fan of the subshell option, because it
complicates stuff if you work on multiple projects, and requires tracking usage
manually.</p>
</section>
<section id="upgrading-and-moving">
<h3>Upgrading and moving</h3>
<p>Upgrading the system Python may make your virtualenvs unusable.
For patch version upgrades, you can just update symlinks (see <a class="reference external" href="https://github.com/Kwpolska/scripts/blob/master/fix-venvs.sh">fix-venvs.sh</a>).
However, if the minor version changes, it’s best to re-create the virtualenv
(you need to create <code class="docutils literal">requirements.txt</code> ahead of time).</p>
<p>You cannot move a virtualenv between directories/machines or rename
virtualenvs. You need to use <code class="docutils literal">pip freeze &gt; requirements.txt</code>, create a new
virtualenv, and run <code class="docutils literal">pip install <span class="pre">-r</span> requirements.txt</code> (you can then delete
the old environment with a simple <code class="docutils literal">rm <span class="pre">-rf</span></code>)</p>
</section>
</section>
<section id="packages-with-c-extensions-binary">
<h2>Packages with C extensions (binary)</h2>
<p>The situation improved drastically in the past year or so. Nowadays, almost
all packages have a pre-compiled package available in PyPI. Those packages work
for Windows, macOS, and Linux. There are packages for some of the most
common <em>offenders</em>, including Pillow, lxml, PyQt5, numpy… However, there might
still be packages without wheels on PyPI.</p>
<p>If there is no wheel for a package and you are on Windows, check out <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">Christoph
Gohlke’s unofficial binaries</a>.
If you can’t find any wheels online, you would have to resort to compiling it
manually — this requires installing Visual Studio (Visual C++) in a version
that matches your Python, and it’s kind of a pain to do.</p>
<p>If you are not on Windows, you must install a C compiler and toolchain.
If you get a warning about missing <code class="docutils literal">Python.h</code>, install the appropriate development
package — for example, <code class="docutils literal"><span class="pre">python-dev</span></code> or <code class="docutils literal"><span class="pre">python3-dev</span></code>) on Debian/Ubuntu,
<code class="docutils literal"><span class="pre">python-devel</span></code> or <code class="docutils literal"><span class="pre">python3-devel</span></code> on RHEL/Fedora. The package you’re trying
to install might have other dependencies that you need to install (the
<code class="docutils literal"><span class="pre">-dev(el)</span></code> part is important, too)</p>
</section>
<section id="other-stuff">
<h2>Other stuff</h2>
<p>If you’re working on a project, use <code class="docutils literal">pip install <span class="pre">-e</span> .</code> inside the project
directory to install the package in your environment in development (editable)
mode. This loads code directly from your repository — you don’t need to
re-install on every change; you might need to re-install when your version
number changes.</p>
</section>
</section>
<section id="editors-and-ides">
<h1>Editors and IDEs</h1>
<p>Another important thing a developer should take care of is the choice of an
editor. This is an important decision, and is the reason for many holy wars in
the programmer community.</p>
<p>A good editor should have syntax highlighting for all languages you need to
work with. It should also have features like visual block/multiple selections,
sophisticated find-and-replace, file finding, code completion, and many more minor
but helpful features.</p>
<p>Then there’s the difference between IDEs and text editors. Text editors are
simpler, whereas IDEs try to include many extra things not necessarily related
to writing code. IDEs often use more resources, but you won’t notice it with a
modern computer (especially with a SSD).</p>
<p>The best IDE out there is <a class="reference external" href="https://www.jetbrains.com/pycharm/">PyCharm</a> from
JetBrains. It has both a free Community and paid Professional edition. The
JetBrains folks are experts at IDEs — they have fully-fledged tools for many
languages. Their Python solution offers a plethora of options that aid
programmers in their work.  Also, if you work with Java, or otherwise more than
one IDEA-supported language, then install IntelliJ IDEA and the Python plugin
(which has the same features as PyCharm).  Students can get <a class="reference external" href="https://www.jetbrains.com/student/">free
Professional/Ultimate licenses for JetBrains products</a>.</p>
<p>I also spend a lot of time in <a class="reference external" href="http://www.vim.org/">Vim</a> (<a class="reference external" href="https://neovim.io/">neovim</a>/<a class="reference external" href="http://vimr.org/">VimR</a> to be precise). Vim is the
most powerful text editor out there, and with the right set of plugins it can
beat IDEs at speed and productivity. Vim has a steep learning curve, but it’s
worth it — you can do large changes with just a few keystrokes. Vim is
considered so good that many IDEs (Visual Studio, IntelliJ IDEA/PyCharm) have
Vim emulation plugins.</p>
<p>Another option is <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a> — it’s
a text editor, but can offer many IDE-like features with the right set of
plugins. It’s Electron-based architecture, or effectively being based on top of
Google’s Chromium, is unfortunate and can lead to terrible performance on
lower-end machines, and on higher-end ones in some cases. (In my experience,
it’s better than Atom.) You can also try <a class="reference external" href="https://www.sublimetext.com/">Sublime Text</a> ($80).</p>
<p>But really, almost any editor will do. But please <strong>avoid</strong> IDLE, the editor
included with Python. It lacks some of the most basic things — it doesn’t even
have an option to show line numbers. Not to mention its ugliness. Also, don’t
use Notepad and TextEdit. Those are too simple, and Notepad has encoding
issues.</p>
</section>
<section id="update-history">
<h1>Update history</h1>
<dl class="simple">
<dt>2018-09-21</dt>
<dd><p>Link to python-virtual-environments post.</p>
</dd>
<dt>2017-07-19</dt>
<dd><p>Better description of problems caused by using sudo pip.</p>
</dd>
<dt>2017-07-10</dt>
<dd><p>Added notes about not removing built-in Pythons.</p>
</dd>
<dt>2017-07-07</dt>
<dd><p>Spelling fixes and updates to the virtualenv usage section.</p>
</dd>
</dl>
</section>
]]></content:encoded><category>Python</category><category>best practices</category><category>devel</category><category>guide</category><category>guide</category><category>Python</category></item><item><title>Setting up a Python development environment</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/</link><pubDate>Mon, 03 Jul 2017 10:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/</guid><description>
Setting up Python is usually simple, but there are some places where newcomers
(and experienced users) need to be careful. What versions are there? What’s the
difference between Python, CPython, Anaconda, PyPy? Those and many other
questions may stump new developers, or people wanting to use Python.
</description><content:encoded><![CDATA[
<p>Setting up Python is usually simple, but there are some places where newcomers
(and experienced users) need to be careful. What versions are there? What’s the
difference between Python, CPython, Anaconda, PyPy? Those and many other
questions may stump new developers, or people wanting to use Python.</p>



<p>Note: this guide is opinionated.</p>
<section id="glossary-and-questions">
<h1>Glossary and questions</h1>
<section id="python-versions-2-vs-3">
<h2>Python versions: 2 vs 3</h2>
<p>The Python community has undergone sort of a <em>schism</em> in recent years. Python
3, released in 2008, broke backwards compatibility: deprecated some bad
constructs and libraries (eg. <code class="docutils literal">raw_input()</code> became <code class="docutils literal">input()</code> and the
original Python 2 function that ran code input by users is gone; <code class="docutils literal">print()</code>
became a function; many things that returned lists now are iterators — <code class="docutils literal">zip</code>,
<code class="docutils literal">range</code>), and completely remodelled strings (which are now Unicode by
default, and the interpreter behavior is stricter when the wrong type is used)</p>
<p>For new code, you should use Python 3. <a class="reference external" href="https://python3wos.appspot.com/">Most popular packages support Python 3</a>, and many of them support both Pythons at
the same time. The early bugs were ironed out in the first few point releases,
some features that made porting easier were added (back).</p>
<p>But what if you end up needing Python 2 later? No problem: you can learn the
differences in a short time, and with the help of a few libraries (eg. <code class="docutils literal">six</code>)
you can easily write code that is compatible with Python 2 and 3 at the same
time, using the same codebase (most libraries out there do that).</p>
<p>Python 2 will go EOL and lose official support and updates in 2020.</p>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/Python2orPython3">Python 2 or Python 3 on Python Wiki</a></p>
</section>
<section id="can-i-run-multiple-pythons-on-the-same-machine">
<h2>Can I run multiple Pythons on the same machine?</h2>
<p>Yes. Note that multiple Python interpreters are completely separate: they have
their own pip and packages, and you can’t run Python 2 code in a Python 3
interpreter. You need to specify which interpreter to use when installing
packages and running some scripts (eg. <code class="docutils literal">pip2</code>, <code class="docutils literal">pip3</code> or <code class="docutils literal">python3 <span class="pre">-m</span> pip</code>).</p>
<p>It’s best to limit yourself to the latest Python 2 and 3 versions. Python is
backwards-compatible within the major release, so Python 2.7 runs code
written with older 2.x versions in mind.</p>
</section>
<section id="implementations">
<h2>Implementations</h2>
<p>A programming language is an abstract construct. To run code written in that
language, an interpreter or compiler needs to be written. In Python’s case,
there’s a plethora of implementations. Some of them are:</p>
<ul class="simple">
<li><p><strong>CPython</strong> is the reference implementation. This is the implementation
distributed on <a class="reference external" href="https://python.org/">https://python.org/</a> and as part of many operating systems.
Most Python features are first implemented in CPython, and then they are
ported to other implementations.  If you don’t know what to choose, use
CPython.</p></li>
<li><p><strong>PyPy</strong> is a fast implementation, written in a subset of Python. It’s compatible with
Python 2.7 and 3.5 (beta support). It can run all pure Python code, and many
extension libraries that use CFFI.</p></li>
<li><p><strong>IronPython</strong> is a .NET CLR implementation. It can integrate with .NET code.</p></li>
<li><p><strong>Jython</strong> is a Java JVM implementation. It can integrate with Java code, as
well as other JVM languages.</p></li>
</ul>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/PythonImplementations">Python Implementations on Python Wiki</a></p>
</section>
<section id="distributions">
<h2>Distributions</h2>
<p>There are also Python (CPython) distributions. They ship the CPython
interpreter and add some extra packages/features.  They are maintained by other
communities or corporate entities.</p>
<p>The most popular third-party distribution is <a class="reference external" href="https://www.continuum.io/downloads">Anaconda</a> from Continuum Analytics. It’s popular
for data scientists, and includes over 100 packages, with extra pre-built
binaries available from the <code class="docutils literal">conda</code> package manager.</p>
<p>I personally recommend to avoid Anaconda:</p>
<ul class="simple">
<li><p>Most packages have binary wheels for Windows, macOS and Linux (yes, Linux!)
making the installation as simple as <code class="docutils literal">pip install numpy</code>.</p></li>
<li><p>You waste disk space for packages Anaconda installs that you won’t ever need.</p></li>
<li><p>It’s provided by some random for-profit company.</p></li>
<li><p>I’ve seen bugs that were not reproducible outside of Anaconda.</p></li>
<li><p>You can still do data science using the official distribution. There’s
nothing special about Anaconda.</p></li>
</ul>
<p>Read more: <a class="reference external" href="https://wiki.python.org/moin/PythonDistributions">Python distributions on Python Wiki</a></p>
</section>
<section id="can-i-make-exe-files-from-python-programs">
<h2>Can I make .exe files from Python programs?</h2>
<p>Yes, you can. There are tools for this — <a class="reference external" href="http://www.pyinstaller.org/">PyInstaller</a> is the best one. Note that you usually need to
run it on the destination operating system. And remember that “compiling” to
exe files like that <strong>is not</strong> a security measure — your source code is still
easily recoverable. (It’s not a security measure in other languages either,
even if getting source code back might be more expensive/tricky in those.)</p>
</section>
<section id="where-to-learn-python-where-to-get-help">
<h2>Where to learn Python? Where to get help?</h2>
<p>The choice of learning material is important. If you get a bad book, it might
discourage you from learning (because it’s boring), or may teach you
bad/outdated practices.</p>
<p>If you can already program in another language, I recommend the <a class="reference external" href="https://docs.python.org/3/tutorial/">official
Python tutorial</a>. For newcomers to
programming, I recommend <a class="reference external" href="http://greenteapress.com/wp/think-python-2e/">Think Python</a> or <a class="reference external" href="https://automatetheboringstuff.com/">Automate the Boring Stuff
with Python</a>.  They teach Python 3, and
(mostly) best practices.</p>
<p>If you need help, try <code class="docutils literal">#python</code> on freenode IRC, the <a class="reference external" href="https://mail.python.org/mailman/listinfo/tutor">Tutor</a> or <a class="reference external" href="https://mail.python.org/mailman/listinfo/python-list">Python-list</a> mailing lists, or a bunch of other communities. (I’m a regular on <code class="docutils literal">#python</code>)</p>
</section>
</section>
<section id="installing-python">
<h1>Installing Python</h1>
<p>This guide will focus on installing CPython 2.7 and 3.x (latest), using the standard
distribution. This choice is satisfactory for most people. Third-party
distributions, while handy in some cases, are not needed for most. (See
<a class="reference internal" href="https://chriswarrick.com/blog/2017/07/03/setting-up-a-python-development-environment/#distributions">Distributions</a> for arguments)</p>
<p>Throughout this guide, I’ll refer to the Python interpreter executable as
<code class="docutils literal">python</code>. The exact name depends on your system and desired version. On most
OSes, <code class="docutils literal">python</code> is Python 2 and <code class="docutils literal">python3</code> is 3; <code class="docutils literal">python2</code> should also
exist.  On Arch Linux, <code class="docutils literal">python</code> is Python 3. On Windows, use the <code class="docutils literal">py</code>
launcher.</p>
<section id="windows">
<h2>Windows</h2>
<p>Download the installer(s): <a class="reference external" href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></p>
<p>Those installers come with <code class="docutils literal">pip</code>, and modern Python 3.x versions come with
the <code class="docutils literal">py</code> launcher.  You can use that launcher to pick a specific Python
version, eg.:</p>
<ul class="simple">
<li><p><code class="docutils literal">py <span class="pre">-3</span> <span class="pre">-m</span> pip install &lt;package&gt;</code></p></li>
<li><p><code class="docutils literal">py <span class="pre">-2</span> somefile.py</code></p></li>
<li><p><code class="docutils literal">py <span class="pre">-2.7</span></code></p></li>
<li><p><code class="docutils literal">py</code> (default system version)</p></li>
</ul>
<p>It’s recommended for most use, and mandatory for upgrading pip.</p>
<p>The 32-bit versions are more versatile. Most packages support both (the only
exception I’m aware of is Tensorflow, which only allows 64-bit Python 3.5 as of
now).</p>
</section>
<section id="macos">
<h2>macOS</h2>
<p>macOS ships with Python 2.7.10 (as of macOS Sierra). It’s not the latest
version; it’s good enough for most people, but I still recommend installing
your own (the system Python doesn’t include <code class="docutils literal">pip</code>, for example). You can
install the latest 2.7 version, as well as Python 3, using a package manager. I
recommend Homebrew — it’s the most popular solution, and lets you install many
other packages.</p>
<p><strong>DO NOT</strong> use the python.org installers: they do not have uninstallers, so you
will have outdated versions lying around after some time. There is no
auto-update as well.  <strong>DO NOT</strong> attempt to remove the system-installed Python,
this will only damage your system and you’ll need to reinstall.</p>
<p>If you already have a package manager installed (MacPorts, Fink), don’t install
a new one and just use the existing one.</p>
<ol class="arabic simple">
<li><p>Install <a class="reference external" href="https://brew.sh/">Homebrew</a>.</p></li>
<li><p>Run <code class="docutils literal">brew install python python3</code>.</p></li>
<li><p>You should now have <code class="docutils literal">python</code>, <code class="docutils literal">python3</code>, <code class="docutils literal">pip</code> and <code class="docutils literal">pip3</code>.</p></li>
</ol>
<p>To update Homebrew and Python, run <code class="docutils literal">brew update</code>.</p>
</section>
<section id="linux-and-other-unix-like-oses">
<h2>Linux (and other Unix-like OSes)</h2>
<p>On Linux, there usually are good enough packages in your OS repositories. You
should be able to install the appropriate package for Python (2 and/or 3).
Most (if not all) distributions require Python — <strong>do not</strong> remove the
pre-installed packages, and be careful not to overwrite them with something
newer.</p>
<p>If the version that ships with your distribution is too old, there are some
options. There might be some repositories with better versions, eg. the
<a class="reference external" href="https://launchpad.net/~fkrull/+archive/ubuntu/deadsnakes">deadsnakes PPA</a>
for Ubuntu. Then there’s the other option of compiling Python. There
are some tools to help with this, like <code class="docutils literal">pyenv</code> or <code class="docutils literal">pythonz</code> (they can also
manage multiple Python versions), or you can do it manually.
The instructions depend on your exact requirements, but here’s a summary:</p>
<ol class="arabic simple">
<li><p>Download the <a class="reference external" href="https://www.python.org/downloads/source/">source distribution from Python.org</a> and unpack it. Go into the unpacked source directory.</p></li>
<li><p>Ensure you’ve got a functional C compiler and Python’s dependencies. You can
usually use your system’s package manager to install the build dependencies
of your system Python. Some dependencies are optional (eg. <code class="docutils literal">sqlite3</code>
requires SQLite headers).</p></li>
<li><p>Run <code class="docutils literal">./configure <span class="pre">--prefix=/opt/python3.6</span></code> and then <code class="docutils literal">make</code>. (You may add other options to both. It will
take a while.)</p></li>
<li><p>Run <code class="docutils literal">make altinstall</code> as root. Avoid <code class="docutils literal">make install</code>, as it can override
<code class="docutils literal">python</code> executables.</p></li>
</ol>
<p>Remember: compiling Python should be considered a <strong>last resort</strong>, unless you
have very specific Python version requirements.</p>
</section>
</section>
<section id="installing-packages">
<h1>Installing packages</h1>
<p>To install third-party packages, you should use pip, the Python package
manager. If you’re using Windows or macOS (from Homebrew), pip is included with
your copy of Python.  If you’re on Linux and installed Python from a system
repository, install the correct system package (<code class="docutils literal"><span class="pre">python-pip</span></code>,
<code class="docutils literal"><span class="pre">python3-pip</span></code>). If you compiled your own Python, pip is also included.</p>
<p>To run pip, use <code class="docutils literal">py <span class="pre">-m</span> pip</code> (Windows), <code class="docutils literal">python <span class="pre">-m</span> pip</code> (other platforms),
or the short <code class="docutils literal">pip</code>/<code class="docutils literal">pip3</code> commands.</p>
<p><strong>NEVER use sudo pip.</strong> This can cause numerous problems:</p>
<ul class="simple">
<li><p>conflicts between packages installed by pip and your system package
manager</p></li>
<li><p>pip modifying system packages, leading to issues when updating them, or
breaking dependencies</p></li>
<li><p>no isolation between package versions, which is sometimes needed to satisfy
dependencies</p></li>
</ul>
<p>Note that a package install is specific to the Python interpreter used to run
<code class="docutils literal">pip</code>. Packages installed to a virtualenv are separate from system packages;
packages installed for “global” Python 2.7 are separate from 3.6 packages.
Virtual environments generally don’t use the system packages, unless
specifically enabled during creation.</p>
<p>Some distros have popular packages in their repositories. Sometimes they’re
good; in other cases they’re terribly outdated or they lack important
components, making package managers angry and sick of supporting a 2-year-old
version. (Especially since most bugs are closed with “we’ve fixed that long
ago”)</p>
<section id="user-installs">
<h2>User installs</h2>
<p>At a small scale, you can install packages with pip for a single user.  Use
<code class="docutils literal">pip install <span class="pre">--user</span> PACKAGE</code> to do this. If your package installs <a class="reference external" href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/">scripts</a>,
they will be installed to <code class="docutils literal"><span class="pre">~/.local/bin</span></code> on Linux, and
<code class="docutils literal">~/Library/Python/X.Y/bin</code> on macOS (X.Y is Python version), or you can use
<code class="docutils literal">python <span class="pre">-m</span></code> if the package supports it.</p>
<p>For most people and projects, virtual environments are better. There are,
however, use cases for putting some packages user-wide — if you don’t work on
projects, but instead are doing one-off research projects, those are better
suited by user-wide installs.</p>
</section>
<section id="virtual-environments">
<h2>Virtual environments</h2>
<p class="lead">I wrote a newer, more detailed post about virtualenvs: <a class="reference external" href="https://chriswarrick.com/blog/2018/09/04/python-virtual-environments/">Python Virtual
Environments in Five Minutes</a></p>
<p>Virtual environments are the best way to install and manage Python packages.
Advantages include:</p>
<ul class="simple">
<li><p>Isolation of projects and their requirements: if one app/package requires
library version X, but another requires version Y, they can live in separate
virtual environments</p></li>
<li><p>Independent from system-wide packages</p></li>
<li><p>Lightweight (an empty virtualenv is about 10 MB)</p></li>
<li><p>Simple to re-create in any place (<code class="docutils literal">pip freeze &gt; requirements.txt</code> → <code class="docutils literal">pip install <span class="pre">-r</span> requirements.txt</code>)</p></li>
</ul>
<section id="tools-and-management">
<h3>Tools and management</h3>
<p>There are two tools to facilitate creation of virtual environments: the older
<a class="reference external" href="https://virtualenv.pypa.io/en/stable/">virtualenv</a> project, and the newer
<code class="docutils literal">venv</code> module. The <code class="docutils literal">venv</code> module is shipped with Python 3.x; some
distributions may put it in a separate package or remove it altogether. Use
whichever works for you.  Virtualenv is compatible with more Python versions
and cannot be broken by incompetent OS package maintainers (<code class="docutils literal">venv</code> requires
an extra package on Debian).</p>
<p>There are multiple schools of thought regarding virtualenv placement and
content. Myself, I use <a class="reference external" href="https://virtualenvwrapper.readthedocs.io/en/latest/">virtualenvwrapper</a> to manage virtualenvs
and put them in <code class="docutils literal">~/virtualenvs</code>. Other people put virtualenvs inside their
git repositories (but they <em>must</em> be in <code class="docutils literal">.gitignore</code>) Virtualenvs should only contain packages
installed with <code class="docutils literal">pip</code> so they can be recreated quickly.</p>
<p>I also use the <code class="docutils literal">virtualenvwrapper</code> plugin for Oh My Zsh, which also
activates virtualenvs with the same name as a git repo, or the environment
named by a <code class="docutils literal">.venv</code> file.</p>
</section>
<section id="installation-and-usage">
<h3>Installation and usage</h3>
<p>To install virtualenv user-wide, use <code class="docutils literal">pip install <span class="pre">--user</span> virtualenv</code>. You can
then use it with <code class="docutils literal">python <span class="pre">-m</span> virtualenv DIRECTORY</code>. You may pass extra
options, eg. interpreter to use (<code class="docutils literal"><span class="pre">-p</span> python3</code>). Sometimes you need to install
virtualenv for every Python version; usually, one copy is enough.</p>
<p>How to use them? This is a subject of heated debate in the Python community.</p>
<ul class="simple">
<li><p>Some people believe that activating (<code class="docutils literal">source bin/activate</code> on *nix;
<code class="docutils literal">Scripts\activate</code> on Windows) is the right thing to do and simplifies work.</p></li>
<li><p>Others think that you should use <code class="docutils literal">bin/python</code> (or other scripts in that
directory) directly, as activation only changes <code class="docutils literal">$PATH</code> and some helper
variables — those variables are not mandatory for operation, running
the correct <code class="docutils literal">python</code> is.</p></li>
<li><p>Others still think <a class="reference external" href="https://gist.github.com/datagrok/2199506">virtualenvs should be used in subshells</a>.</p></li>
</ul>
<p>In my opinion, if activating virtualenvs works in your environment, you should
do it — it’s the most convenient option. There are, however, cases when
activation fails, or is otherwise impossible — calling <code class="docutils literal">bin/python</code> directly
is your best bet in that case. If you are working inside shell scripts, do not
activate virtualenvs.  I’m not a fan of the subshell option, because it
complicates stuff if you work on multiple projects, and requires tracking usage
manually.</p>
</section>
<section id="upgrading-and-moving">
<h3>Upgrading and moving</h3>
<p>Upgrading the system Python may make your virtualenvs unusable.
For patch version upgrades, you can just update symlinks (see <a class="reference external" href="https://github.com/Kwpolska/scripts/blob/master/fix-venvs.sh">fix-venvs.sh</a>).
However, if the minor version changes, it’s best to re-create the virtualenv
(you need to create <code class="docutils literal">requirements.txt</code> ahead of time).</p>
<p>You cannot move a virtualenv between directories/machines or rename
virtualenvs. You need to use <code class="docutils literal">pip freeze &gt; requirements.txt</code>, create a new
virtualenv, and run <code class="docutils literal">pip install <span class="pre">-r</span> requirements.txt</code> (you can then delete
the old environment with a simple <code class="docutils literal">rm <span class="pre">-rf</span></code>)</p>
</section>
</section>
<section id="packages-with-c-extensions-binary">
<h2>Packages with C extensions (binary)</h2>
<p>The situation improved drastically in the past year or so. Nowadays, almost
all packages have a pre-compiled package available in PyPI. Those packages work
for Windows, macOS, and Linux. There are packages for some of the most
common <em>offenders</em>, including Pillow, lxml, PyQt5, numpy… However, there might
still be packages without wheels on PyPI.</p>
<p>If there is no wheel for a package and you are on Windows, check out <a class="reference external" href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">Christoph
Gohlke’s unofficial binaries</a>.
If you can’t find any wheels online, you would have to resort to compiling it
manually — this requires installing Visual Studio (Visual C++) in a version
that matches your Python, and it’s kind of a pain to do.</p>
<p>If you are not on Windows, you must install a C compiler and toolchain.
If you get a warning about missing <code class="docutils literal">Python.h</code>, install the appropriate development
package — for example, <code class="docutils literal"><span class="pre">python-dev</span></code> or <code class="docutils literal"><span class="pre">python3-dev</span></code>) on Debian/Ubuntu,
<code class="docutils literal"><span class="pre">python-devel</span></code> or <code class="docutils literal"><span class="pre">python3-devel</span></code> on RHEL/Fedora. The package you’re trying
to install might have other dependencies that you need to install (the
<code class="docutils literal"><span class="pre">-dev(el)</span></code> part is important, too)</p>
</section>
<section id="other-stuff">
<h2>Other stuff</h2>
<p>If you’re working on a project, use <code class="docutils literal">pip install <span class="pre">-e</span> .</code> inside the project
directory to install the package in your environment in development (editable)
mode. This loads code directly from your repository — you don’t need to
re-install on every change; you might need to re-install when your version
number changes.</p>
</section>
</section>
<section id="editors-and-ides">
<h1>Editors and IDEs</h1>
<p>Another important thing a developer should take care of is the choice of an
editor. This is an important decision, and is the reason for many holy wars in
the programmer community.</p>
<p>A good editor should have syntax highlighting for all languages you need to
work with. It should also have features like visual block/multiple selections,
sophisticated find-and-replace, file finding, code completion, and many more minor
but helpful features.</p>
<p>Then there’s the difference between IDEs and text editors. Text editors are
simpler, whereas IDEs try to include many extra things not necessarily related
to writing code. IDEs often use more resources, but you won’t notice it with a
modern computer (especially with a SSD).</p>
<p>The best IDE out there is <a class="reference external" href="https://www.jetbrains.com/pycharm/">PyCharm</a> from
JetBrains. It has both a free Community and paid Professional edition. The
JetBrains folks are experts at IDEs — they have fully-fledged tools for many
languages. Their Python solution offers a plethora of options that aid
programmers in their work.  Also, if you work with Java, or otherwise more than
one IDEA-supported language, then install IntelliJ IDEA and the Python plugin
(which has the same features as PyCharm).  Students can get <a class="reference external" href="https://www.jetbrains.com/student/">free
Professional/Ultimate licenses for JetBrains products</a>.</p>
<p>I also spend a lot of time in <a class="reference external" href="http://www.vim.org/">Vim</a> (<a class="reference external" href="https://neovim.io/">neovim</a>/<a class="reference external" href="http://vimr.org/">VimR</a> to be precise). Vim is the
most powerful text editor out there, and with the right set of plugins it can
beat IDEs at speed and productivity. Vim has a steep learning curve, but it’s
worth it — you can do large changes with just a few keystrokes. Vim is
considered so good that many IDEs (Visual Studio, IntelliJ IDEA/PyCharm) have
Vim emulation plugins.</p>
<p>Another option is <a class="reference external" href="https://code.visualstudio.com/">Visual Studio Code</a> — it’s
a text editor, but can offer many IDE-like features with the right set of
plugins. It’s Electron-based architecture, or effectively being based on top of
Google’s Chromium, is unfortunate and can lead to terrible performance on
lower-end machines, and on higher-end ones in some cases. (In my experience,
it’s better than Atom.) You can also try <a class="reference external" href="https://www.sublimetext.com/">Sublime Text</a> ($80).</p>
<p>But really, almost any editor will do. But please <strong>avoid</strong> IDLE, the editor
included with Python. It lacks some of the most basic things — it doesn’t even
have an option to show line numbers. Not to mention its ugliness. Also, don’t
use Notepad and TextEdit. Those are too simple, and Notepad has encoding
issues.</p>
</section>
<section id="update-history">
<h1>Update history</h1>
<dl class="simple">
<dt>2018-09-21</dt>
<dd><p>Link to python-virtual-environments post.</p>
</dd>
<dt>2017-07-19</dt>
<dd><p>Better description of problems caused by using sudo pip.</p>
</dd>
<dt>2017-07-10</dt>
<dd><p>Added notes about not removing built-in Pythons.</p>
</dd>
<dt>2017-07-07</dt>
<dd><p>Spelling fixes and updates to the virtualenv usage section.</p>
</dd>
</dl>
</section>
]]></content:encoded><category>Python</category><category>best practices</category><category>devel</category><category>guide</category><category>guide</category><category>Python</category></item><item><title>Unix locales vs Unicode (‘ascii’ codec can’t encode character…)</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/</link><pubDate>Sun, 18 Jun 2017 18:40:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/</guid><description>
You might get unusual errors about Unicode and inability to convert
to ASCII. Programs might just crash at random. Those are often simple to fix —
all you need is correct locale configuration.
</description><content:encoded><![CDATA[
<p>You might get unusual errors about Unicode and inability to convert
to ASCII. Programs might just crash at random. Those are often simple to fix —
all you need is correct locale configuration.</p>



<p class="lead">Has this ever happened to you?</p>
<div class="code"><pre class="code pytb"><a id="rest_code_526327b4277f4a8497b67746e0a751b2-1" name="rest_code_526327b4277f4a8497b67746e0a751b2-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-1"></a><span class="gt">Traceback (most recent call last):</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-2" name="rest_code_526327b4277f4a8497b67746e0a751b2-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-2"></a>  File <span class="nb">&quot;aogonek.py&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-3" name="rest_code_526327b4277f4a8497b67746e0a751b2-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-3"></a><span class="w">    </span><span class="nb">print</span><span class="p">(</span><span class="sa">u</span><span class="s1">&#39;</span><span class="se">\u0105</span><span class="s1">&#39;</span><span class="p">)</span>
<a id="rest_code_526327b4277f4a8497b67746e0a751b2-4" name="rest_code_526327b4277f4a8497b67746e0a751b2-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_526327b4277f4a8497b67746e0a751b2-4"></a><span class="gr">UnicodeEncodeError</span>: <span class="n">&#39;ascii&#39; codec can&#39;t encode character &#39;\u0105&#39; in position 0: ordinal not in range(128)</span>
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1" name="rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_ca5594fd2ef54ad38a77f0c5883c3188-1"></a>Nikola: Could not guess locale for language en, using locale C
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_f5ea18fead964936bccf8b8666032087-1" name="rest_code_f5ea18fead964936bccf8b8666032087-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-1"></a>Input: ą
<a id="rest_code_f5ea18fead964936bccf8b8666032087-2" name="rest_code_f5ea18fead964936bccf8b8666032087-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-2"></a>Desired ascii(): &#39;\u0105&#39;
<a id="rest_code_f5ea18fead964936bccf8b8666032087-3" name="rest_code_f5ea18fead964936bccf8b8666032087-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_f5ea18fead964936bccf8b8666032087-3"></a>Real ascii(): &#39;\udcc4\udc85&#39;
</pre></div>
<div class="code"><pre class="code text"><a id="rest_code_73da6abf15b34ece9c498c4adc163917-1" name="rest_code_73da6abf15b34ece9c498c4adc163917-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-1"></a>perl: warning: Setting locale failed.
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-2" name="rest_code_73da6abf15b34ece9c498c4adc163917-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-2"></a>perl: warning: Please check that your locale settings:
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-3" name="rest_code_73da6abf15b34ece9c498c4adc163917-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-3"></a>    [...]
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-4" name="rest_code_73da6abf15b34ece9c498c4adc163917-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-4"></a>    are supported and installed on your system.
<a id="rest_code_73da6abf15b34ece9c498c4adc163917-5" name="rest_code_73da6abf15b34ece9c498c4adc163917-5" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_73da6abf15b34ece9c498c4adc163917-5"></a>perl: warning: Falling back to the standard locale (&quot;C&quot;).
</pre></div>
<p class="lead">All those errors have the same root cause: incorrect locale configuration.
To fix them all, you need to generate the missing locales and set them.</p>
<section id="check-currently-used-locale">
<h1>Check currently used locale</h1>
<p>The <code class="docutils literal">locale</code> command (without arguments) should tell you which locales you’re
currently using.  (The list might be shorter on your end)</p>
<div class="code"><pre class="code sh"><a id="rest_code_45351c7f546a450b945adfb5fea5446d-1" name="rest_code_45351c7f546a450b945adfb5fea5446d-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-1"></a>$<span class="w"> </span>locale
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-2" name="rest_code_45351c7f546a450b945adfb5fea5446d-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-2"></a><span class="nv">LANG</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-3" name="rest_code_45351c7f546a450b945adfb5fea5446d-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-3"></a><span class="nv">LC_CTYPE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-4" name="rest_code_45351c7f546a450b945adfb5fea5446d-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-4"></a><span class="nv">LC_NUMERIC</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-5" name="rest_code_45351c7f546a450b945adfb5fea5446d-5" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-5"></a><span class="nv">LC_TIME</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-6" name="rest_code_45351c7f546a450b945adfb5fea5446d-6" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-6"></a><span class="nv">LC_COLLATE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-7" name="rest_code_45351c7f546a450b945adfb5fea5446d-7" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-7"></a><span class="nv">LC_MONETARY</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-8" name="rest_code_45351c7f546a450b945adfb5fea5446d-8" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-8"></a><span class="nv">LC_MESSAGES</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-9" name="rest_code_45351c7f546a450b945adfb5fea5446d-9" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-9"></a><span class="nv">LC_PAPER</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-10" name="rest_code_45351c7f546a450b945adfb5fea5446d-10" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-10"></a><span class="nv">LC_NAME</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-11" name="rest_code_45351c7f546a450b945adfb5fea5446d-11" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-11"></a><span class="nv">LC_ADDRESS</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-12" name="rest_code_45351c7f546a450b945adfb5fea5446d-12" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-12"></a><span class="nv">LC_TELEPHONE</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-13" name="rest_code_45351c7f546a450b945adfb5fea5446d-13" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-13"></a><span class="nv">LC_MEASUREMENT</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-14" name="rest_code_45351c7f546a450b945adfb5fea5446d-14" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-14"></a><span class="nv">LC_IDENTIFICATION</span><span class="o">=</span><span class="s2">&quot;en_US.UTF-8&quot;</span>
<a id="rest_code_45351c7f546a450b945adfb5fea5446d-15" name="rest_code_45351c7f546a450b945adfb5fea5446d-15" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_45351c7f546a450b945adfb5fea5446d-15"></a><span class="nv">LC_ALL</span><span class="o">=</span>
</pre></div>
<p>If any of those is set to <code class="docutils literal">C</code> or <code class="docutils literal">POSIX</code>, has a different encoding than
<code class="docutils literal"><span class="pre">UTF-8</span></code> (sometimes spelled <code class="docutils literal">utf8</code>) is empty (with the exception of
<code class="docutils literal">LC_ALL</code>), or if you see any errors, you need to reconfigure your locale.</p>
</section>
<section id="check-locale-availability-and-install-missing-locales">
<h1>Check locale availability and install missing locales</h1>
<p>The first thing you need to do is check locale availability. To do this, run
<code class="docutils literal">locale <span class="pre">-a</span></code>. This will produce a list of all installed locales.  You can use
<code class="docutils literal">grep</code> to get a more reasonable list.</p>
<div class="code"><pre class="code text"><a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-1" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-1"></a>$ locale -a | grep -i utf
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-2" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-2" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-2"></a>&lt;lists all UTF-8 locales&gt;
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-3" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-3" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-3"></a>$ locale -a | grep -i utf | grep -i en_US
<a id="rest_code_704767d3e7724ac7b8d1176bc3b74b03-4" name="rest_code_704767d3e7724ac7b8d1176bc3b74b03-4" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_704767d3e7724ac7b8d1176bc3b74b03-4"></a>en_US.UTF-8
</pre></div>
<p>The best locale to use is the one for your language, with the UTF-8 encoding.
The locale will be used by some console apps for output. I’m going to use
<code class="docutils literal"><span class="pre">en_US.UTF-8</span></code> in this guide.</p>
<p>If you can’t see any UTF-8 locales, or no appropriate locale setting for your
language of choice, you might need to generate those. The required actions
depend on your distro/OS.</p>
<ul class="simple">
<li><p>Debian, Ubuntu, and derivatives: install <code class="docutils literal"><span class="pre">language-pack-en-base</span></code>, run <code class="docutils literal">sudo <span class="pre">dpkg-reconfigure</span> locales</code></p></li>
<li><p>RHEL, CentOS, Fedora: install <code class="docutils literal"><span class="pre">glibc-langpack-en</span></code></p></li>
<li><p>Arch Linux: uncomment relevant entries in <code class="docutils literal">/etc/locale.gen</code> and run <code class="docutils literal">sudo <span class="pre">locale-gen</span></code> <a class="reference external" href="https://wiki.archlinux.org/index.php/Locale">(wiki)</a></p></li>
<li><p>For other OSes, refer to the documentation.</p></li>
</ul>
<p>You need a UTF-8 locale to ensure compatibility with software. Avoid the <code class="docutils literal">C</code>
and <code class="docutils literal">POSIX</code> locales (it’s ASCII) and locales with other encodings (those
aren’t used by ~anyone these days)</p>
</section>
<section id="configure-system-wide">
<h1>Configure system-wide</h1>
<p>On some systems, you may be able to configure locale system-wide.  Check your
system documentation for details. If your system has systemd, run</p>
<div class="code"><pre class="code text"><a id="rest_code_8e2d3316c858497393bb3774f7ebe9d1-1" name="rest_code_8e2d3316c858497393bb3774f7ebe9d1-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_8e2d3316c858497393bb3774f7ebe9d1-1"></a>sudo localectl set-locale LANG=en_US.UTF-8
</pre></div>
</section>
<section id="configure-for-a-single-user">
<h1>Configure for a single user</h1>
<p>If your environment does not allow system-wide locale configuration (macOS,
shared server with generated but unconfigured locales), or if you want to
ensure it’s always configured independently of system settings.</p>
<p>To do this, you need to edit the configuration file for your shell. If you’re
using bash, it’s <code class="docutils literal">.bashrc</code> (or <code class="docutils literal">.bash_profile</code> on macOS). For zsh users,
<code class="docutils literal">.zshrc</code>.  Add this line (or equivalent in your shell):</p>
<div class="code"><pre class="code sh"><a id="rest_code_28348ddaf62c4af99190326623915503-1" name="rest_code_28348ddaf62c4af99190326623915503-1" href="https://chriswarrick.com/blog/2017/06/18/unix-locales-vs-unicode/#rest_code_28348ddaf62c4af99190326623915503-1"></a><span class="nb">export</span><span class="w"> </span><span class="nv">LANG</span><span class="o">=</span>en_US.UTF-8<span class="w"> </span><span class="nv">LC_ALL</span><span class="o">=</span>en_US.UTF-8
</pre></div>
<p>That should be enough. Note that those settings don’t apply to programs
not launched through a shell.</p>
<hr class="docutils">
<p><strong>Python/Windows corner:</strong> Python 3.7 will fix this on Unix by assuming UTF-8
if it encounters the C locale.  On Windows, Python 3.6 is using UTF-8
interactively, but not when using shell redirections to files or pipes.</p>
<p><em>This post was brought to you by ą — U+0105 LATIN SMALL LETTER A WITH OGONEK.</em></p>
</section>
]]></content:encoded><category>Programming</category><category>guide</category><category>locale</category><category>Python</category><category>Unicode</category><category>Unix</category></item><item><title>Deploying Python Web Applications with nginx and uWSGI Emperor</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/</link><pubDate>Wed, 10 Feb 2016 14:00:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/</guid><description>
You’ve just written a great Python web application. Now, you want to share it with the world. In order to do that, you need a server, and some software to do that for you.
The following is a comprehensive guide on how to accomplish that, on multiple Linux-based operating systems, using nginx and uWSGI Emperor. It doesn’t force you to use any specific web framework — Flask, Django, Pyramid, Bottle will all work. Written for Ubuntu, Debian, Fedora, CentOS 7, Alma Linux, Rocky Linux and Arch Linux (should be helpful for other systems, too). Now with an Ansible Playbook.
Revision 8 (2022-02-20): works with Fedora 35, AlmaLinux 8, RockyLinux 8
While this guide is still valid, in 2026 I switched to Docker and Gunicorn for my Python web app deployments. Check out Deploying Python Web Applications with Docker for more details.
</description><content:encoded><![CDATA[
<p>You’ve just written a great Python web application. Now, you want to share it with the world. In order to do that, you need a server, and some software to do that for you.</p>
<p>The following is a comprehensive guide on how to accomplish that, on multiple Linux-based operating systems, using nginx and uWSGI Emperor. It doesn’t force you to use any specific web framework — Flask, Django, Pyramid, Bottle will all work. Written for Ubuntu, Debian, Fedora, CentOS 7, Alma Linux, Rocky Linux and Arch Linux (should be helpful for other systems, too). Now with an Ansible Playbook.</p>
<p><em>Revision 8 (2022-02-20): works with Fedora 35, AlmaLinux 8, RockyLinux 8</em></p>
<p><em>While this guide is still valid, in 2026 I switched to Docker and Gunicorn for my Python web app deployments. Check out <a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/">Deploying Python Web Applications with Docker</a> for more details.</em></p>



<p>CI status for the associated Ansible Playbook: <img alt="ci-status" src="https://github.com/Kwpolska/ansible-nginx-uwsgi/workflows/CI in Docker for ansible-nginx-uwsgi %28pyweb%29/badge.svg"></p>
<p>For easy linking, I set up some aliases: <a class="reference external" href="https://go.chriswarrick.com/pyweb">https://go.chriswarrick.com/pyweb</a> and <a class="reference external" href="https://go.chriswarrick.com/uwsgi-tut">https://go.chriswarrick.com/uwsgi-tut</a>.</p>
<section id="prerequisites">
<h1>Prerequisites</h1>
<p>In order to deploy your web application, you need a server that gives you root and ssh access — in other words, a VPS (or a dedicated server, or a datacenter lease…). If you’re looking for a great VPS service for a low price, I recommend <a class="reference external" href="https://hetzner.cloud/?ref=Qy1lehF8PwzP">Hetzner Cloud</a> (reflink <a class="brackets" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#footnote-1" id="footnote-reference-1" role="doc-noteref"><span class="fn-bracket">[</span>1<span class="fn-bracket">]</span></a>), which offers a pretty good entry-level VPS for €3.49 + VAT / month (with higher plans available for equally good prices). If you want to play along at home, without buying a VPS, you can create a virtual machine on your own, or use Vagrant with a Vagrant box for Fedora 35 (<code class="docutils literal"><span class="pre">fedora/35-cloud-base</span></code>).</p>
<p>Your server should also run a modern Linux-based operating system. This guide was written and tested on:</p>
<ul class="simple">
<li><p>Ubuntu 18.04 LTS, 20.04 LTS or newer</p></li>
<li><p>Debian 10 (buster), 11 (bullseye) or newer</p></li>
<li><p>Fedora 33 or newer (with SELinux enabled and disabled)</p></li>
<li><p>CentOS 7 (with SELinux enabled and disabled) — manual guide should also work on RHEL 7.</p></li>
<li><p>AlmaLinux 8 (with SELinux enabled and disabled) — manual guide should also work on RHEL 8. Referred to as “EL8” collectively with Rocky Linux.</p></li>
<li><p>Rocky Linux 8 (with SELinux enabled and disabled) — manual guide should also work on RHEL 8. Referred to as “EL8” collectively with AlmaLinux.</p></li>
<li><p>Arch Linux</p></li>
</ul>
<p>Debian 8 (jessie) 9 (stretch), Ubuntu 16.04 LTS, and Fedora 24 through 32 are not officially supported, even though they still probably work.</p>
<p>What if you’re using <strong>Docker</strong>? This guide does not apply, you may want to read <a class="reference external" href="https://chriswarrick.com/blog/2026/02/06/deploying-python-web-applications-with-docker/">Deploying Python Web Applications with Docker</a> instead.</p>
<p>Users of other Linux distributions (and perhaps other Unix flavors) can also follow this tutorial. This guide assumes <code class="docutils literal">systemd</code> as your init system; if you are not using systemd, you will have to get your own daemon files somewhere else. In places where the instructions are split three-way, try coming up with your own, reading documentation and config files; the Arch Linux instructions are probably the closest to upstream (but not always).  Unfortunately, all Linux distributions have their own ideas when it comes to running and managing nginx and uWSGI.</p>
<p>nginx and uWSGI are considered best practices by most people. nginx is a fast, modern web server, with uWSGI support built in (without resorting to reverse proxying).  uWSGI is similarly aimed at speed.  The Emperor mode of uWSGI is recommended for init system integration by the uWSGI team, and it’s especially useful for multi-app deployments. (This guide is opinionated.)</p>
</section>
<section id="automate-everything-ansible-playbook">
<h1>Automate everything: Ansible Playbook</h1>
<p class="lead">A <a class="reference external" href="https://github.com/Kwpolska/ansible-nginx-uwsgi">Playbook</a> that automates everything in this tutorial is available. <img alt="ci-status" src="https://github.com/Kwpolska/ansible-nginx-uwsgi/workflows/CI in Docker for ansible-nginx-uwsgi %28pyweb%29/badge.svg"></p>
<section id="how-to-use">
<h2>How to use</h2>
<ol class="arabic simple">
<li><p>Install <a class="reference external" href="https://docs.ansible.com/ansible/intro_installation.html">Ansible</a> on your control computer (not necessarily the destination server).</p></li>
<li><p>Clone the <a class="reference external" href="https://github.com/Kwpolska/ansible-nginx-uwsgi">Playbook</a> from GitHub.</p></li>
<li><p>Read <code class="docutils literal">README.md</code>. You should also understand how Ansible works.</p></li>
<li><p>Configure (change three files: <code class="docutils literal">hosts</code>, <code class="docutils literal">group_vars/all</code>, and <code class="docutils literal">group_vars/os_&lt;destination OS&gt;</code></p></li>
<li><p>Make sure all the dependencies are installed on your destination server</p></li>
<li><p>Run <code class="docutils literal"><span class="pre">ansible-playbook</span> <span class="pre">-v</span> <span class="pre">nginx-uwsgi.yml</span> <span class="pre">-i</span> hosts</code> and watch magic happen.</p></li>
<li><p>Skip over to <a class="reference internal" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#end-result">End result</a> and test your site.</p></li>
</ol>
</section>
</section>
<section id="the-manual-guide">
<h1>The manual guide</h1>
<p>Even though I personally recommend the Playbook as a much less error-prone way to set up your app, it might not be compatible with everyone’s system, or otherwise be the wrong solution. The original manual configuration guide is still maintained.</p>
<p>Even if you are using the Playbook, you should still read this to find out what happens under the hood, and to find out about other caveats/required configuration changes.</p>
<aside class="admonition note">
<p class="admonition-title">Note</p>
<p>All the commands in this tutorial are meant to be run <strong>as root</strong> — run <code class="docutils literal">su</code> or <code class="docutils literal">sudo su</code> first to get an administrative shell. This tutorial assumes familiarity with basic Linux administration and command-line usage.</p>
</aside>
<section id="getting-started">
<h2>Getting started</h2>
<p>Start by installing Python 3 (with venv), nginx and uWSGI. I recommend using your operating system’s packages. Make sure you are downloading the latest versions available for your OS (update the package cache first). For uWSGI, we need the <code class="docutils literal">logfile</code> and <code class="docutils literal">python3</code> plugins. (Arch Linux names the <code class="docutils literal">python3</code> plugin <code class="docutils literal">python</code>; the <code class="docutils literal">logfile</code> plugin may be built-in — check with your system repositories!). I’ll also install Git to clone the tutorial app, but it’s optional if your workflow does not involve Git.</p>
<p><strong>Ubuntu, Debian:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_dc96945fddd249e3b571e60cd43c2440-1" name="rest_code_dc96945fddd249e3b571e60cd43c2440-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_dc96945fddd249e3b571e60cd43c2440-1"></a>apt<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>python3-venv<span class="w"> </span>uwsgi<span class="w"> </span>uwsgi-emperor<span class="w"> </span>uwsgi-plugin-python3<span class="w"> </span>nginx-full<span class="w"> </span>git
</pre></div>
<p><strong>Fedora:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_684497d7a94a42268b1cbf5bb326c87c-1" name="rest_code_684497d7a94a42268b1cbf5bb326c87c-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_684497d7a94a42268b1cbf5bb326c87c-1"></a>dnf<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>uwsgi<span class="w"> </span>uwsgi-plugin-python3<span class="w"> </span>uwsgi-logger-file<span class="w"> </span>nginx<span class="w"> </span>git
</pre></div>
<p><strong>CentOS 7:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_20fd4da87897484280bca847882fd041-1" name="rest_code_20fd4da87897484280bca847882fd041-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_20fd4da87897484280bca847882fd041-1"></a>yum<span class="w"> </span>install<span class="w"> </span>epel-release
<a id="rest_code_20fd4da87897484280bca847882fd041-2" name="rest_code_20fd4da87897484280bca847882fd041-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_20fd4da87897484280bca847882fd041-2"></a>yum<span class="w"> </span>install<span class="w"> </span>python36<span class="w"> </span>uwsgi<span class="w"> </span>uwsgi-plugin-python36<span class="w"> </span>uwsgi-logger-file<span class="w"> </span>nginx<span class="w"> </span>git<span class="w"> </span>wget
</pre></div>
<p><strong>EL8 (AlmaLinux 8, Rocky Linux 8):</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_146ba186238e4081a6ecc5df6adebac5-1" name="rest_code_146ba186238e4081a6ecc5df6adebac5-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_146ba186238e4081a6ecc5df6adebac5-1"></a>dnf<span class="w"> </span>install<span class="w"> </span>epel-release
<a id="rest_code_146ba186238e4081a6ecc5df6adebac5-2" name="rest_code_146ba186238e4081a6ecc5df6adebac5-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_146ba186238e4081a6ecc5df6adebac5-2"></a>dnf<span class="w"> </span>install<span class="w"> </span>python36<span class="w"> </span>uwsgi<span class="w"> </span>uwsgi-plugin-python3<span class="w"> </span>uwsgi-logger-file<span class="w"> </span>nginx<span class="w"> </span>git<span class="w"> </span>wget
</pre></div>
<p><strong>Arch Linux:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_d74d4895ec02488689a7fe3ff44dbb98-1" name="rest_code_d74d4895ec02488689a7fe3ff44dbb98-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_d74d4895ec02488689a7fe3ff44dbb98-1"></a>pacman<span class="w"> </span>-S<span class="w"> </span>python<span class="w"> </span>uwsgi<span class="w"> </span>uwsgi-plugin-python<span class="w"> </span>nginx<span class="w"> </span>git
</pre></div>
</section>
<section id="preparing-your-application">
<h2>Preparing your application</h2>
<p>This tutorial will work for any web framework. I will use <a class="reference external" href="https://github.com/Kwpolska/flask-demo-app">a really basic Flask app</a> that has just one route (<code class="docutils literal">/</code>), a static <code class="docutils literal">hello.png</code> file and a <code class="docutils literal">favicon.ico</code> for demonstration purposes. The app is pretty basic, but all the usual advanced features (templates, user logins, database access, etc.) would work without any other web server-related config. Note that the app does not use <code class="docutils literal">app.run()</code>. While you could add it, it would be used for local development and debugging only, and would have to be prepended by <code class="docutils literal">if __name__ == '__main__':</code> (if it wasn’t, that server would run instead of uWSGI, which is bad)</p>
<p>The app will be installed somewhere under the <code class="docutils literal">/srv</code> directory, which is a great place to store things like this. I’ll choose <code class="docutils literal">/srv/myapp</code> for this tutorial, but for real deployments, you should use something more distinguishable — the domain name is a great idea.</p>
<p>If you don’t use Flask, this tutorial also has instructions for other web frameworks (Django, Pyramid, Bottle) in the configuration files; it should be adjustable to any other WSGI-compliant framework/script nevertheless.</p>
<aside class="sidebar">
<p class="sidebar-title">Paths and locations</p>
<p>This guide used to recommend creating the venv in <code class="docutils literal">/srv/myapp</code>. This was changed to improve in-place Python upgrades. Virtual environments should be ephemeral, so that <code class="docutils literal">rm <span class="pre">-rf</span> $VIRTUAL_ENV</code> is recoverable in less than 10 minutes and 2 commands. The old structure made the venv hard to delete without deleting <code class="docutils literal">appdata</code>. The current structure has <code class="docutils literal">/srv/myapp/venv</code> and <code class="docutils literal">/srv/myapp/appdata</code> separate. An alternative structure would put the app in <code class="docutils literal">/srv/myapp</code>, but that requires including <code class="docutils literal">venv</code>, sockets and other deployment-specific files in <code class="docutils literal">.gitignore</code> (or having dirty working directories).</p>
</aside>
<p>We’ll start by creating a virtual environment, which is very easy with Python 3:</p>
<div class="code"><pre class="code sh"><a id="rest_code_1d7f4017262f40ca9004a3fe734e356d-1" name="rest_code_1d7f4017262f40ca9004a3fe734e356d-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_1d7f4017262f40ca9004a3fe734e356d-1"></a>mkdir<span class="w"> </span>/srv/myapp
<a id="rest_code_1d7f4017262f40ca9004a3fe734e356d-2" name="rest_code_1d7f4017262f40ca9004a3fe734e356d-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_1d7f4017262f40ca9004a3fe734e356d-2"></a>python3<span class="w"> </span>-m<span class="w"> </span>venv<span class="w"> </span>--prompt<span class="w"> </span>myapp<span class="w"> </span>/srv/myapp/venv
</pre></div>
<p>(The <code class="docutils literal"><span class="pre">--prompt</span></code> option is not supported on some old versions of Python, but you can just skip it if that’s the case, it’s just to make the prompt after <code class="docutils literal">source bin/activate</code> more informative.)</p>
<p>Now, we need to put our app there and install requirements. An example for the tutorial demo app:</p>
<div class="code"><pre class="code sh"><a id="rest_code_f4e2ef824ed045478948be971f94b599-1" name="rest_code_f4e2ef824ed045478948be971f94b599-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_f4e2ef824ed045478948be971f94b599-1"></a><span class="nb">cd</span><span class="w"> </span>/srv/myapp
<a id="rest_code_f4e2ef824ed045478948be971f94b599-2" name="rest_code_f4e2ef824ed045478948be971f94b599-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_f4e2ef824ed045478948be971f94b599-2"></a>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/Kwpolska/flask-demo-app<span class="w"> </span>appdata
<a id="rest_code_f4e2ef824ed045478948be971f94b599-3" name="rest_code_f4e2ef824ed045478948be971f94b599-3" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_f4e2ef824ed045478948be971f94b599-3"></a>venv/bin/pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>appdata/requirements.txt
</pre></div>
<p>I’m storing my application data in the <code class="docutils literal">appdata</code> subdirectory so that it doesn’t clutter the virtual environment (or vice versa).  You may also install the <code class="docutils literal">uwsgi</code> package in the virtual environment, but it’s optional.</p>
<p>What this directory should be depends on your web framework.  For example, for a Django app, you should have an <code class="docutils literal">appdata/manage.py</code> file (in other words, <code class="docutils literal">appdata</code> is where your app structure starts).  I also assumed that the <code class="docutils literal">appdata</code> folder should have a <code class="docutils literal">static</code> subdirectory with all static files, including <code class="docutils literal">favicon.ico</code> if you have one (we will add support for both in nginx).</p>
<p>At this point, you should chown this directory to the user and group your server is going to run as.  This is especially important if uwsgi and nginx run as different users (as they do on Fedora). Run one of the following commands:</p>
<p><strong>Ubuntu, Debian:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_68d4b156f0bb491d92e8f5a85b8a211f-1" name="rest_code_68d4b156f0bb491d92e8f5a85b8a211f-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_68d4b156f0bb491d92e8f5a85b8a211f-1"></a>chown<span class="w"> </span>-R<span class="w"> </span>www-data:www-data<span class="w"> </span>/srv/myapp
</pre></div>
<p><strong>Fedora, CentOS, EL8 (AlmaLinux, Rocky Linux):</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_e0bdfa35e6be477ea4b37661d6b9562f-1" name="rest_code_e0bdfa35e6be477ea4b37661d6b9562f-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_e0bdfa35e6be477ea4b37661d6b9562f-1"></a>chown<span class="w"> </span>-R<span class="w"> </span>uwsgi:nginx<span class="w"> </span>/srv/myapp
</pre></div>
<p><strong>Arch Linux:</strong></p>
<div class="code"><pre class="code sh"><a id="rest_code_c7fe9bf6369947f18fd80bd5a01204f2-1" name="rest_code_c7fe9bf6369947f18fd80bd5a01204f2-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_c7fe9bf6369947f18fd80bd5a01204f2-1"></a>chown<span class="w"> </span>-R<span class="w"> </span>http:http<span class="w"> </span>/srv/myapp
</pre></div>
</section>
<section id="configuring-uwsgi-and-nginx">
<h2>Configuring uWSGI and nginx</h2>
<aside class="admonition note">
<p class="admonition-title">Note</p>
<p>Parts of the configuration depend on your operating system. I tried to provide advice for Ubuntu, Debian, Fedora, CentOS, EL8, and Arch Linux. If you experience any issues, in particular with plugins, please consult the documentation.</p>
</aside>
<p>We need to write a configuration file for uWSGI and nginx.</p>
<section id="uwsgi-configuration">
<h3>uWSGI configuration</h3>
<p>Start with this, but read the notes below and change the values accordingly:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-1" name="rest_code_3dc7358e7e1040868406e431b3fa0248-1"></a><span class="k">[uwsgi]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-2" name="rest_code_3dc7358e7e1040868406e431b3fa0248-2"></a><span class="na">socket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">/srv/myapp/uwsgi.sock</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-3" name="rest_code_3dc7358e7e1040868406e431b3fa0248-3"></a><span class="na">chmod-socket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">775</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-4" name="rest_code_3dc7358e7e1040868406e431b3fa0248-4"></a><span class="na">chdir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">/srv/myapp/appdata</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-5" name="rest_code_3dc7358e7e1040868406e431b3fa0248-5"></a><span class="na">master</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">true</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-6" name="rest_code_3dc7358e7e1040868406e431b3fa0248-6"></a><span class="na">binary-path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">/srv/myapp/venv/bin/uwsgi</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-7" name="rest_code_3dc7358e7e1040868406e431b3fa0248-7"></a><span class="na">virtualenv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">/srv/myapp/venv</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-8" name="rest_code_3dc7358e7e1040868406e431b3fa0248-8"></a><span class="na">module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">flaskapp:app</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-9" name="rest_code_3dc7358e7e1040868406e431b3fa0248-9"></a><span class="na">uid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">www-data</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-10" name="rest_code_3dc7358e7e1040868406e431b3fa0248-10"></a><span class="na">gid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">www-data</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-11" name="rest_code_3dc7358e7e1040868406e431b3fa0248-11"></a><span class="na">processes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">1</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-12" name="rest_code_3dc7358e7e1040868406e431b3fa0248-12"></a><span class="na">threads</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">1</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-13" name="rest_code_3dc7358e7e1040868406e431b3fa0248-13"></a><span class="na">plugins</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">python3,logfile</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3dc7358e7e1040868406e431b3fa0248-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_3dc7358e7e1040868406e431b3fa0248-14" name="rest_code_3dc7358e7e1040868406e431b3fa0248-14"></a><span class="na">logger</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">file:/srv/myapp/uwsgi.log</span>
</code></td></tr></table></div><p>Save this file as:</p>
<ul class="simple">
<li><p>Ubuntu, Debian: <code class="docutils literal"><span class="pre">/etc/uwsgi-emperor/vassals/myapp.ini</span></code></p></li>
<li><p>Fedora, CentOS, EL8 (AlmaLinux, Rocky Linux): <code class="docutils literal">/etc/uwsgi.d/myapp.ini</code></p></li>
<li><p>Arch Linux: <code class="docutils literal">/etc/uwsgi/vassals/myapp.ini</code> (create the directory first and <strong>chown</strong> it to http: <code class="docutils literal">mkdir <span class="pre">-p</span> /etc/uwsgi/vassals; chown <span class="pre">-R</span> http:http /etc/uwsgi/vassals</code>)</p></li>
</ul>
<p>The options are:</p>
<ul>
<li><p><code class="docutils literal">socket</code> — the socket file that will be used by your application. It’s usually a file path (Unix domain socket). You could use a local TCP socket, but it’s not recommended.</p></li>
<li><p><code class="docutils literal">chdir</code> — the app directory.</p></li>
<li><p><code class="docutils literal"><span class="pre">binary-path</span></code> — the uWSGI executable to use. Remove if you didn’t install the (optional) <code class="docutils literal">uwsgi</code> package in your virtual environment.</p></li>
<li><p><code class="docutils literal">virtualenv</code> — the virtual environment for your application.</p></li>
<li><p><code class="docutils literal">module</code> — the name of the module that houses your application, and the object that speaks the WSGI interface, separated by colons. This depends on your web framework:</p>
<div class="table-responsive-lg">
<table class="table table-bordered">
<thead><tr>
<th style="width: 10%">Framework</th>
<th style="width: 30%">Flask, Bottle</th>
<th style="width: 30%">Django</th>
<th style="width: 30%">Pyramid</th>
</tr></thead>
<tbody>
<tr>
<th>Package</th>
<td>module where <code>app</code> is defined</td>
<td><code><em>project</em>.wsgi</code><br><span style="font-size: 0.9rem">(<code style="font-size: 0.9rem"><em>project</em></code> is the package with <code style="font-size: 0.9rem">settings.py</code>)</span></td>
<td>module where <code>app</code> is defined</td>
</tr>
<tr>
<th>Callable</th>
<td>Flask: <code>app</code> instance<br>Bottle: <code>app = bottle.default_app()</code></td>
<td><code>application</code></td>
<td><code>app = config.make_wsgi_app()</code></td>
</tr>
<tr class="table-active">
<th>Module</th>
<td><code style="font-size: 1.2rem"><em>package</em>:app</code></td>
<td><code style="font-size: 1.2rem"><em>project</em>.wsgi:application</code></td>
<td><code style="font-size: 1.2rem"><em>package</em>:app</code></td>
</tr>
<tr>
<th>Caveats</th>
<td>Make sure <code>app</code> is <strong>not</strong> in an <code style="font-size: 0.85rem">if __name__ == '__main__':</code> block</td>
<td>Add environment variable for settings:<br><code style="font-size: 0.7rem">env = DJANGO_SETTINGS_MODULE=<em>project</em>.settings</code></td>
<td>Make sure <code>app</code> is <strong>not</strong> in an <code style="font-size: 0.85rem">if __name__ == '__main__':</code> block (the demo quickstart does that!)</td>
</tr>
</tbody>
</table>
</div></li>
<li><p><code class="docutils literal">uid</code> and <code class="docutils literal">gid</code> — the names of the user account to use for your server.  Use the same values as in the <code class="docutils literal">chown</code> command above.</p></li>
<li><p><code class="docutils literal">processes</code> and <code class="docutils literal">threads</code> — control the resources devoted to this application. Because this is a simple hello app, I used one process with one thread, but for a real app, you will probably need more (you need to see what works the best; there is no algorithm to decide). Also, remember that if you use multiple processes, they don’t share memory (you need a database to share data between them).</p></li>
<li><p><code class="docutils literal">plugins</code> — the list of uWSGI plugins to use. For Arch Linux, use <code class="docutils literal">plugins = python</code> (the <code class="docutils literal">logfile</code> plugin is always active).  For CentOS 7 only (i.e. <strong>not</strong> for EL8), use <code class="docutils literal">plugins = python36</code>.</p></li>
<li><p><code class="docutils literal">logger</code> — the path to your app-specific logfile. (Other logging facilities are available, but this one is the easiest, especially for multiple applications on the same server)</p></li>
<li><p><code class="docutils literal">env</code> — environment variables to pass to your app. Useful for configuration, may be specified multiple times. Example for Django: <code class="docutils literal">env = DJANGO_SETTINGS_MODULE=project.settings</code></p></li>
</ul>
<p>You can test your configuration by running <code class="docutils literal">uwsgi <span class="pre">--ini</span> /path/to/myapp.ini</code> (disable the logger for stderr output or run <code class="docutils literal">tail <span class="pre">-f</span> /srv/myapp/uwsgi.log</code> in another window).</p>
<p>If you’re using <strong>Fedora</strong>, <strong>CentOS</strong>, or <strong>EL8</strong>, there are two configuration changes you need to make globally: in <code class="docutils literal">/etc/uwsgi.ini</code>, disable the <code class="docutils literal"><span class="pre">emperor-tyrant</span></code> option (which we don’t need, as it sets uid/gid for every process based on the owner of the related <code class="docutils literal">.ini</code> config file — we use one global setup) and set <code class="docutils literal">gid = nginx</code>.  We’ll need this so that nginx can talk to your socket.</p>
</section>
<section id="nginx-configuration">
<h3>nginx configuration</h3>
<p>We need to configure our web server. Here’s a basic configuration that will get us started:</p>
<p>Save this file as:</p>
<ul class="simple">
<li><p>Ubuntu, Debian: <code class="docutils literal"><span class="pre">/etc/nginx/sites-enabled/myapp.conf</span></code></p></li>
<li><p>Fedora, CentOS, EL8 (AlmaLinux, Rocky Linux): <code class="docutils literal">/etc/nginx/conf.d/myapp.conf</code></p></li>
<li><p>Arch Linux: add <code class="docutils literal">include <span class="pre">/etc/nginx/conf.d/*.conf;</span></code> to your <code class="docutils literal">http</code> directive in <code class="docutils literal">/etc/nginx/nginx.conf</code> and use <code class="docutils literal">/etc/nginx/conf.d/myapp.conf</code></p></li>
</ul>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-1" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-1"></a><span class="k">server</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-2" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-2"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c1"># for a public HTTP server:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-3" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-3"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">listen</span><span class="w"> </span><span class="mi">80</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-4" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-4"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c1"># for a public HTTPS server:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-5" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-5"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="c1"># listen 443 ssl;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-6" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-6"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">server_name</span><span class="w"> </span><span class="s">localhost</span><span class="w"> </span><span class="s">myapp.local</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-7" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-7"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-8" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-8"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">location</span><span class="w"> </span><span class="s">/</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-9" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-9"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">include</span><span class="w"> </span><span class="s">uwsgi_params</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-10" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-10"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">uwsgi_pass</span><span class="w"> </span><span class="s">unix:/srv/myapp/uwsgi.sock</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-11" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-11"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-12" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-12"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-13" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-13"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">location</span><span class="w"> </span><span class="s">/static</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-14" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-14"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">alias</span><span class="w"> </span><span class="s">/srv/myapp/appdata/static</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-15" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-15"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-16" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-16"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-17" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-17"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">location</span><span class="w"> </span><span class="s">/favicon.ico</span><span class="w"> </span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-18" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-18"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="kn">alias</span><span class="w"> </span><span class="s">/srv/myapp/appdata/static/favicon.ico</span><span class="p">;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-19" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-19"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_87fa085cf558477a847e9e0988b1b3e2-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="rest_code_87fa085cf558477a847e9e0988b1b3e2-20" name="rest_code_87fa085cf558477a847e9e0988b1b3e2-20"></a><span class="p">}</span>
</code></td></tr></table></div><p>Note that this file is a very basic and rudimentary configuration. This configuration is fine for local testing, but for a real deployment, you will need to adjust it:</p>
<ul class="simple">
<li><p>set <code class="docutils literal">listen</code> to <code class="docutils literal">443 ssl</code> and create a http→https redirect on port 80 (you can get a free SSL certificate from <a class="reference external" href="https://letsencrypt.org/">Let’s Encrypt</a>; make sure to <a class="reference external" href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html">configure SSL properly</a>).</p></li>
<li><p>set <code class="docutils literal">server_name</code> to your real domain name</p></li>
<li><p>you might also want to add custom error pages, log files, or change anything else that relates to your web server — consult other nginx guides for details</p></li>
<li><p>nginx usually has some server already enabled by default — edit <code class="docutils literal">/etc/nginx/nginx.conf</code> or remove their configuration files from your sites directory to disable it</p></li>
</ul>
</section>
</section>
<section id="service-setup">
<h2>Service setup</h2>
<p>After you’ve configured uWSGI and nginx, you need to enable and start the system services.</p>
<section id="for-arch-linux">
<h3>For Arch Linux</h3>
<p>All you need is:</p>
<div class="code"><pre class="code sh"><a id="rest_code_f4fee615da8f41d4811b829f880176d6-1" name="rest_code_f4fee615da8f41d4811b829f880176d6-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_f4fee615da8f41d4811b829f880176d6-1"></a>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>nginx<span class="w"> </span>emperor.uwsgi
<a id="rest_code_f4fee615da8f41d4811b829f880176d6-2" name="rest_code_f4fee615da8f41d4811b829f880176d6-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_f4fee615da8f41d4811b829f880176d6-2"></a>systemctl<span class="w"> </span>start<span class="w"> </span>nginx<span class="w"> </span>emperor.uwsgi
</pre></div>
<p>Verify the service is running with <code class="docutils literal">systemctl status emperor.uwsgi</code></p>
</section>
<section id="for-fedora-centos-el8">
<h3>For Fedora, CentOS, EL8</h3>
<p>Make sure you followed the extra note about editing <code class="docutils literal">/etc/uwsgi.ini</code> earlier and run:</p>
<div class="code"><pre class="code sh"><a id="rest_code_4a91378499014435877a7e9c80fb5673-1" name="rest_code_4a91378499014435877a7e9c80fb5673-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_4a91378499014435877a7e9c80fb5673-1"></a>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>nginx<span class="w"> </span>uwsgi
<a id="rest_code_4a91378499014435877a7e9c80fb5673-2" name="rest_code_4a91378499014435877a7e9c80fb5673-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_4a91378499014435877a7e9c80fb5673-2"></a>systemctl<span class="w"> </span>start<span class="w"> </span>nginx<span class="w"> </span>uwsgi
</pre></div>
<p>Verify the service is running with <code class="docutils literal">systemctl status uwsgi</code></p>
<p>If you disabled SELinux, this is enough to get an app working and you can skip over to the next section.</p>
<p>If you want to use SELinux, you need to do the following to allow nginx to read static files:</p>
<div class="code"><pre class="code sh"><a id="rest_code_41a1d2f1251346b2af452af27fd6ea47-1" name="rest_code_41a1d2f1251346b2af452af27fd6ea47-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_41a1d2f1251346b2af452af27fd6ea47-1"></a>setenforce<span class="w"> </span><span class="m">0</span>
<a id="rest_code_41a1d2f1251346b2af452af27fd6ea47-2" name="rest_code_41a1d2f1251346b2af452af27fd6ea47-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_41a1d2f1251346b2af452af27fd6ea47-2"></a>chcon<span class="w"> </span>-R<span class="w"> </span>system_u:system_r:httpd_t:s0<span class="w"> </span>/srv/myapp/appdata/static
<a id="rest_code_41a1d2f1251346b2af452af27fd6ea47-3" name="rest_code_41a1d2f1251346b2af452af27fd6ea47-3" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_41a1d2f1251346b2af452af27fd6ea47-3"></a>setenforce<span class="w"> </span><span class="m">1</span>
</pre></div>
<p>We now need to install a <a class="reference external" href="https://chriswarrick.com/pub/nginx-uwsgi.pp">SELinux policy</a> (that I created for this project; updated 2020-05-02) to allow nginx and uWSGI to communicate.
Download <a class="reference external" href="https://chriswarrick.com/pub/nginx-uwsgi.pp">nginx-uwsgi.pp</a> and run:</p>
<div class="code"><pre class="code sh"><a id="rest_code_3cf167a88c294332abedc17e9c7f3735-1" name="rest_code_3cf167a88c294332abedc17e9c7f3735-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_3cf167a88c294332abedc17e9c7f3735-1"></a>semodule<span class="w"> </span>-i<span class="w"> </span>nginx-uwsgi.pp
</pre></div>
<p>Hopefully, this is enough (you can delete the file). In case it isn’t, please read SELinux documentation, check audit logs, and look into <code class="docutils literal">audit2allow</code>.</p>
</section>
<section id="for-ubuntu-and-debian">
<h3>For Ubuntu and Debian</h3>
<p>Ubuntu and Debian (still!) use LSB services for uWSGI. Because LSB services are awful, we’re going to set up our own systemd-based (native) service.</p>
<p>Start by disabling the LSB service that comes with Ubuntu and Debian:</p>
<div class="code"><pre class="code sh"><a id="rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-1" name="rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-1"></a>systemctl<span class="w"> </span>stop<span class="w"> </span>uwsgi-emperor
<a id="rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-2" name="rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_e3ea69a4dabd430fb3155f4d1d8ed983-2"></a>systemctl<span class="w"> </span>disable<span class="w"> </span>uwsgi-emperor
</pre></div>
<p>Copy the <code class="docutils literal">.service</code> file from the <a class="reference external" href="https://uwsgi-docs.readthedocs.org/en/latest/Systemd.html#adding-the-emperor-to-systemd">uWSGI systemd documentation</a> to <code class="docutils literal">/etc/systemd/system/emperor.uwsgi.service</code>.  Change the ExecStart line to:</p>
<div class="code"><pre class="code ini"><a id="rest_code_0af5cc3b6ac14570b52f79551d4b8985-1" name="rest_code_0af5cc3b6ac14570b52f79551d4b8985-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_0af5cc3b6ac14570b52f79551d4b8985-1"></a><span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/uwsgi --ini /etc/uwsgi-emperor/emperor.ini</span>
</pre></div>
<p>You can now reload systemd daemons and enable the services:</p>
<div class="code"><pre class="code sh"><a id="rest_code_cf61a6a5205149b7989dbb4550f60700-1" name="rest_code_cf61a6a5205149b7989dbb4550f60700-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_cf61a6a5205149b7989dbb4550f60700-1"></a>systemctl<span class="w"> </span>daemon-reload
<a id="rest_code_cf61a6a5205149b7989dbb4550f60700-2" name="rest_code_cf61a6a5205149b7989dbb4550f60700-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_cf61a6a5205149b7989dbb4550f60700-2"></a>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>nginx<span class="w"> </span>emperor.uwsgi
<a id="rest_code_cf61a6a5205149b7989dbb4550f60700-3" name="rest_code_cf61a6a5205149b7989dbb4550f60700-3" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_cf61a6a5205149b7989dbb4550f60700-3"></a>systemctl<span class="w"> </span>reload<span class="w"> </span>nginx
<a id="rest_code_cf61a6a5205149b7989dbb4550f60700-4" name="rest_code_cf61a6a5205149b7989dbb4550f60700-4" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_cf61a6a5205149b7989dbb4550f60700-4"></a>systemctl<span class="w"> </span>start<span class="w"> </span>emperor.uwsgi
</pre></div>
<p>Verify the service is running with <code class="docutils literal">systemctl status emperor.uwsgi</code>.  (Ignore
the warning about no request plugin)</p>
</section>
</section>
</section>
<section id="end-result">
<h1>End result</h1>
<p>Your web service should now be running at <a class="reference external" href="http://localhost/">http://localhost/</a> (or wherever you set up server to listen).</p>
<p>If you used the demo application, you should see something like this (complete with the favicon and image greeting):</p>
<img alt="/images/nginx-uwsgi-demo.png" class="centered" src="https://chriswarrick.com/images/nginx-uwsgi-demo.png">
<p>If you want to test with cURL:</p>
<div class="code"><pre class="code sh"><a id="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-1" name="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-1"></a>curl<span class="w"> </span>-v<span class="w"> </span>http://localhost/
<a id="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-2" name="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-2"></a>curl<span class="w"> </span>-I<span class="w"> </span>http://localhost/favicon.ico
<a id="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-3" name="rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-3" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_a6f6d19b27a4438eaffbdd0c3b8add49-3"></a>curl<span class="w"> </span>-I<span class="w"> </span>http://localhost/static/hello.png
</pre></div>
<section id="troubleshooting">
<h2>Troubleshooting</h2>
<p>Hopefully, everything works. If it doesn’t:</p>
<ul class="simple">
<li><p>Check your nginx, system (<code class="docutils literal">journalctl</code>, <code class="docutils literal">systemctl status SERVICE</code>) and uwsgi (<code class="docutils literal">/srv/myapp/uwsgi.log</code>) logs.</p></li>
<li><p>Make sure you followed all instructions.</p></li>
<li><p>If you get a default site, disable that site in nginx config (<code class="docutils literal">/etc/nginx/nginx.conf</code> or your sites directory).</p></li>
<li><p>If you have a firewall installed, make sure to open the ports your web server runs on (typically 80/443). For <code class="docutils literal">firewalld</code> (Fedora, CentOS, EL8):</p></li>
</ul>
<div class="code"><pre class="code sh"><a id="rest_code_523bca1d77ee4cedb025cba2a35e403d-1" name="rest_code_523bca1d77ee4cedb025cba2a35e403d-1" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_523bca1d77ee4cedb025cba2a35e403d-1"></a>firewall-cmd<span class="w"> </span>--add-service<span class="w"> </span>http
<a id="rest_code_523bca1d77ee4cedb025cba2a35e403d-2" name="rest_code_523bca1d77ee4cedb025cba2a35e403d-2" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#rest_code_523bca1d77ee4cedb025cba2a35e403d-2"></a>firewall-cmd<span class="w"> </span>--add-service<span class="w"> </span>https
</pre></div>
<ul class="simple">
<li><p>If it still does not work, feel free to ask in the comments, mentioning your distribution, installation method, and what doesn’t work.</p></li>
</ul>
</section>
</section>
<section id="can-i-use-docker">
<h1>Can I use Docker?</h1>
<p>This blog post is written for systems running standalone. But Docker is a bit special, in that it offers a limited subset of OS features this workflow expects. The main issue is with user accounts, which generally work weird in Docker, and I had issues with <code class="docutils literal">setuid</code>/<code class="docutils literal">setgid</code> as used by uWSGI. Another issue is the lack of systemd, which means that another part of the tutorial fails to apply.</p>
<p>This tutorial uses uWSGI Emperor, which can run multiple sites at once, and offers other management features (such as seamless code restarts with <code class="docutils literal">touch /etc/uwsgi/vassals/myapp.ini</code>) that may not be useful or easy to use in a Docker environment. You’d probably also run uWSGI and nginx in separate containers in a typical Docker deployment.</p>
<p>Regardless, many parts of this tutorial can be used with Docker, although with the aforementioned adjustments. I have done some work on this topic. This tutorial has an Ansible Playbook attached, and the tutorial/playbook are compatible with five Linux distros in multiple versions. How do I know that there were no unexpected bugs in an older version? I could grab a Vagrant image or set up a VM. I do that when I need specific testing, but doing it for each of the distros on each update would take at least half an hour, probably even more. Yeah, that needs automating. I decided to use GitHub Actions for the CI, which can run anything, as long as you provide a Dockerfile.</p>
<p>The Docker images were designed to support running the Playbook and testing it. But the changes, setups and patches could be a good starting point if you wanted to make your own Docker containers that could run in production. You can take a look at <a class="reference external" href="https://github.com/Kwpolska/ansible-nginx-uwsgi/tree/master/ci">the Docker files for CI</a> The images support all 5 distros using their base images, but you could probably use Alpine images, or the <code class="docutils literal">python</code> docker images; be careful not to mix Python versions in the latter case.</p>
<p>In 2026, I gave up on setting up Python applications with uWSGI using the system Python and virtual environments. I’ve switched all my deployments to Docker containers with Gunicorn as the application server. Nowadays, Docker is a much better choice, as not having to deal with system Python and system virtual environments makes deployments much easier. I wrote up my experiences and shared the configuration files in <a class="reference external" href="https://chriswarrick.com/blog/2026/02/06/deploying-python-web-applications-with-docker/">Deploying Python Web Applications with Docker</a>.</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="footnote-1" role="doc-footnote">
<span class="label"><span class="fn-bracket">[</span><a role="doc-backlink" href="https://chriswarrick.com/blog/2016/02/10/deploying-python-web-apps-with-nginx-and-uwsgi-emperor/#footnote-reference-1">1</a><span class="fn-bracket">]</span></span>
<p>This reflink gives you €20 in credit (expires the next month). I earn €10 after you spend €10 of your own.</p>
</aside>
</aside>
</section>
]]></content:encoded><category>Python</category><category>Ansible</category><category>Arch Linux</category><category>Django</category><category>Flask</category><category>guide</category><category>Internet</category><category>Linux</category><category>nginx</category><category>Python</category><category>systemd</category><category>uWSGI</category></item><item><title>Python Apps the Right Way: entry points and scripts</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/</link><pubDate>Mon, 15 Sep 2014 16:00:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/</guid><description>
There are multiple ways to write an app in Python.  However, not all of them
provide your users with the best experience.
One of the problems some people encounter is writing launch scripts.  The
best way to handle this is the Entry Points mechanism of Setuptools, and a
__main__.py file.  It’s quite easy to implement.  If you’re interested,
read on to learn more!
</description><content:encoded><![CDATA[
<p>There are multiple ways to write an app in Python.  However, not all of them
provide your users with the best experience.</p>
<p>One of the problems some people encounter is <em>writing launch scripts</em>.  The
best way to handle this is the <em>Entry Points</em> mechanism of Setuptools, and a
<code class="docutils literal">__main__.py</code> file.  It’s quite easy to implement.  If you’re interested,
read on to learn more!</p>



<section id="requirements-and-desired-results">
<h1>Requirements and Desired Results</h1>
<p>You will need:</p>
<ul>
<li><p>a Python project</p></li>
<li><p>a setup.py file using <a class="reference external" href="https://pypi.python.org/pypi/setuptools">setuptools</a></p></li>
<li><p>the following directory structure:</p>
<ul class="list-nobullets">
    <li>
    <a href="https://chriswarrick.com/listings/entry_points_project/"><i class="bi bi-folder-fill"></i>
    entry_points_project/</a>
    <li>
        <ul class="list-nobullets">
        <li>
        <a href="https://chriswarrick.com/listings/entry_points_project/my_project/"><i class="bi bi-folder-fill"></i> my_project/</a>
            <li>
            <ul class="list-nobullets">
                <li>
                <a href="https://chriswarrick.com/listings/entry_points_project/my_project/__init__.py.html"><i class="bi bi-file-earmark-code-fill"></i>
                __init__.py</a>
                </li>
                <li>
                <a href="https://chriswarrick.com/listings/entry_points_project/my_project/__main__.py.html"><i class="bi bi-file-earmark-code-fill"></i>
                __main__.py</a>
                </li>
            </ul>
            </li>
        <li>
        <a href="https://chriswarrick.com/listings/entry_points_project/setup.py.html"><i class="bi bi-file-earmark-code-fill"></i> setup.py</a>
        </li>
        </ul>
    </li>
    </ul></li>
</ul>
<p>(<code class="docutils literal">entry_points_project</code> is also where the README and other auxiliary files
go, while <code class="docutils literal">my_project</code> contains all the Python code.)</p>
<p>When you’re done, you will have a project that can be executed by:</p>
<ul class="simple">
<li><p><code class="docutils literal">python <span class="pre">-m</span> my_project</code></p></li>
<li><p><code class="docutils literal">my_project</code></p></li>
</ul>
<p>Provided that you have your Python directory and its <code class="docutils literal">Scripts\</code> subdirectory on
the %PATH%, this will <strong>also work in Windows</strong>.</p>
 <div class="panel panel-info">
   <div class="panel-heading">
     <h3 class="panel-title">Looking for a project template?</h3>
   </div>
   <div class="panel-body">
    If you want to create a well-structured project with release automation and
some other goodies, check out my <a href="https://github.com/Kwpolska/python-project-template" style="font-weight: bold;">Python Project Template</a>.
   </div>
 </div></section>
<section id="step-1-create-a-main-py-file">
<h1>Step 1: create a <code class="docutils literal">__main__.py</code> file</h1>
<p>In order to implement the first desired result, you need to create a
<code class="docutils literal">__main__.py</code> file in your package.  This file needs to contain a <code class="docutils literal">main()</code>
function that takes no arguments, and also a special passage to determine code
to run:</p>
<p><a class="reference external" href="link://listing/listings/entry_points_project/my_project/__main__.py">entry_points_project/my_project/__main__.py</a>  <a class="reference external" href="link://listing_source/listings/entry_points_project/my_project/__main__.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-1" name="rest_code_d0a7bdde7283412db1d179ad410001ec-1"></a><span class="kn">import</span><span class="w"> </span><span class="nn">sys</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-2" name="rest_code_d0a7bdde7283412db1d179ad410001ec-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-3" name="rest_code_d0a7bdde7283412db1d179ad410001ec-3"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-4" name="rest_code_d0a7bdde7283412db1d179ad410001ec-4"></a><span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="n">args</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-5" name="rest_code_d0a7bdde7283412db1d179ad410001ec-5"></a><span class="w">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="sd">&quot;&quot;&quot;The main routine.&quot;&quot;&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-6" name="rest_code_d0a7bdde7283412db1d179ad410001ec-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="n">args</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-7" name="rest_code_d0a7bdde7283412db1d179ad410001ec-7"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">args</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-8" name="rest_code_d0a7bdde7283412db1d179ad410001ec-8"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-9" name="rest_code_d0a7bdde7283412db1d179ad410001ec-9"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;This is the main routine.&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-10" name="rest_code_d0a7bdde7283412db1d179ad410001ec-10"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;It should do something interesting.&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-11" name="rest_code_d0a7bdde7283412db1d179ad410001ec-11"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-12" name="rest_code_d0a7bdde7283412db1d179ad410001ec-12"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># Do argument parsing here (eg. with argparse) and anything else</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-13" name="rest_code_d0a7bdde7283412db1d179ad410001ec-13"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># you want your project to do. Return values are exit codes.</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-14" name="rest_code_d0a7bdde7283412db1d179ad410001ec-14"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-15" name="rest_code_d0a7bdde7283412db1d179ad410001ec-15"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-16" name="rest_code_d0a7bdde7283412db1d179ad410001ec-16"></a><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&quot;__main__&quot;</span><span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_d0a7bdde7283412db1d179ad410001ec-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="rest_code_d0a7bdde7283412db1d179ad410001ec-17" name="rest_code_d0a7bdde7283412db1d179ad410001ec-17"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</code></td></tr></table></div><ol class="arabic simple">
<li><p>The <code class="docutils literal">if __name__ == &quot;__main__&quot;:</code> idiom, as <a class="reference external" href="https://docs.python.org/3/library/__main__.html">documented here</a>, is used to check whether
this is executed as the top-level file, or if it has been imported by someone
else (in this case, executing the <code class="docutils literal">main()</code> function is not always intended).</p></li>
<li><p>The <code class="docutils literal">main()</code> function must not take any arguments, because that’s how
<code class="docutils literal">entry_points</code> executes things.</p></li>
</ol>
</section>
<section id="step-2-adjust-setup-py-accordingly">
<h1>Step 2: adjust <code class="docutils literal">setup.py</code> accordingly</h1>
<p>This is the real deal: create the entry points in your <code class="docutils literal">setup.py</code> file.</p>
<p><a class="reference external" href="link://listing/listings/entry_points_project/setup.py">entry_points_project/setup.py</a>  <a class="reference external" href="link://listing_source/listings/entry_points_project/setup.py">(Source)</a></p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-1" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">setuptools</span><span class="w"> </span><span class="kn">import</span> <span class="n">setup</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-2" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-3" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-3"></a><span class="n">setup</span><span class="p">(</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-4" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-4"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">name</span><span class="o">=</span><span class="s2">&quot;my_project&quot;</span><span class="p">,</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-5" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-5"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">version</span><span class="o">=</span><span class="s2">&quot;0.1.0&quot;</span><span class="p">,</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-6" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">packages</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;my_project&quot;</span><span class="p">],</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-7" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-7"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">entry_points</span><span class="o">=</span><span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-8" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-8"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;console_scripts&quot;</span><span class="p">:</span> <span class="p">[</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-9" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-9"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;my_project = my_project.__main__:main&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-10" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-10"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-11" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-11"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">},</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_c3236443b6d14709bd22e3b2b15c29c3-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="rest_code_c3236443b6d14709bd22e3b2b15c29c3-12" name="rest_code_c3236443b6d14709bd22e3b2b15c29c3-12"></a><span class="p">)</span>
</code></td></tr></table></div><ol class="arabic simple">
<li><p>You must use setuptools, otherwise this won’t work.</p></li>
<li><p>The most important piece of code is the <code class="docutils literal">entry_points</code> declaration
(unsurprisingly).</p></li>
<li><p>The declaration reads</p></li>
</ol>
<div class="code"><pre class="code text"><a id="rest_code_a39bdd0254594347ad5e67fddd274e39-1" name="rest_code_a39bdd0254594347ad5e67fddd274e39-1" href="https://chriswarrick.com/blog/2014/09/15/python-apps-the-right-way-entry_points-and-scripts/#rest_code_a39bdd0254594347ad5e67fddd274e39-1"></a>&quot;name_of_executable = module.with:function_to_execute&quot;
</pre></div>
<ol class="arabic simple" start="4">
<li><p>If you are developing a GUI application (in Tkinter, PyQt/PySide,
wxPython, PyGTK, PyGame…), you should change the declaration to
<code class="docutils literal">gui_scripts</code>.  On *nix, this makes no difference, but on Windows, it
means that running your script by opening the created <code class="docutils literal">.exe</code> files does
not show a console window. Note that stdout/stderr do not work in that mode
under Windows, which can lead to spurious application crashes.  (GUI-only
processes cannot use stdout/stderr because they don’t have a console
attached)</p></li>
<li><p>You can create <strong>multiple scripts</strong> this way.  You can also have multiple
<code class="docutils literal">console_scripts</code> <em>and</em> <code class="docutils literal">gui_scripts</code> in one setup file.</p></li>
</ol>
<p class="text-muted">All <a class="reference external" href="https://chriswarrick.com/listings/entry_points_project/">code samples</a> are freely reusable, but if you mention where you got them from, it’d be really nice.</p>
</section>
]]></content:encoded><category>Python</category><category>best practices</category><category>devel</category><category>guide</category><category>Python</category></item><item><title>Adventures in Windows: Music Player Daemon</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2013/09/01/mpd-on-windows/</link><pubDate>Sun, 01 Sep 2013 17:15:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2013/09/01/mpd-on-windows/</guid><description>
Recently, I had to reinstall Windows.  One of the things I had to set up
was MPD, the Music Player Daemon.
This is a short guide on how to do this.
</description><content:encoded><![CDATA[
<p>Recently, I had to reinstall Windows.  One of the things I had to set up
was MPD, the <a class="reference external" href="http://musicpd.org/">Music Player Daemon</a>.</p>
<p>This is a short guide on how to do this.</p>



<section id="step-1-get-mpd-and-mpc">
<h1>Step 1: get MPD and MPC</h1>
<p>Download <a class="reference external" href="http://musicpd.org/download/win32/">MPD</a> (<code class="docutils literal"><span class="pre">mpd-x.y.z-win32.zip</span></code>, replacing <code class="docutils literal">x.y.z</code> with whatever is the current available version of this file) and <a class="reference external" href="http://musicpd.org/download/mpc/">MPC</a> (<code class="docutils literal"><span class="pre">mpc-x.y-win32-zip</span></code>).  I suggest using
<code class="docutils literal"><span class="pre">C:\mpd</span></code> as your base path.  This post assumes you actually used this
value.</p>
<p>Put everything from the <code class="docutils literal"><span class="pre">/mpd-x.y.z-win32/bin/</span></code> directory of the
<code class="docutils literal"><span class="pre">mpd-x.y.z-win32.zip</span></code> archive into your base path (<code class="docutils literal"><span class="pre">C:\mpd</span></code>).  From
the <code class="docutils literal"><span class="pre">mpc-x.y-win32.zip</span></code> archive, take <code class="docutils literal">mpc.exe</code> and
<code class="docutils literal"><span class="pre">libmpdclient-2.dll</span></code> and put them there.</p>
</section>
<section id="step-1-5-optional-but-recommended-get-gmpc">
<h1>Step 1.5 (optional, but recommended): get GMPC</h1>
<p>If you want a nice, easy, graphical interface for MPD, you should install
GMPC, the <a class="reference external" href="http://gmpclient.org/">Gnome Music Player Client</a>.  The installation is very
straightforward, so I’ll leave the details out.</p>
</section>
<section id="step-2-create-a-config-file">
<h1>Step 2: create a config file</h1>
<p>You need to create a configuration file.  A sample one is included in
<code class="docutils literal"><span class="pre">/mpd-x.y.z-win32/doc/mpdconf.sample</span></code>.  Use the <code class="docutils literal">winmm</code> output type.</p>
<p><strong>Warning:</strong> Windows Notepad will not work, because it does not understand
Unix-style line endings (<code class="docutils literal">\n</code> instead of <code class="docutils literal">\r\n</code>).</p>
<p>For <code class="docutils literal">db_file</code> and <code class="docutils literal">log_file</code>, I recommend a file in <code class="docutils literal"><span class="pre">C:\mpd\data\</span></code>.
I also recommend saving your config as <code class="docutils literal"><span class="pre">C:\mpd\data\mpd.conf</span></code> (in fact,
this is yet another assumption we make in this guide)</p>
<section id="multi-boot-corner-keep-parts-of-the-config-the-same">
<h2>Multi Boot Corner: keep parts of the config the same</h2>
<p>Because I have a dual-boot system, there are some directions for
multi-boot users.</p>
<p>Your <code class="docutils literal">music_directory</code>, <code class="docutils literal">playlist_directory</code> and <code class="docutils literal">state_file</code> <em>must</em> be the same on all the systems in your multi-boot environment.  It is recommended to use the same <code class="docutils literal">db_file</code>.</p>
<p>Your audio outputs must have the same names.</p>
</section>
</section>
<section id="step-3-test-your-configuration">
<h1>Step 3: test your configuration</h1>
<p>Open up two Command Prompt windows.  In the first one, run:</p>
<pre class="literal-block">cd C:\mpd
mpd data\mpd.conf</pre>
<p>If you see this message:</p>
<pre class="literal-block">Failed to load database: Failed to open database file &quot;&lt;name&gt;&quot;: No such file or directory</pre>
<p>then you can ignore it.  If you see another message, fix whatever it
states.  You may also use <code class="docutils literal"><span class="pre">--stdout</span></code> or <code class="docutils literal"><span class="pre">-v</span></code> to get more output
messages.</p>
<section id="multi-boot-path">
<h2>Multi Boot path</h2>
<p>If you followed the Multi Boot instructions correctly, you might be
hearing music already.  If you do not, use your other Command Prompt window and
run:</p>
<pre class="literal-block">cd C:\mpd
mpc play</pre>
<p>If it outputs the name of a song, a <code class="docutils literal">[playing]</code> line, all is well (if you
cannot hear music, unmute your audio).</p>
<p>If you do not have a mpd database yet, use the <em>Single path</em>.</p>
<p><strong>If MPD works, press Ctrl+C in the window where you ran ``mpd
datampd.conf.``</strong></p>
</section>
<section id="single-path">
<h2>Single path</h2>
<p>In the other Command Prompt window, run:</p>
<pre class="literal-block">cd C:\mpd
mpc update
mpc add &quot;FILENAME&quot;
mpc play</pre>
<p>(FILENAME should be a name of a file in your music library.  Make sure to
keep the quotes.)</p>
<p>And now you should hear music.  If you do not, try to unmute, then read
the output of <code class="docutils literal">mpc</code> and try to fix it.</p>
<p><strong>If MPD works, press Ctrl+C in the window where you ran ``mpd
datampd.conf.``</strong></p>
</section>
</section>
<section id="step-3-5-test-gmpc">
<h1>Step 3.5: test GMPC</h1>
<p>Start the Gnome Music Player Client.  Click <em>Forward</em>, <em>Connect</em>,
<em>Forward</em>, <em>Close</em> and all should be well.</p>
</section>
<section id="step-4-create-a-windows-service">
<h1>Step 4: create a Windows service</h1>
<p>In order to run the daemon in the <em>daemon</em> mode, i.e. hidden, you need to
perform some extra steps.  You cannot use Startup in the Start Menu, you
also cannot use the Run registry keys (this results in an ugly Command Prompt
window running all the time that you cannot close or hide in the tray).</p>
<p>How to solve this problem?  Just run it as a Windows service.  That is
very easy to do.</p>
<p>Open a Command Prompt window as an administrator (right-click on <em>Command
Prompt</em> in the Start Menu/on the Start Screen and choose <em>Run as administrator</em>).</p>
<p>In that window, run one very easy command (make sure to copy-paste this
exactly!):</p>
<pre class="literal-block">sc create mpd binPath= &quot;c:\mpd\mpd.exe c:\mpd\data\mpd.conf&quot;</pre>
<p>If it said:</p>
<ul class="simple">
<li><p><code class="docutils literal">[SC] CreateService SUCCESS</code>, congratulations — you are almost done!  Skip down to <em>Service configuration.</em></p></li>
<li><p><code class="docutils literal">[SC] OpenSCManager FAILED 5: Access is denied.</code>, you need an
<strong>Administrator</strong> Command Prompt.</p></li>
<li><p>something else, check your spelling or Google the error.</p></li>
</ul>
<section id="service-configuration">
<h2>Service configuration</h2>
<p>That is the easiest part of this guide.</p>
<p>Start the <em>Services</em> console.  You can get to it by typing
<code class="docutils literal">services.msc</code> into the Start Menu/Screen search (<em>Run</em> for XP or
older).</p>
<p>In the tool, find the <code class="docutils literal">mpd</code> service.  Go to the <em>Log On</em> tab, choose
<em>This account:</em> and enter your credentials there.  Hit <em>Apply</em> and go to
the <em>General</em> tab, on which you should choose the <em>Startup type</em> to be
<em>Automatic (Delayed Start)</em>.  Finish by pressing <em>Start</em>.  MPD should be
running and configured properly.  You can now hit <em>OK</em> and close the
<em>Services</em> window, along with the command prompts you have open.</p>
<p><strong>Warning:</strong> if you change your Windows password, you need to change your
password in the <em>Services</em> console as well!</p>
</section>
<section id="just-in-case-uninstalling-the-service">
<h2>Just in case: uninstalling the service</h2>
<p>First off, stop the service (in the Services console or through <code class="docutils literal">sc stop
mpd</code> in an administrator command prompt).</p>
<p>Then, run <code class="docutils literal">sc delete mpd</code>.</p>
</section>
</section>
]]></content:encoded><category>Windows</category><category>guide</category><category>mpd</category><category>Windows</category></item></channel></rss>