<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kelvin Wangonya</title><link>https://wangonya.com/</link><description>Recent content on Kelvin Wangonya</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://wangonya.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Handling missing dict keys, revisited</title><link>https://wangonya.com/blog/handling-missing-dict-keys-revisited/</link><pubDate>Wed, 08 Apr 2026 07:00:59 +0300</pubDate><guid>https://wangonya.com/blog/handling-missing-dict-keys-revisited/</guid><description>&lt;p>A while back, I wrote a &lt;a href="https://wangonya.com/blog/handling-missing-dict-keys/">post&lt;/a> showing how to handle missing dict keys. In summary:&lt;/p>
&lt;ul>
&lt;li>Using &lt;code>setdefault&lt;/code>&lt;/li>
&lt;li>Using &lt;code>defaultdict&lt;/code>&lt;/li>
&lt;li>Implementing &lt;code>__missing__&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>While the advice there still stands, I&amp;rsquo;ve been reading through Fluent Python and came across two things worth being aware of when subclassing &lt;code>dict&lt;/code>:&lt;/p>
&lt;ol>
&lt;li>&lt;code>__contains__&lt;/code> doesn&amp;rsquo;t call &lt;code>__missing__&lt;/code>, so &lt;code>k in d&lt;/code> returns &lt;code>False&lt;/code> for keys not yet set, even if &lt;code>__missing__&lt;/code> would handle them&lt;/li>
&lt;li>&lt;code>dict.get&lt;/code> doesn&amp;rsquo;t call &lt;code>__missing__&lt;/code>, so &lt;code>.get(k)&lt;/code> won&amp;rsquo;t use your custom default&lt;/li>
&lt;/ol>
&lt;p>Both are by design and often what you want. &lt;code>__missing__&lt;/code> is only used by &lt;code>d[key]&lt;/code>, not other dict methods. Even &lt;code>defaultdict&lt;/code> follows the same rule: only &lt;code>d[key]&lt;/code> triggers the default factory and methods like &lt;code>.get()&lt;/code> and &lt;code>in&lt;/code> do not.&lt;/p></description></item><item><title>On Disabling Javascript</title><link>https://wangonya.com/blog/on-disabling-javascript/</link><pubDate>Fri, 24 Oct 2025 16:37:29 +0300</pubDate><guid>https://wangonya.com/blog/on-disabling-javascript/</guid><description>&lt;blockquote>
&lt;p>Update 2025-11-25: After trying this for about three weeks, I&amp;rsquo;ve found that disabling Javascript by default is really inconvenient.
Many sites just don&amp;rsquo;t work properly without it, and having to manually enable it every time is a hassle.
I guess that&amp;rsquo;s the tradeoff one would have to make in this case, but I probably just don&amp;rsquo;t care enough at the moment
to go ahead with this. Of course I might revisit this again later, but for now it&amp;rsquo;s back to the default browsing experience.&lt;/p></description></item><item><title>Handling NULL values for "not equal" checks in SQL</title><link>https://wangonya.com/blog/mysql-where-not-equal-null/</link><pubDate>Mon, 19 May 2025 11:08:03 +0300</pubDate><guid>https://wangonya.com/blog/mysql-where-not-equal-null/</guid><description>&lt;p>This one bit me today. Apparently &lt;code>NULL&lt;/code> values give unexpected results when checked using &lt;code>!=&lt;/code> or &lt;code>&amp;lt;&amp;gt;&lt;/code>.&lt;/p>
&lt;p>For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="n">id&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">competitor_type&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">--------------------------------
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Ariya&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Frontier&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">NULL&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Rogue&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Competitor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Sentra&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Non&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">competitor&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">table&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">WHERE&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LOWER&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">competitor_type&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">!=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;non-competitor&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I expected to see ids 1, 2 and 3 as a result, but only got 3.&lt;/p></description></item><item><title>Be careful with join type typos</title><link>https://wangonya.com/blog/join-typo/</link><pubDate>Thu, 07 Nov 2024 09:00:30 +0300</pubDate><guid>https://wangonya.com/blog/join-typo/</guid><description>&lt;p>I noticed a typo in one of my sql queries today, but the funny thing is the query still worked fine.
It looked something like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">table_1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line hl">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="n">LEFFT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">table_2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">USING&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">b&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At first I thought BigQuery was pretty smart and just assumed I meant &lt;code>LEFT&lt;/code> instead.
Maybe it&amp;rsquo;s a common typo and there&amp;rsquo;s an alias for it. So I got curious and tried out this:&lt;/p></description></item><item><title>with statements don't create scope</title><link>https://wangonya.com/blog/with-scope/</link><pubDate>Tue, 01 Oct 2024 16:27:39 +0300</pubDate><guid>https://wangonya.com/blog/with-scope/</guid><description>&lt;p>I saw some code today that initialized a variable inside &lt;code>with&lt;/code> and continued to use it outside the block.
I&amp;rsquo;ve always assumed &lt;code>with&lt;/code> statements had their own scope so this had me a little confused. Turns out this is perfectly fine.&lt;/p>
&lt;blockquote>
&lt;/blockquote>
&lt;blockquote>
&lt;p>A &lt;code>with&lt;/code> statement does not create a scope (like &lt;code>if&lt;/code>, &lt;code>for&lt;/code> and &lt;code>while&lt;/code> do not create a scope either).&lt;/p>
&lt;p>As a result, Python will analyze the code and see that you made an assignment in the &lt;code>with&lt;/code> statement, and thus that will make the variable local (to the real scope).&lt;/p></description></item><item><title>Spotify Cleaner</title><link>https://wangonya.com/blog/spotify-cleaner/</link><pubDate>Wed, 25 Sep 2024 08:09:31 +0300</pubDate><guid>https://wangonya.com/blog/spotify-cleaner/</guid><description>&lt;p>I&amp;rsquo;ve had my Spotify account for a long time, and over that time, my musical tastes have evolved.
As a consequence, there are a lot of liked songs, playlists, and podcasts I no longer listen to but have in my library.
There&amp;rsquo;s nothing wrong with keeping them in the library—I don&amp;rsquo;t have them downloaded, so they&amp;rsquo;re not really taking up any space—but I don&amp;rsquo;t like the clutter.&lt;/p>
&lt;p>As far as I know, Spotify doesn&amp;rsquo;t provide any way to batch delete things, so I created a &lt;a href="https://github.com/wangonya/spotify-cleaner">spotify-cleaner&lt;/a> for this.&lt;/p></description></item><item><title>man pages have sections!</title><link>https://wangonya.com/blog/man-pages-sections/</link><pubDate>Wed, 25 Sep 2024 05:47:44 +0300</pubDate><guid>https://wangonya.com/blog/man-pages-sections/</guid><description>&lt;p>I noticed this when reading through &lt;a href="https://beej.us/guide/bgc/html/split/index.html">Beej&amp;rsquo;s Guide to C Programming&lt;/a>. While explaining &lt;code>printf&lt;/code>, reference is made to &lt;code>man 3 printf&lt;/code> - which looked different from how I usually run &lt;code>man&lt;/code>. Why the &lt;code>3&lt;/code>?&lt;/p>
&lt;p>So I ran &lt;code>man printf&lt;/code> instead. Output:&lt;/p>



&lt;div class="goat svg-container ">
 
 &lt;svg
 xmlns="http://www.w3.org/2000/svg"
 font-family="Menlo,Lucida Console,monospace"
 
 viewBox="0 0 880 89"
 >
 &lt;g transform='translate(8,16)'>
&lt;text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>P&lt;/text>
&lt;text text-anchor='middle' x='0' y='36' fill='currentColor' style='font-size:1em'>N&lt;/text>
&lt;text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>R&lt;/text>
&lt;text text-anchor='middle' x='8' y='36' fill='currentColor' style='font-size:1em'>A&lt;/text>
&lt;text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>I&lt;/text>
&lt;text text-anchor='middle' x='16' y='36' fill='currentColor' style='font-size:1em'>M&lt;/text>
&lt;text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>N&lt;/text>
&lt;text text-anchor='middle' x='24' y='36' fill='currentColor' style='font-size:1em'>E&lt;/text>
&lt;text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>T&lt;/text>
&lt;text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>F&lt;/text>
&lt;text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>(&lt;/text>
&lt;text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>1&lt;/text>
&lt;text text-anchor='middle' x='56' y='52' fill='currentColor' style='font-size:1em'>p&lt;/text>
&lt;text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>)&lt;/text>
&lt;text text-anchor='middle' x='64' y='52' fill='currentColor' style='font-size:1em'>r&lt;/text>
&lt;text text-anchor='middle' x='72' y='52' fill='currentColor' style='font-size:1em'>i&lt;/text>
&lt;text text-anchor='middle' x='80' y='52' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='88' y='52' fill='currentColor' style='font-size:1em'>t&lt;/text>
&lt;text text-anchor='middle' x='96' y='52' fill='currentColor' style='font-size:1em'>f&lt;/text>
&lt;text text-anchor='middle' x='112' y='52' fill='currentColor' style='font-size:1em'>-&lt;/text>
&lt;text text-anchor='middle' x='128' y='52' fill='currentColor' style='font-size:1em'>f&lt;/text>
&lt;text text-anchor='middle' x='136' y='52' fill='currentColor' style='font-size:1em'>o&lt;/text>
&lt;text text-anchor='middle' x='144' y='52' fill='currentColor' style='font-size:1em'>r&lt;/text>
&lt;text text-anchor='middle' x='152' y='52' fill='currentColor' style='font-size:1em'>m&lt;/text>
&lt;text text-anchor='middle' x='160' y='52' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='168' y='52' fill='currentColor' style='font-size:1em'>t&lt;/text>
&lt;text text-anchor='middle' x='184' y='52' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='192' y='52' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='200' y='52' fill='currentColor' style='font-size:1em'>d&lt;/text>
&lt;text text-anchor='middle' x='216' y='52' fill='currentColor' style='font-size:1em'>p&lt;/text>
&lt;text text-anchor='middle' x='224' y='52' fill='currentColor' style='font-size:1em'>r&lt;/text>
&lt;text text-anchor='middle' x='232' y='52' fill='currentColor' style='font-size:1em'>i&lt;/text>
&lt;text text-anchor='middle' x='240' y='52' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='248' y='52' fill='currentColor' style='font-size:1em'>t&lt;/text>
&lt;text text-anchor='middle' x='264' y='52' fill='currentColor' style='font-size:1em'>d&lt;/text>
&lt;text text-anchor='middle' x='272' y='52' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='280' y='52' fill='currentColor' style='font-size:1em'>t&lt;/text>
&lt;text text-anchor='middle' x='288' y='52' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='384' y='4' fill='currentColor' style='font-size:1em'>U&lt;/text>
&lt;text text-anchor='middle' x='392' y='4' fill='currentColor' style='font-size:1em'>s&lt;/text>
&lt;text text-anchor='middle' x='400' y='4' fill='currentColor' style='font-size:1em'>e&lt;/text>
&lt;text text-anchor='middle' x='408' y='4' fill='currentColor' style='font-size:1em'>r&lt;/text>
&lt;text text-anchor='middle' x='424' y='4' fill='currentColor' style='font-size:1em'>C&lt;/text>
&lt;text text-anchor='middle' x='432' y='4' fill='currentColor' style='font-size:1em'>o&lt;/text>
&lt;text text-anchor='middle' x='440' y='4' fill='currentColor' style='font-size:1em'>m&lt;/text>
&lt;text text-anchor='middle' x='448' y='4' fill='currentColor' style='font-size:1em'>m&lt;/text>
&lt;text text-anchor='middle' x='456' y='4' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='464' y='4' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='472' y='4' fill='currentColor' style='font-size:1em'>d&lt;/text>
&lt;text text-anchor='middle' x='480' y='4' fill='currentColor' style='font-size:1em'>s&lt;/text>
&lt;text text-anchor='middle' x='800' y='4' fill='currentColor' style='font-size:1em'>P&lt;/text>
&lt;text text-anchor='middle' x='808' y='4' fill='currentColor' style='font-size:1em'>R&lt;/text>
&lt;text text-anchor='middle' x='816' y='4' fill='currentColor' style='font-size:1em'>I&lt;/text>
&lt;text text-anchor='middle' x='824' y='4' fill='currentColor' style='font-size:1em'>N&lt;/text>
&lt;text text-anchor='middle' x='832' y='4' fill='currentColor' style='font-size:1em'>T&lt;/text>
&lt;text text-anchor='middle' x='840' y='4' fill='currentColor' style='font-size:1em'>F&lt;/text>
&lt;text text-anchor='middle' x='848' y='4' fill='currentColor' style='font-size:1em'>(&lt;/text>
&lt;text text-anchor='middle' x='856' y='4' fill='currentColor' style='font-size:1em'>1&lt;/text>
&lt;text text-anchor='middle' x='864' y='4' fill='currentColor' style='font-size:1em'>)&lt;/text>
&lt;/g>

 &lt;/svg>
 
&lt;/div>
&lt;p>Then &lt;code>man 3 printf&lt;/code>:&lt;/p></description></item><item><title>Learning touch typing</title><link>https://wangonya.com/blog/learning-touch-typing/</link><pubDate>Tue, 27 Aug 2024 06:22:21 +0300</pubDate><guid>https://wangonya.com/blog/learning-touch-typing/</guid><description>&lt;p>I now understand why I&amp;rsquo;ve always had a hard time getting into Vim.
I&amp;rsquo;ve tried it on and off for years, and of everything I&amp;rsquo;ve read about it, I have not seen &amp;lsquo;knowing to type properly&amp;rsquo;
as a prerequisite. I think it is. &amp;lsquo;Keeping your fingers on the home row&amp;rsquo; is a big thing with it,
but this doesn&amp;rsquo;t help if you&amp;rsquo;re not usually typing with your fingers on the home row in the first place.&lt;/p></description></item><item><title>On embracing asynchronous communication</title><link>https://wangonya.com/blog/async-communication/</link><pubDate>Wed, 27 Mar 2024 12:12:34 +0300</pubDate><guid>https://wangonya.com/blog/async-communication/</guid><description>&lt;p>I&amp;rsquo;ve been trying to improve my workflows this year. One thing I&amp;rsquo;ve known for a while, but never really got
serious about implementing, is defaulting to asynchronous communication. I first learned about this concept
a few years ago when reading &lt;a href="https://basecamp.com/handbook/how-we-work#asynchronously">Basecamp&amp;rsquo;s Employee Handbook&lt;/a>.&lt;/p>
&lt;p>I work remotely for a company in the UK, and we use Slack for communication. The timezone difference is only
two/three hours, so the whole team is usually all online at the same time for most of the day. I (and I&amp;rsquo;m sure most other
members of the team) just find it a lot easier to pull someone in for a &amp;lsquo;quick&amp;rsquo; huddle each time there&amp;rsquo;s something
to discuss. I always hesitate before doing this, but end up doing it anyway most of the time. The fact that it is
very easy to do doesn&amp;rsquo;t help. I think it does more harm than good.&lt;/p></description></item><item><title>Pydantic validators don't raise validation errors immediately</title><link>https://wangonya.com/blog/pydantic-validators-raise/</link><pubDate>Wed, 06 Mar 2024 05:15:40 +0300</pubDate><guid>https://wangonya.com/blog/pydantic-validators-raise/</guid><description>&lt;p>This one really had me confused. I was facing an error with &lt;a href="https://docs.pydantic.dev/latest/concepts/validators/">Pydantic validators&lt;/a> which I thought I had handled, but it just didn&amp;rsquo;t work as expected.&lt;/p>
&lt;p>The schema looked something like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-py" data-lang="py">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Schema&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">BaseModel&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dates&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">List&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">end_date&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">Optional&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="nb">str&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@validator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;dates&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">update_date_format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@validator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;start_date&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">set_start_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">values&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># some logic here that expects `dates` to exist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">v&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">values&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;dates&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">v&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nd">@validator&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;end_date&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">def&lt;/span> &lt;span class="nf">set_end_date&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="bp">cls&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">values&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># some logic here that expects `dates` to exist&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">v&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">values&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;dates&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">v&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>My assumption in the last two validators was that &lt;code>dates&lt;/code> would always be available because it&amp;rsquo;s a required field.
To my surprise, an &lt;code>IndexError&lt;/code> was always raised on &lt;code>set_start_date&lt;/code>.&lt;/p></description></item><item><title>Trying out Ubuntu 23.04</title><link>https://wangonya.com/blog/ubuntu-23-04/</link><pubDate>Thu, 07 Sep 2023 05:34:19 +0300</pubDate><guid>https://wangonya.com/blog/ubuntu-23-04/</guid><description>&lt;p>I haven&amp;rsquo;t used Ubuntu since I first discovered Linux 9 years ago in University, so I thought I&amp;rsquo;d give it a try this past weekend.
I didn&amp;rsquo;t like it. I only used it for a day and a half before I had to wipe everything and go back to Manjaro.&lt;/p>
&lt;p>Before I get into the things that really bothered me, here&amp;rsquo;s what I liked:&lt;/p>
&lt;h2 id="1-online-accounts">1. Online accounts&lt;/h2>
&lt;p>This is more of a Gnome thing than Ubuntu, but still, I love that I can add all my online accounts in the settings and have everything synced up automatically in the calendar and email apps.
I love KDE Plasma, but this is the one thing I really miss in it.&lt;/p></description></item><item><title>Python __slots__</title><link>https://wangonya.com/blog/python-slots/</link><pubDate>Tue, 15 Aug 2023 22:03:09 +0300</pubDate><guid>https://wangonya.com/blog/python-slots/</guid><description>&lt;p>I just learned about this today while going through the &lt;a href="https://github.com/dabeaz-course/python-mastery">python mastery&lt;/a> course.
Apparently, some good memory optimization can be done by using it in classes.&lt;/p>
&lt;p>&lt;a href="https://stackoverflow.com/a/28059785/9312256">This answer&lt;/a> does a good job explaining how it works.&lt;/p>
&lt;p>I&amp;rsquo;ve not had a need for it yet, but it&amp;rsquo;s a good thing to keep in mind for when I do end up needing it.&lt;/p></description></item><item><title>Incron</title><link>https://wangonya.com/blog/incron/</link><pubDate>Wed, 12 Jul 2023 08:58:30 +0300</pubDate><guid>https://wangonya.com/blog/incron/</guid><description>&lt;blockquote>
&lt;p>&lt;a href="http://inotify.aiken.cz/?section=incron&amp;amp;page=about&amp;amp;lang=en">incron&lt;/a> is an &amp;ldquo;inotify cron&amp;rdquo; system. It consists of a daemon and a table manipulator. You can use it a similar way as the regular cron. The difference is that the inotify cron handles filesystem events rather than time periods.&lt;/p>&lt;/blockquote>
&lt;p>I use it to auto-commit changes made to specific files to version control.&lt;/p>
&lt;h2 id="example-usage">Example usage&lt;/h2>
&lt;p>View incrontabs:&lt;/p>



&lt;div class="goat svg-container ">
 
 &lt;svg
 xmlns="http://www.w3.org/2000/svg"
 font-family="Menlo,Lucida Console,monospace"
 
 viewBox="0 0 104 25"
 >
 &lt;g transform='translate(8,16)'>
&lt;text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>i&lt;/text>
&lt;text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>c&lt;/text>
&lt;text text-anchor='middle' x='24' y='4' fill='currentColor' style='font-size:1em'>r&lt;/text>
&lt;text text-anchor='middle' x='32' y='4' fill='currentColor' style='font-size:1em'>o&lt;/text>
&lt;text text-anchor='middle' x='40' y='4' fill='currentColor' style='font-size:1em'>n&lt;/text>
&lt;text text-anchor='middle' x='48' y='4' fill='currentColor' style='font-size:1em'>t&lt;/text>
&lt;text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>a&lt;/text>
&lt;text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>b&lt;/text>
&lt;text text-anchor='middle' x='80' y='4' fill='currentColor' style='font-size:1em'>-&lt;/text>
&lt;text text-anchor='middle' x='88' y='4' fill='currentColor' style='font-size:1em'>l&lt;/text>
&lt;/g>

 &lt;/svg>
 
&lt;/div>
&lt;p>Add/edit incrontabs:&lt;/p></description></item><item><title>Taking notes</title><link>https://wangonya.com/blog/notes/</link><pubDate>Fri, 23 Jun 2023 18:26:44 +0300</pubDate><guid>https://wangonya.com/blog/notes/</guid><description>&lt;p>I need to get in the habit of taking notes while I work. Especially when I&amp;rsquo;m debugging.
I&amp;rsquo;ve noticed a poor habit recur when I&amp;rsquo;m working on a particularly difficult problem.&lt;/p>
&lt;p>It usually goes something like this:&lt;/p>
&lt;ul>
&lt;li>Start working on problem. Do some research. Try out &lt;code>A&lt;/code>.&lt;/li>
&lt;li>&lt;code>A&lt;/code> doesn&amp;rsquo;t work. Do some more research. Try &lt;code>B&lt;/code>.&lt;/li>
&lt;li>&lt;code>B&lt;/code> doesn&amp;rsquo;t work.&lt;/li>
&lt;li>Try &lt;code>C&lt;/code>. Nothing.&lt;/li>
&lt;li>At this point I&amp;rsquo;m already tired so I think to myself, &amp;ldquo;&lt;code>A&lt;/code> seems like a pretty good idea. Why didn&amp;rsquo;t it work? Let&amp;rsquo;s try it again.&amp;rdquo;.&lt;/li>
&lt;li>Oh, that&amp;rsquo;s why &lt;code>A&lt;/code> didn&amp;rsquo;t work. Of course.&lt;/li>
&lt;li>Try some variation of &lt;code>B&lt;/code>.&lt;/li>
&lt;li>Try &lt;code>C&lt;/code> again.&lt;/li>
&lt;li>Think about &lt;code>A&lt;/code> some more&amp;hellip;&lt;/li>
&lt;/ul>
&lt;p>So much time is wasted, with very little progress made. Even worse, if this is at the end of the day and I have to leave it pending and come back to it the next day - or if I have to stash the changes and work on something else for a while then come back to it later, then the cycle begins all over again.&lt;/p></description></item><item><title>Adding anything to i3blocks</title><link>https://wangonya.com/blog/i3blocks/</link><pubDate>Wed, 14 Jun 2023 21:34:04 +0300</pubDate><guid>https://wangonya.com/blog/i3blocks/</guid><description>&lt;style>
 img {width: 60%}
&lt;/style>
&lt;p>This was initially a post about adding what&amp;rsquo;s playing on Spotify to &lt;a href="https://github.com/vivien/i3blocks">i3blocks&lt;/a>. I had just started using i3blocks then and thought it was pretty cool how easy it was to do.
I&amp;rsquo;ve since discovered the possibilities are endless. You can add pretty much anything that outputs text to the statusbar.&lt;/p>
&lt;p>Below are some examples of what&amp;rsquo;s possible.&lt;/p>
&lt;h2 id="showing-and-controlling-music">Showing and controlling music&lt;/h2>
&lt;p>I like seeing what&amp;rsquo;s playing without having to bring up the Spotify app every time. If I can also control playback without bringing up the app, even better.&lt;/p></description></item><item><title>mysql-dump specific tables</title><link>https://wangonya.com/blog/mysql-dump-specific-tables/</link><pubDate>Sat, 13 Aug 2022 15:19:50 +0300</pubDate><guid>https://wangonya.com/blog/mysql-dump-specific-tables/</guid><description>&lt;p>If you only need to dump one table:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">mysqldump -u username -ppassword db_name table_name &amp;gt; dump.sql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For multiple tables, separate the table names with a whitespace:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">mysqldump -u username -ppassword db_name table_name_1 table_name_2 &amp;gt; dump.sql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To only get tables with a certain prefix, e.g &lt;code>pref_&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">mysqldump db_name &lt;span class="k">$(&lt;/span>mysql -D db_name -Bse &lt;span class="s2">&amp;#34;show tables like &amp;#39;pref\_%&amp;#39;&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span> &amp;gt; dump.sql
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># flags: -B batch, -s silent mode, -e execute&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To only dump rows that meet a specific criteria:&lt;/p></description></item><item><title>Grokking algorithms notes</title><link>https://wangonya.com/blog/grokking-algorithms-notes/</link><pubDate>Sat, 21 May 2022 12:03:23 +0300</pubDate><guid>https://wangonya.com/blog/grokking-algorithms-notes/</guid><description>&lt;p>Book: &lt;a href="https://www.manning.com/books/grokking-algorithms">https://www.manning.com/books/grokking-algorithms&lt;/a>&lt;/p>
&lt;h2 id="the-feynman-algorithm">The Feynman algorithm&lt;/h2>
&lt;ol>
&lt;li>Write down the problem.&lt;/li>
&lt;li>Think real hard.&lt;/li>
&lt;li>Write down the solution.&lt;/li>
&lt;/ol>
&lt;h2 id="binary-search">Binary search&lt;/h2>
&lt;p>Use if the input is sorted.&lt;/p>
&lt;p>If the input consists of numbers, for example, half the numbers are eliminated in each step with binary search. When searching for a number between 1 and 100, a maximum of 7 steps are needed to get the result.&lt;/p>



&lt;div class="goat svg-container ">
 
 &lt;svg
 xmlns="http://www.w3.org/2000/svg"
 font-family="Menlo,Lucida Console,monospace"
 
 viewBox="0 0 336 25"
 >
 &lt;g transform='translate(8,16)'>
&lt;path d='M 32,0 L 40,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 80,0 L 88,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 128,0 L 136,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 176,0 L 184,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 216,0 L 224,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 256,0 L 264,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;path d='M 296,0 L 304,0' fill='none' stroke='currentColor'>&lt;/path>
&lt;polygon points='48.000000,0.000000 36.000000,-5.600000 36.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 40.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='96.000000,0.000000 84.000000,-5.600000 84.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 88.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='144.000000,0.000000 132.000000,-5.600000 132.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 136.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='192.000000,0.000000 180.000000,-5.600000 180.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 184.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='232.000000,0.000000 220.000000,-5.600000 220.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 224.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='272.000000,0.000000 260.000000,-5.600000 260.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 264.000000, 0.000000)'>&lt;/polygon>
&lt;polygon points='312.000000,0.000000 300.000000,-5.600000 300.000000,5.600000' fill='currentColor' transform='rotate(0.000000, 304.000000, 0.000000)'>&lt;/polygon>
&lt;text text-anchor='middle' x='0' y='4' fill='currentColor' style='font-size:1em'>1&lt;/text>
&lt;text text-anchor='middle' x='8' y='4' fill='currentColor' style='font-size:1em'>0&lt;/text>
&lt;text text-anchor='middle' x='16' y='4' fill='currentColor' style='font-size:1em'>0&lt;/text>
&lt;text text-anchor='middle' x='56' y='4' fill='currentColor' style='font-size:1em'>5&lt;/text>
&lt;text text-anchor='middle' x='64' y='4' fill='currentColor' style='font-size:1em'>0&lt;/text>
&lt;text text-anchor='middle' x='104' y='4' fill='currentColor' style='font-size:1em'>2&lt;/text>
&lt;text text-anchor='middle' x='112' y='4' fill='currentColor' style='font-size:1em'>5&lt;/text>
&lt;text text-anchor='middle' x='152' y='4' fill='currentColor' style='font-size:1em'>1&lt;/text>
&lt;text text-anchor='middle' x='160' y='4' fill='currentColor' style='font-size:1em'>3&lt;/text>
&lt;text text-anchor='middle' x='200' y='4' fill='currentColor' style='font-size:1em'>7&lt;/text>
&lt;text text-anchor='middle' x='240' y='4' fill='currentColor' style='font-size:1em'>4&lt;/text>
&lt;text text-anchor='middle' x='280' y='4' fill='currentColor' style='font-size:1em'>2&lt;/text>
&lt;text text-anchor='middle' x='320' y='4' fill='currentColor' style='font-size:1em'>1&lt;/text>
&lt;/g>

 &lt;/svg>
 
&lt;/div>
&lt;p>In general, for any list of &lt;em>n&lt;/em>, binary search will take log&lt;sub>2&lt;/sub>&lt;em>n&lt;/em> steps to run in the worst case.&lt;/p></description></item><item><title>Checking string contains substring</title><link>https://wangonya.com/blog/check-string-substring-go/</link><pubDate>Fri, 29 Apr 2022 11:02:01 +0300</pubDate><guid>https://wangonya.com/blog/check-string-substring-go/</guid><description>&lt;p>From &lt;a href="https://stackoverflow.com/a/61842548/9312256">this answer&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;regexp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;strings&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">const&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">str&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;something&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">substr&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;some&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 1. Contains&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">res&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">strings&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Contains&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">substr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">res&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 2. Index: check the index of the first instance of substr in str, or -1 if substr is not present&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">i&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">strings&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Index&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">substr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 3. Split by substr and check len of the slice, or length is 1 if substr is not present&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">ss&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">strings&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">substr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ss&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="c1">// 2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 4. Check number of non-overlapping instances of substr in str&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">c&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">strings&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Count&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">str&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">substr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 5. RegExp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">matched&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">_&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">regexp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">MatchString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">substr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">str&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">matched&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 6. Compiled RegExp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">re&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">regexp&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">MustCompile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">substr&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">res&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">re&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">MatchString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">str&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">res&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Option two easily solves &lt;a href="https://leetcode.com/problems/implement-strstr/">this
problem&lt;/a>.&lt;/p></description></item><item><title>Handling missing dict keys</title><link>https://wangonya.com/blog/handling-missing-dict-keys/</link><pubDate>Thu, 10 Feb 2022 06:10:15 +0300</pubDate><guid>https://wangonya.com/blog/handling-missing-dict-keys/</guid><description>&lt;p>Trying to access a non-existent key using this notation:
&lt;code>dict[key]&lt;/code> raises a &lt;code>KeyError&lt;/code>. An easy
workaround for this is to use &lt;code>get(key)&lt;/code> instead, which
returns &lt;code>None&lt;/code> if &lt;code>key&lt;/code> isn&amp;rsquo;t found, or
&lt;code>get(key, default)&lt;/code> which returns &lt;code>default&lt;/code> if
&lt;code>key&lt;/code> isn&amp;rsquo;t found.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; &lt;span class="nv">d&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d&lt;span class="o">[&lt;/span>&lt;span class="s2">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Traceback &lt;span class="o">(&lt;/span>most recent call last&lt;span class="o">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> File &lt;span class="s2">&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span>, line 1, in &amp;lt;module&amp;gt;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">KeyError: &lt;span class="s1">&amp;#39;x&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d.get&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;x&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d.get&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;x&amp;#34;&lt;/span>,&lt;span class="s2">&amp;#34;y&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1">&amp;#39;y&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But what if you want to not only return a default if the key is missing,
but also assign that default to the specified key in the dict? There are
a couple of ways to do that.&lt;/p></description></item><item><title>Kadane's algorithm</title><link>https://wangonya.com/blog/kadanes-algorithm/</link><pubDate>Thu, 02 Dec 2021 08:25:49 +0300</pubDate><guid>https://wangonya.com/blog/kadanes-algorithm/</guid><description>&lt;p>Possible use case: &lt;a href="https://en.wikipedia.org/wiki/Maximum_subarray_problem">Maximum subarray
problem&lt;/a>.&lt;/p>
&lt;h2 id="steps">Steps&lt;/h2>
&lt;ol>
&lt;li>Initialize two variables: &lt;code>max_sum = current_sum = 0&lt;/code>&lt;/li>
&lt;li>Loop through numbers in list
&lt;ul>
&lt;li>Set &lt;code>current_sum = max(0, current_sum + list[i])&lt;/code>&lt;/li>
&lt;li>Set &lt;code>max_sum = max(max_sum, current_sum)&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Return &lt;code>max_sum&lt;/code>&lt;/li>
&lt;/ol>
&lt;h2 id="caveats-">Caveats &lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>, &lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/h2>
&lt;ul>
&lt;li>Kadane&amp;rsquo;s Algorithm requires at least one positive number, so an
input of all negative numbers would be invalid.&lt;/li>
&lt;li>If the array contains all non-negative numbers, then the problem is
trivial; a maximum subarray is the entire array.&lt;/li>
&lt;li>If the array contains all non-positive numbers, then a solution is
any subarray of size 1 containing the maximal value of the array (or
the empty subarray (which has sum 0), if it is permitted).&lt;/li>
&lt;li>Several different sub-arrays may have the same maximum sum.&lt;/li>
&lt;/ul>
&lt;h3 id="solving-best-time-to-buy-and-sell-stock-with-kadanes-algorithm">Solving &lt;a href="https://leetcode.com/problems/best-time-to-buy-and-sell-stock/">Best Time to Buy and Sell Stock&lt;/a> with Kadane&amp;rsquo;s Algorithm&lt;/h3>
&lt;p>Slightly tweak the algorithm to track max profit and min price.&lt;/p></description></item><item><title>Running multiple programs in parallel from a bash script</title><link>https://wangonya.com/blog/running-bash-parallel/</link><pubDate>Mon, 22 Nov 2021 06:58:33 +0300</pubDate><guid>https://wangonya.com/blog/running-bash-parallel/</guid><description>&lt;p>This comes in handy when I want to, for example:&lt;/p>
&lt;ul>
&lt;li>run a MySQL proxy to Cloudql or similar, then&lt;/li>
&lt;li>run a project server (fastapi, django etc) that depends on the
database connection&lt;/li>
&lt;/ul>
&lt;p>From &lt;a href="https://stackoverflow.com/questions/3004811/how-do-you-run-multiple-programs-in-parallel-from-a-bash-script">this
answer&lt;/a>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">set&lt;/span> -m &lt;span class="c1"># enable job control&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">prog1 &lt;span class="p">&amp;amp;&lt;/span> prog2 &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">fg&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This will:&lt;/p>
&lt;ul>
&lt;li>Start prog1.&lt;/li>
&lt;li>Send it to background, but keep printing its output.&lt;/li>
&lt;li>Start prog2, and keep it in foreground, so you can close it with
ctrl-c.&lt;/li>
&lt;li>When you close prog2, you&amp;rsquo;ll return to prog1&amp;rsquo;s foreground, so you
can also close it with ctrl-c.&lt;/li>
&lt;/ul></description></item><item><title>Processing iterators in parallel</title><link>https://wangonya.com/blog/python-zip/</link><pubDate>Wed, 03 Nov 2021 06:13:46 +0300</pubDate><guid>https://wangonya.com/blog/python-zip/</guid><description>&lt;p>Use &lt;a href="https://docs.python.org/3/library/functions.html#zip">zip&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>&lt;code>zip(*iterables, strict=False)&lt;/code>&lt;/p>
&lt;p>Iterate over several iterables in parallel, producing tuples with an
item from each one.&lt;/p>&lt;/blockquote>
&lt;h2 id="examples">Examples&lt;/h2>
&lt;h3 id="without-zip">Without zip&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">countries&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;Kenya&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Tanzania&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Uganda&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">capitals&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;Nairobi&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Dodoma&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Kampala&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;=== using range ===&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">countries&lt;/span>&lt;span class="p">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">country&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">capital&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">countries&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">capitals&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Country: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">country&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, Capital: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">capital&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;=== using enumerate ===&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">country&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">enumerate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">countries&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">country&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">capital&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">countries&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">capitals&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Country: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">country&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, Capital: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">capital&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="o">===&lt;/span> using &lt;span class="nv">range&lt;/span> &lt;span class="o">===&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Kenya, Capital: Nairobi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Tanzania, Capital: Dodoma
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Uganda, Capital: &lt;span class="nv">Kampala&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">===&lt;/span> using &lt;span class="nv">enumerate&lt;/span> &lt;span class="o">===&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Kenya, Capital: Nairobi
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Tanzania, Capital: Dodoma
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Country: Uganda, Capital: Kampala
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="with-zip">With zip&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;=== using zip ===&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">country&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">capital&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">zip&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">countries&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">capitals&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Country: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">country&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">, Capital: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">capital&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output:&lt;/p></description></item><item><title>Getting the Python version at runtime</title><link>https://wangonya.com/blog/python-runtime-version/</link><pubDate>Sun, 24 Oct 2021 17:42:19 +0300</pubDate><guid>https://wangonya.com/blog/python-runtime-version/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">sys&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sys&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">version&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">3.9.7 &lt;span class="o">(&lt;/span>default, Aug &lt;span class="m">31&lt;/span> 2021, 13:28:12&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>GCC 11.1.0&lt;span class="o">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>You can use your database as a simple calculator</title><link>https://wangonya.com/blog/db-calc/</link><pubDate>Sat, 23 Oct 2021 17:49:32 +0300</pubDate><guid>https://wangonya.com/blog/db-calc/</guid><description>&lt;p>Saw this in the &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/entering-queries.html">MySQL
docs&lt;/a>.
I&amp;rsquo;m assuming this only works for relational databases.&lt;/p>
&lt;p>I don&amp;rsquo;t know if it&amp;rsquo;s very useful but definitely interesting.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="n">MariaDB&lt;/span>&lt;span class="p">[]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIN&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PI&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="c1">------------------+---------+
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIN&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PI&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="c1">------------------+---------+
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">70710678118655&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="c1">------------------+---------+
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">row&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">set&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">sec&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="cl">&lt;span class="n">postgres&lt;/span>&lt;span class="o">=#&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">SIN&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PI&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&lt;/span>&lt;span class="o">+&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">sin&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="k">column&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">--------------------+----------
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="mi">7071067811865475&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">|&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">25&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">row&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Setting up PostgreSQL on Arch Linux</title><link>https://wangonya.com/blog/postgresql-setup-arch/</link><pubDate>Fri, 15 Oct 2021 16:09:08 +0300</pubDate><guid>https://wangonya.com/blog/postgresql-setup-arch/</guid><description>&lt;p>&lt;a href="https://wiki.archlinux.org/title/PostgreSQL">Arch Linux PostgreSQL
docs&lt;/a>&lt;/p>
&lt;h2 id="install">Install&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ sudo pacman -S postgresql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="setup-the-data-directory">Setup the data directory&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ sudo -iu postgres
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>postgres&lt;span class="o">]&lt;/span>$ initdb -D /var/lib/postgres/data
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="start-postgresqlservice">Start postgresql.service&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ systemctl start postgresql.service
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ systemctl &lt;span class="nb">enable&lt;/span> postgresql.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="add-user">Add user&lt;/h2>
&lt;pre>&lt;code>[postgres]$ createuser --interactive
&lt;/code>&lt;/pre>
&lt;h2 id="create-db">Create db&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ createdb myDatabaseName
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Setting up MariaDB on Arch Linux</title><link>https://wangonya.com/blog/mariadb-setup-arch/</link><pubDate>Fri, 15 Oct 2021 15:56:36 +0300</pubDate><guid>https://wangonya.com/blog/mariadb-setup-arch/</guid><description>&lt;p>&lt;a href="https://wiki.archlinux.org/title/MariaDB">Arch Linux MariaDB docs&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>MariaDB is a reliable, high performance and full-featured database
server which aims to be an &amp;lsquo;always Free, backward compatible,
drop-in&amp;rsquo; replacement of MySQL. Since 2013 MariaDB is Arch Linux&amp;rsquo;s
default implementation of MySQL.&lt;/p>&lt;/blockquote>
&lt;h2 id="install">Install&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ sudo pacman -S mariadb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="setup-the-data-directory">Setup the data directory&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ sudo mariadb-install-db --user&lt;span class="o">=&lt;/span>mysql --basedir&lt;span class="o">=&lt;/span>/usr --datadir&lt;span class="o">=&lt;/span>/var/lib/mysql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="start-mariadbservice">Start mariadb.service&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ systemctl start mariadb.service
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ systemctl &lt;span class="nb">enable&lt;/span> mariadb.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="add-user">Add user&lt;/h2>
&lt;blockquote>
&lt;p>In the below example, the user monty with some_pass as password is
being created, then granted full permissions to the database mydb:&lt;/p></description></item><item><title>Getting the running Go version</title><link>https://wangonya.com/blog/go-version/</link><pubDate>Sat, 24 Jul 2021 05:02:01 +0300</pubDate><guid>https://wangonya.com/blog/go-version/</guid><description>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span> &lt;span class="nx">main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;log&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;runtime&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">log&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Printf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Running Go: %s&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">runtime&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Version&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Output: &lt;code>Running Go: go1.16.6&lt;/code>&lt;/p></description></item><item><title>Writing DRYer tests using pytest parametrize</title><link>https://wangonya.com/blog/pytest-parametrize/</link><pubDate>Thu, 08 Apr 2021 17:08:41 +0300</pubDate><guid>https://wangonya.com/blog/pytest-parametrize/</guid><description>&lt;p>Tests don&amp;rsquo;t always need to be DRY, which isn&amp;rsquo;t necessarily a bad
thing.&lt;/p>
&lt;p>&lt;a href="https://stackoverflow.com/a/129722/9312256">This&lt;/a> SO answer sums it up
nicely:&lt;/p>
&lt;blockquote>
&lt;p>Readability is more important for tests. If a test fails, you want the
problem to be obvious. The developer shouldn&amp;rsquo;t have to wade through a
lot of heavily factored test code to determine exactly what failed.
You don&amp;rsquo;t want your test code to become so complex that you need to
write unit-test-tests.&lt;/p></description></item><item><title>What happens when you run PSQL slash commands?</title><link>https://wangonya.com/blog/psql-commands/</link><pubDate>Thu, 10 Dec 2020 05:51:19 +0300</pubDate><guid>https://wangonya.com/blog/psql-commands/</guid><description>&lt;p>Running &lt;code>\?&lt;/code> within a psql database gives a whole list of
commands that come in handy when performing various kinds of tasks.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ psql
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">psql &lt;span class="o">(&lt;/span>13.0&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Type &lt;span class="s2">&amp;#34;help&amp;#34;&lt;/span> &lt;span class="k">for&lt;/span> help.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">wangonya&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="c1"># \?&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">General
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="se">\c&lt;/span>opyright show PostgreSQL usage and distribution terms
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="se">\c&lt;/span>rosstabview &lt;span class="o">[&lt;/span>COLUMNS&lt;span class="o">]&lt;/span> execute query and display results in crosstab
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="se">\e&lt;/span>rrverbose show most recent error message at maximum verbosity
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> .....
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>But what are the queries executed when these commands run?&lt;/p>
&lt;p>I was recently tasked to write a bash script that loops through every
schema on a database and does a &lt;code>pg_dump&lt;/code> on it for backup
then uploads the backups to an external server.&lt;/p></description></item><item><title>Working with celery signals</title><link>https://wangonya.com/blog/celery-signals/</link><pubDate>Tue, 03 Nov 2020 06:17:15 +0300</pubDate><guid>https://wangonya.com/blog/celery-signals/</guid><description>&lt;p>If you&amp;rsquo;re new to celery, &lt;a href="https://docs.celeryq.dev/en/stable/getting-started/first-steps-with-celery.html#first-steps">start
here&lt;/a>.&lt;/p>
&lt;p>Sometimes when using celery, you may want to get notified when a task
running in the background executes successfully or when it fails. You
may also want to run a function each time before the celery task runs or
after it completes. These and many others along the same line are all
situations where
&lt;a href="https://docs.celeryq.dev/en/stable/userguide/signals.html">signals&lt;/a>
would come in handy.&lt;/p>
&lt;p>I&amp;rsquo;ll create a simple file &lt;code>tasks.py&lt;/code> and set up celery to
demonstrate how to use celery signals.&lt;/p></description></item><item><title>Shallow &amp; deep copying in Python</title><link>https://wangonya.com/blog/shallow-deep-copy-python/</link><pubDate>Sun, 21 Jun 2020 12:36:17 +0300</pubDate><guid>https://wangonya.com/blog/shallow-deep-copy-python/</guid><description>&lt;p>What happens when a variable is assigned to another variable in python?
For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; &lt;span class="nv">x&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; &lt;span class="nv">y&lt;/span> &lt;span class="o">=&lt;/span> x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Both &lt;code>x&lt;/code> and &lt;code>y&lt;/code> will have the value
&lt;code>5&lt;/code>. But, when &lt;code>x&lt;/code> was assigned to &lt;code>y&lt;/code>,
&lt;code>y&lt;/code> was not created as a completely new/separate object.
Instead, an &lt;strong>alias&lt;/strong> for &lt;code>x&lt;/code> was created. That is,
&lt;code>y&lt;/code> points to the memory location of &lt;code>x&lt;/code>. It does
not have its own memory location - yet.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; id&lt;span class="o">(&lt;/span>x&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">140428600776960&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; id&lt;span class="o">(&lt;/span>y&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">140428600776960&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; x is y
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">True
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You may never have any problems with this when working with &lt;a href="https://stackoverflow.com/a/23715872">immutable
types&lt;/a> because the alias is broken
as soon as either of the two variables change.&lt;/p></description></item><item><title>Variables &amp; mutability in Rust</title><link>https://wangonya.com/blog/variables-mutability/</link><pubDate>Sun, 14 Jun 2020 22:33:13 +0300</pubDate><guid>https://wangonya.com/blog/variables-mutability/</guid><description>&lt;p>By default, variables are immutable in Rust. Coming from a Python
background, I have to keep in mind that this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">var&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;var = &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">var&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// var = 10
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">var&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">5&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// try and reassign var
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;var is now &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">var&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&amp;hellip; will not compile.&lt;/p>
&lt;p>The rust compiler gives a clear output of what went wrong:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">error&lt;span class="o">[&lt;/span>E0384&lt;span class="o">]&lt;/span>: cannot assign twice to immutable variable &lt;span class="sb">`&lt;/span>var&lt;span class="sb">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">2&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">let&lt;/span> &lt;span class="nv">var&lt;/span> &lt;span class="o">=&lt;/span> 10&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span> ---
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span> &lt;span class="p">|&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span> first assignment to &lt;span class="sb">`&lt;/span>var&lt;span class="sb">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span> help: make this binding mutable: &lt;span class="sb">`&lt;/span>mut var&lt;span class="sb">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">3&lt;/span> &lt;span class="p">|&lt;/span> println!&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;var = {}&amp;#34;&lt;/span>, var&lt;span class="o">)&lt;/span>&lt;span class="p">;&lt;/span> // &lt;span class="nv">var&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="m">4&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nv">var&lt;/span> &lt;span class="o">=&lt;/span> 5&lt;span class="p">;&lt;/span> // try and reassign var
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">|&lt;/span> ^^^^^^^ cannot assign twice to immutable variable
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once a value is assigned to &lt;code>var&lt;/code>, &lt;code>var&lt;/code> is bound
to that value until it goes out of scope.&lt;/p></description></item><item><title>When to use Python's enumerate() instead of range() in loops</title><link>https://wangonya.com/blog/python-enumerate/</link><pubDate>Sun, 26 Jan 2020 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/python-enumerate/</guid><description>&lt;p>The &lt;code>range()&lt;/code> function is often useful when iterating over a
set of integers:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">n&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>or a list of strings:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">fruit&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;apple&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mango&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;banana&amp;#34;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, say you want to iterate over the list of fruits and also show the
index of the current item in the list. Using &lt;code>range()&lt;/code>, this
might be done like this:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">fruits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;apple&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;mango&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;banana&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="nb">range&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fruits&lt;/span>&lt;span class="p">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fruit&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fruits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">fruit&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Output:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 0: apple&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1: mango&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2: banana&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It gets the job done, but not very pythonic. You have to get the length
of the list to keep track of the index, then index into the array to get
the current fruit - which makes the code more verbose and harder to
read.&lt;/p></description></item><item><title>difflib - finding close matches of strings from a list</title><link>https://wangonya.com/blog/difflib/</link><pubDate>Sun, 22 Sep 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/difflib/</guid><description>&lt;p>Say we have a list of strings: &lt;code>_list = [...,]&lt;/code> and user
input &lt;code>_input = '...'&lt;/code>, how do we find the items in
&lt;code>_list&lt;/code> that most closely resemble &lt;code>_input&lt;/code>?&lt;/p>
&lt;p>Python has a built-in package called &lt;code>difflib&lt;/code> with the
function &lt;code>get_close_matches()&lt;/code> that can help us.&lt;/p>
&lt;p>&lt;code>get_close_matches(word, possibilities, n, cutoff)&lt;/code> accepts
four parameters:&lt;/p>
&lt;ul>
&lt;li>&lt;code>word&lt;/code> - the word to find close matches for in our list&lt;/li>
&lt;li>&lt;code>possibilities&lt;/code> - the list in which to search for close
matches of &lt;code>word&lt;/code>&lt;/li>
&lt;li>&lt;code>n&lt;/code> (optional) - the maximum number of close matches to
return. Must be &lt;code>&amp;gt; 0&lt;/code>. Default is &lt;code>3&lt;/code>.&lt;/li>
&lt;li>&lt;code>cutoff&lt;/code> (optional) - a float in the range [0, 1] that
a &lt;code>possibility&lt;/code> must score in order to be considered
similar to &lt;code>word&lt;/code>. &lt;code>0&lt;/code> is very lenient,
&lt;code>1&lt;/code> is very strict. Default is &lt;code>0.6&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>An example from the docs:&lt;/p></description></item><item><title>HTML to JSX compiler</title><link>https://wangonya.com/blog/html-to-jsx-compiler/</link><pubDate>Mon, 09 Sep 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/html-to-jsx-compiler/</guid><description>&lt;p>I just came across &lt;a href="https://magic.reactjs.net/htmltojsx.htm">this&lt;/a>
online HTML to JSX Compiler. If you&amp;rsquo;re new (or not) to react and
you&amp;rsquo;re still having a little trouble with JSX, I think this tool is
great for learning.&lt;/p>
&lt;p>Just paste in your HTML in the HTML editor on the left, and it&amp;rsquo;ll be
converted into valid JSX on the right.&lt;/p></description></item><item><title>Python 'is' vs '=='</title><link>https://wangonya.com/blog/python-is-vs-/</link><pubDate>Fri, 06 Sep 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/python-is-vs-/</guid><description>&lt;p>A lot of times when I&amp;rsquo;m using &lt;code>if&lt;/code> in Python, I find myself
wondering whether to use &lt;code>is&lt;/code> or &lt;code>==&lt;/code> for the
check.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># do I do&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="ow">is&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># or&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>It can be a bit confusing if you&amp;rsquo;re new to Python, and it&amp;rsquo;s easy to
assume the two can be used interchangeably. So, what&amp;rsquo;s the difference?&lt;/p>
&lt;h2 id="is">&lt;code>is&lt;/code>&lt;/h2>
&lt;p>The &lt;code>is&lt;/code> operator checks if both elements point to the same
object. Let&amp;rsquo;s fire up a python console to help illustrate this:&lt;/p></description></item><item><title>Making your SMART goals smarter with stretch goals</title><link>https://wangonya.com/blog/stretch-smart-goals/</link><pubDate>Fri, 30 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/stretch-smart-goals/</guid><description>&lt;p>I&amp;rsquo;ve been reading the book &amp;quot;Smarter Faster Better&amp;quot; by Charles Duhigg
and in it, he gives a perspective on goal-setting that I found
interesting.&lt;/p>
&lt;p>You may already know about &lt;a href="https://www.mindtools.com/pages/article/smart-goals.htm">SMART
goals&lt;/a>, which
is an awesome format to set your goals in. It does have a subtle pitfall
though: cognitive closure.&lt;/p>
&lt;h3 id="cognitive-closure">Cognitive closure&lt;/h3>
&lt;blockquote>
&lt;p>Cognitive closure (psychology), the human desire to eliminate
ambiguity and arrive at definite conclusions (sometimes
irrationally) -
&lt;a href="https://en.wikipedia.org/wiki/Cognitive_closure">Wikipedia&lt;/a>&lt;/p>&lt;/blockquote>
&lt;p>You know that nice feeling of crossing things off your to-do list?
Closure. Which is great, for the most part. It only gets bad when we end
up expending more effort to get immediate results, when we are so
focused on small daily &amp;quot;wins&amp;quot; that we lose focus on the larger
picture.&lt;/p></description></item><item><title>Automatically counting and numbering HTML elements with CSS counters</title><link>https://wangonya.com/blog/css-counters/</link><pubDate>Sat, 24 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/css-counters/</guid><description>&lt;p>Say you had an unknown number of &lt;code>&amp;lt;div&amp;gt;&lt;/code> elements and (for
some reason) you wanted to count them and number each of them
automatically - how would you do it? If you&amp;rsquo;re like me, your first
thought would be to use some kind of Javascript to play around with the
DOM. What if I told you (insert Morpheus voice here) you can do it with
CSS?&lt;/p>
&lt;h2 id="how-to-use-css-counters">How to use CSS counters&lt;/h2>
&lt;p>Getting counters working requires three steps:&lt;/p></description></item><item><title>Publishing your Python packages on TestPyPi before publishing on PyPi</title><link>https://wangonya.com/blog/publishing-package-on-test-pypi/</link><pubDate>Fri, 23 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/publishing-package-on-test-pypi/</guid><description>&lt;p>If you&amp;rsquo;re just creating a package for learning purposes, there&amp;rsquo;s no
need (IMO) to pollute the official PyPi index with it. Also, you may
want to release a package to a select number of users for testing before
you actually release it officially. For these purposes, you&amp;rsquo;re better
off using &lt;a href="https://test.pypi.org/">TestPyPi&lt;/a>:&lt;/p>
&lt;blockquote>
&lt;p>a separate instance of the Python Package Index that allows you to try
distribution tools and processes without affecting the real index.&lt;/p></description></item><item><title>Testing Click applications with pytest</title><link>https://wangonya.com/blog/testing-click-with-pytest/</link><pubDate>Tue, 20 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/testing-click-with-pytest/</guid><description>&lt;p>It&amp;rsquo;s good practice to, as much as possible, write tests for your code.
If you&amp;rsquo;re working with Python, &lt;a href="https://pytest.org/en/latest/">pytest&lt;/a>
makes the process of writing and running tests much smoother. I wrote a
few posts some time back on getting started with testing with pytest, so
if you&amp;rsquo;re completely new to it, you might want to take a look at them:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://wangonya.com/blog/getting-started-with-pytest/">Getting started with
pytest&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://wangonya.com/blog/pytest-asserting-exceptions/">Asserting Exceptions with
Pytest&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://wangonya.com/blog/pytest-capture-print/">Capturing print statements while
debugging&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://wangonya.com/blog/pytest-skip/">Skipping tests&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>For testing CLI apps, Click provides a convenient module:
&lt;code>click.testing&lt;/code> which has some useful functions (notably
&lt;code>CliRunner()&lt;/code>) to help us invoke commands and check their
behavior.&lt;/p></description></item><item><title>Performing CRUD operations with a CLI app using Firebase</title><link>https://wangonya.com/blog/cli-crud-with-firebase/</link><pubDate>Thu, 15 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/cli-crud-with-firebase/</guid><description>&lt;p>For the next phase in this series, we&amp;rsquo;ll learn how to make a CLI app to
perform CRUD operations, i.e., Creating, Retrieving, Updating and
Deleting data. We&amp;rsquo;ll use Firebase to store our data.&lt;/p>
&lt;h3 id="what-well-create">What we&amp;rsquo;ll create&lt;/h3>
&lt;p>A &lt;code>contacts&lt;/code> app with the following functionality:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># add a new contact with name=Peter and mobile=01034512&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts add Peter --mobile &lt;span class="m">01034512&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Contact Peter added!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span> &lt;span class="s1">&amp;#39;mobile&amp;#39;&lt;/span>: &lt;span class="s1">&amp;#39;01034512&amp;#39;&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># view all contacts&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts list
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Here&lt;span class="err">&amp;#39;&lt;/span>s a list of all your contacts:
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span> ... &lt;span class="c1"># list of all contacts }&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># view single contact&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts view Peter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span> &lt;span class="s1">&amp;#39;mobile&amp;#39;&lt;/span>: &lt;span class="s1">&amp;#39;01034512&amp;#39;&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts view Meg
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">The contact you searched &lt;span class="k">for&lt;/span> doesn&lt;span class="err">&amp;#39;&lt;/span>t exist
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># update mobile number for Peter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts update Peter --mobile &lt;span class="m">00000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Contact updated!
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">{&lt;/span> &lt;span class="s1">&amp;#39;mobile&amp;#39;&lt;/span>: &lt;span class="s1">&amp;#39;00000&amp;#39;&lt;/span> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># delete the contact Peter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ contacts delete Peter
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Contact deleted!
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This post is a bit long. If you just want to take a look at the code or
see how the app works, check out &lt;a href="https://github.com/wangonya/contacts-cli">the
repo&lt;/a>.&lt;/p></description></item><item><title>Prompting users for input</title><link>https://wangonya.com/blog/prompting-users-for-input/</link><pubDate>Sat, 10 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/prompting-users-for-input/</guid><description>&lt;p>Getting user input is an important part of any kind of application.
Since we&amp;rsquo;ve already learned about
&lt;a href="https://wangonya.com/blog/click-commands-options/">options&lt;/a>, adding a
user prompt to our hello world app should be a breeze. All we need to do
is add &lt;code>prompt=True&lt;/code> to the option decorator, so that it
prompts the user for input if no option is passed in.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># helloworld.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">click&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.command&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.option&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;-c&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;--case&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Choice&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;upper&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;lower&amp;#39;&lt;/span>&lt;span class="p">]),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;person&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;you&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">case&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">person&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello World! Also, hey &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> ☺️&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">person&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="k">case&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;upper&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="k">case&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;lower&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Save and run the app:&lt;/p></description></item><item><title>Adding arguments to CLI commands</title><link>https://wangonya.com/blog/click-commands-arguments/</link><pubDate>Fri, 09 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/click-commands-arguments/</guid><description>&lt;p>Arguments work very similarly to
&lt;a href="https://wangonya.com/blog/click-commands-options/">options&lt;/a>. If you&amp;rsquo;re
familiar with functional programming, then you&amp;rsquo;re familiar with
arguments. The concept is the same in Click.&lt;/p>
&lt;p>Let&amp;rsquo;s edit our code a bit to see how we can integrate arguments.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># helloworld.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">click&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.command&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.option&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;-c&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;--case&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Choice&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s1">&amp;#39;upper&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;lower&amp;#39;&lt;/span>&lt;span class="p">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@click.argument&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;person&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">default&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;you&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">case&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">person&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Hello World! Also, hey &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2"> ☺️&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">person&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="k">case&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;upper&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upper&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">elif&lt;/span> &lt;span class="k">case&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s1">&amp;#39;lower&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lower&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">click&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">echo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">response&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Just like with commands and options, Click provides a decorator to add
arguments.&lt;/p></description></item><item><title>Adding options to CLI commands</title><link>https://wangonya.com/blog/click-commands-options/</link><pubDate>Wed, 07 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/click-commands-options/</guid><description>&lt;p>In the previous post, we used &lt;code>setuptools&lt;/code> to package our app
and enable us to run it using a single executable command
&lt;code>hello&lt;/code>. In this post, we look at how to make CLI apps more
functional and interactive using options.&lt;/p>
&lt;h2 id="options">Options&lt;/h2>
&lt;p>Options are used to alter the default behavior of commands. This is
often accomplished by passing in parameters in the form of
&lt;code>--option&lt;/code> or &lt;code>-o&lt;/code> for short.&lt;/p>
&lt;p>Let&amp;rsquo;s assume that instead of just printing out &amp;quot;Hello World!&amp;quot;, we
wanted to have the option of printing it in all lowercase characters or
all uppercase characters. We can add this functionality by adding an
&lt;code>option()&lt;/code> decorator.&lt;/p></description></item><item><title>Using setuptools to package your Python app</title><link>https://wangonya.com/blog/using-setuptools/</link><pubDate>Mon, 05 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/using-setuptools/</guid><description>&lt;p>In our previous post, we made a Hello World! app to get us started with
Click. You might have noticed though that we needed to do
&lt;code>python hello-world.py&lt;/code> to run it. Since we&amp;rsquo;re building CLI
apps, that&amp;rsquo;s just not cool and it&amp;rsquo;s not how CLI apps work anyway. We
need to be able to run a single command, something like:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&lt;span class="o">(&lt;/span>venv&lt;span class="o">)&lt;/span> $ hello
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Hello World!
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s where &lt;a href="https://setuptools.readthedocs.io/en/latest/">setuptools&lt;/a>
comes in. Setuptools helps us bundle our script so we can install it and
run it like an app (&lt;code>$ hello&lt;/code>), instead of like a script
(&lt;code>$ python hello-world.py&lt;/code>).&lt;/p></description></item><item><title>Setting up your Python environment for Click</title><link>https://wangonya.com/blog/setting-up-python-click/</link><pubDate>Fri, 02 Aug 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/setting-up-python-click/</guid><description>&lt;p>In this post, we&amp;rsquo;ll cover the very basics of working with Python and
Click to create a CLI app. We&amp;rsquo;ll install Python 3, set up our
development environment, install Click, and create a
&lt;code>hello-world&lt;/code> app.&lt;/p>
&lt;h3 id="python-3x">Python 3.x&lt;/h3>
&lt;p>Getting started with Python is easy. Most *nix systems come with Python
pre-installed. We&amp;rsquo;ll be using Python 3. To check which version of
Python you have, open up your terminal and run &lt;code>python -V&lt;/code>.
You should get an output similar to this:&lt;/p></description></item><item><title>Fibonacci sequence with Python recursion and memoization</title><link>https://wangonya.com/blog/python-fibonacci-recursion-memoization/</link><pubDate>Sun, 16 Jun 2019 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/python-fibonacci-recursion-memoization/</guid><description>&lt;p>The Fibonacci sequence is a sequence of numbers such that any number,
except for the first and second, is the sum of the previous two.&lt;/p>
&lt;p>For example:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-example" data-lang="example">[0, 1, 1, 2, 3, 5, 8, 13, 21...]
&lt;/code>&lt;/pre>&lt;p>We can represent this in the formula:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-example" data-lang="example">fib(n) = fib(n-1)+fib(n-2)
&lt;/code>&lt;/pre>&lt;p>With this formula, we can write a simple &lt;a href="http://pages.cs.wisc.edu/~calvin/cs110/RECURSION.html">recursive
function&lt;/a> to
solve for &lt;code>fib(n)&lt;/code>.&lt;/p>
&lt;p>&lt;strong>Note: Only use this to test for small numbers, preferably n &amp;lt; 10.
I&amp;rsquo;ll explain later&lt;/strong>&lt;/p></description></item><item><title>Creating a simple ToDo API with Django</title><link>https://wangonya.com/blog/django-todo-api/</link><pubDate>Mon, 01 Apr 2019 07:57:54 +0300</pubDate><guid>https://wangonya.com/blog/django-todo-api/</guid><description>&lt;p>In this tutorial, we&amp;rsquo;ll create a simple todo api with Python 3 and
Django 2.&lt;/p>
&lt;h2 id="installing-the-requirements">Installing the requirements&lt;/h2>
&lt;p>Create a virtual environment and install Django.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ virtualenv venv &lt;span class="c1"># creates a virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ &lt;span class="nb">source&lt;/span> venv/bin/activate &lt;span class="c1"># activates the virtual environment&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">(&lt;/span>venv&lt;span class="o">)&lt;/span>$ pip install Django
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s all we&amp;rsquo;ll need for now.&lt;/p>
&lt;h2 id="creating-the-project">Creating the project&lt;/h2>
&lt;p>Use the Django &lt;code>startproject&lt;/code> command to create the project
we&amp;rsquo;ll be working on.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">$ django-admin startproject todoapi
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This creates a &lt;code>todoapi&lt;/code> directory with generated files to
start us off. The directory should look something like this:&lt;/p></description></item><item><title>Staying alert without caffeine</title><link>https://wangonya.com/blog/alert/</link><pubDate>Sun, 17 Mar 2019 18:02:01 +0300</pubDate><guid>https://wangonya.com/blog/alert/</guid><description>&lt;p>After my first post on &amp;quot;&lt;a href="https://wangonya.com/blog/health-dev/">Caring for your Health as a
Developer&lt;/a>&amp;quot;, I decided to do a
bit of research on caffeine, specifically in coffee. I did learn quite a
bit but what I found most interesting was that after oil, &lt;a href="https://capital.com/top-5-most-traded-commodities-in-the-world">coffee is the
2nd most traded commodity in the
world&lt;/a>
🤯. People are really drinking a lot of coffee (2.25 billion cups of
coffee on a daily basis). But while many may love and enjoy the
momentary energy boost provided by caffeinated drinks, is it really the
best way to go in the long term?&lt;/p></description></item><item><title>Caring for your health as a developer</title><link>https://wangonya.com/blog/health-dev/</link><pubDate>Thu, 14 Mar 2019 19:54:39 +0300</pubDate><guid>https://wangonya.com/blog/health-dev/</guid><description>&lt;blockquote>
&lt;p>&amp;quot;When health is absent, wisdom cannot reveal itself, art cannot
manifest, strength cannot fight, wealth becomes useless, and
intelligence cannot be applied.&amp;quot; ― Herophilus&lt;/p>&lt;/blockquote>
&lt;p>Let&amp;rsquo;s face it. As developers, it&amp;rsquo;s easy to let things get a bit out of
hand when it comes to health. Many times we find ourselves in front of screens for
hours on end. We sleep really late (or not at all) sometimes. Unless
you&amp;rsquo;re disciplined enough to follow a schedule, you might find yourself
not having time to eat proper meals so snacking becomes a habit. All
these are usually sacrifices made to fix some bug or find the most
efficient solution to some problem. Usually, our health suffers as a
result. While this might seem to work out just fine for the moment, we
don&amp;rsquo;t look at the bigger picture - how it will affect us in the future.&lt;/p></description></item><item><title>Lexical variable scoping with Javascript</title><link>https://wangonya.com/blog/lexical-scoping/</link><pubDate>Fri, 08 Mar 2019 12:52:10 +0300</pubDate><guid>https://wangonya.com/blog/lexical-scoping/</guid><description>&lt;p>Lexical scoping means that the scope of a variable is determined by where it is defined in the source code — specifically, by the block or function it is written inside. In Javascript, code blocks are created using curly braces ({}). For
example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span> &lt;span class="nx">someFunction&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// some code here
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">function&lt;/span> &lt;span class="nx">anotherFunction&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// some more code here
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>someFunction&lt;/code> and &lt;code>anotherFunction&lt;/code> are two
different code blocks. These two different code blocks could also be
considered as two different scopes. What that means is that the
variables declared in &lt;code>someFunction&lt;/code> only affect that block
of code, and those declared in &lt;code>anotherFunction&lt;/code> only affect
that block of code. They are &lt;em>&amp;quot;scoped&amp;quot;&lt;/em> in that sense.&lt;/p></description></item><item><title>Javascript arithmetic cheat sheet</title><link>https://wangonya.com/blog/js-math/</link><pubDate>Tue, 05 Mar 2019 05:25:12 +0300</pubDate><guid>https://wangonya.com/blog/js-math/</guid><description>&lt;p>Given that one of the main reasons computers were invented was to solve
mathematical problems quickly, it is no wonder that all the modern
programming languages are so rich in arithmetic-oriented methods. The
earliest computers were basically just calculators. (&lt;em>Yes, I&amp;rsquo;m looking
at you &lt;a href="https://en.wikipedia.org/wiki/Abacus">Abacus&lt;/a>&lt;/em>). If you dabble
in Javascript (and a little math every now and then), you might find
this useful. The very obvious operations like simple addition (+) and
subtraction (-) have been omitted. So have more advanced operations.&lt;/p></description></item><item><title>Difference between a Python module and a package</title><link>https://wangonya.com/blog/python-module-package/</link><pubDate>Wed, 20 Feb 2019 18:35:12 +0300</pubDate><guid>https://wangonya.com/blog/python-module-package/</guid><description>&lt;h3 id="modules">Modules&lt;/h3>
&lt;p>Modules are single Python files that can be imported. Any python file
can be a module. For example, if I have two Python files:
&lt;code>module.py&lt;/code> and &lt;code>hello.py&lt;/code> in the same directory:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># module.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">hello&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Hello &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">format&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>I can &lt;code>import&lt;/code> that module in my &lt;code>hello.py&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">#hello.py&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">module&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">module&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">hello&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;World!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Hello World!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The same can be done in the interpreter:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; from module import hello
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;gt;&amp;gt;&amp;gt; hello&lt;span class="o">(&lt;/span>&lt;span class="s2">&amp;#34;World!&amp;#34;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="c1"># Hello World!&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="packages">Packages&lt;/h3>
&lt;p>Packages are made up of multiple Python files (or modules), and can even
include libraries written in different languages like C or C++. Seeing
an &lt;code>__init__.py&lt;/code> file in a folder typically tells you that
that folder is a Python package. The &lt;code>__init__.py&lt;/code> doesn&amp;rsquo;t
have to contain any code &amp;ndash; sometimes it does &amp;ndash; it just has to be there
for Python take that particular folder as a package.&lt;/p></description></item><item><title>Displaying a css spinner on ajax calls with fetch api</title><link>https://wangonya.com/blog/css-fetch-spinner/</link><pubDate>Fri, 01 Feb 2019 08:18:26 +0300</pubDate><guid>https://wangonya.com/blog/css-fetch-spinner/</guid><description>&lt;p>I always have to search for how to do this or refer back to my previous
code whenever I work with &lt;code>fetch&lt;/code>. For a while, I&amp;rsquo;ve used
the solution to
&lt;a href="https://stackoverflow.com/questions/43792026/display-spinner-during-ajax-call-when-using-fetch-api">this&lt;/a>
SO question. It&amp;rsquo;s a correct solution and it works great but to be
honest, I couldn&amp;rsquo;t clearly explain that piece of code if asked. So I thought of a
simple way to do it. Here&amp;rsquo;s how:&lt;/p>
&lt;h2 id="setting-up-the-html">Setting up the HTML&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-html" data-lang="html">&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- this will fetch the data --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">button&lt;/span> &lt;span class="na">onclick&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;loadData()&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>Load data&lt;span class="p">&amp;lt;/&lt;/span>&lt;span class="nt">button&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&amp;lt;!-- this will show our spinner --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="nt">div&lt;/span> &lt;span class="na">hidden&lt;/span> &lt;span class="na">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;spinner&amp;#34;&lt;/span>&lt;span class="p">&amp;gt;&amp;lt;/&lt;/span>&lt;span class="nt">div&lt;/span>&lt;span class="p">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The spinner visibility is hidden by default using the built-in
&lt;code>hidden&lt;/code> attribute. This is the element we&amp;rsquo;ll manipulate in
order to show and hide it as desired.&lt;/p></description></item><item><title>Skipping tests</title><link>https://wangonya.com/blog/pytest-skip/</link><pubDate>Thu, 31 Jan 2019 08:16:36 +0300</pubDate><guid>https://wangonya.com/blog/pytest-skip/</guid><description>&lt;p>Sometimes you might want to skip a particular test while executing
others for some reason. Maybe the database guy isn&amp;rsquo;t done setting up and that particular test requires a database connection. Instead of having to wait, you can just write the test and instruct pytest to skip it. Give the appropriate reason so it doesn&amp;rsquo;t look like you just skipped a failing test to keep your test suite green.&lt;/p>
&lt;p>There are a couple of ways to do this.&lt;/p></description></item><item><title>Capturing print statements while debugging</title><link>https://wangonya.com/blog/pytest-capture-print/</link><pubDate>Wed, 30 Jan 2019 08:06:29 +0300</pubDate><guid>https://wangonya.com/blog/pytest-capture-print/</guid><description>&lt;p>You might need to capture print statements in your tests while
debugging. This might be just to help you debug, or for some other
reason. I mostly do this kind of thing when testing for database
connections where, in addition to other tests, I want to make sure I see
that &amp;quot;Database connection successful&amp;quot; message.&lt;/p>
&lt;p>Let&amp;rsquo;s demonstrate with a simple example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">add_numbers&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">num1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">num2&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Add function started...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">num1&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">num2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Numbers added. Returning result...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">test_add_numbers&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">assert&lt;/span> &lt;span class="n">add_numbers&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">3&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Running the test above fails with the given traceback:&lt;/p></description></item><item><title>Asserting exceptions with pytest</title><link>https://wangonya.com/blog/pytest-asserting-exceptions/</link><pubDate>Tue, 29 Jan 2019 05:15:40 +0300</pubDate><guid>https://wangonya.com/blog/pytest-asserting-exceptions/</guid><description>&lt;p>The first time I had someone review my pull requests, she was pretty strict
on tests. I couldn&amp;rsquo;t merge if the tests were failing, of course. But I
also couldn&amp;rsquo;t merge if coverage had decreased. TDD was still new to me
so maintaining coverage was a challenge since I was only testing the
bare minimum I could. I had to find out how to make my tests more robust
and ensure as much of my code was tested as possible. One area that I
wasn&amp;rsquo;t really sure how to test was the custom exceptions I had written.&lt;/p></description></item><item><title>Getting started with pytest</title><link>https://wangonya.com/blog/getting-started-with-pytest/</link><pubDate>Mon, 28 Jan 2019 08:15:40 +0300</pubDate><guid>https://wangonya.com/blog/getting-started-with-pytest/</guid><description>&lt;p>Test-Driven Development is great. If you&amp;rsquo;re a Pythonista, it gets even
better with pytest - a framework that makes building simple and scalable
tests easy.&lt;/p>
&lt;p>In this series, I&amp;rsquo;ll be exploring the cool features that pytest offers
to help make testing Python code a breeze.&lt;/p>
&lt;h2 id="preparing-your-python-environment">Preparing your python environment&lt;/h2>
&lt;p>Let&amp;rsquo;s set up our testing environment with &lt;code>virtualenv&lt;/code>.
We&amp;rsquo;ll be working with Python 3. &lt;code>cd&lt;/code> into your working
directory and create a new virtual environment:&lt;/p></description></item><item><title>Python's heapq module</title><link>https://wangonya.com/blog/heapq/</link><pubDate>Fri, 21 Dec 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/heapq/</guid><description>&lt;p>Often when working with collections of data, you may want to find the
smallest or largest item. It&amp;rsquo;s easy enough to write a function that
iterates through the items and returns the smallest or largest one, or
use the builtin &lt;code>min()&lt;/code>, &lt;code>max()&lt;/code>, or
&lt;code>sorted()&lt;/code> functions. Another interesting way may be
implementing a heap (priority) queue.&lt;/p>
&lt;p>Python provides a pretty convenient module called &lt;code>heapq&lt;/code>
that does that for you. &lt;code>heapq&lt;/code> comes with a cool set of
inbuilt functions that you can read more about in the
&lt;a href="https://docs.python.org/3.0/library/heapq.html">docs&lt;/a>.&lt;/p></description></item><item><title>Sorting algorithms with Javascript (Part 2)</title><link>https://wangonya.com/blog/js-sort-2/</link><pubDate>Sun, 04 Nov 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/js-sort-2/</guid><description>&lt;p>I&amp;rsquo;m going to show Javascript implementations of three more sorting
algorithms:&lt;/p>
&lt;ul>
&lt;li>Quick sort&lt;/li>
&lt;li>Heap sort&lt;/li>
&lt;li>Counting sort&lt;/li>
&lt;/ul>
&lt;p>Again, this is not intended to be an in-depth explanation on the ins and
outs of how the algorithms work and their performance. If you&amp;rsquo;d rather
read about that, here&amp;rsquo;s a nice resource I found: &lt;a href="https://brilliant.org/wiki/sorting-algorithms/">Sorting
Algorithms&lt;/a>&lt;/p>
&lt;p>To keep things simple, I&amp;rsquo;ll be sorting a simple list &lt;code>list&lt;/code>
having only 5 elements &lt;code>[4, 2, 3, 1, 5]&lt;/code>.&lt;/p></description></item><item><title>Sorting algorithms with Javascript (Part 1)</title><link>https://wangonya.com/blog/js-sort-1/</link><pubDate>Thu, 18 Oct 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/js-sort-1/</guid><description>&lt;p>I&amp;rsquo;ve been learning a lot about data structures and algorithms lately
and I&amp;rsquo;ve noticed in my reading that there aren&amp;rsquo;t a lot of examples
showing implementations of algorithms in Javascript. You&amp;rsquo;ll mostly find
examples in Java, Python, C, C++ etc. Maybe there&amp;rsquo;s a reason for
preferring these languages over Javascript? I&amp;rsquo;m not sure.&lt;/p>
&lt;p>In this first part, I&amp;rsquo;m going to show Javascript implementations of
three sorting algorithms:&lt;/p>
&lt;ul>
&lt;li>Merge sort&lt;/li>
&lt;li>Insertion sort&lt;/li>
&lt;li>Bubble sort&lt;/li>
&lt;/ul>
&lt;p>This is not intended to be an in-depth explanation on the ins and outs
of how the algorithms work and their performance. If you&amp;rsquo;d rather read
about that, here&amp;rsquo;s a nice resource I found: &lt;a href="https://brilliant.org/wiki/sorting-algorithms/">Sorting
Algorithms&lt;/a>&lt;/p></description></item><item><title>Javascript lookaheads and lookbehinds</title><link>https://wangonya.com/blog/lookaheads-lookbehinds/</link><pubDate>Wed, 29 Aug 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/lookaheads-lookbehinds/</guid><description>&lt;p>Regular expressions are patterns used to match character combinations in
strings. They help us work with strings in a very performant way.&lt;/p>
&lt;p>By formulating regex with a special syntax, you can:&lt;/p>
&lt;ul>
&lt;li>search text in a string&lt;/li>
&lt;li>replace substrings in a string&lt;/li>
&lt;li>extract information from a string&lt;/li>
&lt;/ul>
&lt;p>If all this is completely new to you, take a look at the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">mdn web
docs&lt;/a>
for more info.&lt;/p>
&lt;p>For this post, I&amp;rsquo;ll focus on one of the easier (and very useful) ways
you can use regex.&lt;/p></description></item><item><title>Javascript array iteration with some() and every()</title><link>https://wangonya.com/blog/array-iteration/</link><pubDate>Tue, 28 Aug 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/array-iteration/</guid><description>&lt;p>If you&amp;rsquo;re using an array in your code, chances are, you&amp;rsquo;ll need to
iterate over the values in the array. There&amp;rsquo;s a couple of ways you can
do that, some better and more efficient than others depending on what
you want to accomplish.&lt;/p>
&lt;p>For this post, I&amp;rsquo;ll focus on two ways: &lt;code>some()&lt;/code> and
&lt;code>every()&lt;/code>.&lt;/p>
&lt;h2 id="some">&lt;code>some()&lt;/code>&lt;/h2>
&lt;p>The &lt;code>some()&lt;/code> method tests whether &lt;strong>at least one&lt;/strong> element in
the array passes the test implemented by the provided function. It
checks the elements one by one, and if it finds an array element where
the function returns a truthy value, &lt;code>some()&lt;/code> returns
&lt;code>true&lt;/code> and does not check the remaining values. Otherwise, it
returns &lt;code>false&lt;/code>.&lt;/p></description></item><item><title>'this' and arrow functions</title><link>https://wangonya.com/blog/arrow-this/</link><pubDate>Mon, 27 Aug 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/arrow-this/</guid><description>&lt;p>Arrow functions were introduced in ES6 as a new syntax for writing
Javascript functions. Thanks to their short syntax, they encourage the
use of small functions, which make code look cleaner (and
&lt;code>() =&amp;gt;&lt;/code> just looks cooler 😄).&lt;/p>
&lt;p>As a beginner just getting to wrap my head around ES6 syntax, I began
using arrow functions &lt;strong>everywhere&lt;/strong> without really understanding how
they worked. As you might expect, I ended up running into some problems,
especially with the &lt;code>this&lt;/code> keyword.&lt;/p></description></item><item><title>Finding an element in the array (the ES5, ES6 and ES7 way)</title><link>https://wangonya.com/blog/finding-array/</link><pubDate>Sun, 26 Aug 2018 00:00:00 +0000</pubDate><guid>https://wangonya.com/blog/finding-array/</guid><description>&lt;p>This&amp;rsquo;ll be a quick one.&lt;/p>
&lt;p>Say you want to check if a specific element exists in an array. There&amp;rsquo;s
a couple of ways to do that:&lt;/p>
&lt;h2 id="es5">ES5&lt;/h2>
&lt;h3 id="indexof">&lt;code>indexOf()&lt;/code>&lt;/h3>
&lt;p>&lt;code>indexOf&lt;/code> returns the index of the first matching item found,
or &lt;code>-1&lt;/code> if not found.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// check if a Fortnite ninja exists in the array
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kr">const&lt;/span> &lt;span class="nx">ninjas&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;Alchemist&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Brawler&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Skirmisher&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Harvester&amp;#34;&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ninjas&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">indexOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Brawler&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// 1
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ninjas&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">indexOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Harvester&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// 3
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ninjas&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">indexOf&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Assassin&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// -1 (doesn&amp;#39;t exist)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="lastindexof">&lt;code>lastIndexOf()&lt;/code>&lt;/h3>
&lt;p>&lt;code>lastIndexOf()&lt;/code> returns the index of the last matching item
found, or &lt;code>-1&lt;/code> if not found.&lt;/p></description></item></channel></rss>