<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Python on Noetic Nought</title>
    <link>https://punchagan.muse-amuse.in/tags/python/</link>
    <description>Recent content in Python on Noetic Nought</description>
    <generator>Hugo</generator>
    <language>en-US</language>
    <copyright>© 2006-2026 CC-BY-SA-4.0</copyright>
    <lastBuildDate>Sun, 06 Nov 2022 12:19:00 +0530</lastBuildDate>
    <atom:link href="https://punchagan.muse-amuse.in/tags/python/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Moving from Heroku to Fly.io</title>
      <link>https://punchagan.muse-amuse.in/blog/moving-from-heroku-to-fly-dot-io/</link>
      <pubDate>Sun, 06 Nov 2022 12:19:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/moving-from-heroku-to-fly-dot-io/</guid>
      <description>&lt;p&gt;A couple of months ago Heroku &lt;a href=&#34;https://blog.heroku.com/next-chapter&#34;&gt;announced&lt;/a&gt; their plan to &amp;ldquo;Focus on Mission&#xA;Critical&amp;rdquo; and shut down the free product plan. The ideas is to free up their&#xA;developer time to focus on the important stuff instead of fighting abuse of the&#xA;free plans. I&amp;rsquo;m surprised they invested in the free plans for so many years!&lt;/p&gt;&#xA;&lt;h2 id=&#34;my-heroku-apps&#34;&gt;My Heroku Apps&lt;/h2&gt;&#xA;&lt;p&gt;I have a bunch of apps on the free (Hobby dev) plan, and only app on the Hobby&#xA;Basic plan because it needed a bigger DB. All of these apps are small enough&#xA;that I could easily host all of them on my shared &lt;a href=&#34;https://www.hetzner.com/&#34;&gt;Hetzner server&lt;/a&gt;, where this&#xA;blog is hosted. But, I like using Heroku for services that I run for other&#xA;people. It makes access control and deployment much easier, and lets me invite&#xA;other people to help maintain apps easily, despite constraints like &lt;a href=&#34;https://devcenter.heroku.com/articles/heroku-postgres-plans#hobby-tier&#34;&gt;10k rows&lt;/a&gt; in&#xA;the Postgres DB and &lt;a href=&#34;https://devcenter.heroku.com/articles/free-dyno-hours&#34;&gt;Dyno sleeping&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Over the years of using Heroku, I ended up accumulating a bunch of small apps&#xA;on the service. Most of these apps aren&amp;rsquo;t actively being used any more and&#xA;didn&amp;rsquo;t feel worth the effort of moving.&lt;/p&gt;&#xA;&lt;p&gt;I decided to let most of the apps die, since they aren&amp;rsquo;t actively being&#xA;used. Only a couple of apps are used regularly enough to be worth keeping alive&#xA;&amp;ndash; &lt;a href=&#34;https://sotg.indiaultimate.org/&#34;&gt;SOTG Calculator&lt;/a&gt; and &lt;a href=&#34;https://rsvp.tiks-ultimate.in/features&#34;&gt;RSVP app&lt;/a&gt;. I turned on &lt;a href=&#34;https://devcenter.heroku.com/articles/maintenance-mode&#34;&gt;maintenance mode&lt;/a&gt; on the RSVP app&#xA;for a couple of days, as an experiment, and I had to bring back the services&#xA;due to &amp;ldquo;popular&amp;rdquo; demand.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-not-pay-heroku&#34;&gt;Why not pay Heroku?&lt;/h2&gt;&#xA;&lt;p&gt;I did consider just moving up to the Hobby basic plan and paying for running&#xA;the app. I wasn&amp;rsquo;t keen on investing numerous hours to get these apps to run&#xA;again. &lt;a href=&#34;https://instagram.com/akilesh.m&#34;&gt;Akilesh&lt;/a&gt; convinced me that the amount to pay Heroku could be collected&#xA;from the team and wouldn&amp;rsquo;t amount to much per person. I almost took this route.&lt;/p&gt;&#xA;&lt;p&gt;But, it bugged me that the amount we&amp;rsquo;d be paying Heroku could fund a couple of&#xA;turf practice sessions for the team. I could host the apps on my Hetzner server&#xA;&amp;ndash; we already pay enough for it. But, giving other people maintainer access to&#xA;apps is important and this was not straightforward with Hetzner.&lt;/p&gt;&#xA;&lt;p&gt;Also, the SOTG app couldn&amp;rsquo;t be funded this way.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-fly-dot-io&#34;&gt;Why Fly.io?&lt;/h2&gt;&#xA;&lt;p&gt;I ranted about this to my friends on Zulip and &lt;a href=&#34;https://github.com/rajaboja/&#34;&gt;Rajesh&lt;/a&gt; offered to help me as a&#xA;way to learn some devops stuff. I was more than happy to have someone to&#xA;discuss this stuff with and get some help.&lt;/p&gt;&#xA;&lt;p&gt;We decided to give &lt;a href=&#34;https://fly.io/&#34;&gt;Fly.io&lt;/a&gt; a try despite being skeptical about using yet another&#xA;free service. Their free Hobby plan includes 3GB of persistent storage space&#xA;(which neither of the apps currently use, but potentially could). They also&#xA;built &lt;a href=&#34;https://fly.io/blog/new-turboku/&#34;&gt;Turboku&lt;/a&gt; &amp;ndash; a tool to move apps from Heroku. It seemed worth giving a try,&#xA;and we could always fall back on Hetzner if it didn&amp;rsquo;t work out.&lt;/p&gt;&#xA;&lt;p&gt;We had a couple of months before the Heroku shutdown date, when I ranted about&#xA;this. Rajesh and I exchanged a few links and messages on how to potentially go&#xA;about doing this, when we got down to it. But, he got busy with other things&#xA;and now the deadline was only a month away. I decided to use the notes and do&#xA;the migration myself. I was glad I had the notes to refer to. The initial&#xA;&amp;ldquo;research&amp;rdquo; made the task seem less daunting.&lt;/p&gt;&#xA;&lt;h2 id=&#34;migrating-a-simple-app&#34;&gt;Migrating a simple app&lt;/h2&gt;&#xA;&lt;p&gt;I started with the simpler app first &amp;ndash; the &lt;a href=&#34;https://sotg.indiaultimate.org/&#34;&gt;SOTG app&lt;/a&gt;. I used the &lt;a href=&#34;https://fly.io/launch/heroku&#34;&gt;Turboku web&#xA;page&lt;/a&gt; and it worked pretty seemlessly! It copied over the environment variables&#xA;from Heroku and deployed the app.&lt;/p&gt;&#xA;&lt;p&gt;But, using the Turboku web page meant that I didn&amp;rsquo;t have a &lt;code&gt;fly.toml&lt;/code&gt; file to&#xA;do any future deployments. I used the &lt;code&gt;fly launch&lt;/code&gt; command to create a new app&#xA;and edited the &lt;code&gt;fly.toml&lt;/code&gt; file to point to the migrated app.&lt;/p&gt;&#xA;&lt;p&gt;Setting up the custom domain was pretty simple too, using the CLI. I just had&#xA;to run &lt;code&gt;fly certs add sotg.indiaultimate.org&lt;/code&gt; after changing the DNS entries to&#xA;point to &lt;code&gt;sotg-calculator.fly.dev&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The whole thing felt quite simple and I was done in under an hour &amp;ndash; reading&#xA;the docs, installing the tool, trying out different things, getting it all&#xA;working. Everything. Quite impressive!&lt;/p&gt;&#xA;&lt;h2 id=&#34;migrating-a-bigger-app&#34;&gt;Migrating a bigger app&lt;/h2&gt;&#xA;&lt;p&gt;Encouraged by this, I started with the RSVP app. I didn&amp;rsquo;t think it would be&#xA;much harder than this, but I guess when there are a few more moving parts, it&amp;rsquo;s&#xA;hard to tell what could pop-up.&lt;/p&gt;&#xA;&lt;p&gt;I used the same approach for the migration &amp;ndash; Turboku web page to migrate from&#xA;Heroku and then ran the launch command to generate a &lt;code&gt;fly.toml&lt;/code&gt; file that I&#xA;edited to point to the deployed app.&lt;/p&gt;&#xA;&lt;p&gt;The deployment seemed to go fine, but the app wouldn&amp;rsquo;t come up. I looked at the&#xA;logs to find out that the app was getting &lt;a href=&#34;https://neo4j.com/developer/kb/linux-out-of-memory-killer/&#34;&gt;OOM killed&lt;/a&gt;. Fly.io provides half the&#xA;memory (256MB) that Heroku provided. But, I wasn&amp;rsquo;t expecting this tiny app to&#xA;need much more.&lt;/p&gt;&#xA;&lt;p&gt;I removed some default imports of large packages, but it didn&amp;rsquo;t really help&#xA;that much. I did consider reducing the Gunicorn&amp;rsquo;s &lt;code&gt;WEB_CONCURRENCY&lt;/code&gt; setting to&#xA;1, but didn&amp;rsquo;t want to take that route unless absolutely required. I looked&#xA;around the forums a little, and &lt;a href=&#34;https://community.fly.io/t/question-about-weird-deployment-size-on-fly/5677/2&#34;&gt;found&lt;/a&gt; that using a Dockerfile instead of the&#xA;buildpacks might improve the memory situation. And it did!&lt;/p&gt;&#xA;&lt;p&gt;Next, I moved to setting up the custom domain and it worked from the Fly.io&#xA;side seemlessly. But, the &lt;code&gt;flask_dance&lt;/code&gt; library was generating &lt;code&gt;http&lt;/code&gt; URLs in&#xA;it&amp;rsquo;s OAuth redirect URLs. The app already uses FlaskSSLify, but that didn&amp;rsquo;t&#xA;seem to be sufficient. After reading some &lt;a href=&#34;https://flask-dance.readthedocs.io/en/latest/proxies.html&#34;&gt;Flask dance&lt;/a&gt; and &lt;a href=&#34;https://flask.palletsprojects.com/en/latest/deploying/proxy_fix/&#34;&gt;Flask&lt;/a&gt; docs, I found&#xA;that Werkzeug&amp;rsquo;s &lt;code&gt;ProxyFix&lt;/code&gt; exists exactly for this!&lt;/p&gt;&#xA;&lt;p&gt;After dealing with these two unexpected problems, I got to the problem that I&#xA;was aware I had to tackle &amp;ndash; Fly.io doesn&amp;rsquo;t have support for cron jobs. The&#xA;RSVP app uses some scheduled jobs to periodically sync some metadata from&#xA;Google Drive, Calendar, etc.&lt;/p&gt;&#xA;&lt;p&gt;I took a hackish route to work around this. Using the &lt;a href=&#34;https://schedule.readthedocs.io/en/stable/&#34;&gt;schedule&lt;/a&gt; library, I wrote&#xA;a &lt;a href=&#34;https://github.com/thatte-idli-kaal-soup/rsvpapp/blob/master/scripts/cron.py&#34;&gt;&amp;ldquo;cron&amp;rdquo; script&lt;/a&gt; that would run the jobs on the desired schedule. I created a&#xA;duplicate app to run the cron service, even though it could potentially be run&#xA;as a different process on the same app. I didn&amp;rsquo;t want to risk any more OOM&#xA;kills on the web app. But, it can be a little bit more work to keep the&#xA;environment variables and other such things in sync between the two apps.&lt;/p&gt;&#xA;&lt;p&gt;I was quite excited about Fly.io having a datacenter in Madras and was swayed&#xA;by Fly.io&amp;rsquo;s marketing about running the app close to the users. I tried this&#xA;but the performance was terrible since the Mongo DB was in North Virginia. I&#xA;quickly switched back to using an East Coast region for Fly.io app too.&lt;/p&gt;&#xA;&lt;p&gt;But, while writing this blog post, I realized that I could move the DB to&#xA;India. I moved the DB to the AWS Mumbai datacenter, and the Fly.io app to the&#xA;Madras datacenter.&lt;/p&gt;&#xA;&lt;h2 id=&#34;all-s-well-that-ends-well&#34;&gt;All&amp;rsquo;s well that ends well&lt;/h2&gt;&#xA;&lt;p&gt;The app has been chugging along for a few days without any new hiccups. I&amp;rsquo;m&#xA;hoping things stay this way for the weeks and months to come, if not years.&lt;/p&gt;&#xA;&lt;p&gt;On the whole, I found the whole experience more beta-ish than deploying&#xA;something to Heroku. But, I&amp;rsquo;m quite happy with how the whole thing turned&#xA;out. I think things will get smoother with time &amp;ndash; with my growing familarity&#xA;with Fly.io and more people using their tools suggesting improvements.&lt;/p&gt;&#xA;&lt;p&gt;I am wary of depending on yet another Hobby plan, but neither of these apps&#xA;make any revenue and I&amp;rsquo;m not (yet) comfortable charging users for the small set&#xA;of features they provide.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;d like to hear stories of other people moving away from Heroku! Feel free to&#xA;reach out!&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>An innocent query that caused Zulip downtime</title>
      <link>https://punchagan.muse-amuse.in/blog/zulip-downtime-postmortem/</link>
      <pubDate>Thu, 28 May 2020 11:34:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/zulip-downtime-postmortem/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Recently, &lt;a href=&#34;https://github.com/zulip/zulip/commit/8f32db81a1a1230b425aef8f7c6d2b7fc4543ee7&#34;&gt;a change&lt;/a&gt; that I contributed caused some downtime on the Zulip cloud&#xA;(zulipchat.com). Here&amp;rsquo;s a user &lt;a href=&#34;https://twitter.com/zulip/status/1255005502599131137&#34;&gt;tweeting at us&lt;/a&gt;, about this.&lt;/p&gt;&#xA;&lt;p&gt;I shared this with some friends (who use Zulip) and they asked me to share more&#xA;about what happened. I began writing an explanation, and it eventually turned&#xA;into a blog post. The post tries to explain what caused the down-time, without&#xA;assuming too much knowledge of the Zulip DB schema, but it would help if you&#xA;used Zulip a little.&lt;/p&gt;&#xA;&lt;p&gt;The goal of my change was to change how Zulip backend calculates the&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt; for a user &amp;ndash; the time stamp indicating when the last&#xA;message was read.&lt;/p&gt;&#xA;&lt;p&gt;Previously, the code used simply kept track of the message ID of the messages&#xA;being read by a user in a field called the &amp;ldquo;pointer&amp;rdquo;. My change was to move away&#xA;from this &lt;code&gt;pointer&lt;/code&gt; approach to using the actual timestamp of when a user last&#xA;read a message.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-the-pointer&#34;&gt;What is the pointer?&lt;/h2&gt;&#xA;&lt;p&gt;Put very simply, the pointer is just a message ID&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &amp;ndash; ideally, the ID of the&#xA;&amp;ldquo;last message&amp;rdquo; a user has read. Message IDs in Zulip are incremental &amp;ndash; a&#xA;message that has arrived after another one, would have a higher ID than the&#xA;older message. So, it would&amp;rsquo;ve been a great way to keep track of the last read&#xA;message, if all the messages were in &amp;ldquo;one continuous feed&amp;rdquo;. But, guess what,&#xA;Zulip has streams and topics which are precisely what make Zulip such a valuable&#xA;communication tool!&lt;/p&gt;&#xA;&lt;p&gt;The pointer can be set to the ID of the message that is currently being read,&#xA;but only when we are in the &amp;ldquo;All messages&amp;rdquo; view. In this view, all messages are&#xA;ordered chronologically, so any message that is after another message would have&#xA;arrived after it, and would have an ID greater than the other message. So&#xA;reading a message in this view means, any message with a lower ID must&amp;rsquo;ve&#xA;already been read.&lt;/p&gt;&#xA;&lt;p&gt;When you are reading messages in a stream/topic (narrowed) view, the &lt;code&gt;pointer&lt;/code&gt;&#xA;is not updated. We can&amp;rsquo;t be sure that all messages with ID lower than the&#xA;current message&amp;rsquo;s ID have already been read. There could be a whole bunch of&#xA;unread messages in other streams/topics than the current one you are reading.&#xA;So, the &lt;code&gt;pointer&lt;/code&gt; doesn&amp;rsquo;t get updated until you go to the &amp;ldquo;All messages&amp;rdquo; view&#xA;and scroll over the messages, even if you have already read them in a narrowed&#xA;view.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-change-this&#34;&gt;Why change this?&lt;/h2&gt;&#xA;&lt;p&gt;Using the &lt;code&gt;pointer&lt;/code&gt; to compute the &lt;code&gt;furthest_read_time&lt;/code&gt; doesn&amp;rsquo;t work very well,&#xA;because it is only updated in the &amp;ldquo;All messages&amp;rdquo; view. In other words,&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt; turned out to actually mean something like&#xA;&lt;code&gt;furthest_read_time_in_all_messages_view&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;furthest_read_time&lt;/code&gt; is used in the UI to display the bankruptcy banner &amp;ndash; a&#xA;prompt shown to a user to mark all messages as read, if they have &amp;ldquo;too many&amp;rdquo;&#xA;unreads, and haven&amp;rsquo;t read new messages in the last 48 hours.&lt;/p&gt;&#xA;&lt;p&gt;But, this is a problem, especially in Zulip instances with a lot of traffic,&#xA;where people leave a lot of messages unread until they have the time to&#xA;catch-up. It is common for people to communicate only in a handful of&#xA;streams/topics, and leave a lot of messages unread in other streams or topics,&#xA;that they are hoping to catch-up on, when they have more time at hand. Such&#xA;users would avoid using the &amp;ldquo;All messages&amp;rdquo; view at any cost.&lt;/p&gt;&#xA;&lt;p&gt;Even in not-so-high-traffic realms, some users just prefer not to use the &amp;ldquo;All&#xA;messages&amp;rdquo; view, and just stick to narrowed views.&lt;/p&gt;&#xA;&lt;p&gt;So, for these users the &lt;code&gt;furthest_read_time&lt;/code&gt; would get updated very rarely, and&#xA;could potentially remain at a date way back in the past. This meant the users&#xA;would see the bankruptcy banner despite actively participating in the Realm,&#xA;even if only in a few topics/streams. This is annoying UX, and what something we&#xA;wanted to fix.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-did-we-change-this-to&#34;&gt;What did we change this to?&lt;/h2&gt;&#xA;&lt;p&gt;We decided to use the last read message time as the message to consider for the&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt;. The following &amp;ldquo;innocent looking&amp;rdquo; query should do that for&#xA;us, we thought&amp;hellip;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;objects&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, it does, but not without bringing down the whole of &lt;code&gt;zulipchat.com&lt;/code&gt; after&#xA;a deploy! 🙈 But, why?!&lt;/p&gt;&#xA;&lt;p&gt;Some background on how data is stored would be useful to see why.&lt;/p&gt;&#xA;&lt;h2 id=&#34;usermessage-table-is-huge-my-friend&#34;&gt;UserMessage table is huge, my friend&lt;/h2&gt;&#xA;&lt;p&gt;Zulip&amp;rsquo;s data model has a &lt;code&gt;Message&lt;/code&gt; table that stores the content of each&#xA;message, when it was sent, by whom, to which topic, etc. The &lt;code&gt;UserMessage&lt;/code&gt; table&#xA;is then used to keep track of what the status of this message is, for each user&#xA;that has received the message.  A 32 bit flag field is used to keep track of&#xA;things like, whether the user has read a message, starred a message, has been&#xA;mentioned in a message, etc. So, if a messages is sent to a stream with N users,&#xA;it creates 1 row in the &lt;code&gt;Message&lt;/code&gt; table and N rows in the &lt;code&gt;UserMessage&lt;/code&gt; table.&#xA;If M such messages are sent, it would create M*N rows in the &lt;code&gt;UserMessage&lt;/code&gt;&#xA;table. So, pretty soon, the &lt;code&gt;UserMessage&lt;/code&gt; table becomes huge! &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;To make common queries on this table efficient, the DB has indexes for them.&#xA;Some of the indexes on the &lt;code&gt;UserMessage&lt;/code&gt; table are documented &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/production/expensive-migrations.html#running-expensive-migrations-early&#34;&gt;here&lt;/a&gt;, though the&#xA;documentation was created in the migration context for production deployments.&#xA;There are indexes for various things, including &lt;strong&gt;unread&lt;/strong&gt; messages.&lt;/p&gt;&#xA;&lt;p&gt;And here&amp;rsquo;s our innocent looking query, as a reminder.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;objects&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This query searches through the &lt;code&gt;read&lt;/code&gt; messages for a particular user, and tries&#xA;to figure out the last message they read. Note that the DB only has indexes for&#xA;unread messages, not read messages! So, this query isn&amp;rsquo;t using DB indexes to&#xA;search for this needle in the haystack, and ends up being pretty damn slow!&lt;/p&gt;&#xA;&lt;p&gt;Additionally, this query is run for every user when the &amp;ldquo;home page&amp;rdquo; is loaded&#xA;since we want to calculate their &lt;code&gt;furthest_read_time&lt;/code&gt; to decide if should show&#xA;the bankruptcy banner.&lt;/p&gt;&#xA;&lt;p&gt;Also, Zulip&amp;rsquo;s architecture is designed to allow using the same app server and DB&#xA;to host multiple different realms. And zulipchat.com is such a deployment where&#xA;a few servers are used to serve all the realms. (I don&amp;rsquo;t know too much about the&#xA;deployment setup, though).&lt;/p&gt;&#xA;&lt;p&gt;When a new change is deployed to zulipchat.com and the server is restarted, all&#xA;the clients of all the users reload. Having an expensive query in that path,&#xA;would just kill the DB. And this innocent looking query &lt;a href=&#34;https://twitter.com/zulip/status/1255005502599131137&#34;&gt;didn&amp;rsquo;t disappoint&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-did-we-fix-this&#34;&gt;How did we fix this?&lt;/h2&gt;&#xA;&lt;p&gt;Well, this change was &lt;a href=&#34;https://github.com/zulip/zulip/commit/976e554799a03ff9d82d7b75d77d45985cd25df4&#34;&gt;reverted&lt;/a&gt; immediately by &lt;a href=&#34;https://github.com/timabbott&#34;&gt;Tim&lt;/a&gt;, and things were kicked back&#xA;into a usable state.&lt;/p&gt;&#xA;&lt;p&gt;Later, we decided to take a different approach. We decided to look at a&#xA;different table (&lt;code&gt;UserActivity&lt;/code&gt;) that tracks user activity, mainly for the&#xA;purpose of analytics. This table keeps track of the last time a user performed&#xA;an action based on the API calls made.&lt;/p&gt;&#xA;&lt;p&gt;Among other things, changing any of the flags in the 32-bit flag field is one of&#xA;the actions that is tracked. Marking a message as read was being tracked too. We&#xA;use the last time this action was performed to compute the last time a user was&#xA;&amp;ldquo;active&amp;rdquo;, and based on that decide if we should show the bankruptcy banner or&#xA;not.&lt;/p&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s the &lt;a href=&#34;https://github.com/zulip/zulip/commit/ded3b0076070365dddccd43d7f05fd627c2637f7&#34;&gt;actual commit&lt;/a&gt; that makes this change. But, it turns out that needed a&#xA;&lt;a href=&#34;https://github.com/zulip/zulip/commit/734d651b45542e9a1bdea10cd290637f73be30d9&#34;&gt;follow-up fix&lt;/a&gt; too. 🙈&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;https://web.mit.edu/tabbott/www/&#34;&gt;Tim Abbott&lt;/a&gt; and &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;The pointer was used to do a &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/subsystems/pointer.html&#34;&gt;bunch of useful things&lt;/a&gt;, but we are&#xA;currently in the process of &lt;a href=&#34;https://github.com/zulip/zulip/issues/8994&#34;&gt;removing it&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Zulip&amp;rsquo;s code base uses a concept called &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/subsystems/sending-messages.html#soft-deactivation&#34;&gt;soft-deactivation&lt;/a&gt;&#xA;to mitigate this problem on Realms where there are a lot of users who log in&#xA;very infrequently, or don&amp;rsquo;t login after an initial period of activity. So, the&#xA;number of rows are not exactly &lt;code&gt;M*N&lt;/code&gt; in all the cases, but in the worst case&#xA;they are.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Django ModelFormSet and multiple saves</title>
      <link>https://punchagan.muse-amuse.in/blog/django-modelformset-multiple-saves/</link>
      <pubDate>Wed, 08 Jan 2020 09:45:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/django-modelformset-multiple-saves/</guid>
      <description>&lt;p&gt;A friend and I were trying to &lt;a href=&#34;https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#using-a-model-formset-in-a-view&#34;&gt;use the Django ModelFormSets&lt;/a&gt; in a project, and we&#xA;ran into a subtle bug that took a little big of digging into the Django code to&#xA;identify and work around.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-bug&#34;&gt;The Bug&lt;/h2&gt;&#xA;&lt;p&gt;We weren&amp;rsquo;t really familiar with Django&amp;rsquo;s &lt;code&gt;FormSet&lt;/code&gt; or &lt;code&gt;ModelFormSet&lt;/code&gt;, when we&#xA;started. We began by reading the documentation to get started.&lt;/p&gt;&#xA;&lt;p&gt;The Django docs had &lt;a href=&#34;https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#using-a-model-formset-in-a-view&#34;&gt;an example&lt;/a&gt; that looked straight-forward, and showed how to&#xA;use &lt;code&gt;ModelFormSet&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;manage_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modelformset_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Author&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;c1&#34;&gt;# do something.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;You create a &lt;code&gt;ModelFormSet&lt;/code&gt; class using the &lt;code&gt;modelformset_factory&lt;/code&gt; using the&#xA;required model, and the required fields.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Use the data from a &lt;code&gt;POST&lt;/code&gt; to create an instance of the class from above.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Save the data if the formset validates, and we are done!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;We tweaked the example to our needs, and it worked for us. Mostly.&lt;/p&gt;&#xA;&lt;p&gt;A user reported that after saving the form once with some data, trying to save&#xA;more data didn&amp;rsquo;t work! The form would try to save the data already saved in the&#xA;last save, and fail validation that required some of the fields to be unique.&lt;/p&gt;&#xA;&lt;p&gt;On the second save, the data which was saved during the last save was still&#xA;being treated as newly filled in data!&lt;/p&gt;&#xA;&lt;p&gt;This also caused newly filled-in data during the second save to be lost forever.&#xA;The user was forced to reload the page and re-enter the data.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-why&#34;&gt;The Why&lt;/h2&gt;&#xA;&lt;p&gt;The way Django keeps track of newly filled-in data in the form along with&#xA;multiple levels of caching causes this bug to manifest.&lt;/p&gt;&#xA;&lt;h3 id=&#34;modelformset-queryset-argument&#34;&gt;&lt;code&gt;ModelFormSet&lt;/code&gt; &lt;code&gt;queryset&lt;/code&gt; argument&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;AuthorFormSet&lt;/code&gt; (or any &lt;code&gt;ModelFormSet&lt;/code&gt; created using the &lt;code&gt;modelformset_factory&lt;/code&gt;)&#xA;takes an additional optional argument &lt;code&gt;queryset&lt;/code&gt;. This argument can be used to&#xA;choose specific rows in the DB that need to be used to populate the initial form&#xA;rows, if any. If no &lt;code&gt;queryset&lt;/code&gt; is specified, all the objects in the DB are used.&lt;/p&gt;&#xA;&lt;h3 id=&#34;formset-metadata&#34;&gt;&lt;code&gt;FormSet&lt;/code&gt;  metadata&lt;/h3&gt;&#xA;&lt;p&gt;First, metadata about the form is saved in a few hidden input fields (called the&#xA;&lt;code&gt;ManagementForm&lt;/code&gt;). This hidden form keep tracks of metadata like the total&#xA;number of forms to show, initial form count and the minimum &amp;amp; maximum number of&#xA;forms to display.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-TOTAL_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;19&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-TOTAL_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-INITIAL_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-INITIAL_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-MIN_NUM_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-MIN_NUM_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-MAX_NUM_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1000&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-MAX_NUM_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Initial form count is the count of the number of forms that are pre-filled using&#xA;data from the DB &amp;ndash; essentially, the length of the &lt;code&gt;queryset&lt;/code&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;metadata-does-not-change&#34;&gt;Metadata does not change&lt;/h3&gt;&#xA;&lt;p&gt;When the &lt;code&gt;ModelFormSet&lt;/code&gt; is used as described in the documentation, the metadata&#xA;in the &lt;code&gt;ManagementForm&lt;/code&gt; doesn&amp;rsquo;t get updated when the form is re-rendered in the&#xA;response to a successful &lt;code&gt;POST&lt;/code&gt; request. If one form with new data was&#xA;successfully saved, the number of initial forms in the re-rendered form must go&#xA;up by 1, but it doesn&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;h3 id=&#34;queryset-caching-problem&#34;&gt;Queryset caching problem&lt;/h3&gt;&#xA;&lt;p&gt;Django has caching at the queryset level which means that the queryset doesn&amp;rsquo;t&#xA;get updated with the newly created instances, even if they match the query that&#xA;the queryset uses.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;queryset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;existing_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;existing_authors&lt;/code&gt; is a queryset that looks for a specific set of authors in the&#xA;DB, or may be all the authors in the DB, if that&amp;rsquo;s what the form needs to do.&lt;/p&gt;&#xA;&lt;p&gt;So, when a formset has been submitted, and some new rows have been created in&#xA;the model&amp;rsquo;s table, the new rows don&amp;rsquo;t automatically get added to the &lt;code&gt;queryset&lt;/code&gt;&#xA;since it the results fetched from the DB are cached by the &lt;code&gt;queryset&lt;/code&gt;. We need&#xA;to create a new &lt;code&gt;queryset&lt;/code&gt; for it to include the newly created rows.&lt;/p&gt;&#xA;&lt;p&gt;These two levels of caching combined make the bug manifest, as it does. I&amp;rsquo;m not&#xA;yet sure what the correct &amp;ldquo;fix&amp;rdquo; for this is, but we ended up using a work-around&#xA;&amp;ndash; create a new formset when returning from a successful &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-work-around&#34;&gt;The Work-Around&lt;/h2&gt;&#xA;&lt;p&gt;We instantiate a new &lt;code&gt;ModelFormSet&lt;/code&gt; instance when returning the form, on a&#xA;successful &lt;code&gt;POST&lt;/code&gt;. This means, the &lt;code&gt;ManagementForm&lt;/code&gt; is recreated for the new&#xA;formset and has the correct metadata about the form, even when being rendered in&#xA;the response of a successful &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The code in the example in Django docs, would look something like the one below:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;manage_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modelformset_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Author&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This blog post should probably become a PR or an issue, but I&amp;rsquo;m not familiar&#xA;with how contributing to Django works. This blog post is an attempt to&#xA;understand the issue better, and potentially help others who get bit by it.&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;  &lt;div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Isolating flaky Django tests</title>
      <link>https://punchagan.muse-amuse.in/blog/isolating-flaky-django-tests/</link>
      <pubDate>Wed, 05 Jun 2019 18:37:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/isolating-flaky-django-tests/</guid>
      <description>&lt;p&gt;The Zulip repository had a bunch of flaky tests that were fixed a few weeks ago.&#xA;I learnt a couple of tricks that I wasn&amp;rsquo;t aware of during this.&lt;/p&gt;&#xA;&lt;p&gt;Django&amp;rsquo;s test runner has an &lt;a href=&#34;https://docs.djangoproject.com/en/1.11/ref/django-admin/#cmdoption-test-reverse&#34;&gt;option&lt;/a&gt; to run tests in the reverse order. The&#xA;documentation of this option explicitly mentions that this option is useful for&#xA;debugging side-effects of tests that are not properly isolated. I wasn&amp;rsquo;t aware&#xA;of this option, and it&amp;rsquo;s a pretty neat tool.&lt;/p&gt;&#xA;&lt;p&gt;The test runner also has a &lt;a href=&#34;https://docs.djangoproject.com/en/1.11/ref/django-admin/#cmdoption-test-parallel&#34;&gt;&lt;code&gt;--parallel&lt;/code&gt; option&lt;/a&gt; to run tests in parallel, and the&#xA;Zulip server uses this option when running the back-end tests. I never really&#xA;bothered to look into how test cases are assigned to different processes. The&#xA;Django docs explain:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Django distributes test cases — &lt;code&gt;unittest.TestCase&lt;/code&gt; subclasses — to subprocesses.&#xA;If there are fewer test cases than configured processes, Django will reduce the&#xA;number of processes accordingly.&lt;/p&gt;&#xA;&lt;p&gt;Each process gets its own database. You must ensure that different test cases&#xA;don’t access the same resources. For instance, test cases that touch the&#xA;filesystem should create a temporary directory for their own use.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;When running tests in parallel, the set of tests running in the same process can&#xA;vary quite a bit based on the execution speed of tests in different processes.&#xA;To add more variation to the order in that tests are run, the number of&#xA;processes being used could also be changed.&lt;/p&gt;&#xA;&lt;p&gt;These two tools combined together can get tests to run in different orders than&#xA;the usual order in which they usually get run, and can help find tests which are&#xA;not well isolated.&lt;/p&gt;&#xA;&lt;p&gt;It could be a good idea to run tests in parallel (with a randomly chosen,&#xA;reasonable number of processes) and with the &lt;code&gt;--reverse&lt;/code&gt; flag, once in every few&#xA;CI runs, or as a cron job periodically.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;  &lt;div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;https://baali.muse-amuse.in&#34;&gt;Shantanu Choudhary&lt;/a&gt; for nudging me to write this post, and reading&#xA;drafts of this post. Thanks also to &lt;a href=&#34;https://blog.zulip.org/author/tabbott/&#34;&gt;Tim Abbott&lt;/a&gt; for making me aware of these&#xA;tricks.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Python&#39;s globals</title>
      <link>https://punchagan.muse-amuse.in/blog/python-globals/</link>
      <pubDate>Sun, 29 Jul 2018 09:09:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/python-globals/</guid>
      <description>&lt;h2 id=&#34;tl-dr&#34;&gt;TL; DR&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The &lt;code&gt;global&lt;/code&gt; statement is a parser directive to indicate that &lt;code&gt;globals&lt;/code&gt; are&#xA;being used. When looking up &lt;code&gt;globals&lt;/code&gt;, the &lt;code&gt;globals&lt;/code&gt; of the current scope are&#xA;fetched.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Python&amp;rsquo;s &lt;code&gt;globals&lt;/code&gt; are really just module-level.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Every function has an associated &lt;code&gt;__globals__&lt;/code&gt; dictionary, which is the &lt;strong&gt;same&#xA;as the module&amp;rsquo;s &lt;code&gt;__dict__&lt;/code&gt; for the module where it was defined&lt;/strong&gt;. This&#xA;&lt;code&gt;__globals__&lt;/code&gt; dict is the name-space that is looked up when trying to fetch&#xA;&lt;code&gt;globals&lt;/code&gt; within a function.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Avoid globals to make it easier to test functions&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;motivation&#34;&gt;Motivation&lt;/h2&gt;&#xA;&lt;p&gt;During a mentoring session I was doing recently, we ran into a problem with&#xA;&lt;code&gt;globals&lt;/code&gt; in Python.&lt;/p&gt;&#xA;&lt;p&gt;Here is a toy example to describe what we were seeing.&lt;/p&gt;&#xA;&lt;p&gt;We had code in a module &lt;code&gt;foo.py&lt;/code&gt; where the function &lt;code&gt;f&lt;/code&gt; was using a global&#xA;defined in &lt;code&gt;main&lt;/code&gt;, and we were trying to write tests for the function &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# foo.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this file &lt;code&gt;foo.py&lt;/code&gt; prints out &lt;code&gt;5&lt;/code&gt; as expected.&lt;/p&gt;&#xA;&lt;p&gt;We would now like to import &lt;code&gt;f&lt;/code&gt; into a different module and use it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;running-f-in-a-different-module&#34;&gt;Running &lt;code&gt;f&lt;/code&gt; in a different module&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running the module &lt;code&gt;bar.py&lt;/code&gt; gives us a &lt;code&gt;NameError&lt;/code&gt;, as expected. The name &lt;code&gt;a&lt;/code&gt;&#xA;was defined in the &lt;code&gt;main&lt;/code&gt; in &lt;code&gt;foo.py&lt;/code&gt; which is never being run when the code is&#xA;imported in &lt;code&gt;bar.py&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bar.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bar.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;foo.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ne&#34;&gt;NameError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;defined&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;setting-a-global-value-for-a&#34;&gt;Setting a global value for &lt;code&gt;a&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;We&amp;rsquo;d like to be able to run &lt;code&gt;f&lt;/code&gt; without running &lt;code&gt;main&lt;/code&gt; and the first fix that&#xA;comes to mind is to set the value of &lt;code&gt;a&lt;/code&gt; in &lt;code&gt;bar&lt;/code&gt;, and let &lt;code&gt;f&lt;/code&gt; use that.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Surprise! Nothing changes.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/example/bar.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/example/bar.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/tmp/example/foo.py&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ne&#34;&gt;NameError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;defined&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Why doesn&amp;rsquo;t this work?!&lt;/p&gt;&#xA;&lt;h2 id=&#34;function-globals-and-the-global-statement&#34;&gt;Function &lt;code&gt;__globals__&lt;/code&gt; and the &lt;code&gt;global&lt;/code&gt; statement&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;code&gt;global&lt;/code&gt; statement is a directive to the parser, that specifies that the&#xA;variable being assigned to is a global variable.&lt;/p&gt;&#xA;&lt;p&gt;This can be seen by looking at the disassembled code for &lt;code&gt;f&lt;/code&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;dis&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;dis&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;dis&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;5&lt;/span&gt;           &lt;span class=&#34;err&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;LOAD_GLOBAL&lt;/span&gt;              &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;LOAD_GLOBAL&lt;/span&gt;              &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CALL_FUNCTION&lt;/span&gt;            &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;6&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;POP_TOP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;err&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;LOAD_CONST&lt;/span&gt;               &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;None&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;           &lt;span class=&#34;err&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;RETURN_VALUE&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;globals&lt;/code&gt; for the current frame are fetched, and the value is updated in that&#xA;dict. Each function in Python has an associated &lt;code&gt;__globals__&lt;/code&gt; dict which is a&#xA;reference to that module&amp;rsquo;s &lt;code&gt;__dict__&lt;/code&gt; in which the function was defined. So, in&#xA;the case where we try to set the &lt;code&gt;a = 4&lt;/code&gt; in &lt;code&gt;bar.main&lt;/code&gt;, the &lt;code&gt;main&lt;/code&gt; function&amp;rsquo;s&#xA;&lt;code&gt;__globals__&lt;/code&gt; dict is being updated.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__globals__&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;keys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__globals__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;dict_keys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;__name__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__doc__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__package__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__loader__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__spec__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__annotations__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__builtins__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__file__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__cached__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;f&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;dis&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;main&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;As you can see &lt;code&gt;a&lt;/code&gt; is being set to &lt;code&gt;4&lt;/code&gt;, but &lt;code&gt;f&lt;/code&gt; still doesn&amp;rsquo;t see value, since&#xA;it has it&amp;rsquo;s own &lt;code&gt;__globals__&lt;/code&gt; dictionary. Printing the &lt;code&gt;globals&lt;/code&gt; dictionary for&#xA;&lt;code&gt;f&lt;/code&gt; should make that clear.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__globals__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the variable &lt;code&gt;a&lt;/code&gt; was declared in the module &lt;code&gt;foo&lt;/code&gt; outside of any of the&#xA;functions, it would be in &lt;code&gt;f&lt;/code&gt;&amp;rsquo;s &lt;code&gt;__globals__&lt;/code&gt; dict when it is imported, and&#xA;hence the name error would go away, but setting it still would not work.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# foo.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;global&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;bar.py&lt;/code&gt; would print the value &lt;code&gt;3&lt;/code&gt; which has been defined in &lt;code&gt;foo.py&lt;/code&gt;,&#xA;and not &lt;code&gt;4&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;updating-globals&#34;&gt;Updating &lt;code&gt;__globals__&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;p&gt;To update the value of &lt;code&gt;a&lt;/code&gt; for &lt;code&gt;f&lt;/code&gt;, we could modify it&amp;rsquo;s &lt;code&gt;globals&lt;/code&gt; dict.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;vm&#34;&gt;__globals__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;module-dict-and-monkey-patching&#34;&gt;Module &lt;code&gt;__dict__&lt;/code&gt; and monkey-patching&lt;/h2&gt;&#xA;&lt;p&gt;As mentioned previously, a function&amp;rsquo;s &lt;code&gt;__globals__&lt;/code&gt; dict is a reference to the&#xA;module&amp;rsquo;s &lt;code&gt;__dict__&lt;/code&gt; for the module where the function was defined. So, we could&#xA;achieve the same result as above by updating &lt;code&gt;foo.__dict__&lt;/code&gt;. And setting an&#xA;attribute on the module &lt;code&gt;foo&lt;/code&gt; is the same as updating this dict.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;foo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have used a library like &lt;code&gt;mock&lt;/code&gt; to patch some code while running tests,&#xA;this is essentially what is happening. The &lt;code&gt;target&lt;/code&gt; module&amp;rsquo;s dict is looked up&#xA;for the specified object/function and replaced with a mock object.&lt;/p&gt;&#xA;&lt;h2 id=&#34;use-an-argument-to-make-it-testable&#34;&gt;Use an argument to make it testable&lt;/h2&gt;&#xA;&lt;p&gt;The function &lt;code&gt;f&lt;/code&gt; would&amp;rsquo;ve been much easier to test, if it took &lt;code&gt;a&lt;/code&gt; as an&#xA;argument, instead of using a global value. This functional approach would make&#xA;the code easier to reason about too.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# foo.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vm&#34;&gt;__name__&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# bar.py&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;foo&lt;/span&gt; &lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Thanks to &lt;a href=&#34;https://in.linkedin.com/in/akshaya-mukundhan&#34;&gt;Akshaya&lt;/a&gt; and &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reviewing this blog post.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Create a Public Jupyter Server, quickly!</title>
      <link>https://punchagan.muse-amuse.in/blog/create-a-public-jupyter-server-quickly/</link>
      <pubDate>Thu, 25 Aug 2016 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/create-a-public-jupyter-server-quickly/</guid>
      <description>&lt;p&gt;I create public Jupyter notebooks once in a while, to collaborate with a&#xA;friend, or to make it easier for myself to work with data on a remote machine.&lt;/p&gt;&#xA;&lt;p&gt;Each time I need to look up the &lt;a href=&#34;http://jupyter-notebook.readthedocs.io/en/latest/public_server.html&#34;&gt;docs&lt;/a&gt;, and manually set-up a few things, before&#xA;I can start using the notebook.&lt;/p&gt;&#xA;&lt;p&gt;I just wrote a bash script that does the following, quickly -&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Install Jupyter into a temporary virtualenv&lt;/li&gt;&#xA;&lt;li&gt;Create certificate files&lt;/li&gt;&#xA;&lt;li&gt;Start the server with https enabled and a password&lt;/li&gt;&#xA;&lt;li&gt;Delete all temporary files, when the server is shutdown&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;script src=&#34;https://gist-it.appspot.com/github/punchagan/dot-files/blob/master/bin/jupyter-server.sh&#34;&gt;&lt;/script&gt;&#xA;&lt;p&gt;You can get it &lt;a href=&#34;https://github.com/punchagan/dot-files/blob/master/bin/jupyter-server.sh&#34;&gt;here&lt;/a&gt;, if you&amp;rsquo;d like to use it.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Python reload and module dict</title>
      <link>https://punchagan.muse-amuse.in/blog/python-reload-and-module-dict/</link>
      <pubDate>Thu, 23 Jun 2016 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/python-reload-and-module-dict/</guid>
      <description>&lt;p&gt;I was trying to play around with Nikola&amp;rsquo;s code today and learnt about a&#xA;documented weirdness of Python&amp;rsquo;s reload.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Below are two versions of code &amp;ndash; &lt;code&gt;ORIGINAL&lt;/code&gt; and &lt;code&gt;UPDATED&lt;/code&gt; respectively&#xA;referring to the orginial code and the code after changes. The code only has a&#xA;&lt;code&gt;PLUGINS&lt;/code&gt; list, which is changed in each version of the code.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Work in a temporary directory&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;os&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;tempfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;os&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chdir&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tempfile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mkdtemp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Module content, original and updated&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;ORIGINAL&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;# PLUGINS = []&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UPDATED&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;PLUGINS = [&amp;#39;rss&amp;#39;]&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create_conf_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Create a conf.py module with given content.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;conf.py&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;conf&lt;/code&gt; doesn&amp;rsquo;t have a &lt;code&gt;PLUGINS&lt;/code&gt; attribute in the &lt;code&gt;ORIGINAL&lt;/code&gt; code.  It&amp;rsquo;s been commented out!&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;create_conf_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ORIGINAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# PLUGINS is not defined in the module, originally.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PLUGINS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The code for &lt;code&gt;conf&lt;/code&gt; has been updated, but the module doesn&amp;rsquo;t yet have a&#xA;&lt;code&gt;PLUGINS&lt;/code&gt; attribute, since the new module isn&amp;rsquo;t imported until we reload.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;create_conf_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UPDATED&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PLUGINS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;PLUGINS&lt;/code&gt; has the expected value, after the reload&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;importlib&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;importlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PLUGINS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;What happens when we revert to the &lt;code&gt;ORIGINAL&lt;/code&gt; code, and reload the module?&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# We write back the original file. PLUGINS should be empty!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;create_conf_file&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ORIGINAL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kn&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;importlib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;conf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;PLUGINS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;---Whaaaat!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The behavior is well documented, along with a reasoning of why it is the way it&#xA;is, but you can trip over it if you don&amp;rsquo;t know. I hit a bug and was wondering&#xA;if there was a race condition somewhere, until I read the docs for &lt;a href=&#34;https://docs.python.org/3/library/importlib.html#importlib.reload&#34;&gt;reload&lt;/a&gt;. On&#xA;reload, &lt;strong&gt;the module dict is updated&lt;/strong&gt;, instead of creating a new dict. Any&#xA;values &lt;strong&gt;not redefined&lt;/strong&gt; in the new code for the module &lt;strong&gt;remain unchanged&lt;/strong&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Playing music using mpsyt from Emacs</title>
      <link>https://punchagan.muse-amuse.in/blog/playing-music-using-mpsyt-from-emacs/</link>
      <pubDate>Mon, 20 Apr 2015 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/playing-music-using-mpsyt-from-emacs/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve started using the wonderful &lt;a href=&#34;https://github.com/np1/mps-youtube/&#34;&gt;mpsyt&lt;/a&gt; to play any music from youtube, since&#xA;I&amp;rsquo;m not really interested in the video.  But, since I use emacs for chat/IRC, I&#xA;end up getting youtube links into emacs and opening them opens them up in my&#xA;browser. I ended up writing some &lt;code&gt;elisp&lt;/code&gt; to play the songs from within an&#xA;instance of &lt;code&gt;mpsyt&lt;/code&gt; running inside an emacs buffer.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/short-url-at-point&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Gets the short url at point.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;This function is required only because&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;`thing-at-point-url-at-point&amp;#39;&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; ignores urls (without a scheme)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;that don&amp;#39;t start with www.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;thing-at-point-bounds-of-url-at-point&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;car&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;cdr&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;buffer-substring-no-properties&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;car&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;cdr&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;bounds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/mpsyt-url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;buffer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;current-buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;*mpsyt*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;;; Start a new term with *mpsyt* if there isn&amp;#39;t one&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-process&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-buffer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;kill-buffer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-buffer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;ansi-term&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;mpsyt&amp;#34;&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;mpsyt&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;;; Play given url in mpsyt&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;mpsyt-proc&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-process&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;;; If something is already playing, stop it and play this...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term-send-string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;\n\n\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;;; We wait for a bit, since looking for the prompt seems to fail, sometimes?&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;sleep-for&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term-send-string&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;;; Actually send the command to playurl&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;term-simple-send&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get-process&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;mpsyt-proc-name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;playurl %s&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;switch-to-buffer&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;buffer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;defun&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;pc/mpsyt-url-at-point&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;s&#34;&gt;&amp;#34;Play the URL at point using mpsyt.&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;interactive&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;url-get-url-at-point&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/short-url-at-point&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;No URL found&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Playing %s with mpsyt&amp;#34;&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;pc/mpsyt-url&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;url&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The current version of mpsyt crashes when run from inside emacs due to a bug in&#xA;the code to get the terminal size, which should be fixed once this &lt;a href=&#34;https://github.com/np1/mps-youtube/pull/247&#34;&gt;patch&lt;/a&gt; is&#xA;merged.&lt;/p&gt;&#xA;&lt;p&gt;I would&amp;rsquo;ve expected &lt;code&gt;thing-at-point-url-at-point&lt;/code&gt; to be able to find urls even&#xA;when they don&amp;rsquo;t have a schema, but it tries to guess the schema from urls and&#xA;fails to work when the url starts with &lt;code&gt;youtube.com&lt;/code&gt; instead of&#xA;&lt;code&gt;www.youtube.com&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I started off using the command-line interface of &lt;code&gt;mpsyt&lt;/code&gt; by running it using&#xA;&lt;code&gt;shell-command&lt;/code&gt; or &lt;code&gt;start-process&lt;/code&gt;.  But, it seemed useful to have a buffer of&#xA;&lt;code&gt;mpsyt&lt;/code&gt; to switch to &amp;ndash; easier to search for new music, repeating songs, etc.&#xA;Not all tasks/actions are achievable through &lt;code&gt;mpsyt&lt;/code&gt;&amp;rsquo;s command line args.&lt;/p&gt;&#xA;&lt;p&gt;I ended up writing more code than I thought I would have to[1].  But, I&amp;rsquo;m&#xA;pretty happy with how this all works, right now.&lt;/p&gt;&#xA;&lt;p&gt;[1] - Isn&amp;rsquo;t it true, more often than not?&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-27</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-27/</link>
      <pubDate>Thu, 28 Aug 2014 09:51:30 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-27/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I spent the whole of yesterday just working on the LED-bot.&lt;/li&gt;&#xA;&lt;li&gt;Spent some time cleaning up meta-stuff about the project, making it a real&#xA;package, adding a setup.py, added LICENSE &amp;amp; AUTHOR files, etc.&lt;/li&gt;&#xA;&lt;li&gt;I found it really frustrating that there&amp;rsquo;s no good/standard way to remove&#xA;duplication of information between pip&amp;rsquo;s &lt;code&gt;requirements.txt&lt;/code&gt; and&#xA;&lt;code&gt;install_requires&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;We got the bot running on the Beagle Bone, but it turned out to be too slow.&#xA;After some playing around with trying to get rid of Python for-loops, I was&#xA;able to use PIL&amp;rsquo;s &lt;code&gt;image.tobytes&lt;/code&gt; and some image cropping to get the data to&#xA;be sent to the LEDs, and it sped up the display quite a bit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-26</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-26/</link>
      <pubDate>Wed, 27 Aug 2014 10:23:27 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-26/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I spent most of the day refactoring the code for the LED Bot, and am happy&#xA;with the way it looks right now.&lt;/li&gt;&#xA;&lt;li&gt;My talk at Hack and Tell went OK.  I was distracted by &lt;a href=&#34;https://github.com/damianavila/live_reveal&#34;&gt;live&lt;sub&gt;reveal&lt;/sub&gt;&lt;/a&gt; not&#xA;displaying properly on the smaller resolution, and not being able to mirror&#xA;screens!&lt;/li&gt;&#xA;&lt;li&gt;There were a bunch of interesting talks presented by the&#xA;others. &lt;a href=&#34;http://comparea.org&#34;&gt;http://comparea.org&lt;/a&gt;, &lt;a href=&#34;https://medium.com/@vijayp/of-taxis-and-rainbows-f6bc289679a1&#34;&gt;Taxis and Rainbows&lt;/a&gt; were the most interesting&#xA;ones for me.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-20</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-20/</link>
      <pubDate>Fri, 22 Aug 2014 22:43:04 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-20/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I finished going through the third of Dave Beazley&amp;rsquo;s tutorials on Generators&#xA;and Co-routines.&lt;/li&gt;&#xA;&lt;li&gt;Also refactored api-diff to use astroid, instead of the ast module.  Kinda&#xA;happy with what I have, for now. May be more, later&amp;hellip;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-21</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-21/</link>
      <pubDate>Fri, 22 Aug 2014 10:33:34 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-21/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I added an additional view to xtab, to see all the pages that were killed,&#xA;and reopen them, if you so choose.&lt;/li&gt;&#xA;&lt;li&gt;Also, cleaned up the &lt;code&gt;api-diff&lt;/code&gt; project and renamed it to &lt;a href=&#34;https://github.com/punchagan/what-changed&#34;&gt;what-changed&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Started thinking about building the GitHub organization dashboard, that I&#xA;thought would be interesting to have, since the 1st or 2nd week of Hacker&#xA;School.&lt;/li&gt;&#xA;&lt;li&gt;A bunch of awesome thursday presentations, and job fair and awesome food by&#xA;Chef Warren!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-19</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-19/</link>
      <pubDate>Wed, 20 Aug 2014 18:06:53 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-19/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I spent most of the day working through David Beazly&amp;rsquo;s tutorials on&#xA;generators and coroutines, and it was mind bending.&lt;/li&gt;&#xA;&lt;li&gt;I learnt about &lt;code&gt;send&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; methods on generators!  I hadn&amp;rsquo;t heard of&#xA;them before, and was totally surprised to come across them.&lt;/li&gt;&#xA;&lt;li&gt;I spent a little time late in the day getting class diffs working, and&#xA;refactoring the api-diff tool to remove duplication of code between classes&#xA;and modules. But, not very happy with the way I did it.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-18</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-18/</link>
      <pubDate>Tue, 19 Aug 2014 13:11:49 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-18/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I refactored the API-diff code, and am pretty happy with what I have right&#xA;now, and need to add support for diffing Classes. I&amp;rsquo;m considering using&#xA;&lt;a href=&#34;http://www.astroid.org&#34;&gt;Atstroid&lt;/a&gt; instead of Python&amp;rsquo;s &lt;code&gt;ast&lt;/code&gt; module, since some of the work that I want&#xA;to do, has already been done for me.&lt;/li&gt;&#xA;&lt;li&gt;With the white-boarding group, we worked on a set of simple exercises for&#xA;strings and arrays.&lt;/li&gt;&#xA;&lt;li&gt;José Valim&amp;rsquo;s presentation on Elixir was interesting and got me reading up a&#xA;stuff about concurrency, and related stuff.  Thanks!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-17</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-17/</link>
      <pubDate>Mon, 18 Aug 2014 21:59:07 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-17/</guid>
      <description>&lt;h2 id=&#34;friday&#34;&gt;Friday&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Updated my HS profile page with projects that I worked on, and a short bio.&lt;/li&gt;&#xA;&lt;li&gt;Joined the group discussing algorithmic complexity&lt;/li&gt;&#xA;&lt;li&gt;Submitted a pull request to blaggregator to fix issues with broken profile&#xA;images.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;saturday-and-sunday&#34;&gt;Saturday &amp;amp; Sunday&lt;/h2&gt;&#xA;&lt;p&gt;I almost didn&amp;rsquo;t write any code during the weekend.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-14</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-14/</link>
      <pubDate>Fri, 15 Aug 2014 18:09:59 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-14/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I spent the morning cleaning up the &amp;ldquo;repr&amp;rdquo; functions of the diff classes, so&#xA;that the diff of functions between two modules can be printed out in a&#xA;somewhat meaningful way.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I spent most of the afternoon, preparing to make a small presentation on how&#xA;&lt;code&gt;sys.path&lt;/code&gt; works in Python.  I thought I didn&amp;rsquo;t do as good a job of it, as I&#xA;would&amp;rsquo;ve liked, but Tom thought it was not too bad&amp;hellip;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Looks like another of those days, where I didn&amp;rsquo;t get much done&amp;hellip;  I spent&#xA;the evening finishing off &lt;a href=&#34;http://craphound.com/homeland/&#34;&gt;Homeland&lt;/a&gt;. It&amp;rsquo;s a brilliant book, and everyone who&#xA;cares about the Government and policies and technology MUST read it!  Thanks&#xA;Cory.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-13</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-13/</link>
      <pubDate>Thu, 14 Aug 2014 11:11:59 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-13/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I feel like I didn&amp;rsquo;t get much done yesterday.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I mostly worked on the API differ, but didn&amp;rsquo;t get much done.  I have a few&#xA;tests, and some code for diffing two functions, but I&amp;rsquo;m not very happy with&#xA;it.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I helped Giorgio and Carlos with using my client only &lt;code&gt;hs_oauth&lt;/code&gt;&#xA;script/library, for their Zulip bot.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The white boarding group worked on some binary related problems, and it was&#xA;fun.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I looked at how the HS OAuth backend works on blaggregator and thought about&#xA;how to go about fixing the issue of broken images on the site.  The problem&#xA;happens because the image URLs are returned from the HS API calls, that are&#xA;made whenever a user logs in(?), and the URLs are cached.  Since, HS uses&#xA;cloudfront for its assets, the URLs expire after a period of time, and the&#xA;cached urls in blag&amp;rsquo;s database need to be updated.  There could be two ways&#xA;of doing it -&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Check if the URL 404s, every time a URL is requested, on the server side.&lt;/li&gt;&#xA;&lt;li&gt;Do it on the client side, with some javascript magic.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Intuitively, I feel like 2. would be better, but Madhu suggested&#xA;that 1. wouldn&amp;rsquo;t be that bad either.  We could try both out, and see which&#xA;works better I suppose.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;d be interested to try this out, sometime.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-12</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-12/</link>
      <pubDate>Wed, 13 Aug 2014 10:30:30 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-12/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;An issue I was seeing with &lt;code&gt;pip&lt;/code&gt; and a package installed in&#xA;&lt;code&gt;system-site-packages&lt;/code&gt; turned out to be non-reproducible.  It was probably&#xA;PEBKAC.&lt;/li&gt;&#xA;&lt;li&gt;I was wondering around in the morning trying to find something to work on.&lt;/li&gt;&#xA;&lt;li&gt;I decided to work on Pankaj&amp;rsquo;s idea to write a tool that gives you API&#xA;differences between two versions of a library.  It would be useful to have&#xA;the list of public API changes in a library you use, to estimate the cost of&#xA;updating to the newer version, without having to manually go through all the&#xA;changes.&lt;/li&gt;&#xA;&lt;li&gt;I spent some time talking to Sophia, and looking at her FTP server&amp;rsquo;s&#xA;refactored code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-11</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-11/</link>
      <pubDate>Mon, 11 Aug 2014 11:16:08 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-11/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I spent about an hour in the morning testing out the staging blaggregator&#xA;instance, and things seemed to work as expected.  Side note, I got added as a&#xA;collaborator on the blaggregator repo!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We worked through the first chapter on getting video working, but we mostly&#xA;ended up just copying code rather than actually understanding/carefully&#xA;studying it.  I&amp;rsquo;m not sure how I feel about it, but we got to display fancy&#xA;stuff.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I wasn&amp;rsquo;t feeling like working on any of my &amp;lsquo;old&amp;rsquo;/&amp;lsquo;ongoing&amp;rsquo; projects, and&#xA;since Mondays don&amp;rsquo;t feel very productive, I worked on writing a couple of&#xA;simple scripts to create twitter lists of HSers, batch wise.&lt;/p&gt;&#xA;&lt;p&gt;For the HS API, I just reused some old code I had lying around from my&#xA;experiments with the OAuth2 API, though I had to tweak it a little bit to be&#xA;able to actually login, using requests. Something about CSRF tokens seems to&#xA;have changed.&lt;/p&gt;&#xA;&lt;p&gt;In the process, I found that twitter&amp;rsquo;s API isn&amp;rsquo;t very pleasant to use.  Or&#xA;may be it&amp;rsquo;s the fact that I was using python twitter client without getting&#xA;my own client id/key, but the whole experience of dealing with the twitter&#xA;API wasn&amp;rsquo;t a pleasant one at all!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Amber, Daria and I also spent about an hour white-boarding some problems from&#xA;the Cracking the Code Interview book.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I ended up fixing some minor issues with blaggregator and am hoping that the&#xA;long pending PR will be merged today.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-08</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-08/</link>
      <pubDate>Sat, 09 Aug 2014 20:56:22 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-08/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;I spent the morning doing some white-boarding interview practice with a Jorge&#xA;and Brian.&lt;/li&gt;&#xA;&lt;li&gt;I spent the rest of the day, playing with PyPy and working through &lt;a href=&#34;http://morepypy.blogspot.in/2011/04/tutorial-writing-interpreter-with-pypy.html&#34;&gt;a tutorial&lt;/a&gt;&#xA;that teaches us to write a BF interpreter.&lt;/li&gt;&#xA;&lt;li&gt;I spent the Saturday revamping my Emacs config.  The main issue with my&#xA;config was having a &amp;ldquo;package&amp;rdquo; list, of all the packages that the&#xA;configuration uses, in case we are trying to duplicate it elsewhere.  I&#xA;noticed that this gets out of sync, because I install packages by hand and&#xA;never update this list.  I wrote up &lt;a href=&#34;https://github.com/punchagan/dot-emacs/blob/master/user-lisp/setup-defuns.el&#34;&gt;some code&lt;/a&gt;, that keeps this list in sync&#xA;with all the packages I have installed.  I configured el-get to play well&#xA;with my config, and am pretty happy with my setup, though I still have to add&#xA;some matching/searching features with helm/ido/whatever else.&lt;/li&gt;&#xA;&lt;li&gt;I spent the Sunday writing a patch to &lt;a href=&#34;https://github.com/punchagan/xtab/tree/kill-by-memory&#34;&gt;xtab&lt;/a&gt; to be able to limit the number of&#xA;tabs in Chromium by the memory it uses.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-08-03</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-03/</link>
      <pubDate>Mon, 04 Aug 2014 16:10:41 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-08-03/</guid>
      <description>&lt;h2 id=&#34;friday&#34;&gt;Friday&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;On Friday, I didn&amp;rsquo;t do the exercises that everyone else doing job prep were&#xA;doing.  I wanted to continue writing C code, and continued to work on the&#xA;&lt;code&gt;bencode&lt;/code&gt; parser in C.  I barely was able to finish adding support for lists.&lt;/li&gt;&#xA;&lt;li&gt;I got comfortable using Valgrind, in the process of debugging a stupidity of&#xA;not using &lt;code&gt;realloc&lt;/code&gt; correctly.&lt;/li&gt;&#xA;&lt;li&gt;What I was able to write with Python in an hour or so, I have been writing&#xA;for about a day, in C, and haven&amp;rsquo;t yet finished it!  It definitely doesn&amp;rsquo;t&#xA;help that my C is very rusty&amp;hellip;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;saturday-and-sunday&#34;&gt;Saturday &amp;amp; Sunday&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I didn&amp;rsquo;t work much, and went around New York with Madhu.  We went to quite&#xA;a few places around here, the highlight being, the view of Manhattan&amp;rsquo;s&#xA;skyline from the Staten Island Ferry.&lt;/li&gt;&#xA;&lt;li&gt;NYC&amp;rsquo;s library also had an interesting exhibhition on the history of&#xA;America, just before and during WW-I.&lt;/li&gt;&#xA;&lt;li&gt;On Sunday, I tried out Mary TTS on the raspberry pi, and it is simply&#xA;unusable.&lt;/li&gt;&#xA;&lt;li&gt;I then, started writing a simple wrapper around Google&amp;rsquo;s tts that is used&#xA;by Google translate.&lt;/li&gt;&#xA;&lt;li&gt;The TTS part is more or less working right now, the next step would be to&#xA;deploy it on the RaspberryPi and start using it as a radio, to see what my&#xA;needs are like. Hooking it up to &lt;a href=&#34;https://github.com/jasperproject/jasper-client&#34;&gt;Jasper client&lt;/a&gt; seems like a good idea,&#xA;right now&amp;hellip; though I&amp;rsquo;m not sure if it would work very well, with the pi&amp;rsquo;s&#xA;audio output drowning out the voice commands.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-07-28</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-28/</link>
      <pubDate>Mon, 28 Jul 2014 22:23:39 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-28/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;There seemed to be excitement in the space to have Jessica around.  We had&#xA;coffee with her, and I chatted with her briefly. She encouraged me to try and&#xA;send a patch to CPython, that involved debugging and fixing some C issues.&lt;/li&gt;&#xA;&lt;li&gt;I spent some time with Tom, while he tried to get &lt;code&gt;cinspect&lt;/code&gt; working for him,&#xA;and it seemed like having the developer next to you, helped.  As always.  We&#xA;didn&amp;rsquo;t make any fixes to the code, but it worked.&lt;/li&gt;&#xA;&lt;li&gt;I spent the afternoon, adding tests for a simple issue, to see how patches are sent.&lt;/li&gt;&#xA;&lt;li&gt;Later, I paired with Sophia for an hour to refactor the vcs code. It&amp;rsquo;s&#xA;beginning to look much better than what it used to, and I like that.&lt;/li&gt;&#xA;&lt;li&gt;Jessica&amp;rsquo;s talk on buffer overflows was enlightening and entertaining. It was&#xA;very similar to a talk that Max gave on one of the thursdays, but it was&#xA;exciting nevertheless.&lt;/li&gt;&#xA;&lt;li&gt;After the talk, I am inspired to try and work through the Hacking: Art of&#xA;exploitation, at some point. I&amp;rsquo;m beginning to feel like time at HackerSchool&#xA;running out!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-07-25</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-25/</link>
      <pubDate>Fri, 25 Jul 2014 09:25:50 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-25/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;We worked on writing our own (toy) version control system on Friday, as a&#xA;part of job prep.  I paired with Sophia, and we got upto the point where we&#xA;had diffs working, when we decided to refactor the code with some tests and&#xA;stuff.&lt;/li&gt;&#xA;&lt;li&gt;The party was brilliant with a lot of activity.  All the project&#xA;installations looked so cool, and it was so much fun!&lt;/li&gt;&#xA;&lt;li&gt;I spent some time during the weekend watching the &amp;ldquo;Anatomy of Matplotlib&amp;rdquo;&#xA;lectures.&lt;/li&gt;&#xA;&lt;li&gt;I started some work with poking around Matplotlib&amp;rsquo;s template backend, and&#xA;trying to start writing and ascii backend.&lt;/li&gt;&#xA;&lt;li&gt;Also, I was trying to help UC setup &lt;a href=&#34;https://github.com/andrewrk/groovebasin&#34;&gt;GrooveBasin&lt;/a&gt; on his raspberry pi, and&#xA;helped him configure &lt;a href=&#34;https://github.com/jasperproject/jasper-client&#34;&gt;jasper&lt;/a&gt; on it.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-07-24</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-24/</link>
      <pubDate>Thu, 24 Jul 2014 09:53:03 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-24/</guid>
      <description>&lt;h2 id=&#34;glowing-leds-and-me&#34;&gt;Glowing LEDs and me&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It turned out that the SPI driver exposed a faster way to write bits, writing&#xA;to all the LEDs at once, instead of one at a time, and this was sufficient to&#xA;get things working!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Kyle and I started to have enough, of the glowing LEDs and decided to wrap up&#xA;the project, but, Nick had different ideas for us! We had talked about having&#xA;the music stream via airplay, but Nick got his DJing tools, and it would be&#xA;too bad to not use it for the party, but doing that meant Airplay&amp;rsquo;s delay&#xA;wouldn&amp;rsquo;t help the DJ. So, we connected a line-in, and thought we&amp;rsquo;d be done if&#xA;we just read the input and used that data. But, it turns out that&amp;rsquo;s not so&#xA;simple because sending data over the wire, added noise to it, and in a whole&#xA;range of frequencies! I tried removing all the fourier coefficients which&#xA;were lower than a threshold, but I felt like it didn&amp;rsquo;t work very well, until&#xA;Nick reduced the gain of this output on the amp to the very minimum. Finally,&#xA;Kyle and I decided that this was good enough for the party!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I also hacked up a quick script to read a font file, and use the grey values&#xA;to get ascii characters to show up on the LED strip.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;miscellaneous&#34;&gt;Miscellaneous&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;While trying to find the RPi on the network, I learnt that &lt;code&gt;sudo nmap -sP 10.0.1.*&lt;/code&gt; gives us the hostname as well, instead of just IPs.  &lt;code&gt;sudo&lt;/code&gt; being&#xA;the key, here.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Kyle and I went and grabbed dinner in a restaurant in west village. It was&#xA;good to sit down and talk about various things, and eat. The glowing LEDs&#xA;were totally out of my mind for that period, and the break was good!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;There were a bunch of HSers doing mock-interviews and it was fun to watch, so&#xA;I stayed on until quite late, when all of us headed out together.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;today&#34;&gt;Today&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I&amp;rsquo;m excited about trying to build a small version control system from&#xA;scratch today!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Though I have had quite a bit of glowing LEDs in my face for the past week,&#xA;I may suck up to it, and figure out how to do scrolling text on the&#xA;display.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Also, excited to see how all the cool projects will come together in the&#xA;party tonight!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Recurse Center, 2014-07-23</title>
      <link>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-23/</link>
      <pubDate>Wed, 23 Jul 2014 10:51:51 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/recurse-center/recurse-center-2014-07-23/</guid>
      <description>&lt;h2 id=&#34;shairplay-and-ws2801&#34;&gt;Shairplay and WS2801&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Kyle mounted the LEDs onto a cardboard, and packaged it to look cool.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We thought we were done with the project, until we found out we weren&amp;rsquo;t!  The&#xA;LEDs all lighted up correctly, when we played the audio from a file on disk,&#xA;but streaming messed something up!  Only the first few columns lighted up,&#xA;when we were listening on the stream.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We spent the whole evening trying to debug the issue, and eliminated quite a&#xA;few hypothesis, but weren&amp;rsquo;t able to fix it, yet.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;miscellaneous&#34;&gt;Miscellaneous&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;rntz live coded a parser for us yesterday, and I learnt a few things about&#xA;parsers.  I&amp;rsquo;m glad I went to the discussion/talk.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I started working through the videos of Anatomy of Matplotlib, and hope to&#xA;get new insights into how it works.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;today&#34;&gt;Today&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Today will be spent mostly trying to get streaming audio working.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I feel like debugging this, will take my understanding of the&#xA;hardware-software interface to a new level.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
  </channel>
</rss>
