James Cookehttps://jamescooke.info/2024-03-07T00:00:00+00:00Pipx’s upgrade is shallow, let’s go deeper2024-03-07T00:00:00+00:002024-03-07T00:00:00+00:00Jamestag:jamescooke.info,2024-03-07:/pipxs-upgrade-is-shallow-lets-go-deeper.html<p>Software installed in pipx’s managed virtual environments can get
stale. How can we update those packages <em>and</em> their dependencies?</p><p>pipx has been managing my Python tools for almost a year.</p>
<p>But those tools are getting stale - new versions are out - I need to upgrade.</p>
<h2>💪 Let’s upgrade this</h2>
<p>One of my favourite and most used Python tools installed in pipx is
<a href="https://pypi.org/project/frogmouth/">Frogmouth</a>. While working on some
documentation, I think I’ve spotted a bug in some Markdown rendering. So before
I report the bug, let’s ensure I’ve got the latest version.</p>
<p>Upgrading “Is Easy ™️”. Just use <code>pipx upgrade</code>:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>upgrade<span class="w"> </span>frogmouth
</code></pre></div>
<p>We get a spinner, and then:</p>
<div class="highlight"><pre><span></span><code>frogmouth is already at latest version 0.9.2 (location: /home/james/.local/pipx/venvs/frogmouth)
</code></pre></div>
<p>Success! Nothing to do, end of blog post.</p>
<p>…</p>
<h2>🔎 Let’s check</h2>
<p>Frogmouth is using <a href="https://pypi.org/project/textual/">Textual</a> and
<a href="https://pypi.org/project/rich/">rich</a> under the hood - so if I want to make
sure I’ve got the latest Markdown code, I need to ensure they’ve been upgraded too.</p>
<p>Let’s ask <code>pip</code> to tell us all versions of packages in the <code>frogmouth</code> virtual environment:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>runpip<span class="w"> </span>frogmouth<span class="w"> </span>list
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">Package</span><span class="w"> </span><span class="n">Version</span>
<span class="o">------------------</span><span class="w"> </span><span class="o">---------</span>
<span class="n">anyio</span><span class="w"> </span><span class="mf">3.7</span><span class="o">.</span><span class="mi">1</span>
<span class="n">certifi</span><span class="w"> </span><span class="mf">2023.7</span><span class="o">.</span><span class="mi">22</span>
<span class="n">frogmouth</span><span class="w"> </span><span class="mf">0.9</span><span class="o">.</span><span class="mi">2</span><span class="w"> </span><span class="err">👈</span><span class="w"> </span><span class="n">Here</span><span class="s1">'s Frogmouth at the latest version</span>
<span class="n">h11</span><span class="w"> </span><span class="mf">0.14</span><span class="o">.</span><span class="mi">0</span>
<span class="n">httpcore</span><span class="w"> </span><span class="mf">0.17</span><span class="o">.</span><span class="mi">3</span>
<span class="n">httpx</span><span class="w"> </span><span class="mf">0.24</span><span class="o">.</span><span class="mi">1</span>
<span class="n">idna</span><span class="w"> </span><span class="mf">3.4</span>
<span class="n">importlib</span><span class="o">-</span><span class="n">metadata</span><span class="w"> </span><span class="mf">6.8</span><span class="o">.</span><span class="mi">0</span>
<span class="n">linkify</span><span class="o">-</span><span class="n">it</span><span class="o">-</span><span class="n">py</span><span class="w"> </span><span class="mf">2.0</span><span class="o">.</span><span class="mi">2</span>
<span class="n">markdown</span><span class="o">-</span><span class="n">it</span><span class="o">-</span><span class="n">py</span><span class="w"> </span><span class="mf">3.0</span><span class="o">.</span><span class="mi">0</span>
<span class="n">mdit</span><span class="o">-</span><span class="n">py</span><span class="o">-</span><span class="n">plugins</span><span class="w"> </span><span class="mf">0.4</span><span class="o">.</span><span class="mi">0</span>
<span class="n">mdurl</span><span class="w"> </span><span class="mf">0.1</span><span class="o">.</span><span class="mi">2</span>
<span class="n">pip</span><span class="w"> </span><span class="mf">24.0</span>
<span class="n">pkg_resources</span><span class="w"> </span><span class="mf">0.0</span><span class="o">.</span><span class="mi">0</span>
<span class="n">Pygments</span><span class="w"> </span><span class="mf">2.16</span><span class="o">.</span><span class="mi">1</span>
<span class="n">rich</span><span class="w"> </span><span class="mf">13.5</span><span class="o">.</span><span class="mi">2</span><span class="w"> </span><span class="err">👈</span><span class="w"> </span><span class="n">rich</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="mf">13.7</span><span class="o">.</span><span class="mi">1</span><span class="w"> </span><span class="n">on</span><span class="w"> </span><span class="n">PyPI</span>
<span class="n">setuptools</span><span class="w"> </span><span class="mf">69.1</span><span class="o">.</span><span class="mi">1</span>
<span class="n">sniffio</span><span class="w"> </span><span class="mf">1.3</span><span class="o">.</span><span class="mi">0</span>
<span class="n">textual</span><span class="w"> </span><span class="mf">0.43</span><span class="o">.</span><span class="mi">2</span><span class="w"> </span><span class="err">👈</span><span class="w"> </span><span class="n">Textual</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="mf">0.52</span><span class="o">.</span><span class="mi">1</span><span class="w"> </span><span class="n">on</span><span class="w"> </span><span class="n">PyPI</span>
<span class="n">typing_extensions</span><span class="w"> </span><span class="mf">4.7</span><span class="o">.</span><span class="mi">1</span>
<span class="n">uc</span><span class="o">-</span><span class="n">micro</span><span class="o">-</span><span class="n">py</span><span class="w"> </span><span class="mf">1.0</span><span class="o">.</span><span class="mi">2</span>
<span class="n">wheel</span><span class="w"> </span><span class="mf">0.42</span><span class="o">.</span><span class="mi">0</span>
<span class="n">xdg</span><span class="w"> </span><span class="mf">6.0</span><span class="o">.</span><span class="mi">0</span>
<span class="n">zipp</span><span class="w"> </span><span class="mf">3.16</span><span class="o">.</span><span class="mi">2</span>
</code></pre></div>
<p>Uho - rich and Textual didn’t get updated by doing <code>pipx upgrade</code>.</p>
<h2>🤔 This kinda makes sense</h2>
<p>When we have a virtual environment for a project and we run <code>pip upgrade</code>, it
<em>just</em> upgrades the package we request. It only upgrades dependencies if they
conflict with the newly upgraded package. This is called the “only-if-needed”
strategy and is <a href="https://pip.pypa.io/en/stable/user_guide/#only-if-needed-recursive-upgrade">documented in the pip User
Guide</a>.</p>
<p>But, given I’m a <a href="https://pypi.org/project/pip-tools/">pip-tools</a> addict, I
rarely call <code>pip</code> directly. Usually I blow away all of a project’s
requirements, rebuild them with <code>pip-compile</code> and then install all the new
freshness with <code>pip-sync</code>.</p>
<p>How can I get this “everything new” behaviour with <code>pipx</code>? I think there are
two options…</p>
<h2>Option 1: Tell pip to be eager</h2>
<p>Also listed in the pip User Guide is the “eager” option which:</p>
<blockquote>
<p>upgrades all dependencies regardless of whether they still satisfy the new
parent requirements.</p>
</blockquote>
<p>This sounds like what I’m looking for.</p>
<p>And, luckily, <code>pipx upgrade --help</code> shows us just what we need:</p>
<div class="highlight"><pre><span></span><code>--pip-args PIP_ARGS Arbitrary pip arguments to pass directly to pip install/upgrade commands
</code></pre></div>
<p>Let’s try it by passing <code>--upgrade-strategy=eager</code>:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>upgrade<span class="w"> </span>--pip-args<span class="o">=</span>--upgrade-strategy<span class="o">=</span>eager<span class="w"> </span>frogmouth
</code></pre></div>
<p>This, unfortunately, gives very little output regarding the packages being
updated. So let’s check them again with <code>pip list</code> (this time just grepping for
‘rich’ and ‘textual’):</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>runpip<span class="w"> </span>frogmouth<span class="w"> </span>list<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-E<span class="w"> </span><span class="s1">'^rich|^textual'</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>rich 13.7.1 🎉 Yay - upgraded to latest.
textual 0.43.2 😞 boo - not upgraded to latest.
</code></pre></div>
<h3>😬 Textual ain’t gunna upgrade</h3>
<p>After “some” digging, it turns out that Textual isn’t going to upgrade when
installing / upgrading Frogmouth. That’s because Frogmouth has a <a href="https://python-poetry.org/docs/dependency-specification/#caret-requirements">caret
requirement</a>
in <a href="https://github.com/Textualize/frogmouth/blob/main/pyproject.toml#L31">its <code>pyproject.toml</code>
file</a>
which restricts Textual from being upgraded beyond <code>0.43</code>.</p>
<p>I only discovered this after pulling out <code>pip-tools</code> and running a clean
compile of the current Frogmouth requirements and diffing them to the output of
<code>pipx runpip frogmouth list</code>.</p>
<p>Personally, I think this kind of pinning is frustrating, especially in <a href="https://0ver.org/">zero
versioned</a> software. If something breaks I can apply any
pins required to get them to work - I don’t need the upstream maintainer to do
it for me. That just creates slowness and unnecessary confusion.</p>
<p>Anyway - back to the upgrades…</p>
<h2>Option 2: Hit it with a reinstall</h2>
<p>There is <em>another</em> way. That’s to ask pipx to do a reinstallation of the
software. As per <code>pipx reinstall --help</code>:</p>
<blockquote>
<p>Package is uninstalled, then installed with pipx install <span class="caps">PACKAGE</span> with the
same options used in the original install of <span class="caps">PACKAGE</span>.</p>
</blockquote>
<p>Warning: this is a bit of a lie. The <code>--python</code> option is not kept when doing
reinstall. But, this <em>does</em> allow for new versions of Python to be used after reinstalling.</p>
<p>Given that I’m not using the default Python version for pipx installs, I always
have to pass in my preferred Python:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>reinstall<span class="w"> </span>frogmouth<span class="w"> </span>--python<span class="o">=</span>python3.12
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="nx">uninstalled</span><span class="w"> </span><span class="nx">frogmouth</span><span class="p">!</span><span class="w"> </span><span class="err">✨</span><span class="w"> </span><span class="err">🌟</span><span class="w"> </span><span class="err">✨</span>
<span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="kn">package</span><span class="w"> </span><span class="nx">frogmouth</span><span class="w"> </span><span class="m m-Double">0.9.2</span><span class="p">,</span><span class="w"> </span><span class="nx">installed</span><span class="w"> </span><span class="nx">using</span><span class="w"> </span><span class="nx">Python</span><span class="w"> </span><span class="m m-Double">3.12.2</span>
<span class="w"> </span><span class="nx">These</span><span class="w"> </span><span class="nx">apps</span><span class="w"> </span><span class="nx">are</span><span class="w"> </span><span class="nx">now</span><span class="w"> </span><span class="nx">globally</span><span class="w"> </span><span class="nx">available</span>
<span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">frogmouth</span>
<span class="nx">done</span><span class="p">!</span><span class="w"> </span><span class="err">✨</span><span class="w"> </span><span class="err">🌟</span><span class="w"> </span><span class="err">✨</span>
</code></pre></div>
<p>And rich and Textual got to the same versions as before with “eager”:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>runpip<span class="w"> </span>frogmouth<span class="w"> </span>list<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-E<span class="w"> </span><span class="s1">'^rich|^textual'</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>rich 13.7.1
textual 0.43.2
</code></pre></div>
<h2>Which is best?</h2>
<p>My guess is you should use what you think is best for your workflow.</p>
<p>I’m aggressive with my upgrading, so I’m happy with the <code>pipx reinstall</code> route.
This also may give cleaner virtual environments since we shouldn’t get any
hanging dependencies in the scenario that a package stops using a particular dependency.</p>
<p>Also, during my experimentation, I accidentally installed a package off PyPI
called “eager” 🤦. Luckily it didn’t run and the source doesn’t look malicious
to my trusting eye. But it’s this kind of mistake that’s nicely cleaned up
every time the virtual environment is recreated with <code>reinstall</code>. 😅</p>Missing tiny data breaks pipeline2024-02-18T00:00:00+00:002024-02-18T00:00:00+00:00Jamestag:jamescooke.info,2024-02-18:/missing-tiny-data-breaks-pipeline.html<p>At work, when our usage and revenue reporting pipelines fail, they
usually fail because of <em>tiny</em> data.</p><p>This week, during our monthly reporting run, two major label licensing reports
failed validation. This is unexpected because usually all reports are generated
and validate just fine.</p>
<p>It turned out a row of advertising revenue was missed for the United States
Minor Outlying Islands (<span class="caps">UMI</span>).</p>
<p>That missed row was worth just £ 0.0003. 🙀</p>
<h2>👌 This is tiny tiny data</h2>
<p>At work (<a href="https://www.mixcloud.com/">Mixcloud</a>) we generate usage reports for
major labels on a monthly basis. The pipeline:</p>
<blockquote>
<p>identifies, reports and pays royalties out on tens of millions of tracks,
played by millions of Mixcloud creators, and owned by hundreds of thousands
of different artists and songwriters.
<a href="https://blog.mixcloud.com/2021/06/30/why-mixcloud-doesnt-offer-on-demand-video-vods/">Via Mixcloud blog</a></p>
</blockquote>
<p>This missing row was “tiny” by many definitions:</p>
<ul>
<li>It was a tiny territory that I have to <a href="https://en.wikipedia.org/wiki/United_States_Minor_Outlying_Islands">look up on
Wikipedia</a>.
Turns out the population is about 300 people.</li>
<li>It was a tiny amount of revenue that would get rounded out of existence at
payout time. It would literally make zero change to the total payout for the
month to any label.</li>
</ul>
<p>We often use a 0.1 % sense check definition of edge cases when working out what
bugs and issues to put effort against, and by every definition, this missing
row was less than 0.1 % of all sorts of monthly factors.</p>
<h2>🔥 But the pipeline failed</h2>
<p>A long time ago, I realised that we needed to validate the reports generated
<em>before</em> they were sent to partners. So we built a post-process validation
system. This checks the generated reports from the client perspective,
providing row-wise, file-wise and batch-wise validation.</p>
<p>One of these checks ensures that advertising revenue is reported in <span class="caps">GBP</span> £.
However, because we had a missing row for the United States Minor Outlying
Islands (<span class="caps">UMI</span>), the reported advertising-based usage row became <span class="caps">USD</span> $ and failed validation.</p>
<p>Under the hood, this happened because we have a <code>LEFT JOIN</code> between revenue and
usage which wasn’t populated on the revenue side because the <span class="caps">UMI</span> row was missing.</p>
<h2>🛑 When there’s a validation failure, everything stops</h2>
<p>When the generated reports with $ 0 amounts of advertising revenue hit our
validators they fail for the partners whose reports contain enough detail to
see that revenue and currency information. Even though this was just two
partners, when we receive those validation errors in the pipeline, the monthly
production stops.</p>
<p>We keep the generated reports, but work to find out the cause of the error and
assess how many generated reports are tainted.</p>
<h2>🔧 Fix and regenerate</h2>
<p>This time the error was, as discussed, tiny. And the fix was pretty tiny too.
We generated an extra row of revenue for <span class="caps">UMI</span> worth £ 0.0001 and spliced it back
into our monthly source data snapshots.</p>
<p>Then we reran all partners that receive reports on Mixcloud’s ad-funded usage
and our ops colleagues got our monthly production process back up to speed.</p>
<h2>🤔 Is this kind of behaviour a “good” thing?</h2>
<p>After this incident, I’m left wondering if it’s <span class="caps">OK</span> that our pipeline is halted
by a missing row worth less than a penny that wouldn’t affect monthly payouts.</p>
<h3>This is good</h3>
<p>On the “good” side, we could say:</p>
<blockquote>
<p>All the main sources of error are stable, it’s just the tiny edge cases that
are failing.</p>
</blockquote>
<p>In addition, these failures are so rare that we often are surprised when things
fail. Plus, it’s good that we have the validation in place that finds these
kind of errors and reports them.</p>
<h3>This is bad</h3>
<p>On the other hand, we could say:</p>
<blockquote>
<p>The pipelines are so fragile that a tiny missing piece of revenue allocated
to a user in a territory can bring down a monthly reporting run.</p>
</blockquote>
<p>There also seems some truth in this.</p>
<p>Probably the <code>LEFT JOIN</code> in our revenue pipeline that caused the <span class="caps">USD</span> row to
appear is not robust enough. And as we’ve dug more into the error later in the
week, my colleague Tim might have found a scenario that we would never be able
to prevent without strengthening this revenue query’s <span class="caps">SQL</span>.</p>
<h2>⭐ Turn the bad into good</h2>
<p>What I realised is that the failure is a gift in disguise - it’s helped us to
see a flaw in the pipeline that’s so often hidden by aggregation. Instead of
resting on our laurels, we have an opportunity to improve the robustness and
accuracy of our revenue pipeline, plus a new test case to add to our test suite.</p>
<p>As a result of this error, we’re also planning to adjust the source of the
missing row. This is currently a manual monthly process, but we’ve seen that it
might be better incorporated into our pipeline directly, which we think will
give more stability.</p>
<p>So, if you happen to be that Mixcloud user in the United States Minor Outlying
Islands who listened in January - thanks so much. Your unusual pattern of
listening really helped us out. 😊</p>
<hr>
<p>🙏 Thanks to Duncan and Dan for proof reading and suggestions.</p>hledger failure messages are better than Ledger’s2023-08-29T00:00:00+01:002023-08-29T00:00:00+01:00Jamestag:jamescooke.info,2023-08-29:/hledger-failure-messages-are-better-than-ledgers.html<p>About six months ago, I upgraded our family accounts from Ledger to
hledger. The <span class="caps">CLI</span> <span class="caps">API</span> of hledger is better than that of Ledger and the
feedback received when a balance assertion fails is just one example.</p><p>For any new plain text accounting project I always recommend using
<a href="https://hledger.org/">hledger</a> over
<a href="https://ledger-cli.org/index.html">Ledger</a>.</p>
<p>The main reason is errors and failures are better reported and rendered with
hledger, so let’s look at an example - failed balance assertions.</p>
<h2>An erroneous assertion</h2>
<p>Given a journal file with a single transaction, which contains an error:</p>
<div class="highlight"><pre><span></span><code><span class="mf">2023</span><span class="o">/</span><span class="mf">08</span><span class="o">/</span><span class="mf">29</span><span class="w"> </span><span class="n">Some</span><span class="w"> </span><span class="n">person</span>
<span class="w"> </span><span class="n">Assets</span><span class="p">:</span><span class="n">Current</span><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="mf">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="mf">75.73</span>
<span class="w"> </span><span class="n">Income</span>
</code></pre></div>
<p>The error is that the balance of the Current Account is asserted as <code>$ 75.73</code>
after the transaction, when it’s really <code>$ 100</code>.</p>
<h2>Ledger output</h2>
<p>Running Ledger, here’s the version:</p>
<div class="highlight"><pre><span></span><code>ledger<span class="w"> </span>--version
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">Ledger</span><span class="w"> </span><span class="mf">3.1</span><span class="o">.</span><span class="mi">3</span><span class="o">-</span><span class="mi">20190331</span><span class="p">,</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">command</span><span class="o">-</span><span class="n">line</span><span class="w"> </span><span class="n">accounting</span><span class="w"> </span><span class="k">tool</span>
<span class="n">Copyright</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="mi">2003</span><span class="o">-</span><span class="mi">2019</span><span class="p">,</span><span class="w"> </span><span class="n">John</span><span class="w"> </span><span class="n">Wiegley</span><span class="o">.</span><span class="w"> </span><span class="n">All</span><span class="w"> </span><span class="n">rights</span><span class="w"> </span><span class="n">reserved</span><span class="o">.</span>
<span class="n">This</span><span class="w"> </span><span class="n">program</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">made</span><span class="w"> </span><span class="n">available</span><span class="w"> </span><span class="n">under</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">terms</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">BSD</span><span class="w"> </span><span class="n">Public</span><span class="w"> </span><span class="n">License</span><span class="o">.</span>
<span class="n">See</span><span class="w"> </span><span class="n">LICENSE</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">included</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">distribution</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">details</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">disclaimer</span><span class="o">.</span>
</code></pre></div>
<p>Now, let’s ask for a balance - this will check the transaction and complain
about the incorrect balance assertion:</p>
<div class="highlight"><pre><span></span><code>ledger<span class="w"> </span>-f<span class="w"> </span>ledger.dat<span class="w"> </span>bal
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="k">While</span><span class="w"> </span><span class="nv">parsing</span><span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="s2">"/tmp/ledger.dat"</span>,<span class="w"> </span><span class="nv">line</span><span class="w"> </span><span class="mi">2</span>:
<span class="k">While</span><span class="w"> </span><span class="nv">parsing</span><span class="w"> </span><span class="nv">posting</span>:
<span class="w"> </span><span class="nv">Assets</span>:<span class="nv">Current</span><span class="w"> </span>$<span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>$<span class="w"> </span><span class="mi">75</span>.<span class="mi">73</span>
<span class="w"> </span><span class="o">^^^^^^^</span>
<span class="nv">Error</span>:<span class="w"> </span><span class="nv">Balance</span><span class="w"> </span><span class="nv">assertion</span><span class="w"> </span><span class="nv">off</span><span class="w"> </span><span class="nv">by</span><span class="w"> </span>$<span class="w"> </span><span class="o">-</span><span class="mi">24</span>.<span class="mi">27</span><span class="w"> </span><span class="ss">(</span><span class="nv">expected</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">see</span><span class="w"> </span>$<span class="w"> </span><span class="mi">100</span><span class="ss">)</span>
</code></pre></div>
<p>I’ve always found the “off by” amount confusing and find I don’t know if the
asserted balance is too low or high.</p>
<h2>hledger’s failed assertion</h2>
<p>Just confirming my <code>hledger</code> version:</p>
<div class="highlight"><pre><span></span><code>hledger<span class="w"> </span>--version
</code></pre></div>
<div class="highlight"><pre><span></span><code>hledger 1.28, linux-x86_64
</code></pre></div>
<p>Now let’s run the same balance report with hledger:</p>
<div class="highlight"><pre><span></span><code>hledger<span class="w"> </span>-f<span class="w"> </span>ledger.dat<span class="w"> </span>bal
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">hledger</span><span class="o">:</span><span class="w"> </span><span class="n">Error</span><span class="o">:</span><span class="w"> </span><span class="sr">/tmp/</span><span class="n">ledger</span><span class="o">.</span><span class="na">dat</span><span class="o">:</span><span class="mi">2</span><span class="o">:</span><span class="mi">34</span><span class="o">:</span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="mi">2023</span><span class="o">-</span><span class="mi">08</span><span class="o">-</span><span class="mi">29</span><span class="w"> </span><span class="n">Some</span><span class="w"> </span><span class="n">person</span>
<span class="mi">2</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Assets</span><span class="o">:</span><span class="n">Current</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="mi">100</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="mf">75.73</span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="o">^^^^^^^^^</span>
<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Income</span><span class="w"> </span><span class="n">$</span><span class="w"> </span><span class="o">-</span><span class="mi">100</span>
<span class="n">This</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="n">assertion</span><span class="w"> </span><span class="n">failed</span><span class="o">.</span>
<span class="n">In</span><span class="w"> </span><span class="n">account</span><span class="o">:</span><span class="w"> </span><span class="n">Assets</span><span class="o">:</span><span class="n">Current</span>
<span class="n">and</span><span class="w"> </span><span class="n">commodity</span><span class="o">:</span><span class="w"> </span><span class="n">$</span>
<span class="k">this</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="n">was</span><span class="w"> </span><span class="n">asserted</span><span class="o">:</span><span class="w"> </span><span class="mf">75.73</span>
<span class="n">but</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">calculated</span><span class="w"> </span><span class="n">balance</span><span class="w"> </span><span class="k">is</span><span class="o">:</span><span class="w"> </span><span class="mi">100</span>
<span class="n">a</span><span class="w"> </span><span class="n">difference</span><span class="w"> </span><span class="n">of</span><span class="o">:</span><span class="w"> </span><span class="o">-</span><span class="mf">24.27</span>
<span class="n">Consider</span><span class="w"> </span><span class="n">viewing</span><span class="w"> </span><span class="k">this</span><span class="w"> </span><span class="n">account</span><span class="s1">'s calculated balances to troubleshoot. Eg:</span>
<span class="s1">hledger reg '</span><span class="n">Assets</span><span class="o">:</span><span class="n">Current$</span><span class="s1">' cur:'</span><span class="o">\</span><span class="n">$</span><span class="err">'</span><span class="w"> </span><span class="o">-</span><span class="n">I</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="o">-</span><span class="n">f</span><span class="w"> </span><span class="n">FILE</span>
</code></pre></div>
<p>For me, this output is:</p>
<ul>
<li>Much more clear. It helpfully shows the failing transaction in the error message.</li>
<li>Easier to understand: The asserted balance is compared to the computed balance.</li>
</ul>
<h2>Conclusion</h2>
<p>Given that plain text accounting is hard enough to work with at the best of
times, I would always go for a tool that helps me out the most with the
complexity. Right now, that means I’d take hledger over Ledger.</p>An Ode to pipx2023-07-26T21:00:00+01:002023-07-26T21:00:00+01:00Jamestag:jamescooke.info,2023-07-26:/an-ode-to-pipx.html<p>Using pipx has improved my daily development experience considerably.</p><p>Oh pipx, how I love thee… 🎵</p>
<p>Using pipx means I can have Python packages installed and executable on my path
much more easily than in the past. That’s changed my personal <em>and</em> work
development experience for the better. Here’s how…</p>
<h2>Before pipx</h2>
<p>When I wanted to make a Python package (like IPython) available on the command
line in my Linux environment, I would get hacky… Using <code>virtualenv</code> and
boilerplate <code>bash</code> scripts I would manage package installs, and then wrap them
in a script to make them available on my <code>PATH</code>.</p>
<p>As an example, to make IPython runnable on the command line I would:</p>
<ul>
<li>Create an IPython directory in my user’s <code>opt</code> dir: <code>~/opt/ipython</code>.</li>
<li>Build a virtual environment inside it.</li>
<li>Activate the virtual environment and install IPython there with <code>pip</code>.</li>
<li>Add a wrapper executable script called <code>ipython</code> which was then callable on
my shell’s <code>PATH</code>.</li>
</ul>
<p>That script looked like:</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/bash</span>
<span class="nb">set</span><span class="w"> </span>-eo<span class="w"> </span>pipefail
~/opt/ipython/venv/bin/ipython
</code></pre></div>
<blockquote>
<p>A side note about Python environments:
The main reason for using virtual environments for these projects and tools is
to keep my Ubuntu global Python environment clean: Not all Python installed
packages can or should just be thrown in there. Separation is important, and
sometimes required, not least because each package may have conflicting package
requirements and may not be able to be installed together.</p>
</blockquote>
<h3>Disadvantages of these hacks</h3>
<p>There were a growing number of issues with the hacky approach above - not least
the problems with managing the resulting stack of venv and wrappers as the
number of Python tools I wanted on my path grew.</p>
<p>Yes - these could be handled with Ansible (I like to build and manage my
machines with Ansible), but there always seems to be a lag between the time I
“need” a new thing on my command line, and when I manage to get it wired into
Ansible correctly.</p>
<p>Upgrades also became hard - where were all those manually managed tools? Which
ones should I update?</p>
<p>A small, but niggling, disadvantage for using the wrapper script to run local
private tools: I found is that it was hard to keep “development” and
“production” separate. I’d rarely re-create the private code repository so I
could run a version on shell <code>PATH</code> separate from the development directory.
No, instead, the wrapper script would call the development directory directly.
Often when I was trying to do small fixes or improvements, I would accidentally
break my tool, or make it unusable in some way. Annoying when you’re trying to
update some accounts and the bank account parsing tool is crashing because
you’re half way through updating it.</p>
<h2>Switching to pipx</h2>
<p>I installed pipx into the user virtual environment on my Ubuntu machine as
per <a href="https://pypa.github.io/pipx/">the instructions</a>.</p>
<div class="highlight"><pre><span></span><code>python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--user<span class="w"> </span>pipx
</code></pre></div>
<p>Then, installing IPython was as simple as:</p>
<div class="highlight"><pre><span></span><code>pipx<span class="w"> </span>install<span class="w"> </span>ipython
</code></pre></div>
<p>Everything just worked and IPython was installed successfully. pipx even warned
me that there was a previous executable on my path (my previous crappy wrapper script).</p>
<h3>A better dev life</h3>
<p>Now I use pipx to install, manage the virtual environment and expose packages’
endpoints on my shell’s <code>PATH</code>.</p>
<ul>
<li>🙅 Gone are the wrapper scripts and manually built virtual environments.</li>
<li>🙅 Gone are the multiple directories of Python apps, some in <code>~/opt</code> some in
<code>~/active</code> (my usual working path). Along with their Make recipes for
managing virtual environments and upgrades.</li>
<li>🙅 Gone is the need for orchestration scripts and Make recipes to “know” the
particular directory and virtual environment a package is installed in. pipx
can upgrade everything with <code>pipx upgrade-all</code>.</li>
</ul>
<h2>✅ Public packages</h2>
<p>I now install all my favourite, regularly used, public packages with pipx so
they’re available all the time on the command line.</p>
<p>My favourite public packages currently installed are:</p>
<ul>
<li><a href="https://github.com/devpi/devpi">devpi-server</a> to allow Tox to install
packages without having Pip call PyPI.</li>
<li><a href="https://flit.pypa.io/en/stable/">flit</a> for packaging.</li>
<li><a href="https://github.com/Textualize/frogmouth/">frogmouth</a> - my new favourite
Markdown tool.</li>
<li><a href="https://pypi.org/project/hledger-utils/">hledger-utils</a> for helping with our
family accounts.</li>
</ul>
<h2>✅ Personal private packages</h2>
<p>I’ve got baggage - and it lives in private repositories: A suite of personal
tools I’ve built up over the years used for all sorts of tasks, from filing
downloads into correct directories, to managing my work time, to bookkeeping
our family accounts.</p>
<p>With pipx these are now executable from anywhere in my shell, with none of the
previous overhead and boilerplate mentioned above.</p>
<p>These personal private packages are a little harder for me to get into pipx,
but only because I’m lazy - if you’ve done your proper packaging, then you’re
probably already set.</p>
<blockquote>
<p>I’ve got a follow-up post about making your private packages installable with
pipx which I’ll publish soon.</p>
</blockquote>
<h2>Next steps</h2>
<p>Some things I’m not sure about yet.</p>
<h3>Private packages from private repositories</h3>
<p>My current pipx install workflow for private packages depends on having them
cloned to a local directory, and then calling <code>pipx install [path]</code> to install
from there.</p>
<p>I would like it if I could install my private packages directly from their
private GitLab repository without manually cloning first - I’m pretty sure pipx
<em>can</em> do this, I’ve just not hacked around enough with the invocation.</p>
<p>This improvement would mean that I would just use a pipx install of my private
packages, and that means more cleanliness in my development environment - no
need to keep directories around in order to provide runnable Python code any more.</p>
<h3>Managing all this with Ansible</h3>
<p>As I mentioned I usually build and manage my machines with Ansible. I need to
invest some time in catching my Ansible playbooks with my current machine
states and the <a href="https://docs.ansible.com/ansible/latest/collections/community/general/pipx_module.html">Ansible <code>pipx</code>
module</a>
in Ansible galaxy looks particularly helpful.</p>
<h2>🙏 Thanks</h2>
<p>Thanks for reading.</p>
<p>Thanks to <a href="https://pythonbytes.fm/episodes/show/342/dont-believe-those-old-blogging-myths">Brian and Michael’s
coverage</a>
of <a href="https://jvns.ca/blog/2023/06/05/some-blogging-myths/">Julia Evans’s “Some blogging
myths”</a> post… For
“nagging” bloggers that it doesn’t have to be perfect - just write the thing
and put it out there.</p>
<p>Thanks to <a href="https://fosstodon.org/">Fosstodon folks</a> for tooting the new and
interesting things, that, in turn, inspire me to try out these things and get
them working for myself.</p>Pytest’s cache and gitignore2022-12-19T15:00:00+00:002022-12-19T15:00:00+00:00Jamestag:jamescooke.info,2022-12-19:/pytests-cache-and-gitignore.html<p class="first last">Sanity checking Pytest’s <tt class="docutils literal">.gitignore</tt> files.</p>
<p>This post is about sanity checking. It was written at the end of 2019, but not
published until the end of 2022. The underlying change to Pytest’s cache
directories was made in <tt class="docutils literal">3.8.1</tt>, released at the end of 2018.</p>
<div class="section" id="tl-dr">
<h2><span class="caps">TL</span>;<span class="caps">DR</span> 🥱</h2>
<ul class="simple">
<li>You can check any path, real or imaginary, with <tt class="docutils literal">git <span class="pre">check-ignore</span></tt> to see
if Git will ignore it or not.</li>
<li>Pytest prevents its cache directory <tt class="docutils literal">.pytest_cache</tt> from getting into Git
repositories by adding a <tt class="docutils literal">.gitignore</tt> file inside them.</li>
</ul>
</div>
<div class="section" id="the-long-story">
<h2>The (long) story 📜</h2>
<p>While working on a project using Pytest, <tt class="docutils literal">pytest <span class="pre">--lf</span></tt> was not selecting all
possible tests.</p>
<p>The <tt class="docutils literal"><span class="pre">--lf</span></tt> flag tells Pytest to run <a class="reference external" href="https://docs.pytest.org/en/latest/cache.html#rerunning-only-failures-or-failures-first">the tests that failed in the last run</a>
and those test IDs are stored in Pytest’s cache.</p>
<p>To ensure that I started from a clean place, I went to clean out the
<tt class="docutils literal">.pytest_cache</tt> directory. But while I was looking at that directory, I had a
mild panic - I had completely forgotten to add it to project’s <tt class="docutils literal">.gitignore</tt>
file!</p>
<p>Had I accidentally committed the <tt class="docutils literal">.pytest_cache</tt> dir?!</p>
<p>Was this why <tt class="docutils literal">pytest <span class="pre">--lf</span></tt> was being strange?!</p>
<div class="section" id="not-in-git">
<h3>Not in Git</h3>
<p>Firstly, I was able to reassure myself that I’d <em>not</em> accidentally committed
the cache directory: <tt class="docutils literal">git log</tt> can accept a path, so when <tt class="docutils literal">git log <span class="pre">--</span>
.pytest_cache</tt> came back empty, this was reassuring. It was not committed to
the repo!</p>
<p>However, there was no entry for <tt class="docutils literal">.pytest_cache</tt> in <tt class="docutils literal">.gitignore</tt>.</p>
<p>I usually populate the <tt class="docutils literal">.gitignore</tt> for Python projects by lifting the lines
that I want from the <a class="reference external" href="https://github.com/github/gitignore/blob/master/Python.gitignore">Github gitignore repo</a>, but I’d
forgotten to copy over the line for <tt class="docutils literal">.pytest_cache</tt>.</p>
<p>Why is the <tt class="docutils literal">.pytest_cache</tt> directory being ignored by Git if I’ve not written
a pattern for it into <tt class="docutils literal">.gitignore</tt>?</p>
</div>
<div class="section" id="checking-ignored-files">
<h3>Checking ignored files</h3>
<p>My guess was one of the existing patterns in <tt class="docutils literal">.gitignore</tt> might be matching
the <tt class="docutils literal">.pytest_cache</tt> path. To check this I went through deleting lines from
the file until it was empty. But even with an empty ignore file,
<tt class="docutils literal">.pytest_cache</tt> still did not get picked up by Git!</p>
<p>Then I went and found that there is a super-helpful <tt class="docutils literal">git <span class="pre">check-ignore</span></tt>
command. You can read some of the background of this command on <a class="reference external" href="https://stackoverflow.com/a/12168102/1286705">Stack Overflow</a>. This can be used to check
what Git ignore thinks of a path.</p>
<p>So now I can call:</p>
<pre class="literal-block">
git check-ignore -v .pytest_cache/
</pre>
<p>And get back:</p>
<pre class="literal-block">
.pytest_cache/.gitignore:2:* .pytest_cache/
</pre>
<p>This means:</p>
<ul class="simple">
<li>There is a file <tt class="docutils literal"><span class="pre">.pytest_cache/.gitignore</span></tt>.</li>
<li>Line 2 of that file is <tt class="docutils literal">*</tt>.</li>
<li>This rule is being applied to <tt class="docutils literal">.pytest_cache/</tt>.</li>
</ul>
<p>So - Pytest creates its own <tt class="docutils literal">.gitignore</tt> file in the cache to prevent it
being included! Phew, what a journey! 😪</p>
</div>
<div class="section" id="a-bit-more-investigation">
<h3>A bit more investigation</h3>
<p>So now we have an opportunity to learn a little bit about Pytest…</p>
<p>From some searching, I found that the inclusion of a <tt class="docutils literal">.gitignore</tt> file in
Pytest’s cache directories was a feature:</p>
<ul class="simple">
<li>Introduced in <a class="reference external" href="https://github.com/pytest-dev/pytest/pull/3982">Pull #3982: Ignore pytest cache</a>.</li>
<li>To solve <a class="reference external" href="https://github.com/pytest-dev/pytest/issues/3286">Issue #3286: .pytest_cache is showing up in projects git repos</a>.</li>
</ul>
<p>Previously, Pytest had renamed its cache directory from <tt class="docutils literal">.cache</tt> to
<tt class="docutils literal">.pytest_cache</tt>. As a result, on projects where maintainers hadn’t updated
their ignore files, the new cache directories had been committed by accident.</p>
<p>In looking at the Pytest team’s response, what’s interesting to me is the
trade-off between:</p>
<ul class="simple">
<li>Pytest developers do nothing. Let Pytest users update their <tt class="docutils literal">.gitignore</tt>
files or other <span class="caps">SCM</span> ignore methods, or…</li>
<li>Pytest developers take some action. Prevent the folder being added to <span class="caps">SCM</span>
systems or some other fix.</li>
</ul>
<p>In the discussion on the Issue, <a class="reference external" href="https://github.com/pytest-dev/pytest/issues/3286#issuecomment-393142058">this comment</a>
shows the idea of a <tt class="docutils literal"><span class="pre">.pytest_cache/.gitignore</span></tt> file coming into being:</p>
<blockquote>
another devious idea - if we add a <tt class="docutils literal">.gitignore</tt> with the content <tt class="docutils literal">*</tt>
then the folder is protected as well and people dont need to track manually</blockquote>
<p>But all decisions have consequences.</p>
</div>
<div class="section" id="less-might-be-more">
<h3>Less might be more</h3>
<p>For me I would prefer to follow <a class="reference external" href="https://www.python.org/dev/peps/pep-0020/#id3">the Zen of Python</a>:</p>
<blockquote>
Explicit is better than implicit.</blockquote>
<p>I would vote for: Let Pytest users update their ignore mechanisms.</p>
<p>This would mean:</p>
<ul class="simple">
<li>Pytest <span class="caps">SCM</span> users learn that <tt class="docutils literal">.pytest_cache</tt> exists and add it to their
<tt class="docutils literal">.gitignore</tt> or similar.</li>
<li>Confusion is avoided because no directories are unexpectedly ignored by Git.
(Confusion as you can see in my case above and also in <a class="reference external" href="https://github.com/pytest-dev/pytest/issues/4886">this issue</a>.)</li>
<li>Other side effects do not occur, like this ones mentioned in the issue above
regarding Debian packaging or search.</li>
</ul>
<p>To the wider open source issue, I think that projects that do less will last
better than projects that do too much. I would generally take trade-offs where
less is done rather than more.</p>
</div>
</div>
<div class="section" id="reflection-2022">
<h2>Reflection 2022</h2>
<p>Much of this post was written in 2019, much has happened, my confusion has lessened.</p>
<p>If you ask “did the Pytest team do the right thing by adding <tt class="docutils literal">.gitignore</tt> to
the newly named <tt class="docutils literal">.pytest_cache</tt> directories?”, then my answer is <strong>yes</strong>.</p>
<p>It seems to have been a successful strategy and is even <a class="reference external" href="https://github.com/python/mypy/pull/8193">used by mypy</a> with a hat-tip to Ronny
Pfannschmidt’s original comment suggesting the idea.</p>
<p>While editing this post, I found <a class="reference external" href="https://github.com/pytest-dev/pytest/issues/4886#issuecomment-470498105">two</a>
<a class="reference external" href="https://github.com/pytest-dev/pytest/issues/4886#issuecomment-469877128">quotes</a>
from Ronny that I’ll end with:</p>
<blockquote>
<p>we would be more than happy to have a better way (like xdg)</p>
<p>but lets be realistic here - the added .gitignore protects beginner uses
from a very common mistake, that’s why its there</p>
<p>its a practical solution to a practical problem and has a interference component</p>
</blockquote>
<p>…</p>
<blockquote>
from my pov its an absolutely acceptable tradeoff to prevent a lot of
developer pain by inflicting a extra step on package maintainers</blockquote>
<p>Nice one Pytest team for looking after new developers! 🙌</p>
</div>
Migrating Open Source projects on Travis CI to fix GitHub API limit problems2020-04-23T23:00:00+01:002020-04-23T23:00:00+01:00Jamestag:jamescooke.info,2020-04-23:/migrating-open-source-projects-on-travis-ci-to-fix-github-api-limit-problems.html<p class="first last">Open source maintainers can move their projects from travis-ci.org to
travis-ci.com to get more reliable GitHub integration.</p>
<p>Previously I wrote that <a class="reference external" href="/travis-hitting-githubs-api-limits-for-open-source-projects.html">Travis dot org has been exhausting its GitHub <span class="caps">API</span> rate
limit</a>.
Test results for projects built on Travis dot org (travis-ci.org) have not
been reliably reported back to GitHub. This leaves commits on GitHub in a
pending yellow status and pull requests blocked.</p>
<p>The solution is for open source maintainers to migrate their projects from
Travis dot org to Travis dot com (travis-ci.com). This solves the <span class="caps">API</span> rate
limit problem because Travis dot com uses GitHub Apps, whereas Travis dot org
uses a GitHub integration.</p>
<p>With GitHub Apps <a class="reference external" href="https://developer.github.com/apps/differences-between-apps/#token-based-identification">each install of the app gets its own <span class="caps">API</span> quota</a>.
So with the Travis dot com GitHub app installed in your GitHub user or
organisation, the 5,000 requests per hour <span class="caps">API</span> limit applies to just your
install of the app, not globally for all Travis dot com calls to GitHub. As a
small-time open source developer, there are no realistic future scenarios where
my install of the app will reach 5k requests per hour.</p>
<div class="section" id="key-migration-points">
<h2>Key migration points</h2>
<p>The <a class="reference external" href="https://docs.travis-ci.com/user/migrate/open-source-repository-migration/#migrating-a-repository">migration documentation on Travis</a>
is pretty comprehensive, but watch out for these gotchas:</p>
<ul>
<li><p class="first">Make sure you “Sign up for the beta” of migration in <a class="reference external" href="https://travis-ci.org/account/repositories">your Travis dot org
account</a>.</p>
<img alt="Travis "Sign up for beta" call to action" src="https://jamescooke.info/images/200424_travis_sign_up.png" />
<p>Without this your existing repositories will not appear in your new Travis
dot com account.</p>
</li>
<li><p class="first">If you have required checks in the branch protection rules of your GitHub
project repository, these need to be switched over.</p>
<img alt="GitHub branch status checks required" src="https://jamescooke.info/images/200424_branch_status_checks.png" />
<p>You will need to trigger a build on Travis dot com for these new checks to
appear as options.</p>
</li>
<li><p class="first">Remember to change any build badges on your <span class="caps">README</span> from dot org to dot com.</p>
</li>
</ul>
</div>
<div class="section" id="a-trade-off">
<h2>A trade off</h2>
<p>With GitHub apps, results of checks are kept in the Checks Framework. This
means that when you click “details” of a Travis dot com check, you will be
shown GitHub’s page for this check (<a class="reference external" href="https://github.com/jamescooke/flake8-aaa/pull/140/checks?check_run_id=582544560">here’s an example</a>).
Whereas with Travis dot org, clicking on the “details” link for a check took
you straight to Travis dot org.</p>
<p>Here’s how GitHub advertises this benefit:</p>
<img alt="Integrations built with Checks API - Travis CI - Get a complete picture of a project’s health directly from GitHub by viewing your build's stages, jobs, and results, including the config associated with them. You can also re-run builds from within the GitHub interface." src="https://jamescooke.info/images/200424_travis_checks_integration.png" />
<p>Once you migrate your project, Travis will be one click further away. Therefore
you are more likely to stay on GitHub while nursing a pull request or checking
on a build.</p>
<p>While I’m sure many people consider this an improvement, I’m not a fan of the
GitHub checks system. I prefer the old system because:</p>
<ul class="simple">
<li>It was easier and more reliable to visit the external build system’s site. As
we’ve seen with this whole issue, communication across GitHub’s boundary can
be unreliable.</li>
<li>I prefer Travis’s interface for showing build information, not GitHub’s
static checks page.</li>
</ul>
</div>
<div class="section" id="finally">
<h2>Finally</h2>
<p>Thanks to <span class="caps">MK</span> at Travis for the help with migration.</p>
<p>I’m glad that it was possible to find a way to continue to use Travis on my
open source projects.</p>
<p>Happy building!</p>
</div>
Travis hitting GitHub’s API limits for Open Source projects2020-04-02T23:00:00+01:002020-04-02T23:00:00+01:00Jamestag:jamescooke.info,2020-04-02:/travis-hitting-githubs-api-limits-for-open-source-projects.html<p class="first last">GitHub’s <span class="caps">API</span> rate limits are hurting Travis <span class="caps">CI</span>’s service quality.
What does this mean for the future of the GitHub ecosystem?</p>
<!-- -->
<blockquote>
<strong>Note:</strong> A newer post <a class="reference external" href="/migrating-open-source-projects-on-travis-ci-to-fix-github-api-limit-problems.html">Migrating Open Source projects on Travis <span class="caps">CI</span> to fix
GitHub <span class="caps">API</span> limit problems</a>
has information on how to fix the problems described below.</blockquote>
<p>Last week, GitHub’s Dependabot created <a class="reference external" href="https://github.com/jamescooke/flake8-aaa/pull/138">a pull request</a> with a fix to a
vulnerability found in the development dependencies of one of my <span class="caps">FOSS</span> projects.
This was a bump to Mozilla’s <a class="reference external" href="https://github.com/mozilla/bleach">bleach</a>, a
project that GitHub states is used by more than 61,000 other projects.</p>
<a class="reference external image-reference" href="https://github.com/jamescooke/flake8-aaa/pull/138"><img alt="GitHub's Dependabot opened a PR to bump bleach in Flake8-AAA." src="https://jamescooke.info/images/200402_pr.png" /></a>
<p><a class="reference external" href="https://github.com/jamescooke/flake8-aaa">Flake8-<span class="caps">AAA</span>’s repository</a> is wired
into Travis <span class="caps">CI</span> to provide automated execution of its test suites across all
supported versions of Python. Better still, because Flake8-<span class="caps">AAA</span> is an open
source public repository, Travis provides the computing power to run these
tests for free. I’ve always found Travis reliable and stable, so it’s a
requirement that pull requests have a “green” Travis build before merging into
Flake8-<span class="caps">AAA</span>’s master branch.</p>
<div class="section" id="unreported-build-status">
<h2>Unreported build status</h2>
<p>However, when I checked on the Dependabot Pull Request, GitHub was still
waiting for the status of its Travis build to be reported.</p>
<img alt="GitHub's merge dialogue box showing that expected tests have not completed." src="https://jamescooke.info/images/200401_some_checks_havent_completed_yet.png" />
<p>You can see that the “Merge pull request” box is greyed out because the
required Travis build has not completed yet according to GitHub.</p>
<p><strong>But</strong> here’s the build at <a class="reference external" href="https://travis-ci.org/github/jamescooke/flake8-aaa/builds/669024353">Travis</a> - both
green <em>and</em> done within 3 minutes of Dependabot opening the <span class="caps">PR</span> at GitHub, so
the call from Travis to GitHub to report the build status on the commit failed
for some reason.</p>
<img alt="Travis build of the Dependabot PR is green." src="https://jamescooke.info/images/200402_green_build.png" />
</div>
<div class="section" id="debugging">
<h2>Debugging</h2>
<p>Sometimes webhook and <span class="caps">API</span> calls to GitHub fail - I’ve seen this with both
personal and work projects. Often the simplest solution is to retrigger the
build in some way. At first I tried to get a follow up build to work by:</p>
<ul class="simple">
<li>Creating a new commit on the branch with updated requirements and pushing
that to the branch.</li>
<li>Amending the existing commit and pushing with <tt class="docutils literal"><span class="pre">--force</span></tt>.</li>
<li>Creating and pushing a new branch with an update to all requirements.</li>
</ul>
<p>All of these strategies had the same effect - a new build was triggered on
Travis and that build was green, but it was not reported to GitHub. So it
looked like all <span class="caps">API</span> calls were failing from Travis to GitHub.</p>
<p>Next, while checking the <a class="reference external" href="https://www.githubstatus.com/">GitHub status page</a>
and <a class="reference external" href="https://www.traviscistatus.com/">Travis status page</a>, I found this
status update on the Travis site:</p>
<a class="reference external image-reference" href="https://www.traviscistatus.com/incidents/rx6fhs3wqcln"><img alt="Travis status page shows GitHub commit status issue: GitHub status may not be posted on commits occasionally from builds using the legacy Services integration." src="https://jamescooke.info/images/200402_travis_status.png" /></a>
<p>In light of that status message, I tried installing the Travis app integration,
but had no success getting it to link to Flake8-<span class="caps">AAA</span>.</p>
<p>The message says:</p>
<blockquote>
Please write to <a class="reference external" href="mailto:support@travis-ci.com">support@travis-ci.com</a> if you encounter any similar
problems.</blockquote>
<p>So I emailed.</p>
</div>
<div class="section" id="reply-from-travis-support">
<h2>Reply from Travis Support</h2>
<p>Here’s the full text of the reply from Travis support:</p>
<blockquote>
<p><span class="caps">MK</span> (Travis <span class="caps">CI</span>)</p>
<p>Mar 31, 15:38 <span class="caps">EDT</span></p>
<p>Hello ,</p>
<p>Thanks for your patience on this issue.</p>
<p>We want to provide some visibility into the issues we are facing, the
effects on our infrastructure and efforts made so far to restore normalcy.</p>
<ol class="arabic simple">
<li>We recently started hitting <span class="caps">API</span> rate limits for Github calls and on
March 25, 2020, we contacted Github to ask for increases and are
awaiting their feedback in this regard.</li>
<li>On the Travis <span class="caps">CI</span> end, we have made improvements on how our code accesses
the Github <span class="caps">API</span>, which has led to improvements, albeit minimal.</li>
<li>While we occasionally hit <span class="caps">API</span> limits, it’s important to note that we
haven’t hit these kinds of limits before now. In the interim, the
best course of action would be to retry the action you wanted to perform.</li>
</ol>
<p>For next steps,</p>
<ol class="arabic simple">
<li>We are following up with Github via various channels to get the
requested <span class="caps">API</span> rate limit increased.</li>
<li>In addition, we are looking for more avenues to remove
invalid/unnecessary Github <span class="caps">API</span> calls in our codebase to ensure we stay
under the limit and avoid disruptions like this.</li>
<li>We are coordinating internally to ensure customers are up-to-date on
progress made so far.</li>
</ol>
<p>We know how critical our platform is to your business and our goal is to
provide the best experience for our customers. In line with this, we extend
our sincere apologies for inconveniences this is causing.</p>
<p>Thank you and we will provide periodic updates as we have more.</p>
</blockquote>
<p>Firstly, thanks to Travis support for this helpful message - it’s pretty
unusual for a service that offers a free tier to be open and responsive to
messages from freeloading users like myself.</p>
<p>Secondly, I assumed that Travis would not be opposed to publishing the text of
the email since it should help other developers in my situation.</p>
<p>In response to the mail itself:</p>
<ul>
<li><p class="first">My understanding is that this issue mainly affects open source projects on
Travis dot org.</p>
</li>
<li><p class="first">This message makes no mention of migrating to the Travis dot com GitHub Apps
integration, so I assume that it wouldn’t work for Flake8-<span class="caps">AAA</span> or other open
source projects.</p>
</li>
<li><p class="first">The mail states:</p>
<blockquote>
<p>In the interim, the best course of action would be to retry the action
you wanted to perform.</p>
</blockquote>
<p>Unfortunately I’ve had no success with this yet, but will continue to try.</p>
</li>
</ul>
<!-- -->
<blockquote>
<strong>Update:</strong> Since writing this post I have successfully migrated projects
to Travis dot com. My <a class="reference external" href="/migrating-open-source-projects-on-travis-ci-to-fix-github-api-limit-problems.html">next post</a>
has a list of items to remember when migrating.</blockquote>
<p>Although I’m happy with the Travis response so far, I’m worried about what this
means about the future of GitHub.</p>
</div>
<div class="section" id="thoughts-on-the-github-ecosystem">
<h2>Thoughts on the GitHub ecosystem</h2>
<p>I was not part of the “mass exodus” from GitHub in 2018 after <a class="reference external" href="https://github.blog/2018-10-26-github-and-microsoft/">Microsoft
completed its purchase</a> of the platform. At
the time I thought that this could only be good for the site, however, now I’m
reconsidering, especially in the light of the situation above. Let me explain why…</p>
<div class="section" id="github-wants-actions-to-replace-travis">
<h3>GitHub wants Actions to replace Travis</h3>
<p><a class="reference external" href="https://github.com/features/actions">GitHub Actions</a> is what GitHub calls
its “world-class <span class="caps">CI</span>/<span class="caps">CD</span>” system. <span class="caps">CI</span>/<span class="caps">CD</span> has been supported by Actions since
August 2019 and is free for open source projects - GitHub has “embraced” <span class="caps">CI</span>/<span class="caps">CD</span>.</p>
<p>Travis dot org is now a <strong>competitor</strong> to GitHub rather than the helpful
addition to the ecosystem it was before.</p>
<p>Also the existence of <span class="caps">CI</span>/<span class="caps">CD</span> in Actions means that GitHub can allow the
degradation of other <span class="caps">CI</span>/<span class="caps">CD</span> integrations because it’s able to offer a “better”
replacement - use Actions instead. My guess would be that GitHub intends
Actions to replace all <span class="caps">CI</span>/<span class="caps">CD</span> building on GitHub for open source projects.</p>
</div>
<div class="section" id="github-wants-developers-to-stay-on-github">
<h3>GitHub wants developers to stay on GitHub</h3>
<p>In the final paragraph of the <a class="reference external" href="https://github.blog/2018-10-26-github-and-microsoft/">GitHub blog post above</a>, Nat Friedman states:</p>
<blockquote>
Our vision is to serve every developer on the planet, by being the best
place to build software.</blockquote>
<p>Building software includes <span class="caps">CI</span>/<span class="caps">CD</span> and GitHub’s vision means that every developer
that needs a <span class="caps">CI</span>/<span class="caps">CD</span> function would stay on GitHub while “building software”, not
traverse external systems like Travis, Circle <span class="caps">CI</span> or Codeship.</p>
</div>
<div class="section" id="github-can-make-it-harder-for-ci-cd-integrations-to-keep-up">
<h3>GitHub can make it harder for <span class="caps">CI</span>/<span class="caps">CD</span> integrations to keep up</h3>
<p>Since GitHub (and therefore Microsoft) <a class="reference external" href="https://dependabot.com/blog/hello-github/">acquired Dependabot in 2019</a>, GitHub now has a tool which it
can use to generate a larger number of builds on <span class="caps">CI</span>/<span class="caps">CD</span> services integrated with
its platform like Travis. This will have the knock-on effect of making it
harder for those <span class="caps">CI</span>/<span class="caps">CD</span> services to keep within their <span class="caps">API</span> rate limits and more
expensive to run because they will need to buy more computing power from <span class="caps">AWS</span>
and/or Google to run builds.</p>
<p>Best of all for GitHub, they can put this pressure on others while maintaining
the guise of <a class="reference external" href="https://github.blog/2019-05-23-introducing-new-ways-to-keep-your-code-secure/#automated-security-fixes-with-dependabot">making “dependency upgrades easy”</a>.
Now GitHub automatically creates a pull request for any project owned by an
account with security alerts enabled when it finds a relevant security
vulnerability alert.</p>
<p>In the case of the pull request above that started this post, that was a
vulnerability in bleach. As I mentioned this is a project used by over 60k
projects on GitHub. So when a security advisory on bleach occurs, Dependabot
creates a pull request on GitHub, each pull request will then be built by a
<span class="caps">CI</span>/<span class="caps">CD</span> system for those repositories that have one wired in. For an external
<span class="caps">CI</span>/<span class="caps">CD</span> system like Travis, that flood of builds requires a large volume of
computing resources <strong>and</strong> GitHub <span class="caps">API</span> calls.</p>
<p>The <a class="reference external" href="https://developer.github.com/v3/#rate-limiting">GitHub rate limit documentation</a> currently states a quota of
5,000 requests per hour. If each <span class="caps">CI</span>/<span class="caps">CD</span> build requires 2 <span class="caps">API</span> calls (one to say
“in progress” and one to post the result), then once 2,500 builds are completed
in an hour the quota will be exhausted. If 4% of all the repositories that
depend on bleach are using Travis for builds, then a single bump to the bleach
release would exhaust a 5,000 request quota immediately - and that’s before any
“normal” human-driven regular build activity is taken into consideration.</p>
<p>Now I’m pretty sure that Travis has an hourly quota that’s greater than 5,000
requests per hour, probably granted to them when GitHub saw them as augmenting
the GitHub ecosystem, but when the Travis email above stated:</p>
<blockquote>
We are following up with Github via various channels to get the requested
<span class="caps">API</span> rate limit increased.</blockquote>
<p>… why would GitHub bump this now?</p>
<p>Instead, GitHub can leave Travis in an awkward situation: choose to throttle
builds and get reliable status calls back to the GitHub <span class="caps">API</span>, or make open
source projects have a less reliable and smooth experience when status update
<span class="caps">API</span> calls are dropped. Either option makes GitHub Actions look “better” as a
<span class="caps">CI</span>/<span class="caps">CD</span> solution - a win for GitHub.</p>
</div>
</div>
<div class="section" id="finally-hope">
<h2>Finally, hope</h2>
<p>I hope that my thoughts on the GitHub ecosystem above are overly negative and
that these issues with Travis are not the start of an “extinguish” strategy by
GitHub towards external <span class="caps">CI</span>/<span class="caps">CD</span> systems (see <a class="reference external" href="https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish">Embrace, extend, extinguish</a>).</p>
<p>I hope I’m completely wrong and that GitHub open up their <span class="caps">API</span> limits to Travis
so that open source projects like Flake8-<span class="caps">AAA</span> can still use it for reliable
<span class="caps">CI</span>/<span class="caps">CD</span>. But if things don’t go well then I’m certainly more ready to join the
GitHub exodus, just 18 months behind the curve.</p>
<p>Thanks Travis <span class="caps">CI</span> for all the builds, I hope we have many more to come!</p>
</div>
It’s good to extract2018-04-21T19:00:00+01:002018-04-21T19:00:00+01:00Jamestag:jamescooke.info,2018-04-21:/its-good-to-extract.html<p class="first last">Thoughts on the benefits of extracting library code from Python
projects into their own packages.</p>
<p>Last week we released version 1 of <a class="reference external" href="https://pypi.org/project/pysyncgateway/">pysyncgateway</a> - a Python package for
communicating with <a class="reference external" href="https://github.com/couchbase/sync_gateway">Couchbase’s Sync Gateway</a> via its <span class="caps">REST</span> <span class="caps">API</span>.</p>
<p>But this “new” library was not created from scratch. It consists mainly of code
extracted from my employer’s Django based <span class="caps">API</span> server repository. That <span class="caps">API</span> is
now around 4,000 lines of code and test smaller and installs <tt class="docutils literal">pysyncgateway</tt>
as a package during deployment.</p>
<p>Both the process of extraction and the final result have been been really
helpful - this post covers some of the benefits that we have found so far.</p>
<div class="section" id="better-separation-of-concerns">
<h2>Better separation of concerns</h2>
<p>The boundary between the new library and the server code makes it much easier
to reason about where responsibilities start and end.</p>
<p>Originally the Sync Gateway communication code was tightly knitted with our
Django <span class="caps">API</span> server:</p>
<ul class="simple">
<li>It used Django settings for establishing URLs of the Sync Gateway instance in
test and production.</li>
<li>It provided test cases to our server’s old <tt class="docutils literal">Unittest</tt> test suite, Those
test cases created test Databases, Users and Documents on the Sync Gateway
for each test - tearing them down afterwards.</li>
<li>It manipulated the statistical data retrieved from Sync Gateway and posted it
to our <tt class="docutils literal">statsd</tt> instance. Again Django’s settings were used for configuration.</li>
</ul>
<p>In extracting the library, these responsibilities have been cleaned out and clarified:</p>
<ul class="simple">
<li>Communication with Sync Gateway’s <span class="caps">API</span> from Python - Responsibility of
<tt class="docutils literal">pysyncgateway</tt> library. All calls made to Sync Gateway are the
responsibility of the library.</li>
<li>Testing and mitigating any strange behaviours of the Sync Gateway <span class="caps">API</span> -
Responsibility of <tt class="docutils literal">pysyncgateway</tt>. The library’s code is the place to pin
and mitigate any strange behaviours that are found.</li>
<li>Integration of Sync Gateway’s objects (User, Document, Database) into
the <span class="caps">API</span> server and Django - Responsibility of <span class="caps">API</span> server code. The server
code remains responsible for managing its own tests conditions.</li>
<li>Synchronisation of Django’s User object with Sync Gateway’s User objects -
Responsibility of <span class="caps">API</span> server. The library is oblivious to the application that is
using it - in the same way that the <a class="reference external" href="http://docs.python-requests.org/en/master/">requests libary</a> is oblivious to the fact that is
it being used by <tt class="docutils literal">pysyncgateway</tt> to communicate with Sync Gateway.</li>
</ul>
</div>
<div class="section" id="improved-efficiency-of-development-and-test">
<h2>Improved efficiency of development and test</h2>
<p>While working on the library code, I’ve found that testing has been much more efficient.</p>
<p>In terms of time, a single test run as part of a build on <a class="reference external" href="https://circleci.com/gh/constructpm/pysyncgateway/tree/master">Circle <span class="caps">CI</span></a> takes around
10s whereas in our <span class="caps">API</span> server test suite it was taking 40s and was mixed in
with a much longer (~20 minute) long test suite.</p>
<p>The dedicated library repository now means that when I’ve had questions
about how Sync Gateway behaves in certain situations, then the library is
the place to explore that behaviour and ensure that the library code is
fulfilling its main responsibility - communicating as best it can with any Sync
Gateway instance.</p>
</div>
<div class="section" id="document-all-the-things">
<h2>Document all the things</h2>
<p>The documentation built by <a class="reference external" href="http://www.sphinx-doc.org/en/master/">sphinx</a> and
hosted on <a class="reference external" href="https://pysyncgateway.readthedocs.io/en/stable/">Read The Docs</a> is
great. I’ve found it much better than reading docs via a code editor or
<tt class="docutils literal">ipython</tt> and end up using the <span class="caps">RTD</span> site as the main point of reference.</p>
<p>Luckily many of the docstrings were in place in much of the code before the
extraction, but moving they were mixed in with <span class="caps">API</span> project specific information
that could not be published. Again, the clarity of responsibilities meant that
we could clean up much of the docs to make them ready to be published.</p>
</div>
<div class="section" id="still-a-monolith-but-with-packaging-benefits">
<h2>Still a monolith, but with packaging benefits</h2>
<p>Our server code remains a single monolith - it’s one installed blob of code on
one server. The Sync Gateway code was extracted into a library, not a service.</p>
<p>However, now that the Sync Gateway code is installed from PyPi via
<tt class="docutils literal"><span class="pre">pip-sync</span></tt>, this provides the additional abstraction that we can select the
version of the library that will be installed.</p>
<p>This means we will have more flexibility to improve the library to work with
the latest version of Sync Gateway 2 (it’s currently only tested with 1.5) and
also Python 3. We can upgrade the library, make breaking changes if required
and bump versions without touching the server monolith at all.</p>
</div>
<div class="section" id="finally">
<h2>Finally</h2>
<p>The extraction of <tt class="docutils literal">pysyncgateway</tt> has worked out well for us and so I’m
preparing to extract our next library - a simple object orientated layer that
we use to communicate with Nextcloud.</p>
<p>There will be quite a bit of time invested to extract the code, but my
expectation is that the test benefits will be great. Not only will we get to
remove library code that takes around 6 minutes to test, but also we will gain
the library’s test suite as a dedicated area to test the nuanced edge cases of
Nextcloud’s <span class="caps">API</span>.</p>
<p>Happy code extraction!</p>
</div>
AAA Part 2: Extracting Arrange code to make fixtures2017-08-07T00:00:00+01:002017-08-07T00:00:00+01:00Jamestag:jamescooke.info,2017-08-07:/aaa-part-2-extracting-arrange-code-to-make-fixtures.html<p class="first last">This post explores how to extract arrangement code when working with
the Arrange Act Assert pattern so that it can be used with certainty
across the test suite.</p>
<p>In this post I will describe how code in tests’ Arrange blocks can become
over-complicated, break the <span class="caps">AAA</span> pattern and benefit from extraction.</p>
<div class="section" id="background">
<h2>Background</h2>
<ul class="simple">
<li>This post is Part 2 of a series on the Arrange Act Assert pattern for Python
developers. See <a class="reference external" href="/arrange-act-assert-pattern-for-python-developers.html">Part 1</a> for an
introduction to the pattern and outline of its constituent parts.</li>
<li>When I mention “code extraction” I’m primarily referring to the Extract
Method <a class="footnote-reference" href="#em" id="footnote-reference-1">[1]</a> of refactoring. <a class="reference external" href="https://www.goodreads.com/book/show/387190.Test_Driven_Development">Kent Beck’s book “Test Driven Development: By
Example”</a> really
turned me on to the value in eliminating duplicated code between tests and
between tests and the <span class="caps">SUT</span> <a class="footnote-reference" href="#sut" id="footnote-reference-2">[2]</a>.</li>
<li>I’m using <a class="reference external" href="https://docs.pytest.org/en/latest/">pytest</a> in this example
which means that fixtures are marked with the <tt class="docutils literal">@pytest.fixture</tt> decorator.
If you’re using <tt class="docutils literal">unittest</tt> then you could extract the set up code into the
<tt class="docutils literal">TestCase.setUp</tt> method.</li>
<li>If you can, perform Extract Method while your test suite is <span class="caps">GREEN</span> <a class="footnote-reference" href="#green" id="footnote-reference-3">[3]</a>.
This means that you can be more assured that your refactoring has worked
without errors.</li>
<li>During my work I often build permission systems that manage access to
resources such as files, accounts, projects, etc, based on the connection
between Users and those resources. The example test below is from one of
those projects. I often use Simpsons and Futurama characters in tests because
I think it makes it easier to visualise the test conditions when characters
are used that other programmers may be familiar with already.</li>
</ul>
</div>
<div class="section" id="the-problem">
<h2>The problem</h2>
<p>I’ve found that this problem, which I call “Complicated Setup”, occurs as a test suite grows and
the complexity of the tests on the outside of the code increases.</p>
<p>Tests will often need to combine a number of objects in increasingly complex
states to build the <span class="caps">SUT</span> <a class="footnote-reference" href="#sut" id="footnote-reference-4">[2]</a>. As a result, additional assertions are
required before the Act block to ensure that the test conditions are correctly
established. The problem with these additional assertions is that
they break the <span class="caps">AAA</span> pattern because there should be no assertions in the Arrange block.</p>
<div class="highlight"><pre><span></span><span class="c1"># Warning - this test does *not* fit the AAA pattern because it has</span>
<span class="c1"># assertions in the Arrange block.</span>
<span class="k">def</span> <span class="nf">test_owner_invite_admin</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Leela can invite Bender to an additional Project, Fry is notified</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> Account Role | Project Role | Name</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> Owner | - | Leela</span>
<span class="sd"> Admin | - | Fry</span>
<span class="sd"> Viewer | Admin | Bender</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> """</span>
<span class="c1"># LEELA (and account)</span>
<span class="n">account</span> <span class="o">=</span> <span class="n">AccountFactory</span><span class="p">(</span><span class="n">owner__first_name</span><span class="o">=</span><span class="s1">'Leela'</span><span class="p">)</span>
<span class="n">account_document</span> <span class="o">=</span> <span class="n">AccountDocument</span><span class="p">(</span><span class="n">account</span><span class="p">,</span> <span class="n">default_database</span><span class="p">)</span>
<span class="n">account_document</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">()</span>
<span class="n">leela</span> <span class="o">=</span> <span class="n">account</span><span class="o">.</span><span class="n">owner</span>
<span class="n">new_project</span> <span class="o">=</span> <span class="n">leela</span><span class="o">.</span><span class="n">create_project</span><span class="p">(</span><span class="s1">'new_project'</span><span class="p">)</span>
<span class="c1"># FRY</span>
<span class="n">admin_membership</span> <span class="o">=</span> <span class="n">AccountMembershipFactory</span><span class="p">(</span>
<span class="n">account</span><span class="o">=</span><span class="n">account</span><span class="p">,</span>
<span class="n">permission</span><span class="o">=</span><span class="s1">'AA'</span><span class="p">,</span>
<span class="n">person__first_name</span><span class="o">=</span><span class="s1">'Fry'</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">fry</span> <span class="o">=</span> <span class="n">admin_membership</span><span class="o">.</span><span class="n">person</span>
<span class="c1"># BENDER</span>
<span class="n">project_data</span> <span class="o">=</span> <span class="n">ProjectMembershipFactory</span><span class="p">(</span>
<span class="n">account</span><span class="o">=</span><span class="n">account</span><span class="p">,</span>
<span class="n">person__first_name</span><span class="o">=</span><span class="s1">'Bender'</span><span class="p">,</span>
<span class="n">role</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">project_couchbase</span> <span class="o">=</span> <span class="n">project_data</span><span class="p">[</span><span class="s1">'project'</span><span class="p">]</span>
<span class="n">bender</span> <span class="o">=</span> <span class="n">project_data</span><span class="p">[</span><span class="s1">'person'</span><span class="p">]</span>
<span class="c1"># Check</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">bender</span><span class="o">.</span><span class="n">accounts</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="c1"># <</span>
<span class="k">assert</span> <span class="n">bender</span><span class="o">.</span><span class="n">accounts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">owner</span> <span class="o">==</span> <span class="n">leela</span> <span class="c1"># < Assertions in Arrange</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">bender</span><span class="o">.</span><span class="n">projects</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="c1"># <</span>
<span class="k">assert</span> <span class="n">bender</span><span class="o">.</span><span class="n">projects</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">new_project</span> <span class="c1"># <</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">fry</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="c1"># <</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">leela</span><span class="o">.</span><span class="n">new_project</span><span class="o">.</span><span class="n">invite</span><span class="p">(</span><span class="n">bender</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">True</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">fry</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
</pre></div>
<p>Tests on the arrangement of the <span class="caps">SUT</span> will often be informed by the tests that are about
to be carried out on it in the Act. Here I want to ensure that Fry is notified with a new
message so it is important that after Arrange Fry has no messages waiting.
But adding these assertions before the Act section means
breaking <span class="caps">AAA</span> and this is a smell the test has grown too complex and should be cut down.</p>
<p>It is possible to use Extract Method to create a fixture that solves this issue
and returns the test to pure <span class="caps">AAA</span> pattern. I’ve used a simplified example to
illustrate how to solve this below. I’ve imagined a <tt class="docutils literal"><span class="caps">SUT</span></tt> class that must be
called with some arrangement functions like <tt class="docutils literal">arrange_a</tt>, <tt class="docutils literal">arrange_b</tt>, etc.</p>
<script async class="speakerdeck-embed" data-id="da526efe5fb6445eadb71b7f4b66c2f5" data-ratio="1.82857142857143" src="//speakerdeck.com/assets/embed.js"></script><p>If the example does not load for you, you can <a class="reference external" href="https://speakerdeck.com/jamescooke/extract-arrangement-code">view it on speakerdeck</a>.</p>
<p>Now applying this process to the Futurama account test above I get the
following fixture with its own dedicated test and a much simpler test for the
invite behaviour.</p>
<div class="highlight"><pre><span></span><span class="nd">@pytest</span><span class="o">.</span><span class="n">fixture</span>
<span class="k">def</span> <span class="nf">account_members</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple:</span>
<span class="sd"> User: Leela - Account owner.</span>
<span class="sd"> User: Fry - Admin.</span>
<span class="sd"> User: Bender - Project admin.</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> Account Role | Project Role | Name</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> Owner | - | Leela</span>
<span class="sd"> Admin | - | Fry</span>
<span class="sd"> Viewer | Admin | Bender</span>
<span class="sd"> ----------------+---------------+-----------</span>
<span class="sd"> """</span>
<span class="c1"># LEELA (and account)</span>
<span class="n">account</span> <span class="o">=</span> <span class="n">AccountFactory</span><span class="p">(</span><span class="n">owner__first_name</span><span class="o">=</span><span class="s1">'Leela'</span><span class="p">)</span>
<span class="n">account_document</span> <span class="o">=</span> <span class="n">AccountDocument</span><span class="p">(</span><span class="n">account</span><span class="p">,</span> <span class="n">default_database</span><span class="p">)</span>
<span class="n">account_document</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">()</span>
<span class="n">leela</span> <span class="o">=</span> <span class="n">account</span><span class="o">.</span><span class="n">owner</span>
<span class="n">new_project</span> <span class="o">=</span> <span class="n">leela</span><span class="o">.</span><span class="n">create_project</span><span class="p">(</span><span class="s1">'new_project'</span><span class="p">)</span>
<span class="c1"># FRY</span>
<span class="n">admin_membership</span> <span class="o">=</span> <span class="n">AccountMembershipFactory</span><span class="p">(</span>
<span class="n">account</span><span class="o">=</span><span class="n">account</span><span class="p">,</span>
<span class="n">permission</span><span class="o">=</span><span class="s1">'AA'</span><span class="p">,</span>
<span class="n">person__first_name</span><span class="o">=</span><span class="s1">'Fry'</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">fry</span> <span class="o">=</span> <span class="n">admin_membership</span><span class="o">.</span><span class="n">person</span>
<span class="c1"># BENDER</span>
<span class="n">project_data</span> <span class="o">=</span> <span class="n">ProjectMembershipFactory</span><span class="p">(</span>
<span class="n">account</span><span class="o">=</span><span class="n">account</span><span class="p">,</span>
<span class="n">person__first_name</span><span class="o">=</span><span class="s1">'Bender'</span><span class="p">,</span>
<span class="n">role</span><span class="o">=</span><span class="s1">'admin'</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">project_couchbase</span> <span class="o">=</span> <span class="n">project_data</span><span class="p">[</span><span class="s1">'project'</span><span class="p">]</span>
<span class="n">bender</span> <span class="o">=</span> <span class="n">project_data</span><span class="p">[</span><span class="s1">'person'</span><span class="p">]</span>
<span class="k">return</span> <span class="n">leela</span><span class="p">,</span> <span class="n">fry</span><span class="p">,</span> <span class="n">bender</span>
<span class="k">def</span> <span class="nf">test_account_members</span><span class="p">(</span><span class="n">account_members</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Fry has no pending messages and Bender is a member of the Account</span>
<span class="sd"> """</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">account_members</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span>
<span class="n">leela</span><span class="p">,</span> <span class="n">fry</span><span class="p">,</span> <span class="n">bender</span> <span class="o">=</span> <span class="n">result</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">bender</span><span class="o">.</span><span class="n">accounts</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
<span class="k">assert</span> <span class="n">bender</span><span class="o">.</span><span class="n">accounts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">owner</span> <span class="o">==</span> <span class="n">leela</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">bender</span><span class="o">.</span><span class="n">projects</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
<span class="k">assert</span> <span class="n">bender</span><span class="o">.</span><span class="n">projects</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">new_project</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">fry</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">test_owner_invite_admin</span><span class="p">(</span><span class="n">account_members</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Leela can invite Bender to an additional Project, Fry is notified</span>
<span class="sd"> """</span>
<span class="n">leela</span><span class="p">,</span> <span class="n">fry</span><span class="p">,</span> <span class="n">bender</span> <span class="o">=</span> <span class="n">account_members</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">leela</span><span class="o">.</span><span class="n">new_project</span><span class="o">.</span><span class="n">invite</span><span class="p">(</span><span class="n">bender</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">True</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">fry</span><span class="o">.</span><span class="n">messages</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
</pre></div>
<p>Even though this example is long winded, I hope you can see that the
extraction of the set up code into its own fixture has simplified the tests and
brought the code back into conformity with the <span class="caps">AAA</span> pattern.</p>
</div>
<div class="section" id="benefits-of-extraction">
<h2>Benefits of extraction</h2>
<p>The result of the extraction process is a pair of tests with a single fixture. The tests
fit the <span class="caps">AAA</span> pattern that I advocated in Part 1 of this series and the resulting
code’s structure has a number of advantages for the future of the test suite:</p>
<ul>
<li><p class="first">Continued development on the fixture can happen using <span class="caps">TDD</span> <a class="footnote-reference" href="#tdd" id="footnote-reference-5">[4]</a> by adding
new requirements to <tt class="docutils literal">test_fixture()</tt> and then expanding the fixture to get
back to <span class="caps">GREEN</span>.</p>
</li>
<li><p class="first">The resulting fixture can be reused really easily. Permutations of different
actions on a particular <span class="caps">SUT</span> can be easily tested without having to depend on
our power of copy and paste and without creating more duplicated code.</p>
</li>
<li><p class="first">If a situation arises in the future where the arrangement of the <span class="caps">SUT</span> needs to
change in the fixture all the tests that use it <em>might</em> fail. However, the
payoff for the additional failure of the fixture’s dedicated tests is that
there is the opportunity to fix the problem in one place - the extracted code
in the fixture.</p>
<p>On top of that, the fix can be performed using <span class="caps">TDD</span> because the fixture is
already extracted and under test - a potential double win.</p>
</li>
</ul>
<p>In this way the test suite remains dynamic, clear and able to adapt with the
software it’s testing.</p>
</div>
<div class="section" id="should-all-fixtures-have-their-own-tests">
<h2>Should all fixtures have their own tests?</h2>
<p>I’m often asked whether I think test fixtures should be tested. My answer is:
“It depends”.</p>
<p>When the fixture was arrived at via “Complicated setup” then my answer is
“yes”. As we’ve seen, the <tt class="docutils literal">test_fixture()</tt> test remains to pin the fixture’s
behaviour and assert that the <span class="caps">SUT</span> is in the expected state.</p>
<p>When the fixture has been extracted because of “Setup duplication” <a class="footnote-reference" href="#sd" id="footnote-reference-6">[5]</a> there will
be a fixture created that does not have its own explicit test. Instead, the
fixture is tested implicitly by the two tests but does not have a dedicated
test of its own.</p>
<p>For me this is an “<span class="caps">OK</span>” situation and if it turns out that the fixture should be
adjusted then a fixture test can be created to facilitate that change under the
usual <span class="caps">RED</span>, <span class="caps">GREEN</span>, <span class="caps">REFACTOR</span> cycle.</p>
</div>
<div class="section" id="flake8-aaa">
<h2>flake8-aaa</h2>
<p>Check out <a class="reference external" href="https://flake8-aaa.readthedocs.io/en/stable/">flake8-aaa</a> - a
Flake8 plugin that makes it easier to write tests that follow the Arrange Act
Assert pattern.</p>
<p>Happy testing!</p>
</div>
<div class="section" id="tiny-glossary">
<h2>Tiny glossary</h2>
<table class="docutils footnote" frame="void" id="em" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td>Extract Method is a refactoring step <a class="reference external" href="https://refactoring.com/catalog/extractMethod.html">defined here</a>.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="sut" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label">[2]</td><td><em>(<a class="fn-backref" href="#footnote-reference-2">1</a>, <a class="fn-backref" href="#footnote-reference-4">2</a>)</em> <a class="reference external" href="https://en.wikipedia.org/wiki/System_under_test">System Under Test</a> I’ve used this to mean the
Unit under test, there is no implication around the size of the “system” or
“unit”.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="green" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-3">[3]</a></td><td><span class="caps">GREEN</span> is the name for the state when all tests in your suite pass.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="tdd" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-5">[4]</a></td><td>Test Driven Development.</td></tr>
</tbody>
</table>
<table class="docutils footnote" frame="void" id="sd" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-6">[5]</a></td><td>Setup duplication: My name for the situation where there are large
chunks of Arrange code duplicated between tests. This topic warrants a
follow-up post.</td></tr>
</tbody>
</table>
</div>
Arrange Act Assert pattern for Python developers2017-07-06T23:00:00+01:002017-07-06T23:00:00+01:00Jamestag:jamescooke.info,2017-07-06:/arrange-act-assert-pattern-for-python-developers.html<p class="first last">This post introduces the Arrange Act Assert pattern of testing and
shows how it can be used in a Python context with Pytest.</p>
<p>This is the first of two posts exploring the Arrange Act Assert pattern and
how to apply it to Python tests.
It presents a recognisable and reusable test template
following the Arrange Act Assert pattern of testing. In addition, I aim to
present strategies for test writing and refactoring which I’ve developed over
the last couple of years, both on my own projects and within teams.</p>
<p>In this first part I will introduce the Arrange Act Assert pattern and discuss its
constituent parts.</p>
<div class="section" id="what-is-arrange-act-assert">
<h2>What is Arrange Act Assert?</h2>
<p>The “Arrange-Act-Assert” (also <span class="caps">AAA</span> and 3A) pattern of testing was <a class="reference external" href="https://xp123.com/articles/3a-arrange-act-assert/">observed and
named by Bill Wake in 2001</a>. I first came across it in
<a class="reference external" href="https://www.goodreads.com/book/show/387190.Test_Driven_Development">Kent Beck’s book “Test Driven Development: By Example”</a> and I
spoke about it at <a class="reference external" href="https://jamescooke.info/cleaner-unit-testing-with-the-arrange-act-assert-pattern.html">PyConUK 2016</a>.</p>
<p>The pattern focuses each test on a single action. The advantage of this focus
is that it clearly separates the arrangement of the System Under Test (<span class="caps">SUT</span>) and
the assertions that are made on it after the action.</p>
<p>On multiple projects I’ve worked on I’ve experienced organised and “clean” code
in the main codebase, but disorganisation and inconsistency in the
test suite. However when <span class="caps">AAA</span> is applied, I’ve found it helps by unifying and
clarifying the structure of tests which helps make the test suite much more
understandable and manageable.</p>
</div>
<div class="section" id="tl-dr-the-shape-of-an-aaa-test">
<h2><span class="caps">TL</span>;<span class="caps">DR</span>: The shape of an <span class="caps">AAA</span> test</h2>
<p>Here is a test that I was working on recently that follows the <span class="caps">AAA</span> pattern.
I’ve extracted it from Vim and blocked out the code with the colour that Vim assigns.</p>
<img alt="The shape of a test in Python built with Arrange Act Assert." src="https://jamescooke.info/images/test_shape.png" />
<p>Hopefully in this rough image you will see three sections to the test separated
by an empty line:</p>
<ul class="simple">
<li>First there is the test definition, docstring and Arrangement.</li>
<li>Empty line.</li>
<li>In the middle, there is a single line of code - this is the most important
part: The Act.</li>
<li>Empty line.</li>
<li>Finally there are the Assertions. You can see that the Assert block code
lines all start with the orange / brown colour - that is because the Python
keyword <tt class="docutils literal">assert</tt> is marked with this colour in Vim with my current configuration.</li>
</ul>
<p>While working on test suites that employ this pattern, my experience has been
that I’ve found it easier to understand each test. My eye has definitely got
used to the test “shape”. Want to know what is being tested? Just look at the
clear line above the assertion block.</p>
<p>Follow this pattern across your tests and your suite will be much improved.</p>
</div>
<div class="section" id="background">
<h2>Background</h2>
<p>I’ll now go into detail on each of these parts using Pytest and a toy
test example - a simple happy-path test for Python’s builtin
<tt class="docutils literal">list.reverse</tt> function.</p>
<p>I’ve made the following assumptions:</p>
<ul class="simple">
<li>We all love <a class="reference external" href="https://www.python.org/dev/peps/pep-0008/"><span class="caps">PEP008</span></a>, so we want
tests to pass <tt class="docutils literal">flake8</tt> linting.</li>
<li><a class="reference external" href="https://www.python.org/dev/peps/pep-0020/"><span class="caps">PEP020</span>, The Zen of Python</a>, is
also something we work towards - I will use some of it’s “mantras” when I
justify some of the suggestions in this guide.</li>
<li>Simplicity trumps performance. We want a test suite that is easy to maintain
and manage and can pay for that with some performance loss. I’ve assumed this
is a reasonable trade off because the tests are run much less frequently than
the <span class="caps">SUT</span> in production.</li>
</ul>
<p>This post is only an introduction to the <span class="caps">AAA</span> pattern. Where certain topics will
be covered in more detail in future posts in this series, I have marked them
with a footnote.</p>
</div>
<div class="section" id="definition">
<h2>Definition</h2>
<p>The definition of the test function.</p>
<div class="section" id="example">
<h3>Example</h3>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">test_reverse</span><span class="p">():</span>
</pre></div>
</div>
<div class="section" id="guidelines">
<h3>Guidelines</h3>
<ul class="simple">
<li>Name your function something descriptive because the function name will be
shown when the test fails in Pytest output.</li>
<li>Good test method names can make docstrings redundant in simple tests (<a class="reference external" href="https://github.com/jamescooke/blog/pull/10#discussion_r125855056">thanks
Adam!</a>).</li>
</ul>
</div>
</div>
<div class="section" id="docstring">
<h2>Docstring</h2>
<p>An optional short single line statement about the behaviour under test.</p>
<div class="section" id="example-1">
<h3>Example</h3>
<div class="highlight"><pre><span></span><span class="sd">"""</span>
<span class="sd">list.reverse inverts the order of items in a list, in place</span>
<span class="sd">"""</span>
</pre></div>
</div>
<div class="section" id="guidelines-1">
<h3>Guidelines</h3>
<p>Docstrings are not part of the <span class="caps">AAA</span> pattern. Consider if your test needs one or
if you are best to omit it for simplicity.</p>
<p>If you do include a docstring, then I recommend that you:</p>
<ul>
<li><p class="first">Follow the existing Docstring style of your project so that the tests are
consistent with the code base you are testing.</p>
</li>
<li><p class="first">Keep the language positive - state clearly what the expected behaviour is.
Positive docstrings read similar to:</p>
<blockquote>
<p>X does Y when Z</p>
</blockquote>
<p>Or…</p>
<blockquote>
<p>Given Z, then X does Y</p>
</blockquote>
</li>
<li><p class="first">Be cautious when using any uncertain language in the docstring and follow the
mantra “Explicit is better than implicit” (<a class="reference external" href="https://www.python.org/dev/peps/pep-0020/"><span class="caps">PEP20</span></a>)</p>
<p>Words like “should” and “if” introduce uncertainty. For example:</p>
<blockquote>
<p>X should do Y if Z</p>
</blockquote>
<p>In this case the reader could be left with questions. Is X doing it right at
the moment? Is this a <tt class="docutils literal"><span class="caps">TODO</span></tt> note? Is this a test for an expected failure?</p>
<p>In a similar vein, avoid future case.</p>
<blockquote>
<p>X will do Y when Z</p>
</blockquote>
<p>Again, this reads like a <tt class="docutils literal"><span class="caps">TODO</span></tt>.</p>
</li>
</ul>
</div>
</div>
<div class="section" id="arrange">
<h2>Arrange</h2>
<p>The block of code that sets up the conditions for the test action.</p>
<div class="section" id="example-2">
<h3>Example</h3>
<p>There’s not much work to do in this example to build a list, so the arrangement
block is just one line.</p>
<div class="highlight"><pre><span></span><span class="n">greek</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'alpha'</span><span class="p">,</span> <span class="s1">'beta'</span><span class="p">,</span> <span class="s1">'gamma'</span><span class="p">,</span> <span class="s1">'delta'</span><span class="p">]</span>
</pre></div>
</div>
<div class="section" id="guidelines-2">
<h3>Guidelines</h3>
<ul class="simple">
<li>Use a single block of code with no empty lines.</li>
<li>Do not use <tt class="docutils literal">assert</tt> in the Arrange block. If you need to make an assertion
about your arrangement, then this is a smell that your arrangement is too
complicated and should be extracted to a fixture or setup function and tested
in its own right.</li>
<li>Only prepare non-deterministic results not available after action.</li>
<li>The arrange section should not require comments. If you have a large
arrangement in your tests which is complex enough to require detailed
comments then consider:<ul>
<li>Extracting the comments into a multi-line docstring.</li>
<li>Extracting the arrangement code into a fixture and testing that the fixture
is establishing the expected conditions as previously mentioned.</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="act">
<h2>Act</h2>
<p>The line of code where the Action is taken on the <span class="caps">SUT</span>.</p>
<div class="section" id="example-3">
<h3>Example</h3>
<div class="highlight"><pre><span></span><span class="n">result</span> <span class="o">=</span> <span class="n">greek</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
</pre></div>
</div>
<div class="section" id="guidelines-3">
<h3>Guidelines</h3>
<ul>
<li><p class="first">Start every Action line with <tt class="docutils literal">result =</tt>.</p>
<p>This makes it easier to distinguish test actions and means you can avoid the
hardest job in programming: naming. When every result is called <tt class="docutils literal">result</tt>,
then you do not need to waste brain power wondering if it should be <tt class="docutils literal">item =</tt>
or <tt class="docutils literal">response =</tt> etc. An added benefit is that you can find test actions
easily with a tool like <tt class="docutils literal">grep</tt>.</p>
</li>
<li><p class="first">Even when there is no result from the action, capture it with <tt class="docutils literal">result =</tt>
and then <tt class="docutils literal">assert result is None</tt>. In this way, the <span class="caps">SUT</span>’s behaviour is pinned.</p>
</li>
<li><p class="first">If you struggle to write a single line action, then consider extracting some
of that code into your arrangement.</p>
</li>
<li><p class="first">The action can be wrapped in <tt class="docutils literal">with ... raises</tt> for expected exceptions. In
this case your action will be two lines surrounded by empty lines.</p>
</li>
</ul>
</div>
</div>
<div class="section" id="assert">
<h2>Assert</h2>
<p>The block of code that performs the assertions on the state of the <span class="caps">SUT</span> after
the action.</p>
<div class="section" id="example-4">
<h3>Example</h3>
<div class="highlight"><pre><span></span><span class="k">assert</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">None</span>
<span class="k">assert</span> <span class="n">greek</span> <span class="o">==</span> <span class="p">[</span><span class="s1">'delta'</span><span class="p">,</span> <span class="s1">'gamma'</span><span class="p">,</span> <span class="s1">'beta'</span><span class="p">,</span> <span class="s1">'alpha'</span><span class="p">]</span>
</pre></div>
</div>
<div class="section" id="guidelines-4">
<h3>Guidelines</h3>
<ul class="simple">
<li>Use a single block of code with no empty lines.</li>
<li>First test <tt class="docutils literal">result</tt>, then side effects.</li>
<li>Limit the actions that you make in this block. Ideally, no actions should
happen, but that is not always possible.</li>
<li>Use simple blocks of assertions. If you find that you are repeatedly writing
the same code to extract information from the <span class="caps">SUT</span> and perform assertions on
it, then consider extracting an assertion helper.</li>
</ul>
</div>
</div>
<div class="section" id="the-final-test">
<h2>The final test</h2>
<p>Here’s the example test in full:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">test_reverse</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> list.reverse inverts the order of items in a list, in place</span>
<span class="sd"> """</span>
<span class="n">greek</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'alpha'</span><span class="p">,</span> <span class="s1">'beta'</span><span class="p">,</span> <span class="s1">'gamma'</span><span class="p">,</span> <span class="s1">'delta'</span><span class="p">]</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">greek</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">None</span>
<span class="k">assert</span> <span class="n">greek</span> <span class="o">==</span> <span class="p">[</span><span class="s1">'delta'</span><span class="p">,</span> <span class="s1">'gamma'</span><span class="p">,</span> <span class="s1">'beta'</span><span class="p">,</span> <span class="s1">'alpha'</span><span class="p">]</span>
</pre></div>
</div>
<div class="section" id="flake8-aaa">
<h2>flake8-aaa</h2>
<p>Check out <a class="reference external" href="https://flake8-aaa.readthedocs.io/en/stable/">flake8-aaa</a> - a
Flake8 plugin that makes it easier to write tests that follow the Arrange Act
Assert pattern outlined above.</p>
</div>
<div class="section" id="thanks">
<h2>Thanks</h2>
<p>I hope that this introduction has been helpful and you will return for part 2:
<a class="reference external" href="/aaa-part-2-extracting-arrange-code-to-make-fixtures.html"><span class="caps">AAA</span> Part 2: Extracting Arrange code to make fixtures</a>.</p>
<p>Thanks to <a class="reference external" href="https://adamj.eu/">Adam</a> for reviewing this post and his helpful feedback.</p>
<p>Thanks for reading and happy testing!</p>
</div>
Comparing Django Q Objects in Python 3 with pytest2017-05-30T22:00:00+01:002017-05-30T22:00:00+01:00Jamestag:jamescooke.info,2017-05-30:/comparing-django-q-objects-in-python-3-with-pytest.html<p class="first last">An updated simple assertion helper for comparing instances of
Django’s Q objects using pytest in Python 3.</p>
<div class="section" id="background">
<h2>Background</h2>
<p>In a <a class="reference external" href="https://jamescooke.info/comparing-django-q-objects.html">previous post</a> I wrote
about comparing Django’s Q object instances. The original code was Python 2
with unittest and was <a class="reference external" href="https://github.com/jamescooke/blog/issues/6">due for an update</a>.</p>
<p>The previous issue with comparing Django’s Q objects remains the same:</p>
<blockquote>
<p>Django’s Q object does not implement <tt class="docutils literal">__cmp__</tt> and neither does
<tt class="docutils literal">Node</tt> which it extends (<tt class="docutils literal">Node</tt> is in the <tt class="docutils literal">django.utils.tree</tt> module).</p>
<p>Unfortunately, that means that comparison of Q objects that are equal fails.</p>
</blockquote>
</div>
<div class="section" id="a-simple-python-3-solution">
<h2>A simple Python 3 solution</h2>
<p>The following is a Python 3.6 assertion helper for use with pytest that uses
the original strategy of comparing the string versions of the Q objects.</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
<span class="k">def</span> <span class="nf">assert_q_equal</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Test two Q objects for equality. Does is not match commutative.</span>
<span class="sd"> Args:</span>
<span class="sd"> left (Q)</span>
<span class="sd"> right (Q)</span>
<span class="sd"> Raises:</span>
<span class="sd"> AssertionError: When -</span>
<span class="sd"> * `left` or `right` are not an instance of `Q`</span>
<span class="sd"> * `left` and `right` are not considered equal.</span>
<span class="sd"> """</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">Q</span><span class="p">),</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">left</span><span class="o">.</span><span class="vm">__class__</span><span class="si">}</span><span class="s1"> is not subclass of Q'</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">right</span><span class="p">,</span> <span class="n">Q</span><span class="p">),</span> <span class="sa">f</span><span class="s1">'</span><span class="si">{</span><span class="n">right</span><span class="o">.</span><span class="vm">__class__</span><span class="si">}</span><span class="s1"> is not subclass of Q'</span>
<span class="k">assert</span> <span class="nb">str</span><span class="p">(</span><span class="n">left</span><span class="p">)</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="n">right</span><span class="p">),</span> <span class="sa">f</span><span class="s1">'Q</span><span class="si">{</span><span class="n">left</span><span class="si">}</span><span class="s1"> != Q</span><span class="si">{</span><span class="n">right</span><span class="si">}</span><span class="s1">'</span>
</pre></div>
<p>This time the helper is just a function rather than a mixin for
<tt class="docutils literal">unittest.TestCase</tt>.</p>
<p><tt class="docutils literal">isinstance</tt> is used for comparison so that any instance of a class derived
from <tt class="docutils literal">Q</tt> can also be matched. The assertions have secondary expressions in
the form of <a class="reference external" href="https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep498">f-strings</a> to give
helpful output without raising a custom assertion.</p>
<p>When two <tt class="docutils literal">Q</tt> instances do not match, pytest shows the following output:</p>
<pre class="literal-block">
______________________ test_neq_multi_not_commutative ______________________
test_assert_q_equal.py:83: in test_neq_multi_not_commutative
assert_q_equal(q_a, q_b)
test_assert_q_equal.py:22: in assert_q_equal
assert str(left) == str(right), f'Q{left} != Q{right}'
E AssertionError: Q(AND: ('speed', 12), ('direction', 'north')) != Q(AND: ('direction', 'north'), ('speed', 12))
E assert "(AND: ('spee...n', 'north'))" == "(AND: ('direc...'speed', 12))"
E - (AND: ('speed', 12), ('direction', 'north'))
E + (AND: ('direction', 'north'), ('speed', 12))
==================== 1 failed, 7 passed in 0.07 seconds ====================
</pre>
<p>The important thing is to adjust your assertion helpers to best fit
the needs of your test suite and team.</p>
</div>
<div class="section" id="final-testing-related-note">
<h2>Final testing related note</h2>
<p>Thanks to <a class="reference external" href="https://github.com/jamescooke/blog/pull/7#pullrequestreview-41177014">Adam’s feedback on my initial post</a>, I
improved the assertions to use <tt class="docutils literal">isinstance</tt> and secondary expressions to
provide helpful output.</p>
<p>Tests for <tt class="docutils literal">assert_q_equal</tt> and its original code are <a class="reference external" href="https://gist.github.com/jamescooke/1bed3414fee7d5c72540e567bcd63887">in this gist</a>.</p>
<p>Happy testing!</p>
</div>
My Vim setup for Python development2017-01-04T14:30:00+00:002017-01-04T14:30:00+00:00Jamestag:jamescooke.info,2017-01-04:/my-vim-setup-for-python-development.html<p class="first last">My current Vim setup for Python development.</p>
<p>Below is a list of my Vim plug-ins and configurations.</p>
<p>My goal has been to make Vim more useful for (primarily) Python development.
This post refers to Vim 7, because I have not yet updated to Vim 8. I’m using
<a class="reference external" href="https://github.com/junegunn/vim-plug">vim-plug</a> to manage my packages, so
mentions of packages below will use the <tt class="docutils literal">Plug</tt> command.</p>
<p>All the commands and configuration below come from my <a class="reference external" href="https://github.com/jamescooke/dotfiles/blob/master/store/.vimrc">vimrc file</a>. You’ll
find that I don’t have a large number of plug-ins or configuration lines
compared to other more famous Vim users (cough) <a class="reference external" href="https://github.com/nelstrom/dotfiles/blob/master/bundles.vim">Drew</a> (cough). That
is a direct result of <a class="reference external" href="https://vimeo.com/65250028">Kris Jenkins’s Bare Bones Navigation Vim talk</a> at Vim London. The main result of which has been
that I have always run a very simple Vim setup.</p>
<p>My relatively recent use of <span class="caps">FZF</span> and Ctags listed below are a direct result of
attending the most recent <a class="reference external" href="https://www.meetup.com/Vim-London/">Vim London meetup</a> and, if you’re in the London area, I
fully recommend joining and attending. Every meetup I attend, my Vim-fu improves.</p>
<div class="section" id="specific-python-config">
<h2>Specific Python config</h2>
<p>The following are my <tt class="docutils literal">.vimrc</tt> lines for handling Python.</p>
<p>When searching for files with Vim, only load Python files:</p>
<div class="highlight"><pre><span></span><span class="k">set</span> <span class="nb">suffixesadd</span><span class="p">=</span>.<span class="k">py</span>
</pre></div>
<p>Ignore <tt class="docutils literal">pyc</tt> files when expanding wildcards:</p>
<div class="highlight"><pre><span></span><span class="k">set</span> <span class="nb">wildignore</span><span class="p">=</span>*.pyc
</pre></div>
<p>Don’t show <tt class="docutils literal">pyc</tt> in file lists:</p>
<div class="highlight"><pre><span></span><span class="k">let</span> <span class="k">g</span>:netrw_list_hide<span class="p">=</span> <span class="s1">'.*\.pyc$'</span>
</pre></div>
<p>Keep “Pythonic” tabs using 4 white spaces:</p>
<div class="highlight"><pre><span></span><span class="k">set</span> <span class="nb">autoindent</span> <span class="nb">nosmartindent</span> <span class="c">" auto/smart indent</span>
<span class="k">set</span> <span class="nb">smarttab</span>
<span class="k">set</span> <span class="nb">expandtab</span> <span class="c">" expand tabs to spaces</span>
<span class="k">set</span> <span class="nb">shiftwidth</span><span class="p">=</span><span class="m">4</span>
<span class="k">set</span> <span class="nb">softtabstop</span><span class="p">=</span><span class="m">4</span>
</pre></div>
<p>I really get frustrated with tabs that look like white spaces, so I ensure
they are visible by telling Vim to show all tabs as little arrows <tt class="docutils literal">▷</tt>. This
line also ensures that end of lines are shown with a negation sign <tt class="docutils literal">¬</tt> :</p>
<div class="highlight"><pre><span></span><span class="k">set</span> <span class="nb">listchars</span><span class="p">=</span><span class="nb">eol</span>:¬<span class="p">,</span><span class="k">tab</span>:▷\ <span class="p">,</span>
</pre></div>
<p>A classic “Python tell” in Vim is the 79th or 80th character highlight:</p>
<div class="highlight"><pre><span></span><span class="k">set</span> <span class="nb">colorcolumn</span><span class="p">=</span><span class="m">80</span> <span class="c">" Show the 80th char column.</span>
<span class="nb">highlight</span> ColorColumn ctermbg<span class="p">=</span><span class="m">5</span>
</pre></div>
</div>
<div class="section" id="fzf">
<h2><span class="caps">FZF</span></h2>
<p>My greatest recent revelation has been the integration of <a class="reference external" href="https://github.com/junegunn/fzf"><span class="caps">FZF</span></a> to provide “quick” fuzzy searching. Most
frequently I search for files in the current git repository, open buffers and tags.</p>
<p>Install <span class="caps">FZF</span> and get it working on your machine, then add it to your Vim
setup using <a class="reference external" href="https://github.com/junegunn/fzf.vim">fzf.vim</a>:</p>
<div class="highlight"><pre><span></span>Plug <span class="s1">'junegunn/fzf'</span><span class="p">,</span> { <span class="s1">'dir'</span>: <span class="s1">'~/.fzf'</span><span class="p">,</span> <span class="s1">'do'</span>: <span class="s1">'./install --all'</span> }
Plug <span class="s1">'junegunn/fzf.vim'</span>
</pre></div>
<p>I’ve mapped my most common <span class="caps">FZF</span> searches to <a class="reference external" href="http://stevelosh.com/blog/2010/09/coming-home-to-vim/#using-the-leader">leader commands</a>:</p>
<div class="highlight"><pre><span></span>imap <span class="p"><</span><span class="k">c</span><span class="p">-</span><span class="k">x</span><span class="p">><</span><span class="k">c</span><span class="p">-</span><span class="k">o</span><span class="p">></span> <span class="p"><</span>plug<span class="p">>(</span>fzf<span class="p">-</span><span class="nb">complete</span><span class="p">-</span>line<span class="p">)</span>
map <span class="p"><</span>leader<span class="p">></span><span class="k">b</span> :Buffers<span class="p"><</span><span class="k">cr</span><span class="p">></span>
map <span class="p"><</span>leader<span class="p">></span><span class="k">f</span> :Files<span class="p"><</span><span class="k">cr</span><span class="p">></span>
map <span class="p"><</span>leader<span class="p">></span><span class="k">g</span> :GFiles<span class="p"><</span><span class="k">cr</span><span class="p">></span>
map <span class="p"><</span>leader<span class="p">></span><span class="k">t</span> :Tags<span class="p"><</span><span class="k">cr</span><span class="p">></span>
</pre></div>
<p>Keeping <span class="caps">FZF</span>’s line completion on <tt class="docutils literal"><span class="pre"><span class="caps">CTRL</span>-x</span> <span class="pre"><span class="caps">CTRL</span>-o</span></tt> means that I can keep
access to Vim’s line completion which is bound to <tt class="docutils literal"><span class="pre"><span class="caps">CTRL</span>-x</span> <span class="pre"><span class="caps">CTRL</span>-l</span></tt> by default.</p>
<p><a class="reference external" href="https://github.com/ggreer/the_silver_searcher">Ag</a> results integration
with <span class="caps">FZF</span> is next on my list, I’m still using <tt class="docutils literal">Ag</tt> results on the command line.</p>
</div>
<div class="section" id="ctags">
<h2>Ctags</h2>
<p>I was definitely slow to get on the <a class="reference external" href="https://en.wikipedia.org/wiki/Ctags">Ctags</a>
bandwagon, only adding them to my workflow in the last couple of months, but
along with <span class="caps">FZF</span>, they have been a revelation. I’ve been using <a class="reference external" href="https://en.wikipedia.org/wiki/Ctags">Exhuberant Ctags</a> as my index generator.</p>
<p>TPope has published a neat trick of stashing the <tt class="docutils literal">ctags</tt> script inside the
<tt class="docutils literal">.git</tt> folder, outlined in <a class="reference external" href="https://tbaggery.com/2011/08/08/effortless-ctags-with-git.html">his blog post here</a>. My version
of the script is inside my <a class="reference external" href="https://github.com/jamescooke/dotfiles/blob/master/store/.git_template/hooks/ctags.sh">git hooks configuration</a>
and works in combination with my <a class="reference external" href="https://github.com/jamescooke/dotfiles/blob/master/store/.ctags">ctags config</a>.</p>
<p>As mentioned above, I have used <tt class="docutils literal"><leader>t</tt> to trigger an <span class="caps">FZF</span>-powered search
of tags:</p>
<div class="highlight"><pre><span></span>map <span class="p"><</span>leader<span class="p">></span><span class="k">t</span> :Tags<span class="p"><</span><span class="k">cr</span><span class="p">></span>
</pre></div>
<p>The default “jump to definition under cursor” is still the default <tt class="docutils literal"><span class="pre"><span class="caps">CTRL</span>-]</span></tt>
which, with “previous tag” <tt class="docutils literal"><span class="pre"><span class="caps">CTRL</span>-t</span></tt> makes it really easy to traverse code.</p>
</div>
<div class="section" id="visual-selection">
<h2>Visual selection</h2>
<p>The <a class="reference external" href="https://github.com/gorkunov/smartpairs.vim">smartpairs plugin</a> is
fantastic for selecting text inside brackets, braces and parentheses and is
excellent for all languages I work with, not just Python:</p>
<div class="highlight"><pre><span></span>Plug <span class="s1">'gorkunov/smartpairs.vim'</span>
</pre></div>
</div>
<div class="section" id="linting">
<h2>Linting</h2>
<p>In general, I’ve used external programs to provide linting of my Python code
and so I run Vim with the current project’s virtualenv active.</p>
<p>With <a class="reference external" href="https://pypi.python.org/pypi/isort">Isort</a> installed in the current
environment, sort the imports of the current file with <tt class="docutils literal"><leader>i</tt> or call it
with <tt class="docutils literal">:Isort</tt> command on a range of lines:</p>
<div class="highlight"><pre><span></span>map <span class="p"><</span>leader<span class="p">></span><span class="k">i</span> :Isort<span class="p"><</span><span class="k">cr</span><span class="p">></span>
command<span class="p">!</span> <span class="p">-</span>range<span class="p">=</span>% Isort :<span class="p"><</span>line1<span class="p">>,<</span>line2<span class="p">>!</span> isort <span class="p">-</span>
</pre></div>
<p>With <a class="reference external" href="https://pypi.python.org/pypi/flake8/">flake8</a> installed in the current
environment, lint the current file with <tt class="docutils literal">F7</tt> as provided by <a class="reference external" href="https://github.com/nvie/vim-flake8">Vincent
Driessen’s vim-flake8</a>:</p>
<div class="highlight"><pre><span></span>Plug <span class="s1">'nvie/vim-flake8'</span>
</pre></div>
<p>Happy Vimming!</p>
<p><tt class="docutils literal">:xa</tt></p>
</div>
A successful pip-tools workflow for managing Python package requirements2016-11-13T23:00:00+00:002016-11-13T23:00:00+00:00Jamestag:jamescooke.info,2016-11-13:/a-successful-pip-tools-workflow-for-managing-python-package-requirements.html<p class="first last">Using pip-tools with multiple requirements files can be difficult.
This post describes my current workflow that manages the complexity with a
<tt class="docutils literal">Makefile</tt>.</p>
<p>In this post I present the <tt class="docutils literal"><span class="pre">pip-tools</span></tt> workflow I’ve been using over a number
of projects to manage multiple inherited requirements files. At its core is a
<a class="reference external" href="https://www.gnu.org/software/make/manual/make.html"><span class="caps">GNU</span> Make</a> Makefile to
provide recipes for managing requirements and specifying the dependencies
between the requirements files.</p>
<p>If you are not aware of the excellent <tt class="docutils literal"><span class="pre">pip-tools</span></tt> <a class="reference external" href="https://github.com/jazzband/pip-tools">package</a> it provides two commands:
<tt class="docutils literal"><span class="pre">pip-compile</span></tt> and <tt class="docutils literal"><span class="pre">pip-sync</span></tt>. In this post I will be focusing on using
<tt class="docutils literal"><span class="pre">pip-compile</span></tt> to compile <tt class="docutils literal">.in</tt> files consisting of top level requirements.</p>
<p><tt class="docutils literal"><span class="pre">pip-compile</span></tt> consults the PyPI index for each top level package required,
looking up the package versions available, outputting a specific list of pinned
packages in a <tt class="docutils literal">.txt</tt> file. This extra layer of abstraction (<tt class="docutils literal">.in</tt> files
containing top level requirements rather than just outputting <tt class="docutils literal">.txt</tt> files
with <tt class="docutils literal">pip freeze</tt>) is very helpful for managing requirements, but does create
some complications which mean that a solid workflow is essential for stable
package management.</p>
<blockquote>
<p><em>Update 13/10/2019</em></p>
<p>This post has been updated to use <tt class="docutils literal"><span class="pre">-c</span></tt> constraint files rather than
<tt class="docutils literal"><span class="pre">-r</span></tt> recursive inclusion. More info at the end of the post.</p>
</blockquote>
<div class="section" id="keep-requirements-files-in-their-own-folder">
<h2>Keep requirements files in their own folder</h2>
<p>In order to preserve sanity, I keep my project requirements in their own folder
directly inside the project.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>project
$<span class="w"> </span>ls<span class="w"> </span>requirements/
base.in<span class="w"> </span>base.txt<span class="w"> </span>Makefile<span class="w"> </span>test.in<span class="w"> </span>test.txt
</pre></div>
<p>During this post, I’ll use this simple example with one set of “base”
requirements and one set of “test” requirements.</p>
</div>
<div class="section" id="store-in-and-txt-files-in-version-control">
<h2>Store <tt class="docutils literal">.in</tt> and <tt class="docutils literal">.txt</tt> files in version control</h2>
<p>Both <tt class="docutils literal">.in</tt> and <tt class="docutils literal">.txt</tt> files are tracked in the project’s revision control
system, for example <tt class="docutils literal">git</tt>. This allows for shipping of the compiled <tt class="docutils literal">.txt</tt>
files for installation, but more importantly, it presents the opportunity to
check the diff of <tt class="docutils literal">.txt</tt> files when upgrading packages.</p>
<p>I also tend to keep <tt class="docutils literal">.in</tt> files sorted alphabetically.</p>
</div>
<div class="section" id="set-in-files-to-depend-on-txt-files">
<h2>Set <tt class="docutils literal">.in</tt> files to depend on <tt class="docutils literal">.txt</tt> files</h2>
<p>In the example project there are <tt class="docutils literal">base.in</tt> and <tt class="docutils literal">test.in</tt> requirements files:</p>
<ul class="simple">
<li><tt class="docutils literal">base.in</tt> compiles to <tt class="docutils literal">base.txt</tt></li>
<li><tt class="docutils literal">test.in</tt> compiles to <tt class="docutils literal">test.txt</tt></li>
</ul>
<p>I want the test requirements to be compiled to respect the versions of the base
packages so that they can be installed without disrupting those selected
versions. Therefore I set <tt class="docutils literal">test.in</tt> to be constrained by the <tt class="docutils literal">base.txt</tt>
compiled requirements with <tt class="docutils literal"><span class="pre">-c</span></tt>:</p>
<p><tt class="docutils literal">base.in</tt> contains:</p>
<pre class="literal-block">
project-packages
</pre>
<p><tt class="docutils literal">test.in</tt> contains:</p>
<pre class="literal-block">
-c base.txt
test-packages
</pre>
</div>
<div class="section" id="use-a-makefile-for-common-tasks">
<h2>Use a Makefile for common tasks</h2>
<p>On each project that has multiple requirements files, I use a Makefile and
place it in the requirements folder.</p>
<div class="highlight"><pre><span></span><span class="nf">.PHONY</span><span class="o">:</span><span class="w"> </span><span class="n">all</span> <span class="n">check</span> <span class="n">clean</span>
<span class="nv">objects</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>wildcard<span class="w"> </span>*.in<span class="k">)</span>
<span class="nv">outputs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">$(</span>objects:.in<span class="o">=</span>.txt<span class="k">)</span>
<span class="nf">all</span><span class="o">:</span><span class="w"> </span><span class="k">$(</span><span class="nv">outputs</span><span class="k">)</span>
<span class="nf">%.txt</span><span class="o">:</span><span class="w"> </span>%.<span class="n">in</span>
<span class="w"> </span>pip-compile<span class="w"> </span>-v<span class="w"> </span>--output-file<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>$<
<span class="nf">test.txt</span><span class="o">:</span><span class="w"> </span><span class="n">base</span>.<span class="n">txt</span>
<span class="nf">check</span><span class="o">:</span>
<span class="w"> </span>@which<span class="w"> </span>pip-compile<span class="w"> </span>><span class="w"> </span>/dev/null
<span class="nf">clean</span><span class="o">:</span><span class="w"> </span><span class="n">check</span>
<span class="w"> </span>-<span class="w"> </span>rm<span class="w"> </span>*.txt
</pre></div>
<!-- ** -->
<p>Here is [a similar] file <a class="reference external" href="https://github.com/jamescooke/flake8-aaa/blob/master/requirements/Makefile">in a current project</a>.</p>
<blockquote>
<p>Note 1: This is an updated version of the Makefile that I have been using.
There are no <tt class="docutils literal">clean</tt> or <tt class="docutils literal">check</tt> recipes.</p>
<p>Note 2: <tt class="docutils literal">make</tt> requires recipes to be indented by tabs, so if you
want to copy this file then it could be helpful to pull the <a class="reference external" href="https://raw.githubusercontent.com/jamescooke/flake8-aaa/master/requirements/Makefile">raw file from
Github</a>
rather than copying and pasting from this page which does not show tab characters.</p>
</blockquote>
<p>Let’s go over the key functionality provided by this Makefile:</p>
<ul>
<li><p class="first">First two definitions:</p>
<div class="highlight"><pre><span></span><span class="nv">objects</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">$(</span>wildcard<span class="w"> </span>*.in<span class="k">)</span>
</pre></div>
<!-- ** -->
<p><tt class="docutils literal">objects</tt> is a list containing every <tt class="docutils literal">.in</tt> file in requirements folder.</p>
<div class="highlight"><pre><span></span><span class="nv">outputs</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">$(</span>objects:.in<span class="o">=</span>.txt<span class="k">)</span>
</pre></div>
<p><tt class="docutils literal">outputs</tt> is also a list made of one <tt class="docutils literal">.txt</tt> filename for each <tt class="docutils literal">.in</tt> file
in the <tt class="docutils literal">outputs</tt> list. The <tt class="docutils literal">.txt</tt> files do not need to exist yet, this
list tells <tt class="docutils literal">make</tt> what they should be called.</p>
</li>
<li><p class="first">A recipe called <tt class="docutils literal">all</tt> to build all <tt class="docutils literal">.txt</tt> files:</p>
<div class="highlight"><pre><span></span><span class="nf">all</span><span class="o">:</span><span class="w"> </span><span class="k">$(</span><span class="nv">outputs</span><span class="k">)</span>
</pre></div>
<p>The <tt class="docutils literal">all</tt> recipe has no commands of its own - it solely depends on all the
<tt class="docutils literal">.txt</tt> files in the <tt class="docutils literal">outputs</tt> list being built. In order to fulfil this
recipe, <tt class="docutils literal">make</tt> will attempt to build every <tt class="docutils literal">.txt</tt> file in the <tt class="docutils literal">objects</tt>
list.</p>
</li>
<li><p class="first">Up until now, <tt class="docutils literal">make</tt> does not know how to build a <tt class="docutils literal">.txt</tt> file, so here we
give it a recipe:</p>
<div class="highlight"><pre><span></span><span class="nf">%.txt</span><span class="o">:</span><span class="w"> </span>%.<span class="n">in</span>
<span class="w"> </span>pip-compile<span class="w"> </span>-v<span class="w"> </span>--output-file<span class="w"> </span><span class="nv">$@</span><span class="w"> </span>$<
</pre></div>
<p>The first line tells <tt class="docutils literal">make</tt> that any <tt class="docutils literal">.txt</tt> file depends on the <tt class="docutils literal">.in</tt>
file with the same name. <tt class="docutils literal">make</tt> will check the date stamp on the two files
and compare them - if the <tt class="docutils literal">.txt</tt> file is older than the <tt class="docutils literal">.in</tt> file or does
not exist, then <tt class="docutils literal">make</tt> will build it.</p>
<p>The next line tells <tt class="docutils literal">make</tt> the command to use to perform the build - it is
the <tt class="docutils literal"><span class="pre">pip-compile</span></tt> command with the following flags:</p>
<ul class="simple">
<li><tt class="docutils literal"><span class="pre">-v</span></tt> means <tt class="docutils literal"><span class="pre">pip-compile</span></tt> will give verbose output. I find this helpful
for general watchfulness, but you may prefer to remove it.</li>
<li><tt class="docutils literal"><span class="pre">output-file</span> $@</tt> means “send the output to the target of the recipe”, which
is the <tt class="docutils literal">.txt</tt> file we’ve asked to be made. For example when invoking <tt class="docutils literal">make
base.txt</tt>, then <tt class="docutils literal"><span class="pre">--output-file</span> base.txt</tt> will be passed.</li>
<li><tt class="docutils literal">$<</tt> at the end is the corresponding <tt class="docutils literal">.in</tt> input file. Make matches the
names using the <tt class="docutils literal">%</tt> sign in the recipe, so it knows to build <tt class="docutils literal">base.txt</tt>
from <tt class="docutils literal">base.in</tt>.</li>
</ul>
</li>
<li><p class="first">Now we tell <tt class="docutils literal">make</tt> about the dependency between the requirements files.</p>
<div class="highlight"><pre><span></span><span class="nf">test.txt</span><span class="o">:</span><span class="w"> </span><span class="n">base</span>.<span class="n">txt</span>
</pre></div>
<p>This creates a dependency chain. This is an additional recipe for
<tt class="docutils literal">test.txt</tt> which tells <tt class="docutils literal">make</tt> that it depends on <tt class="docutils literal">base.txt</tt>. That means
that if <tt class="docutils literal">make</tt> is asked to build <tt class="docutils literal">test.txt</tt>, then it should be updated if
<tt class="docutils literal">test.in</tt> <em>or</em> <tt class="docutils literal">base.txt</tt> have been updated.</p>
<p>If <tt class="docutils literal">base.in</tt> is updated, then <tt class="docutils literal">make</tt> knows that it will need to recompile
<tt class="docutils literal">base.txt</tt> in order to make <tt class="docutils literal">test.txt</tt>. We can see that here:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>touch<span class="w"> </span>base.in<span class="w"> </span><span class="c1"># Update timestamp on base.in</span>
$<span class="w"> </span>make<span class="w"> </span>-n<span class="w"> </span>test.txt<span class="w"> </span><span class="c1"># What commands will be run to build test.txt</span>
pip-compile<span class="w"> </span>-v<span class="w"> </span>--output-file<span class="w"> </span>base.txt<span class="w"> </span>base.in
pip-compile<span class="w"> </span>-v<span class="w"> </span>--output-file<span class="w"> </span>test.txt<span class="w"> </span>test.in
</pre></div>
<p>This is exactly what we want for requirements constraining. If the
requirements in our base have changed, then we want our test file to be
recompiled too because of the <tt class="docutils literal"><span class="pre">-c</span> base.txt</tt> line we added to the
<tt class="docutils literal">test.in</tt> file.</p>
<p>Of course, this is a trivial example, but I have used
multiple lines of dependency in Makefiles to manage multiple levels of
inheritance in requirements files.</p>
</li>
<li><p class="first">Finally, a recipe to help us update requirements.</p>
<div class="highlight"><pre><span></span><span class="nf">check</span><span class="o">:</span>
<span class="w"> </span>@which<span class="w"> </span>pip-compile<span class="w"> </span>><span class="w"> </span>/dev/null
<span class="nf">clean</span><span class="o">:</span><span class="w"> </span><span class="n">check</span>
<span class="w"> </span>-<span class="w"> </span>rm<span class="w"> </span>*.txt
</pre></div>
<!-- ** -->
<p>The <tt class="docutils literal">check</tt> recipe will fail if <tt class="docutils literal"><span class="pre">pip-tools</span></tt> is not installed.</p>
<p>The <tt class="docutils literal">clean</tt> recipe will remove all the <tt class="docutils literal">.txt</tt> files if the <tt class="docutils literal">check</tt>
recipe is successful. This makes it harder to accidentally delete your
requirements files without <tt class="docutils literal"><span class="pre">pip-tools</span></tt> already installed to be able to
build them again.</p>
</li>
</ul>
<p>I’ve explained what the Makefile above does, but not how or when you would use
it. So let’s continue with some common workflow actions.</p>
</div>
<div class="section" id="build-one-or-more-requirements-files">
<h2>Build one or more requirements files</h2>
<p>To update all requirements use the default <tt class="docutils literal">all</tt> recipe.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>make<span class="w"> </span>all
</pre></div>
<p>To update a particular file, ask for it by name:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>make<span class="w"> </span>test.txt
</pre></div>
<p>If <tt class="docutils literal">make</tt> tells you that a file is up-to-date but you want to force it to
be rebuilt you should <tt class="docutils literal">touch</tt> the <tt class="docutils literal">.in</tt> file.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>make<span class="w"> </span>base.txt
make:<span class="w"> </span><span class="s1">'base.txt'</span><span class="w"> </span>is<span class="w"> </span>up<span class="w"> </span>to<span class="w"> </span>date.
$<span class="w"> </span>touch<span class="w"> </span>base.in
$<span class="w"> </span>make<span class="w"> </span>base.txt
pip-compile<span class="w"> </span>-v<span class="w"> </span>--output-file<span class="w"> </span>base.txt<span class="w"> </span>base.in
...
</pre></div>
</div>
<div class="section" id="add-a-dependency">
<h2>Add a dependency</h2>
<p>To add a dependency, locate the appropriate <tt class="docutils literal">.in</tt> file and add the new
package name there. The version number is only required if a particular version
of the library is required. The latest version will be chosen by default when compiling.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>cat<span class="w"> </span>>><span class="w"> </span>base.in
ipython
$<span class="w"> </span>make<span class="w"> </span>all
</pre></div>
</div>
<div class="section" id="update-a-package">
<h2>Update a package</h2>
<p>In order to update a single top level package version, remove its lines from
the compiled corresponding <tt class="docutils literal">.txt</tt> files. I tend to be quite “aggressive” with
this and remove every package that the top level package depended on using
<tt class="docutils literal">sed</tt> with a pattern match.</p>
<p>Given that I want to update <tt class="docutils literal">ipython</tt> and it is not pinned in my <tt class="docutils literal">.in</tt>
file:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>sed<span class="w"> </span><span class="s1">'/ipython/d'</span><span class="w"> </span>-i<span class="w"> </span>*.txt
$<span class="w"> </span>make<span class="w"> </span>all
</pre></div>
<p>There is no command for this removal built into the Makefile, but potentially
it could be. Ideally, it could be provided as extra functionality by
<tt class="docutils literal"><span class="pre">pip-tools</span></tt>. Beware that packages often contain each other’s names as
substrings so could lead to bad matching. If in doubt review your diff and
potentially remove lines from your <tt class="docutils literal">.txt</tt> files manually.</p>
<p>The call to <tt class="docutils literal">make all</tt> will reevaluate the latest version for packages that
do not have corresponding lines in the <tt class="docutils literal">.txt</tt> file and they will be updated
as required.</p>
</div>
<div class="section" id="update-all-requirements">
<h2>Update all requirements</h2>
<p>A full update of all requirements to the latest version (including updating all
packages that are not pinned in the <tt class="docutils literal">.in</tt> file with a particular version
number) can be achieved with:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>make<span class="w"> </span>clean<span class="w"> </span>all
</pre></div>
<p>The <tt class="docutils literal">clean</tt> recipe will clean out all <tt class="docutils literal">*.txt</tt> files if you have
<tt class="docutils literal"><span class="pre">pip-tools</span></tt> installed. Then the <tt class="docutils literal">all</tt> recipe will rebuild them all in
dependency order.</p>
</div>
<div class="section" id="finally">
<h2>Finally</h2>
<p>A tip for working with Makefiles. If you want to see what commands will be run
by a recipe, you can use the <tt class="docutils literal"><span class="pre">-n</span></tt> flag and inspect the commands that were planned:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>make<span class="w"> </span>-n<span class="w"> </span>all
</pre></div>
<p>Happy requirements packing!</p>
</div>
<div class="section" id="update-21-11-2016">
<h2>Update 21/11/2016</h2>
<p>For more information on the advantages and disadvantages of setting recursive
requirements to point at <tt class="docutils literal">.in</tt> files or <tt class="docutils literal">.txt</tt> files please see <a class="reference external" href="https://github.com/nvie/pip-tools/issues/398">this Issue</a> on the <tt class="docutils literal"><span class="pre">pip-tools</span></tt>
repository.</p>
<p>In particular, <a class="reference external" href="https://github.com/nvie/pip-tools/issues/398#issuecomment-261313647">my comment</a>
illustrates how development requirements can become out of sync with base
requirements when <tt class="docutils literal">.in</tt> files are used in recursion which does not happen
when <tt class="docutils literal">.txt</tt> files are used. It’s for this reason, that I continue to
recommend pointing at <tt class="docutils literal">.txt</tt> files with <tt class="docutils literal"><span class="pre">-r</span></tt>.</p>
</div>
<div class="section" id="update-30-06-2017">
<h2>Update 30/06/2017</h2>
<p>See also <a class="reference external" href="https://github.com/jamescooke/blog/issues/9">this comment on GitHub</a> from Devin Fee for a
<tt class="docutils literal">Makefile</tt> which:</p>
<blockquote>
… corrects the annoyance <tt class="docutils literal"><span class="pre">-e</span> <span class="pre">file:///Users/dfee/code/zebra</span> <span class="pre">-></span> <span class="pre">-e</span> .</tt>,
making the file useful for users who don’t develop / deploy from your
directory.</blockquote>
</div>
<div class="section" id="update-13-10-2019">
<h2>Update 13/10/2019</h2>
<p><a class="reference external" href="https://github.com/jazzband/pip-tools/pull/905">This pull request</a> updated
the <tt class="docutils literal"><span class="pre">pip-tools</span></tt> <span class="caps">README</span> to include <a class="reference external" href="https://github.com/jazzband/pip-tools#workflow-for-layered-requirements">info on creating layered requirements
files</a>
using <tt class="docutils literal"><span class="pre">-c</span></tt> constraints. The use of <tt class="docutils literal"><span class="pre">-c</span></tt> came up in <a class="reference external" href="https://github.com/jazzband/pip-tools/issues/398">this long running issue</a> discussing layered
requirements and how to ensure that each layer is compatible with the others.</p>
<p>I think that <tt class="docutils literal"><span class="pre">-c</span></tt> constraints are much better than <tt class="docutils literal"><span class="pre">-r</span></tt> inclusion and have
updated the post to reflect that.</p>
</div>
Django Factory Audit2016-10-12T10:00:00+01:002016-10-12T10:00:00+01:00Jamestag:jamescooke.info,2016-10-12:/django-factory-audit.html<p class="first last">Exploring the various model instance factories available for Django.
Each factory is tested based on the quality of the instances it
creates. Bonus: talk version and slides also available.</p>
<p>Factories build instances of models, primarily for testing, but can be used
anywhere. In this post I present my attempts at grading different factory
libraries available for Django based on the validity of the instances that they create.</p>
<div class="section" id="the-problem">
<h2>The Problem</h2>
<p>You’re a much better programmer than me - I’m a bad programmer. I make
mistakes, lots of them. I often forget to validate my instances before saving.
In order for my tests to be more dependable and solid, I’d like whatever object
factory I use to look after me by validating the generated instance before it
reaches the database.</p>
<p>This is the way that I’ve been looking at Django model instances - for a single
model we can imagine sets of instances which might look like:</p>
<img alt="Venn diagram showing sets of Django model instances grouped by validity." src="https://jamescooke.info/images/venn.png" style="width: 500px;" />
<p>Where:</p>
<ul class="simple">
<li><tt class="docutils literal">ε</tt>: The universal set of all possible instances of this model.</li>
<li><tt class="docutils literal">D</tt>: The set of instances that the database would consider valid. It’s
interesting to note that this set might change as code is developed, tested
and run on machines that have different database versions or use different
databases altogether.</li>
<li><tt class="docutils literal">V</tt>: The set of valid instances which pass <tt class="docutils literal">full_clean</tt>. This is a subset
of <tt class="docutils literal">D</tt>.</li>
</ul>
<p>The main issue is the set <tt class="docutils literal">D/V</tt> of instances. These are all the instances
which can be saved into the database but are considered invalid by Django.</p>
<p>When factories create instances that reside in this <tt class="docutils literal">D/V</tt> set, they create
instability in the system:</p>
<ul class="simple">
<li>If a user attempts to edit that instance through the Django Admin system,
then they may not be able to save their changes without fixing a list of
invalid fields.</li>
<li>Test suites will be executed using model instances that <em>should</em> not be
created during the “normal” lifetime of the application.</li>
</ul>
</div>
<div class="section" id="possible-solutions">
<h2>Possible solutions</h2>
<p>We could argue that way in which Django does not call <tt class="docutils literal">full_clean</tt> before it
writes instances to the database is the root of the problem - I’ve previously
<a class="reference external" href="https://jamescooke.info/djangos-model-save-vs-full_clean.html">written and spoken about this</a>. However, this is more a
“condition of the environment” and therefore something that we need to manage,
rather than fix.</p>
<p>Also, look at it another way. Any factory that integrates with Django can
inspect the target model and immediately find the constraints on each field.
Therefore with Django, factory libraries have all the information they need to
build a strategy for creating valid data. On top of that, Django provides the
<tt class="docutils literal">full_clean</tt> function so any generated data can also be checked for validity
before it’s sent to the database. Why should we have to re-code the constraints
already created for our models into our factories? This looks like duplication
of work.</p>
<p>So let’s explore how different factory libraries deal with this problem of
instances in the <tt class="docutils literal">D/V</tt> set - the white of the fried egg in the diagram.</p>
</div>
<div class="section" id="factory-libraries">
<h2>Factory libraries</h2>
<p>The following factory libraries have been explored:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/fcurella/django-fakery">Django Fakery</a></li>
<li><a class="reference external" href="https://github.com/FactoryBoy/factory_boy">Factory Boy</a><ul>
<li><a class="reference external" href="https://github.com/jamescooke/factory_djoy">Factory Djoy</a></li>
</ul>
</li>
<li><a class="reference external" href="https://hypothesis.readthedocs.io/en/latest/django.html">Hypothesis[django]</a></li>
<li><a class="reference external" href="https://github.com/klen/mixer">Mixer</a></li>
<li><a class="reference external" href="https://github.com/vandersonmota/model_mommy">Model Mommy</a></li>
</ul>
<p>Factory Djoy is my factory library. It’s a thin wrapper around Factory Boy
which does the hard work. I’ve indented it because it’s really a version of
Factory Boy than a standalone factory library.</p>
</div>
<div class="section" id="test-conditions">
<h2>Test conditions</h2>
<p>The code used to test the factory libraries is available in the <a class="reference external" href="https://github.com/jamescooke/factory_audit">Factory Audit
repository</a>. For each factory
library, two factories have been created in a default state, one targeting each
of the test Models:</p>
<ul>
<li><p class="first"><tt class="docutils literal">ItemFactory</tt>: to create and save instances of <tt class="docutils literal">plant.models.Item</tt>, a
test model defined <a class="reference external" href="https://github.com/jamescooke/factory_audit/blob/master/factory_audit/plant/models.py">in the ‘plant’ app</a>.</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Item</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Single Item with one required field 'name'</span>
<span class="sd"> """</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
<p>This example has been taken from the <a class="reference external" href="https://github.com/jamescooke/factory_audit">Factory_Djoy <span class="caps">README</span></a> but with a reduced length of
name down to one character to more easily force name collisions.</p>
</li>
<li><p class="first"><tt class="docutils literal">UserFactory</tt>: to create and save instances of the default
<tt class="docutils literal">django.contrib.auth</tt> User Model.</p>
</li>
</ul>
<p>The goal is that each factory should reliably generate 10 valid instances of
each model.</p>
<p>Wherever possible I’ve tried to be as explicit as possible and import the
target model, rather than refer to it by name as some factories allow.</p>
</div>
<div class="section" id="gradings">
<h2>Gradings</h2>
<p>Each factory library has been graded based on how its default configuration
behaves when used with the <tt class="docutils literal">Item</tt> and <tt class="docutils literal">User</tt> models.</p>
<p>The gradings are based on the definition of “valid”. Valid instances are ones
which will pass Django’s <tt class="docutils literal">full_clean</tt> and not raise a <tt class="docutils literal">ValidationError</tt>.
For example, using the <tt class="docutils literal">ItemFactory</tt> a generated item passes validation with:</p>
<div class="highlight"><pre><span></span><span class="n">item</span> <span class="o">=</span> <span class="n">ItemFactory</span><span class="p">()</span>
<span class="n">item</span><span class="o">.</span><span class="n">full_clean</span><span class="p">()</span>
</pre></div>
<p>The gradings are:</p>
<ul class="simple">
<li><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span> - Factory creates <strong>invalid</strong> instances of the model and
saves them to the database. These are instances in the <tt class="docutils literal">D/V</tt> set.</li>
<li><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span> - Factory raises an exception and does not save any
invalid instances. Preferably this would be a <tt class="docutils literal">ValidationError</tt>, but I’ve
also allowed <tt class="docutils literal">IntegrityError</tt> and <tt class="docutils literal">RunTimeError</tt> here.</li>
<li><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span> - Factory creates multiple <strong>valid</strong> instances with no
invalid instances created or skipped. Running factory <tt class="docutils literal">n</tt> times generates
<tt class="docutils literal">n</tt> valid instances.</li>
</ul>
<p>The tests on each of the factories have been written to pass when the factory
behaves to the expected grade. For example, the test on Factory Djoy’s
<tt class="docutils literal">ItemFactory</tt> expect that it raises <tt class="docutils literal">ValidationError</tt> each time it’s used
and <a class="reference external" href="https://github.com/jamescooke/factory_audit/blob/master/factory_audit/plant/tests/test_factory_djoy_factories.py#L12-L20">is therefore <span class="caps">YELLOW</span> grade</a>.</p>
</div>
<div class="section" id="results">
<h2>Results</h2>
<div class="section" id="original-results">
<h3>Original results</h3>
<table border="1" class="docutils">
<colgroup>
<col width="33%" />
<col width="33%" />
<col width="33%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Library</th>
<th class="head">ItemFactory</th>
<th class="head">UserFactory</th>
</tr>
</thead>
<tbody valign="top">
<tr><td><strong>Django Fakery</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
</tr>
<tr><td><strong>Factory Boy</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
</tr>
<tr><td><strong>Factory Djoy</strong></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Hypothesis[django]</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
</tr>
<tr><td><strong>Mixer</strong></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Model Mommy</strong></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="update">
<h3>Update</h3>
<p>Thanks to Piotr and Adam who pointed out some issues with my grading system.</p>
<p><strong>Adam</strong> pointed out that collisions are still collisions, even if they are
unlikely. Therefore, even if factories are employing fantastic strategies for
generating valid data, their generated instances should still be run through
<tt class="docutils literal">full_clean</tt> before save.</p>
<p>I agree with this opinion and think that calling <tt class="docutils literal">full_clean</tt> on every
instance creates the opportunity for two benefits, over and above asserting
that every instance is valid:</p>
<ul class="simple">
<li>If a factory raises <tt class="docutils literal">ValidationError</tt> with information on what failed it
will always be helpful to the developer who is fixing the broken test run.</li>
<li>If invalid data is found, this would create an opportunity for a factory to
adjust failing fields so that valid data can be saved and the test run will
not be interrupted.</li>
</ul>
<p>I’ve added a “Uses <tt class="docutils literal">full_clean</tt>” field to evaluate each factory and capture
this information.</p>
<p><strong>Piotr</strong> pointed out that the results of the grading are inconclusive since I
don’t agree with the results. For example, in the original results Mixer is the
only library that has <span class="caps">GREEN</span> <span class="caps">GREEN</span> and therefore we would assume that it is the
best of the factories tested. However, that’s not the case, since I found it
hard to use and its exception bubbling was also intrusive.</p>
<p>I’ve added the “Ease of use” grading to capture this information based on my
experience working with each factory.</p>
</div>
<div class="section" id="new-gradings">
<h3>New gradings</h3>
<ul class="simple">
<li>Uses <tt class="docutils literal">full_clean</tt>:<ul>
<li><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span> - Not instance of <tt class="docutils literal">full_clean</tt> in the factory code base.</li>
<li><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span> - Factory code base includes <tt class="docutils literal">full_clean</tt> in the
test suite only.</li>
<li><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span> - Factory tests every generated instance with
<tt class="docutils literal">full_clean</tt>.</li>
</ul>
</li>
<li>Ease of use:<ul>
<li><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span> - Do not bother trying. Too difficult to use.</li>
<li><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span> - Some pain may be experienced. You might struggle to
install, need to adjust your workflow, packages, etc.</li>
<li><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span> - Easy to install. Clean <span class="caps">API</span>.</li>
</ul>
</li>
</ul>
</div>
<div class="section" id="updated-results">
<h3>Updated results</h3>
<p>Results with additional “Uses <tt class="docutils literal">full_clean</tt> and “Ease of use” information:</p>
<table border="1" class="docutils">
<colgroup>
<col width="20%" />
<col width="20%" />
<col width="20%" />
<col width="19%" />
<col width="20%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Library</th>
<th class="head">ItemFactory</th>
<th class="head">UserFactory</th>
<th class="head">Uses <tt class="docutils literal">full_clean</tt></th>
<th class="head">Ease of use</th>
</tr>
</thead>
<tbody valign="top">
<tr><td><strong>Django Fakery</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Factory Boy</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Factory Djoy</strong></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Hypothesis[django]</strong></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
<tr><td><strong>Mixer</strong></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
</tr>
<tr><td><strong>Model Mommy</strong></td>
<td><img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
<td><img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></td>
<td><img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="section" id="notes-about-each-library">
<h2>Notes about each library</h2>
<p>Grading each library was often harder than I thought it would be because many
don’t fall into one grading or another. Where that has happened I’ve noted it below.</p>
<div class="section" id="django-fakery-1">
<h3>Django Fakery</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></p>
<p>Unfortunately, Django Fakery does not recognise that only one character is
allowed for the Item model’s <tt class="docutils literal">name</tt> field. It uses Latin words from a
generator which are saved by the default SQLite database and are invalid
because they are too long.</p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></p>
<p>In order to create <tt class="docutils literal">User</tt> instances Django Fakery also uses the Latin
generator which collides often. This means that <tt class="docutils literal">IntegrityError</tt> is raised
when collisions occur, but any Users created are valid.</p>
</li>
</ul>
</div>
<div class="section" id="factory-boy-1">
<h3>Factory Boy</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></p>
<p>Creates invalid instance of <tt class="docutils literal">Item</tt> which has no name and saves it.</p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></p>
<p>Creates <tt class="docutils literal">User</tt> with invalid <tt class="docutils literal">username</tt> and <tt class="docutils literal">password</tt> fields and
saves it.</p>
</li>
</ul>
<p>Factory Boy has no automatic strategies used for default factories and so it
fails this test hard. If the library was extended to call <tt class="docutils literal">full_clean</tt> for
generated instances before saving then it could be upgraded to <span class="caps">YELLOW</span>.</p>
</div>
<div class="section" id="factory-djoy-1">
<h3>Factory Djoy</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></p>
<p>Calls <tt class="docutils literal">full_clean</tt> on the <tt class="docutils literal">Item</tt> instance created by Factory Boy which it
wraps. This raises <tt class="docutils literal">ValidationError</tt> and the <tt class="docutils literal">Item</tt> is not saved.</p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></p>
<p>Creates valid instances using a <a class="reference external" href="https://factory-djoy.readthedocs.io/en/latest/userfactory.html#unique-usernames">simple strategy</a>
Unique <tt class="docutils literal">usernames</tt> are generated via Faker Factory which is already a
requirement of Factory Boy. <tt class="docutils literal">full_clean</tt> is called on the generated
instance to catch any collisions in the strategy and on collision, a new name
is generated and retried.</p>
</li>
</ul>
<p>Factory Djoy contains only one simple strategy for creating <tt class="docutils literal">Users</tt>. It has
no inspection ability to create strategies of its own based on Models.</p>
</div>
<div class="section" id="hypothesis-django-1">
<h3>Hypothesis[django]</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="red_circle" src="https://jamescooke.info/images/red_circle.png" style="width: 25px;" /> <span class="caps">RED</span></p>
<p>Hypothesis’s Django extra does not reliably create instances of either model
because it’s <tt class="docutils literal">example</tt> function does <a class="reference external" href="https://github.com/jamescooke/factory_audit/pull/4">not reliably generate valid data</a>. In the case that an
invalid example is generated it is skipped and the previous example is used.</p>
<p>Interestingly, Hypothesis creates <tt class="docutils literal">User</tt> instances that Django considers to
have invalid email addresses.</p>
</li>
<li><p class="first"><strong>Uses “full_clean“</strong> <img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></p>
<p>Hypothesis’s code base currently includes a <a class="reference external" href="https://github.com/HypothesisWorks/hypothesis-python/blob/f6230a6f72ea8c89543e8c56a44d0510fb662f5d/tests/django/toystore/test_given_models.py#L112">single instance</a> of <tt class="docutils literal">full_clean</tt>.
This is in its test suite to assert that instances built are valid. However,
it doesn’t call <tt class="docutils literal">full_clean</tt> on generated instances during its normal operation.</p>
</li>
</ul>
</div>
<div class="section" id="mixer-1">
<h3>Mixer</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></p>
<p>Mixer appears to inspect the <tt class="docutils literal">Item</tt> model and generates a very limited
strategy for generating names. Unfortunately it runs out of instances around
23, even though there are hundreds of characters available.</p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></p>
</li>
<li><p class="first"><strong>Ease of use</strong> <img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></p>
<p>Mixer helpfully raises <tt class="docutils literal">Runtime</tt> error if a strategy can’t generate a valid
instance. However, it echoes this to the standard out, which is annoying and
really confused me when I was first using it because exceptions appear on the
terminal even though all tests have passed.</p>
<p>It uses an old version of Fake Factory which meant that its tests had to be
extracted into a second test run that occurs after a <tt class="docutils literal"><span class="pre">pip-sync</span></tt> has taken
place. I found this the hardest factory library to work with.</p>
</li>
</ul>
</div>
<div class="section" id="model-mommy-1">
<h3>Model Mommy</h3>
<ul>
<li><p class="first"><strong>ItemFactory</strong> <img alt="yellow_heart" src="https://jamescooke.info/images/yellow_heart.png" style="width: 25px;" /> <span class="caps">YELLOW</span></p>
<p>There is no method used to create unique values so there are collisions
when there are a small number of possible values. Items that are
created are valid.</p>
</li>
<li><p class="first"><strong>UserFactory</strong> <img alt="green_heart" src="https://jamescooke.info/images/green_heart.png" style="width: 25px;" /> <span class="caps">GREEN</span></p>
<p>Model Mommy’s random text strategy works here for <tt class="docutils literal">username</tt> and the random
strings are unlikely to collide.</p>
</li>
</ul>
<p>Model Mommy depends on its strategies to create valid data and does not call
<tt class="docutils literal">full_clean</tt> meaning that <tt class="docutils literal">IntegrityError</tt> can be raises when collisions
occur. It could be argued that it should be downgraded to <span class="caps">YELLOW</span> because
<tt class="docutils literal">IntegrityError</tt> is raised.</p>
</div>
</div>
<div class="section" id="and-the-winner-is">
<h2>And the winner is?</h2>
<p>What is the best factory to use? This is a really hard question.</p>
<p>These factory libraries generally consist of two parts and different libraries
do each part well.</p>
<ul class="simple">
<li>Control / <span class="caps">API</span>: Personally I really like the Factory Boy <span class="caps">API</span> and how it
interfaces with Django. I’m happy with the Factory Djoy library because it
provides the certainly of calling <tt class="docutils literal">full_clean</tt> for every created instance
on top of the Factory Boy <span class="caps">API</span>.</li>
<li>Data strategy: I’m excited by Hypothesis and its ability to generate test data.</li>
</ul>
<p>My current advice is to use Factory Djoy, or wrap your favourite factory in a
call to <tt class="docutils literal">full_clean</tt>.</p>
<p>Yes, there is a performance overhead to calling <tt class="docutils literal">full_clean</tt> but my opinion
is that eliminating the <tt class="docutils literal">D/V</tt> set of invalid instances is worth the effort
and makes the test suite “fundamentally simpler” <a class="footnote-reference" href="#footnote-1" id="footnote-reference-1">[1]</a>.</p>
<p>My future thinking is that if Hypothesis can improve its interface to Django it
could be the winner.</p>
</div>
<div class="section" id="resources">
<h2>Resources</h2>
<ul class="simple">
<li><a class="reference external" href="https://github.com/jamescooke/factory_audit">Factory audit repository</a>:
Contains the research work - factories and tests for each factory library.
Pull requests very welcome - especially if they add a new factory library or
fix a test.</li>
<li><a class="reference external" href="https://speakerdeck.com/jamescooke/full-clean-factories">Slides</a>: From my
presentation of these results at the London Django October meetup.</li>
<li>Video: Available via the <a class="reference external" href="https://skillsmatter.com/skillscasts/9137-full-clean-factories">Skills Matter website</a>.</li>
<li>Thanks to Adam for pointing out the collisions issue which you can hear in
the video around 20 minutes in. Even if collisions are unlikely, they can
still be a problem. <a class="reference external" href="https://adamj.eu/tech/2014/09/03/factory-boy-fun/">Check out his Factory Boy post</a>.</li>
<li>The <a class="reference external" href="#update">15th October update</a> to the post is visible as a <a class="reference external" href="https://github.com/jamescooke/blog/pull/4">Pull
Request on the blog’s repository</a>.</li>
</ul>
<p>Happy fabricating!</p>
<table class="docutils footnote" frame="void" id="footnote-1" rules="none">
<colgroup><col class="label" /><col /></colgroup>
<tbody valign="top">
<tr><td class="label"><a class="fn-backref" href="#footnote-reference-1">[1]</a></td><td><!-- -->
<blockquote>
Taking a few percent hit, going a little slower, in order to do
something that’s just fundamentally simpler”</blockquote>
<p><a class="reference external" href="https://youtu.be/zFMdhXYlFfY?t=20m1s">Pycon <span class="caps">UK</span> 2016: Python and the Glories of the <span class="caps">UNIX</span> Tradition</a></p>
<p class="last">Brandon Rhodes, Pycon <span class="caps">UK</span> 2016</p>
</td></tr>
</tbody>
</table>
</div>
Cleaner unit testing with the Arrange Act Assert pattern2016-09-18T20:00:00+01:002016-09-18T20:00:00+01:00Jamestag:jamescooke.info,2016-09-18:/cleaner-unit-testing-with-the-arrange-act-assert-pattern.html<p class="first last">My PyConUK 2016 talk about the <span class="caps">AAA</span> pattern for unit tests and how
using it can help us all make our tests cleaner, easier to read
and as Pythonic as possible.</p>
<p>At <a class="reference external" href="https://2016.pyconuk.org/talks/cleaner-unit-testing-with-the-arrange-act-assert-pattern/">PyConUK 2016</a>
I spoke about the Arrange Act Assert pattern and how it can help clean up unit tests.</p>
<blockquote>
<strong>Note:</strong> A newer post <a class="reference external" href="https://jamescooke.info/arrange-act-assert-pattern-for-python-developers.html">Arrange Act Assert pattern for Python developers</a> is available. It has
much clearer examples and guidelines for using <span class="caps">AAA</span> than the video and
slides below.</blockquote>
<div class="section" id="original-proposal">
<h2>Original proposal</h2>
<p>PyConUK ask that we provide an explanation of why we think that attendees
will be interested in our talk. This was my original proposal’s reasoning.</p>
<blockquote>
<p>This talk focuses on developers that practise <span class="caps">TDD</span>, or want to use it
more in their coding.</p>
<p>My assumption is that our community feels a lot of pain from testing.
I’ve heard fellow developers talk about the difficulty with managing
complicated test suites; issues with reading and understanding others’
tests; and struggles when updating others’ tests. I hope that the
PyConUK attendees will have felt some of this pain be interested in a
talk that demonstrates the use of a pattern that can (hopefully)
mitigate some of it and help us all to be “cleaner” testers.</p>
<p>Although I’ve marked “moderately experienced” I think that my talk
would have a broad appeal: Those who are new to testing and would like
a “template” to follow. And those who are expert because of the
discussion about when to <span class="caps">DRY</span> out tests and how to assert that our test
refactors are safe.</p>
</blockquote>
</div>
<div class="section" id="slides-and-video">
<h2>Slides and video</h2>
<p>The video of the talk does not capture much of the screen, so the slides are
posted here too.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/GGw5T1mw9vU" frameborder="0" allowfullscreen></iframe><script async class="speakerdeck-embed" data-id="d25e0e15acef4ccc8fe70abba5adce03" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script></div>
<div class="section" id="resources">
<h2>Resources</h2>
<ul>
<li><p class="first"><a class="reference external" href="https://www.python.org/dev/peps/pep-0008/"><span class="caps">PEP08</span></a> and <a class="reference external" href="https://www.python.org/dev/peps/pep-0020/"><span class="caps">PEP20</span>, The Zen of Python</a>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://www.goodreads.com/book/show/387190.Test_Driven_Development">Kent Beck: Test Driven Development: By Example</a> - a
great book which references the <span class="caps">AAA</span> pattern (page 97).</p>
</li>
<li><p class="first"><a class="reference external" href="https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html">Google-style docstrings</a>:
In addition to using this style in my <span class="caps">AAA</span> tests, I’ve started to add a
<tt class="docutils literal">Trusts</tt> section to indicate which other tests are trusted by any
particular test and why.</p>
</li>
<li><p class="first"><a class="reference external" href="https://xp123.com/articles/3a-arrange-act-assert/">Bill Wake’s post about <span class="caps">AAA</span></a>: Bill Wake is cited by
Kent Beck as having coined the term <tt class="docutils literal">3A</tt>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://refactoring.com/catalog/extractMethod.html">Extract Method</a>: I’ve
used extract method as defined by Martin Fowler. See also <a class="reference external" href="https://refactoring.com/catalog/extractVariable.html">Extract Variable</a>.</p>
<blockquote>
<p><strong>Update August 2018:</strong> Check out <a class="reference external" href="https://flake8-aaa.readthedocs.io/en/stable/">flake8-aaa</a> - a Flake8 plugin that
makes it easier to write tests that follow the Arrange Act Assert pattern.</p>
</blockquote>
</li>
</ul>
</div>
<div class="section" id="finally">
<h2>Finally</h2>
<p>Thanks again to <a class="reference external" href="https://github.com/txels">Carles</a> for introducing me to the
<span class="caps">AAA</span> pattern.</p>
</div>
Python unittest: assertTrue is truthy, assertFalse is falsy2016-05-12T14:00:00+01:002016-05-12T14:00:00+01:00Jamestag:jamescooke.info,2016-05-12:/python-unittest-asserttrue-is-truthy-assertfalse-is-falsy.html<p class="first last">Exploring Python’s <tt class="docutils literal">unittest</tt> module boolean assert methods and how
they can be misleading in certain situations, but not if you <span class="caps">RTFM</span> of course.</p>
<p>In this post, I explore the differences between the unittest boolean assert
methods <tt class="docutils literal">assertTrue</tt> and <tt class="docutils literal">assertFalse</tt> and the <tt class="docutils literal">assertIs</tt> identity assertion.</p>
<div class="section" id="definitions">
<h2>Definitions</h2>
<p>Here’s what the <a class="reference external" href="https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue">unittest module documentation</a>
currently notes about <tt class="docutils literal">assertTrue</tt> and <tt class="docutils literal">assertFalse</tt>, with the appropriate
code highlighted:</p>
<blockquote>
<p><tt class="docutils literal">assertTrue(expr, msg=None)</tt></p>
<p><tt class="docutils literal">assertFalse(expr, msg=None)</tt></p>
<blockquote>
<p>Test that <em>expr</em> is true (or false).</p>
<p>Note that this is equivalent to</p>
<div class="highlight"><pre><span></span><span class="nb">bool</span><span class="p">(</span><span class="n">expr</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">True</span>
</pre></div>
<p>and not to</p>
<div class="highlight"><pre><span></span><span class="n">expr</span> <span class="ow">is</span> <span class="kc">True</span>
</pre></div>
<p>(use <tt class="docutils literal">assertIs(expr, True)</tt> for the latter).</p>
</blockquote>
</blockquote>
<p><a class="reference external" href="https://developer.mozilla.org/en-US/docs/Glossary/Truthy">Mozilla Developer Network defines truthy</a> as:</p>
<blockquote>
A value that translates to true when evaluated in a Boolean context.</blockquote>
<p>In Python this is equivalent to:</p>
<div class="highlight"><pre><span></span><span class="nb">bool</span><span class="p">(</span><span class="n">expr</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">True</span>
</pre></div>
<p>Which exactly matches what <tt class="docutils literal">assertTrue</tt> is testing for.</p>
<p>Therefore the documentation already indicates <tt class="docutils literal">assertTrue</tt> is truthy and
<tt class="docutils literal">assertFalse</tt> is falsy. These assertion methods are creating a <tt class="docutils literal">bool</tt> from
the received value and then evaluating it. It also suggests that we really
shouldn’t use <tt class="docutils literal">assertTrue</tt> or <tt class="docutils literal">assertFalse</tt> for very much at all.</p>
</div>
<div class="section" id="what-does-this-mean-in-practice">
<h2>What does this mean in practice?</h2>
<p>Let’s use a very simple example - a function called <tt class="docutils literal">always_true</tt> that
returns <tt class="docutils literal">True</tt>. We’ll write the tests for it and then make changes to the
code and see how the tests perform.</p>
<p>Starting with the tests, we’ll have two tests. One is “loose”, using
<tt class="docutils literal">assertTrue</tt> to test for a truthy value. The other is “strict” using
<tt class="docutils literal">assertIs</tt> as recommended by the documentation:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unittest</span>
<span class="kn">from</span> <span class="nn">func</span> <span class="kn">import</span> <span class="n">always_true</span>
<span class="k">class</span> <span class="nc">TestAlwaysTrue</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_assertTrue</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> always_true returns a truthy value</span>
<span class="sd"> """</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">always_true</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertTrue</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_assertIs</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> always_true returns True</span>
<span class="sd"> """</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">always_true</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertIs</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
</pre></div>
<p>Here’s the code for our simple function in <tt class="docutils literal">func.py</tt>:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">always_true</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> I'm always True.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="kc">True</span>
</pre></div>
<p>When run, everything passes:</p>
<pre class="literal-block">
always_true returns True ... ok
always_true returns a truthy value ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.004s
OK
</pre>
<p>Happy days!</p>
<p>Now, “someone” changes <tt class="docutils literal">always_true</tt> to the following:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">always_true</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> I'm always True.</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: True</span>
<span class="sd"> """</span>
<span class="k">return</span> <span class="s1">'True'</span>
</pre></div>
<p>Instead of returning <tt class="docutils literal">True</tt> (boolean), it’s now returning string <tt class="docutils literal">'True'</tt>.
(Of course this “someone” hasn’t updated the docstring - we’ll raise a ticket later.)</p>
<p>This time the result is not so happy:</p>
<pre class="literal-block">
always_true returns True ... FAIL
always_true returns a truthy value ... ok
======================================================================
FAIL: always_true returns True
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/assertttt/test.py", line 22, in test_is_true
self.assertIs(result, True)
AssertionError: 'True' is not True
----------------------------------------------------------------------
Ran 2 tests in 0.004s
FAILED (failures=1)
</pre>
<p>Only <em>one</em> test failed! This means <tt class="docutils literal">assertTrue</tt> gave us a false-positive. It
passed when it shouldn’t have. It’s lucky we wrote the second test with
<tt class="docutils literal">assertIs</tt>.</p>
<p>Therefore, just as we learned from the manual, to keep the functionality of
<tt class="docutils literal">always_true</tt> pinned tightly the stricter <tt class="docutils literal">assertIs</tt> should be used rather
than <tt class="docutils literal">assertTrue</tt>.</p>
</div>
<div class="section" id="use-assertion-helpers">
<h2>Use assertion helpers</h2>
<p>Writing out <tt class="docutils literal">assertIs</tt> to test for <tt class="docutils literal">True</tt> and <tt class="docutils literal">False</tt> values is not too
lengthy. However, if you have a project in which you often need to check that
values are exactly <tt class="docutils literal">True</tt> or exactly <tt class="docutils literal">False</tt>, then you can make yourself
the <tt class="docutils literal">assertIsTrue</tt> and <tt class="docutils literal">assertIsFalse</tt> assertion helpers.</p>
<p>This doesn’t save a particularly large amount of code, but it does improve
readability in my opinion.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">assertIsTrue</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertIs</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">assertIsFalse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertIs</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<div class="section" id="summary">
<h2>Summary</h2>
<p>In general, my recommendation is to keep tests as tight as possible. If you
mean to test for the exact value <tt class="docutils literal">True</tt> or <tt class="docutils literal">False</tt>, then follow the
<a class="reference external" href="https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue">documentation</a>
and use <tt class="docutils literal">assertIs</tt>. Do not use <tt class="docutils literal">assertTrue</tt> or <tt class="docutils literal">assertFalse</tt> unless you
really have to.</p>
<p>If you are looking at a function that can return various types, for example,
sometimes <tt class="docutils literal">bool</tt> sometimes <tt class="docutils literal">int</tt>, then consider refactoring. This is a code
smell and in Python, that <tt class="docutils literal">False</tt> value for an error would probably be better
raised as an exception.</p>
<p>In addition, if you really need to assert the return value from a function
under test is truthy, there might be a second code smell - is your code
correctly encapsulated? If <tt class="docutils literal">assertTrue</tt> and <tt class="docutils literal">assertFalse</tt> are asserting
that function return values will trigger <tt class="docutils literal">if</tt> statements correctly, then it
might be worth sense-checking you’ve encapsulated everything you intended in
the appropriate place. Maybe those <tt class="docutils literal">if</tt> statements should be encapsulated
within the function under test.</p>
<p>Happy testing!</p>
</div>
API Documentation and the Communication Illusion2016-05-04T12:00:00+01:002016-05-04T12:00:00+01:00Jamestag:jamescooke.info,2016-05-04:/api-documentation-and-the-communication-illusion.html<p class="first last">How can documenting an <span class="caps">API</span> help us to communicate with our team and
<span class="caps">API</span> consumer developers efficiently?</p>
<p>In this post I talk quite a lot about the “Communication Illusion” - a quote
often <a class="reference external" href="https://en.wikiquote.org/wiki/George_Bernard_Shaw#Misattributed">misattributed to George Bernard Shaw</a>:</p>
<blockquote>
The single biggest problem in communication is the illusion that it has
taken place.</blockquote>
<p>Now let’s talk about documenting APIs…</p>
<div class="section" id="api-documentation-and-my-current-workflow">
<h2><span class="caps">API</span> documentation and my current workflow</h2>
<p>When I’m building an <span class="caps">API</span>, I usually have a client in mind that will be
consuming its resources. That means a developer or team of developers will be
writing code against the <span class="caps">API</span> that I build and so my current workflow for
updating or creating new <span class="caps">API</span> services focuses on providing <span class="caps">API</span> documentation.</p>
<p>It works like this:</p>
<ul>
<li><p class="first">Manually document the endpoint using <a class="reference external" href="https://github.com/jamescooke/restapidocs"><span class="caps">REST</span> <span class="caps">API</span> documentation templates</a>. Highlight any side effects,
requirements and illustrate required data and responses.</p>
<p>Alternatively, if there is a change to be made to the service, then the
documentation edit can be provided as an <span class="caps">SCM</span> diff which can be easily reviewed.</p>
</li>
<li><p class="first">Ask for sign off on the <span class="caps">API</span> documentation from the <span class="caps">API</span> consumer development
team. Incorporate any feedback and repeat until team are happy.</p>
</li>
<li><p class="first">Build out new endpoint using test cases written from the documentation.</p>
</li>
<li><p class="first">Once complete, export server responses back from the test suite into the
documentation. Note any changes that were required to the signed off document
and flag them to the consumer developers during the release process, if not beforehand.</p>
</li>
</ul>
</div>
<div class="section" id="past-experience-of-communications-illusions">
<h2>Past experience of Communications Illusions</h2>
<p>In conversations with other developers about my process it’s been called
“tedious”. I can agree that it seems like extra effort at first, however, I
believe that it pays off in the long run and that belief is based on my past
experience at my old web development business, Fublo.</p>
<p>At Fublo, we often produced <a class="reference external" href="https://en.wiktionary.org/wiki/brochureware">brochureware</a> sites on top of a simple <span class="caps">CMS</span>
system. When starting a new project, conversation within our team would often
happen like this:</p>
<blockquote>
We know the solution to the problem, so instead of drawing out the design,
let’s just jump straight into <span class="caps">HTML</span> and code it up. This will save time.</blockquote>
<p>Inevitably this didn’t save time at all. We would often have to burn much of
our initial work because we couldn’t fit the final client requirements into it,
or rework major structural elements because they turned out to be unsuitable.</p>
<p>This inefficiency is the result of three illusions:</p>
<ul class="simple">
<li><strong>The illusion with ourselves:</strong> When we thought that we knew the solution
and that it would be suitable and workable, this was just an illusion. Our
minds tricked us into thinking that we knew the answer but we didn’t.</li>
<li><strong>The Communications Illusion within the team:</strong> This was in full effect
within our small team. We found that what we described as the problem to each
other would fit with our own distorted view and we would only find out that
our opinions were not the same some significant time after starting the
build - sometimes too late to make changes.</li>
<li><strong>The Communications Illusion with the client:</strong> We also didn’t often fully
understand the client need, even though we thought we did at the outset.
Sometimes there would be omissions in the brief or misunderstandings about
how content would be provided, presented or managed.</li>
</ul>
<p>Those three illusions sum up to one big Communications Illusion - we believe
that we, our team and our clients all have tallying opinions and ideas, when
there is no proof that that is the case.</p>
<p>Pretty quickly, but probably not as quickly as we would have liked, we realised
that the “tedious” way of producing flat designs before starting coding was
often the most efficient, even though it felt like it wasn’t. It provided the
quickest route to a communication feedback loop, within ourselves, our team and
with our clients and that destroys the Communication Illusion. On top of that
it meant that we were not making any accidental, hard to refactor, architectural
decisions on the fly without all the required information.</p>
</div>
<div class="section" id="applying-this-to-api-design">
<h2>Applying this to <span class="caps">API</span> design</h2>
<p>So it’s my opinion that producing a flat <span class="caps">API</span> document without touching a line
of code or writing a single test is the most efficient way of destroying the
potential Communications Illusions when creating APIs.</p>
<p>This means that providing static <span class="caps">API</span> documentation first is the most efficient
path to a place where <span class="caps">API</span> producers and consumers have a joint shared opinion
about how the <span class="caps">API</span> will operate and perform.</p>
</div>
<div class="section" id="tooling-wishlist">
<h2>Tooling wishlist</h2>
<p>On the flip side of those benefits in the long term, there is still a part of
me that finds some of my manual process a little slow. My inner need for
efficiency feels unfulfilled every time I copy and paste an <span class="caps">API</span> response into a document.</p>
<p>In an ideal world I would have tools that would:</p>
<ul class="simple">
<li>Extract from the <span class="caps">API</span> documentation a set of tests that could be run against
the built <span class="caps">API</span> to assert that the documentation features were all adhered to.</li>
<li>A tool that would extract from the server responses made to these tests the
response payloads so that they could be added back in or matched with the <span class="caps">API</span>
document that they came from.</li>
</ul>
<p>However, even if those tools did exist, the starting point would still be some
form of static documentation that describes what the <span class="caps">API</span> does.</p>
<p>I’ve seen that there are tools like <a class="reference external" href="https://apiary.io/">Apiary</a> which might
make this process easier, but I would want to hear some positive experience and
read a case study before I committed to using such a service for client work.</p>
</div>
<div class="section" id="final-thoughts">
<h2>Final thoughts</h2>
<p>So, I hope in this post I’ve been able to convince you that it’s most
efficient to document your <span class="caps">API</span> before you build or change it. I hope that, like
me, you find that that efficiency comes from the increase in communication that
the documentation creates as a side-effect, destroying the Communication
Illusion that can ruin a project build.</p>
<p>Unfortunately, I’ve not found a way to ensure that the consumer programmers of
my APIs read and understand what’s in the documentation before coding starts.
That’s a second layer of Communication Illusion that I’ll maybe get to tackle
another day.</p>
<p>Happily, I still agree with this (old, now deleted) Tweet that I posted more
than 18 months ago:</p>
<blockquote>
<p>Building an <span class="caps">API</span>… All that matters is the docs.</p>
<p>October 3, 2014</p>
</blockquote>
<p>…and in fact, after working on more <span class="caps">API</span> builds and writing this post, I
believe it’s even more true than before.</p>
<p>Happy <span class="caps">API</span> building!</p>
<ul class="simple">
<li><a class="reference external" href="https://news.ycombinator.com/item?id=11666301">Read comments on Hacker News</a></li>
</ul>
</div>
Comparing Django Q Objects2016-03-28T12:00:00+01:002016-03-28T12:00:00+01:00Jamestag:jamescooke.info,2016-03-28:/comparing-django-q-objects.html<p class="first last">A super simple assertion helper for comparing instances of Django’s Q objects.</p>
<div class="section" id="background">
<h2>Background</h2>
<blockquote>
<strong>Note:</strong> A newer version of this post exists with an assertion helper for
<a class="reference external" href="https://jamescooke.info/comparing-django-q-objects-in-python-3-with-pytest.html">Python 3 and pytest</a>. Read on for
Python 2 and unittest and general background on Q objects…</blockquote>
<p>When programmatically building complex queries in Django <span class="caps">ORM</span>, it’s helpful
to be able to test the resulting <a class="reference external" href="https://docs.djangoproject.com/en/1.8/topics/db/queries/#complex-lookups-with-q">Q object instances</a>
against each other.</p>
<p>However, Django’s Q object does not implement <tt class="docutils literal">__cmp__</tt> and neither does
<tt class="docutils literal">Node</tt> which it extends (<tt class="docutils literal">Node</tt> is in the <tt class="docutils literal">django.utils.tree</tt> module).</p>
<p>Unfortunately, that means that comparison of Q objects that are equal fails.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">thing</span><span class="o">=</span><span class="s1">'value'</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">b</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">thing</span><span class="o">=</span><span class="s1">'value'</span><span class="p">)</span>
<span class="o">>>></span> <span class="k">assert</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">)</span>
<span class="o">...</span>
<span class="n">Assertion</span> <span class="n">Error</span><span class="p">:</span>
</pre></div>
<p>This means that writing unit tests that assert that correct Q objects have been
created is hard.</p>
</div>
<div class="section" id="a-simple-solution">
<h2>A simple solution</h2>
<p>Q objects generate great Unicode representations of themselves:</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">a</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">place</span><span class="o">=</span><span class="s1">'Residential'</span><span class="p">)</span> <span class="o">&</span> <span class="n">Q</span><span class="p">(</span><span class="n">people__gt</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">unicode</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="sa">u</span><span class="s2">"(AND: ('place', 'Residential'), ('people__gt', 5))"</span>
</pre></div>
<p>In addition, it is “good” testing practice to write assertion helpers whenever
a test suite has complicated assertions to make frequently. This provides an
opportunity to <span class="caps">DRY</span> out test code and expand on any error messages that are
raised on failure.</p>
<p>Therefore a really simple solution is an assertion helper that would compare Q
objects by:</p>
<ul class="simple">
<li>Asserting that left and right sides are both instances of <tt class="docutils literal">Q</tt>.</li>
<li>Asserting that the Unicode for the left and right sides are identical.</li>
</ul>
<p>So here’s a mixin containing the assertion helper. It can be added to any class
that extends <tt class="docutils literal">unittest.TestCase</tt> (such as Django’s default <tt class="docutils literal">TestCase</tt>):</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
<span class="k">class</span> <span class="nc">QTestMixin</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">assertQEqual</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Assert `Q` objects are equal by ensuring that their</span>
<span class="sd"> unicode outputs are equal (crappy but good enough)</span>
<span class="sd"> """</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertIsInstance</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">Q</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertIsInstance</span><span class="p">(</span><span class="n">right</span><span class="p">,</span> <span class="n">Q</span><span class="p">)</span>
<span class="n">left_u</span> <span class="o">=</span> <span class="n">unicode</span><span class="p">(</span><span class="n">left</span><span class="p">)</span>
<span class="n">right_u</span> <span class="o">=</span> <span class="n">unicode</span><span class="p">(</span><span class="n">right</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">left_u</span><span class="p">,</span> <span class="n">right_u</span><span class="p">)</span>
</pre></div>
<p>Disadvantage of this method is that it is simplistic and doesn’t find all the Q
objects that are identical (see below). However, the advantage is that it
provides rich diffs on failure:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">TestFail</span><span class="p">(</span><span class="n">TestCase</span><span class="p">,</span> <span class="n">QTestMixin</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_unhappy</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Two Q objects are not the same</span>
<span class="sd"> """</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">place</span><span class="o">=</span><span class="s1">'Residential'</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">place</span><span class="o">=</span><span class="s1">'Palace'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertQEqual</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
</pre></div>
<p>Gives output:</p>
<div class="highlight"><pre><span></span>AssertionError:<span class="w"> </span>u<span class="s2">"(AND: ('place', 'Residential'))"</span><span class="w"> </span>!<span class="o">=</span><span class="w"> </span>u<span class="s2">"(AND: ('place', 'Palace'))"</span>
-<span class="w"> </span><span class="o">(</span>AND:<span class="w"> </span><span class="o">(</span><span class="s1">'place'</span>,<span class="w"> </span><span class="s1">'Residential'</span><span class="o">))</span>
?<span class="w"> </span>^^^^^^^^^
+<span class="w"> </span><span class="o">(</span>AND:<span class="w"> </span><span class="o">(</span><span class="s1">'place'</span>,<span class="w"> </span><span class="s1">'Palace'</span><span class="o">))</span>
?<span class="w"> </span>^<span class="w"> </span>+++
</pre></div>
<p>Which can be very helpful when trying to track down errors.</p>
<blockquote>
See this <a class="reference external" href="https://jamescooke.info/comparing-django-q-objects-in-python-3-with-pytest.html">updated post</a> for a version of
this assertion helper for Python 3 with pytest.</blockquote>
</div>
<div class="section" id="the-perfect-world-predicate-logic">
<h2>The perfect world: Predicate Logic</h2>
<p>Since Q objects represent the logic of <span class="caps">SQL</span> <tt class="docutils literal"><span class="caps">WHERE</span></tt> clauses they are therefore
Python representations of predicates. In an ideal world the predicate logic
rules of equality could be used to compare Q objects and this would be built
directly into <tt class="docutils literal">Q.__cmp__</tt>.</p>
<p>This would mean that:</p>
<div class="highlight"><pre><span></span><span class="c1"># WARNING MAGIC IMAGINARY CODE!</span>
<span class="c1"># Commutative would work</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">b</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="kc">True</span>
<span class="c1"># Double negation would work</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">b</span> <span class="o">=</span> <span class="o">~~</span><span class="p">(</span><span class="n">Q</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="kc">True</span>
<span class="c1"># Negation on expression would work</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">=</span> <span class="o">~</span><span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">&</span> <span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
<span class="o">>>></span> <span class="n">b</span> <span class="o">=</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="o">|</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="o">>>></span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span>
<span class="kc">True</span>
<span class="c1"># END IMAGINATION SECTION</span>
</pre></div>
<p>This is probably never going to be implemented in Django, because it would be
functionality only used (as far as I can see) for testing. In addition, without
a special implementation for rendering Q objects diffs, it would be hard to
understand the source of errors when mismatches occur.</p>
</div>
<div class="section" id="final-testing-related-notes">
<h2>Final testing related notes</h2>
<ul class="simple">
<li>When a suite has complicated assertions to test regularly, create an
assertion helper. Write tests to show that your helper works correctly under
various conditions.</li>
<li>Tests for <tt class="docutils literal">assertQEqual</tt> are <a class="reference external" href="https://gist.github.com/jamescooke/b9bd5afba3a7253d53bd">in this gist</a>. (If you spot
something missing, please let me know!)</li>
<li>Always consider the output of failing tests - the complexity of managing a
test suite for a software project can be greatly influenced by how
informative assertion errors are when they occur.</li>
<li>A secondary assertion helper could be created to check for inequality
<tt class="docutils literal">assertQNotEquals</tt>.</li>
</ul>
</div>
Django’s model save vs full_clean2015-11-15T17:00:00+00:002015-11-15T17:00:00+00:00Jamestag:jamescooke.info,2015-11-15:/djangos-model-save-vs-full_clean.html<p class="first last">Confirming that Django can screw up your data when saving, and
exploring why this is still the case.</p>
<div class="section" id="screwing-up-data">
<h2>Screwing up data</h2>
<p>At a previous talk I gave on <a class="reference external" href="/things-i-wish-id-known-about-django.html">“Things I wish I’d known about Django”</a> there was this slide:</p>
<script async class="speakerdeck-embed" data-slide="6" data-id="6f327318d302437f8ccafb8da4c2cd32" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script></div>
<div class="section" id="what">
<h2>What?</h2>
<p>I’ve made some experimental code in a <a class="reference external" href="https://github.com/jamescooke/django-clean-vs-save">small Django clean vs save project</a>. It has a few models
and a <a class="reference external" href="https://github.com/jamescooke/django-clean-vs-save/blob/master/clean_vs_save/clean_vs_save/tests.py">single test file</a>
which is readable and passes.</p>
<p>The main take-aways are:</p>
<ul class="simple">
<li>Creating an instance of a Model and calling <tt class="docutils literal">save</tt> on that instance does
not call <tt class="docutils literal">full_clean</tt>. Therefore it’s possible for invalid data to enter
your database if you don’t manually call the <tt class="docutils literal">full_clean</tt> function before saving.</li>
<li>Object managers’ default <tt class="docutils literal">create</tt> function also doesn’t call
<tt class="docutils literal">full_clean</tt>.</li>
</ul>
<p>Personally I find this jarring.</p>
<p>Given that the developer is the customer of Django I think it conflicts with
the <a class="reference external" href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment">principle of least astonishment</a>.</p>
</div>
<div class="section" id="why-is-it-like-this">
<h2>Why is it like this?</h2>
<p>The <a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects">Django documentation of Validating Objects</a>
is quoted in <a class="reference external" href="https://code.djangoproject.com/ticket/13100">Django ticket #13100</a> as saying:</p>
<blockquote>
Note that full_clean() will <span class="caps">NOT</span> be called automatically when you call your
model’s save() method. You’ll need to call it manually if you want to run
model validation outside of a ModelForm. (This is for backwards
compatibility.)</blockquote>
<p><strong>Ahh “backwards compatibility”?!</strong></p>
<p>It appears that phrase only lived for four months back in 2010.</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/django/django/commit/4d6c66d4d8fa63005f8ca2d3fbae195922969d13">Created 5th Jan 2010</a></li>
<li><a class="reference external" href="https://github.com/django/django/commit/4a15dc450996b62596d74f8d98388c9e2f4a10c7#diff-5b33a9c46f488003c1846ef677f861d3L56">Removed 9th May 2010</a></li>
</ul>
<p>I haven’t been able to find any more specific reasons that it was added or removed.</p>
</div>
<div class="section" id="what-next">
<h2>What next?</h2>
<p>More warnings I guess:</p>
<ul class="simple">
<li>Consider if you ever want to be able to call <tt class="docutils literal">save</tt> <strong>without</strong>
<tt class="docutils literal">full_clean</tt>. If the answer is ‘no’, then explore how you’ll wrap your
models in business logic or extend them in some way that implements this
(with tests of course). A quick search of the internet will show you some
Django plugins that adjust this behaviour.</li>
<li>Remember that you can ruin your database when migrating if you don’t call
<tt class="docutils literal">full_clean</tt> after the migration has changed a model but before saving. All
migrations should be tested to ensure that they can roll-back if
<tt class="docutils literal">full_clean</tt> raises a <tt class="docutils literal">ValidationError</tt> during migration.</li>
<li>Check out posts like <a class="reference external" href="http://dev.nando.audio/2014/04/04/why_i_sort_of_dislike_django.html">Why I sort of dislike Django</a>. It
mentions things like backwards compatibility and the <tt class="docutils literal">save</tt> function.</li>
</ul>
</div>
<div class="section" id="finally">
<h2>Finally</h2>
<p>Thanks to <a class="reference external" href="https://twitter.com/petexgraham"><span class="caps">PXG</span></a> for sharing the “Why I sort
of dislike Django” post and discussing Django project structures with me.</p>
<p>Thanks for reading!</p>
</div>
Irregular Vim2015-08-16T21:00:00+01:002015-08-16T21:00:00+01:00Jamestag:jamescooke.info,2015-08-16:/irregular-vim.html<p class="first last">At July’s Vim London I gave a talk about some of Vim’s irregular
behaviours. Using bare-bones Vim to present and demonstrate from is a
risky business!</p>
<p>My frustrations with Vim arise when it makes actions that are unexpected. At
<a class="reference external" href="https://www.meetup.com/Vim-London/events/223784891/">Vim London</a> I presented
some of my “pet misbehaviours” - these are the ones that affect my regular use
of Vim.</p>
<div class="section" id="background">
<h2>Background</h2>
<p>If you’re new to Vim then one of the key features of Vim is that it’s a modal
editor. As a result, to quote a quote from a <a class="reference external" href="/vi-nature-everywhere-lightning-talk.html">previous talk</a>:</p>
<blockquote>
The “Zen” of vi is that you’re speaking a language.</blockquote>
<p>So what happens when a language has many irregularities and frequently broken
rules? They become hard to learn. For example the <a class="reference external" href="https://www.oxford-royale.co.uk/articles/learning-english-hard.html">English language is hard</a> because:</p>
<blockquote>
… although there are rules, there are lots of exceptions to those rules.</blockquote>
<p>My fear is that if Vim is hard to learn it will be overlooked by new users and
it will cease to exist in the future. I think we should all be working on the
maxim that Drew has put on the <a class="reference external" href="https://www.meetup.com/Vim-London/">Vim London meetup page</a>:</p>
<blockquote>
Use Vim better, make Vim better.</blockquote>
</div>
<div class="section" id="pet-misbehaviours">
<h2>Pet misbehaviours</h2>
<p>Here are the five behaviours looked at in this talk, each one linked to its
section in the slides on Github.</p>
<ul>
<li><p class="first"><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides/blob/master/slides/10a_motion_exceptions.rst">Linewise motions always include the start and end position</a></p>
<p><strong>Except</strong> when the end of the motion is in column 1.</p>
</li>
<li><p class="first"><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides/blob/master/slides/15a_change_is_delete_insert.rst">Change is equivalent to Delete Insert</a></p>
<p><strong>Except</strong> when motion is <tt class="docutils literal">w</tt>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides/blob/master/slides/20a_pasting_and_registers.rst">Pasting from registers is easily repeatable</a></p>
<p><strong>Except</strong> when in visual modes.</p>
</li>
<li><p class="first"><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides/blob/master/slides/25a_add_number.rst">Incrementing number after cursor is predictable</a></p>
<p><strong>Except</strong> when the number starts with a <tt class="docutils literal">0</tt>.</p>
</li>
<li><p class="first"><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides/blob/master/slides/30a_ctrl_o_goes_jump_older.rst"><span class="caps">CTRL</span>-O goes back to old cursor position</a></p>
<p><strong>Except</strong> when in visual modes.</p>
</li>
</ul>
</div>
<div class="section" id="testing-process">
<h2>Testing process</h2>
<p>Automated and predictable testing is an important part of how I work and so I
attempted to use a repeatable process for testing each of the behaviours.</p>
<ol class="arabic simple">
<li>Outline the <strong>assumption</strong> about Vim. Highlight the docs (where available)
that make the statement or assertion.</li>
<li>Do some small <strong>tests</strong> of this assertion. Does it work as expected? How do
we feel about the behaviour?</li>
<li>Update the assertion with any <strong>exceptions</strong> and look at any reasons for
those exceptions.</li>
</ol>
</div>
<div class="section" id="content">
<h2>Content</h2>
<p><a class="reference external" href="https://vimeo.com/135055397">Video on vimeo</a> (thanks <a class="reference external" href="https://twitter.com/nelstrom">Drew</a>).</p>
<iframe src="//player.vimeo.com/video/135055397" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><p><a class="reference external" href="https://github.com/jamescooke/irregular-vim-slides">Slides are on GitHub</a>.</p>
</div>
<div class="section" id="learnings">
<h2>Learnings</h2>
<p>One of my annoyances that started this journey arose when attempting to delete
everything up to but not including a character. As you’ll see at the end of the
talk, I learned a new movement command <tt class="docutils literal">t</tt> (thanks Audience!).</p>
<p><tt class="docutils literal">t</tt> is like <tt class="docutils literal">f</tt> but not inclusive. From the help <tt class="docutils literal">:help t</tt> file:</p>
<blockquote>
Till before [count]’th occurrence of {char} to the right. The cursor is
placed on the character left of {char} inclusive. {char} can be entered
like with the f command.</blockquote>
<p>This exactly solves the problem that started my exploration of Vim’s
irregularities. It’s a humbling experience when you talk for 20 minutes about
Vim commands and still learn a ‘basic’ one at the end of the talk. I think that
this is a reminder to me that Vim is deep.</p>
</div>
<div class="section" id="future">
<h2>Future</h2>
<p>I would like to improve these misbehaviours and make them more regular. My hope
is that, if this could be achieved, it would make Vim’s interface even more
great and also easier to learn.</p>
<p>The main thing for me going forwards is to use <a class="reference external" href="https://neovim.io/">Neovim</a>. A
project that is open to improving how Vim works. Here’s a great post about <a class="reference external" href="https://geoff.greer.fm/2015/01/15/why-neovim-is-better-than-vim/">why
Neovim is better than Vim</a> - thanks
<a class="reference external" href="https://twitter.com/ggreer">Geoff</a>.</p>
<p>From there I will check out how many of these irregularities can be improved
with code changes because having to have a <tt class="docutils literal">vimrc</tt> file that resets Vim to
‘regular’ behaviour by turning off things like octal numerical increments seems
horrible and repellent to new users.</p>
<p>We can do better.</p>
</div>
<div class="section" id="thanks">
<h2>Thanks</h2>
<ul class="simple">
<li><a class="reference external" href="https://twitter.com/nelstrom">Drew</a> for asking me to talk and providing
the <tt class="docutils literal">cw</tt> example.</li>
<li><a class="reference external" href="https://twitter.com/krisajenkins">Kris</a> for inspiring me at my first Vim
London meetup with <a class="reference external" href="https://vimeo.com/65250028">Barebones Vim navigation</a>.
This showed me so much about Vim that I didn’t know and also that you <strong>can</strong>
do a high quality presentation from Vim. (I hope that one day I’ll be able to
meet your standard Kris).</li>
</ul>
<p>And thanks to you for reading!</p>
</div>
Things I wish I’d known about Django2015-07-18T20:00:00+01:002015-07-18T20:00:00+01:00Jamestag:jamescooke.info,2015-07-18:/things-i-wish-id-known-about-django.html<p class="first last">Django has been my go-to web framework for about three years. But I
wish I’d started with it sooner. This became a talk which I gave at
the London Django meetup in July this year.</p>
<p>This month at <a class="reference external" href="https://www.meetup.com/The-London-Django-Meetup-Group/events/223297765/">The London Django meetup</a> I
gave a talk about some of the things I wish I’d known about Django (before I started).</p>
<br>
<script async class="speakerdeck-embed" data-id="6f327318d302437f8ccafb8da4c2cd32" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>
<br><div class="section" id="thanks">
<h2>Thanks</h2>
<p>My thanks to <a class="reference external" href="https://github.com/zalun">Piotr</a>, who I mentioned in the talk.
For years he told me to check out <a class="reference external" href="https://www.djangoproject.com/">Django</a>
because “it does things right”. Only when I’d truly broken myself with <span class="caps">PHP</span> did
I take his advice and I haven’t looked back.</p>
<p>Django opened the door for me to:</p>
<ul class="simple">
<li><strong>Python</strong> which has become my backend language of choice.</li>
<li><strong>Test Driven Development</strong> which has become a way of life.</li>
</ul>
</div>
<div class="section" id="more-power">
<h2>More Power</h2>
<p>When I’m developing for web and using Django, I think it’s possible for me to
keep more features live with fewer errors than was previously possible for me
with <span class="caps">PHP</span> based tools. I put this down to two main things:</p>
<ul class="simple">
<li>The application of tests in my Django projects. I’m particularly happy with
the test suite provided by Django. Where I’ve needed to rewire it or patch
it, it’s responded well.</li>
<li>The structure that Django provides, without enforcing how projects are built.</li>
</ul>
</div>
<div class="section" id="summary">
<h2>Summary</h2>
<p>I wish I’d jumped into Django sooner. If you’re thinking about transitioning to
it, see what you can do today. I think it pays back in the long run.</p>
<p>Thanks for reading.</p>
</div>
A water pouring problem sketched in Python2015-01-09T10:00:00+00:002015-01-09T10:00:00+00:00Jamestag:jamescooke.info,2015-01-09:/a-water-pouring-problem-sketched-in-python.html<p class="first last">A small Python 3 sketch of a solution to a water pouring problem.</p>
<div class="section" id="the-problem">
<h2>The problem</h2>
<p>At the end of last year, I came across the following water pouring problem
because something similar had come up in a friend’s functional programming interview:</p>
<blockquote>
<strong>There are three glasses on the table - 3, 5, and 8 oz. The first two are
empty, the last contains 8 oz of water. By pouring water from one glass to
another make at least one of them contain exactly 4 oz of water.</strong></blockquote>
<p><em>Source: A. Bogomolny,</em> <a class="reference external" href="https://www.cut-the-knot.org/water.shtml">3 Glasses Puzzle from Interactive Mathematics
Miscellany and Puzzles</a>, <em>Accessed
09 January 2015</em></p>
</div>
<div class="section" id="a-solution-using-search-not-algebra">
<h2>A solution using search, not algebra</h2>
<p>At first I started to explore the problem by looking at it algebraically. What
are the differences between each cup? How can those differences be summed
together to give the required remainder of 4?</p>
<p>However this didn’t yield anything helpful. Instead, I started looking at the
solution states. What do the cups have to look like for the puzzle to be solved?</p>
<div class="section" id="two-success-states">
<h3>Two success states</h3>
<p>There are at least two success states. One where the 5 oz cup contains 4 oz
of water and the other where the 8 oz cup contains 4 oz of water. The other two
cups must contain the remaining 4 oz of water. This is the notation I’ve used
for these two states, where <tt class="docutils literal">x + y = 4</tt>:</p>
<pre class="literal-block">
[<Cup x/3>, <Cup 4/5>, <Cup y/8>]
</pre>
<p>And:</p>
<pre class="literal-block">
[<Cup x/3>, <Cup y/5>, <Cup 4/8>]
</pre>
</div>
<div class="section" id="the-search-problem">
<h3>The search problem</h3>
<p>So taking the second state, and assuming that the first cup is full, then the
question becomes:</p>
<blockquote>
How do we get from the start state to the end state?</blockquote>
<pre class="literal-block">
[<Cup 0/3>, <Cup 0/5>, <Cup 8/8>]
...
TODO: Search in here for a path
...
[<Cup 3/3>, <Cup 1/5>, <Cup 4/8>]
</pre>
<p>This is really helpful. It turns an algebra problem into a search problem.
Computers are good at doing search. We can write code for this.</p>
</div>
</div>
<div class="section" id="a-python-3-sketch">
<h2>A Python 3 sketch</h2>
<p>I’ve written some Python to solve this problems using a type of depth first
<a class="reference external" href="https://en.wikipedia.org/wiki/Tree_traversal">Tree Traversal</a> and tree
generation strategy.</p>
<p>The <a class="reference external" href="https://github.com/jamescooke/water-pouring-python">code repository is available on GitHub</a>. The <span class="caps">README</span> contains the
installation and operating instructions.</p>
<p>These are some of the features of the code:</p>
<div class="section" id="cup-and-game-classes">
<h3>Cup and Game classes</h3>
<p>In this code, the <a class="reference external" href="https://github.com/jamescooke/water-pouring-python/blob/master/water/cup.py">Cup
class</a>
represents a cup in the problem. Each Cup has a certain <tt class="docutils literal">capacity</tt> and
<tt class="docutils literal">contents</tt>. The benefit of using a Cup class as a data type is that it can
perform checks that is not holding more than its capacity of water or that it’s
holding a negative capacity of water either.</p>
<p>The <a class="reference external" href="https://github.com/jamescooke/water-pouring-python/blob/master/water/game.py">Game
class</a>
is more complex as it represents a single state in the tree. Each Game state
has three main properties:</p>
<ul class="simple">
<li><tt class="docutils literal">cups</tt> - The three Cups that make up this Game state.</li>
<li><tt class="docutils literal">parent</tt> - The Game that came before this one in the search. The starting
state will have this as <tt class="docutils literal">None</tt>, but all the rest will have a parent.</li>
<li><tt class="docutils literal">children</tt> - Each Game will have some or no child Game states stored in a
list. These are the valid states that can be made by pouring some or all of
one Cup’s contents into another Cup in the Game that haven’t already been
seen during the search.</li>
</ul>
<p>The Game’s <tt class="docutils literal">children</tt> property makes the Game class a <a class="reference external" href="https://en.wikipedia.org/wiki/Recursive_data_type">recursive data
structure</a> because it can
contain other instances of Games. This opens the door to the recursive search
described below.</p>
<p>Again using this Game type is really helpful because I’ve been able to write
tested functions for supporting data type functions like <tt class="docutils literal">__eq__</tt> (which
tests if two Game stats are logically the same). The most important function in
Game is <tt class="docutils literal">is_solvable</tt> which implements the search function.</p>
</div>
<div class="section" id="recursive-search">
<h3>Recursive search</h3>
<p>As mentioned above, the <tt class="docutils literal">Game.is_solvable</tt> function implements the tree
search, so here it is in full, comments removed.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">is_solvable</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">is_goal</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">print_trace</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">make_children</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">solvable_child</span><span class="p">()</span>
</pre></div>
<p>There are two base cases to this <a class="reference external" href="https://en.wikipedia.org/wiki/Recursion_(computer_science)#Recursive_functions_and_algorithms">recursive function</a>.</p>
<ul class="simple">
<li><tt class="docutils literal">self.is_goal()</tt> : Goal has been reached. This Game contains a Cup that
has 4 oz of water, success, a goal state has been found! Return <tt class="docutils literal">True</tt>
and print a trace of how the algorithm got here.</li>
<li><tt class="docutils literal">self.make_children() == 0</tt> : There are no child states. This Game can not
generate any new states that don’t exist in the tree already, so this state
is a fail, return <tt class="docutils literal">False</tt>.</li>
</ul>
<p>When neither of those two base cases are found, then this state is on a
“success path” if one of its children “is solvable”. The recursive case is that
the <tt class="docutils literal">Game.solvable_child</tt> helper function is then used to call
<tt class="docutils literal">Game.is_solvable</tt> on each of the child Games.</p>
<p>Here is the helper function without comments:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">solvable_child</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">for</span> <span class="n">child</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">children</span><span class="p">:</span>
<span class="k">if</span> <span class="n">child</span><span class="o">.</span><span class="n">is_solvable</span><span class="p">():</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="kc">False</span>
</pre></div>
<p>There are two “interesting” features of this function:</p>
<ul class="simple">
<li>It operates like a <a class="reference external" href="https://en.wikipedia.org/wiki/Short-circuit_evaluation">short circuited <span class="caps">OR</span></a> reduction. This
means that as soon as a solvable child is found, it stops searching and
returns <tt class="docutils literal">True</tt>.</li>
<li>It has been split out from <tt class="docutils literal">Game.is_solvable</tt> to assist with unit testing.</li>
</ul>
<p>This short circuiting feature is important. I wasn’t able to get it to work in
a <tt class="docutils literal">reduce</tt> statement on the <tt class="docutils literal">Game.children</tt>, so instead I wrote it out
explicitly as a for-loop.</p>
</div>
<div class="section" id="duplicate-search">
<h3>Duplicate search</h3>
<p>When generating new Games by pouring water from Cup to Cup, only new Game
states are added as children of any particular Game. This prevents duplication
of Games and ensures that the search will terminate once all different possible
states have been generated at the very latest.</p>
<p>The <tt class="docutils literal">Game.has_game</tt> function implements this duplicate search using a
recursive depth first tree search.</p>
</div>
<div class="section" id="as-much-functional-style-as-possible">
<h3>As much functional style as possible</h3>
<p>Originally I intended to write this sketch with as much <a class="reference external" href="https://en.wikipedia.org/wiki/Functional_programming">functional style code</a> as possible. However,
there were certainly some functions that we not possible to achieve this
without some serious hacking, and so I chose to keep those functions as simple
and testable as possible.</p>
<p>I’d love to have the time to come back and construct a similar sketch for this
problem in Haskell.</p>
</div>
</div>
<div class="section" id="possible-improvements-and-follow-up-ideas">
<h2>Possible improvements and follow up ideas</h2>
<p>Apart from a fully functional rewrite, there are a couple of ways that I could
see to improve the sketch. Even though it doesn’t run slowly, there are
certainly some optimisations that could be made, plus some follow up ideas.</p>
<div class="section" id="save-time-by-checking-cups-contents-when-pouring">
<h3>Save time by checking Cups contents when pouring</h3>
<p>When generating child Game states by pouring from one cup to another, the
system does not care if a Cup has water to give or if the recipient is full. It
does the pour and then eliminates the new state because it’s a duplicate of its parent.</p>
<p>Instead, time could be saved by improving the pouring function so that pours
only generate new Game states when there is water to give and the destination
cup has space for that water.</p>
</div>
<div class="section" id="improve-the-network-anti-duplication-search">
<h3>Improve the network anti-duplication search</h3>
<p>Searching the existing Game states to ensure that the same state hasn’t already
been created first runs to the top of the Game tree, then searches downwards.</p>
<p>Most Game states will be duplicates of a Game that’s either their parent or one
Game state away from them. This means there’s an advantage, especially when
running bigger problem searches, to search nearest Games first.</p>
</div>
<div class="section" id="create-a-goal-variable">
<h3>Create a <tt class="docutils literal">goal</tt> variable</h3>
<p>The code could be improved to accept a <tt class="docutils literal">goal</tt> value for the amount of water
that should be in a Cup for success to be achieved.</p>
</div>
<div class="section" id="search-for-bigger-solvable-problems">
<h3>Search for bigger solvable problems</h3>
<p>Going meta, it would be interesting now to use this code to search for a nice
big complicated water pouring problem. What’s the largest number of Cups and
steps to success that can be found?</p>
</div>
</div>
<div class="section" id="related-stuff">
<h2>Related stuff</h2>
<p>I’ve always been fascinated by the power of graph searching as a replacement
for intelligence. In this example, the code has searched all possible Game
states for one that meets the success criteria.</p>
<p>My first introduction to this idea was via <a class="reference external" href="https://www.theguardian.com/science/2007/jul/10/uk.obituaries1">Donald Michie</a>‘s <span class="caps">MENACE</span>
machine. This was a noughts-and-crosses playing machine made from matchboxes.
It used a very simple algorithm, which is effectively a weighted graph, to
“learn” to play the game. <a class="reference external" href="https://www.it.uu.se/edu/course/homepage/ai/menace">Uppsala University has an interesting project
outline for building a code version</a>.</p>
<p>Thanks for reading.</p>
</div>
Django Contexts and get2014-11-17T20:00:00+00:002014-11-17T20:00:00+00:00Jamestag:jamescooke.info,2014-11-17:/django-contexts-and-get.html<p class="first last">Found that tests on a recent project started breaking for no clear
reason, and it turned out it was because I’d used <tt class="docutils literal">get</tt> to retrieve
values from Contexts.</p>
<div class="section" id="background">
<h2>Background</h2>
<p>If you know me, then you know that I’m an avid tester. It could even be argued
that I test too extensively as part of my day-to-day development, but that’s a
post for another day.</p>
<p>On a recent project, a particular view started failing with the error:</p>
<pre class="literal-block">
AttributeError: 'ContextList' object has no attribute 'get'
</pre>
<p>I wasn’t happy with just changing the tests to work again, so I dug down into
why they started failing.</p>
</div>
<div class="section" id="tl-dr">
<h2><span class="caps">TL</span>;<span class="caps">DR</span></h2>
<p>To get a value from a Context object returned by the Django Test Client, then
it’s better to use the <tt class="docutils literal">[]</tt> operator than the <tt class="docutils literal">get</tt> method.</p>
<p>For example:</p>
<div class="highlight"><pre><span></span><span class="c1"># In a test, after doing</span>
<span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s1">'home'</span><span class="p">))</span>
<span class="c1"># ... then it's better to use [] to test the context</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s1">'name'</span><span class="p">],</span> <span class="s1">'Homer'</span><span class="p">)</span>
<span class="c1"># ...than to use get</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'name'</span><span class="p">),</span> <span class="s1">'Homer'</span><span class="p">)</span>
</pre></div>
</div>
<div class="section" id="reason">
<h2>Reason</h2>
<p>It turns out that the problem was to do with a developer on the project
changing how the template for the view was generated. They changed a view that
was using a single template, to a couple of templates using <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/templates/#template-inheritance">Django’s template
inheritance</a>
and the <tt class="docutils literal">extends</tt> template tag.</p>
<p>This then effects how Django’s test client returns the Context object for inspection.</p>
<p>To test this I prepared the following test:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.core.urlresolvers</span> <span class="kn">import</span> <span class="n">reverse</span>
<span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TestCase</span>
<span class="k">class</span> <span class="nc">Tests</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_get</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s1">'home'</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'name'</span><span class="p">),</span> <span class="s1">'Homer'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_operator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">client</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s1">'home'</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s1">'name'</span><span class="p">],</span> <span class="s1">'Homer'</span><span class="p">)</span>
</pre></div>
<p>The home view was just a simple template renderer:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
<span class="k">def</span> <span class="nf">home</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'home.html'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'name'</span><span class="p">:</span> <span class="s1">'Homer'</span><span class="p">,</span> <span class="p">})</span>
</pre></div>
<div class="section" id="simple-works">
<h3>Simple works</h3>
<p>When the ‘home.html’ template is a simple template with no inheritance (it can
be completely empty), then both tests pass.</p>
<p><span class="quo">‘</span>home.html’ template code:</p>
<div class="highlight"><pre><span></span><span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World<span class="p"></</span><span class="nt">p</span><span class="p">></span>
</pre></div>
<p>Test run:</p>
<div class="highlight"><pre><span></span>./manage.py<span class="w"> </span><span class="nb">test</span>
Creating<span class="w"> </span><span class="nb">test</span><span class="w"> </span>database<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="s1">'default'</span>...
..
----------------------------------------------------------------------
Ran<span class="w"> </span><span class="m">2</span><span class="w"> </span>tests<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">0</span>.027s
OK
Destroying<span class="w"> </span><span class="nb">test</span><span class="w"> </span>database<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="s1">'default'</span>...
</pre></div>
</div>
<div class="section" id="template-inheritance-fails-with-get">
<h3>Template inheritance fails with <cite>get</cite></h3>
<p>Now adjust ‘home.html’ to extend another template ‘base.html’ which has
arbitrary contents.</p>
<p>New ‘home.html’ template code:</p>
<div class="highlight"><pre><span></span>{% extends 'base.html' %}
<span class="p"><</span><span class="nt">p</span><span class="p">></span>Hello World<span class="p"></</span><span class="nt">p</span><span class="p">></span>
</pre></div>
<p>Test run:</p>
<div class="highlight"><pre><span></span>./manage.py<span class="w"> </span><span class="nb">test</span>
Creating<span class="w"> </span><span class="nb">test</span><span class="w"> </span>database<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="s1">'default'</span>...
E.
<span class="o">======================================================================</span>
ERROR:<span class="w"> </span>test_get<span class="w"> </span><span class="o">(</span>mini.tests.Tests<span class="o">)</span>
----------------------------------------------------------------------
Traceback<span class="w"> </span><span class="o">(</span>most<span class="w"> </span>recent<span class="w"> </span>call<span class="w"> </span>last<span class="o">)</span>:
<span class="w"> </span>File<span class="w"> </span><span class="s2">"/home/james/active/mini/mmm/mini/tests.py"</span>,<span class="w"> </span>line<span class="w"> </span><span class="m">9</span>,<span class="w"> </span><span class="k">in</span><span class="w"> </span>test_get
<span class="w"> </span>self.assertEqual<span class="o">(</span>response.context.get<span class="o">(</span><span class="s1">'name'</span><span class="o">)</span>,<span class="w"> </span><span class="s1">'Homer'</span><span class="o">)</span>
AttributeError:<span class="w"> </span><span class="s1">'ContextList'</span><span class="w"> </span>object<span class="w"> </span>has<span class="w"> </span>no<span class="w"> </span>attribute<span class="w"> </span><span class="s1">'get'</span>
----------------------------------------------------------------------
Ran<span class="w"> </span><span class="m">2</span><span class="w"> </span>tests<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">0</span>.029s
FAILED<span class="w"> </span><span class="o">(</span><span class="nv">errors</span><span class="o">=</span><span class="m">1</span><span class="o">)</span>
Destroying<span class="w"> </span><span class="nb">test</span><span class="w"> </span>database<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nb">alias</span><span class="w"> </span><span class="s1">'default'</span>...
</pre></div>
<p>So the <tt class="docutils literal">test_get</tt> case, which was using <tt class="docutils literal">get</tt> failed.</p>
</div>
</div>
<div class="section" id="conclusion">
<h2>Conclusion</h2>
<p>It’s definitely more robust to be using list access <tt class="docutils literal">[]</tt> on Context objects
returned by the Django Test Client where possible when checking values passed
through to templating.</p>
<p>Thanks for reading.</p>
</div>
Current state of Codeship2014-10-12T18:00:00+01:002014-10-12T18:00:00+01:00Jamestag:jamescooke.info,2014-10-12:/current-state-of-codeship.html<p class="first last">For the last month I’ve been using Codeship for Continuous
Integration on my current client project. These are my current
thoughts on this hosted service that works with Github and BitBucket repositories.</p>
<div class="section" id="background">
<h2>Background</h2>
<p>In September I was introduced to <a class="reference external" href="https://www.codeship.io/">Codeship</a> at a
presentation by <a class="reference external" href="http://anglepoised.com/">Paul Love</a>. These are some of the
learnings I have from using their hosted service primarily for <a class="reference external" href="https://en.wikipedia.org/wiki/Continuous_integration">Continuous
Integration</a> for the
last couple of weeks on a client project.</p>
<p>This post isn’t about advantages and disadvantages of <span class="caps">CI</span> or <a class="reference external" href="https://en.wikipedia.org/wiki/Continuous_delivery">Continuous
Delivery</a>, but more focused
on Codeship’s offering currently, compared to other <span class="caps">CI</span> services I’ve used over
the last 6 months or so.</p>
</div>
<div class="section" id="tl-dr">
<h2><span class="caps">TL</span>;<span class="caps">DR</span></h2>
<p>Codeship is relatively new and working hard to stabilise the system while
providing documentation and service.</p>
<p>The 100 free builds they provide per month, along with the ability to integrate
with <a class="reference external" href="https://bitbucket.org/">BitBucket</a> mean that you can run private
projects on <span class="caps">CI</span> for free, but watch out for their lack of stability.</p>
</div>
<div class="section" id="positives">
<h2>Positives</h2>
<div class="section" id="good-value">
<h3>Good value</h3>
<p>Codeship currently offers <a class="reference external" href="https://www.codeship.io/pricing">100 builds a month for free</a> on private repos that include BitBucket and
<a class="reference external" href="https://github.com/">Github</a> - this is <strong><span class="caps">GOOD</span></strong>. It’s hard to find hosted <span class="caps">CI</span>
systems that will work with non-Github repository hosting.</p>
</div>
<div class="section" id="good-support">
<h3>Good support</h3>
<p>Codeship’s support team know their stuff.</p>
<p>I’ve had multiple discussions with Codeship’s support via email and Twitter and
I’ve found that they get back to you with timely email replies and suggestions
about why things are breaking. Great for a free service!</p>
</div>
<div class="section" id="good-speed">
<h3>Good speed</h3>
<p><strong>Builds are <span class="caps">QUICK</span>!</strong> So quick that I thought they weren’t using a real <span class="caps">DB</span> and
wrote a test to prove that they were listening to the settings I’d pushed
specifically for Codeship.</p>
</div>
</div>
<div class="section" id="negatives">
<h2>Negatives</h2>
<p>Unfortunately the good freeness above comes with some disadvantages.</p>
<div class="section" id="false-negatives">
<h3>False negatives</h3>
<p>Some of my builds have received false negatives meaning they have failed when
they shouldn’t have. This is annoying but manageable and can often be solved by
re-running the build.</p>
<p>For example, I’ve had a couple of builds happen on an instance where the
database wasn’t available when the tests started running, so everything went
<span class="caps">RED</span>. Slack then went <span class="caps">RED</span>. Client team start worrying.</p>
<p>Codeship’s solution for this was “Add <cite>sleep 3</cite> to make the tests wait 3
seconds before running”. This works but why isn’t Codeship’s instance build
process checking this before starting the run?</p>
</div>
<div class="section" id="false-positives">
<h3>False positives</h3>
<p>Builds have received false positives. They have passed when they shouldn’t
have - and this is <strong>far worse</strong> than a false negative.</p>
<p>This week a build on Codeship had <cite>git submodule init</cite> fail, but the build
didn’t go red. The same condition happened last week and the build <em>did</em> fail.
While I’m writing this, Codeship are looking into the problem.</p>
</div>
<div class="section" id="scarce-documentation">
<h3>Scarce documentation</h3>
<p>It’s not very clear how to work with teams, amongst other topics. Team members
can’t see how many remaining free builds are available each month so they can’t
see if they’re using up the allowance of free builds quickly or not.</p>
</div>
<div class="section" id="artefacts-need-special-attention">
<h3>Artefacts need special attention</h3>
<p>It’s hard to get build artefacts off Codeship’s build instances since the
system burns the instance once the build is complete regardless of result. This
means if you don’t push artefacts off the server yourself with a script,
they’re gone.</p>
<p>Compare with <a class="reference external" href="https://circleci.com/">CircleCI</a> - they <a class="reference external" href="https://circleci.com/docs/build-artifacts">keep build artefacts
in a special folder</a> available for
further processing, downloading, or access after the build is complete.</p>
</div>
<div class="section" id="test-commands-are-in-codeship-not-repo">
<h3>Test commands are in Codeship not repo</h3>
<p>A minor gripe I have with the Codeship system is that the test setup and run
commands are stored in the configuration for the project on their site. With
Travis for example, the server runs the commands it finds in <tt class="docutils literal">.travis.yml</tt>.</p>
<p>The benefit of putting the test commands in the repo is that they can be easily
coordinated with git commits - if you want to change how something is run, you
can do it all in the code, commit and push.</p>
<p>The Codeship way means copy-and-pasting run commands up onto their website and
then pushing new code to be tested with those settings. It makes it hard to
prove which branch was run with which settings, or if things were changed to
make builds pass.</p>
</div>
</div>
<div class="section" id="summary">
<h2>Summary</h2>
<p>Most concerning are the false negatives and positives on build. It’s very
important that a dev team can trust their <span class="caps">CI</span>/<span class="caps">CD</span> service 100%. These are the
results for the current Django project I’m building on Codeship:</p>
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script><div class="math">
\begin{equation*}
\frac {1\ False\ Negative + 1\ False\ Positive}
{37\ Total\ Builds} = 5\%\ Incorrect\ Results
\end{equation*}
</div>
<p>These are the false builds that I’m aware of - there might be some that have
gone unnoticed. For me, a figure of 95% success makes Codeship ‘just’ stable
enough for work, but it’s <strong>free and works with Bitbucket</strong> and that’s a
massive positive. I would be disappointed if we were on a paid account and
receiving the same instability.</p>
<p>For the future, if they can stabilise the builds and document the system then
they could become the go-to <span class="caps">CI</span> service for teams on Bitbucket.</p>
</div>
<div class="section" id="project-background">
<h2>Project Background</h2>
<p>I’m running 125 tests in around 15s on a Python (2.7) Django (1.7) project that
makes integrated <span class="caps">API</span> calls to Dropbox, sits on top of MySQL, runs coverage and flake8.</p>
<p>Thanks for reading.</p>
</div>
<script type='text/javascript'>if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
var align = "center",
indent = "0em",
linebreak = "false";
if (false) {
align = (screen.width < 768) ? "left" : align;
indent = (screen.width < 768) ? "0em" : indent;
linebreak = (screen.width < 768) ? 'true' : linebreak;
}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({" +
" config: ['MMLorHTML.js']," +
" TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: true," +
" messageStyle: 'normal'," +
" tex2jax: { " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: true," +
" preview: 'TeX'," +
" }, " +
" 'HTML-CSS': { " +
" availableFonts: ['STIX', 'TeX']," +
" preferredFont: 'STIX'," +
" styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
" linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
" }, " +
"}); " +
"if ('default' !== 'default') {" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
</script>Flat designs to website specification - a checklist2014-03-29T16:00:00+00:002014-03-29T16:00:00+00:00Jamestag:jamescooke.info,2014-03-29:/flat-designs-to-website-specification-a-checklist.html<p class="first last">Agencies often provide flat designs to web developers as a
specification, but these only scratch the surface of a true website
functional specification. This is a check-list of features which can
be fleshed out to start the journey towards a full functional spec.</p>
<div class="section" id="isolated-design-has-problems">
<h2>Isolated design has problems</h2>
<p>Since many web projects are approached from the visual aspect, often the <em>seen</em>
elements are designed first. This can be fine if it’s integrated with well
thought out feedback from developers, but can create more work for the project
if it’s completed and signed off in isolation.</p>
<ul class="simple">
<li><strong>Results in more development work</strong> when a design might have some serious
development implications when compared to a slightly different solution that
could also have been acceptable.</li>
<li><strong>Work estimates will be less accurate</strong> since the flat designs just start to
scratch the surface of the development required - they are not a full specification.</li>
<li><strong>Can lead to frustration within the design team</strong> as they are asked to
redesign elements during the production process that they thought were
already signed off.</li>
<li><strong>Potentially leads to uncertainty with the client</strong> if ‘signed off’ designs
are presented again for sign off with changes that were not previously foreseen.</li>
</ul>
</div>
<div class="section" id="how-to-use-this-checklist">
<h2>How to use this checklist</h2>
<p>Next time you see a software project being discussed just via flat designs, let
your alarm bells ring. Open up conversation about the features on this list to
break down the isolation that the design team is operating in.</p>
<div class="section" id="for-developers">
<h3>For Developers</h3>
<p>This basic list can start a journey of specification exploration. Start to ask
questions about all these features before you agree on a specification or
timeline since some of these items can become heavy or project effecting.</p>
<p>This list is very back-end focused, but hopefully can be helpful for
front-enders too.</p>
</div>
<div class="section" id="for-website-owners">
<h3>For Website owners</h3>
<p>If you’re being asked to sign off a project on flat designs alone, then it
might be beneficial to check that the team you’re working with have these
aspects of the development on their radar. They might not have the answer to
them yet, but should have a plan to find them.</p>
</div>
<div class="section" id="for-designers">
<h3>For Designers</h3>
<p>You are often stuck in the middle of the process. Continue to involve your
development team, they will be able to point out things that will require more
effort to build before your client signs off the visuals, saving the project
work in the long term.</p>
<p>You can help to ensure you get good value feedback by asking them questions
about items on this checklist - ensure they’re not lulled into a false sense of
“it’ll be easy” by your fantastic design work!</p>
</div>
</div>
<div class="section" id="the-checklist">
<h2>The Checklist</h2>
<p>The following details are often missing from flat web designs, but should be
provided in a full specification.</p>
<ul class="simple">
<li><strong>Page titles</strong> - Standard and often missed by designers that use a generic
image of a web browser frame to wrap their designs. Loved by content managers
and search engines. Do they have a format and can be auto-generated? Does the
content database need an extra field?</li>
<li><strong>Hidden <span class="caps">HTML</span> data</strong> - What about all the data in the <span class="caps">HTML</span> <cite><head></cite>? Meta
description, icon, Facebook data? Also for each image what will be the <cite><img>
alt</cite> tag?</li>
<li><strong>URLs</strong> - Also missed by designers when using generic browser frames, what
are the URLs of each page being shown? Remember to check the URLs of pages
that have pagination.</li>
<li><strong>Data field requirements</strong> - Designs often show the ‘best case’ for content,
but ensuring good data is entering the database is essential for a successful
web project. What are the limits - shortest names? Longest ones? Are spaces
allowed? Should content be trimmed? Emails should be validated, but on what
level? Semantically, or with a request to a <span class="caps">DNS</span> or mail server?</li>
<li><strong>Form fields, validation and error messages</strong> - If you’re looking at a
design that shows a web form, are there are error messages in the design?
Expanding on the requirements for the data above, what will happen to the
form when invalid data is entered? How will fields be flagged for errors?
Which data elements will be sent back to the form and which will be cleaned
out? Are there any fields (like address) that need to be localised?</li>
<li><strong>User sign up requirements</strong> - If the site will be accepting registrations,
what will users need to provide to register? Email address? User name (how
long)? Are there any blocked words in user names (like ‘admin’, the project
brand name or profanities)? Password (how long)? Are there any password
strength requirements? How will users reset their passwords?</li>
<li><strong>Transactional emails</strong> - What emails will need to be sent by the system?
What is their content and design? Can users manage these notifications?</li>
<li><strong>Security</strong> - Will the site have any functions that will protect the data of
its users? For example, will the user login page throttle access on multiple
incorrect passwords? Will there be ‘https’ required?</li>
<li><strong>Private data</strong> - Since flat designs will show the public end user view of a
project, what data is hidden from the user but essential for the project?
Latest login dates? Number of logins? <span class="caps">IP</span> address of last visit or
registration? Banned, active, subscriber flags? Active or dormant flags on content?</li>
<li><strong>Click and hover behaviours</strong> - What will happen when elements like links
are hovered? Are there any menus functions that are hidden behind clicks? Are
there any titles to be shown when the user hovers an item?</li>
<li><strong>Error pages</strong> - What is the design for the 404 page? What about 503 and any
other error pages? Will there need to be a holding page when the site is
being updated and is offline?</li>
<li><strong>Analytics configuration</strong> - How should the analytics be configured to track
behaviours on the site? Is it required? Will a simple configuration suffice
or will there need to be funnels and or events configured? Analytics can be
complex enough to require as much work as the original build out of a
project, so ensuring that the specification is defined and covers the
business needs early is a benefit.</li>
<li><strong>Translation requirements</strong> - Will any of the content in the designs require
translation? This also effects the items mentioned above in the checklist.
Remember that any image elements that have been prepared that contain text
will need to be generated in each target language - will each of those
translated texts fit within the design?</li>
</ul>
</div>
<div class="section" id="feedback-and-thoughts">
<h2>Feedback and thoughts</h2>
<p>I hope that the list above helps someone who’s working through the design of a
site. Any time that I’ve worked on a project where developers and stakeholders
have been involved in the design stages early on have always been successful.</p>
<p>If there are items you think should be added you can contribute on <a class="reference external" href="https://github.com/jamescooke/blog/blob/master/content/1403-spec-checklist.rst">GitHub</a>.</p>
<p>Thanks for reading.</p>
</div>
Seinfeld method and coding2014-01-31T16:00:00+00:002014-01-31T16:00:00+00:00Jamestag:jamescooke.info,2014-01-31:/seinfeld-method-and-coding.html<p class="first last">A presentation I made at ustwo’s Tech Thursday about Seinfeld
Technique and how it can help coders to get their personal projects moving.</p>
<p>This presentation focuses on using the Seinfeld method “Don’t break the chain”
to get going with personal projects. Those could be all types of things from
learning the piano, a new programming language or achieving a personal goal.</p>
<p>I believe that the Seinfeld method can help break down some of the blockers
that we experience when procrastinating, by forcing us to refactor large,
unmeasurable and daunting tasks into mini-tasks which are the opposite -
achievable, simple and regular. It also helps us to refocus on continual small
steps rather than the big picture.</p>
<br>
<script async class="speakerdeck-embed" data-id="bdabe0106c8c013162a91ed72f379050" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>
<br><p>I’m especially keen on how the regular measurement of time spent on a project
can give insight, and so I’ve started combining Seinfeld with Pomodoro Technique.</p>
<p>The most important thing is to “make it work for you” - there are all sorts of
ways that these techniques can be used to push a project forward or help you to
achieve your goal.</p>
<p>Hope that’s helpful!</p>
<p>Thanks to <a class="reference external" href="https://www.ustwo.com/">Victor at ustwo London</a> for asking me to talk
at their Tech Thursday.</p>
<p>Read more on <a class="reference external" href="https://lifehacker.com/281626/jerry-seinfelds-productivity-secret">Seinfeld Technique</a> and
<a class="reference external" href="https://en.wikipedia.org/wiki/Pomodoro_Technique">Pomodoro Technique</a>. I’m
currently using <a class="reference external" href="http://tomatoi.st/">tomatoist</a> as my online pomodoro timer.</p>
<p>Update 11/05/2018: I’ve been using a local install of this <a class="reference external" href="https://github.com/bastibe/pomodoro-timer"><span class="caps">HTML</span> Pomodoro timer</a> for the last couple of years now.
Output the <span class="caps">JSON</span> report that it creates into a couple of processors that count
my hours and measure my efficiency. This means that I can ensure that I’m
working the right number of hours per week, but also taking a good number of breaks.</p>
Python generators and yield2013-12-14T16:00:00+00:002013-12-14T16:00:00+00:00Jamestag:jamescooke.info,2013-12-14:/python-generators-and-yield.html<p class="first last">Notes to myself on generators and how to create them with generator
expressions and the yield statement.</p>
<div class="section" id="it-started-with-an-interview">
<h2>It started with an interview</h2>
<p>Last week in an interview for a Django developer job, I was asked:</p>
<div class="highlight"><pre><span></span><span class="n">thing</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">xrange</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</pre></div>
<!-- -->
<blockquote>
What is the type of thing?</blockquote>
<p>Although I was able to identify that the type is dependent on the <tt class="docutils literal">()</tt> around
the list-comprehension-like-construction, I didn’t know the exact type that
<tt class="docutils literal">thing</tt> would be.</p>
<p>The answer is a <strong>generator</strong>.</p>
<p>This post shows some of the functionalities of generators and how they can
be used in Python control flow.</p>
</div>
<div class="section" id="generator-expressions">
<h2>Generator expressions</h2>
<p>Generators can be created with generator expressions. A generator expression is
a bit like a list comprehension. List Comprehension uses square brackets
<tt class="docutils literal">[]</tt>. In Python…</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="p">[</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span>
</pre></div>
<pre class="literal-block">
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
</pre>
<p>A generator expression is a shortcut that allows generators to be created
easily with a similar syntax - this time it’s using parentheses <tt class="docutils literal">()</tt>.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
</pre></div>
<pre class="literal-block">
<generator object <genexpr> at 0x2fa5eb0>
</pre>
</div>
<div class="section" id="generators-are-iterators">
<h2>Generators are iterators</h2>
<p>Generators “provide a convenient way to implement the iterator protocol”.</p>
<p>In Python, an <a class="reference external" href="https://docs.python.org/2.7/library/stdtypes.html#typeiter">iterator</a> provides two key
functions, <cite>__iter__</cite> and <cite>next</cite>, so a generator itself must provide these two functions:</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_gen</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="o">>>></span> <span class="n">my_gen</span><span class="o">.</span><span class="fm">__iter__</span>
<span class="o"><</span><span class="n">generator</span> <span class="nb">object</span> <span class="o"><</span><span class="n">genexpr</span><span class="o">></span> <span class="n">at</span> <span class="mh">0x293c3c0</span><span class="o">></span>
</pre></div>
<p><tt class="docutils literal">__iter__</tt> is there and returns the generator, now for <tt class="docutils literal">next</tt>…</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_gen</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="mi">0</span>
<span class="o">>>></span> <span class="n">my_gen</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="mi">1</span>
</pre></div>
<p>Therefore <tt class="docutils literal">next</tt> works. We can keep hitting until…</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_gen</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="mi">81</span>
<span class="o">>>></span> <span class="n">my_gen</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="o">---------------------------------------------------------------------------</span>
<span class="ne">StopIteration</span> <span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">)</span>
<span class="o"><</span><span class="n">ipython</span><span class="o">-</span><span class="nb">input</span><span class="o">-</span><span class="mi">19</span><span class="o">-</span><span class="n">b28d59f370d8</span><span class="o">></span> <span class="ow">in</span> <span class="o"><</span><span class="n">module</span><span class="o">></span><span class="p">()</span>
<span class="o">----></span> <span class="mi">1</span> <span class="n">zzz</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="ne">StopIteration</span><span class="p">:</span>
</pre></div>
<p>A <tt class="docutils literal">StopIteration</tt> is raised - so the generator does everything we’d expect it
to by the iterator protocol.</p>
</div>
<div class="section" id="building-a-generator-with-yield">
<h2>Building a generator with yield</h2>
<p>Although it’s not clear from the example above, a generator is able to
relinquish control and return a value - while saving its state. It then allows
the control to pass back to the structure that called it, until it’s called
again, picking up where it left off.</p>
<p>This allows for loops over sets of values to be programmed, without the full
list of values being calculated first. A generator can be used so that <cite>next</cite>
is called before each iteration required.</p>
<p>In this way, only the values required for each iteration need to be computed.</p>
<div class="section" id="the-yield-keyword-simple-example">
<h3>The yield keyword - simple example</h3>
<p>Adding <tt class="docutils literal">yield</tt> to a function allows for generators to be constructed ‘manually’.</p>
<p>At its very simplest, a function could be written just to generate a single
value. However, to show that a generator can return to its previous state when
called again, let’s make one with two values. For example…</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">two_things</span><span class="p">():</span>
<span class="k">yield</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="s1">'hi'</span>
</pre></div>
<p>Now we can make an instance of the generator.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_things</span> <span class="o">=</span> <span class="n">two_things</span><span class="p">()</span>
<span class="o">>>></span> <span class="n">my_things</span>
<span class="o"><</span><span class="n">generator</span> <span class="nb">object</span> <span class="n">two_things</span> <span class="n">at</span> <span class="mh">0x31d0960</span><span class="o">></span>
</pre></div>
<p>And we can ask for next value.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_things</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="mi">1</span>
</pre></div>
<p>Now when we call <tt class="docutils literal">next</tt> again, our generator continues from the state of the
last yield.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="n">my_things</span><span class="o">.</span><span class="n">next</span><span class="p">()</span>
<span class="s1">'hi'</span>
</pre></div>
<p>So you see how different values can be returned, one after the other.</p>
<p>And after that second thing, the generator now raises a <tt class="docutils literal">StopIteration</tt>, since
it has no further values to return.</p>
<p>Since a generator implements the iterator protocol, it can be used in a <cite>for</cite>
statement and therefore in a list comprehension. This makes for a convenient
way to check the values of a limited generator like this one.</p>
<div class="highlight"><pre><span></span><span class="o">>>></span> <span class="p">[</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">two_things</span><span class="p">()]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="s1">'hi'</span><span class="p">]</span>
</pre></div>
</div>
<div class="section" id="more-complex-example-with-yield">
<h3>More complex example with yield</h3>
<p>So let’s write Fibonacci as a generator. I’m going to start with doctests to
create the definition of the function, then put the code at the end.</p>
<p>What I like about the doctests in this example is that in 3 <tt class="docutils literal">fib</tt> is tested
with <tt class="docutils literal">next</tt>, but in 4 it’s tested using a list comprehension.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">last</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> 1. Creates a generator</span>
<span class="sd"> >>> type(fib(0))</span>
<span class="sd"> <type 'generator'></span>
<span class="sd"> 2. fib(0) just generates 0th value (1)</span>
<span class="sd"> >>> zero_fib = fib(0)</span>
<span class="sd"> >>> zero_fib.next()</span>
<span class="sd"> 1</span>
<span class="sd"> >>> zero_fib.next()</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> StopIteration</span>
<span class="sd"> 3. fib(1) creates a generator that creates 0th (1) and 1st (1) values of</span>
<span class="sd"> fib seq</span>
<span class="sd"> >>> one_fib = fib(1)</span>
<span class="sd"> >>> one_fib.next()</span>
<span class="sd"> 1</span>
<span class="sd"> >>> one_fib.next()</span>
<span class="sd"> 1</span>
<span class="sd"> >>> one_fib.next()</span>
<span class="sd"> Traceback (most recent call last):</span>
<span class="sd"> ...</span>
<span class="sd"> StopIteration</span>
<span class="sd"> 4. fib(10) generates the first 10 fibonacci numbers</span>
<span class="sd"> >>> [x for x in fib(10)]</span>
<span class="sd"> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]</span>
<span class="sd"> """</span>
<span class="n">result</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">a</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="n">x</span> <span class="o"><=</span> <span class="n">last</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">result</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">a</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">result</span>
<span class="n">x</span> <span class="o">+=</span> <span class="mi">1</span>
</pre></div>
<p>That’s all - have fun with generators!</p>
</div>
</div>
Git: To squash or not to squash?2013-11-19T11:00:00+00:002013-11-19T11:00:00+00:00Jamestag:jamescooke.info,2013-11-19:/git-to-squash-or-not-to-squash.html<p class="first last">Should detailed history be kept for development features, if so, where?</p>
<div class="section" id="it-started-with-a-tweet">
<h2>It started with a Tweet</h2>
<p>Over the weekend I spotted a tweet from <a class="reference external" href="https://oli.me.uk/">Oliver</a>…</p>
<blockquote class="twitter-tweet" lang="en"><p>To squash features into develop, or not to squash features into develop?</p>— Oliver Caldwell (@OliverCaldwell) <a href="https://twitter.com/OliverCaldwell/statuses/401299558887485440">November 15, 2013</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script><p>And I jumped straight in with…</p>
<blockquote>
<p><a class="reference external" href="https://twitter.com/OliverCaldwell">@OliverCaldwell</a> Squash, but keep
detailed commit messages. Unless you have a particular use-case / reason
not to.</p>
<p>November 17, 2013</p>
</blockquote>
<p>Then, as part of our following conversation, I drew a picture:</p>
<img alt="Git squashing, feature versus history" src="https://jamescooke.info/images/git.jpg" />
<!-- -->
<blockquote>
<p>This is how I see it. Better to keep the direct route rather than the “how we got here”.</p>
<p>November 18, 2013</p>
</blockquote>
<p>But…</p>
</div>
<div class="section" id="it-s-about-more-than-just-squashing">
<h2>It’s about more than just squashing</h2>
<p>What I realised while writing this post and experimenting with <cite>git</cite> is that
the issue is not as simple as “Squash? Yes / No?”</p>
<p>Variables to consider include:</p>
<ul class="simple">
<li><strong>How you record your commit messages on your squashed commit.</strong> This effects
the impact of history loss - good commit messages and or external ticketing /
dev tracking mean it’s less important.</li>
<li><strong>Whether you push your feature branches for other developers, or between your
dev boxes, to share.</strong> Do you need to keep the shared history between machines?</li>
<li><strong>The velocity of your project.</strong> How long do you need to keep history for?
Do bugs show up regularly?</li>
</ul>
</div>
<div class="section" id="tl-dr-simple-project-squash-yes">
<h2><span class="caps">TL</span>;<span class="caps">DR</span> Simple project. Squash = Yes</h2>
<p>For a simple project with no sharing between devs required and regular
releases, then squashing features seems like a good idea if you:</p>
<ul class="simple">
<li>Keep detailed commit messages when you squash.</li>
<li>Use <cite>git rebase</cite> to squash your features’ commits into a candidate branch and
merge that in to <cite>dev</cite> or <cite>master</cite> depending on your <span class="caps">SCM</span> strategy.</li>
<li>Only push your squashed features to keep <cite>origin</cite> clean and easy to understand.</li>
<li>Keep your feature branches if you want. But, if you delete them <cite>git</cite> will
keep your commits in the reflog for 30 days by default.</li>
</ul>
</div>
<div class="section" id="keeping-a-detailed-history">
<h2>Keeping a detailed history</h2>
<p>One of the issues that Oliver raised was about losing history.</p>
<blockquote class="twitter-tweet" data-conversation="none" lang="en"><p><a href="https://twitter.com/jamesfublo">@jamesfublo</a> I suppose so. Squashing just feels like you're killing off that fine grained history, like when was that two line change made.</p>— Oliver Caldwell (@OliverCaldwell) <a href="https://twitter.com/OliverCaldwell/statuses/402394094111977472">November 18, 2013</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script><p>So, since I advocate squashing and branch deletion, I’m therefore suggesting
that the <strong>reflog is used to recover detailed history in the local repository</strong>
if required.</p>
<p>So let’s explore how much history is actually kept…</p>
<p><a class="reference external" href="https://git-scm.com/docs/git-reflog">From the docs</a>:</p>
<blockquote>
Reflog is a mechanism to record when the tip of branches are updated.</blockquote>
<p>This means that…</p>
<p><strong>Every commit that every branch in your local repostitory has ever pointed to
is kept in the reflog.</strong></p>
<p>And this even includes branch switching…</p>
<blockquote>
<span class="caps">HEAD</span> reflog records branch switching as well.</blockquote>
<p>Sounds very warm and cozy, <strong><span class="caps">BUT</span></strong> there are conditions, so let’s do a
practical experiment with a test repository.</p>
</div>
<div class="section" id="experiment-squashing-with-rebase-and-keeping-history">
<h2>Experiment: Squashing with rebase and keeping history</h2>
<p>Make a repository with an initial commit.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>init
</pre></div>
<p>Create a <cite><span class="caps">README</span>.md</cite> file and put a line of text into it and commit - this
commit is called A.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>cat<span class="w"> </span>><span class="w"> </span>README.md
First<span class="w"> </span>line<span class="w"> </span>of<span class="w"> </span>readme<span class="w"> </span>file
^C
$<span class="w"> </span>git<span class="w"> </span>add<span class="w"> </span>README.md
$<span class="w"> </span>git<span class="w"> </span>commit
</pre></div>
<p>Current <cite>git</cite> tree status:</p>
<pre class="literal-block">
A <-master
</pre>
<div class="section" id="work-on-feature">
<h3>Work on feature</h3>
<p>In a new branch, we create a <em>feature</em> to update the <span class="caps">README</span> with two new lines
and to delete the first line.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>-b<span class="w"> </span>feature-a
<span class="c1"># First feature commit (B)</span>
$<span class="w"> </span>cat<span class="w"> </span>>><span class="w"> </span>README.md
Add<span class="w"> </span>a<span class="w"> </span>second<span class="w"> </span>line
^C
$<span class="w"> </span>git<span class="w"> </span>add<span class="w"> </span>README.md
$<span class="w"> </span>git<span class="w"> </span>commit
<span class="c1"># Second feature commit (C)</span>
$<span class="w"> </span>cat<span class="w"> </span>>><span class="w"> </span>README.md
Add<span class="w"> </span>a<span class="w"> </span>third<span class="w"> </span>line
^C
$<span class="w"> </span>git<span class="w"> </span>add<span class="w"> </span>README.md
$<span class="w"> </span>git<span class="w"> </span>commit
<span class="c1"># Third feature commit (D)</span>
$<span class="w"> </span>vim<span class="w"> </span>README.md
<span class="c1"># Remove first line and save</span>
$<span class="w"> </span>git<span class="w"> </span>add<span class="w"> </span>README.md
$<span class="w"> </span>git<span class="w"> </span>commit
</pre></div>
<p>Current <cite>git</cite> tree status:</p>
<pre class="literal-block">
A <-master
\
B--C--D <-feature-a
</pre>
</div>
<div class="section" id="check-progress-in-reflog">
<h3>Check progress in reflog</h3>
<p>Checkout <cite>master</cite>.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>master
</pre></div>
<p>Let’s check the reflog.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>reflog
</pre></div>
<pre class="literal-block">
8e48d1d HEAD@{0}: checkout: moving from feature-a to master
262057a HEAD@{1}: commit: D: Remove first line
9efbf73 HEAD@{2}: commit: C: Add a third line
f2503d5 HEAD@{3}: commit: B: Add a second line
8e48d1d HEAD@{4}: checkout: moving from master to feature-a
8e48d1d HEAD@{5}: commit (initial): Make readme
</pre>
<p>Newest stuff pops out first:</p>
<ul class="simple">
<li><cite><span class="caps">HEAD</span>@{0}</cite> - Checkout from <cite>feature-a</cite> to <cite>master</cite> is recorded.</li>
<li><cite><span class="caps">HEAD</span>@{1}</cite> to <cite><span class="caps">HEAD</span>@{3}</cite> - our <cite>feature-a</cite> commits (D, C and B).</li>
<li><cite><span class="caps">HEAD</span>@{4}</cite> - Checkout of the <cite>feature-a</cite> branch.</li>
<li><cite><span class="caps">HEAD</span>@{5}</cite> - Initial commit.</li>
</ul>
</div>
<div class="section" id="squash-commits-into-candidate-branch">
<h3>Squash commits into candidate branch</h3>
<p><cite>feature-a</cite> is ready to bring into <cite>master</cite>. Let’s first cleanup our history by
doing an interactive rebase. We use a candidate branch for this work because
it’s a nice safety net which can help with testing.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>feature-a
$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>-b<span class="w"> </span>feature-a-candidate
</pre></div>
<p>Current <cite>git</cite> tree status:</p>
<pre class="literal-block">
A <-master
\
B--C--D <-feature-a <-feature-a-candidate
</pre>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>rebase<span class="w"> </span>--interactive<span class="w"> </span>master
</pre></div>
<p>Let’s squash our three commits into one.</p>
<pre class="literal-block">
pick f2503d5 B: Add a second line
squash 9efbf73 C: Add a third line
squash 262057a D: Remove first line
</pre>
<p>And now we merge together the three commits, describing the activity that took
place. We keep the messages so that history is clean, but informative. We also
include a reference to the ticket we are working against:</p>
<pre class="literal-block">
Updating README.md as per #ticket
* Add a second line
* Add a third line
* Remove first line
</pre>
<p>Check reflog again:</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>reflog
</pre></div>
<pre class="literal-block">
d0445b2 HEAD@{0}: rebase -i (finish): returning to refs/heads/feature-a-candidat
d0445b2 HEAD@{1}: rebase -i (squash): Updating README.md as per #ticket
362b6ef HEAD@{2}: rebase -i (squash): # This is a combination of 2 commits.
f2503d5 HEAD@{3}: checkout: moving from feature-a-candidate to f2503d5
262057a HEAD@{4}: checkout: moving from feature-a to feature-a-candidate
</pre>
<p>The reflog shows us that there is a new commit <cite>d0445b2</cite>, we’ll call this <cite>E</cite>.
This is the commit that results from the rebase and leaves the tree looking like:</p>
<pre class="literal-block">
A <-master
|\
| B--C--D <-feature-a
\
\
E <-feature-a-candidate
</pre>
<p>This is a good stage to test everything <strong>and</strong> to check that your tests are
what you expect them to be, ensure that no information has been lost.</p>
</div>
<div class="section" id="merge-onto-master">
<h3>Merge onto master</h3>
<p>The new commit <cite>E</cite> is the patch for our <em>feature</em> which we now merge onto
<cite>master</cite>.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>master
$<span class="w"> </span>git<span class="w"> </span>merge<span class="w"> </span>feature-a-candidate<span class="w"> </span>master
</pre></div>
<pre class="literal-block">
Updating 8e48d1d..d0445b2
Fast-forward
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
</pre>
<p>The tree:</p>
<pre class="literal-block">
A--E <-master <-feature-a-candidate
\
B--C--D <-feature-a
</pre>
</div>
<div class="section" id="push">
<h3>Push</h3>
<p>At this stage the <em>feature</em> would usually be pushed to a branch on <cite>origin</cite>.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>push<span class="w"> </span>origin<span class="w"> </span>master
</pre></div>
<p>Note that we’ve only shared the squashed <cite>E</cite> commit, not <cite>B</cite>, <cite>C</cite> or <cite>D</cite> in the
<cite>feature-a</cite> branch.</p>
</div>
<div class="section" id="cleanup">
<h3>Cleanup</h3>
<p>We can then cleanup our working branches. First the candidate.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>branch<span class="w"> </span>-d<span class="w"> </span>feature-a-candidate
</pre></div>
<p>This leaves us with a tree like:</p>
<pre class="literal-block">
A--E <-master
\
B--C--D <-feature-a
</pre>
</div>
</div>
<div class="section" id="keeping-history">
<h2>Keeping history</h2>
<p>As Oliver noted, the <cite>feature-a</cite> branch can just be kept by the developer in
their local repository to preserve the full history - that is certainly an option.</p>
<blockquote class="twitter-tweet" data-conversation="none" lang="en"><p><a href="https://twitter.com/jamesfublo">@jamesfublo</a> I suppose you can still keep the unsquashed branches in the repository. I never used to squash, but I might start.</p>— Oliver Caldwell (@OliverCaldwell) <a href="https://twitter.com/OliverCaldwell/statuses/402401798738018304">November 18, 2013</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script><p>However, I prefer a clean working repository so I like to delete the
<cite>feature-a</cite> branch.</p>
<div class="section" id="clean-up-the-feature-branch">
<h3>Clean up the feature branch</h3>
<p>When deleting the <cite>feature-a</cite> branch <cite>git</cite> requires the <cite>-D</cite> flag to force the
deletion. <cite>git</cite> does not <em>work out</em> that <cite>E</cite> is <em>equal</em> to <cite>B</cite>, <cite>C</cite> and <cite>D</cite>
combined, so thinks that history could be lost.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>branch<span class="w"> </span>-D<span class="w"> </span>feature-a
</pre></div>
<pre class="literal-block">
Deleted branch feature-a (was 262057a)
</pre>
<p>This leaves a tree like:</p>
<pre class="literal-block">
A--E <-master
\
B--C--D
</pre>
</div>
<div class="section" id="b-c-and-d-are-now-hanging-commits">
<h3>B, C and D are now hanging commits</h3>
<p>Check reflog.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>reflog
</pre></div>
<p>This is a part of it:</p>
<pre class="literal-block">
...
262057a HEAD@{12}: commit: D: Remove first line
9efbf73 HEAD@{13}: commit: C: Add a third line
f2503d5 HEAD@{14}: commit: B: Add a second line
...
</pre>
<p>The development commits from the <em>feature</em> development are still available and
could be checked out into <em>detached <span class="caps">HEAD</span></em> state and inspected, played with,
rebranched. Let’s try that.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>262057a
</pre></div>
<p>Now play and explore as much as you want.</p>
<p>When you’re ready, move back to <cite>master</cite>.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span>master
</pre></div>
<p>And <cite>git</cite> warns us that we’ve left behind our hanging commits:</p>
<pre class="literal-block">
Warning: you are leaving 3 commits behind, not connected to
any of your branches:
262057a D: Remove first line
9efbf73 C: Add a third line
f2503d5 B: Add a second line
If you want to keep them by creating a new branch, this may be a good time
to do so with:
git branch new_branch_name 262057a
</pre>
</div>
</div>
<div class="section" id="how-long-are-hanging-commits-kept">
<h2>How long are hanging commits kept?</h2>
<p>But how long will these unreachable commits <em>hang</em> around for?</p>
<p><strong>We can decide!</strong></p>
<p>Hanging commits are removed from the local repository by garbage collection,
known as <cite>gc</cite>, or by manual removal.</p>
<p>There are various settings which <cite>gc</cite> will use to determine which commits
should be cleaned before the repository is repacked.</p>
<p><cite>gc.reflogExpireUnreachable</cite> tells <cite>gc</cite> how long hanging commits should be left
in the repository. Default value is 30 days. Adjust this to a value that you
feel comfortable with. You can make that setting on any of the normal levels -
global, system or local.</p>
<p>Hey - you want to keep all history in the reflog for ever? Here’s a setting:</p>
<pre class="literal-block">
[gc]
reflogExpire = never
reflogExpireUnreachable = never
</pre>
<p>I’m happy with the 30 day default myself!</p>
<p>For more detailed explanation, checkout the Configuration section of the
<cite>git-gc</cite> man page.</p>
</div>
<div class="section" id="a-manual-clean">
<h2>A manual clean</h2>
<p>Just for experimention, I tried to clean the repository of the <cite>B</cite>, <cite>C</cite> and <cite>D</cite>
hanging commits. This was challenging because my default settings prevented
reflog and <cite>gc</cite> from performing the clean, however I found <a class="reference external" href="https://stackoverflow.com/a/14995269/1286705">this <span class="caps">SO</span> answer
helpful</a>.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>reflog<span class="w"> </span>expire<span class="w"> </span>--all<span class="w"> </span>--expire-unreachable<span class="o">=</span><span class="m">0</span>
$<span class="w"> </span>git<span class="w"> </span>repack<span class="w"> </span>-A<span class="w"> </span>-d
</pre></div>
<p>Repacking occurred. Now check reflog.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>git<span class="w"> </span>reflog
</pre></div>
<pre class="literal-block">
d0445b2 HEAD@{0}: merge feature-a-candidate: Fast-forward
8e48d1d HEAD@{1}: checkout: moving from feature-a-candidate to master
d0445b2 HEAD@{2}: rebase -i (finish): returning to refs/heads/feature-a-candidat
d0445b2 HEAD@{3}: checkout: moving from master to feature-a
8e48d1d HEAD@{4}: commit (initial): Make readme
</pre>
<p>There are now only two commits in the repository:</p>
<ul class="simple">
<li><cite>8e48d1d</cite> - Initial commit <cite>A</cite> @ 1 and 4.</li>
<li><cite>d0445b2</cite> - Feature commit <cite>E</cite> made by the rebase @ 0, 2 and 3</li>
</ul>
<p>The cleaned repository now looks like:</p>
<pre class="literal-block">
A--E <-master
</pre>
<p>So fresh and so clean!</p>
</div>
<div class="section" id="summary">
<h2>Summary</h2>
<p>At the end of the day, the dev team (even if that’s just you on a weekend
project) decides how best to keep history and share features.</p>
<p>My general solution is for:</p>
<ul class="simple">
<li>Squashed single-commit features.</li>
<li>Detailed commit messages created at <em>squash-time</em>.</li>
<li>Devs keep more history locally, either with branches or in a long-life reflog.</li>
<li>Devs backup their repositories and don’t rely on <cite>origin</cite>.</li>
</ul>
<p>Remember there can be a full 30 day history (or longer depending on the
<cite>gc.reflogExpireUnreachable</cite> setting) in the local repo which hasn’t been
pushed to <cite>origin</cite>. It’s this history that could save your bacon one day - so
consider backing it up!</p>
<p>Happy source code management!</p>
</div>
<div class="section" id="update-23-08-2018">
<h2>Update 23/08/2018</h2>
<p>See also <a class="reference external" href="https://github.com/jamescooke/blog/issues/17">this comment on GitHub</a> from Curt J. Sampson with some
great points about when not to squash. One helpful excerpt:</p>
<blockquote>
I think of a set of commits I’m proposing for master branch as a story I’m
telling to the other developers. Make the story as clear as possible,
divided up into reasonably small chunks where you can do so. This will make
other developers love, rather than hate, reviewing your code.</blockquote>
<p>Thanks Curt - spread the love!</p>
</div>
<div class="section" id="update-06-01-2019">
<h2>Update 06/01/2019</h2>
<p>The Twitter account that I used in my conversations with Oliver above has been
deleted. I’ve replaced the links to tweets with the original content.</p>
</div>
vi-nature everywhere - lightning talk2013-11-01T20:00:00+00:002013-11-01T20:00:00+00:00Jamestag:jamescooke.info,2013-11-01:/vi-nature-everywhere-lightning-talk.html<p class="first last">This week I presented at Vim-London about vi nature and the benefits
for using it in more than vim.</p>
<p>vi-nature, the ‘language’ of <cite>vim</cite>. It’s the reason that <cite>vim</cite> works so well
for me. However, it does take some learning, and even after many months of use,
I’d say I’ve only just scratched the surface.</p>
<p>So if we’re investing so much time and energy in learning this language, then
why not apply it to more tasks than just editing files?</p>
<p>In this five minute lighting talk I gave at <a class="reference external" href="https://www.meetup.com/Vim-London/">Vim London</a> this week, I delved into some of the benefits
and issues with using vi-nature for more than just editing.</p>
<iframe src="//player.vimeo.com/video/78173248" width="500" height="281" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><p>The feedback after the talk was great - here are my take-aways:</p>
<ul class="simple">
<li>Check out <a class="reference external" href="https://www.uzbl.org/">uzbl</a> - it provides an interface layer
that can be programmed to different keybindings. Thanks Nestor.</li>
<li>Check out <a class="reference external" href="https://awesomewm.org/">Awesome Window Manager</a> because it’s completely operational without mouse. Thanks Nestor.</li>
<li>Write a blog post about ‘vi-nature’ because there’s not much about it on the web - Yes I will do this, thanks for the suggestion Max.</li>
<li>Check out Mac <span class="caps">OSX</span>’s <a class="reference external" href="https://github.com/jigish/slate">slate</a> because it creates a programmable keyboard interface for window management. Thanks David.</li>
</ul>
<p>Lots to follow up on and hopefully some ways to take vi-nature to more places.</p>
<p>Thanks for reading!</p>
Things to remember about decorators2013-10-22T20:00:00+01:002013-10-22T20:00:00+01:00Jamestag:jamescooke.info,2013-10-22:/things-to-remember-about-decorators.html<p class="first last">Notes to myself about Python decorators with a focus on making them testable.</p>
<p>After an interview question about Python decorators which I stumbled over, I
promised myself that I would improve my knowledge of this metaprogramming technique.</p>
<p>These are my notes to myself on decorators - maybe they’ll be helpful to
someone else who’s improving their knowledge of decorators too.</p>
<ul>
<li><p class="first">A decorator is pure Pythonic syntatic sugar.</p>
</li>
<li><p class="first">A decorator is a Python callable that receives the decorated function and
returns a new function in its place.</p>
<p>For example, if there is a decorator called <cite>my_decorator</cite> and we want to
decorate <cite>my_func</cite> then…</p>
<div class="highlight"><pre><span></span><span class="nd">@my_decorator</span>
<span class="k">def</span> <span class="nf">my_func</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""some stuff"""</span>
<span class="o">...</span>
<span class="k">return</span>
</pre></div>
<p>Is equivalent to writing.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_func</span><span class="p">():</span>
<span class="w"> </span><span class="sd">"""some stuff"""</span>
<span class="o">...</span>
<span class="k">return</span>
<span class="n">my_func</span> <span class="o">=</span> <span class="n">my_decorator</span><span class="p">(</span><span class="n">my_func</span><span class="p">)</span>
</pre></div>
</li>
<li><p class="first">The decorator callable is executed at load time, not at execution time. Here
is an example of a silly decorator that prints “Hello World” when the Python
file is loaded - there is nothing else in the file.</p>
<p><cite>hello.py</cite></p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">say_hello</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="nb">print</span> <span class="s1">'Hello World'</span>
<span class="k">return</span> <span class="n">func</span>
<span class="nd">@say_hello</span>
<span class="k">def</span> <span class="nf">nothing</span><span class="p">():</span>
<span class="c1"># Do nothing just return</span>
<span class="k">return</span>
</pre></div>
<p>Run it on the command line, and “Hello World” appears when the <cite>nothing</cite>
function is decorated.</p>
<div class="highlight"><pre><span></span>$<span class="w"> </span>python<span class="w"> </span>hello.py
Hello<span class="w"> </span>World
</pre></div>
</li>
<li><p class="first">When writing a decorator, remember to patch over the docstring of the wrapped
function. This can be done by accessing the passed function’s <cite>__doc__</cite>
attribute. Failing to do so will prevent doctest from testing the decorated function.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_decorator</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="c1"># Pass through the doc string</span>
<span class="n">wrapper</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__doc__</span>
<span class="k">return</span> <span class="n">wrapper</span>
</pre></div>
<p><strong>Update</strong> This is actually far better done with the <cite>wraps</cite> decorator from
the <cite>functools</cite> modules, which fixes the <cite>__name__</cite> and <cite>__doc__</cite> attributes
to what we’d expect them to be.</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">wraps</span>
<span class="k">def</span> <span class="nf">my_decorator</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="nd">@wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">wrapper</span>
</pre></div>
<p>Found on <a class="reference external" href="https://jeffknupp.com/blog/2013/11/29/improve-your-python-decorators-explained/">Improve your Python</a>.</p>
</li>
<li><p class="first">When unit testing decorators, one strategy can be to manually call the
decorator on a mocked object and inspect how it interacts with it.</p>
<p>Here’s a caching function which is used to speed up the Fibonacci series.</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">cache</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
<span class="c1"># Keep a dict of values returned already</span>
<span class="n">vals</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">vals</span><span class="o">.</span><span class="n">has_key</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="n">vals</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="k">return</span> <span class="n">vals</span><span class="p">[</span><span class="n">x</span><span class="p">]</span>
<span class="n">wrapper</span><span class="o">.</span><span class="vm">__doc__</span> <span class="o">=</span> <span class="n">func</span><span class="o">.</span><span class="vm">__doc__</span>
<span class="k">return</span> <span class="n">wrapper</span>
</pre></div>
<p>Now use the cache function as a decorator.</p>
<div class="highlight"><pre><span></span><span class="nd">@cache</span>
<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Fibonacci series</span>
<span class="sd"> >>> fib(1)</span>
<span class="sd"> 1</span>
<span class="sd"> >>> fib(2)</span>
<span class="sd"> 2</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="n">x</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">'Must be greater than 0'</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">x</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">fib</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
<p>And here’s a unittest that asserts that the cache function only allows calls
through when there is no value saved in the <cite>vals</cite> dict.</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">unittest</span>
<span class="kn">from</span> <span class="nn">mock</span> <span class="kn">import</span> <span class="n">Mock</span>
<span class="k">class</span> <span class="nc">TestCashDecorator</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_cache</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">my_fn</span> <span class="o">=</span> <span class="n">Mock</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'my_fn'</span><span class="p">)</span>
<span class="n">my_fn</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="s1">'hi'</span>
<span class="n">wrapped</span> <span class="o">=</span> <span class="n">cache</span><span class="p">(</span><span class="n">my_fn</span><span class="p">)</span>
<span class="c1"># First call gives a call count of 1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">wrapped</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="s1">'hi'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">my_fn</span><span class="o">.</span><span class="n">call_count</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># Second call keeps the call count at 1 - the cached value is used</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">wrapped</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="s1">'hi'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">my_fn</span><span class="o">.</span><span class="n">call_count</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># Subsequent call with a new value increased the call count</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">wrapped</span><span class="p">(</span><span class="mi">7</span><span class="p">),</span> <span class="s1">'hi'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">my_fn</span><span class="o">.</span><span class="n">call_count</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
</li>
<li><p class="first">Make sure the scope of variables used in the decorators is correct, this is
<a class="reference external" href="http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/">an interesting article by Simeon Franklin about decorators and scope</a>.</p>
<p>If in doubt, extend any tests to test a second decorated function and ensure
that the two functions do not effect each other.</p>
<p>Below is a test that aims to check that cache dictionaries are not shared
between instances of the <cite>cache</cite> decorator, it is appended to the
<cite>test_cache</cite> test above.</p>
<div class="highlight"><pre><span></span><span class="c1"># Check that the vals dict isn't shared between other decor</span>
<span class="n">my_other_fn</span> <span class="o">=</span> <span class="n">Mock</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'other fn'</span><span class="p">)</span>
<span class="n">my_other_fn</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="s1">'other hi'</span>
<span class="c1"># Create other wrapped function</span>
<span class="n">other_wrapped</span> <span class="o">=</span> <span class="n">cache</span><span class="p">(</span><span class="n">my_other_fn</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">other_wrapped</span><span class="p">(</span><span class="mi">7</span><span class="p">),</span> <span class="s1">'other hi'</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">my_other_fn</span><span class="o">.</span><span class="n">call_count</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># The original function has not have been additionally called, its</span>
<span class="c1"># call count remains 2</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">my_fn</span><span class="o">.</span><span class="n">call_count</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
</li>
</ul>
<p>All suggested tips on decorators very welcome - thanks for reading!</p>
Calculating your day rate for spare time freelance work2013-07-14T20:00:00+01:002013-07-14T20:00:00+01:00Jamestag:jamescooke.info,2013-07-14:/calculating-your-day-rate-for-spare-time-freelance-work.html<p class="first last">So you want to earn some extra cash on your weekends, what should you charge?</p>
<p>So you want to do some freelance work and you’re not sure how much to charge
your new client. The most important thing is to not underestimate your value -
it frustrates me so much when I hear of a talented coder selling themselves short.</p>
<div class="section" id="the-calculation">
<h2>The calculation</h2>
<p>When you work for yourself, it’ll be like your day job, except you keep the
profit and take the additional time and cost overheads.</p>
<p>This calculation has worked well for me in the past, so I’m sharing it here.
It’s so simple. I hope it can work for you.</p>
<div class="math">
\begin{equation*}
Your Day Rate = \frac {2\times Your Annual Salary} {252 - Number Of Days Holiday}
\end{equation*}
</div>
<p>Where:</p>
<ul class="simple">
<li><span class="quo">‘</span>2’ is my freelance multiplier.</li>
<li><span class="quo">‘</span>252’ is the number of working days in a year - an estimate.</li>
</ul>
</div>
<div class="section" id="why-is-this-based-on-my-current-salary">
<h2><span class="dquo">“</span>Why is this based on my current salary?”</h2>
<p>I assume you will be doing some work similar to your day job. This means that
you can use your usual salary as a base unit for calculating your day rate.</p>
<p>If you don’t have a day job and all your income will be from self-employment,
then I would guess that you will have an idea what your employed market value
would be in the kind of business you’ll be selling your services to is.</p>
</div>
<div class="section" id="why-is-the-multiplier-2">
<h2><span class="dquo">“</span>Why is the multiplier 2?”</h2>
<p>Remember, the value of the work that you provide a company is greater than the
amount that you are paid:</p>
<ul class="simple">
<li>In the <span class="caps">UK</span>, your employer pays an employment tax - <a class="reference external" href="https://www.gov.uk/national-insurance-rates-letters#2">Employers’ National
Insurance Contributions</a>.</li>
<li>Your employer pays overheads as part of your employment which you might not
be exposed to. The cost of your equipment, heating and lighting your work
space, insuring you at work, payroll costs… All these overheads mount up
and you will be taking these on when you’re working freelance.</li>
<li>Any successful business must sell the goods or services at a profit.
Therefore, if you’re contributing code to a project, then the future or
immediate value of your contribution should be greater than your input for a
business to be making a profit from you.</li>
</ul>
<p>You can play with this number of course, but a factor of 2 has worked for me in
the past.</p>
<p>One assumption is that you’re going to do this new project in your free time,
probably on the weekends and evenings. Usually this would earn an overtime rate
for someone on an hourly wage - usually double time or time and a half.</p>
<p>If you’re in the <span class="caps">UK</span>, more free time will be taken up managing a tax-return,
paying <a class="reference external" href="https://www.gov.uk/set-up-sole-trader"><span class="caps">HMRC</span> for additional National Insurance Contributions</a>, invoicing and
keeping records. You need to ensure that this time is covered in some way by
the income from your freelance work.</p>
</div>
<div class="section" id="what-if-my-new-client-is-too-poor-too-rich-to-afford-x">
<h2><span class="dquo">“</span>What if my new client is too poor / too rich to afford £X?”</h2>
<p>Of course, you’re perfectly allowed to adjust this if you want to give away
some of your work at less than the market rate. Remember, your employer is
already paying something along the lines of what you’ve just calculated for
your time. Carefully consider how much you should adjust that for someone else.</p>
<p>In my previous businesses I’ve charged all clients the same basic rate for the
simple reason that it’s easier on the books and my brain.</p>
</div>
<div class="section" id="in-the-end">
<h2>In the end</h2>
<p>As you work more freelance jobs you’ll get a feel for what’s suitable and
what’s not.</p>
<p>I hope this has been helpful.</p>
<p>Good luck!</p>
</div>
<script type='text/javascript'>if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
var align = "center",
indent = "0em",
linebreak = "false";
if (false) {
align = (screen.width < 768) ? "left" : align;
indent = (screen.width < 768) ? "0em" : indent;
linebreak = (screen.width < 768) ? 'true' : linebreak;
}
var mathjaxscript = document.createElement('script');
mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
mathjaxscript.type = 'text/javascript';
mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.3/latest.js?config=TeX-AMS-MML_HTMLorMML';
var configscript = document.createElement('script');
configscript.type = 'text/x-mathjax-config';
configscript[(window.opera ? "innerHTML" : "text")] =
"MathJax.Hub.Config({" +
" config: ['MMLorHTML.js']," +
" TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'none' } }," +
" jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
" extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
" displayAlign: '"+ align +"'," +
" displayIndent: '"+ indent +"'," +
" showMathMenu: true," +
" messageStyle: 'normal'," +
" tex2jax: { " +
" inlineMath: [ ['\\\\(','\\\\)'] ], " +
" displayMath: [ ['$$','$$'] ]," +
" processEscapes: true," +
" preview: 'TeX'," +
" }, " +
" 'HTML-CSS': { " +
" availableFonts: ['STIX', 'TeX']," +
" preferredFont: 'STIX'," +
" styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
" linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
" }, " +
"}); " +
"if ('default' !== 'default') {" +
"MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
"var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
"VARIANT['normal'].fonts.unshift('MathJax_default');" +
"VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
"VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
"VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
"});" +
"}";
(document.body || document.getElementsByTagName('head')[0]).appendChild(configscript);
(document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
</script>Pyramid London talk - A testing strategy for Pyramid Applications2013-06-16T21:00:00+01:002013-06-16T21:00:00+01:00Jamestag:jamescooke.info,2013-06-16:/pyramid-london-talk-a-testing-strategy-for-pyramid-applications.html<p class="first last">Talk at Pyramid London meetup about testing strategies for Pyramid applications.</p>
<p>Pyramid London meetup returned in June to <a class="reference external" href="https://skillsmatter.com/">Skills Matter</a>. This time I spoke about testing strategies for Pyramid applications.</p>
<p>As outlined in the slides below, my current testing framework builds up with doctests, through unit and integration tests to functional / behaviour driven testing on the outside of the application. Hopefully my very basic “drawn on Google Docs” diagram of the Pyramid Framework illustrates how each of the testing methods fits within the framework.</p>
<p>I would like to have been able to talk more about Behaviour Driven Development and <a class="reference external" href="https://behave.readthedocs.io/en/latest/">testing with Behave</a>, which I’m enjoying at the moment, but maybe that’s for another presentation. Again, putting together this presentation was really helpful - it helped me to reflect on the methods we’re using at the moment, and how I might be able to improve and progress the level of test driven development in my daily work.</p>
<br>
<script async class="speakerdeck-embed" data-id="57b235d0b8f1013000d27aa19dd2a8cb" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<br><p><a class="reference external" href="https://skillsmatter.com/skillscasts/4265-pyramid-sqlalchemy-testing-and-auth-policy">Video is available via the SkillsMatter site</a>.</p>
<p>Many thanks to <a class="reference external" href="http://lucumr.pocoo.org/">Armin Ronacher</a> for his talk on <a class="reference external" href="https://docs.sqlalchemy.org/en/latest/">SQLAlchemy</a> at the same Pyramid meetup - the <a class="reference external" href="https://skillsmatter.com/skillscasts/4266-pyramid-sqlalchemy-testing-and-auth-policy-4266">video is also online at SkillsMatter</a>. As well as the technical details and some hints for things to check out with <span class="caps">SQLA</span>, I found Armin’s thoughts on how the Pyramid community might improve on how we introduce new developers to Pyramid and SQLAlchemy very helpful. I hope I might be able to contribute to that some time in the future.
Hopefully we’ll see more people at the next Pyramid Meetup which may include a talk on using <a class="reference external" href="http://www.celeryproject.org/">Celery</a> with Pyramid.</p>
Pyramid London talk - Pyramid Router2013-05-08T23:00:00+01:002013-05-08T23:00:00+01:00Jamestag:jamescooke.info,2013-05-08:/pyramid-london-talk-pyramid-router.html<p class="first last">Talk at the first Pyramid London meetup about the Pyramid Router, <span class="caps">URL</span> Traversal and Dispatch.</p>
<p>Our first Pyramid London meetup was kindly hosted at <a class="reference external" href="https://skillsmatter.com/">Skills Matter</a>, who have <a class="reference external" href="https://skillsmatter.com/skillscasts/4189-routing-traversal-and-url-dispatch">posted the video of my talk on their page for the meetup</a>.</p>
<br>
<script async class="speakerdeck-embed" data-id="76686b40b8ed01307b196e084453428f" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<br><p>All the code I demonstrated is on <a class="reference external" href="https://github.com/jamescooke/pyramid-london-talk">GitHub in the pyramid-london-talk repository</a> - Please note that the traversal code is in the traversal branch, not in a separate project.</p>
<p>I learned loads from preparing the demonstration code and chatting to everyone that attended - so thanks and hope to see you at the next meetup in June!</p>
Reincublog Django app2013-04-28T13:00:00+01:002013-04-28T13:00:00+01:00Jamestag:jamescooke.info,2013-04-28:/reincublog-django-app.html<p class="first last">Reincublog is a super mini Django blog weekend hack, coded as part of a recruitment process.</p>
<p>Reincublog is a Django app that I was asked to code as part of the recruitment process at Reincubate. It’s a weekend of glue code which I was set to see if I am a competent Django programmer. I’m not sure that it’s the kind of test that I show my best at - I’m more of an algorithm guy.</p>
<p>However, after living on GitHub for a few months, the repo has picked up a couple of stars, and because I like to keep a super clean GitHub account, I’ve decided to clean it out of my account.</p>
<p>So, from today the <a class="reference external" href="https://github.com/shonenada/reincublog">Reincublog code</a> will live on <a class="reference external" href="https://github.com/shonenada">shonenada’s GitHub</a> hopefully it can grow and be useful.</p>
Migrating from Django 1.4 to 1.5 - Lessons learned2013-03-29T19:00:00+00:002013-03-29T19:00:00+00:00Jamestag:jamescooke.info,2013-03-29:/migrating-from-django-14-to-15-lessons-learned.html<p class="first last">Migrating a project from Django 1.4 to Django 1.5 had a couple of gotchas that cost me dev time.</p>
<p>From <a class="reference external" href="https://twitter.com/ryankask/">Ryan Kaskel</a>‘s talk at <a class="reference external" href="https://www.meetup.com/The-London-Django-Meetup-Group/">Django London</a> in November last
year, I guessed that upgrading the <a class="reference external" href="https://github.com/jamescooke/actionguide">Action Guide code</a> from Django 1.4 to 1.5 might have
created some issues with users (<a class="reference external" href="https://docs.djangoproject.com/en/dev/releases/1.5/#configurable-user-model">user models have changed in Django 1.5 to
allow more customisation</a>).</p>
<p>However, as it turns out, the main problems were with settings and urls, the
users were fine. My main take-aways were:</p>
<div class="section" id="url-formats-have-changed-now-need-quotes">
<h2>Url formats have changed - now need quotes</h2>
<p>The Django team had already updated the <cite>url</cite> tag to accept the path parameter
as a string, but the old syntax was still allowed. 1.4 allowed both types of
syntax, the team having provided <cite>{% load url from future %}</cite> for those that
wanted to update their templates to the new syntax.</p>
<p>Here’s the warning from the <a class="reference external" href="https://docs.djangoproject.com/en/1.5/ref/templates/builtins/#std:templatetag-url"><span class="caps">URL</span> tag documentation</a>.</p>
<img alt="Screenshot of warning from Django documentation. Warning reads: "Don't forget to put quotes around the function path or pattern name!" src="https://jamescooke.info/images/url-warning.png" />
<p>This was a reasonably easy change to implement - some search and replace and
all <cite>url</cite> tags can be easily hunted down and changed.</p>
</div>
<div class="section" id="read-up-on-the-settings-no-allowed-hosts-makes-500s">
<h2>Read up on the settings - no ALLOWED_HOSTS makes 500s</h2>
<p>This was the real killer.</p>
<p>There is a <a class="reference external" href="https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts">new ALLOWED_HOSTS settings in 1.5</a> required
to get Django and running in non-debug mode.</p>
<p>Worst thing about the implementation of this new setting is that I couldn’t get
a single bit of debugging output it through <cite>wsgi</cite> on WebFaction - just a 500
error on every page load when I took the site out of debug mode.</p>
<p>I was so confused that I posted <a class="reference external" href="https://stackoverflow.com/questions/15605185/django-1-5-url-deprecation-warning-causes-500-error-in-webfaction-apache-wsgi/15626247">this question on StackOverflow</a>,
thinking the problem was <cite>url</cite> warnings being shown as errors and halting the
<cite>wsgi</cite>. In the end, just adding <cite>ALLOWED_HOSTS</cite> fixed everything up great.</p>
<p>My main problem was that I scanned the docs, tested the migration on localhost
in dev mode, and just expected everything to deploy. With Captain Hindsight,
I’d have RTFMed much harder before deploying - a lesson for the future.</p>
<p>Apart from that, everything works really well. <strong>Have fun!</strong></p>
</div>
Pelican Svbtle theme tweaks2013-02-21T19:40:00+00:002013-02-21T19:40:00+00:00Jamestag:jamescooke.info,2013-02-21:/pelican-svbtle-theme-tweaks.html<p class="first last">A tweaked fork of the Pelican Svbtle theme with some cleaned <span class="caps">CSS</span> and <span class="caps">HTML</span>.</p>
<p>My first experiments with <a class="reference external" href="https://blog.getpelican.com/">Pelican</a> to run this blog have been good - it’s a great way to publish static pages quickly and I find it much easier to manage than Octopress.</p>
<p>It’s built on a version of the <a class="reference external" href="https://github.com/wting/pelican-svbtle">Pelican-svbtle theme</a>. There were some problems with the theme in its current form, so I’ve forked <a class="reference external" href="https://github.com/CNBorn/pelican-svbtle">CNBorn’s already adjusted version</a> and cleaned out some of the <span class="caps">LESS</span> and templates - <a class="reference external" href="https://github.com/jamescooke/pelican-svbtle">my fork is on GitHub</a>.</p>
<p>However, this theme isn’t going to stay. <a class="reference external" href="https://github.com/thesocialspaces">Paul</a> has been working on some flat <span class="caps">HTML</span> based on Bootstrap to make a new clean theme. Once that’s stable, I’ll plug in some Pelican / Jinja2 tags and hopefully this site will have a new clean theme soon.</p>
jsFiddle documentation update2013-01-25T19:40:00+00:002013-01-25T19:40:00+00:00Jamestag:jamescooke.info,2013-01-25:/jsfiddle-documentation-update.html<p class="first last">A newly structured documentation site and tutorial for the online editor.</p>
<p><a class="reference external" href="http://doc.jsfiddle.net/">Updated documentation</a> for <a class="reference external" href="https://jsfiddle.net/">jsFiddle</a>, <a class="reference external" href="https://github.com/jsfiddle/jsfiddle-docs-alpha/commit/ef0f234e44e5a6d6791c09e672364fdf9518a31a">merged by Piotr</a>.</p>
<p>Includes a new <a class="reference external" href="http://doc.jsfiddle.net/tutorial.html">tutorial</a> - but images are already out of date!</p>
<p>jsFiddle is such a great tool and my goal for the tutorial was to create a simple introduction which first time students would be able to understand and execute.</p>
Setting up this homepage with Pelican2013-01-20T17:25:00+00:002013-01-20T17:25:00+00:00Jamestag:jamescooke.info,2013-01-20:/setting-up-this-homepage-with-pelican.html<p class="first last">Using Pelican to generate this blog, a move away from Jekyll and to
some pure Python.</p>
<p>This page has been through a lot in the last ten years.</p>
<p>Since starting work at Quibly, I’ve had a lot more time to code and it’s exactly what I wanted, hopefully it’ll continue. The result of that is that I’ve got more to write about… The code that I develop at work, fixes I make to open source libraries and general things I learn, primarily about Python and web - hopefully all valuable and worth sharing.</p>
<p>I’m experimenting with <a class="reference external" href="https://github.com/getpelican/pelican">Pelican</a> - a static blog generator written in Python. It’s excellent and noticeably easier than Jekyll - probably because I’m much more clued up in Python than Ruby. I’m lazy, so I’m hosting the outputted static files in the <tt class="docutils literal"><span class="pre">gh-pages</span></tt> branch of the <a class="reference external" href="https://github.com/jamescooke/blog/">blog’s repository</a> to take advantage of <a class="reference external" href="https://pages.github.com/">GitHub Pages’ free hosting features</a> - thanks GitHub!</p>
<p>In addition, I found <a class="reference external" href="https://www.davidfischer.name/2012/12/quick-note-pelican-github/">this article by David Fischer</a> very helpful. Particularly the suggestion of adding the <tt class="docutils literal"><span class="caps">CNAME</span></tt> copy command to the <tt class="docutils literal">Makefile</tt> to get GitHub Pages one configuration requirement and <tt class="docutils literal"><span class="pre">gph-import</span></tt> working nicely together. Plus David pointed out that Pelican already has a <tt class="docutils literal">github</tt> target in the <tt class="docutils literal">Makefile</tt> which I hadn’t noticed and is now what I use to push articles live.</p>
<p>All in all - great and simple.</p>
Got the Stack Overflow tumbleweed badge for Mako filters question2013-01-20T16:40:00+00:002013-01-20T16:40:00+00:00Jamestag:jamescooke.info,2013-01-20:/got-the-stack-overflow-tumbleweed-badge-for-mako-filters-question.html<p class="first last">My Mako question got no views and no answers - should we be using Mako if things are so quiet?</p>
<p>Last week I posted a question on Stack Overflow - “<a class="reference external" href="https://stackoverflow.com/questions/14215591/mako-template-filter-ordering">Mako template filter
ordering</a>”
- this week it earned the <a class="reference external" href="https://stackoverflow.com/help/badges/63/tumbleweed">Tumbleweed badge</a>.</p>
<p>It’s always a little concerning when libraries and toolkits you’re using in a
project have forums and message boards that are a little too quiet - is there a
bad smell? Is there something bad I don’t know about this tech? Even worse is
when you look around those quiet forums (or tags in Stack Overflow) you find
comments like this about the library you’re being asked to use:</p>
<img alt="Screenshot of comment on StackOverflow. Comment reads: "Suggestion: Don't use Mako. It's horrible. [...]"" src="https://jamescooke.info/images/mako.png" />
<p>You should listen to a <a class="reference external" href="https://stackoverflow.com/questions/10870379/is-there-an-equivalent-to-django-template-filters-in-mako">Stack Overflow moderator who has 93K points</a>
at time of writing right?</p>
<p>Meanwhile… I haven’t found the reason for the template filter ordering being
strange - and I still think that the <tt class="docutils literal">h</tt> filter is putting itself last in the
mako render order, but now I’ve got a work around, I’m going back to post it.</p>
<p>Maybe 10 more people will see it before Easter - it might even help someone.</p>
Password cases and test fixes on pyramid_simpleauth2012-11-30T12:00:00+00:002012-11-30T12:00:00+00:00Jamestag:jamescooke.info,2012-11-30:/password-cases-and-test-fixes-on-pyramid_simpleauth.html<p class="first last">Updates to pyramid_simpleauth to allow for uppercase passwords and some bug fixes.</p>
<p>At Quibly we’re using Pyramid at the centre of a Python framework. Providing user functionality is the <a class="reference external" href="https://github.com/thruflo/pyramid_simpleauth">pyramid_simpleauth</a> library.</p>
<p>While writing integration tests before we put the site live, I found that my test users we not able to authenticate with their testing passwords (usually just a simple string like ‘Password’). Digging inside the simpleauth library, I found some fixes necessary to how cases are handled by the lib - plus also fixed some doctests while I was at it.</p>
<p>These <a class="reference external" href="https://github.com/thruflo/pyramid_simpleauth/pull/7">changes</a> all
been merged now and the library rolled up a version.</p>
Django-mailchimp compatability with v1.3 API2012-09-25T07:14:00+01:002012-09-25T07:14:00+01:00Jamestag:jamescooke.info,2012-09-25:/django-mailchimp-compatability-with-v13-api.html<p class="first last">Some small updates to the django-mailchimp library to upgrade to the latest Mailchimp <span class="caps">API</span>.</p>
<p>For a <a class="reference external" href="/pages/fublo-ltd.html">Fublo</a> project with <a class="reference external" href="https://www.neuxpower.com/">Neuxpower</a>, we had to communicate with <a class="reference external" href="https://developer.mailchimp.com/">Mailchimp via their
<span class="caps">API</span></a>. On Django one of the best libraries for
this is <a class="reference external" href="https://github.com/piquadrat/django-mailchimp">django-mailchimp</a>.</p>
<p>However, in its previous state django-mailchimp wasn’t able to specify a <tt class="docutils literal">send_welcome</tt> parameter which lets Mailchimp know whether it should send out a list welcome message when a new user subscribes. For the project, we were managing the signup explicitly with Neuxpower’s code, so no welcome message was required and the default for Mailchimp was <tt class="docutils literal">True</tt> for sending meaning that Neuxpower’s new customers would get hit with a double welcome message… Not desirable.</p>
<p>This <a class="reference external" href="https://github.com/piquadrat/django-mailchimp/pull/6">small change</a> is now merged in with the library, which has rolled up to a ‘v1.3’ status as there is no backward compatibility.</p>
Fixing exception in django-menu2012-05-05T19:40:00+01:002012-05-05T19:40:00+01:00Jamestag:jamescooke.info,2012-05-05:/fixing-exception-in-django-menu.html<p class="first last">A tiny pull request to stop django-menu from throwing exceptions on
new unconfigured sites.</p>
<p><a class="reference external" href="https://github.com/rossp/django-menu/">django-menu</a> is a nice simple library for building very simple menus. However, when a site is loaded for the first time, the menu structure was not configured and so it was throwing a <tt class="docutils literal">DoesNotExist</tt> Exception.</p>
<p>This tiny <a class="reference external" href="https://github.com/rossp/django-menu/pull/5">pull request</a> simply
wrapped the call to the menu in a <tt class="docutils literal">try</tt>/<tt class="docutils literal">except</tt> so that new sites using
django-menu won’t fall over on first load.</p>