<?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 devel</title><link>https://chriswarrick.com/</link><atom:link href="https://chriswarrick.com/blog/tags/devel.xml" rel="self" type="application/rss+xml" /><description>A rarely updated blog, mostly about programming.</description><lastBuildDate>Sat, 03 Apr 2021 11:00:00 GMT</lastBuildDate><generator>https://github.com/Kwpolska/YetAnotherBlogGenerator</generator><item><title>What an ARM Mac means for developers and Windows users</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2020/06/22/what-an-arm-mac-means-for-developers-and-windows-users/</link><pubDate>Mon, 22 Jun 2020 19:00:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2020/06/22/what-an-arm-mac-means-for-developers-and-windows-users/</guid><description>
The rumor mill was right this time, and Apple has just announced they will
transition Macs to ARM processors. These news have some side effects for
software developers, particularly those not working with the Apple ecosystem.
And they also affect people who depend on both macOS and Windows.
</description><content:encoded><![CDATA[
<p>The rumor mill was right this time, and Apple has just announced they will
transition Macs to ARM processors. These news have some side effects for
software developers, particularly those not working with the Apple ecosystem.
And they also affect people who depend on both macOS and Windows.</p>



<p>In this post, I am not going to focus in the differences between x86_64 and ARM,
RISC and CISC, and all the benchmarks. Let’s assume that Apple manages to offer
ARM-based CPUs that can match performance of most Intel processors in Apple’s
lineup, and let’s even assume they can make an ARM Mac Pro. (A note on naming:
Apple Silicon is the official name, but it sounds ugly. I’ll just call it ARM.
For Intel, I’ll use either Intel or x86(_64).)</p>
<p>For many users, the transition will be more-or-less transparent. Sure, they’ll
lose some apps, just like they probably did with Catalina (which dropped
support for 32-bit Intel apps), or some apps will not be available/will be
buggy in the first few months of the transition (though it will be easier than
the PowerPC transition, because Apple uses little-endian byte order on ARM).</p>
<section id="how-will-it-work-out-in-apple-land">
<h1>How will it work out in Apple land?</h1>
<p>For developers who work only on iOS apps, the transition also won’t mean much.
Maybe a faster, more accurate Simulator. They’ll need to buy an ARM Mac sooner
or later (within the next 5 years), because Apple requires them to use the
latest Xcode version for App Store submissions, and Xcode supports at best the
previous version of macOS.  But that has been Apple’s policy forever, and the
Intel Macs will probably be within the usual deprecation range when that
happens.</p>
<p>The requirements for macOS-only developers are pretty obvious, they will need
to buy an ARM Mac on day one, so they can test their apps on the new platform.
They will also need to work on ARM compatibility — although updating your app
for the new OS is a yearly ritual in Apple land, so that’s also mostly
business-as-usual (unless you do a lot of unportable low-level stuff in your
code). There are some pro apps that tend to lag behind new Apple decrees (some
might have been hit by Catalina), and users of those apps might prefer to stay
with Intel for a little bit longer.</p>
<p>But then, we get to the requirements of developers who use Macs, but don’t work
exclusively with the Apple platforms. This is a fairly large group, since many
developers like Macs for the good hardware, Unix-based software, and the
integration of both. And for some part, non-developers are affected too.</p>
</section>
<section id="who-needs-non-apple-operating-systems">
<h1>Who needs non-Apple operating systems?</h1>
<p>The first group are people tied to Windows, somehow. Some of them might be
using Boot Camp to play games. Others might be using Boot Camp or
virtualization software (Parallels Desktop, VMware Fusion, Oracle VM
VirtualBox) to run Windows and Windows-specific apps — perhaps they need the
Windows version of Office, or various Windows-onlypro apps, or they need
Windows to file their taxes, because their government does not care about
non-Windows OSes. Or perhaps they’re web developers, and they need to test
compatibility with the Windows versions of browsers, or the old Microsoft
browsers (IE and pre-Chromium Edge).</p>
<p>The second group is software developers who need Linux. While macOS provides a
very competent development environment, and many things can be run directly on
macOS, some use-cases may require a Linux VM.  Perhaps the most notable case is
Docker.</p>
<p>Docker is a solution for lightweight app containers, that can offer separation
between apps, and that can simplify and standardize deployment. Docker itself
is not a virtualization solution (at least in the traditional sense). Docker
must run on top of Linux (there’s also Docker-on-Windows, but that’s another
story). The Docker Desktop for Mac app runs a lightweight Linux VM, and runs
containers in that VM. The virtualization solution <a class="reference external" href="https://github.com/docker/for-mac">Docker for Mac uses</a> is <code class="docutils literal">Hypervisor.framework</code>, which is
part of macOS itself.</p>
<p>Who else needs virtualization? Android developers. The Android Emulator is also
a virtual machine that runs the Android operating system. Android can run on
different architectures, and so, a x86 system image is typically used for the
Emulator.</p>
</section>
<section id="is-virtualization-possible-on-arm">
<h1>Is virtualization possible on ARM?</h1>
<p>Yes, definitely. Apple has been testing it much earlier, since the
aforementioned <code class="docutils literal">Hypervisor.framework</code> was found <a class="reference external" href="https://twitter.com/never_released/status/1250533740557852674">on iOS in April</a>.
And Apple announced virtualization support for ARM Macs during the keynote, and
showed an example of a Linux VM. That VM was, of course, running an ARM64
distribution of Linux.</p>
<p>But what can we use this for? Turns out, it’s complicated. The easiest thing
from the few use-cases mentioned before is Android. Google just needs to get
the Emulator working on ARM Macs and ship that to the devs.</p>
<p>What about Linux in general? Many mainstream distributions
support ARM64, so that’s not a problem in general. The support for a particular
distro or software might be worse than on x86_64, but it’s generally not a
problem for users.</p>
<p>But for Docker, there’s a problem. One of the many advantages of Docker is
dev-prod parity. If you deploy your app with Docker to an x86_64 Linux server,
you can also install Docker on an x86_64 Linux developer machine (or a Linux VM on an
Intel Mac/Windows PC). Both the server and the dev machine can run <strong>the same</strong>
image, the same code, the same configuration. That won’t happen if they are a
different architecture. This means that you can end up with bugs happening
because of different environments, and it’s also possible that some images you
depend on are not available for both architectures.</p>
<p>And then we get to Windows. Windows also has an ARM version, but it’s currently
available only with a new ARM device (you can’t buy it standalone). If
Microsoft were to sell this, we’d have an issue with the software. Windows 10
on ARM supports 32/64-bit ARM software, and can run 32-bit Intel (x86) software
using emulation. It cannot, however, emulate apps that require 64-bit Intel
processors (x86_64).  This makes the software situation on that platform a bit
better. While many developers don’t care about ARM and might not have builds
for ARM available, most Windows software is available in both x86 and x86_64
versions, or is exclusively 32-bit. But certain pro apps are x86_64 only, so if
there is no ARM build of it, an ARM Windows PC currently cannot run it.
(<em>Update:</em> Microsoft announced <a class="reference external" href="https://blogs.windows.com/windowsexperience/2020/09/30/now-more-essential-than-ever-the-role-of-the-windows-pc-has-changed/">x86_64 emulation on ARM</a>,
which means more software will work.)</p>
<p>And note that Microsoft knows about the transition, but we haven’t heard
anything about Windows during the keynote…</p>
</section>
<section id="can-we-emulate-x86-64-and-run-x86-64-windows-10">
<h1>Can we emulate x86(_64) and run x86(_64) Windows 10?</h1>
<p>Theoretically? Yes. Practically? No.</p>
<p>The issue with emulation is speed. There are a few x86 emulators available, and
those emulators can be run on an ARM device just fine. You can find videos on
YouTube (not a very reliable source of information, I know) in which people try
to benchmark those, or try to run Windows using an emulator like that. And even
with an ancient Windows version, the emulation is painfully slow. Windows 10
would be basically unusable if you tried to emulate all of it.</p>
<p>How does the x86 emulation on Windows 10 for ARM work? You can watch <a class="reference external" href="https://channel9.msdn.com/Events/Build/2017/P4171">the
Channel 9 video about Windows 10 on ARM</a> (around 6:00) for more
details. The trick is that system DLLs are using a hybrid x86/ARM64 library
format, which means x86 code can call those DLLs at native speeds. This means
that many apps run at near-native speed (depending on the ratio of custom code
to system DLL calls). This technique cannot work for emulating the entire
operating system. If Windows 10 on ARM was made available for ARM Macs, running
x86 Windows apps would become feasible.</p>
<p>Rosetta probably uses similar technique. Most apps will be translated at
install time, not at run time. But you can’t do that with an entire OS.</p>
</section>
<section id="whats-next-for-people-who-rely-on-both-macos-and-windows">
<h1>What’s next for people who rely on both macOS and Windows?</h1>
<p>For a few more years, Intel Macs will still be supported by Apple (with new
macOS versions) and by software vendors. But after that? Well, you’re stuck
with two machines, at least until Windows on ARM becomes viable and runnable on
Macs. Or you can start exploring alternatives to macOS software. If you’re one
of the macOS-as-UNIX-with-great-UX developers (hello!), perhaps you’ll have to
switch to Linux — or perhaps Windows with Windows Subsystem for Linux? (The
latter is becoming more usable with every Windows release, so keep an eye on
that… I wrote this post in NeoVim in WSL2, with Windows Terminal supporting
many advanced terminal features, and the transparent filesystem integration
letting me access Windows files directly).</p>
</section>
<section id="post-m1-announcement-update-2020-11-14">
<h1>Post-M1 announcement update (2020-11-14)</h1>
<p>Parallels have confirmed <a class="reference external" href="https://www.parallels.com/blogs/parallels-desktop-apple-silicon-mac/">support for M1 Macs</a> and
are offering a Technical Preview of their M1 virtualization product. This
announcement’s mention of Windows 10 ARM supporting x86_64 apps has caused
some tech writers to assume Parallels will support Windows 10 ARM on M1
Macs. This is <strong>not</strong> what the post says. Parallels is not, and cannot
announce support for that OS, because Windows 10 ARM is (still) available to
ARM OEMs only to install on their devices — making an official announcement
about this feature today would be admitting to doing something illegal/not
allowed by the EULA. I’m pretty sure they are not working on support for
Windows 10 ARM now and in the foreseeable future, until Microsoft opens up
Windows 10 ARM to the public — their own legal issues aside, who would they sell
the Windows support to?</p>
<p>In other news, <a class="reference external" href="https://github.com/docker/for-mac/issues/4733">Docker is not ready yet</a>.</p>
</section>
]]></content:encoded><category>Apple</category><category>Apple</category><category>ARM</category><category>devel</category><category>Mac</category></item><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>Revamping My Projects Page with Nikola</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2014/10/13/revamping-my-projects-page-with-nikola/</link><pubDate>Mon, 13 Oct 2014 12:15:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2014/10/13/revamping-my-projects-page-with-nikola/</guid><description>
A week ago, I was inspired to produce a new projects page for
myself.  The previous one was a trainwreck with a lot of hacks.  Also hosted on
GitHub Pages for some reason.
</description><content:encoded><![CDATA[
<p>A week ago, I was inspired to produce a new <a class="reference external" href="https://chriswarrick.com/projects/">projects page</a> for
myself.  The previous one was a trainwreck with a lot of hacks.  Also hosted on
GitHub Pages for some reason.</p>



<p>So, considering I’m so invested in <a class="reference external" href="https://getnikola.com/">Nikola</a> already,
I produced the <a class="reference external" href="http://plugins.getnikola.com/#projectpages">projectpages plugin</a>
and also made it publicly available.  The plugin produces two files,
<code class="docutils literal">projects/index.html</code> and <code class="docutils literal">projects/projects.json</code>, and also enforces a
specific framework for the stories used for the individual projects, because
all the metadata are taken from special meta fields.</p>
<p>In Nikola, post metadata is completely arbitrary (in fact, that’s my fault; I
<a class="reference external" href="https://github.com/getnikola/nikola/pull/304">contributed the feature</a> back in February 2013).
You can put anything you want, and Nikola will let any plugin and template use the information in any way it likes.</p>
<p>And that is basically the gist of the projectpages plugin.  Using some specific
<a class="reference external" href="https://github.com/getnikola/plugins/tree/master/v7/projectpages#meta-fields">meta fields</a>,
the plugin produces all the files.  It also provides ready-made templates for
the story pages (though the default templates are designed to fit my site
only).</p>
<p>This plugin is basically a special index page generator.  It takes all the
stories in the designated projects directory, looks at the metadata, and
lists them in a nice format (slider of featured projects + a list of everything
else that is not hidden).  Everything automated and done for you, as is always
with Nikola — which values simplicity and ease of use.</p>
<p><strong>The result:</strong> a pretty <strong><a href="https://chriswarrick.com/projects/">projects page</a></strong>.  And some good OSS work done.</p><p>PS. I just underwent a move to <a class="reference external" href="https://www.digitalocean.com/">DigitalOcean</a>
and I love them.  Moreover, this blog is proudly <em>HTTPS only</em> as of yesterday.</p>
]]></content:encoded><category>Python</category><category>devel</category><category>Nikola</category><category>Python</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></channel></rss>