{"title":"The Sharat's","link":[{"@attributes":{"href":"https:\/\/sharats.me\/","rel":"alternate"}},{"@attributes":{"href":"https:\/\/sharats.me\/posts\/index.xml","rel":"self"}}],"id":"https:\/\/sharats.me\/","updated":"2025-06-06T00:00:00+05:30","entry":[{"title":"Use a proxy for LLM app development","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/use-proxy-for-llm-app-dev\/","rel":"alternate"}},"published":"2025-06-06T00:00:00+05:30","updated":"2025-06-06T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2025-06-06:\/posts\/use-proxy-for-llm-app-dev\/","summary":"<p>Most everybody is developing LLM applications these days. New frameworks and libraries show up nearly every week. A common theme is easy switching between LLM providers with minimal code changes.<\/p>\n<p>That sounds great, and it is.<\/p>\n<p>But, as with all abstractions that make it dead simple to start, they also \u2026<\/p>","content":"<p>Most everybody is developing LLM applications these days. New frameworks and libraries show up nearly every week. A common theme is easy switching between LLM providers with minimal code changes.<\/p>\n<p>That sounds great, and it is.<\/p>\n<p>But, as with all abstractions that make it dead simple to start, they also make debugging and maintenance that much harder.<\/p>\n<p>I&rsquo;m constantly asking myself: <em>Under all those library calls, what actual API request was made? What payload was sent? What did the server return? What were the headers?<\/em> Having access to this info makes debugging and discovery <strong>so much easier<\/strong>. Once you see it, there&rsquo;s no going back.<\/p>\n<p>Example video:<\/p>\n<video controls=\"\" muted=\"\" playsinline=\"\" preload=\"\" src=\"https:\/\/sharats.me\/static\/mitmproxy-llm-apis.mp4\">Your browser does not support HTML5 video. Here&rsquo;s <a href=\"https:\/\/sharats.me\/static\/mitmproxy-llm-apis.mp4\">a link to the video<\/a>instead.<\/video>\n<p>All code for this article is in <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\" rel=\"noopener noreferrer\" target=\"_blank\">this GitHub repo<\/a>. Follow along!<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#setup-a-local-proxy\">Setup a local proxy<\/a><\/li>\n<li><a href=\"#how-mitmproxy-works-quick-primer\">How mitmproxy works (quick primer)<\/a><ul>\n<li><a href=\"#what-about-https\">What about HTTPS?<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#install-and-run-mitmproxy-locally\">Install and run mitmproxy locally<\/a><\/li>\n<li><a href=\"#test-with-a-simple-http-request\">Test with a simple HTTP request<\/a><\/li>\n<li><a href=\"#trust-mitmproxys-ca-cert-for-https-support\">Trust mitmproxy&rsquo;s CA cert for HTTPS support<\/a><\/li>\n<li><a href=\"#use-mitmproxy-with-python-requests\">Use mitmproxy with Python requests<\/a><ul>\n<li><a href=\"#with-http\">With http:\/\/:<\/a><\/li>\n<li><a href=\"#with-https\">With https:\/\/:<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#monitor-openai-sdk-calls-via-mitmproxy\">Monitor OpenAI SDK calls via mitmproxy<\/a><\/li>\n<li><a href=\"#compare-different-api-styles\">Compare different API styles<\/a><\/li>\n<li><a href=\"#inspect-langchain-calls\">Inspect LangChain calls<\/a><\/li>\n<li><a href=\"#use-mitmproxy-scripting-to-highlight-llm-conversations\">Use mitmproxy scripting to highlight LLM conversations<\/a><\/li>\n<li><a href=\"#inspect-tool-calls-in-langchain\">Inspect tool calls in LangChain<\/a><\/li>\n<li><a href=\"#handle-dynamic-ca-certs-eg-eks-kubernetes-api\">Handle dynamic CA certs (e.g., EKS Kubernetes API)<\/a><\/li>\n<li><a href=\"#run-mitmproxy-in-a-dockerized-webapp\">Run mitmproxy in a Dockerized webapp<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"setup-a-local-proxy\">Setup a local proxy<a class=\"headerlink\" href=\"#setup-a-local-proxy\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The best way to observe LLM traffic during development is through a <strong>local forward proxy<\/strong>. I&rsquo;ve used mitmproxy, Proxyman, HTTP Toolkit, and Charles. Here we&rsquo;ll use mitmproxy, though I&rsquo;ve recently moved to Proxyman. Most setup steps are similar.<\/p>\n<h2 id=\"how-mitmproxy-works-quick-primer\">How mitmproxy works (quick primer)<a class=\"headerlink\" href=\"#how-mitmproxy-works-quick-primer\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Mitmproxy acts as a <strong>forward proxy<\/strong> between your local app and the real server.<\/p>\n<p>When your code makes a request to <code>example.com<\/code>, it instead sends it to mitmproxy, which then forwards it to the actual server and relays the response back. Like the name suggests, it&rsquo;s a <u>m<\/u>an <u>i<\/u>n <u>t<\/u>he <u>m<\/u>iddle. Or, as I like to call it, <u>m<\/u>achine <u>i<\/u>n <u>t<\/u>he <u>m<\/u>iddle.<\/p>\n<h3 id=\"what-about-https\">What about HTTPS?<a class=\"headerlink\" href=\"#what-about-https\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>That&rsquo;s where it gets tricky. HTTPS uses TLS certificates, and mitmproxy doesn&rsquo;t have the real cert for <code>example.com<\/code>. This causes a TLS handshake failure unless you trust mitmproxy&rsquo;s generated <strong>custom CA certificate<\/strong>.<\/p>\n<p>By trusting that CA, your app accepts mitmproxy&rsquo;s certificate for any domain it intercepts and so we don&rsquo;t see any browser warnings or connection errors about failed TLS handshakes.<\/p>\n<h2 id=\"install-and-run-mitmproxy-locally\">Install and run mitmproxy locally<a class=\"headerlink\" href=\"#install-and-run-mitmproxy-locally\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Clone the repo (or start from scratch if you prefer):<\/p>\n<div class=\"hl\"><pre class=content><code><span>git<span class=\"w\"> <\/span>clone<span class=\"w\"> <\/span>https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\n<\/span><span><span class=\"nb\">cd<\/span><span class=\"w\"> <\/span>mitmproxy-for-llm-apps\n<\/span><span>uv<span class=\"w\"> <\/span>sync\n<\/span><span>make<span class=\"w\"> <\/span>mitm\n<\/span><\/code><\/pre><\/div>\n\n<p>This runs mitmproxy on port 9020 and starts the web UI on port 9021. It may open in your browser. Open the <code>Makefile<\/code> to inspect what it does, don&rsquo;t just run scripts from random repos&hellip; like, who does that? (Looks out the window)<\/p>\n<h2 id=\"test-with-a-simple-http-request\">Test with a simple HTTP request<a class=\"headerlink\" href=\"#test-with-a-simple-http-request\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Try this to verify everything is working:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-x<span class=\"w\"> <\/span>http:\/\/localhost:9020<span class=\"w\"> <\/span>httpbun.com\/any\n<\/span><\/code><\/pre><\/div>\n\n<p>You should see this request show up in the mitmproxy UI, along with full request\/response headers and bodies.<\/p>\n<h2 id=\"trust-mitmproxys-ca-cert-for-https-support\">Trust mitmproxy&rsquo;s CA cert for HTTPS support<a class=\"headerlink\" href=\"#trust-mitmproxys-ca-cert-for-https-support\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Now try an HTTPS URL:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-x<span class=\"w\"> <\/span>https:\/\/localhost:9020<span class=\"w\"> <\/span>https:\/\/httpbun.com\/any\n<\/span><\/code><\/pre><\/div>\n\n<p>\ud83d\udca5 <strong>Expected<\/strong> TLS verification failure.<\/p>\n<p>Fix it by telling <code>curl<\/code> to use mitmproxy&rsquo;s CA cert (located at <code>~\/.mitmproxy\/mitmproxy-ca-cert.pem<\/code>):<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-x<span class=\"w\"> <\/span>https:\/\/localhost:9020<span class=\"w\"> <\/span>--cacert<span class=\"w\"> <\/span>~\/.mitmproxy\/mitmproxy-ca-cert.pem<span class=\"w\"> <\/span>https:\/\/httpbun.com\/any\n<\/span><\/code><\/pre><\/div>\n\n<p>Now HTTPS traffic works and shows up in mitmproxy.<\/p>\n<h2 id=\"use-mitmproxy-with-python-requests\">Use mitmproxy with Python requests<a class=\"headerlink\" href=\"#use-mitmproxy-with-python-requests\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here&rsquo;s how to set up Python code to route traffic through the proxy.<\/p>\n<h3 id=\"with-http\">With <code>http:\/\/<\/code>:<a class=\"headerlink\" href=\"#with-http\" title=\"Permanent link\">&para;<\/a><\/h3>\n<div class=\"hl\"><div class=filename><span>experiment.py<\/span><\/div><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">httpx<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">url<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"n\">httpx<\/span><span class=\"o\">.<\/span><span class=\"n\">Client<\/span><span class=\"p\">(<\/span><span class=\"n\">proxy<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;http:\/\/localhost:9020&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">url<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Run it:<\/p>\n<div class=\"hl\"><pre class=content><code><span>uv<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>python<span class=\"w\"> <\/span>experiment.py<span class=\"w\"> <\/span>http:\/\/httpbun.com\/any\n<\/span><\/code><\/pre><\/div>\n\n<p>This will show up normally in mitmproxy.<\/p>\n<h3 id=\"with-https\">With <code>https:\/\/<\/code>:<a class=\"headerlink\" href=\"#with-https\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>\ud83d\udca5 Will fail with a certificate verification error.<\/p>\n<p>Let&rsquo;s make Python trust mitmproxy&rsquo;s CA by injecting it into <code>certifi<\/code>&rsquo;s trusted certificates file, which <code>httpx<\/code> uses:<\/p>\n<div class=\"hl\"><div class=filename><span>experiment.py<\/span><\/div><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">pathlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Path<\/span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">certifi<\/span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">httpx<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Save the original certifi file<\/span>\n<\/span><span><span class=\"n\">certifi_orig_path<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Path<\/span><span class=\"p\">(<\/span><span class=\"n\">certifi<\/span><span class=\"o\">.<\/span><span class=\"n\">where<\/span><span class=\"p\">()<\/span> <span class=\"o\">+<\/span> <span class=\"s2\">&quot;.original&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">certifi_orig_path<\/span><span class=\"o\">.<\/span><span class=\"n\">exists<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"n\">certifi_orig_path<\/span><span class=\"o\">.<\/span><span class=\"n\">write_text<\/span><span class=\"p\">(<\/span><span class=\"n\">Path<\/span><span class=\"p\">(<\/span><span class=\"n\">certifi<\/span><span class=\"o\">.<\/span><span class=\"n\">where<\/span><span class=\"p\">())<\/span><span class=\"o\">.<\/span><span class=\"n\">read_text<\/span><span class=\"p\">())<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Add mitmproxy&#39;s CA cert to the certifi bundle<\/span>\n<\/span><span><span class=\"n\">Path<\/span><span class=\"p\">(<\/span><span class=\"n\">certifi<\/span><span class=\"o\">.<\/span><span class=\"n\">where<\/span><span class=\"p\">())<\/span><span class=\"o\">.<\/span><span class=\"n\">write_text<\/span><span class=\"p\">(<\/span>\n<\/span><span>    <span class=\"n\">certifi_orig_path<\/span><span class=\"o\">.<\/span><span class=\"n\">read_text<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"o\">+<\/span> <span class=\"s2\">&quot;<\/span><span class=\"se\">\\n\\n<\/span><span class=\"s2\"># mitmproxy-ca-cert.pem<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span>\n<\/span><span>    <span class=\"o\">+<\/span> <span class=\"p\">(<\/span><span class=\"n\">Path<\/span><span class=\"o\">.<\/span><span class=\"n\">home<\/span><span class=\"p\">()<\/span> <span class=\"o\">\/<\/span> <span class=\"s2\">&quot;.mitmproxy&quot;<\/span> <span class=\"o\">\/<\/span> <span class=\"s2\">&quot;mitmproxy-ca-cert.pem&quot;<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">read_text<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">url<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"n\">httpx<\/span><span class=\"o\">.<\/span><span class=\"n\">Client<\/span><span class=\"p\">(<\/span><span class=\"n\">proxy<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;http:\/\/localhost:9020&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">url<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now HTTPS requests work and appear in mitmproxy.<\/p>\n<h2 id=\"monitor-openai-sdk-calls-via-mitmproxy\">Monitor OpenAI SDK calls via mitmproxy<a class=\"headerlink\" href=\"#monitor-openai-sdk-calls-via-mitmproxy\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Let&rsquo;s now observe a real LLM call using the OpenAI SDK:<\/p>\n<div class=\"hl\"><div class=filename><span>experiment.py<\/span><\/div><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">openai<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">client<\/span> <span class=\"o\">=<\/span> <span class=\"n\">openai<\/span><span class=\"o\">.<\/span><span class=\"n\">OpenAI<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"o\">.<\/span><span class=\"n\">chat<\/span><span class=\"o\">.<\/span><span class=\"n\">completions<\/span><span class=\"o\">.<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span>\n<\/span><span>    <span class=\"n\">model<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;gpt-4o-mini&quot;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">messages<\/span><span class=\"o\">=<\/span><span class=\"p\">[{<\/span><span class=\"s2\">&quot;role&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;user&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;content&quot;<\/span><span class=\"p\">:<\/span> <span class=\"s2\">&quot;I&#39;m a little teapot!&quot;<\/span><span class=\"p\">}],<\/span>\n<\/span><span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">choices<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span><span class=\"o\">.<\/span><span class=\"n\">message<\/span><span class=\"o\">.<\/span><span class=\"n\">content<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We&rsquo;re using OpenAI&rsquo;s SDK, which, under all the abstractions, uses <code>httpx<\/code> to make the HTTP requests. But that means we don&rsquo;t have control on the creation of the <code>httpx.Client<\/code> object, so we can&rsquo;t inject the proxy there. Thankfully, <a href=\"https:\/\/www.python-httpx.org\/environment_variables\/#proxies\" rel=\"noopener noreferrer\" target=\"_blank\"><code>httpx<\/code> respects the &ldquo;standard&rdquo; proxy environment variables<\/a>. So we run the script like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">HTTPS_PROXY<\/span><span class=\"o\">=<\/span>http:\/\/127.0.0.1:9020<span class=\"w\"> <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span>sk-proj-...<span class=\"w\"> <\/span>uv<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>python<span class=\"w\"> <\/span>experiment.py\n<\/span><\/code><\/pre><\/div>\n\n<p>You&rsquo;ll now see the full OpenAI API request and response payloads in mitmproxy.<\/p>\n<h2 id=\"compare-different-api-styles\">Compare different API styles<a class=\"headerlink\" href=\"#compare-different-api-styles\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Try switching from completions to the new responses API:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">client<\/span><span class=\"o\">.<\/span><span class=\"n\">responses<\/span><span class=\"o\">.<\/span><span class=\"n\">create<\/span><span class=\"p\">(<\/span>\n<\/span><span>    <span class=\"n\">model<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;gpt-4o-mini&quot;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"nb\">input<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;I&#39;m a little teapot!&quot;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">output_text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Run this and you should see how different the JSON body is structured between the two APIs. If you enable streaming in those API calls, you&rsquo;ll see the individual SSE events in the Response tab in mitmproxy.<\/p>\n<h2 id=\"inspect-langchain-calls\">Inspect LangChain calls<a class=\"headerlink\" href=\"#inspect-langchain-calls\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>LangChain uses OpenAI under the hood:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">langchain_openai<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ChatOpenAI<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">llm<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ChatOpenAI<\/span><span class=\"p\">(<\/span><span class=\"n\">model<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;gpt-4o-mini&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">api_key<\/span><span class=\"o\">=<\/span><span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">getenv<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;OPENAI_API_KEY&quot;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">llm<\/span><span class=\"o\">.<\/span><span class=\"n\">invoke<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Hello there matey!&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">content<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>All calls show up in mitmproxy showing the exact API calls under all the LangChain abstractions. This is great for understanding how higher-level tools serialize prompts and responses.<\/p>\n<h2 id=\"use-mitmproxy-scripting-to-highlight-llm-conversations\">Use mitmproxy scripting to highlight LLM conversations<a class=\"headerlink\" href=\"#use-mitmproxy-scripting-to-highlight-llm-conversations\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Mitmproxy supports scripting addons.<\/p>\n<p>Here&rsquo;s a <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/main\/llm_commenter.py\" rel=\"noopener noreferrer\" target=\"_blank\">script<\/a> that extracts the current LLM &ldquo;conversation&rdquo; and shows it in the <em>Comment<\/em> tab for OpenAI completions calls.<\/p>\n<p>Start mitmproxy like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>mitmweb<span class=\"w\"> <\/span>--scripts<span class=\"w\"> <\/span>llm_commenter.py\n<\/span><\/code><\/pre><\/div>\n\n<p>Note: it&rsquo;s experimental, and the Comment tab support is new, but still better than manually parsing JSON.<\/p>\n<h2 id=\"inspect-tool-calls-in-langchain\">Inspect tool calls in LangChain<a class=\"headerlink\" href=\"#inspect-tool-calls-in-langchain\" title=\"Permanent link\">&para;<\/a><\/h2>\n<blockquote>\n<p>Code from prompt:\nWrite a minimal python script to call LangChain with OpenAI, with a single tool to add two numbers, and prompt OpenAI to add 20 to the answer to life, universe, and everything else.<\/p>\n<\/blockquote>\n<p>We have the resulting code <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/a8721301e2431062979bcbfcc3565c536697c3ef\/main.py#L59\" rel=\"noopener noreferrer\" target=\"_blank\">here<\/a>. Run it with the proxy enabled and you&rsquo;ll see two OpenAI calls:<\/p>\n<ul>\n<li>First: receives the tool call<\/li>\n<li>Second: sends tool execution result and gets final response<\/li>\n<\/ul>\n<p>Seeing this logic play out makes complex LangChain chains far easier to understand.<\/p>\n<h2 id=\"handle-dynamic-ca-certs-eg-eks-kubernetes-api\">Handle dynamic CA certs (e.g., EKS Kubernetes API)<a class=\"headerlink\" href=\"#handle-dynamic-ca-certs-eg-eks-kubernetes-api\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Some services (like EKS) use their own custom CA certs.<\/p>\n<p>Example: <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/a8721301e2431062979bcbfcc3565c536697c3ef\/main.py#L110\" rel=\"noopener noreferrer\" target=\"_blank\">this function<\/a> connects to Kubernetes and requires trusting the EKS CA.<\/p>\n<p>You&rsquo;ll need to:<\/p>\n<ol>\n<li>Add the CA to your app&rsquo;s <code>certifi<\/code> trust store<\/li>\n<li>Also add it to <strong>mitmproxy&rsquo;s<\/strong> trust store (if in a separate venv)<\/li>\n<li>Clear mitmproxy&rsquo;s SSL cache<\/li>\n<\/ol>\n<p>To clear the cache, use <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/main\/mitmproxy_ssl_clear.py\" rel=\"noopener noreferrer\" target=\"_blank\"><code>ssl.clear<\/code><\/a>, a custom mitmproxy addon.<\/p>\n<p>Now mitmproxy shows all AWS and Kubernetes traffic. This is now ready to be wired as a tool for LLMs.<\/p>\n<h2 id=\"run-mitmproxy-in-a-dockerized-webapp\">Run mitmproxy in a Dockerized webapp<a class=\"headerlink\" href=\"#run-mitmproxy-in-a-dockerized-webapp\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We created a small Flask webapp (<code>server.py<\/code>) that prompts for user input and calls an LLM:<\/p>\n<div class=\"hl\"><pre class=content><code><span>make<span class=\"w\"> <\/span>serve\n<\/span><\/code><\/pre><\/div>\n\n<p>View it at <a href=\"http:\/\/localhost:9022\" rel=\"noopener noreferrer\" target=\"_blank\">localhost:9022<\/a>. LLM traffic will appear in mitmproxy at <a href=\"http:\/\/localhost:9021\" rel=\"noopener noreferrer\" target=\"_blank\">localhost:9021<\/a>.<\/p>\n<p>Check out the <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/main\/Dockerfile\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Dockerfile<\/code><\/a> and <a href=\"https:\/\/github.com\/sharat87\/mitmproxy-for-llm-apps\/blob\/main\/entrypoint.sh\" rel=\"noopener noreferrer\" target=\"_blank\"><code>entrypoint.sh<\/code><\/a> for how mitmproxy is booted inside the container.<\/p>\n<p>Build and run:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>build<span class=\"w\"> <\/span>-t<span class=\"w\"> <\/span>mapp<span class=\"w\"> <\/span>.<span class=\"w\"> <\/span><span class=\"o\">&amp;&amp;<\/span><span class=\"w\"> <\/span><span class=\"o\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span>docker<span class=\"w\"> <\/span>rm<span class=\"w\"> <\/span>-f<span class=\"w\"> <\/span>mapp\n<\/span><span><span class=\"w\">    <\/span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>--name<span class=\"w\"> <\/span>mapp<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span>-p<span class=\"w\"> <\/span><span class=\"m\">5021<\/span>:9021<span class=\"w\"> <\/span>-p<span class=\"w\"> <\/span><span class=\"m\">5022<\/span>:9022<span class=\"w\"> <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">MITM_PASSWORD<\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">OPENAI_API_KEY<\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span>mapp\n<\/span><span><span class=\"o\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<blockquote>\n<p>\u26a0\ufe0f <strong>Warning:<\/strong> Definitely don&rsquo;t run this in production. Like, please <em>please<\/em> don&rsquo;t.<\/p>\n<\/blockquote>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Abstractions aren&rsquo;t magic, they&rsquo;re just a facade. Looking behind the curtain can give powerful understanding of the various LLM APIs and frameworks.<\/p>\n<p><em>Every<\/em> LLM app developer should have a local dev proxy in their toolkit.<\/p>","category":{"@attributes":{"term":"posts"}}},{"title":"A Tale of Two Forwarded Headers","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/tale-of-two-forwarded-headers\/","rel":"alternate"}},"published":"2023-08-20T00:00:00+05:30","updated":"2023-08-20T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2023-08-20:\/posts\/tale-of-two-forwarded-headers\/","summary":"<p>This is the story of how I handled troubleshooting the redirect URL for OAuth2 in Appsmith, which contained the host as <code>localhost<\/code> instead of the actual domain name when hosted on Google Cloud Run. This is a story of how <code>Forwarded<\/code> and <code>X-Forwarded-*<\/code> headers were propagating through multiple reverse proxies \u2026<\/p>","content":"<p>This is the story of how I handled troubleshooting the redirect URL for OAuth2 in Appsmith, which contained the host as <code>localhost<\/code> instead of the actual domain name when hosted on Google Cloud Run. This is a story of how <code>Forwarded<\/code> and <code>X-Forwarded-*<\/code> headers were propagating through multiple reverse proxies and how they can be confused.<\/p>\n<h2 id=\"the-problem\">The Problem<a class=\"headerlink\" href=\"#the-problem\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Appsmith is an internal tool builder that has a React-based frontend and a Java+Spring based backend server. This backend uses the <code>spring-security<\/code> module&rsquo;s support for OAuth2 authentication, which enables logging in to Appsmith with Google.<\/p>\n<p>Google Cloud Run is <\/p>\n<blockquote>\n<p>[&hellip;] a managed compute platform that lets you run containers directly on top of Google&rsquo;s scalable infrastructure.<\/p>\n<\/blockquote>\n<p>In other words, Google Cloud Run is a <em>serverless<\/em> abstraction, to run Docker containers.<\/p>\n<p>When running Appsmith on Google Cloud Run and enabling Login with Google, the redirect URL used as part of the OAuth2 flow includes the host as <code>localhost<\/code> instead of the actual domain name. This causes the OAuth2 flow to fail due to a mismatch in the redirect URL.<\/p>\n<h2 id=\"primary-behaviour\">Primary Behaviour<a class=\"headerlink\" href=\"#primary-behaviour\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Let&rsquo;s start an Appsmith container, with Google OAuth configured, and see what redirect URL gets generated in a controlled environment.<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>--name<span class=\"w\"> <\/span>appsmith<span class=\"w\"> <\/span>-p<span class=\"w\"> <\/span><span class=\"m\">8001<\/span>:80<span class=\"w\"> <\/span>-v<span class=\"w\"> <\/span>stacks:\/appsmith-stacks<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">  <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">APPSMITH_OAUTH2_GOOGLE_CLIENT_ID<\/span><span class=\"o\">=<\/span>dummy<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">  <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET<\/span><span class=\"o\">=<\/span>dummy<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">  <\/span>appsmith\/appsmith-ce:v1.9.29\n<\/span><\/code><\/pre><\/div>\n\n<p>We configure Google OAuth with dummy values here, since we only care about the generated redirect URL and not the complete OAuth flow.<\/p>\n<p>Let&rsquo;s wait a little while for that to start and show up working on <code>http:\/\/localhost:8001<\/code>. Then, let&rsquo;s initiate the OAuth2 flow and see the redirect URL.<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-sSi<span class=\"w\"> <\/span>http:\/\/localhost:8001\/oauth2\/authorization\/google\n<\/span><\/code><\/pre><\/div>\n\n<p>This will print <em>all<\/em> the response headers. Let&rsquo;s just pick the <code>redirect_uri<\/code> query parameter in the <code>Location<\/code> header (which contains the Google authorization endpoint as part of the OAuth2 flow).<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-sSi<span class=\"w\"> <\/span>http:\/\/localhost:8001\/oauth2\/authorization\/google<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>grep<span class=\"w\"> <\/span>-Eo<span class=\"w\"> <\/span><span class=\"s1\">&#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We get the result as this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>redirect_uri=http:\/\/localhost\/login\/oauth2\/code\/google\n<\/span><\/code><\/pre><\/div>\n\n<p>Which is not entirely accurate because it&rsquo;s missing the <code>:8001<\/code> part, but that&rsquo;s a problem for another day. For now, let&rsquo;s just focus on the <code>localhost<\/code> part. This is the correct host here. But if we make this request with a different host:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>-sSi<span class=\"w\"> <\/span>http:\/\/localhost:8001\/oauth2\/authorization\/google<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">  <\/span>-H<span class=\"w\"> <\/span><span class=\"s1\">&#39;Host: one.com&#39;<\/span><span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>grep<span class=\"w\"> <\/span>-Eo<span class=\"w\"> <\/span><span class=\"s1\">&#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, in the <code>redirect_uri<\/code> query parameter, we see the URL that we expect to see, with <code>one.com<\/code> as the host.<\/p>\n<div class=\"hl\"><pre class=content><code><span>redirect_uri=http:\/\/one.com\/login\/oauth2\/code\/google\n<\/span><\/code><\/pre><\/div>\n\n<p>Similarly, if we try with <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/X-Forwarded-Host\" rel=\"noopener noreferrer\" target=\"_blank\"><code>X-Forwarded-Host<\/code><\/a> header, or the more standard <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Forwarded\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Forwarded<\/code><\/a> header, we always see the correct host in the <code>redirect_uri<\/code> query parameter.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; curl -sSi http:\/\/localhost:8001\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;X-Forwarded-Host: two.com&#39; | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=http:\/\/two.com\/login\/oauth2\/code\/google<\/span>\n<\/span><span>\n<\/span><span><span class=\"go\">&gt; curl -sSi http:\/\/localhost:8001\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;Forwarded: host=three.com&#39; | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=http:\/\/three.com\/login\/oauth2\/code\/google<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The Appsmith backend server seems to be handling the host detection quite well, but when it&rsquo;s run on Google Cloud Run, the host is always <code>localhost<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; curl -sSi https:\/\/appsmith-abcdefghij-uc.a.run.app\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;Host: four.com&#39; | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=http:\/\/localhost\/login\/oauth2\/code\/google<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"cloud-run-the-reverse-proxy\">Cloud Run, the Reverse Proxy<a class=\"headerlink\" href=\"#cloud-run-the-reverse-proxy\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We&rsquo;ve established that if the host is shared correctly with Appsmith, it produces the correct <code>redirect_uri<\/code>. So something about the way Google Cloud Run is forwarding the host is not working as expected. We want to find out just what Cloud Run is sending across.<\/p>\n<p>To get this information, let&rsquo;s run an instance of <a href=\"https:\/\/httpbun.com\" rel=\"noopener noreferrer\" target=\"_blank\"><code>httpbun<\/code><\/a> on Cloud Run, which can respond with all the headers it receives.<\/p>\n<p>Here&rsquo;s a sample configuration of how we can run httpbun on Cloud Run.<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/cloudrun-httpbun.png\"><img alt=\"httpbun on Cloud Run\" src=\"https:\/\/sharats.me\/static\/cloudrun-httpbun.png\"><\/a><\/p>\n<p>Once this is deployed, we get a URL like <code>https:\/\/httpbun-abcdefghij-uc.a.run.app<\/code>. Let&rsquo;s make a request to this and see what headers it reports as being part of the request.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; curl -sSi https:\/\/httpbun-abcdefghij-uc.a.run.app\/headers<\/span>\n<\/span><span><span class=\"go\">{<\/span>\n<\/span><span><span class=\"go\">  &quot;Accept&quot;: &quot;*\/*&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;Forwarded&quot;: &quot;for=\\&quot;1.2.3.4\\&quot;;proto=https&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;Host&quot;: &quot;httpbun-abcdefghij-uc.a.run.app&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;Traceparent&quot;: &quot;00-abcdefghijklmnopqrstuvwxyzabcdef-ghijklmnopqrstuv-01&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;User-Agent&quot;: &quot;curl\/7.88.1&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;X-Cloud-Trace-Context&quot;: &quot;abcdefghijklmnopqrstuvwxyzabcdef\/ghijklmnopqrstuvwxy;o=1&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;X-Forwarded-For&quot;: &quot;1.2.3.4&quot;,<\/span>\n<\/span><span><span class=\"go\">  &quot;X-Forwarded-Proto&quot;: &quot;https&quot;<\/span>\n<\/span><span><span class=\"go\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Fantastic! We see that Cloud Run sends the actual host in the <code>Host<\/code> header, instead of <code>X-Forwarded-Host<\/code>, despite sending in <code>X-Forwarded-For<\/code> and <code>X-Forwarded-Proto<\/code>. This is only slightly odd, but not groundbreaking. As we&rsquo;ve seen earlier, Appsmith handles this just fine.<\/p>\n<p>But in addition to that, notice that we have a <code>Forwarded<\/code> header too. This contains the same information as <code>X-Fowarded-For<\/code> and <code>X-Forwarded-Proto<\/code>, and doesn&rsquo;t contain a <code>host<\/code> field.<\/p>\n<blockquote>\n<p>Detour: The <code>Forwarded<\/code> header is a more standard header that holds the same (and some more) information as the <code>X-Forwarded-*<\/code> suite of headers, which is are a little less standard-ly defined. What&rsquo;s peculiar here is that Cloud Run appears to be sending <em>both<\/em> <code>Forwarded<\/code> and <code>X-Forwarded-*<\/code> headers.<\/p>\n<\/blockquote>\n<p>We didn&rsquo;t test this case with our local Appsmith. That is, we didn&rsquo;t send the actual host in the <code>Host<\/code> header, but also include a <code>Forwarded<\/code> header with information about the origin protocol (and IP Address). Let&rsquo;s do that now.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; curl -sSi http:\/\/localhost:8001\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;Host: abc.com&#39; -H &#39;Forwarded: for&quot;1.2.3.4&quot;;proto=https&#39; | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=https:\/\/localhost\/login\/oauth2\/code\/google<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Boom! There it is. Although we&rsquo;re sending the host in <code>Host<\/code> header, Appsmith responds with <code>localhost<\/code> in the host part of the <code>redirect_uri<\/code>. This is the same behavior we see on Cloud Run.<\/p>\n<h2 id=\"the-reverse-proxy-inside-appsmith-container\">The Reverse Proxy Inside Appsmith Container<a class=\"headerlink\" href=\"#the-reverse-proxy-inside-appsmith-container\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Inside the Appsmith container, we have an NGINX process that handles all incoming requests. If the request points to a static file, it is served immediately. If it points to a backend API call, NGINX will proxy the request over to the Appsmith backend server. This NGINX configuration file is generated by <a href=\"https:\/\/github.com\/appsmithorg\/appsmith\/blob\/v1.9.29\/deploy\/docker\/templates\/nginx\/nginx-app-http.conf.template.sh\" rel=\"noopener noreferrer\" target=\"_blank\">this script<\/a>, and you can peek into the actual configuration used by running <code>docker exec appsmith cat \/etc\/nginx\/sites-enabled\/default<\/code>. For the URL we&rsquo;ve been <code>curl<\/code>-ing so far, the route that matches is this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"k\">location<\/span><span class=\"w\"> <\/span><span class=\"s\">\/oauth2<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kn\">proxy_pass<\/span><span class=\"w\"> <\/span><span class=\"s\">http:\/\/localhost:8080<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Since this <code>location<\/code> block doesn&rsquo;t have <em>any<\/em> <code>proxy_set_header<\/code> directives, the ones in the parent context will apply. We can see these as:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"k\">proxy_set_header<\/span><span class=\"w\"> <\/span><span class=\"s\">X-Forwarded-Proto<\/span><span class=\"w\"> <\/span><span class=\"nv\">$origin_scheme<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"k\">proxy_set_header<\/span><span class=\"w\"> <\/span><span class=\"s\">X-Forwarded-Host<\/span><span class=\"w\">  <\/span><span class=\"nv\">$origin_host<\/span><span class=\"p\">;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>$origin_scheme<\/code> and <code>$origin_host<\/code> are defined at the top of the configuration file, like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">map<\/span><span class=\"w\"> <\/span><span class=\"nv\">$http_x_forwarded_proto<\/span><span class=\"w\"> <\/span><span class=\"nv\">$origin_scheme<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">default<\/span><span class=\"w\"> <\/span><span class=\"nv\">$http_x_forwarded_proto<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">&#39;&#39;<\/span><span class=\"w\"> <\/span><span class=\"nv\">$scheme<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">map<\/span><span class=\"w\"> <\/span><span class=\"nv\">$http_x_forwarded_host<\/span><span class=\"w\"> <\/span><span class=\"nv\">$origin_host<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">default<\/span><span class=\"w\"> <\/span><span class=\"nv\">$http_x_forwarded_host<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">&#39;&#39;<\/span><span class=\"w\"> <\/span><span class=\"nv\">$host<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>What this is essentially doing is setting up so that if the incoming request has an <code>X-Forwarded-Proto<\/code> header, the <code>$origin_scheme<\/code> is set to that header&rsquo;s value. If that header is <em>not<\/em> present in the request, <code>$origin_scheme<\/code> is set to <code>$scheme<\/code>. This is an NGINX variable set to the current request&rsquo;s protocol. Similarly, <code>$origin_host<\/code> either takes the value of <code>X-Forwarded-Host<\/code> header if present, or the current request&rsquo;s host (which is <em>usually<\/em> the <code>Host<\/code> header of the request).<\/p>\n<p>This means that once the request goes from this NGINX to Appsmith backend server, <code>Host<\/code> becomes <code>localhost:8080<\/code>, <code>X-Forwarded-Host<\/code> is set to <code>appsmith-abcdefghij-uc.a.run.app<\/code>, and the others, <code>X-Forwarded-Proto<\/code>, <code>X-Forwarded-For<\/code> and even the <code>Forwarded<\/code> header, are passed along as is.<\/p>\n<p>This is the problem.<\/p>\n<p>Since the <code>Forwarded<\/code> header is the more modern standard, it&rsquo;s value usually takes precedence. The fact that the request has a <code>Forwarded<\/code> header, unfortunately means that all the other <code>X-Forwarded-*<\/code> headers will be ignored by the Appsmith server.<\/p>\n<p>This means the <code>X-Forwarded-Host<\/code> header is completely ignored, and the server instead looks for a <code>host=<\/code> field in the <code>Forwarded<\/code> header, which is missing, so it thinks the host it receives in the <code>Host<\/code> header, <code>localhost:8080<\/code>, is the actual host, and uses that to construct the <code>redirect_uri<\/code>.<\/p>\n<p>We can simulate this theory by sending a request to the Appsmith backend server directly instead of going through the NGINX proxy. We can do this by using the <code>docker exec<\/code> command, like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; docker exec appsmith curl -sSi localhost:8080\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;Forwarded: for=&quot;1.2.3.4&quot;;proto=https&#39; \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;X-Forwarded-Host: abc.com&#39; \\<\/span>\n<\/span><span><span class=\"go\">  | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=https:\/\/localhost\/login\/oauth2\/code\/google<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This produces <code>localhost<\/code> in the <code>redirect_uri<\/code>, just like we saw earlier, instead of <code>abc.com<\/code>. If we remove the <code>Forwarded<\/code> header, or add <code>host=<\/code> field in it, it works just fine.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"go\">&gt; docker exec appsmith curl -sSi localhost:8080\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;X-Forwarded-Host: abc.com&#39; \\<\/span>\n<\/span><span><span class=\"go\">  | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=https:\/\/abc.com\/login\/oauth2\/code\/google<\/span>\n<\/span><span>\n<\/span><span><span class=\"go\">&gt; docker exec appsmith curl -sSi localhost:8080\/oauth2\/authorization\/google \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;Forwarded: for=&quot;1.2.3.4&quot;;proto=https, host=abc.com&#39; \\<\/span>\n<\/span><span><span class=\"go\">  -H &#39;X-Forwarded-Host: abc.com&#39; \\<\/span>\n<\/span><span><span class=\"go\">  | grep -Eo &#39;redirect_uri=[^&amp;]+&#39;<\/span>\n<\/span><span><span class=\"go\">redirect_uri=https:\/\/abc.com\/login\/oauth2\/code\/google<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"the-solution\">The Solution<a class=\"headerlink\" href=\"#the-solution\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In the NGINX, we add\/set the <code>X-Forwarded-Host<\/code> header, at all times, which is the right thing to do. But if the incoming request has a <code>Forwarded<\/code> header, it takes precedence and the <code>X-Forwarded-Host<\/code> header is ignored. This is the problem.<\/p>\n<p>So we get NGINX to <em>also<\/em> add the <code>host=<\/code> field, if a <code>Forwarded<\/code> header exists. We do this in <a href=\"https:\/\/github.com\/appsmithorg\/appsmith\/pull\/25827\/files\" rel=\"noopener noreferrer\" target=\"_blank\">this PR<\/a>.<\/p>\n<p>Essentially, define a <code>$final_forwarded<\/code>, like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">map<\/span><span class=\"w\"> <\/span><span class=\"nv\">$http_forwarded<\/span><span class=\"w\"> <\/span><span class=\"nv\">$final_forwarded<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">default<\/span><span class=\"w\"> <\/span><span class=\"s\">&#39;<\/span><span class=\"nv\">$http_forwarded,<\/span><span class=\"w\"> <\/span><span class=\"s\">host=<\/span><span class=\"nv\">$host<\/span><span class=\"p\">;<\/span><span class=\"kn\">proto=$scheme&#39;<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"kn\">&#39;&#39;<\/span><span class=\"w\"> <\/span><span class=\"s\">&#39;&#39;<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In the <code>http<\/code> block, we set the <code>Forwarded<\/code> header as follows:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"k\">proxy_set_header<\/span><span class=\"w\"> <\/span><span class=\"s\">Forwarded<\/span><span class=\"w\"> <\/span><span class=\"nv\">$final_forwarded<\/span><span class=\"p\">;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This way, if there&rsquo;s no incoming <code>Forwarded<\/code> header, we don&rsquo;t send it to the backend server either. But if it exists, we add the <code>host=<\/code> field (and a <code>proto=<\/code> field for good measure) to it, and send it to the backend server.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The confusion between <code>Forwarded<\/code> and <code>X-Forwarded-*<\/code> suite of headers, and which takes precedence when <em>both<\/em> are set, turned out to be the underlying problem. The NGINX we use inside Appsmith, was only ever tuned to work with <code>X-Forwarded-*<\/code> suite of headers. Additionally, since Google Cloud Run is so opaque, in the sense that we can&rsquo;t even get shell access into the running container, using tools like Httpbun can be very helpful in figuring out what details the request actually contains.<\/p>","category":{"@attributes":{"term":"posts"}}},{"title":"Running Docker containers in network isolation with proxied traffic","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/docker-with-proxy\/","rel":"alternate"}},"published":"2023-04-16T00:00:00+05:30","updated":"2023-04-16T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2023-04-16:\/posts\/docker-with-proxy\/","summary":"<p>Several network configurations, especially in large companies and universities, have a proxy configured for all outgoing traffic. Any network traffic that tries to go out <em>bypassing<\/em> this proxy, will be blocked. For a self-hosted web application, the server will also need to make any and all outgoing connections via this \u2026<\/p>","content":"<p>Several network configurations, especially in large companies and universities, have a proxy configured for all outgoing traffic. Any network traffic that tries to go out <em>bypassing<\/em> this proxy, will be blocked. For a self-hosted web application, the server will also need to make any and all outgoing connections via this proxy.<\/p>\n<p>Now, several applications, web application servers included, support the <code>HTTP_PROXY<\/code> and <code>HTTPS_PROXY<\/code> environment variables to configure such a proxy. But if we don&rsquo;t have a network that blocks non-proxy traffic, how do you do we test this? How can we ensure, that when a proxy is configured, all outgoing requests are only ever made through the proxy?<\/p>\n<p>This article is my attempt at answering this.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#docker-networks\">Docker Networks<\/a><\/li>\n<li><a href=\"#sandbox\">Sandbox<\/a><\/li>\n<li><a href=\"#proxying-https-requests\">Proxying HTTPS Requests<\/a><\/li>\n<li><a href=\"#dns-resolution\">DNS Resolution<\/a><\/li>\n<li><a href=\"#connecting-from-host\">Connecting from Host<\/a><\/li>\n<li><a href=\"#testing-appsmith\">Testing Appsmith<\/a><\/li>\n<li><a href=\"#further-explorations\">Further Explorations<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"docker-networks\">Docker Networks<a class=\"headerlink\" href=\"#docker-networks\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We&rsquo;ll be using Docker&rsquo;s networking features. It provides a simple set of primitives to solve what we need here.<\/p>\n<p>By default, Docker sets up a bridge network for us that allows connectivity to external endpoints. With explicit configuration, we can also have an <em>internal<\/em> network, where connections are only allowed to other containers that are also connected to this internal network.<\/p>\n<p>The Docker&rsquo;s official documentation about <a href=\"https:\/\/docs.docker.com\/compose\/networking\/\" rel=\"noopener noreferrer\" target=\"_blank\">Networking in Docker Compose<\/a> talks more in detail about this.<\/p>\n<h2 id=\"sandbox\">Sandbox<a class=\"headerlink\" href=\"#sandbox\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We need a sandbox environment where there&rsquo;s a proxy and a subject application. We want to ensure that outgoing requests made from the subject application always fail unless they go via the proxy.<\/p>\n<p>Let&rsquo;s start with two containers, in a <code>docker-compose.yml<\/code> configuration.<\/p>\n<ul>\n<li>The <code>subject<\/code> container, which is expected to make all outgoing requests via the proxy only.<\/li>\n<li>The <code>proxy<\/code> container, which runs an HTTP proxy.<\/li>\n<\/ul>\n<p>For the <code>subject<\/code> container, we&rsquo;ll use an ordinary, friendly, memorable, vanilla Ubuntu container, with the command set to <code>sleep infinity<\/code>. This makes the container stay running so that we can get in and play around. Without this, the container would start, do nothing, and just exit. Not very useful.<\/p>\n<p>For the <code>proxy<\/code> container, we&rsquo;ll use <code>mitmproxy<\/code>. Rpecifically, the web interface version called <code>mitmweb<\/code>. This is an excellent proxy application, best used for intercepting requests during development. If you haven&rsquo;t been spoilt by it, I encourage you to check it out.<\/p>\n<p>So, this is our initial version of the sandbox:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nt\">version<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;3&quot;<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nt\">services<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">subject<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">ubuntu<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">sleep infinity<\/span>\n<\/span><span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">proxy<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmweb --web-host 0.0.0.0<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8081:8081&quot;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Save this as a <code>docker-compose.yml<\/code> and do a <code>docker-compose up -d<\/code>. Once the two containers are running, open <a href=\"http:\/\/localhost:8081\" rel=\"noopener noreferrer\" target=\"_blank\">localhost:8081<\/a>. This is where we&rsquo;ll see all the HTTP requests flowing through our proxy.<\/p>\n<p>Let&rsquo;s get inside the <code>subject<\/code> container and make some requests. Start a shell with <code>docker-compose exec subject bash<\/code>. This will start a shell session running <em>inside<\/em> the <code>subject<\/code> container. Use the following command to install <code>curl<\/code> to play with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>apt<span class=\"w\"> <\/span>update\n<\/span><span>apt<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>--yes<span class=\"w\"> <\/span>curl\n<\/span><span>curl<span class=\"w\"> <\/span>httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This will make an external request, and print the response in the Terminal, but this request won&rsquo;t show up in <code>mitmproxy<\/code>&rsquo;s UI. For that, let&rsquo;s do:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This will show the response in the Terminal, as well as in <code>mitmproxy<\/code>&rsquo;s UI.<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/mitmproxy-sample.png\"><img alt=\"Sample request on mitmproxy's UI\" src=\"https:\/\/sharats.me\/static\/mitmproxy-sample.png\"><\/a><\/p>\n<p>Let&rsquo;s step this up. We&rsquo;ll now block direct Internet access to the <code>subject<\/code> container and only allow connecting via the proxy. Consider the following <code>docker-compose.yml<\/code> file:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nt\">version<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;3&quot;<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nt\">services<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">subject<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">ubuntu<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">sleep infinity<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/span><span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">proxy<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmweb --web-host 0.0.0.0<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8081:8081&quot;<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/span><span>\n<\/span><span>\n<\/span><span><span class=\"hll\"><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">  <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">internal<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">true<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">  <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/span><\/code><\/pre><\/div>\n\n<p>This is the same as the previous one, except for <code>networks<\/code> configurations. We define two networks, an internal network named <code>intnet<\/code> and an external network named <code>extnet<\/code>. The <code>subject<\/code> container is only connected to <code>intnet<\/code>, so it can only connect to other containers that are also connected to <code>intnet<\/code>. The <code>proxy<\/code> container is connected to both <code>intnet<\/code> and <code>extnet<\/code>, so it can both access other containers in the <code>intnet<\/code> as well as access the wider Internet.<\/p>\n<p>With this setup, we expect direct network connections from <code>subject<\/code> to the Internet to fail, unless they go via the <code>proxy<\/code> container.<\/p>\n<p>Let&rsquo;s do a <code>docker-compose up -d<\/code> with this file, open a shell with <code>docker-compose exec subject bash<\/code>, and try to install <code>curl<\/code> again. But notice that when we run <code>apt update<\/code>, it doesn&rsquo;t work, since this too requires the Internet and we&rsquo;ve blocked it. We&rsquo;ll use this as proof that blocking Internet is working!<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/mitmproxy-apt-requests.png\"><img alt=\"Requests from apt in mitmproxy UI\" src=\"https:\/\/sharats.me\/static\/mitmproxy-apt-requests.png\"><\/a><\/p>\n<p>Instead of <code>apt update<\/code>, issue the command <code>http_proxy=http:\/\/proxy:8080 apt update<\/code>. This should make all requests via that proxy, and should even show up in <code>mitmproxy<\/code>&rsquo;s UI. Make sure you refresh the page, since the <code>mitmproxy<\/code> container has been recreated. Effectively, we do:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker-compose<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>subject<span class=\"w\"> <\/span>bash\n<\/span><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>apt<span class=\"w\"> <\/span>update\n<\/span><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>apt<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>--yes<span class=\"w\"> <\/span>curl\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice that these commands will show a bunch of requests in <code>mitmproxy<\/code>&rsquo;s UI made to the Ubuntu package archives. Now, we can try out our test with <code>curl<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This will eventually timeout. The <code>subject<\/code> container doesn&rsquo;t have access to the Internet, so this can&rsquo;t run. Let&rsquo;s try:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This should work, and the request should show up in <code>mitmproxy<\/code>&rsquo;s UI.<\/p>\n<h2 id=\"proxying-https-requests\">Proxying HTTPS Requests<a class=\"headerlink\" href=\"#proxying-https-requests\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The setup we have so far works with proxying HTTP requests, but not for HTTPS requests. The whole point of HTTPS over HTTP is to make man-in-the-middle interventions impossible in a request. But that&rsquo;s exactly what a proxy does!<\/p>\n<p>To solve this, we&rsquo;ll install and setup <code>mitmproxy<\/code>&rsquo;s CA into the <code>subject<\/code> container. This will ensure that even if mitmproxy intervenes in HTTPS requests, our <code>subject<\/code> container will gladly accept and mark such requests as verified. This is documented on <a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/\" rel=\"noopener noreferrer\" target=\"_blank\"><code>mitmproxy<\/code>&rsquo;s documentation<\/a>.<\/p>\n<p>The first time mitmproxy starts, it generates a new random CA certificate. This is the certificate is what we want our <code>subject<\/code> container to trust. So we&rsquo;ll use a Docker volume, to share this cert with the <code>subject<\/code> container.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-0><label for=co-0><span class='btn show-full-code-btn'>Show remaining 7 lines<\/span><\/label><pre class=content><code><span><span class=\"nt\">version<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;3&quot;<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nt\">services<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">subject<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">ubuntu<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">sleep infinity<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">volumes<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/certs:\/certs:ro<\/span>\n<\/span><\/span><span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">proxy<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">[<\/span><span class=\"s\">&quot;8081:8081&quot;<\/span><span class=\"p p-Indicator\">]<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmweb --web-host 0.0.0.0<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">volumes<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span class=collapse><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/certs:\/home\/mitmproxy\/.mitmproxy<\/span>\n<\/span><\/span><span class=collapse>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">internal<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">true<\/span>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, we define a volume on each container at the host path <code>.\/certs<\/code> that&rsquo;ll hold the contents of the <code>\/home\/mitmproxy\/.mitmproxy<\/code> folder inside the <code>proxy<\/code> container. This is the path where mitmproxy will save the generated CA root certificate.<\/p>\n<p>We also give the <code>subject<\/code> container access to this volume, at the <code>\/certs<\/code> location inside the <code>container<\/code>. Notice the <code>:ro<\/code> suffix here, which means read-only access. We don&rsquo;t expect the <code>subject<\/code> container to write anything to this volume, just read the CA certificate.<\/p>\n<p>Let&rsquo;s start the containers again with a <code>docker-compose up -d<\/code> and then run our tests again:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>apt<span class=\"w\"> <\/span>update\n<\/span><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>apt<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>--yes<span class=\"w\"> <\/span>curl\n<\/span><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>httpbun.com\/get\n<\/span><span><span class=\"nv\">https_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>But notice that the last command hitting the HTTPS API fails. This is because the <code>subject<\/code> container doesn&rsquo;t trust the <code>mitmproxy<\/code>&rsquo;s CA certificate. We&rsquo;ll see something like this in the output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl: (60) SSL certificate problem: unable to get local issuer certificate\n<\/span><span>More details here: https:\/\/curl.se\/docs\/sslcerts.html\n<\/span><span>\n<\/span><span>curl failed to verify the legitimacy of the server and therefore could not\n<\/span><span>establish a secure connection to it. To learn more about this situation and\n<\/span><span>how to fix it, please visit the web page mentioned above.\n<\/span><\/code><\/pre><\/div>\n\n<p>Now the issue is just that the SSL <em>verification<\/em> has failed. Since the verification failed, <code>curl<\/code> denies continuing with the request. We can tell <code>curl<\/code> to ignore the verification failure by using the <code>--insecure<\/code> flag like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">https_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>--insecure<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>But that&rsquo;s not what we want. We want to tell <code>curl<\/code> to trust the <code>mitmproxy<\/code>&rsquo;s CA certificate. Like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>https_proxy=http:\/\/proxy:8080 curl --cacert \/certs\/mitmproxy-ca.pem https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This should show up as an HTTPS request in mitmproxy with the ability to view full details of the request and response. Try out the same\/similar <code>curl<\/code> commands <em>without<\/em> the proxy, and notice that those requests fail.<\/p>\n<h2 id=\"dns-resolution\">DNS Resolution<a class=\"headerlink\" href=\"#dns-resolution\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>When an HTTP proxy is configured, DNS resolution is done by the proxy. This is because to make the request, it is the proxy that connects to the endpoint server. So it needs to know the IP address of the host. As long as the <code>subject<\/code> container is only making HTTP(s) requests, this is fine. But if we need it to make an explicit DNS query, we see that it fails:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/proxy:8080<span class=\"w\"> <\/span>apt<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>--yes<span class=\"w\"> <\/span>dnsutils\n<\/span><span>nslookup<span class=\"w\"> <\/span>httpbun.com\n<\/span><\/code><\/pre><\/div>\n\n<p>This will fail because direct DNS resolution (as opposed to with a proxy, or with DNS-over-HTTPS) required access to the external network, which the <code>subject<\/code> container doesn&rsquo;t have. We can solve this the same way we solved for HTTP requests, with a proxy.<\/p>\n<p>Let&rsquo;s add the following DNS proxy service to our <code>docker-compose.yml<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"nt\">dns<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmdump --mode dns<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is again an <code>mitmproxy<\/code> container, that runs in DNS mode. And it highlights how awesome <code>mitmproxy<\/code> is! This brings us a DNS <em>proxy<\/em>, that we can use to resolve DNS queries.<\/p>\n<p>Now we&rsquo;ll instruct the <code>subject<\/code> container to use this <code>dns<\/code> container, for DNS queries. This is handled by the <code>resolv.conf<\/code> inside the <code>subject<\/code> container. Let&rsquo;s inspect its contents:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker-compose<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>subject<span class=\"w\"> <\/span>cat<span class=\"w\"> <\/span>\/etc\/resolv.conf\n<\/span><\/code><\/pre><\/div>\n\n<p>We should see something like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>nameserver 127.0.0.11\n<\/span><span>options ndots:0\n<\/span><\/code><\/pre><\/div>\n\n<p>The IP Address next to <code>nameserver<\/code> is what will be used for DNS resolutions. We need this to be the IP Address of the <code>dns<\/code> container, as on the <code>intnet<\/code> network. The <code>docker inspect<\/code> command can help us find this IP Address. In the output of <code>docker inspect $(docker-compose ps -q dns)<\/code>, under <code>NetworkSettings.Networks<\/code>, you&rsquo;ll find the IP Address of the <code>dns<\/code> container, on the <code>intnet<\/code> network. We want this IP Address to be added to the <code>resolv.conf<\/code> of the <code>subject<\/code> container.<\/p>\n<p>We can use the below commands to do this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker-compose<span class=\"w\"> <\/span>up<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span>dns\n<\/span><span>docker-compose<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>subject<span class=\"w\"> <\/span>sh<span class=\"w\"> <\/span>-c<span class=\"w\"> <\/span><span class=\"s2\">&quot;echo nameserver <\/span><span class=\"k\">$(<\/span>\n<\/span><span><span class=\"w\">  <\/span>docker<span class=\"w\"> <\/span>inspect<span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"k\">$(<\/span>docker-compose<span class=\"w\"> <\/span>ps<span class=\"w\"> <\/span>-q<span class=\"w\"> <\/span>dns<span class=\"k\">)<\/span><span class=\"s2\">&quot;<\/span><span class=\"w\"> <\/span>-f<span class=\"w\"> <\/span><span class=\"s1\">$&#39;{{range $k, $v := .NetworkSettings.Networks}}{{$k}}:{{$v.IPAddress}}\\n{{end}}&#39;<\/span><span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>awk<span class=\"w\"> <\/span>-F:<span class=\"w\"> <\/span><span class=\"s1\">&#39;\/_intnet:\/ {print $2}&#39;<\/span>\n<\/span><span><span class=\"k\">)<\/span><span class=\"s2\"> &gt;&gt; \/etc\/resolv.conf&quot;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that we <em>add<\/em> another <code>nameserver<\/code> line with this IP Address instead of replacing the existing one. The reason for this is that the existing one is still useful to resolve internal hostnames, like <code>proxy<\/code>. Now let&rsquo;s try the DNS query again:<\/p>\n<div class=\"hl\"><pre class=content><code><span>nslookup<span class=\"w\"> <\/span>httpbun.com\n<\/span><\/code><\/pre><\/div>\n\n<p>We should see the resolved IP Address show up. You can also try to resolve other hostnames, even internal ones like <code>proxy<\/code>, and see that it responds with that container&rsquo;s <em>internal<\/em> IP Address.<\/p>\n<h2 id=\"connecting-from-host\">Connecting from Host<a class=\"headerlink\" href=\"#connecting-from-host\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>So far, our <code>subject<\/code> container has only been <code>sleep<\/code>ing (pun shamelessly intended). But usually, we&rsquo;d want it to host a website or an app, that&rsquo;s available on HTTP from outside the container, and outside the <code>intnet<\/code> network. Let&rsquo;s set a small website in the <code>subject<\/code> container.<\/p>\n<p>First, let&rsquo;s create a nice <code>index.html<\/code> for our website:<\/p>\n<div class=\"hl\"><pre class=content><code><span>cat<span class=\"w\"> <\/span><span class=\"s\">&lt;&lt;EOF &gt; index.html<\/span>\n<\/span><span><span class=\"s\">&lt;h1&gt;My awesome website!&lt;\/h1&gt;<\/span>\n<\/span><span><span class=\"s\">EOF<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Second, let&rsquo;s change the <code>subject<\/code> container to run a Python content webserver on port <code>80<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"nt\">subject<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">python:3-alpine<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">python -m http.server -d \/www 80<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8090:80&quot;<\/span>\n<\/span><\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">volumes<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/certs:\/certs:ro<\/span>\n<\/span><span><span class=\"hll\"><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.:\/www<\/span>\n<\/span><\/span><\/code><\/pre><\/div>\n\n<p>To verify that it&rsquo;s working, let&rsquo;s <code>curl localhost<\/code> in the <code>subject<\/code> container, and we should see the &ldquo;My awesome website!&rdquo; show up.<\/p>\n<p>We&rsquo;re also exposing this on port 8090 on the host, so if we open <a href=\"http:\/\/localhost:8090\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/localhost:8090<\/a> in the browser on the host system, we should see this &ldquo;My awesome webapp!&rdquo; page, right?<\/p>\n<p>But, no, it doesn&rsquo;t work. The reason is that the <code>subject<\/code> container is only connected to the <code>intnet<\/code> network, which is inaccessible from outside the network-sandbox that Docker has created.<\/p>\n<p>Remember how we used the <code>proxy<\/code> container to let <code>subject<\/code> access Internet resources? We&rsquo;ll do the <em>reverse<\/em> here. We&rsquo;ll define a <em>reverse-proxy<\/em>, that connects to both <code>intnet<\/code> and <code>extnet<\/code>, and will forward all incoming requests to <code>subject<\/code>. We can use <code>mitmproxy<\/code> here as well because it can act as a reverse proxy too (yes, mind blown).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"w\">  <\/span><span class=\"nt\">rproxy<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmdump --mode reverse:http:\/\/subject --listen-port 80<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8091:80&quot;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Although, if you prefer to use a real reverse-proxy, like NGINX, this is the kind of configuration we&rsquo;ll want:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">worker_processes<\/span><span class=\"w\">  <\/span><span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"k\">error_log<\/span><span class=\"w\"> <\/span><span class=\"s\">\/dev\/stderr<\/span><span class=\"w\"> <\/span><span class=\"s\">info<\/span><span class=\"p\">;<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">events<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kn\">worker_connections<\/span><span class=\"w\"> <\/span><span class=\"mi\">1024<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">stream<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kn\">server<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">        <\/span><span class=\"kn\">listen<\/span><span class=\"w\"> <\/span><span class=\"mi\">80<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">        <\/span><span class=\"kn\">proxy_pass<\/span><span class=\"w\"> <\/span><span class=\"s\">http:\/\/subject<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Point is to just listen on port 80 and forward all HTTP requests to the <code>subject<\/code> container&rsquo;s webapp.<\/p>\n<p>Let&rsquo;s bring it up with <code>docker-compose up -d rproxy<\/code>.<\/p>\n<p>Now, if we open <a href=\"http:\/\/localhost:8091\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/localhost:8091<\/a> in the browser on the host system, we should see the response from our little piece of awesome.<\/p>\n<h2 id=\"testing-appsmith\">Testing Appsmith<a class=\"headerlink\" href=\"#testing-appsmith\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Appsmith is a low-code internal tool builder. It&rsquo;s a webapp that lets you build internal tools, without writing code. It&rsquo;s a great tool for building internal tools, but it&rsquo;s also a great tool to test internal tools.<\/p>\n<p>We wanted to test Appsmith and make sure it works well with a proxy. We also want to make sure that when a proxy is configured, it doesn&rsquo;t make any requests trying to bypass it.<\/p>\n<p>To do that, we started with the following <code>docker-compose.yml<\/code> file:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-1><label for=co-1><span class='btn show-full-code-btn'>Show remaining 27 lines<\/span><\/label><pre class=content><code><span><span class=\"nt\">version<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;3&quot;<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nt\">services<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">appsmith<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">appsmith\/appsmith-ce<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">environment<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">HTTP_PROXY<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">http:\/\/proxy:8080<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">HTTPS_PROXY<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">http:\/\/proxy:8080<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">volumes<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/stacks:\/appsmith-stacks<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/resolv.conf:\/etc\/resolv.conf:ro<\/span>\n<\/span><span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"nt\">proxy<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmweb --web-host 0.0.0.0<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8081:8081&quot;<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">volumes<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">.\/certs:\/home\/mitmproxy\/.mitmproxy<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">rproxy<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmdump --mode reverse:http:\/\/subject --listen-port 80<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">ports<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"p p-Indicator\">-<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;8091:80&quot;<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">dns<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">image<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmproxy\/mitmproxy<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">command<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">mitmdump --mode dns<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse><span class=\"w\">      <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nt\">networks<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">intnet<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse><span class=\"w\">    <\/span><span class=\"nt\">internal<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">true<\/span>\n<\/span><span class=collapse><span class=\"w\">  <\/span><span class=\"nt\">extnet<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p p-Indicator\">{}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>A few things are happening here:<\/p>\n<ol>\n<li>We start Appsmith in the internal network with proxy configured to use the <code>proxy<\/code> container. We don&rsquo;t expose any ports for Appsmith, because we&rsquo;ll be accessing it through the <code>rproxy<\/code> container.<\/li>\n<li>We start the <code>proxy<\/code> container which will act as a proxy for all HTTP and HTTPS requests made by Appsmith. The proxy runs on port <code>8080<\/code>, but the web UI runs on port <code>8081<\/code>, which we expose to the host.<\/li>\n<li>We start the <code>rproxy<\/code> container which will act as a reverse proxy for the host (i.e., us) to access Appsmith from the browser.<\/li>\n<li>We start the <code>dns<\/code> container which will act as a DNS server for the internal network.<\/li>\n<li>The Appsmith container uses two volumes: the <code>stacks<\/code> to hold all its data and the <code>resolv.conf<\/code> to add the <code>dns<\/code> container as another nameserver.<\/li>\n<li>The <code>proxy<\/code> container has the <code>certs<\/code> volume, to store the CA certificate for <code>mitmproxy<\/code>.<\/li>\n<\/ol>\n<p>Now, there&rsquo;s still a few missing pieces:<\/p>\n<ol>\n<li>We need the <code>mitmproxy<\/code>&rsquo;s CA cert to be installed in the Appsmith container. This can be done, as <a href=\"https:\/\/docs.appsmith.com\/getting-started\/setup\/instance-configuration\/custom-domain\/custom-ca-root-certificate#setup-custom-ca-root-folder\" rel=\"noopener noreferrer\" target=\"_blank\">detailed in the documentation<\/a>, by copying the cert into <code>stacks\/ca-certs<\/code> folder.<\/li>\n<li>We need the <code>dns<\/code> container&rsquo;s internal IP Address added to Appsmith container&rsquo;s <code>resolv.conf<\/code> file.<\/li>\n<\/ol>\n<div class=\"hl\"><pre class=content><code><span>docker-compose<span class=\"w\"> <\/span>up<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span>dns\n<\/span><span>mkdir<span class=\"w\"> <\/span>-pv<span class=\"w\"> <\/span>stacks\/ca-certs\n<\/span><span>cp<span class=\"w\"> <\/span>-v<span class=\"w\"> <\/span>certs\/mitmproxy-ca.pem<span class=\"w\"> <\/span>stacks\/ca-certs\/mitmproxy-ca.crt\n<\/span><span>cat<span class=\"w\"> <\/span><span class=\"s\">&lt;&lt;EOF &gt; resolv.conf<\/span>\n<\/span><span><span class=\"s\">nameserver 127.0.0.11<\/span>\n<\/span><span><span class=\"s\">options ndots:0<\/span>\n<\/span><span><span class=\"s\">nameserver $(<\/span>\n<\/span><span><span class=\"s\">  docker inspect &quot;$(docker-compose ps -q dns)&quot; -f $&#39;{{range $k, $v := .NetworkSettings.Networks}}{{$k}}:{{$v.IPAddress}}\\n{{end}}&#39; \\<\/span>\n<\/span><span><span class=\"s\">    | awk -F: &#39;\/_intnet:\/ {print $2}&#39;<\/span>\n<\/span><span><span class=\"s\">)<\/span>\n<\/span><span><span class=\"s\">EOF<\/span>\n<\/span><span>docker-compose<span class=\"w\"> <\/span>up<span class=\"w\"> <\/span>-d\n<\/span><\/code><\/pre><\/div>\n\n<p>This will pick up the new CA cert, install it to the trust store, and also start using the new entry in <code>resolv.conf<\/code>.<\/p>\n<p>With this setup, if the Appsmith container makes any outgoing HTTP requests with the configured proxy, it should work fine and should show up in <code>mitmproxy<\/code>&rsquo;s web UI. But if tries to make a request without the proxy, it should fail. This will highlight any features and functionality that get affected due to this.<\/p>\n<h2 id=\"further-explorations\">Further Explorations<a class=\"headerlink\" href=\"#further-explorations\" title=\"Permanent link\">&para;<\/a><\/h2>\n<ol>\n<li>Configure static IP Addresses for the containers in the <code>docker-compose.yml<\/code>, especially the <code>dns<\/code> container. This should make it easier to configure the <code>resolv.conf<\/code> file.<\/li>\n<li>Use NGINX <code>stream<\/code> reverse proxies to have the subject container connect to external databases.<\/li>\n<\/ol>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Since requests directly to the Internet fail, we can use this setup to test if our application doesn&rsquo;t leak any requests when a proxy is configured. Ideally, when I configure a proxy to be used by an application, I don&rsquo;t expect it to make <em>any<\/em> request without that proxy. This sounds like an obvious thing to expect, but the best of expectations fail when it comes to software. This is why we test. This guide should help us test proxy support for applications better.<\/p>","category":{"@attributes":{"term":"posts"}}},{"title":"Shell Script Best Practices","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/shell-script-best-practices\/","rel":"alternate"}},"published":"2022-10-27T00:00:00+05:30","updated":"2022-10-27T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2022-10-27:\/posts\/shell-script-best-practices\/","summary":"<p>This article is about a few quick thumb rules I use when writing shell scripts that I&rsquo;ve come to appreciate over the years. Very opinionated.<\/p>\n<h2 id=\"things\">Things<a class=\"headerlink\" href=\"#things\" title=\"Permanent link\">&para;<\/a><\/h2>\n<ol>\n<li>\n<p>Use <code>bash<\/code>. Using <code>zsh<\/code> or <code>fish<\/code> or any other, will make it hard for others to understand \/ collaborate. Among all shells, <code>bash<\/code> strikes \u2026<\/p><\/li><\/ol>","content":"<p>This article is about a few quick thumb rules I use when writing shell scripts that I&rsquo;ve come to appreciate over the years. Very opinionated.<\/p>\n<h2 id=\"things\">Things<a class=\"headerlink\" href=\"#things\" title=\"Permanent link\">&para;<\/a><\/h2>\n<ol>\n<li>\n<p>Use <code>bash<\/code>. Using <code>zsh<\/code> or <code>fish<\/code> or any other, will make it hard for others to understand \/ collaborate. Among all shells, <code>bash<\/code> strikes a good balance between portability and DX.<\/p>\n<\/li>\n<li>\n<p>Just make the first line be <code>#!\/usr\/bin\/env bash<\/code>, even if you don&rsquo;t give executable permission to the script file.<\/p>\n<\/li>\n<li>\n<p>Use the <code>.sh<\/code> (or <code>.bash<\/code>) extension for your file. It may be fancy to not have an extension for your script, but unless your case explicitly depends on it, you&rsquo;re probably just trying to do clever stuff. Clever stuff are hard to understand.<\/p>\n<\/li>\n<li>\n<p>Use <code>set -o errexit<\/code> at the start of your script.<\/p>\n<ul>\n<li>So that when a command fails, <code>bash<\/code> exits instead of continuing with the rest of the script.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Prefer to use <code>set -o nounset<\/code>. You <em>may<\/em> have a good excuse to not do this, but, my opinion, it&rsquo;s best to always set it.<\/p>\n<ul>\n<li>This will make the script fail, when accessing an unset variable. Saves from horrible unintended consequences, with typos in variable names.<\/li>\n<li>When you want to access a variable that may or may not have been set, use <code>\"${VARNAME-}\"<\/code> instead of <code>\"$VARNAME\"<\/code>, and you&rsquo;re good.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use <code>set -o pipefail<\/code>. Again, you may have good reasons to not do this, but I&rsquo;d recommend to always set it.<\/p>\n<ul>\n<li>This will ensure that a pipeline command is treated as failed, even if one command in the pipeline fails.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use <code>set -o xtrace<\/code>, with a check on <code>$TRACE<\/code> env variable.<\/p>\n<ul>\n<li>For copy-paste: <code>if [[ \"${TRACE-0}\" == \"1\" ]]; then set -o xtrace; fi<\/code>.<\/li>\n<li>This helps in debugging your scripts, a lot. Like, really lot.<\/li>\n<li>People can now <em>enable<\/em> debug mode, by running your script as <code>TRACE=1 .\/script.sh<\/code> instead of <code>.\/script.sh<\/code>.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use <code>[[ ]]<\/code> for conditions in <code>if<\/code> \/ <code>while<\/code> statements, instead of <code>[ ]<\/code> or <code>test<\/code>.<\/p>\n<ul>\n<li><code>[[ ]]<\/code> is a bash <del>builtin<\/del> keyword, and is more powerful than <code>[ ]<\/code> or <code>test<\/code>.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Always quote variable accesses with double-quotes.<\/p>\n<ul>\n<li>One place where it&rsquo;s <em>okay<\/em> not to is on the <em>left-hand-side<\/em> of an <code>[[ ]]<\/code> condition. But even there I&rsquo;d recommend quoting.<\/li>\n<li>When you need the unquoted behaviour, using <code>bash<\/code> arrays will likely serve you much better.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use <code>local<\/code> variables in functions.<\/p>\n<\/li>\n<li>\n<p>Accept multiple ways that users can ask for help and respond in kind.<\/p>\n<ul>\n<li>Check if the first arg is <code>-h<\/code> or <code>--help<\/code> or <code>help<\/code> or just <code>h<\/code> or even <code>-help<\/code>, and in all these cases, print help text and exit.<\/li>\n<li>Please. For the sake of your future-self.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>When printing error messages, please redirect to stderr.<\/p>\n<ul>\n<li>Use <code>echo 'Something unexpected happened' &gt;&amp;2<\/code> for this.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use long options, where possible (like <code>--silent<\/code> instead of <code>-s<\/code>). These serve to document your commands explicitly.<\/p>\n<ul>\n<li>Note though, that commands shipped on some systems like macOS don&rsquo;t always have long options.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>If appropriate, change to the script&rsquo;s directory close to the start of the script.<\/p>\n<ul>\n<li>And it&rsquo;s usually always appropriate.<\/li>\n<li>Use <code>cd \"$(dirname \"$0\")\"<\/code>, which works in <em>most<\/em> cases.<\/li>\n<\/ul>\n<\/li>\n<li>\n<p>Use <code>shellcheck<\/code>. Heed its warnings.<\/p>\n<\/li>\n<\/ol>\n<h2 id=\"template\">Template<a class=\"headerlink\" href=\"#template\" title=\"Permanent link\">&para;<\/a><\/h2>\n<div class=\"hl\"><pre class=content><code><span><span class=\"ch\">#!\/usr\/bin\/env bash<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">set<\/span><span class=\"w\"> <\/span>-o<span class=\"w\"> <\/span>errexit\n<\/span><span><span class=\"nb\">set<\/span><span class=\"w\"> <\/span>-o<span class=\"w\"> <\/span>nounset\n<\/span><span><span class=\"nb\">set<\/span><span class=\"w\"> <\/span>-o<span class=\"w\"> <\/span>pipefail\n<\/span><span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"o\">[[<\/span><span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"si\">${<\/span><span class=\"nv\">TRACE<\/span><span class=\"p\">-0<\/span><span class=\"si\">}<\/span><span class=\"s2\">&quot;<\/span><span class=\"w\"> <\/span><span class=\"o\">==<\/span><span class=\"w\"> <\/span><span class=\"s2\">&quot;1&quot;<\/span><span class=\"w\"> <\/span><span class=\"o\">]]<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"k\">then<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nb\">set<\/span><span class=\"w\"> <\/span>-o<span class=\"w\"> <\/span>xtrace\n<\/span><span><span class=\"k\">fi<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">if<\/span><span class=\"w\"> <\/span><span class=\"o\">[[<\/span><span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"si\">${<\/span><span class=\"nv\">1<\/span><span class=\"p\">-<\/span><span class=\"si\">}<\/span><span class=\"s2\">&quot;<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span>~<span class=\"w\"> <\/span>^-*h<span class=\"o\">(<\/span>elp<span class=\"o\">)<\/span>?$<span class=\"w\"> <\/span><span class=\"o\">]]<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"k\">then<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nb\">echo<\/span><span class=\"w\"> <\/span><span class=\"s1\">&#39;Usage: .\/script.sh arg-one arg-two<\/span>\n<\/span><span>\n<\/span><span><span class=\"s1\">This is an awesome bash script to make your life better.<\/span>\n<\/span><span>\n<\/span><span><span class=\"s1\">&#39;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nb\">exit<\/span>\n<\/span><span><span class=\"k\">fi<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">cd<\/span><span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"k\">$(<\/span>dirname<span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"nv\">$0<\/span><span class=\"s2\">&quot;<\/span><span class=\"k\">)<\/span><span class=\"s2\">&quot;<\/span>\n<\/span><span>\n<\/span><span>main<span class=\"o\">()<\/span><span class=\"w\"> <\/span><span class=\"o\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nb\">echo<\/span><span class=\"w\"> <\/span><span class=\"k\">do<\/span><span class=\"w\"> <\/span>awesome<span class=\"w\"> <\/span>stuff\n<\/span><span><span class=\"o\">}<\/span>\n<\/span><span>\n<\/span><span>main<span class=\"w\"> <\/span><span class=\"s2\">&quot;<\/span><span class=\"nv\">$@<\/span><span class=\"s2\">&quot;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I try to follow these rules in my scripts, and they&rsquo;re known to have made at least my own life better. I&rsquo;m still not consistent though, unfortunately, in following my own rules. So perhaps writing them down this way will help me improve there as well.<\/p>\n<p>Do you have anything you think I should add to this? Please share in the comments!<\/p>\n<p>Edit 1: Included fixes from HN comments at <a href=\"https:\/\/news.ycombinator.com\/item?id=33355407\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/news.ycombinator.com\/item?id=33355407<\/a> and <a href=\"https:\/\/news.ycombinator.com\/item?id=33355077\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/news.ycombinator.com\/item?id=33355077<\/a>.<\/p>\n<p>Edit 2: Fix from <a href=\"https:\/\/news.ycombinator.com\/item?id=33354759\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/news.ycombinator.com\/item?id=33354759<\/a>.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"bash"}},{"@attributes":{"term":"best-practices"}},{"@attributes":{"term":"opinion"}}]},{"title":"Quick insecure TOTP","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/quick-insucure-totp\/","rel":"alternate"}},"published":"2022-09-10T00:00:00+05:30","updated":"2022-09-10T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2022-09-10:\/posts\/quick-insucure-totp\/","summary":"<p>This is about a Hammerspoon script I have that gives me a super-fast way to fill in TOTP fields in MFA logins.<\/p>\n<p class=\"note\"><strong>NOTE<\/strong>: This method of doing MFA is very likely, very unsafe. If you are any bit unsure about anything here, please stay away from this document.<\/p>\n<h2 id=\"hammerspoon\">Hammerspoon<a class=\"headerlink\" href=\"#hammerspoon\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p><a href=\"http:\/\/www.hammerspoon.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">Hammerspoon \u2026<\/a><\/p>","content":"<p>This is about a Hammerspoon script I have that gives me a super-fast way to fill in TOTP fields in MFA logins.<\/p>\n<p class=\"note\"><strong>NOTE<\/strong>: This method of doing MFA is very likely, very unsafe. If you are any bit unsure about anything here, please stay away from this document.<\/p>\n<h2 id=\"hammerspoon\">Hammerspoon<a class=\"headerlink\" href=\"#hammerspoon\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p><a href=\"http:\/\/www.hammerspoon.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">Hammerspoon<\/a> is a very convenient and powerful system automation system, that can be programmed in Lua, for macOS. It&rsquo;s been my replacement for AutoHotkey after moving away from Windows.<\/p>\n<p>Install with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>brew<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>hammerspoon\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"totp-script\">TOTP Script<a class=\"headerlink\" href=\"#totp-script\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Four pieces to this.<\/p>\n<p><strong>One<\/strong>, open <code>~\/.hammerspoon\/init.lua<\/code>, create if it doesn&rsquo;t exist. Ensure you have the following line, perhaps among many others:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">require<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;totp-generator&quot;<\/span><span class=\"p\">).<\/span><span class=\"n\">init<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p><strong>Two<\/strong>, in <code>~\/.hammerspoon\/totp-generator.lua<\/code>, put the following content:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-3><label for=co-3><span class='btn show-full-code-btn'>Show remaining 59 lines<\/span><\/label><pre class=content><code><span><span class=\"kd\">local<\/span> <span class=\"n\">os<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">require<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;os&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"kd\">local<\/span> <span class=\"n\">gauth<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">require<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;gauth&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"kd\">local<\/span> <span class=\"n\">mfa_note_path<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">os.getenv<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;HOME&quot;<\/span><span class=\"p\">)<\/span> <span class=\"o\">..<\/span> <span class=\"s2\">&quot;\/.hammerspoon\/otp-codes.csv&quot;<\/span>\n<\/span><span><span class=\"kd\">local<\/span> <span class=\"n\">keys<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">nil<\/span>\n<\/span><span>\n<\/span><span><span class=\"kr\">function<\/span> <span class=\"nf\">init<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"n\">hs<\/span><span class=\"p\">.<\/span><span class=\"n\">hotkey<\/span><span class=\"p\">.<\/span><span class=\"n\">bind<\/span><span class=\"p\">({<\/span><span class=\"s2\">&quot;alt&quot;<\/span><span class=\"p\">},<\/span> <span class=\"s2\">&quot;n&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">launch<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">hs<\/span><span class=\"p\">.<\/span><span class=\"n\">pathwatcher<\/span><span class=\"p\">.<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">mfa_note_path<\/span><span class=\"p\">,<\/span> <span class=\"kr\">function<\/span><span class=\"p\">()<\/span>\n<\/span><span>        <span class=\"n\">keys<\/span> <span class=\"o\">=<\/span> <span class=\"n\">loadItems<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"kr\">end<\/span><span class=\"p\">):<\/span><span class=\"n\">start<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"n\">keys<\/span> <span class=\"o\">=<\/span> <span class=\"n\">loadItems<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"kr\">end<\/span>\n<\/span><span>\n<\/span><span><span class=\"kd\">local<\/span> <span class=\"n\">chooser<\/span> <span class=\"o\">=<\/span> <span class=\"n\">hs<\/span><span class=\"p\">.<\/span><span class=\"n\">chooser<\/span><span class=\"p\">.<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"kr\">function<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"kr\">if<\/span> <span class=\"n\">item<\/span> <span class=\"o\">==<\/span> <span class=\"kc\">nil<\/span> <span class=\"kr\">then<\/span>\n<\/span><span>        <span class=\"kr\">return<\/span>\n<\/span><span>    <span class=\"kr\">end<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"kd\">local<\/span> <span class=\"n\">hash<\/span> <span class=\"o\">=<\/span> <span class=\"n\">gauth<\/span><span class=\"p\">.<\/span><span class=\"n\">GenCode<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">.<\/span><span class=\"n\">_key<\/span><span class=\"p\">,<\/span> <span class=\"nb\">math.floor<\/span><span class=\"p\">(<\/span><span class=\"nb\">os.time<\/span><span class=\"p\">()<\/span> <span class=\"o\">\/<\/span> <span class=\"mi\">30<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse>    <span class=\"n\">hs<\/span><span class=\"p\">.<\/span><span class=\"n\">eventtap<\/span><span class=\"p\">.<\/span><span class=\"n\">keyStrokes<\/span><span class=\"p\">((<\/span><span class=\"s2\">&quot;%06d&quot;<\/span><span class=\"p\">):<\/span><span class=\"n\">format<\/span><span class=\"p\">(<\/span><span class=\"n\">hash<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse><span class=\"kr\">end<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">queryChangedCallback<\/span><span class=\"p\">(<\/span><span class=\"kr\">function<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">if<\/span> <span class=\"n\">query<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;&quot;<\/span> <span class=\"kr\">then<\/span>\n<\/span><span class=collapse>        <span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">choices<\/span><span class=\"p\">(<\/span><span class=\"kc\">nil<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">choices<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"kr\">for<\/span> <span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span> <span class=\"kr\">in<\/span> <span class=\"nb\">pairs<\/span><span class=\"p\">(<\/span><span class=\"n\">filter<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">,<\/span> <span class=\"n\">keys<\/span><span class=\"p\">)<\/span> <span class=\"ow\">or<\/span> <span class=\"p\">{})<\/span> <span class=\"kr\">do<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">table.insert<\/span><span class=\"p\">(<\/span><span class=\"n\">choices<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">choices<\/span><span class=\"p\">(<\/span><span class=\"n\">choices<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse><span class=\"kr\">end<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"kr\">function<\/span> <span class=\"nf\">launch<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>    <span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">choices<\/span><span class=\"p\">(<\/span><span class=\"kc\">nil<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">query<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"n\">chooser<\/span><span class=\"p\">:<\/span><span class=\"n\">show<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse><span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"kr\">function<\/span> <span class=\"nf\">filter<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">,<\/span> <span class=\"n\">items<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">if<\/span> <span class=\"n\">query<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;&quot;<\/span> <span class=\"kr\">then<\/span>\n<\/span><span class=collapse>        <span class=\"kr\">return<\/span> <span class=\"kc\">nil<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">lowerQuery<\/span> <span class=\"o\">=<\/span> <span class=\"n\">query<\/span><span class=\"p\">:<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">for<\/span> <span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span> <span class=\"kr\">in<\/span> <span class=\"nb\">pairs<\/span><span class=\"p\">(<\/span><span class=\"n\">items<\/span><span class=\"p\">)<\/span> <span class=\"kr\">do<\/span>\n<\/span><span class=collapse>        <span class=\"kr\">if<\/span> <span class=\"n\">item<\/span><span class=\"p\">.<\/span><span class=\"n\">text<\/span><span class=\"p\">:<\/span><span class=\"n\">lower<\/span><span class=\"p\">():<\/span><span class=\"n\">find<\/span><span class=\"p\">(<\/span><span class=\"n\">lowerQuery<\/span><span class=\"p\">)<\/span> <span class=\"o\">~=<\/span> <span class=\"kc\">nil<\/span> <span class=\"kr\">then<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">table.insert<\/span><span class=\"p\">(<\/span><span class=\"n\">result<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">return<\/span> <span class=\"n\">result<\/span>\n<\/span><span class=collapse><span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"kr\">function<\/span> <span class=\"nf\">loadItems<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">f<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">io.open<\/span><span class=\"p\">(<\/span><span class=\"n\">mfa_note_path<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;r&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">content<\/span> <span class=\"o\">=<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span><span class=\"n\">read<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;*all&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"n\">f<\/span><span class=\"p\">:<\/span><span class=\"n\">close<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"kd\">local<\/span> <span class=\"n\">entries<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span class=collapse>    <span class=\"c1\">-- Ref: https:\/\/www.lua.org\/manual\/5.3\/manual.html#6.4.1<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">for<\/span> <span class=\"n\">title<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">desc<\/span> <span class=\"kr\">in<\/span> <span class=\"nb\">string.gmatch<\/span><span class=\"p\">(<\/span><span class=\"n\">content<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;%s*(.-)%s*,%s*(.-)%s*,%s*(.-)%s*<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span><span class=\"p\">)<\/span> <span class=\"kr\">do<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">title<\/span><span class=\"p\">,<\/span> <span class=\"n\">desc<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">table.insert<\/span><span class=\"p\">(<\/span><span class=\"n\">entries<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>            <span class=\"n\">text<\/span><span class=\"o\">=<\/span><span class=\"n\">title<\/span><span class=\"p\">,<\/span>\n<\/span><span class=collapse>            <span class=\"n\">subText<\/span><span class=\"o\">=<\/span><span class=\"n\">desc<\/span><span class=\"p\">,<\/span>\n<\/span><span class=collapse>            <span class=\"n\">_key<\/span><span class=\"o\">=<\/span><span class=\"nb\">string.lower<\/span><span class=\"p\">(<\/span><span class=\"nb\">string.gsub<\/span><span class=\"p\">(<\/span><span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;%s+&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">)),<\/span>\n<\/span><span class=collapse>        <span class=\"p\">})<\/span>\n<\/span><span class=collapse>    <span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"kr\">return<\/span> <span class=\"n\">entries<\/span>\n<\/span><span class=collapse><span class=\"kr\">end<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"kr\">return<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"n\">init<\/span><span class=\"o\">=<\/span><span class=\"n\">init<\/span><span class=\"p\">,<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p><strong>Three<\/strong>, download the <a href=\"https:\/\/raw.githubusercontent.com\/teunvink\/hammerspoon\/master\/gauth.lua\" rel=\"noopener noreferrer\" target=\"_blank\">gauth.lua<\/a> file, and place it in <code>~\/.hammerspoon<\/code> folder. This is what does the bulk of the work, so thanks to <a href=\"https:\/\/github.com\/teunvink\" rel=\"noopener noreferrer\" target=\"_blank\">teunvink<\/a> for this!<\/p>\n<p><strong>Four<\/strong>, in the file <code>~\/.hammerspoon\/opt-codes.csv<\/code>, add your TOTP code data, one per line, like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Mail,abcd efghi jklmn opqrst, Personal Mail Account\n<\/span><span>Another,onemoretotpcodehere, Another nice account\n<\/span><\/code><\/pre><\/div>\n\n<p>Each line contains three entries, separated by commas. First is a title, short and easily identifiable, second is the TOTP Key, third is a description that you could include any longer explanation for yourself.<\/p>\n<p>The TOTP Key in the second column is given by the MFA provider when configuring MFA. We are usually asked to scan the QR code on our phones when setting this up, but we can also get a TOTP Key, usually hidden behind a button that reads something like <code>Can't scan the code?<\/code>. Copy that key and put an entry here.<\/p>\n<p>Now start\/reload Hammerspoon.<\/p>\n<p>Now, while your cursor is in a TOTP field, hit <kbd>Opt+n<\/kbd> and start searching for any entry from the CSV file, and hit Enter on the entry you want to be filled in.<\/p>\n<h2 id=\"demo\">Demo<a class=\"headerlink\" href=\"#demo\" title=\"Permanent link\">&para;<\/a><\/h2>\n<video controls=\"\" muted=\"\" playsinline=\"\" preload=\"\" src=\"https:\/\/sharats.me\/static\/totp-generator-demo.mp4\">Your browser does not support HTML5 video. Here&rsquo;s <a href=\"https:\/\/sharats.me\/static\/totp-generator-demo.mp4\">a link to the video<\/a>instead.<\/video>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Again, this can be very convenient, but is not very secure. The way I use it on my system is quite a bit different from what I demonstrate here, but that&rsquo;s only because I don&rsquo;t want to show off the exact format I am using. So feel free to tweak the CSV format and use something else like JSON or some other encrypted source altogether, like the <code>pass<\/code> CLI, perhaps. But, I can&rsquo;t speak for that.<\/p>\n<p>Keep your keys safe. They are nothing less than passwords.<\/p>\n<p>Thank you for reading.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"hammerspoon"}},{"@attributes":{"term":"lua"}},{"@attributes":{"term":"totp"}},{"@attributes":{"term":"productivity"}}]},{"title":"Peeking into HTTPS Traffic with a Proxy","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/peeking-into-https-traffic-with-a-proxy\/","rel":"alternate"}},"published":"2022-06-17T00:00:00+05:30","updated":"2022-06-17T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2022-06-17:\/posts\/peeking-into-https-traffic-with-a-proxy\/","summary":"<p>This article is about configuring a web application, Appsmith in this case, to run correctly behind a firewall that does SSL decryption, as a Docker container. Instead of a firewall, we&rsquo;ll use a proxy, which, for the purpose of the problem statement, should be the same.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents \u2026<\/span><\/div>","content":"<p>This article is about configuring a web application, Appsmith in this case, to run correctly behind a firewall that does SSL decryption, as a Docker container. Instead of a firewall, we&rsquo;ll use a proxy, which, for the purpose of the problem statement, should be the same.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#setting-up-mitmproxy\">Setting up mitmproxy<\/a><\/li>\n<li><a href=\"#setting-up\">Setting up<\/a><\/li>\n<li><a href=\"#setting-proxy-on-the-whole-container\">Setting proxy on the whole container<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<li><a href=\"#bonus-using-charles\">Bonus: Using Charles<\/a><\/li>\n<\/ul>\n<\/div>\n<p>Since the proxy needs to support HTTPS decryption, we&rsquo;ll use <code>mitmproxy<\/code>, but Charles or any other proxy that supports this would also work just fine.<\/p>\n<h2 id=\"setting-up-mitmproxy\">Setting up <code>mitmproxy<\/code><a class=\"headerlink\" href=\"#setting-up-mitmproxy\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Install with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>brew<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>mitmproxy\n<\/span><\/code><\/pre><\/div>\n\n<p>Now launch it using:<\/p>\n<div class=\"hl\"><pre class=content><code><span>mitmweb<span class=\"w\"> <\/span>--listen<span class=\"w\"> <\/span><span class=\"m\">9020<\/span><span class=\"w\"> <\/span>--web<span class=\"w\"> <\/span><span class=\"m\">9021<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let it run in a separate Terminal window in the background. This will also open the proxy&rsquo;s web UI at <a href=\"http:\/\/localhost:9021\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/localhost:9021<\/a>. To get a console UI instead, use <code>mitmproxy<\/code> instead of <code>mitmweb<\/code> in the above command.<\/p>\n<p>Let&rsquo;s try running some requests through this proxy to see it&rsquo;s working well. Start with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>http:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This should print a valid JSON as the response, with some details about the request itself. Let&rsquo;s repeat this with the proxy.<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>localhost:9020<span class=\"w\"> <\/span>http:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>You should again see the same response here, but this time, a new entry should appear in the <code>mitmweb<\/code> UI. Here, you can inspect the request and be able to see the path, headers and response of the request.<\/p>\n<p>So we&rsquo;ve confirmed that our proxy works. Let&rsquo;s add HTTPS to the mix.<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>Again, same thing, but with HTTPS, without a proxy. You should see the same response as before, but without an entry in the proxy. That&rsquo;s to be expected since we didn&rsquo;t put a <code>--proxy<\/code> here. Let&rsquo;s try that now.<\/p>\n<div class=\"hl\"><pre class=content><code><span>curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>localhost:9020<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This will fail with a verification error, that the SSL certificate couldn&rsquo;t be verified. Let&rsquo;s see why.<\/p>\n<p>The way an SSL proxy works is by establishing two SSL connections, one with the client (a browser, or <code>curl<\/code>), initiated by the client, and another with the server (the <code>httpbun.com<\/code> server in this case). Everything sent by the client is encrypted using the certificate of <code>mitmproxy<\/code>, and everything by and to the server is encrypted with the server&rsquo;s certificate.<\/p>\n<p>The first time <code>mitmproxy<\/code> is started, it creates a new root certificate, in the <code>~\/.mitmproxy<\/code> folder. We can install this root certificate on our system, and then <code>curl<\/code>, or any other client, will trust it. The <code>mitmproxy<\/code> docs talk about <a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/#installing-the-mitmproxy-ca-certificate-manually\" rel=\"noopener noreferrer\" target=\"_blank\">how to install this cert<\/a>. Optionally, for <code>curl<\/code>, instead of installing the cert, we can use the <code>--cacert<\/code> flag to point to the root certificate.<\/p>\n<p>Another point to note here, is that installing this root certificate on your system, doesn&rsquo;t mean it&rsquo;ll be trusted in any Docker containers run on your system. Docker containers are isolated systems in this context, and maintain their own list of trusted root certificates.<\/p>\n<p>To illustrate this, first, let&rsquo;s run the same request from inside a container, and we should see the error right away:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>--rm<span class=\"w\"> <\/span>alpine\/curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>host.docker.internal:9020<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>At this, you should see a certificate validation error. This is because the root certificate of <code>mitmproxy<\/code> isn&rsquo;t installed inside the container&rsquo;s environment, and so the <code>curl<\/code> invocation inside, won&rsquo;t be able to verify <code>mitmproxy<\/code>&rsquo;s certificate.<\/p>\n<p>To confirm that this is indeed because of <code>mitmproxy<\/code>, run the same <code>docker run<\/code> command without the <code>--proxy host.docker.internal<\/code> and you won&rsquo;t see this error, despite running with <code>https<\/code>.<\/p>\n<p>Now we&rsquo;ve reproduced the situation where a process (a web server in our case), inside a Docker container, is trying to run behind an SSL-decrypting firewall (or, an SSL-decrypting proxy in our case here). Let&rsquo;s see what we can do to get this to work.<\/p>\n<h2 id=\"setting-up\">Setting up<a class=\"headerlink\" href=\"#setting-up\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>For our adventure here, we&rsquo;ll use the Docker image of Appsmith, located at <a href=\"https:\/\/hub.docker.com\/repository\/docker\/appsmith\/appsmith-ce\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/hub.docker.com\/repository\/docker\/appsmith\/appsmith-ce<\/a>.<\/p>\n<p>Let&rsquo;s start a <em>temporary<\/em> Appsmith container with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>--rm<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span>--name<span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>-p<span class=\"w\"> <\/span><span class=\"m\">80<\/span>:9022<span class=\"w\"> <\/span>appsmith\/appsmith-ce\n<\/span><\/code><\/pre><\/div>\n\n<p>Once this is ready, you should be able to access your Appsmith instance at <a href=\"http:\/\/localhost:9022\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/localhost:9022<\/a>.<\/p>\n<p>Let&rsquo;s try to run some <code>curl<\/code> requests inside this container, and get them to go through our <code>mitmweb<\/code> proxy.<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>host.docker.internal:9020<span class=\"w\"> <\/span>http:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This should work fine, and the request should show up in the proxy UI with full details as well. Now let&rsquo;s do the same thing with <code>https<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>host.docker.internal:9020<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s copy the root certificate into the container. For <code>mitmproxy<\/code>, the root cert is generated at first start, and is located at <code>~\/.mitmproxy\/mitmproxy-ca-cert.pem<\/code>, going by the docs at <a href=\"https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/#the-mitmproxy-certificate-authority\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/docs.mitmproxy.org\/stable\/concepts-certificates\/#the-mitmproxy-certificate-authority<\/a>.<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>cp<span class=\"w\"> <\/span>~\/.mitmproxy\/mitmproxy-ca-cert.pem<span class=\"w\"> <\/span>ace:\/\n<\/span><\/code><\/pre><\/div>\n\n<p>With this command, we are copying the root certificate of <code>mitmproxy<\/code> into the container, into the root folder. Let&rsquo;s run the same <code>curl<\/code> command now, providing it this root cert:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>--proxy<span class=\"w\"> <\/span>host.docker.internal:9020<span class=\"w\"> <\/span>--cacert<span class=\"w\"> <\/span>\/mitmproxy-ca-cert.pem<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>Now we&rsquo;ll see the correct response, as well as full details of this request in the proxy UI.<\/p>\n<h2 id=\"setting-proxy-on-the-whole-container\">Setting proxy on the whole container<a class=\"headerlink\" href=\"#setting-proxy-on-the-whole-container\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We&rsquo;re now at the point where it&rsquo;s possible for requests inside the container to be run via the proxy, without any cert validation errors.<\/p>\n<p>But this currently needs to be deliberate. Like in the example above, the <code>curl<\/code> command needs the cert to be specified explicitly. Instead, we&rsquo;d like even ordinary <code>curl<\/code> commands to always go through the proxy, since, that&rsquo;s how a firewall would work, and ultimately, that&rsquo;s what we are trying to reproduce here.<\/p>\n<p>Let&rsquo;s stop the <code>ace<\/code> container and start it again with proxy configuration set.<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>stop<span class=\"w\"> <\/span>ace\n<\/span><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>--rm<span class=\"w\"> <\/span>-d<span class=\"w\"> <\/span>--name<span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>-p<span class=\"w\"> <\/span><span class=\"m\">80<\/span>:9022<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">HTTP_PROXY<\/span><span class=\"o\">=<\/span>http:\/\/host.docker.internal:9020<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">HTTPS_PROXY<\/span><span class=\"o\">=<\/span>http:\/\/host.docker.internal:9020<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">http_proxy<\/span><span class=\"o\">=<\/span>http:\/\/host.docker.internal:9020<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span>-e<span class=\"w\"> <\/span><span class=\"nv\">https_proxy<\/span><span class=\"o\">=<\/span>http:\/\/host.docker.internal:9020<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span>appsmith\/appsmith-ce\n<\/span><\/code><\/pre><\/div>\n\n<p>Yep, that&rsquo;s right. We need to set both <code>http_proxy<\/code> <em>and<\/em> <code>HTTP_PROXY<\/code> for all applications inside the container to take it seriously. \ud83e\udd26<\/p>\n<p>Let&rsquo;s run a normal <code>curl<\/code> request on this container to see if the proxy settings are applied:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>http:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>If the proxy configuration is working, then you should see this request appear in the proxy UI. Also, for <code>https<\/code> URLs:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>run<span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This, as we can expect, fails due to a cert validation error, since it&rsquo;s using the proxy, but the proxy&rsquo;s certificate can&rsquo;t be verified. We can provide the root cert of <code>mitmproxy<\/code> using the <code>--cacert<\/code> argument, but we want it to apply to all requests in the container, without such explicit configuration, so we won&rsquo;t do that.<\/p>\n<p>Instead, we want to <em>install<\/em> the root certificate of <code>mitmproxy<\/code> to the <em>truststore<\/em>, so that it&rsquo;s available to <em>all<\/em> processes in the container for validating SSL certificates.<\/p>\n<p>How this is done, depends on the operating system, but in our case, since the container is Ubuntu, all we need to do is:<\/p>\n<ul>\n<li>Copy the certificate file to <code>\/usr\/local\/share\/ca-certificates<\/code>.<\/li>\n<li>If the cert has the <code>.pem<\/code> extension, rename it to use the <code>.crt<\/code> extension. This is because Ubuntu&rsquo;s <code>update-ca-certificates<\/code> command only picks files with a <code>.crt<\/code> extension.<\/li>\n<li>Run <code>update-ca-certificates<\/code>.<\/li>\n<\/ul>\n<p>Let&rsquo;s copy the root cert into the container, and install it by running the above commands inside the container:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span>cp<span class=\"w\"> <\/span>~\/.mitmproxy\/mitmproxy-ca-cert.pem<span class=\"w\"> <\/span>ace:\/usr\/local\/share\/ca-certificates\/mitmproxy-ca-cert.crt\n<\/span><span>docker<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>update-ca-certificates\n<\/span><\/code><\/pre><\/div>\n\n<p>The output should say that one certificate has been added to the truststore.<\/p>\n<p>Let&rsquo;s run the same <code>https<\/code> request again:<\/p>\n<div class=\"hl\"><pre class=content><code><span>docker<span class=\"w\"> <\/span><span class=\"nb\">exec<\/span><span class=\"w\"> <\/span>ace<span class=\"w\"> <\/span>curl<span class=\"w\"> <\/span>https:\/\/httpbun.com\/get\n<\/span><\/code><\/pre><\/div>\n\n<p>This should now print the correct response, as well as show up on the proxy UI with full details for inspection. \ud83c\udf89<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This has culminated in creating the PR <a href=\"https:\/\/github.com\/appsmithorg\/appsmith\/pull\/14207\/files\" rel=\"noopener noreferrer\" target=\"_blank\">#14207<\/a>. This PR contains a fer QoL improvements over the solution above.<\/p>\n<ol>\n<li>\n<p>We install <code>ca-certificates-java<\/code>, so that when we run <code>update-ca-certificates<\/code>, they are also installed into the JVM truststore. This is important since, one, Java maintains its own truststore (like Firefox), and two, Appsmith&rsquo;s server runs on the JVM, so we need this there as well.<\/p>\n<\/li>\n<li>\n<p>We provide support for a <code>ca-certs<\/code> folder in the volume, where users can drop any root cert files which will be auto-added on container startup.<\/p>\n<\/li>\n<li>\n<p>We run <code>update-ca-certificates --fresh<\/code> instead of just <code>update-ca-certificates<\/code>, so that any cert file <em>removed<\/em> from the <code>ca-certs<\/code> folder, also gets removed from the truststores.<\/p>\n<\/li>\n<li>\n<p>We mix up values of the proxy env variables, so that setting just one of <code>http_proxy<\/code> and <code>HTTP_PROXY<\/code> would be enough. This is also done for <code>https_proxy<\/code> and <code>HTTPS_PROXY<\/code>.<\/p>\n<\/li>\n<li>\n<p>We provide a friendly warning when there&rsquo;s <code>.pem<\/code> files in the <code>ca-certs<\/code> folder, since, most likely, they are there because the user forgot to rename them to use the <code>.crt<\/code> extension.<\/p>\n<\/li>\n<li>\n<p>The JVM needs the <code>-Djava.net.useSystemProxies=true<\/code> to use the system configured proxy. Additionally, we also set the individual proxy configuration as additional system properties, so we can apply them when executing requests via Apaches&rsquo; web client libraries. Since, well, that library doesn&rsquo;t respect system proxy configuration, although the rest of JVM does. Go figure.<\/p>\n<\/li>\n<li>\n<p>We set a <code>NO_PROXY<\/code> env variable to hosts that should <em>not<\/em> go through the proxy, like <code>localhost<\/code> and <code>127.0.0.1<\/code>.<\/p>\n<\/li>\n<\/ol>\n<p>Of course, considering our premise, which is to be able to use Appsmith behind an SSL decrypting proxy, all a user needs to do, is to place the firewall&rsquo;s root certificate in the <code>ca-certs<\/code> folder, and restart the Appsmith container.<\/p>\n<h2 id=\"bonus-using-charles\">Bonus: Using Charles<a class=\"headerlink\" href=\"#bonus-using-charles\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Notes on using Charles instead of <code>mitmproxy<\/code>.<\/p>\n<p>Install with:<\/p>\n<div class=\"hl\"><pre class=content><code><span>brew<span class=\"w\"> <\/span>install<span class=\"w\"> <\/span>charles\n<\/span><\/code><\/pre><\/div>\n\n<p>Open Charles<\/p>\n<p>Go to <code>Proxy -&gt; SSL Proxying Settings<\/code>, under &ldquo;SSL Proxying&rdquo;, add a few domains you want SSL decryption to be done. Let&rsquo;s add an entry under &ldquo;Include&rdquo;, with host set to <code>httpbun.com<\/code> and port set to <code>443<\/code> (which is the default port of HTTPS).<\/p>\n<p>Check with http curl, response should show up correctly, and the request should show up in Charles with full information.<\/p>\n<p>Check with https curl, get an error response back, and the request should show up in Charles with incomplete information, and a red error icon.<\/p>\n<p>To get the Charles&rsquo; root certificate, go to <code>Help -&gt; SSL Proxying -&gt; Save Charles Root Certificate...<\/code>. Provide a location to save this cert, like your home folder.<\/p>\n<p>The other steps should be the same as explained above for <code>mitmproxy<\/code>.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"proxy"}},{"@attributes":{"term":"docker"}},{"@attributes":{"term":"mitmproxy"}},{"@attributes":{"term":"https"}},{"@attributes":{"term":"curl"}},{"@attributes":{"term":"appsmith"}}]},{"title":"Time is different every time","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/time-is-different-every-time\/","rel":"alternate"}},"published":"2021-12-24T00:00:00+05:30","updated":"2021-12-24T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2021-12-24:\/posts\/time-is-different-every-time\/","summary":"<p>I love automating things, with shell aliases, global hotkeys, IDE snippets etc.<\/p>\n<p>I see this question of have you spent more time automating something, than the time it&rsquo;s saved you?<\/p>\n<p>I&rsquo;ve seen this question a lot of times over the years, whenever someone sees me using such a \u2026<\/p>","content":"<p>I love automating things, with shell aliases, global hotkeys, IDE snippets etc.<\/p>\n<p>I see this question of have you spent more time automating something, than the time it&rsquo;s saved you?<\/p>\n<p>I&rsquo;ve seen this question a lot of times over the years, whenever someone sees me using such a shortcut<\/p>\n<blockquote>\n<p>How long did it take for you to build and learn that automation? Was the time you saved from it worth it?<\/p>\n<\/blockquote>\n<p>My answer to that is, of course, yes. But the question is a little more nuanced.<\/p>\n<p><em>Was the time saved <strong>worth<\/strong> it?<\/em> Yes.<\/p>\n<p><em>Was the time saved <strong>more<\/strong> than the time you spent in building and learning?<\/em> No.<\/p>\n<p>So, I spent <em>more<\/em> time, in building and learning the shortcut, than I saved because of the shortcut. This was illustrated well in <a href=\"https:\/\/xkcd.com\/1205\/\" rel=\"noopener noreferrer\" target=\"_blank\">this XKCD comic<\/a>:<\/p>\n<p class=\"img\"><a href=\"https:\/\/imgs.xkcd.com\/comics\/is_it_worth_the_time.png\" rel=\"noopener noreferrer\" target=\"_blank\"><img alt=\"Is it worth the time\" src=\"https:\/\/imgs.xkcd.com\/comics\/is_it_worth_the_time.png\"><\/a><\/p>\n<p>This, for most people, makes learning such shortcuts a waste of time. Because, of course, the net time difference is negative. Therein lies the folly.<\/p>\n<blockquote>\n<p>Not all five minutes hold the same value.<\/p>\n<\/blockquote>\n<p>There are times when I&rsquo;m working on a critical fix that needs to go out in negative time. I hope to not end up in such situations, but we do. In such situations, saving a few precious seconds can mean a lot.<\/p>\n<p>Consider a hypothetical example, an internal application server is down for whatever reason. I need to SSH into the server to see what&rsquo;s up. Sure, I could go into my notes, search for the long SSH command for this server, SSH into it, then run commands to check logs, and then to restart if needed etc.<\/p>\n<p>But, what if this was a single shell script. Just SSH into that server, print me the logs, and ask me if I want it restarted or not. Just a Y\/N answer. I&rsquo;m quite sure developing such a script would take more time than I&rsquo;d be saving. However, I&rsquo;d be spending that time developing this script, when I&rsquo;m not in a hurry.<\/p>\n<p>I can afford to spend those <em>ten minutes<\/em> in such a situation, to save <em>ten seconds<\/em> in a more critical situation. This is what makes it worth it.<\/p>\n<p>But there&rsquo;s an ugly face to this. We should know when some shortcut is <em>enough<\/em>. It&rsquo;s easy to get into the trap of trying to optimize it and make it better and better. This is well represented in <a href=\"https:\/\/xkcd.com\/1319\/\" rel=\"noopener noreferrer\" target=\"_blank\">this comic by XKCD<\/a>:<\/p>\n<p class=\"img\"><a href=\"https:\/\/imgs.xkcd.com\/comics\/automation.png\" rel=\"noopener noreferrer\" target=\"_blank\"><img alt=\"The trap of automation, by XKCD\" src=\"https:\/\/imgs.xkcd.com\/comics\/automation.png\"><\/a><\/p>\n<p>Part of the problem is, developers, just like artists, often are never done. There&rsquo;s always a small finishing touch that can be done.<\/p>\n<p>The trick is to recognize, and even assume, that you&rsquo;ll be the only user ever of this shortcut. If it works for you, without too many brain cycles, in a critical situation, you&rsquo;re done. Move on.<\/p>\n<p>So, what do I automate? I&rsquo;ve written about my automations and workflows quite a bit in the past:<\/p>\n<ul>\n<li><a href=\"..\/automating-the-vim-workplace\/\">Automating with Vim workplace<\/a>, <a href=\"..\/automating-the-vim-workplace-2\/\">part 2<\/a>, and <a href=\"..\/automating-the-vim-workplace-3\/\">part 3<\/a>.<\/li>\n<li><a href=\"..\/the-magic-of-autohotkey\/\">The Magic of AutoHotkey<\/a>, and <a href=\"..\/the-magic-of-autohotkey-2\/\">part 2<\/a>.<\/li>\n<\/ul>\n<p>Today, I primarily work with macOS, and have come to love Hammerspoon, as an alternative to AutoHotkey on Windows. I intend to write about my Hammerspoon automations as well, soon.<\/p>\n<p>As I always say, <em>identify, automate, repeat<\/em>.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"automation"}},{"@attributes":{"term":"shower-thoughts"}}]},{"title":"The Python `print` function","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/python-print-function\/","rel":"alternate"}},"published":"2020-04-05T00:00:00+05:30","updated":"2020-04-05T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-04-05:\/posts\/python-print-function\/","summary":"<p>The <a href=\"https:\/\/docs.python.org\/3\/library\/functions.html#print\" rel=\"noopener noreferrer\" target=\"_blank\"><code>print<\/code><\/a> function is most likely the first function we encounter when learning Python.\nThat encounter usually looks like <code>print(\"Hello world!\")<\/code>. After that, we go on to learning more\nstuff about it like being able to pass any number of arguments or of any type etc. I&rsquo;m writing \u2026<\/p>","content":"<p>The <a href=\"https:\/\/docs.python.org\/3\/library\/functions.html#print\" rel=\"noopener noreferrer\" target=\"_blank\"><code>print<\/code><\/a> function is most likely the first function we encounter when learning Python.\nThat encounter usually looks like <code>print(\"Hello world!\")<\/code>. After that, we go on to learning more\nstuff about it like being able to pass any number of arguments or of any type etc. I&rsquo;m writing this\narticle to give an idea how deep this rabbit hole goes. Turns out, the <code>print<\/code> function is <em>very<\/em>\npowerful. So let&rsquo;s get a coffee, put on a dusty pair of sunglasses and bask in its power!<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#the-basics\">The Basics<\/a><\/li>\n<li><a href=\"#handling-of-multiple-arguments\">Handling of Multiple Arguments<\/a><\/li>\n<li><a href=\"#handling-of-non-string-types\">Handling of non-string types<\/a><\/li>\n<li><a href=\"#write-to-files\">Write to files<\/a><ul>\n<li><a href=\"#using-sysstderr\">Using sys.stderr<\/a><\/li>\n<li><a href=\"#modifying-sysstdout\">Modifying sys.stdout<\/a><\/li>\n<li><a href=\"#collecting-with-iostringio\">Collecting with io.StringIO<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#the-end-keyword-argument\">The end= keyword argument<\/a><\/li>\n<li><a href=\"#a-note-about-python-2\">A Note about Python 2<\/a><\/li>\n<li><a href=\"#a-sad-imitation\">A Sad Imitation<\/a><\/li>\n<li><a href=\"#the-pprint-function\">The pprint Function<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"the-basics\">The Basics<a class=\"headerlink\" href=\"#the-basics\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The basic premise of the <code>print<\/code> function is quite, well, basic. It prints out the given arguments\nto the standard output.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Hello world!&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Hello world!\n<\/span><\/code><\/pre><\/div>\n\n<p>Calling it with multiple arguments:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;hello&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;world&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints:<\/p>\n<div class=\"hl\"><pre class=content><code><span>hello world\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice that the two strings, <code>\"hello\"<\/code> and <code>\"world\"<\/code> have a space character printed between them.\nThe <code>print<\/code> function is helpful like that. By default, it places a space between every pair of\nconsecutive arguments to be printed.<\/p>\n<p>It doesn&rsquo;t have to be strings either:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"mi\">42<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;is the answer&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints:<\/p>\n<div class=\"hl\"><pre class=content><code><span>42 is the answer\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s look at each of these features in detail and see how they work.<\/p>\n<h2 id=\"handling-of-multiple-arguments\">Handling of Multiple Arguments<a class=\"headerlink\" href=\"#handling-of-multiple-arguments\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>print<\/code> function accepts arbitrary number of arguments to be printed. These arguments can&rsquo;t be\nkeyword-arguments, because that doesn&rsquo;t make much sense. That&rsquo;s not to say the <code>print<\/code> function\ndoesn&rsquo;t accept any keyword arguments, it does. In fact, the space character that shows up between\nthe arguments to be printed, can be changed by providing the <code>sep=<\/code> keyword argument.<\/p>\n<p>Let&rsquo;s look at the following examples:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;the&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;world&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;is&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;a&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;cruel&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;place&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">the world is a cruel place<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;the&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;world&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;is&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;a&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;cruel&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;place&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">sep<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;-&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">the-world-is-a-cruel-place<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;the&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;world&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;is&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;a&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;cruel&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;place&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">sep<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">theworldisacruelplace<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In the first example, we don&rsquo;t explicitly give any value to the <code>sep=<\/code> keyword argument. So it takes\nit&rsquo;s default value of the space character <code>\" \"<\/code>. In the second example, we set it to the dash\ncharacter <code>\"-\"<\/code> and we can see in the output that the strings are printed joined by dashes.<\/p>\n<p>In the third example, we set the <code>sep=<\/code> to an empty string so the output is all the words printed\nconsecutively making it a cruel experience to read the text.<\/p>\n<p>The <code>sep=<\/code> argument can be any string, it doesn&rsquo;t have to be a single character and it can contain\nnewlines and any other shenanigans too.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;the&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;birds&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;in&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;the&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;sky&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">sep<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">  hammertime<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints the following mind bogglingly useful output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>the\n<\/span><span>  hammertime\n<\/span><span>birds\n<\/span><span>  hammertime\n<\/span><span>in\n<\/span><span>  hammertime\n<\/span><span>the\n<\/span><span>  hammertime\n<\/span><span>sky\n<\/span><\/code><\/pre><\/div>\n\n<p>Yeah, that&rsquo;s a useful trick, but please, consider people&rsquo;s sanity when you do such !@#$.<\/p>\n<h2 id=\"handling-of-non-string-types\">Handling of non-string types<a class=\"headerlink\" href=\"#handling-of-non-string-types\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We know that the <code>print<\/code> function can handle printing objects of any type, not just strings. But how\ndoes that work? The simple answer to this is that <code>print<\/code> will call <code>str<\/code> on non-string objects, and\nprint the result of that call.<\/p>\n<p>Let&rsquo;s experiment with this. Consider the following class definition, which has just one method, the\n<code>__str__<\/code>. If you are unaware of this method, this is what&rsquo;s called when <code>str<\/code> is applied on an\ninstance of this class. I won&rsquo;t go into details of that as that&rsquo;s not the topic of this article.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">class<\/span> <span class=\"nc\">Tantrum<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__str__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"s2\">&quot;awesome __str__ of object <\/span><span class=\"si\">%r<\/span><span class=\"s2\">&quot;<\/span> <span class=\"o\">%<\/span> <span class=\"nb\">id<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">Tantrum<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The output of running this would be something like (the number in the end would obviously be\ndifferent if you run this script):<\/p>\n<div class=\"hl\"><pre class=content><code><span>awesome __str__ of object 4508612624\n<\/span><\/code><\/pre><\/div>\n\n<p>So, what happens if our class doesn&rsquo;t define an implementation for the <code>__str__<\/code> method? Let&rsquo;s try\nthat out:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">class<\/span> <span class=\"nc\">LazySloth<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">pass<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">LazySloth<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints the following output (again, the number in the end would obviously be different for\nyou):<\/p>\n<div class=\"hl\"><pre class=content><code><span>&lt;__main__.LazySloth object at 0x105f327d0&gt;\n<\/span><\/code><\/pre><\/div>\n\n<p>Turns out that when there&rsquo;s no implementation for <code>__str__<\/code>, calling <code>str<\/code> on the instance will\nstill produce some information regarding the instance, which is what we got above.<\/p>\n<p>A neat thing here is that this output is actually what calling <code>repr<\/code> on the instance would produce.\nSo, it looks like <code>str<\/code> is falling back to returning the output of <code>repr<\/code>, when there&rsquo;s no\nimplementation for <code>__str__<\/code> provided. Let&rsquo;s confirm this by defining a <code>__repr__<\/code> method:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">class<\/span> <span class=\"nc\">RatInFormals<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__repr__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"s2\">&quot;a sad overridden __repr__ for instance <\/span><span class=\"si\">%r<\/span><span class=\"s2\">&quot;<\/span> <span class=\"o\">%<\/span> <span class=\"nb\">id<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">RatInFormals<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints the following output (again, the number will be different for you):<\/p>\n<div class=\"hl\"><pre class=content><code><span>a sad overridden __repr__ for instance 4313389264\n<\/span><\/code><\/pre><\/div>\n\n<p>Now we get the output of the overridden <code>__repr__<\/code>.<\/p>\n<p>So here&rsquo;s how it works. The <code>print<\/code> function calls <code>str<\/code> on any non-string objects, which returns\nthe result of the <code>__str__<\/code> method, if available, or the result of calling <code>repr<\/code> on the instance,\nwhich in turn returns the result of the <code>__repr__<\/code> method, which results in a generic output unless\noverridden (like in the last example above).<\/p>\n<p>This should be case in favor towards spending a few seconds thinking about and writing useful\n<code>__str__<\/code> methods for your custom types. Someone walking along working with your code later on,\nmight just print an instance of your class to see what&rsquo;s in it, and the generic output with the\ninstance&rsquo;s <code>id<\/code> is unlikely to be very helpful.<\/p>\n<h2 id=\"write-to-files\">Write to files<a class=\"headerlink\" href=\"#write-to-files\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Another keyword argument accepted by <code>print<\/code> is <code>file=<\/code>. This can be set to a <code>file<\/code> object, in\nwhich case the <em>printing<\/em> will be done to that file object instead of standard output.<\/p>\n<p>Let&rsquo;s try writing text to a file using the <code>print<\/code> function like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;outputs.txt&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;w&quot;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Stuff that doesn&#39;t show up in standard output&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"o\">=<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Running this script obviously doesn&rsquo;t print anything to the standard output. Instead, a file\n&ldquo;outputs.txt&rdquo; is created which contains the following text:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Stuff that doesn&#39;t show up in standard output\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that since we are opening the file with mode as <code>\"w\"<\/code>, so if a file named &ldquo;outputs.txt&rdquo; already\nexists in the current folder, it <strong>will be overwritten<\/strong>.<\/p>\n<h3 id=\"using-sysstderr\">Using <code>sys.stderr<\/code><a class=\"headerlink\" href=\"#using-sysstderr\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <a href=\"https:\/\/docs.python.org\/3\/library\/sys.html#sys.stderr\" rel=\"noopener noreferrer\" target=\"_blank\"><code>sys.stderr<\/code><\/a> object in the <code>sys<\/code> module is a file-like object that represents the\nstandard error. Writing to this file-like object directs it to the standard error stream. This is\nsimilar to the <a href=\"https:\/\/docs.python.org\/3\/library\/sys.html#sys.stdout\" rel=\"noopener noreferrer\" target=\"_blank\"><code>sys.stdout<\/code><\/a> object which represents the standard output stream, in a\nsimilar fashion.<\/p>\n<p>The <code>file=<\/code> keyword argument can be set to <code>sys.stderr<\/code> which will print to the standard error\nstream.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;stuff going to standard error&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"o\">=<\/span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stderr<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>You might not notice any difference from setting the <code>file=<\/code> argument in the above script, but if\nyou are running a terminal emulator \/ shell that shows standard error in red color, then you&rsquo;ll be\nable to see a difference.<\/p>\n<h3 id=\"modifying-sysstdout\">Modifying <code>sys.stdout<\/code><a class=\"headerlink\" href=\"#modifying-sysstdout\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>If we don&rsquo;t set a value explicitly to the <code>file=<\/code> argument, the output will be sent to the standard\noutput. There&rsquo;s a small note to that point to be observed. In reality, the output will be sent to\nthe <code>sys.stdout<\/code> file object. Usually, these two are the same. But, of course, we can set\n<code>sys.stdout<\/code> to something else.<\/p>\n<p>Consider the following script which changes the value of <code>sys.stdout<\/code>, prints something, and then\nrestores the value of <code>sys.stdout<\/code> to its original value.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">original_stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span>\n<\/span><span><span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;out.txt&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;w&quot;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">f<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;trololololol&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">original_stdout<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;restored&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>If we run this script, we&rsquo;ll only see <code>restored<\/code> in the output, but the file <code>out.txt<\/code> will be\ncreated with the output from line 6.<\/p>\n<p>A minor point to note here is that it&rsquo;s probably incorrect to say <em>&ldquo;the default value of the <code>file<\/code>\nargument is <code>sys.stdout<\/code>&ldquo;<\/em>. Since if that were the case, changing the value of <code>sys.stdout<\/code> should\nnot affect the <code>print<\/code> function. Instead, I believe its default value is <code>None<\/code> and in that case,\n<code>print<\/code> uses the current value of <code>sys.stdout<\/code>.<\/p>\n<p>We can verify this by explicitly passing in <code>None<\/code> to the <code>file=<\/code> argument:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">original_stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span>\n<\/span><span><span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;out.txt&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;w&quot;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">f<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;trololololol&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">original_stdout<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;restored&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The above script produces the exact same output as when we didn&rsquo;t provide the <code>file=<\/code> argument\nexplicitly.<\/p>\n<h3 id=\"collecting-with-iostringio\">Collecting with <code>io.StringIO<\/code><a class=\"headerlink\" href=\"#collecting-with-iostringio\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <a href=\"https:\/\/docs.python.org\/3\/library\/io.html#io.StringIO\" rel=\"noopener noreferrer\" target=\"_blank\"><code>io.StringIO<\/code><\/a> can be used to create a file object that collects all that is\nwritten to it, and then get it all out as a string. This is useful when calling a function that\nprints information using the <code>print<\/code> function, but instead, we want that output as a string for\nfurther processing. We can replace <code>sys.stdout<\/code> with a <code>io.StringIO<\/code> instance before calling that\nfunction, and then restore it after. Here&rsquo;s how this might look like:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">io<\/span><span class=\"o\">,<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">print_product<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">original_stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span>\n<\/span><span><span class=\"n\">string_io<\/span> <span class=\"o\">=<\/span> <span class=\"n\">io<\/span><span class=\"o\">.<\/span><span class=\"n\">StringIO<\/span><span class=\"p\">()<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">string_io<\/span>\n<\/span><span><span class=\"n\">print_product<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">original_stdout<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"n\">string_io<\/span><span class=\"o\">.<\/span><span class=\"n\">getvalue<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Result is&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">result<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this script, the <code>print_product<\/code> function prints the result of the multiplication, instead of\nreturning it. So to get the result out of it, we replace <code>sys.stdout<\/code> with a <code>io.StringIO<\/code> instance\nand after calling the <code>print_product<\/code> function, we get the printed result using the <code>.getvalue()<\/code>\nmethod.<\/p>\n<p>However, note that a similar operation with binary data using <code>io.BytesIO<\/code> is not possible, since\nthe <code>print<\/code> function converts all its argument to text before writing to the file.<\/p>\n<h2 id=\"the-end-keyword-argument\">The <code>end=<\/code> keyword argument<a class=\"headerlink\" href=\"#the-end-keyword-argument\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is like one of those things that we notice only when it&rsquo;s taken away. The <code>print<\/code> function\nappends a newline at the end of the last argument to be printed. Check out the following example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;hello on day 1&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;yeah right on day 2&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;oh to hell with you on day 3&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The output of this script is the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span>hello on day 1\n<\/span><span>yeah right on day 2\n<\/span><span>oh to hell with you on day 3\n<\/span><\/code><\/pre><\/div>\n\n<p>The output from the three <code>print<\/code> calls shows up in three separate lines, nice and neat. But we\nnever gave a <code>\"\\n\"<\/code> in our calls to <code>print<\/code>. It comes from the default value of the <code>end=<\/code> argument\nof the <code>print<\/code> function. If we set the <code>end=<\/code> argument to something else, it will replace the\nnewline in the end of the output from a <code>print<\/code> call.<\/p>\n<p>Check out the following script for example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Doing awesome stuff... &quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">end<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"c1\"># do awesome stuff here<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;done&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This script prints the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Doing awesome stuff... done\n<\/span><\/code><\/pre><\/div>\n\n<p>The output of the two <code>print<\/code> calls shows up on the same line, since we suppressed the newline that\nwould&rsquo;ve been printed from the first call to <code>print<\/code>, by setting the <code>end=<\/code> argument to an empty\nstring. The second call to <code>print<\/code> will continue this sentence and finish the line by adding a\nnewline at the end.<\/p>\n<h2 id=\"a-note-about-python-2\">A Note about Python 2<a class=\"headerlink\" href=\"#a-note-about-python-2\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python 2 had a <code>print<\/code> <strong>statement<\/strong>, which worked similar to the <code>print<\/code> <strong>function<\/strong> in Python 3,\nbut is not as feature-rich. Additionally, being a statement, it couldn&rsquo;t be used in all the places,\nfor example, within in a lambda expression.<\/p>\n<p>However, Python 2.6 introduced a <a href=\"https:\/\/docs.python.org\/2\/library\/__future__.html\" rel=\"noopener noreferrer\" target=\"_blank\">future import<\/a> that brought the <code>print<\/code> function to Python 2.\nAdding a <code>from __future__ import print_function<\/code> line at the start of a Python 2 file would disable\nthe <code>print<\/code> statement in that file and turn <code>print<\/code> into a function. This can be very useful for\nwhen migrating to Python 3.<\/p>\n<h2 id=\"a-sad-imitation\">A Sad Imitation<a class=\"headerlink\" href=\"#a-sad-imitation\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here&rsquo;s a sad little imitation of the <code>print<\/code> function that should behave similar to the builtin in\nmost of the features that have been discussed in this article:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">sad_print<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"n\">sep<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot; &quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">end<\/span><span class=\"o\">=<\/span><span class=\"s2\">&quot;<\/span><span class=\"se\">\\n<\/span><span class=\"s2\">&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"p\">(<\/span><span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span> <span class=\"k\">if<\/span> <span class=\"n\">file<\/span> <span class=\"ow\">is<\/span> <span class=\"kc\">None<\/span> <span class=\"k\">else<\/span> <span class=\"n\">file<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">write<\/span><span class=\"p\">(<\/span><span class=\"n\">sep<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">args<\/span><span class=\"p\">))<\/span> <span class=\"o\">+<\/span> <span class=\"n\">end<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">sad_print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;the answer is&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">42<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this <code>sad_print<\/code> function, what we are essentially doing is:<\/p>\n<ol>\n<li>Pick <code>sys.stdout<\/code> if <code>file<\/code> is <code>None<\/code>.<\/li>\n<li>Call <code>str<\/code> on all of the provided arguments.<\/li>\n<li>Join the results of the calls to <code>str<\/code> using the value of <code>sep<\/code>.<\/li>\n<li>Concatenate the value of <code>end<\/code> to the result of above step.<\/li>\n<li>Call write on result of point-1, with the result of the above step.<\/li>\n<\/ol>\n<p>I&rsquo;m sure the <code>print<\/code> builtin does quite a bit more than just this one-liner, but doing this can give\nus some perspective of how all the different pieces fit in together.<\/p>\n<h2 id=\"the-pprint-function\">The <code>pprint<\/code> Function<a class=\"headerlink\" href=\"#the-pprint-function\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python&rsquo;s standard library has a <a href=\"https:\/\/docs.python.org\/3\/library\/pprint.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>pprint<\/code><\/a> module, with a <code>pprint<\/code> function that takes one\nargument, and prints it <em>prettily<\/em>.<\/p>\n<p>For example, consider the following script:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">pprint<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pprint<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">numbers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">numbers<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">numbers<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">planets<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s2\">&quot;Mercury&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Venus&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Earth&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Mars&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Jupiter&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Saturn&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Uranus&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Neptune&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;Pluto&quot;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">planets<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">planets<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We are calling <code>print<\/code> and <code>pprint<\/code> on the same list of strings. Let&rsquo;s look at the output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>[1, 2, 3, 4, 5, 6]\n<\/span><span>[1, 2, 3, 4, 5, 6]\n<\/span><span>[&#39;Mercury&#39;, &#39;Venus&#39;, &#39;Earth&#39;, &#39;Mars&#39;, &#39;Jupiter&#39;, &#39;Saturn&#39;, &#39;Uranus&#39;, &#39;Neptune&#39;, &#39;Pluto&#39;]\n<\/span><span>[&#39;Mercury&#39;,\n<\/span><span> &#39;Venus&#39;,\n<\/span><span> &#39;Earth&#39;,\n<\/span><span> &#39;Mars&#39;,\n<\/span><span> &#39;Jupiter&#39;,\n<\/span><span> &#39;Saturn&#39;,\n<\/span><span> &#39;Uranus&#39;,\n<\/span><span> &#39;Neptune&#39;,\n<\/span><span> &#39;Pluto&#39;]\n<\/span><\/code><\/pre><\/div>\n\n<p>As we can see, the output from <code>pprint<\/code> is prettified, but only if necessary. In the first case,\nwhere we were printing just six numbers, the output was fine as a single line so <code>pprint<\/code> did not\ncut it up into several lines. But in the second case, the line ends up too long and it may not be\ncomfortable on small terminal screens. So, it cuts it up.<\/p>\n<p>The <code>pprint<\/code> module can be useful to prettily print (or formatting) lists and dictionaries. Check\nout its official documentation for more information.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>We may not use all these features of the <code>print<\/code> functions all the time, but I think it&rsquo;s useful to\nknow that <code>print<\/code> is not just a function that prints the given string. It&rsquo;s quite a bit more than\nthat; and when we need it, it&rsquo;s there without having to import anything. Thank you for reading!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"print-function"}},{"@attributes":{"term":"tutorial"}}]},{"title":"Dependency Injection In Python","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/dependency-injection-in-python\/","rel":"alternate"}},"published":"2020-03-29T00:00:00+05:30","updated":"2020-03-29T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-03-29:\/posts\/dependency-injection-in-python\/","summary":"<p>I chose a form of dependency injection (DI) as the solution to a recent problem I needed to solve.\nThis is a quick write-up of how I did it in Python, using the standard library modules.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#the-problem\">The Problem<\/a><\/li>\n<li><a href=\"#the-legacy-solution\">The Legacy Solution<\/a><\/li>\n<li><a href=\"#the-new-di-solution\">The New DI Solution<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"the-problem\">The \u2026<\/h2>","content":"<p>I chose a form of dependency injection (DI) as the solution to a recent problem I needed to solve.\nThis is a quick write-up of how I did it in Python, using the standard library modules.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#the-problem\">The Problem<\/a><\/li>\n<li><a href=\"#the-legacy-solution\">The Legacy Solution<\/a><\/li>\n<li><a href=\"#the-new-di-solution\">The New DI Solution<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"the-problem\">The Problem<a class=\"headerlink\" href=\"#the-problem\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I&rsquo;ll be illustrating the problem in a slightly different context, so I don&rsquo;t derail too much into\nthe subject, which would just be a distraction. So, if the problem feels unrealistic or stupid,\nthat&rsquo;s just a result of my unimaginative thinking.<\/p>\n<p>We have an application, let&rsquo;s call it the task runner, that lets users choose a task to run, and\nruns that task. Each such task is implemented as a separate Python script file, that take no user\ninputs, but do connect to a database and a few REST endpoints.<\/p>\n<p>So this is how it works. We have a bunch of wrapper classes that provide high-level abstractions for\nthe database and the REST endpoints. Instances of these classes are given to the task scripts, which\nuse them to perform their task.<\/p>\n<p>The task scripts are also expected to <em>return<\/em> some information back to our application, with\ndetails such as whether the task was successful or the reasons if there&rsquo;s an error etc. The approach\nfor how this is done is detailed in the following Solution section(s).<\/p>\n<h2 id=\"the-legacy-solution\">The Legacy Solution<a class=\"headerlink\" href=\"#the-legacy-solution\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The current way this is working (which I took the liberty to call <em>The Legacy Solution<\/em>) is that\nwhen a user requests for a specific task to be run, the application reads up the relevant Python\nscript file and calls <code>eval<\/code> on the contents. A pre-made dictionary holding all the instances of\nhigh-level abstractions is provided in the global scope of this call to <code>eval<\/code>.<\/p>\n<p>This has been working well for several years now and, although it feels dirty in hindsight, there\nwere probably good reasons it was done this way:<\/p>\n<ol>\n<li>It was very simple and easy to implement. There&rsquo;s little to no magic.<\/li>\n<li>The task scripts can be updated on production without restarting the application and the changes\n   would take effect immediately.<\/li>\n<li>The scripts&rsquo; logic can be written as module level code. Full freedom on how the code is\n   structured and written.<\/li>\n<\/ol>\n<p>Arguing on how horrible this approach is would be a great topic for a heated debate, and,\nfortunately that&rsquo;s not what I set to write about here. This simple method, while worked, didn&rsquo;t\nscale with the team. We soon decided to move to a more sophisticated approach and so started\nlooking.<\/p>\n<p>A major reason (among several) for this decision was to have the scripts not depend on implicit\nglobals. The use of implicit globals meant that the scripts were using variables that appear as not\ndefined to static code analyzers. Additionally, since the script file was being read into a string\nand <code>eval<\/code>-ed, the stack trace from any errors were not very helpful.<\/p>\n<h2 id=\"the-new-di-solution\">The New DI Solution<a class=\"headerlink\" href=\"#the-new-di-solution\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In the new proposed way for this to work, we have made three critical changes:<\/p>\n<ol>\n<li>The Python script files will be <code>import<\/code>-ed as Python modules, and the <code>task_main<\/code> function at\n   the module level will be called to run the task.<\/li>\n<li>Nothing is implicitly injected into the script&rsquo;s global scope.<\/li>\n<li>Access to the API abstractions is done through a form of dependency injection.<\/li>\n<\/ol>\n<p>In the task scripts, we have a function defined like the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">task_main<\/span><span class=\"p\">(<\/span><span class=\"n\">users_service<\/span><span class=\"p\">,<\/span> <span class=\"n\">sales_service<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"c1\"># do something with `users_service` and `sales_service`.<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, the <code>task_main<\/code> function is defined to accept two arguments. The <code>users_service<\/code> and\n<code>sales_service<\/code>. In our task runner application, we use the <code>inspect<\/code> module to identify the\nabstractions being used in <code>task_main<\/code> and pass them accordingly. Here&rsquo;s how it works:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">importlib<\/span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">inspect<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">run_task_script<\/span><span class=\"p\">(<\/span><span class=\"n\">script<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">module_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">script<\/span><span class=\"o\">.<\/span><span class=\"n\">replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;.py&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">module<\/span> <span class=\"o\">=<\/span> <span class=\"n\">importlib<\/span><span class=\"o\">.<\/span><span class=\"n\">import_module<\/span><span class=\"p\">(<\/span><span class=\"n\">module_name<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"n\">inspect<\/span><span class=\"o\">.<\/span><span class=\"n\">signature<\/span><span class=\"p\">(<\/span><span class=\"n\">module<\/span><span class=\"o\">.<\/span><span class=\"n\">task_main<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">parameters<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">kwargs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">name<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">kwargs<\/span><span class=\"p\">[<\/span><span class=\"n\">name<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">get_service_instance<\/span><span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">module<\/span><span class=\"o\">.<\/span><span class=\"n\">task_main<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">kwargs<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">record_task_response<\/span><span class=\"p\">(<\/span><span class=\"n\">response<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this function, we first convert the script file name into it&rsquo;s module name (hoping it doesn&rsquo;t\ncontain any spaces or dash characters). Then, we use the <code>importlib<\/code> module to import the module of\nthat name. Next, we call <code>inspect.signature<\/code> function on the module&rsquo;s <code>task_main<\/code> function to get\nits parameter names.<\/p>\n<p>Based on these argument names (in <code>args<\/code>), we then construct a dictionary with these names as keys\nand the instance of the API abstraction class, as the value. We then pass this as the keyword\narguments to the call to <code>module.task_main<\/code>.<\/p>\n<p>In this way, the scripts don&rsquo;t assume any implicit globals and the <code>task_main<\/code> accepts arguments\nthat it needs and no more. This makes the code much cleaner and easier to do static analysis on.\nBesides, since we import the module and call a function in it, we get nicer stack traces when\nthere&rsquo;s an exception.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I&rsquo;m sure there&rsquo;s better, and more involved implementations of doing DI in Python, but what we&rsquo;ve\ndone above is enough for the target problem. Additionally, it&rsquo;s just using the standard library, so,\nextra brownie points for that!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"python-importlib"}},{"@attributes":{"term":"python-inspect"}},{"@attributes":{"term":"reflection"}}]},{"title":"The Magic of AutoHotkey \u2014 Part 2","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-magic-of-autohotkey-2\/","rel":"alternate"}},"published":"2020-03-22T00:00:00+05:30","updated":"2020-03-22T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-03-22:\/posts\/the-magic-of-autohotkey-2\/","summary":"<p>In the previous part of <a href=\"..\/the-magic-of-autohotkey\/\">The Magic of AutoHotkey<\/a>, we looked at automating small\npieces of routine tasks with various applications, as well as identifying things that could be done\nbetter with a quick hotkey. This is the next chapter of the story. In this article, I&rsquo;ll show you \u2026<\/p>","content":"<p>In the previous part of <a href=\"..\/the-magic-of-autohotkey\/\">The Magic of AutoHotkey<\/a>, we looked at automating small\npieces of routine tasks with various applications, as well as identifying things that could be done\nbetter with a quick hotkey. This is the next chapter of the story. In this article, I&rsquo;ll show you\nhow I tamed the stock file explorer as well as connecting to office applications with OLE to provide\nadditional rich functionality.<\/p>\n<p>This article is part of a series:<\/p>\n<ol>\n<li><a href=\"..\/the-magic-of-autohotkey\/\">Part 1<\/a><\/li>\n<li>Part 2 (this article).<\/li>\n<\/ol>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#file-explorer-magic\">File Explorer Magic<\/a><ul>\n<li><a href=\"#focus-location-editor\">Focus Location Editor<\/a><\/li>\n<li><a href=\"#open-command-window\">Open Command Window<\/a><\/li>\n<li><a href=\"#folder-shortcuts\">Folder Shortcuts<\/a><\/li>\n<li><a href=\"#better-hotkeys-for-directional-navigation\">Better Hotkeys for Directional Navigation<\/a><\/li>\n<li><a href=\"#select-files-by-pattern\">Select Files by Pattern<\/a><\/li>\n<li><a href=\"#batch-rename\">Batch Rename<\/a><\/li>\n<li><a href=\"#copy-paths-of-selected-files\">Copy Paths of Selected Files<\/a><\/li>\n<li><a href=\"#copy-contents-of-selected-files\">Copy Contents of Selected Files<\/a><\/li>\n<li><a href=\"#create-file-with-clipboard-contents\">Create File with Clipboard Contents<\/a><\/li>\n<li><a href=\"#create-folder-hierarchy-and-enter-it\">Create Folder Hierarchy and Enter it<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#email-selected-files-with-outlook\">Email Selected File(s) with Outlook<\/a><ul>\n<li><a href=\"#global-hotkey-for-new-mail\">Global Hotkey for New Mail<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"file-explorer-magic\">File Explorer Magic<a class=\"headerlink\" href=\"#file-explorer-magic\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The file explorer is probably my most used application during work. Yet, it doesn&rsquo;t feel like it&rsquo;s\ntuned for a power user. Maybe that&rsquo;s also why <a href=\"https:\/\/www.xyplorer.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">there&rsquo;s<\/a> <a href=\"https:\/\/www.zabkat.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">so<\/a> <a href=\"https:\/\/www.gpsoft.com.au\/\" rel=\"noopener noreferrer\" target=\"_blank\">many<\/a>\n<a href=\"https:\/\/www.ghisler.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">alternatives<\/a> to file explorers. I&rsquo;ve tried a few of them in the past, but the best has\nbeen to add exactly the few things I needed in the native file explorer, using AutoHotkey. I&rsquo;ll run\nthrough those here.<\/p>\n<p>As is the case in the previous part, I have a module called <code>file-explorer-tweaks.ahk<\/code> which is\n<code>#Include<\/code>-ed in my master script.<\/p>\n<p>To start, we define a window group, which includes all file explorer windows. We later use this\ngroup to define hotkeys that we want to work <em>only<\/em> on the file explorer windows.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">FileListers<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">CabinetWClass<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">FileListers<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">WorkerW<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">FileListers<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">#32770<\/span><span class=\"p\">,<\/span> <span class=\"n\">ShellView<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This group now matches the file explorer windows, desktop and the file open dialog windows.<\/p>\n<h3 id=\"focus-location-editor\">Focus Location Editor<a class=\"headerlink\" href=\"#focus-location-editor\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Almost all the web browsers today have the default hotkey <kbd>^l<\/kbd> which focuses the location\nbar, and selects everything in it. But in the file explorer, this is <kbd>!d<\/kbd>. Habits rule and\nI constantly hit <kbd>^l<\/kbd> in the file explorer window when I wanted to change something in the\nlocation bar. Obviously, it didn&rsquo;t work, and it would drive me crazy. Until I added the following to\nsave me from insanity:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">l<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span> <span class=\"o\">!<\/span><span class=\"n\">d<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>While this works fine on the face of it, if I hit <kbd>Escape<\/kbd> after focusing the location bar\nlike this, the focus is not returned to the file list. I haven&rsquo;t figured out a solution to that yet,\nso that one&rsquo;s open.<\/p>\n<h3 id=\"open-command-window\">Open Command Window<a class=\"headerlink\" href=\"#open-command-window\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The file explorer has a nice less-known trick. If I right-click without any files selected and with\nthe <kbd>Shift<\/kbd> key held down, I get an extra option in the context menu, called &ldquo;Open command\nwindow here&rdquo;. Clicking on that menu item will open a new command prompt window in the current\ndirectory. This is extremely convenient if you need the command window often (which you might,\nespecially if you&rsquo;re a software developer).<\/p>\n<p>But this needed the mouse. I wanted to do this with the keyboard. Turns out it&rsquo;s easier than one\nmight think:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^!<\/span><span class=\"n\">t<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span> <span class=\"o\">!<\/span><span class=\"n\">dcmd<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, we define the <kbd>^!t<\/kbd> hotkey which will focus the location bar and type in <code>cmd<\/code> and\nhit the <kbd>Enter<\/kbd> key. This will actually open up a command window <em>in the current\ndirectory<\/em>.<\/p>\n<h3 id=\"folder-shortcuts\">Folder Shortcuts<a class=\"headerlink\" href=\"#folder-shortcuts\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Folder shortcuts is where I define a hotkey that will navigate to a specific directory, always. For\nexample, while in a file explorer, hitting <kbd>^h<\/kbd> should navigate to the home folder, hitting\n<kbd>^j<\/kbd> should navigate to the Downloads folder (this key opens the downloads view in web\nbrowsers, see what I did there?).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">h<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">d<\/span><span class=\"nv\">%homedir%<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">j<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">d<\/span><span class=\"nv\">%homedir%<\/span>\\<span class=\"n\">Downloads<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">y<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">dLibraries<\/span>\\<span class=\"n\">Documents<\/span><span class=\"p\">{<\/span><span class=\"n\">enter<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">k<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">dC<\/span><span class=\"o\">:<\/span>\\<span class=\"n\">work<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">t<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">dC<\/span><span class=\"o\">:<\/span>\\<span class=\"n\">tools<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">b<\/span><span class=\"o\">::<\/span><span class=\"n\">Send<\/span> <span class=\"o\">!<\/span><span class=\"n\">dC<\/span><span class=\"o\">:<\/span>\\<span class=\"n\">labs<\/span><span class=\"p\">{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This snippet uses the <code>homedir<\/code> variable defined in the <a href=\"..\/the-magic-of-autohotkey\/#the-setup\">previous article<\/a>.<\/p>\n<p>On the face of it, these are very simple hotkeys. We pass <kbd>!d<\/kbd> to focus the location input\nand type in the location where we want to go to. Simple &amp; effective. They serve sort of like quick\naccess bookmarks and are probably my most used hotkeys defined with AutoHotkey overall, by a margin.<\/p>\n<h3 id=\"better-hotkeys-for-directional-navigation\">Better Hotkeys for Directional Navigation<a class=\"headerlink\" href=\"#better-hotkeys-for-directional-navigation\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>In the previous section, we dealt with navigating to absolution locations. But how about directional\nnavigation, where we want to go back or forward or even up the directory chain?<\/p>\n<p>The default hotkeys for this leverage the arrow keys, which require taking my hands off the\nkeyboard&rsquo;s home row. So, I&rsquo;m using the following keys for these three operations, which are inspired\nby similar behavior in Vim (again!).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\">; Navigate with the keyboard better!<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">o<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Left<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">i<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Right<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">u<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Up<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>To top it, I have also defined mouse &ldquo;hotkeys&rdquo; for these three actions. I rarely use these nowadays,\nbut they&rsquo;re still there for when I already have a hand on the mouse.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\">; Navigate with the mouse!<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">!<\/span><span class=\"n\">WheelUp<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Up<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">WheelUp<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Left<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">WheelDown<\/span><span class=\"o\">::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"o\">!<\/span><span class=\"p\">{<\/span><span class=\"n\">Right<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Pretty self-explanatory really.<\/p>\n<h3 id=\"select-files-by-pattern\">Select Files by Pattern<a class=\"headerlink\" href=\"#select-files-by-pattern\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>I particularly love this one. When I trigger this hotkey, a little prompt shows up where I enter a\nregular expression and then every file in the current folder that matches this pattern will be\nselected. The first time I used this on a folder with ~300 files, I practically had tears in my eyes\nat how easy it was to make the file selection by a pattern.<\/p>\n<p>So, here&rsquo;s the code for this:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-4><label for=co-4><span class='btn show-full-code-btn'>Show remaining 16 lines<\/span><\/label><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><\/pre><pre class=content><code><span><span class=\"c1\">; Get selected files in explorer and more:<\/span>\n<\/span><span><span class=\"c1\">; http:\/\/www.autohotkey.com\/board\/topic\/60985-get-paths-of-selected-items-in-an-explorer-window\/<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">s<\/span><span class=\"o\">::<\/span>\n<\/span><span><span class=\"n\">SelectByRegEx<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">static<\/span> <span class=\"n\">selectionPattern<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>    <span class=\"nb\">WinGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">wx<\/span><span class=\"p\">,<\/span> <span class=\"n\">wy<\/span>\n<\/span><span>    <span class=\"nb\">ControlGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">cx<\/span><span class=\"p\">,<\/span> <span class=\"n\">cy<\/span><span class=\"p\">,<\/span> <span class=\"n\">cw<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">DirectUIHWND3<\/span>\n<\/span><span>    <span class=\"n\">x<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cw<\/span><span class=\"o\">\/<\/span><span class=\"mi\">2<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">200<\/span>\n<\/span><span>    <span class=\"n\">y<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wy<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cy<\/span>\n<\/span><span>    <span class=\"nb\">InputBox<\/span><span class=\"p\">,<\/span> <span class=\"n\">selectionPattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">Select<\/span> <span class=\"n\">by<\/span> <span class=\"n\">regex<\/span>\n<\/span><span>        <span class=\"p\">,<\/span> <span class=\"n\">Enter<\/span> <span class=\"n\">regex<\/span> <span class=\"n\">pattern<\/span> <span class=\"n\">to<\/span> <span class=\"n\">select<\/span> <span class=\"n\">files<\/span> <span class=\"n\">that<\/span> <span class=\"n\">CONTAIN<\/span> <span class=\"n\">it<\/span> <span class=\"p\">(<\/span><span class=\"n\">Empty<\/span> <span class=\"n\">to<\/span> <span class=\"n\">select<\/span> <span class=\"n\">all<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"mi\">400<\/span><span class=\"p\">,<\/span> <span class=\"mi\">150<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%x%<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%y%<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"nv\">%selectionPattern%<\/span>\n<\/span><span>    <span class=\"nb\">if <\/span><span class=\"nv\">ErrorLevel<\/span>\n<\/span><span>        <span class=\"nb\">Return<\/span>\n<\/span><span>    <span class=\"n\">for<\/span> <span class=\"n\">window<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">ComObjCreate<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Shell.Application&quot;<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">Windows<\/span>\n<\/span><span>        <span class=\"nb\">if <\/span><span class=\"nf\">WinActive<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;ahk_id &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">hwnd<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>            <span class=\"n\">pattern<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;S)&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">selectionPattern<\/span>\n<\/span><span>            <span class=\"n\">items<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">document<\/span><span class=\"o\">.<\/span><span class=\"n\">Folder<\/span><span class=\"o\">.<\/span><span class=\"n\">Items<\/span>\n<\/span><span>            <span class=\"n\">total<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">items<\/span><span class=\"o\">.<\/span><span class=\"n\">Count<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>            <span class=\"n\">i<\/span> <span class=\"o\">:=<\/span> <span class=\"mi\">0<\/span>\n<\/span><span class=collapse>            <span class=\"n\">showProgress<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">total<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">160<\/span>\n<\/span><span class=collapse>            <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">showProgress<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>                <span class=\"nb\">Progress<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span> <span class=\"n\">w200<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">Matching<\/span><span class=\"o\">...<\/span>\n<\/span><span class=collapse>            <span class=\"n\">for<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">items<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>                <span class=\"n\">match<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">,<\/span> <span class=\"n\">pattern<\/span><span class=\"p\">)<\/span> <span class=\"o\">?<\/span> <span class=\"mi\">17<\/span> <span class=\"o\">:<\/span> <span class=\"mi\">0<\/span>\n<\/span><span class=collapse>                <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">document<\/span><span class=\"o\">.<\/span><span class=\"n\">SelectItem<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">,<\/span> <span class=\"n\">match<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>                <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">showProgress<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>                    <span class=\"n\">i<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">i<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">100<\/span>\n<\/span><span class=collapse>                    <span class=\"nb\">Progress<\/span><span class=\"p\">,<\/span> <span class=\"o\">%<\/span> <span class=\"n\">i<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">total<\/span>\n<\/span><span class=collapse>                <span class=\"p\">}<\/span>\n<\/span><span class=collapse>            <span class=\"p\">}<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">Break<\/span>\n<\/span><span class=collapse>        <span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Progress<\/span><span class=\"p\">,<\/span> <span class=\"n\">Off<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The code is not very pretty, but oh well. It works well, and I&rsquo;d rather not touch it.<\/p>\n<p>Here&rsquo;s a little <strong>mute<\/strong> video recording of this at work:<\/p>\n<video controls=\"\" muted=\"\" playsinline=\"\" preload=\"\" src=\"https:\/\/sharats.me\/static\/autohotkey-select-by-pattern.mp4\">Your browser does not support HTML5 video. Here&rsquo;s <a href=\"https:\/\/sharats.me\/static\/autohotkey-select-by-pattern.mp4\">a link to the video<\/a>instead.<\/video>\n<h3 id=\"batch-rename\">Batch Rename<a class=\"headerlink\" href=\"#batch-rename\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This is actually built to be invoked as a separate AutoHotkey process, not to be <code>#Include<\/code>-ed into\na master script. That&rsquo;s because the GUI is slightly more complex than what we&rsquo;ve seen in previous\nsections and I didn&rsquo;t bother to make it work well as a module.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-5><label for=co-5><span class='btn show-full-code-btn'>Show remaining 81 lines<\/span><\/label><div class=filename><span>batch-rename.ahk<\/span><\/div><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><span class=collapse>37\n<\/span><span class=collapse>38\n<\/span><span class=collapse>39\n<\/span><span class=collapse>40\n<\/span><span class=collapse>41\n<\/span><span class=collapse>42\n<\/span><span class=collapse>43\n<\/span><span class=collapse>44\n<\/span><span class=collapse>45\n<\/span><span class=collapse>46\n<\/span><span class=collapse>47\n<\/span><span class=collapse>48\n<\/span><span class=collapse>49\n<\/span><span class=collapse>50\n<\/span><span class=collapse>51\n<\/span><span class=collapse>52\n<\/span><span class=collapse>53\n<\/span><span class=collapse>54\n<\/span><span class=collapse>55\n<\/span><span class=collapse>56\n<\/span><span class=collapse>57\n<\/span><span class=collapse>58\n<\/span><span class=collapse>59\n<\/span><span class=collapse>60\n<\/span><span class=collapse>61\n<\/span><span class=collapse>62\n<\/span><span class=collapse>63\n<\/span><span class=collapse>64\n<\/span><span class=collapse>65\n<\/span><span class=collapse>66\n<\/span><span class=collapse>67\n<\/span><span class=collapse>68\n<\/span><span class=collapse>69\n<\/span><span class=collapse>70\n<\/span><span class=collapse>71\n<\/span><span class=collapse>72\n<\/span><span class=collapse>73\n<\/span><span class=collapse>74\n<\/span><span class=collapse>75\n<\/span><span class=collapse>76\n<\/span><span class=collapse>77\n<\/span><span class=collapse>78\n<\/span><span class=collapse>79\n<\/span><span class=collapse>80\n<\/span><span class=collapse>81\n<\/span><span class=collapse>82\n<\/span><span class=collapse>83\n<\/span><span class=collapse>84\n<\/span><span class=collapse>85\n<\/span><span class=collapse>86\n<\/span><span class=collapse>87\n<\/span><span class=collapse>88\n<\/span><span class=collapse>89\n<\/span><span class=collapse>90\n<\/span><span class=collapse>91\n<\/span><span class=collapse>92\n<\/span><span class=collapse>93\n<\/span><span class=collapse>94\n<\/span><span class=collapse>95\n<\/span><span class=collapse>96\n<\/span><span class=collapse>97\n<\/span><span class=collapse>98\n<\/span><span class=collapse>99\n<\/span><span class=collapse>100\n<\/span><span class=collapse>101\n<\/span><\/pre><pre class=content><code><span><span class=\"nb\">#NoEnv<\/span>\n<\/span><span><span class=\"nb\">#NoTrayIcon<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">active_hwnd<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">WinActive<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;ahk_class CabinetWClass&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">If<\/span> <span class=\"p\">(<\/span><span class=\"n\">active_hwnd<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"n\">for<\/span> <span class=\"n\">window<\/span> <span class=\"ow\">in<\/span> <span class=\"nf\">ComObjCreate<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Shell.Application&quot;<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">Windows<\/span>\n<\/span><span>        <span class=\"n\">If<\/span> <span class=\"p\">(<\/span><span class=\"n\">active_hwnd<\/span> <span class=\"o\">==<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">hwnd<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>            <span class=\"n\">parent<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">uriDecode<\/span><span class=\"p\">(<\/span><span class=\"n\">StrReplace<\/span><span class=\"p\">(<\/span><span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">LocationURL<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;file:\/\/\/&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;&quot;<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">))<\/span>\n<\/span><span>            <span class=\"n\">ShowGui<\/span><span class=\"p\">()<\/span>\n<\/span><span>        <span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">ShowGui<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">global<\/span> <span class=\"n\">active_hwnd<\/span><span class=\"p\">,<\/span> <span class=\"n\">parent<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">WindowListView<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Font<\/span><span class=\"p\">,<\/span> <span class=\"n\">s10<\/span> <span class=\"n\">q5<\/span><span class=\"p\">,<\/span> <span class=\"n\">Segoe<\/span> <span class=\"n\">UI<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Margin<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"o\">+<\/span><span class=\"n\">Owner<\/span><span class=\"nv\">%active_hwnd%<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">Search<\/span> <span class=\"n\">pattern<\/span><span class=\"o\">:<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Edit<\/span><span class=\"p\">,<\/span> <span class=\"n\">r1<\/span> <span class=\"n\">w300<\/span> <span class=\"n\">vSourcePattern<\/span> <span class=\"n\">gInputChanged<\/span> <span class=\"o\">-<\/span><span class=\"n\">WantReturn<\/span> <span class=\"n\">X<\/span><span class=\"o\">+<\/span><span class=\"mi\">6<\/span> <span class=\"n\">Section<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">X<\/span><span class=\"o\">+<\/span><span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"n\">Full<\/span> <span class=\"n\">regex<\/span> <span class=\"ow\">is<\/span> <span class=\"n\">supported<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">XM<\/span><span class=\"p\">,<\/span> <span class=\"n\">Replacement<\/span><span class=\"o\">:<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Edit<\/span><span class=\"p\">,<\/span> <span class=\"n\">r1<\/span> <span class=\"n\">w300<\/span> <span class=\"n\">vTargetPattern<\/span> <span class=\"n\">gInputChanged<\/span> <span class=\"o\">-<\/span><span class=\"n\">WantReturn<\/span> <span class=\"n\">XS<\/span> <span class=\"n\">YP<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">X<\/span><span class=\"o\">+<\/span><span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"n\">Use<\/span> <span class=\"n\">$1<\/span><span class=\"p\">,<\/span> <span class=\"n\">$2<\/span><span class=\"p\">,<\/span> <span class=\"n\">$<\/span><span class=\"p\">{<\/span><span class=\"mi\">10<\/span><span class=\"p\">},<\/span> <span class=\"n\">$<\/span><span class=\"p\">{<\/span><span class=\"n\">named<\/span><span class=\"p\">},<\/span> <span class=\"n\">$U1<\/span><span class=\"p\">,<\/span> <span class=\"n\">$U<\/span><span class=\"p\">{<\/span><span class=\"mi\">10<\/span><span class=\"p\">},<\/span> <span class=\"n\">$L2<\/span><span class=\"p\">,<\/span> <span class=\"n\">$T0<\/span> <span class=\"n\">etc<\/span><span class=\"o\">.<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Button<\/span><span class=\"p\">,<\/span> <span class=\"n\">Default<\/span> <span class=\"n\">gDoRename<\/span> <span class=\"n\">XM<\/span> <span class=\"n\">w80<\/span><span class=\"p\">,<\/span> <span class=\"n\">Apply<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Button<\/span><span class=\"p\">,<\/span> <span class=\"n\">gShowHelp<\/span> <span class=\"n\">X<\/span><span class=\"o\">+<\/span><span class=\"mi\">6<\/span> <span class=\"n\">w80<\/span><span class=\"p\">,<\/span> <span class=\"n\">Help<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">ListView<\/span><span class=\"p\">,<\/span> <span class=\"n\">Grid<\/span> <span class=\"n\">r12<\/span> <span class=\"n\">w800<\/span> <span class=\"n\">vWindowListView<\/span> <span class=\"n\">XM<\/span><span class=\"p\">,<\/span> <span class=\"n\">Replacements<\/span><span class=\"o\">|<\/span><span class=\"n\">Current<\/span> <span class=\"n\">name<\/span><span class=\"o\">|<\/span><span class=\"n\">Renamed<\/span> <span class=\"n\">to<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">imList<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">IL_Create<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nf\">LV_SetImageList<\/span><span class=\"p\">(<\/span><span class=\"n\">imList<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nf\">IL_Add<\/span><span class=\"p\">(<\/span><span class=\"n\">imList<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;check.png&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0xFFFFFF<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nf\">IL_Add<\/span><span class=\"p\">(<\/span><span class=\"n\">imList<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;error.png&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0xFFFFFF<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse><span class=\"c1\">    ; IL_Add(imList, &quot;shell32.dll&quot;, 145)<\/span>\n<\/span><span class=collapse><span class=\"c1\">    ; IL_Add(imList, &quot;shell32.dll&quot;, 234)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Show<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">Rename<\/span> <span class=\"n\">with<\/span> <span class=\"n\">Regex<\/span><span class=\"o\">:<\/span> <span class=\"nv\">%parent%<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">InputChanged<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">global<\/span> <span class=\"n\">parent<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">GuiControlGet<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">GuiControlGet<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span>\n<\/span><span class=collapse>    <span class=\"nf\">LV_Delete<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Loop<\/span><span class=\"p\">,<\/span> <span class=\"n\">Files<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%parent%<\/span>\\<span class=\"o\">*<\/span><span class=\"p\">,<\/span> <span class=\"n\">FD<\/span>\n<\/span><span class=collapse>    <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"n\">toName<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">RegExReplace<\/span><span class=\"p\">(<\/span><span class=\"nv\">A_LoopFileName<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">count<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"n\">icon<\/span> <span class=\"o\">:=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span class=collapse>        <span class=\"n\">If<\/span> <span class=\"p\">(<\/span><span class=\"nv\">A_LoopFileName<\/span> <span class=\"o\">==<\/span> <span class=\"n\">toName<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>            <span class=\"n\">icon<\/span> <span class=\"o\">:=<\/span> <span class=\"mi\">3<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">FileExist<\/span><span class=\"p\">(<\/span><span class=\"n\">parent<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;\/&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">toName<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse>            <span class=\"n\">icon<\/span> <span class=\"o\">:=<\/span> <span class=\"mi\">2<\/span>\n<\/span><span class=collapse>        <span class=\"nf\">LV_Add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Icon&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">icon<\/span><span class=\"p\">,<\/span> <span class=\"n\">count<\/span><span class=\"p\">,<\/span> <span class=\"nv\">A_LoopFileName<\/span><span class=\"p\">,<\/span> <span class=\"n\">toName<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"nf\">LV_ModifyCol<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">DoRename<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">global<\/span> <span class=\"n\">parent<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Submit<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">If<\/span> <span class=\"p\">(<\/span><span class=\"n\">SourcePattern<\/span> <span class=\"o\">!=<\/span> <span class=\"s\">&quot;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Loop<\/span> <span class=\"nv\">%parent%<\/span>\\<span class=\"o\">*<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>            <span class=\"n\">toName<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">RegExReplace<\/span><span class=\"p\">(<\/span><span class=\"nv\">A_LoopFileName<\/span><span class=\"p\">,<\/span> <span class=\"n\">SourcePattern<\/span><span class=\"p\">,<\/span> <span class=\"n\">TargetPattern<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">FileMove<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%parent%<\/span>\\<span class=\"nv\">%A_LoopFileName%<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%parent%<\/span>\\<span class=\"nv\">%toName%<\/span>\n<\/span><span class=collapse>        <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">GuiClose<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">GuiEscape<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"n\">GuiClose<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">GuiClose<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">ExitApp<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">uriDecode<\/span><span class=\"p\">(<\/span><span class=\"n\">str<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Loop<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">If <\/span><span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">str<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;i)(?&lt;=%)[\\da-f]{1,2}&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">hex<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">StringReplace<\/span><span class=\"p\">,<\/span> <span class=\"n\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">str<\/span><span class=\"p\">,<\/span> <span class=\"se\">`%<\/span><span class=\"nv\">%hex%<\/span><span class=\"p\">,<\/span> <span class=\"o\">%<\/span> <span class=\"nf\">Chr<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;0x&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">hex<\/span><span class=\"p\">),<\/span> <span class=\"n\">All<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Else<\/span> <span class=\"n\">Break<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Return<\/span><span class=\"p\">,<\/span> <span class=\"n\">str<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">ShowHelp<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"n\">help<\/span><span class=\"o\">=<\/span>\n<\/span><span class=collapse>    <span class=\"g\">(<\/span>\n<\/span><span class=collapse><span class=\"g\">## Pattern:<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"g\">The pattern to search for, which is a Perl-compatible regular expression (PCRE). The pattern&#39;s options (if any) must be included at the beginning of the string followed by a close-parenthesis. For example, the pattern &quot;i)abc.*123&quot; would turn on the case-insensitive option and search for &quot;abc&quot;, followed by zero or more occurrences of any character, followed by &quot;123&quot;. If there are no options, the &quot;)&quot; is optional; for example, &quot;)abc&quot; is equivalent to &quot;abc&quot;.<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"g\">## Replacement:<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"g\">The string to be substituted for each match, which is plain text (not a regular expression). It may include backreferences like $1, which brings in the substring from Haystack that matched the first subpattern. The simplest backreferences are $0 through $9, where $0 is the substring that matched the entire pattern, $1 is the substring that matched the first subpattern, $2 is the second, and so on. For backreferences above 9 (and optionally those below 9), enclose the number in braces; e.g. ${10}, ${11}, and so on. For named subpatterns, enclose the name in braces; e.g. ${SubpatternName}. To specify a literal $, use $$ (this is the only character that needs such special treatment; backslashes are never needed to escape anything).<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"g\">To convert the case of a subpattern, follow the $ with one of the following characters: U or u (uppercase), L or l (lowercase), T or t (title case, in which the first letter of each word is capitalized but all others are made lowercase). For example, both $U1 and $U{1} transcribe an uppercase version of the first subpattern.<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"g\">Nonexistent backreferences and those that did not match anything in Haystack -- such as one of the subpatterns in &quot;(abc)|(xyz)&quot; -- are transcribed as empty strings.<\/span>\n<\/span><span class=collapse><span class=\"g\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">MsgBox<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%help%<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Put this script at a convenient location, probably right next to your master script, and add the\nfollowing hotkey to your master script:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^+<\/span><span class=\"n\">b<\/span><span class=\"o\">::<\/span><span class=\"n\">Run<\/span> <span class=\"n\">batch<\/span><span class=\"o\">-<\/span><span class=\"n\">rename<\/span><span class=\"o\">.<\/span><span class=\"n\">ahk<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here&rsquo;s a little <strong>mute<\/strong> video recording of some usage examples of this tool:<\/p>\n<video controls=\"\" muted=\"\" playsinline=\"\" preload=\"\" src=\"https:\/\/sharats.me\/static\/autohotkey-rename-by-regex.mp4\">Your browser does not support HTML5 video. Here&rsquo;s <a href=\"https:\/\/sharats.me\/static\/autohotkey-rename-by-regex.mp4\">a link to the video<\/a>instead.<\/video>\n<p class=\"note\">If you&rsquo;re using this, please keep caution. Please inspect the previous table before clicking on the\n&ldquo;Apply&rdquo; button. If it ends up messing your files up, don&rsquo;t hold me responsible. I&rsquo;m sharing this\nwithout warranty. As any source code block on this website, this is shared here with <a href=\"https:\/\/sharats.me\/licenses\/mit\/\">MIT\nLicense<\/a>.<\/p>\n<h3 id=\"copy-paths-of-selected-files\">Copy Paths of Selected Files<a class=\"headerlink\" href=\"#copy-paths-of-selected-files\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This, again, is actually <em>partly<\/em> fulfilled by default Windows functionality. When we\n<kbd>Shift+Right Click<\/kbd> on a file, we get the option to &ldquo;Copy as path&rdquo;, which works fine for\nsimple cases. But I wanted the following additional things for this feature:<\/p>\n<ol>\n<li>A keyboard hotkey, like <kbd>^+c<\/kbd>.<\/li>\n<li>No surrounding double quotes.<\/li>\n<li>Work with multiple files being selected. Copy each file&rsquo;s path as one line.<\/li>\n<\/ol>\n<p>For this, I defined the following <kbd>^+c<\/kbd> hotkey on the file explorer windows. <\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^+<\/span><span class=\"n\">c<\/span><span class=\"o\">::<\/span>\n<\/span><span>    <span class=\"nv\">Clipboard<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">JoinArrayContents<\/span><span class=\"p\">(<\/span><span class=\"n\">Explorer_GetSelected<\/span><span class=\"p\">())<\/span>\n<\/span><span>    <span class=\"nb\">Return<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will get a list of all selected files in the current explorer window and join them into a\nsingle string. The <code>Explorer_GetSelected<\/code> function comes from <a href=\"https:\/\/autohotkey.com\/board\/topic\/60985-get-paths-of-selected-items-in-an-explorer-window\/\" rel=\"noopener noreferrer\" target=\"_blank\">this AutoHotkey forum\npost<\/a> and the <code>JoinArrayContents<\/code> is given below:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">JoinArrayContents<\/span><span class=\"p\">(<\/span><span class=\"n\">arr<\/span><span class=\"p\">,<\/span> <span class=\"n\">delimiter<\/span><span class=\"o\">=<\/span><span class=\"s\">&quot;<\/span><span class=\"se\">`n<\/span><span class=\"s\">&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>    <span class=\"n\">for<\/span> <span class=\"n\">index<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">arr<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">if <\/span><span class=\"n\">index<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">1<\/span>\n<\/span><span>            <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">content<\/span> <span class=\"o\">.<\/span> <span class=\"n\">delimiter<\/span>\n<\/span><span>        <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">content<\/span> <span class=\"o\">.<\/span> <span class=\"n\">item<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span>    <span class=\"nb\">return<\/span> <span class=\"n\">content<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now I can select one or more files, hit <kbd>^+c<\/kbd> and the full paths of <em>all<\/em> the selected\nfiles will end up in my clipboard.<\/p>\n<h3 id=\"copy-contents-of-selected-files\">Copy Contents of Selected Files<a class=\"headerlink\" href=\"#copy-contents-of-selected-files\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This one, although sounds similar to the previous section, is quite different and useful in a very\ndifferent way. Where the previous section&rsquo;s hotkey copies the selected files&rsquo; <em>paths<\/em>, this hotkey\nis intended to copy the selected files&rsquo; <em>contents<\/em> as a whole.<\/p>\n<p>I have a few (several?) small text files with snippets, template messages, etc. With this, I just\nselect one or multiple files and hit <kbd>Ctrl+Shift+x<\/kbd> and I&rsquo;m ready to paste their contents.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^+<\/span><span class=\"n\">x<\/span><span class=\"o\">::<\/span>\n<\/span><span>    <span class=\"n\">CopySelectedFileContents<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">files<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">Explorer_GetSelected<\/span><span class=\"p\">()<\/span>\n<\/span><span>        <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>        <span class=\"n\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">files<\/span> <span class=\"p\">{<\/span>\n<\/span><span>            <span class=\"nb\">FileRead<\/span><span class=\"p\">,<\/span> <span class=\"n\">text<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%file%<\/span>\n<\/span><span>            <span class=\"nb\">if <\/span><span class=\"n\">i<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">1<\/span>\n<\/span><span>                <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">content<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;<\/span><span class=\"se\">`n`n<\/span><span class=\"s\">&quot;<\/span>\n<\/span><span>            <span class=\"n\">content<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">content<\/span> <span class=\"o\">.<\/span> <span class=\"n\">text<\/span>\n<\/span><span>        <span class=\"p\">}<\/span>\n<\/span><span>        <span class=\"nv\">Clipboard<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">content<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is the same <code>Explorer_GetSelected<\/code> I referred to in the previous section. However, in the above\nhotkey definition, instead of setting the paths to <code>Clipboard<\/code>, we set the contents of the files.<\/p>\n<p>Just like the previous hotkey, I can select multiple <em>text<\/em> files and hit <kbd>^+x<\/kbd> and the\ncontents of all selected files will end up in my clipboard, separated by two blank lines.<\/p>\n<p>This doesn&rsquo;t work with images yet though. Still have to figure that one out.<\/p>\n<h3 id=\"create-file-with-clipboard-contents\">Create File with Clipboard Contents<a class=\"headerlink\" href=\"#create-file-with-clipboard-contents\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This is the opposite of the previous hotkey. Here, I want whatever is in the Clipboard to be saved\nto a text file in the current folder.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span>21\n<\/span><span>22\n<\/span><\/pre><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^+<\/span><span class=\"n\">v<\/span><span class=\"o\">::<\/span>\n<\/span><span>    <span class=\"n\">CreateFileWithClipboardContents<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">loc<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">Explorer_GetPath<\/span><span class=\"p\">()<\/span>\n<\/span><span>        <span class=\"nb\">WinGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">wx<\/span><span class=\"p\">,<\/span> <span class=\"n\">wy<\/span>\n<\/span><span>        <span class=\"nb\">ControlGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">cx<\/span><span class=\"p\">,<\/span> <span class=\"n\">cy<\/span><span class=\"p\">,<\/span> <span class=\"n\">cw<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">DirectUIHWND3<\/span>\n<\/span><span>        <span class=\"n\">x<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cw<\/span><span class=\"o\">\/<\/span><span class=\"mi\">2<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">200<\/span>\n<\/span><span>        <span class=\"n\">y<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wy<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cy<\/span>\n<\/span><span>        <span class=\"nb\">InputBox<\/span><span class=\"p\">,<\/span> <span class=\"n\">filename<\/span><span class=\"p\">,<\/span> <span class=\"nv\">Clipboard<\/span> <span class=\"n\">File<\/span>\n<\/span><span>            <span class=\"p\">,<\/span> <span class=\"n\">Enter<\/span> <span class=\"n\">file<\/span> <span class=\"n\">name<\/span> <span class=\"n\">to<\/span> <span class=\"n\">paste<\/span> <span class=\"nv\">clipboard<\/span> <span class=\"n\">contents<\/span> <span class=\"ow\">in<\/span><span class=\"o\">:<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"mi\">400<\/span><span class=\"p\">,<\/span> <span class=\"mi\">120<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%x%<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%y%<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span>\n<\/span><span>            <span class=\"p\">,<\/span> <span class=\"n\">clip<\/span><span class=\"o\">.<\/span><span class=\"n\">txt<\/span>\n<\/span><span>        <span class=\"nb\">if <\/span><span class=\"nv\">ErrorLevel<\/span>\n<\/span><span>            <span class=\"nb\">Return<\/span>\n<\/span><span>        <span class=\"n\">filepath<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">loc<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;\\&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">filename<\/span>\n<\/span><span>        <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">FileExist<\/span><span class=\"p\">(<\/span><span class=\"n\">filepath<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n<\/span><span>            <span class=\"nb\">MsgBox<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">Overwrite<\/span><span class=\"p\">,<\/span> <span class=\"n\">Overwriting<\/span> <span class=\"n\">existing<\/span> &#39;<span class=\"nv\">%filename%<\/span>&#39;<span class=\"o\">!<\/span>\n<\/span><span>            <span class=\"nb\">IfMsgBox<\/span> <span class=\"n\">Cancel<\/span>\n<\/span><span>                <span class=\"nb\">Return<\/span>\n<\/span><span>            <span class=\"nb\">FileDelete<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%filepath%<\/span>\n<\/span><span>        <span class=\"p\">}<\/span>\n<\/span><span>        <span class=\"nb\">Fileappend<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%Clipboard%<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%filepath%<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>Explorer_GetPath<\/code> function used in the above snippet is also from the same source I mentioned\nin the previous sections. The way this works is when the hotkey is triggered, we are prompted to\nenter the name of the file to which the clipboard&rsquo;s contents will be saved. Once we provide a file\nname and submit, the file is created.<\/p>\n<p>With this, I can copy some text out of a webpage or an email in Outlook and saving it to a text file\nis a quick <kbd>^+v<\/kbd>. Once I created this hotkey, it became my primary way of creating new text\nfiles. I no longer open Notepad, write (or paste) and then save the file to the desired directory.\nInstead, I open the folder, use this hotkey to create the file, and then open the file in Notepad.\nSomehow, it feels more natural.<\/p>\n<p>This doesn&rsquo;t work with images either. Have to figure this one out too.<\/p>\n<h3 id=\"create-folder-hierarchy-and-enter-it\">Create Folder Hierarchy and Enter it<a class=\"headerlink\" href=\"#create-folder-hierarchy-and-enter-it\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The file explorer has a default hotkey for creating new folders (<kbd>Ctrl+Shift+n<\/kbd>), but it\ndoesn&rsquo;t let us create a tree or folders at one go. To do that, we have to create a directory, enter\nit, create again etc. This quickly gets tedious if it has to be done often.<\/p>\n<p>As always I tried to address it with AutoHotkey.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-6><label for=co-6><span class='btn show-full-code-btn'>Show remaining 10 lines<\/span><\/label><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">n<\/span><span class=\"o\">::<\/span>\n<\/span><span><span class=\"n\">CreateFolderHierarchy<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"n\">loc<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">Explorer_GetPath<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"nb\">WinGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">wx<\/span><span class=\"p\">,<\/span> <span class=\"n\">wy<\/span>\n<\/span><span>    <span class=\"nb\">ControlGetPos<\/span><span class=\"p\">,<\/span> <span class=\"n\">cx<\/span><span class=\"p\">,<\/span> <span class=\"n\">cy<\/span><span class=\"p\">,<\/span> <span class=\"n\">cw<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">DirectUIHWND3<\/span>\n<\/span><span>    <span class=\"n\">x<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cx<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cw<\/span><span class=\"o\">\/<\/span><span class=\"mi\">2<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">200<\/span>\n<\/span><span>    <span class=\"n\">y<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wy<\/span> <span class=\"o\">+<\/span> <span class=\"n\">cy<\/span>\n<\/span><span>    <span class=\"nb\">InputBox<\/span><span class=\"p\">,<\/span> <span class=\"n\">folder<\/span><span class=\"p\">,<\/span> <span class=\"n\">Create<\/span> <span class=\"n\">Folder<\/span><span class=\"p\">,<\/span> <span class=\"n\">Enter<\/span> <span class=\"n\">folder<\/span> <span class=\"n\">name<\/span><span class=\"o\">\/<\/span><span class=\"n\">path<\/span> <span class=\"n\">create<\/span><span class=\"o\">:<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"mi\">400<\/span><span class=\"p\">,<\/span> <span class=\"mi\">120<\/span>\n<\/span><span>        <span class=\"p\">,<\/span> <span class=\"nv\">%x%<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%y%<\/span>\n<\/span><span>    <span class=\"nb\">if <\/span><span class=\"nv\">ErrorLevel<\/span>\n<\/span><span>        <span class=\"nb\">Return<\/span>\n<\/span><span>    <span class=\"n\">folder<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">StrReplace<\/span><span class=\"p\">(<\/span><span class=\"n\">folder<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;\/&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;\\&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">pos<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">folder<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;O)\\{([^\\{]+)\\}&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">match<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">folders<\/span> <span class=\"o\">:=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pos<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">parts<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">StrSplit<\/span><span class=\"p\">(<\/span><span class=\"n\">match<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">),<\/span> <span class=\"s\">&quot;,&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"n\">prefix<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">SubStr<\/span><span class=\"p\">(<\/span><span class=\"n\">folder<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">match<\/span><span class=\"o\">.<\/span><span class=\"n\">Pos<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"n\">suffix<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">SubStr<\/span><span class=\"p\">(<\/span><span class=\"n\">folder<\/span><span class=\"p\">,<\/span> <span class=\"n\">match<\/span><span class=\"o\">.<\/span><span class=\"n\">Pos<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"n\">match<\/span><span class=\"o\">.<\/span><span class=\"n\">Len<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"n\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">part<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">parts<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>            <span class=\"n\">folders<\/span><span class=\"o\">.<\/span><span class=\"n\">Push<\/span><span class=\"p\">(<\/span><span class=\"n\">prefix<\/span> <span class=\"o\">.<\/span> <span class=\"n\">part<\/span> <span class=\"o\">.<\/span> <span class=\"n\">suffix<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"n\">folders<\/span><span class=\"o\">.<\/span><span class=\"n\">Push<\/span><span class=\"p\">(<\/span><span class=\"n\">folder<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"n\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">folder<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">folders<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">FileCreateDir<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%loc%<\/span>\\<span class=\"nv\">%folder%<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"n\">Explorer_GetWindow<\/span><span class=\"p\">()<\/span><span class=\"o\">.<\/span><span class=\"n\">Navigate2<\/span><span class=\"p\">(<\/span><span class=\"n\">loc<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;\\&quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">folders<\/span><span class=\"p\">[<\/span><span class=\"n\">folders<\/span><span class=\"o\">.<\/span><span class=\"n\">Length<\/span><span class=\"p\">()])<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This uses the same explorer library I mentioned in the previous sections. When this hotkey is\ntriggered, we get a prompt where we can enter a folder tree (<em>i.e.,<\/em> folders separated by <code>\/<\/code> or\n<code>\\<\/code>) and they will all be created. As a bonus, we are also switched to that newly created folder,\nso we can start working with it right away.<\/p>\n<p>Now I can hit <kbd>^n<\/kbd> and type in <code>src\/main\/java<\/code> or <code>2020-01\/pics<\/code>, and all nesting structure\nis created and navigated, which is usually followed by pasting some files.<\/p>\n<h2 id=\"email-selected-files-with-outlook\">Email Selected File(s) with Outlook<a class=\"headerlink\" href=\"#email-selected-files-with-outlook\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Outlook is necessary tool for email at most corporate workplaces. So it&rsquo;s important to look at how\nwe use it, and what parts of it we can automate \/ improve.<\/p>\n<p>It&rsquo;s also quite common to have to send files over email as attachments. Yet, considering how often\nwe tend to do that, it&rsquo;s still a tedious process. Go to outlook, start new mail, drag-drop the file\nin this window, fill up the mail, send. It gets a bit better if you copy the file to clipboard and\nthen instead of starting a new mail with <kbd>Ctrl+n<\/kbd>, you could just hit <kbd>Ctrl+v<\/kbd> in\nthe Outlook Mails view and new mail will open up with file in clipboard as attachment. But I&rsquo;d say\nit&rsquo;s still not good enough.<\/p>\n<p>The solution I currently use is the <kbd>Ctrl+m<\/kbd> hotkey for file explorers. The workflow is\nthat I select some files in my file explorer, hit <kbd>Ctrl+m<\/kbd> and a new mail window opens up\nwith the selected files as attachments, the message body containing the list of files for me to\nedit and subject containing the list of files.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">FileListers<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">m<\/span><span class=\"o\">::<\/span><span class=\"n\">OutlookNewMail<\/span><span class=\"p\">(<\/span><span class=\"n\">Explorer_GetSelected<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>Explorer_GetSelected<\/code> function is from the same library I mentioned in an earlier section. The\nfollowing is the definition of the <code>OutlookNewMail<\/code> function:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-7><label for=co-7><span class='btn show-full-code-btn'>Show remaining 9 lines<\/span><\/label><pre class=content><code><span><span class=\"n\">OutlookNewMail<\/span><span class=\"p\">(<\/span><span class=\"n\">attachments<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"n\">outlook<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">ComObjActive<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Outlook.Application&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">mail<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">outlook<\/span><span class=\"o\">.<\/span><span class=\"n\">CreateItem<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">attachments<\/span> <span class=\"o\">!=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">msg<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>        <span class=\"n\">sub<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;Files: &quot;<\/span>\n<\/span><span>        <span class=\"n\">for<\/span> <span class=\"n\">index<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">attachments<\/span> <span class=\"p\">{<\/span>\n<\/span><span>            <span class=\"n\">mail<\/span><span class=\"o\">.<\/span><span class=\"n\">Attachments<\/span><span class=\"o\">.<\/span><span class=\"n\">Add<\/span><span class=\"p\">(<\/span><span class=\"n\">file<\/span><span class=\"p\">)<\/span>\n<\/span><span>            <span class=\"nb\">SplitPath<\/span><span class=\"p\">,<\/span> <span class=\"n\">file<\/span><span class=\"p\">,<\/span> <span class=\"n\">basename<\/span>\n<\/span><span>            <span class=\"n\">msg<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">msg<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;&lt;p class=MsoNormal&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &quot;<\/span>\n<\/span><span>                    <span class=\"o\">.<\/span> <span class=\"n\">basename<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;&lt;o:p&gt;&lt;\/o:p&gt;&lt;\/p&gt;&quot;<\/span>\n<\/span><span>            <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">attachments<\/span><span class=\"o\">.<\/span><span class=\"n\">Length<\/span><span class=\"p\">()<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span>                <span class=\"n\">sub<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;File: &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">basename<\/span>\n<\/span><span>            <span class=\"nb\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">index<\/span> <span class=\"o\">==<\/span> <span class=\"n\">attachments<\/span><span class=\"o\">.<\/span><span class=\"n\">_MaxIndex<\/span><span class=\"p\">())<\/span>\n<\/span><span>                <span class=\"n\">sub<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sub<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot; &amp; &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">basename<\/span>\n<\/span><span>            <span class=\"nb\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">index<\/span> <span class=\"o\">==<\/span> <span class=\"n\">attachments<\/span><span class=\"o\">.<\/span><span class=\"n\">_MinIndex<\/span><span class=\"p\">())<\/span>\n<\/span><span>                <span class=\"n\">sub<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sub<\/span> <span class=\"o\">.<\/span> <span class=\"n\">basename<\/span>\n<\/span><span>            <span class=\"nb\">else<\/span>\n<\/span><span>                <span class=\"n\">sub<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sub<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;, &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">basename<\/span>\n<\/span><span class=collapse>        <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>        <span class=\"nb\">FileRead<\/span><span class=\"p\">,<\/span> <span class=\"n\">emailTpl<\/span><span class=\"p\">,<\/span> <span class=\"n\">email<\/span><span class=\"o\">.<\/span><span class=\"n\">tpl<\/span><span class=\"o\">.<\/span><span class=\"n\">txt<\/span>\n<\/span><span class=collapse>        <span class=\"n\">mail<\/span><span class=\"o\">.<\/span><span class=\"n\">HTMLBody<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">StrReplace<\/span><span class=\"p\">(<\/span><span class=\"n\">emailTpl<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;$$MESSAGE$$&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">msg<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot;&lt;\/ul&gt;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"n\">mail<\/span><span class=\"o\">.<\/span><span class=\"n\">Subject<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sub<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">mail<\/span><span class=\"o\">.<\/span><span class=\"n\">Display<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>AutoHotkey supports connecting to OLE objects, which means we can create hotkey that create rich\ninteractions with Office applications like Outlook. We leverage this in the above function.<\/p>\n<p>All I have to do now, is fill up the &ldquo;To:&rdquo; field and hit <kbd>Ctrl+Enter<\/kbd>. I&rsquo;ve been loving\nthis ever since.<\/p>\n<p class=\"note\">Note, of course, that since this connects to the Outlook OLE object, Outlook needs to be running for\nthis work.<\/p>\n<h3 id=\"global-hotkey-for-new-mail\">Global Hotkey for New Mail<a class=\"headerlink\" href=\"#global-hotkey-for-new-mail\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>If you&rsquo;ve noticed, the above function&rsquo;s <code>attachments<\/code> argument has a default value. If this argument\nis not provided, we just get a blank email window open up. This is convenient on its own.  So I have\nit as a <em>global<\/em> hotkey:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nl\">#c::<\/span><span class=\"n\">OutlookNewMail<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This works really well since the new mail window opens up with my signature already filled up and\nthe focus is set to the &ldquo;To:&rdquo; field perfectly to quickly start working on my email.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>AutoHotkey is a powerful tool for automating all sorts of workflows on Windows. If you can get past\nthe quirks in the language itself, the underlying engine is very powerful. I know that over the few\nyears I&rsquo;ve used it, I&rsquo;ve only made use of a small portion of its potential. In addition, the help\nfile that is shipped with AutoHotkey (right-click on the tray icon and click on &ldquo;Help&rdquo;) is very\ngood. It&rsquo;s exhaustive, very detailed and contains lots of examples. I encourage going over it\noccasionally to find interesting things to add to your workflow. Good luck!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"autohotkey"}},{"@attributes":{"term":"productivity"}},{"@attributes":{"term":"windows"}},{"@attributes":{"term":"automation"}}]},{"title":"Automating the Vim workplace \u2014 Chapter \u2162","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/automating-the-vim-workplace-3\/","rel":"alternate"}},"published":"2020-03-15T00:00:00+05:30","updated":"2020-03-15T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-03-15:\/posts\/automating-the-vim-workplace-3\/","summary":"<p>This is the third installment of my <a href=\"..\/automating-the-vim-workplace\/\">Automate the Vim workplace<\/a> article series. As\nalways, feel free to grab the ideas in this article or, better yet, take inspiration and inspect\nyour workflow to identify such opportunities.<\/p>\n<p>This article is part of a series:<\/p>\n<ol>\n<li><a href=\"..\/automating-the-vim-workplace\/\">Chapter \u2160<\/a>.<\/li>\n<li><a href=\"..\/automating-the-vim-workplace-2\/\">Chapter \u2161<\/a>.<\/li>\n<li>Chapter \u2162 \u2026<\/li><\/ol>","content":"<p>This is the third installment of my <a href=\"..\/automating-the-vim-workplace\/\">Automate the Vim workplace<\/a> article series. As\nalways, feel free to grab the ideas in this article or, better yet, take inspiration and inspect\nyour workflow to identify such opportunities.<\/p>\n<p>This article is part of a series:<\/p>\n<ol>\n<li><a href=\"..\/automating-the-vim-workplace\/\">Chapter \u2160<\/a>.<\/li>\n<li><a href=\"..\/automating-the-vim-workplace-2\/\">Chapter \u2161<\/a>.<\/li>\n<li>Chapter \u2162 (this article).<\/li>\n<\/ol>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#copy-file-full-path\">Copy file full path<\/a><\/li>\n<li><a href=\"#squeeze-expand-contiguous-blank-lines\">Squeeze \/ Expand contiguous blank lines<\/a><\/li>\n<li><a href=\"#duplicate-text-in-motion\">Duplicate Text in Motion<\/a><\/li>\n<li><a href=\"#transpose\">Transpose<\/a><\/li>\n<li><a href=\"#using-vartabstop-to-line-up\">Using vartabstop to Line Up<\/a><\/li>\n<li><a href=\"#strip-trailing-spaces\">Strip Trailing Spaces<\/a><\/li>\n<li><a href=\"#append-character-over-motion\">Append character over motion<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<p class=\"note\">Please note that all that I share below is what I&rsquo;m using with Vim (more specifically, GVim on\nWindows). I don&rsquo;t use Neovim (yet) and I can&rsquo;t speak for any of the below for Neovim.<\/p>\n<h2 id=\"copy-file-full-path\">Copy file full path<a class=\"headerlink\" href=\"#copy-file-full-path\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I work with CSV files quite a bit. I spend a lot of time grooming them, fixing them etc. in Vim and\nthen once they&rsquo;re ready, I need to upload it to an internal tool. For that, the following command\nhas proven to be super useful.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Command to copy the current file&#39;s full absolute path.<\/span>\n<\/span><span>command CopyFilePath <span class=\"k\">let<\/span> @<span class=\"p\">+<\/span> <span class=\"p\">=<\/span> expand<span class=\"p\">(<\/span>has<span class=\"p\">(<\/span><span class=\"s1\">&#39;win32&#39;<\/span><span class=\"p\">)<\/span> ? <span class=\"s1\">&#39;%:p:gs?\/?\\\\?&#39;<\/span> : <span class=\"s1\">&#39;%:p&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is one of those commands that feel super-simple and super-obvious once we add it to our\nworkflow. Running this command places the full path of the current buffer&rsquo;s file into the system\nclipboard. Then, I just go to my browser, click on the upload button and paste the file location.\nThis is much quicker than having to navigate to the folder and selecting the file. It also helps\navoid selecting the wrong file (which happened more than once to me).<\/p>\n<h2 id=\"squeeze-expand-contiguous-blank-lines\">Squeeze \/ Expand contiguous blank lines<a class=\"headerlink\" href=\"#squeeze-expand-contiguous-blank-lines\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>When building or editing large CSV files, I often end up with several (read: hundreds) of blank\nlines. This is usually because I select those lines in visual block mode, cut them, and then paste\nas a new column to some existing rows. Solving that problem is for another day I suppose.<\/p>\n<p>Nonetheless, I needed a quick way to condense several blank lines into a single blank line. The\nfollowing is the result of that:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> dc :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>CleanupBlanks<span class=\"p\">()&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span> s:CleanupBlanks<span class=\"p\">()<\/span> abort\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"p\">!<\/span>empty<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"k\">return<\/span>\n<\/span><span>    <span class=\"k\">endif<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:curr <span class=\"p\">=<\/span> line<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> <span class=\"p\">=<\/span> <span class=\"k\">l<\/span>:curr\n<\/span><span>    <span class=\"k\">while<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> <span class=\"p\">&gt;<\/span> <span class=\"m\">1<\/span> &amp;&amp; empty<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span><span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> <span class=\"p\">-<\/span> <span class=\"m\">1<\/span><span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> <span class=\"p\">-=<\/span> <span class=\"m\">1<\/span>\n<\/span><span>    <span class=\"k\">endwhile<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">=<\/span> <span class=\"k\">l<\/span>:curr\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:last_line_num <span class=\"p\">=<\/span> line<span class=\"p\">(<\/span><span class=\"s1\">&#39;$&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">while<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">&lt;<\/span> <span class=\"k\">l<\/span>:last_line_num &amp;&amp; empty<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span><span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">+<\/span> <span class=\"m\">1<\/span><span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">+=<\/span> <span class=\"m\">1<\/span>\n<\/span><span>    <span class=\"k\">endwhile<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> <span class=\"p\">+<\/span> <span class=\"k\">v<\/span>:count1\n<\/span><span>        exe <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span> . <span class=\"s1\">&#39;+&#39;<\/span> . <span class=\"k\">v<\/span>:count1 . <span class=\"s1\">&#39;,&#39;<\/span> . <span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> . <span class=\"s1\">&#39;d_&#39;<\/span>\n<\/span><span>    <span class=\"k\">else<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> append<span class=\"p\">(<\/span><span class=\"k\">l<\/span>:<span class=\"k\">end<\/span><span class=\"p\">,<\/span> repeat<span class=\"p\">(<\/span>[<span class=\"s1\">&#39;&#39;<\/span>]<span class=\"p\">,<\/span> <span class=\"k\">v<\/span>:count1 <span class=\"p\">-<\/span> <span class=\"p\">(<\/span><span class=\"k\">l<\/span>:<span class=\"k\">end<\/span> <span class=\"p\">-<\/span> <span class=\"k\">l<\/span>:<span class=\"k\">start<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> <span class=\"m\">1<\/span><span class=\"p\">))<\/span>\n<\/span><span>    <span class=\"k\">endif<\/span>\n<\/span><span>    <span class=\"k\">call<\/span> cursor<span class=\"p\">(<\/span><span class=\"k\">l<\/span>:<span class=\"k\">start<\/span><span class=\"p\">,<\/span> <span class=\"m\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This defines the <kbd>dc<\/kbd> mapping, which will condense multiple blank lines under the cursor\ninto a single one.<\/p>\n<p>Then, on a weekend when I was feeling particularly silly, I extended this to accept a number in\nfront of <kbd>dc<\/kbd> which specifies the number of newlines to end up with. So now, this mapping\ncan both condense, and expand vertical blank space to any size I want! Yay, silly weekends!<\/p>\n<h2 id=\"duplicate-text-in-motion\">Duplicate Text in Motion<a class=\"headerlink\" href=\"#duplicate-text-in-motion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Copy-pasta is a legitimate writing and coding technique. But I do it so mindlessly and often, I\nstarted to think of <em>duplicating<\/em> as a distinct operation, and not as a combination of <em>yanking<\/em> and\nthen <em>pasting<\/em>. But if that is so, <em>duplicating<\/em> some text should not mess with my registers. This\nwas messing with the nice semantic pool my thoughts were swimming in (!).<\/p>\n<p>So I built a mapping that would let me duplicate the text over any motion (like text objects),\nwithout touching the registers.  Following is how it&rsquo;s built:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-11><label for=co-11><span class='btn show-full-code-btn'>Show remaining 6 lines<\/span><\/label><pre class=content><code><span><span class=\"c\">&quot; Duplicate text, selected or over motion.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span>uu :<span class=\"k\">t<\/span>.\\<span class=\"p\">|<\/span><span class=\"k\">silent<\/span><span class=\"p\">!<\/span> <span class=\"k\">call<\/span> repeat#<span class=\"k\">set<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;duu&#39;<\/span><span class=\"p\">,<\/span> <span class=\"k\">v<\/span>:count<span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">u<\/span> :<span class=\"k\">set<\/span> <span class=\"nb\">opfunc<\/span><span class=\"p\">=<\/span>DuplicateText<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span>@\n<\/span><span><span class=\"nb\">vnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">u<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> DuplicateText<span class=\"p\">(<\/span><span class=\"s1\">&#39;vis&#39;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span> DuplicateText<span class=\"p\">(<\/span>type<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">marks<\/span> <span class=\"p\">=<\/span> <span class=\"k\">a<\/span>:type <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;vis&#39;<\/span> ? <span class=\"s1\">&#39;&lt;&gt;&#39;<\/span> : <span class=\"s1\">&#39;[]&#39;<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l1<span class=\"p\">,<\/span> c1<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">0<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l2<span class=\"p\">,<\/span> c2<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">1<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> l1 <span class=\"p\">==<\/span> l2\n<\/span><span>        <span class=\"k\">let<\/span> text <span class=\"p\">=<\/span> getline<span class=\"p\">(<\/span>l1<span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> setline<span class=\"p\">(<\/span>l1<span class=\"p\">,<\/span> text[:c2 <span class=\"p\">-<\/span> <span class=\"m\">1<\/span>] . text[c1 <span class=\"p\">-<\/span> <span class=\"m\">1<\/span>:c2] . text[c2 <span class=\"p\">+<\/span> <span class=\"m\">1<\/span>:]<span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> cursor<span class=\"p\">(<\/span>l2<span class=\"p\">,<\/span> c2 <span class=\"p\">+<\/span> <span class=\"m\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">if<\/span> <span class=\"k\">a<\/span>:type <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;vis&#39;<\/span>\n<\/span><span>            exe <span class=\"s1\">&#39;normal! v&#39;<\/span> . <span class=\"p\">(<\/span>c2 <span class=\"p\">-<\/span> c1<span class=\"p\">)<\/span> . <span class=\"s1\">&#39;l&#39;<\/span>\n<\/span><span>        <span class=\"k\">endif<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">else<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> append<span class=\"p\">(<\/span>l2<span class=\"p\">,<\/span> getline<span class=\"p\">(<\/span>l1<span class=\"p\">,<\/span> l2<span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> cursor<span class=\"p\">(<\/span>l2 <span class=\"p\">+<\/span> <span class=\"m\">1<\/span><span class=\"p\">,<\/span> c1<span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"k\">if<\/span> <span class=\"k\">a<\/span>:type <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;vis&#39;<\/span>\n<\/span><span class=collapse>            exe <span class=\"s1\">&#39;normal! V&#39;<\/span> . <span class=\"p\">(<\/span>l2 <span class=\"p\">-<\/span> l1<span class=\"p\">)<\/span> . <span class=\"s1\">&#39;j&#39;<\/span>\n<\/span><span class=collapse>        <span class=\"k\">endif<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"k\">endif<\/span>\n<\/span><span class=collapse><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now, what used to be <kbd>yap}p<\/kbd> has become <kbd>,uap<\/kbd>. That&rsquo;s just one key reduced but a\nreduction in keys is not what I&rsquo;m aiming at here. It&rsquo;s cognitive load of &ldquo;duplicate this text&rdquo; over\n&ldquo;copy this text, go to end of text, paste text&rdquo;. This works in visual mode as well, though I don&rsquo;t\nuse it as often.<\/p>\n<p>Additionally, if triggered in visual mode, the duplicated text is selected again in visual mode.\nThis quickly highlights the newly inserted text, so I can continue with operating on the\nduplicated text.<\/p>\n<p>Now, if you&rsquo;re aware of the <code>:t<\/code> (or <code>:copy<\/code>) command, then what I&rsquo;m doing above may seem\npointlessly elaborate. To an extent, I agree. In fact, I&rsquo;m using the <code>:t<\/code> command for the\n<kbd>,uu<\/kbd> mapping which is for duplicating a single line. The difference is that where <code>:t<\/code>\nonly works line-wise, my implementation above can work character wise as well as line wise. For\nexample, <kbd>,uaw<\/kbd> (or just <kbd>,uw<\/kbd>) will duplicate a single word, just like\n<kbd>,uap<\/kbd> will duplicate a paragraph.<\/p>\n<h2 id=\"transpose\">Transpose<a class=\"headerlink\" href=\"#transpose\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is another mapping I created to help me with CSV files. Specifically, this one works with\ntab-separated files, which are even more awesome to edit in Vim, thanks to the <a href=\"https:\/\/vimhelp.org\/options.txt.html#%27vartabstop%27\" rel=\"noopener noreferrer\" target=\"_blank\">vartabstop<\/a>\noption. The next section describes how I use this when editing tab separated files.<\/p>\n<p>This mapping, when applied over lines with tab separated values, will transpose the matrix made of\nlines and tabs. Check out the GIF below to get a better understanding of how this works.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Transpose tab separated values in selection or over motion.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> gt :<span class=\"k\">set<\/span> <span class=\"nb\">opfunc<\/span><span class=\"p\">=<\/span>Transpose<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span>@\n<\/span><span><span class=\"nb\">vnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> gt :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> Transpose<span class=\"p\">(<\/span><span class=\"m\">1<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span> Transpose<span class=\"p\">(<\/span>...<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> vis <span class=\"p\">=<\/span> get<span class=\"p\">(<\/span><span class=\"k\">a<\/span>:<span class=\"m\">000<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">marks<\/span> <span class=\"p\">=<\/span> vis ? <span class=\"s1\">&#39;&lt;&gt;&#39;<\/span> : <span class=\"s1\">&#39;[]&#39;<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l1<span class=\"p\">,<\/span> c1<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">0<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l2<span class=\"p\">,<\/span> c2<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">1<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:<span class=\"nb\">lines<\/span> <span class=\"p\">=<\/span> map<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span>l1<span class=\"p\">,<\/span> l2<span class=\"p\">),<\/span> <span class=\"s1\">&#39;split(v:val, &quot;\\t&quot;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">py3<\/span> <span class=\"p\">&lt;&lt;<\/span>EOPYTHON\n<\/span><span>import <span class=\"k\">vim<\/span>\n<\/span><span>from itertools import zip_longest\n<\/span><span>out <span class=\"p\">=<\/span> <span class=\"nb\">list<\/span><span class=\"p\">(<\/span>zip_longest<span class=\"p\">(<\/span>*<span class=\"k\">vim<\/span>.eval<span class=\"p\">(<\/span><span class=\"s1\">&#39;l:lines&#39;<\/span><span class=\"p\">),<\/span> fillvalue<span class=\"p\">=<\/span><span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span>EOPYTHON\n<\/span><span>    <span class=\"k\">let<\/span> out <span class=\"p\">=<\/span> map<span class=\"p\">(<\/span>py3eval<span class=\"p\">(<\/span><span class=\"s1\">&#39;out&#39;<\/span><span class=\"p\">),<\/span> <span class=\"s1\">&#39;join(v:val, &quot;\\t&quot;)&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">call<\/span> append<span class=\"p\">(<\/span>l2<span class=\"p\">,<\/span> out<span class=\"p\">)<\/span>\n<\/span><span>    exe l1 . <span class=\"s1\">&#39;,&#39;<\/span> . l2 . <span class=\"s1\">&#39;delete _&#39;<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">Needs <code>+python3<\/code>.<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/vim-transpose.gif\"><img alt=\"Demo of transpose mapping\" src=\"https:\/\/sharats.me\/static\/vim-transpose.gif\"><\/a><\/p>\n<p>The keys I&rsquo;m hitting in the GIF is <kbd>gtip<\/kbd>. I&rsquo;m transposing the lines in the inner\nparagraph.<\/p>\n<p>Note that I&rsquo;m using <code>:py3<\/code> for this, so, <code>+python3<\/code> would be required for this to work. I might port\nit to Vimscript one of these days, hopefully.<\/p>\n<h2 id=\"using-vartabstop-to-line-up\">Using <code>vartabstop<\/code> to Line Up<a class=\"headerlink\" href=\"#using-vartabstop-to-line-up\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The moment I learnt about the <code>vartabstop<\/code> option, I jumped on it right away, considering I worked\nwith tab separated files a lot. I created the following command that would scan the file&rsquo;s contents\nand set the value of this option such that all the columns would line up perfectly, almost like a\nspreadsheet.<\/p>\n<p class=\"note\">The <code>vartabstop<\/code> option is not available in Neovim, which is one of the reasons I don&rsquo;t use it yet.\nI just got too used to <code>vartabstop<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span>command TabsLineUp <span class=\"k\">call<\/span> <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>TabsLineUp<span class=\"p\">()<\/span>\n<\/span><span><span class=\"k\">fun<\/span> s:TabsLineUp<span class=\"p\">()<\/span> abort\n<\/span><span>    <span class=\"k\">py3<\/span> <span class=\"p\">&lt;&lt;<\/span>EOPYTHON\n<\/span><span>import <span class=\"k\">vim<\/span>\n<\/span><span>lengths <span class=\"p\">=<\/span> []\n<\/span><span><span class=\"k\">for<\/span> parts <span class=\"k\">in<\/span> <span class=\"p\">(<\/span><span class=\"k\">l<\/span>.split<span class=\"p\">(<\/span><span class=\"s1\">&#39;\\t&#39;<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"k\">l<\/span> <span class=\"k\">in<\/span> <span class=\"k\">vim<\/span>.current.buffer <span class=\"k\">if<\/span> <span class=\"s1\">&#39;\\t&#39;<\/span> <span class=\"k\">in<\/span> <span class=\"k\">l<\/span><span class=\"p\">)<\/span>:\n<\/span><span>    lengths.append<span class=\"p\">(<\/span>[len<span class=\"p\">(<\/span><span class=\"k\">c<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"k\">c<\/span> <span class=\"k\">in<\/span> parts]<span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">vim<\/span>.current.buffer.<span class=\"k\">options<\/span>[<span class=\"s1\">&#39;vartabstop&#39;<\/span>] <span class=\"p\">=<\/span> <span class=\"s1\">&#39;,&#39;<\/span>.<span class=\"k\">join<\/span><span class=\"p\">(<\/span>str<span class=\"p\">(<\/span>max<span class=\"p\">(<\/span><span class=\"k\">ls<\/span><span class=\"p\">)<\/span> <span class=\"p\">+<\/span> <span class=\"m\">3<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"k\">ls<\/span> <span class=\"k\">in<\/span> zip<span class=\"p\">(<\/span>*lengths<span class=\"p\">))<\/span>\n<\/span><span>EOPYTHON\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">Needs <code>+python3<\/code>.<\/p>\n<p>Here&rsquo;s a nice GIF showing this off! Note that although it looks like we&rsquo;re just adding a lot of\nwhite space to align stuff, <em>no new space characters are inserted<\/em>. The document remains unchanged.\nIt&rsquo;s just the display size of tab characters is what we&rsquo;re changing with <code>vartabstop<\/code>.<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/vim-tabs-line-up-demo.gif\"><img alt=\"Tabs line up demo\" src=\"https:\/\/sharats.me\/static\/vim-tabs-line-up-demo.gif\"><\/a><\/p>\n<p>Finally, tab separated files are easier to deal with than comma separated files.<\/p>\n<p>Also, if you&rsquo;re into CSV and tab separated files, I recommend checking out the amazing <a href=\"https:\/\/github.com\/chrisbra\/csv.vim\" rel=\"noopener noreferrer\" target=\"_blank\">csv.vim<\/a>\nplugin. It makes similar use of the <code>vartabstop<\/code> option.<\/p>\n<h2 id=\"strip-trailing-spaces\">Strip Trailing Spaces<a class=\"headerlink\" href=\"#strip-trailing-spaces\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I know trailing whitespace doesn&rsquo;t bother a lot of people much, but it does upset me. Most of the\nsolutions I found online to remove trailing whitespace operate on the whole file. I wanted it to\nwork with the lines over a motion, like inner paragraph etc. Of course, I could just visually select\nthe text object and then do a <code>:s\/\\s\\+$\/\/<\/code>, but that&rsquo;s too much effort!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Strip all trailing spaces in the selection, or over motion.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">x<\/span> :<span class=\"k\">set<\/span> <span class=\"nb\">opfunc<\/span><span class=\"p\">=<\/span>StripRight<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span>@\n<\/span><span><span class=\"nb\">vnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">x<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> StripRight<span class=\"p\">(<\/span><span class=\"m\">1<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span> StripRight<span class=\"p\">(<\/span>...<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">cp<\/span> <span class=\"p\">=<\/span> getcurpos<span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">marks<\/span> <span class=\"p\">=<\/span> get<span class=\"p\">(<\/span><span class=\"k\">a<\/span>:<span class=\"m\">000<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">)<\/span> ? <span class=\"s1\">&#39;&lt;&gt;&#39;<\/span> : <span class=\"s1\">&#39;[]&#39;<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l1<span class=\"p\">,<\/span> c1<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">0<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l2<span class=\"p\">,<\/span> c2<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">1<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    exe <span class=\"s1\">&#39;keepjumps &#39;<\/span> . l1 . <span class=\"s1\">&#39;,&#39;<\/span> . l2 . <span class=\"s1\">&#39;s\/\\s\\+$\/\/e&#39;<\/span>\n<\/span><span>    <span class=\"k\">call<\/span> setpos<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">,<\/span> <span class=\"k\">cp<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The above snippet defines a mapping, <kbd>,x<\/kbd> which operates on a motion and removes trailing\nwhitespace. There&rsquo;s some nice additions to this, in that it works in visual mode as well, and that\nthe cursor doesn&rsquo;t move as a result of this operation.<\/p>\n<p>Removing trailing whitespace inside current paragraph is now <kbd>,xip<\/kbd>!<\/p>\n<h2 id=\"append-character-over-motion\">Append character over motion<a class=\"headerlink\" href=\"#append-character-over-motion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This mapping lets me add a character at the end of all lines over a motion. So, like,\n<kbd>ga;ip<\/kbd> would add a semicolon to every line inside the paragraph.<\/p>\n<p>I use this mostly to add commas or tab characters when working with CSV (or tab-separated files).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Append a letter to all lines in motion.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>expr<span class=\"p\">&gt;<\/span> ga <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>AppendToLines<span class=\"p\">(<\/span><span class=\"s1\">&#39;n&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>xnoremap <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> ga :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>AppendToLines<span class=\"p\">(<\/span>visualmode<span class=\"p\">())&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">fun<\/span> s:AppendToLines<span class=\"p\">(<\/span><span class=\"k\">mode<\/span><span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">c<\/span> <span class=\"p\">=<\/span> getchar<span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"k\">while<\/span> <span class=\"k\">c<\/span> <span class=\"p\">==<\/span> <span class=\"s2\">&quot;\\&lt;CursorHold&gt;&quot;<\/span> <span class=\"p\">|<\/span> <span class=\"k\">let<\/span> <span class=\"k\">c<\/span> <span class=\"p\">=<\/span> getchar<span class=\"p\">()<\/span> <span class=\"p\">|<\/span> <span class=\"k\">endwhile<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">g<\/span>:_append_to_lines <span class=\"p\">=<\/span> nr2char<span class=\"p\">(<\/span><span class=\"k\">c<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"k\">a<\/span>:<span class=\"k\">mode<\/span> <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;n&#39;<\/span>\n<\/span><span>        exe <span class=\"s1\">&#39;set opfunc=&#39;<\/span> . s:SID<span class=\"p\">()<\/span> . <span class=\"s1\">&#39;AppendToLinesOpFunc&#39;<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"s1\">&#39;g@&#39;<\/span>\n<\/span><span>    <span class=\"k\">else<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> s:AppendToLinesOpFunc<span class=\"p\">(<\/span><span class=\"s1\">&#39;v&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">endif<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">fun<\/span> s:AppendToLinesOpFunc<span class=\"p\">(<\/span>type<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">marks<\/span> <span class=\"p\">=<\/span> <span class=\"k\">a<\/span>:type <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;v&#39;<\/span> ? <span class=\"s1\">&#39;&lt;&gt;&#39;<\/span> : <span class=\"s1\">&#39;[]&#39;<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"k\">l<\/span> <span class=\"k\">in<\/span> range<span class=\"p\">(<\/span>line<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">0<\/span>]<span class=\"p\">),<\/span> line<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">1<\/span>]<span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> setline<span class=\"p\">(<\/span><span class=\"k\">l<\/span><span class=\"p\">,<\/span> getline<span class=\"p\">(<\/span><span class=\"k\">l<\/span><span class=\"p\">)<\/span> . <span class=\"k\">g<\/span>:_append_to_lines<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">endfor<\/span>\n<\/span><span>    unlet <span class=\"k\">g<\/span>:_append_to_lines\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This may seem pointless in that, it&rsquo;s not very hard to do this with visual block mode. Sure. On that\nnote, even <kbd>A<\/kbd> is pretty pointless, it can be done with just <kbd>$a<\/kbd>, right? No. The\npoint here is not about having a shorter key sequence to do this, but a more semantic one. Just like\n<kbd>A<\/kbd> spells &ldquo;append at end of line&rdquo;, to me, <kbd>ga;ip<\/kbd> spells &ldquo;adding semicolon to\nevery line in the paragraph&rdquo;. Personally, I think better this way.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Text objects in Vim (and motions, for the most part) have effectively solved the problem of being\nable expressively select a piece of text to work on. However, in my opinion, the kind of work that\ncan be done on such text is equally (if not more) important. Try to identify what you often do after\nselecting text with text objects and see if you can turn it into an operator mapping like those in\nthis write-up.<\/p>\n<p>This one is shorter than usual and that&rsquo;s not because of lack of content, it&rsquo;s more because of\nterrible planning on my part. Nevertheless, stay tuned for more in this series!<\/p>\n<p class=\"note\">Read the <a href=\"..\/automating-the-vim-workplace-2\/\">previous article<\/a> in this series.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"vim"}},{"@attributes":{"term":"productivity"}}]},{"title":"The Weird `global`","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-weird-global\/","rel":"alternate"}},"published":"2020-03-08T00:00:00+05:30","updated":"2020-03-08T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-03-08:\/posts\/the-weird-global\/","summary":"<p>Python&rsquo;s <code>global<\/code> keyword allows us to change the value of module-level variables inside functions.\nSounds so simple and useful, doesn&rsquo;t it? Well, yeah. I&rsquo;m going to show you how it can be useful in\nthe simple sense and situations where it can drive people nuts.<\/p>\n<h2 id=\"simple-usage\">Simple Usage \u2026<\/h2>","content":"<p>Python&rsquo;s <code>global<\/code> keyword allows us to change the value of module-level variables inside functions.\nSounds so simple and useful, doesn&rsquo;t it? Well, yeah. I&rsquo;m going to show you how it can be useful in\nthe simple sense and situations where it can drive people nuts.<\/p>\n<h2 id=\"simple-usage\">Simple Usage<a class=\"headerlink\" href=\"#simple-usage\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Consider the following <code>top.py<\/code> script. We have a single module-level (aka <code>global<\/code>) variable here,\nand we change its value in the function <code>done<\/code>.<\/p>\n<div class=\"hl\"><div class=filename><span>top.py<\/span><\/div><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">are_we_done<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">False<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">mark_done<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"k\">global<\/span> <span class=\"n\">are_we_done<\/span>\n<\/span><span>    <span class=\"n\">are_we_done<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">True<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Done?&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">are_we_done<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">mark_done<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;Done?&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">are_we_done<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Running this, we get the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Done? False\n<\/span><span>Done? True\n<\/span><\/code><\/pre><\/div>\n\n<p>The reason we were able to change the value of the global variable <code>are_we_done<\/code> from inside the\n<code>mark_done<\/code> function is because we declared it as such on line 5. If that declaration isn&rsquo;t there,\nwe&rsquo;d just be defining a new <em>function level variable<\/em> called <code>are_we_done<\/code> inside the <code>mark_done<\/code>\nfunction. Which is not what we wanted.<\/p>\n<h2 id=\"refer-directly\">Refer Directly<a class=\"headerlink\" href=\"#refer-directly\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Note that declaring variables as <code>global<\/code> is needed only when we&rsquo;re <em>modifying the value of the\nvariable<\/em>. That means if we are only accessing the variable, we don&rsquo;t need to declare it as\n<code>global<\/code>. This is how capitalized constant variables work in most Python scripts:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">CURRENT_PLANET<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;Earth&quot;<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">get_moon_count<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"n\">CURRENT_PLANET<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;Earth&quot;<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"mi\">1<\/span>\n<\/span><span>    <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"k\">raise<\/span> <span class=\"ne\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;No idea!&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">get_moon_count<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This, of course, prints out <code>1<\/code>. Here, we are using the <code>CURRENT_PLANET<\/code> global variable inside the\nfunction without declaring it as global. Accessing doesn&rsquo;t <em>require<\/em> explicitly declaring as\n<code>global<\/code>.<\/p>\n<h3 id=\"modifying-the-referred-object\">Modifying the Referred Object<a class=\"headerlink\" href=\"#modifying-the-referred-object\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>A small note on the terms we&rsquo;ve been using here. Accessing doesn&rsquo;t require <code>global<\/code> declaration, but\nmodifying does. Now look at the following code snippet:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">CALLS<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">record_call<\/span><span class=\"p\">(<\/span><span class=\"n\">phone_number<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">CALLS<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">phone_number<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">record_call<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;123-45-678&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">record_call<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;987-65-432&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">CALLS<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, since we are appending to the <code>CALLS<\/code> list, is that considered modifying the global variable?\nThe answer is <em>no<\/em>. We are merely <em>accessing<\/em> the <code>CALLS<\/code> variable&rsquo;s value, which happens to be a\n<code>list<\/code>, on which we call the <code>.append<\/code> method. There&rsquo;s no modifying going on here so far. The\n<code>.append<\/code> method, however, will change the <em>state<\/em> of the <code>list<\/code> object. But for the purposes of\nusing the <code>CALLS<\/code> variable here, we are only accessing it. So, we don&rsquo;t need to declare it as\n<code>global<\/code>.<\/p>\n<p>So what <em>does<\/em> modifying mean? Simply put, if you want to reassign a global variable, it&rsquo;s\nconsidered as modifying.<\/p>\n<h2 id=\"assigning-without-declaring\">Assigning without Declaring<a class=\"headerlink\" href=\"#assigning-without-declaring\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This behaviour of global variables causes some slightly unintuitive situations. For example,\nconsider the following piece of code:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">is_server_up<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">False<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">mark_server_up<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">is_server_up<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">mark_server_up<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this script, we are using the global variable <code>is_server_up<\/code> on line 5, without declaring it as\n<code>global<\/code>, and it works fine. Now, we add another line to this function:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">is_server_up<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">False<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">mark_server_up<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">is_server_up<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">is_server_up<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">True<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">mark_server_up<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>If we run this script, we get the following error:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Traceback (most recent call last):\n<\/span><span>  File &quot;\/check.py&quot;, line 9, in &lt;module&gt;\n<\/span><span>    mark_server_up()\n<\/span><span>  File &quot;\/check.py&quot;, line 5, in mark_server_up\n<\/span><span>    print(is_server_up)\n<\/span><span>UnboundLocalError: local variable &#39;is_server_up&#39; referenced before assignment\n<\/span><\/code><\/pre><\/div>\n\n<p>Okay, we kind of expected an error because we are trying to modify a global variable without\ndeclaring it. But note that the error comes from <strong>line 5<\/strong>, not on <strong>line 6<\/strong>, where we are\nmodifying the variable. The error message gives a hint on what&rsquo;s happening.<\/p>\n<div class=\"hl\"><pre class=content><code><span>local variable &#39;is_server_up&#39; referenced before assignment\n<\/span><\/code><\/pre><\/div>\n\n<p>Since we didn&rsquo;t declare <code>is_server_up<\/code> as global, and since we are setting a value to\n<code>is_server_up<\/code>, Python decided that we want a local variable in our function with the same name.\nWith that understanding, it looks like we are referencing the <code>is_server_up<\/code> <em>local variable<\/em> before\nassigning a value to it. That&rsquo;s the error we see here.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Global variables have their place, but, if it&rsquo;s not for constant-like values, I&rsquo;d recommend against\nusing global variables at all. It might make sense for small one-off scripts, and when it does, keep\nthe above small details in mind.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"rant"}}]},{"title":"The Magic of AutoHotkey","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-magic-of-autohotkey\/","rel":"alternate"}},"published":"2020-03-01T00:00:00+05:30","updated":"2020-03-01T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-03-01:\/posts\/the-magic-of-autohotkey\/","summary":"<p>For the past several years, my primary work station has been Windows 7. After the initial swearing\nat how things work differently (coming from Linux), I got used to it and started to really like it,\nin some ways. A big part of the reason for that on Windows is \u2026<\/p>","content":"<p>For the past several years, my primary work station has been Windows 7. After the initial swearing\nat how things work differently (coming from Linux), I got used to it and started to really like it,\nin some ways. A big part of the reason for that on Windows is <a href=\"https:\/\/www.autohotkey.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">AutoHotkey<\/a>.<\/p>\n<p>I will document my automations and experiences over the years in this two-part article series.<\/p>\n<ol>\n<li>Part 1 (this article).<\/li>\n<li><a href=\"..\/the-magic-of-autohotkey-2\/\">Part 2<\/a><\/li>\n<\/ol>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#the-setup\">The Setup<\/a><\/li>\n<li><a href=\"#the-common-magic\">The Common Magic<\/a><ul>\n<li><a href=\"#reload-autohotkey-script\">Reload AutoHotkey Script<\/a><\/li>\n<li><a href=\"#open-the-toolbar-calendar\">Open the Toolbar Calendar<\/a><\/li>\n<li><a href=\"#hide-the-show-desktop-button\">Hide the Show Desktop Button<\/a><\/li>\n<li><a href=\"#type-clipboard-contents\">Type Clipboard Contents<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#close-on-escape-key\">Close on Escape Key<\/a><\/li>\n<li><a href=\"#the-caps-lock-story\">The Caps Lock Story<\/a><\/li>\n<li><a href=\"#inserting-snippets\">Inserting Snippets<\/a><\/li>\n<li><a href=\"#window-watcher\">Window Watcher<\/a><\/li>\n<li><a href=\"#mess-with-images-in-clipboard\">Mess with Images in Clipboard<\/a><\/li>\n<li><a href=\"#periodic-time-display\">Periodic Time Display<\/a><\/li>\n<li><a href=\"#vim-keys-for-sumatra-pdf\">Vim Keys for Sumatra PDF<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<p><a href=\"https:\/\/www.autohotkey.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">AutoHotkey<\/a> is an open-source programming language for Windows, that lends itself extremely well\nto tasks within the GUI scripting and automation domains. The hotkey functionality is particularly\ngood, something I haven&rsquo;t found in any other general purpose programming language (<a href=\"https:\/\/www.autoitscript.com\/site\/\" rel=\"noopener noreferrer\" target=\"_blank\">AutoIt<\/a> most\nlikely comes close, but I&rsquo;ve never tried it so can&rsquo;t speak for it).<\/p>\n<p>The language itself may seem a bit flaky around the syntax and some of its constructs, but once we\nget used to them, we can leverage the powerful engine underneath it. That, combined with the\nwell-written documentation, makes AutoHotkey a must-have tool for any Windows power user.<\/p>\n<p>Some hotkeys I use (few that I can&rsquo;t show off here) are so well integrated into my daily\nworkflow, that my fingers just flow on the keyboard and things happen on screen that are hard to\nfollow for others.<\/p>\n<blockquote>\n<p>Any sufficiently advanced technology is indistinguishable from magic.<\/p>\n<p>&ndash; <em>Clarke&rsquo;s Third Law, 1973<\/em><\/p>\n<\/blockquote>\n<p>In these articles, I&rsquo;ll share some of the hotkeys I use, how I came about them and how they improve\nmy workflow. It is not a beginner&rsquo;s AutoHotkey tutorial, that would be the official documentation or\nthe many other resources available online.<\/p>\n<p class=\"note\">A lot of the stuff in this article is made possible by a lot of help from all over the internet, and\nespecially the AutoHotkey forums. Due to most of it being at least a few years old, I don&rsquo;t have the\nexact source links. So, thank you everyone!<\/p>\n<h2 id=\"the-setup\">The Setup<a class=\"headerlink\" href=\"#the-setup\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I usually have one AutoHotkey script running at all times (called <code>master.ahk<\/code>). I <code>#Include<\/code> other\nscripts into this so that all my hotkeys and automations aren&rsquo;t just dumped into one large\n<code>master.ahk<\/code>. It starts off with the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#NoEnv<\/span>\n<\/span><span><span class=\"nb\">#SingleInstance<\/span> <span class=\"n\">force<\/span>\n<\/span><span><span class=\"n\">#Warn<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">SendMode<\/span> <span class=\"n\">Input<\/span>\n<\/span><span><span class=\"nb\">SetWorkingDir<\/span> <span class=\"nv\">%A_ScriptDir%<\/span><span class=\"c1\"> ; Default in autohotkey v2.<\/span>\n<\/span><span><span class=\"nb\">AutoTrim<\/span><span class=\"p\">,<\/span> <span class=\"n\">Off<\/span><span class=\"c1\"> ; Default in autohotkey v2.<\/span>\n<\/span><span><span class=\"nb\">SetTitleMatchMode<\/span> <span class=\"n\">RegEx<\/span>\n<\/span><span><span class=\"nb\">SetNumlockState<\/span><span class=\"p\">,<\/span> <span class=\"n\">AlwaysOn<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">EnvGet<\/span><span class=\"p\">,<\/span> <span class=\"n\">homedir<\/span><span class=\"p\">,<\/span> <span class=\"n\">USERPROFILE<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Most of this I learned to be a best practice from the documentation and from the forums. Please look\nup the documentation for these individual directives, I won&rsquo;t repeat them here.<\/p>\n<h2 id=\"the-common-magic\">The Common Magic<a class=\"headerlink\" href=\"#the-common-magic\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>These are essentials that are general enough that I believe everyone using AutoHotkey should have.\nLet&rsquo;s quickly run these down, so we can move on to more exciting stuff.<\/p>\n<h3 id=\"reload-autohotkey-script\">Reload AutoHotkey Script<a class=\"headerlink\" href=\"#reload-autohotkey-script\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The script <code>master.ahk<\/code> that is running in the background at all times contains some of my hotkeys\nand the rest are <code>#Include<\/code>-ed from other AutoHotkey scripts. I include the below snippet in this\nscript and when I hit <kbd>#+r<\/kbd>, the changes in <code>master.ahk<\/code> and any included scripts are\nreloaded.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nl\">#+r::<\/span><span class=\"n\">Reload<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">All script snippets discussed here, if and when added to your master script, would start working\nfine with a Reload like above. No need to quit it and start again.<\/p>\n<h3 id=\"open-the-toolbar-calendar\">Open the Toolbar Calendar<a class=\"headerlink\" href=\"#open-the-toolbar-calendar\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>It&rsquo;s really sad that there&rsquo;s no default hotkey to have a calendar pop open on Windows. Clicking on\nthe time displayed at the right of the toolbar does show a handy calendar, but there&rsquo;s no hotkey for\nit. The following solves this exact problem. We use the <kbd>#b<\/kbd> hotkey which gives focus to\nthe system tray. Then we navigate to the time and hit the <kbd>{Enter}<\/kbd> key.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nl\">#i::<\/span><span class=\"n\">Send<\/span> <span class=\"n\">#b<\/span><span class=\"p\">{<\/span><span class=\"n\">Left<\/span><span class=\"p\">}{<\/span><span class=\"n\">Enter<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There&rsquo;s a problem with this though. Once the calendar opens up, and we close it by hitting the\n<kbd>Escape<\/kbd> key, the focus is not returned to the window that had focus originally. The\nworkaround for me has been to do <kbd>Alt+Tab<\/kbd> a couple of times, and we&rsquo;re back to work.<\/p>\n<p class=\"note\">It&rsquo;s still arguable how useful this solution is. The pop-up Calendar has very limited functionality.\nThe most annoying this is probably that I spend a few seconds selecting the month I want to look at\nand accidentally click on another window and that Calendar is gone! After a lot of swearing, I\nattempted to solve this problem and built <a href=\"https:\/\/justacalendar.app\" rel=\"noopener noreferrer\" target=\"_blank\">justacalendar.app<\/a>. It&rsquo;s\nsuper-quick, no-login-required, light-weight, just a calendar to look at, and mark dates to top. Do\ncheck it out! Thanks.<\/p>\n<h3 id=\"hide-the-show-desktop-button\">Hide the Show Desktop Button<a class=\"headerlink\" href=\"#hide-the-show-desktop-button\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Every time my mouse moves to the bottom right corner, all my windows go transparent, and <em>almost<\/em>\nreduce me to swearing again. Now, I know we can turn this behaviour off by disabling Aero or some\nother setting and I can even agree that this feature can be useful. But to me, firstly, I hardly\nkeep anything on my Desktop, so its mere existence is quite useless to me. Secondly, even if I\nwanted to look at the desktop, it&rsquo;s a quick <kbd>#d<\/kbd> away, which is much faster considering my\nfingers are almost always on the keyboard.<\/p>\n<p>So I decided to hide the &ldquo;Show Desktop&rdquo; button with the following snippet:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">Control<\/span><span class=\"p\">,<\/span> <span class=\"n\">Hide<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">TrayShowDesktopButtonWClass1<\/span>\n<\/span><span>    <span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">Shell_TrayWnd<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">explorer<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This doesn&rsquo;t reclaim the space occupied by the button, but the button disappears and the above\nproblem goes away, so, I&rsquo;m not complaining.<\/p>\n<h3 id=\"type-clipboard-contents\">Type Clipboard Contents<a class=\"headerlink\" href=\"#type-clipboard-contents\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Remember how some websites (especially bank websites) disallow pasting values into inputs. This is\nextremely annoying when using a password manager or when I want to just paste something. I&rsquo;ve tried\nseveral solutions to this, and the current answer I have with AutoHotkey has served me the best.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nl\">#v::<\/span><span class=\"n\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"n\">Raw<\/span><span class=\"p\">}<\/span><span class=\"nv\">%Clipboard%<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The idea is that instead of sending a paste operation, we have AutoHotkey <em>type out the contents of\nthe clipboard<\/em>. This has the additional benefit of stripping any formatting in the text in the\nclipboard, if for instance, we&rsquo;ve copied something from a website or a Word document with heavy\nformatting.<\/p>\n<h2 id=\"close-on-escape-key\">Close on Escape Key<a class=\"headerlink\" href=\"#close-on-escape-key\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>There are some windows that I&rsquo;d love to close with just a tap on the <kbd>Escape<\/kbd> key, but they\ndon&rsquo;t. A few examples of where I (instinctively) expect this are the photo viewer, font viewer, the\nplaylist in VLC etc. Then there&rsquo;s another set of windows that I found myself trying to close by\nhitting <kbd>^w<\/kbd> (this intuition likely comes from its behaviour in Firefox and Chrome).\nEither way, I needed these keys to act the way I was expecting them to.<\/p>\n<p>There&rsquo;s two parts to the solution to this. First, we define the hotkeys to close the windows on\n<strong>window groups<\/strong>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">CloseOnEsc<\/span>\n<\/span><span><span class=\"nl\">Escape::<\/span><span class=\"n\">PostMessage<\/span> <span class=\"mh\">0x112<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0xF060<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_group<\/span> <span class=\"n\">CloseOnCW<\/span>\n<\/span><span><span class=\"o\">^<\/span><span class=\"n\">w<\/span><span class=\"o\">::<\/span><span class=\"n\">PostMessage<\/span> <span class=\"mh\">0x112<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0xF060<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>What we&rsquo;re doing here is define two hotkeys. First, for all windows in the group called\n<code>CloseOnEsc<\/code>, define the hotkey <kbd>Escape<\/kbd> to close the window (the <code>PostMessage<\/code> part, which\nwe&rsquo;ll get to in a bit). Second, a similar hotkey on <kbd>^w<\/kbd> for windows in the group\n<code>CloseOnCW<\/code>.<\/p>\n<p>Now, you might&rsquo;ve noticed that we don&rsquo;t use the <code>WinClose<\/code> command to close the window. The reason\nis that for some applications (such as Lync), the <code>WinClose<\/code> command <em>quits<\/em> the application instead\nof just sending it back to the tray. The <code>PostMessage<\/code> command above would behave exactly like\nhitting the red close button at the top right of the window.<\/p>\n<p>In the second part of this exercise, we add windows to the groups:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><\/pre><pre class=content><code><span><span class=\"c1\">; Windows that should just disappear on ESC, but don&#39;t already.<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">Photo_Lightweight_Viewer<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">ConsoleWindowClass<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">Skype<\/span> <span class=\"n\">for<\/span> <span class=\"n\">Business<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">Vivaldi<\/span> <span class=\"n\">Settings<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">vivaldi<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">FontViewWClass<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">fontview<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnEsc<\/span><span class=\"p\">,<\/span> <span class=\"n\">Playlist<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">vlc<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\">; Windows that should close with C-w.<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnCW<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">Notepad<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">notepad<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><span><span class=\"nb\">GroupAdd<\/span><span class=\"p\">,<\/span> <span class=\"n\">CloseOnCW<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">FM<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"mi\">7<\/span><span class=\"n\">zFM<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This should be fairly self-explanatory. We add certain windows (as identified by <code>WinTitle<\/code> style\nfilters) and add them to the two groups, using the <code>GroupAdd<\/code> command.<\/p>\n<p>There&rsquo;s one special case here. The stock Windows Calculator app. This one clears the display on\nhitting <kbd>Escape<\/kbd> key. But I wanted it to close on <kbd>Escape<\/kbd> <strong>if<\/strong> the display is\nalready cleared.<\/p>\n<p>So, instead of including Calculator in the above group(s), I use the following snippet to handle\nthis special case.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">CalcFrame<\/span>\n<\/span><span><span class=\"nl\">$Escape::<\/span>\n<\/span><span><span class=\"n\">CloseOrClearCalculator<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">ControlGetText<\/span><span class=\"p\">,<\/span> <span class=\"n\">display<\/span><span class=\"p\">,<\/span> <span class=\"n\">Static4<\/span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">display<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;0&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nb\">WinClose<\/span>\n<\/span><span>    <span class=\"nb\">else<\/span>\n<\/span><span>        <span class=\"nb\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"n\">Escape<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"nb\">#IfWinActive<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will close the Calculator if the display is already <code>\"0\"<\/code>, but passes the <kbd>Escape<\/kbd> key\notherwise.<\/p>\n<h2 id=\"the-caps-lock-story\">The Caps Lock Story<a class=\"headerlink\" href=\"#the-caps-lock-story\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I use <a href=\"https:\/\/github.com\/randyrants\/sharpkeys\" rel=\"noopener noreferrer\" target=\"_blank\">SharpKeys<\/a> to turn my <kbd>Caps Lock<\/kbd> key into an additional <kbd>Ctrl<\/kbd> Key. This\nworks wonders considering that the <kbd>Ctrl<\/kbd> key is used a lot more often than the <kbd>Caps\nLock<\/kbd>, but the <kbd>Caps Lock<\/kbd> key is a lot easier to hit than any of the <kbd>Ctrl<\/kbd>\nkeys.<\/p>\n<p>If you&rsquo;re wondering why I don&rsquo;t do this with AutoHotkey, the reason is that if I did it with\nAutoHotkey, it would be active <em>only when the script is running<\/em>. Which means the remapping isn&rsquo;t\nactive in the lock screen (where I hit <kbd>Ctrl+A<\/kbd> often). But since SharpKeys modifies the\nregistry to achieve what it does, the remapping works even in the lock screen.<\/p>\n<p>Yet, sometimes I miss the original functionality of the <kbd>Caps Lock<\/kbd> key. So I created the\nfollowing hotkey for <kbd>#q<\/kbd> which will turn on Caps Lock mode, and show an annoying\nalways-on-top splash window alerting me to that fact. To turn it back off, it&rsquo;s <kbd>#q<\/kbd> again.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nl\">#q::<\/span>\n<\/span><span><span class=\"n\">ToggleCapsLock<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">if <\/span><span class=\"nf\">GetKeyState<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Capslock&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;T&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">SetCapsLockState<\/span><span class=\"p\">,<\/span> <span class=\"n\">Off<\/span>\n<\/span><span>        <span class=\"nb\">SplashTextOff<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">SetCapsLockState<\/span><span class=\"p\">,<\/span> <span class=\"n\">On<\/span>\n<\/span><span>        <span class=\"nb\">SplashTextOn<\/span><span class=\"p\">,<\/span> <span class=\"mi\">300<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"o\">&lt;&lt;<\/span> <span class=\"n\">CAPS<\/span> <span class=\"n\">LOCK<\/span> <span class=\"n\">ON<\/span> <span class=\"o\">&gt;&gt;<\/span> <span class=\"p\">(<\/span><span class=\"n\">Win<\/span><span class=\"o\">+<\/span><span class=\"n\">q<\/span> <span class=\"n\">to<\/span> <span class=\"n\">turn<\/span> <span class=\"n\">off<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nb\">WinSet<\/span><span class=\"p\">,<\/span> <span class=\"n\">Transparent<\/span><span class=\"p\">,<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span> <span class=\"o\">&lt;&lt;<\/span> <span class=\"n\">CAPS<\/span> <span class=\"n\">LOCK<\/span> <span class=\"n\">ON<\/span> <span class=\"o\">&gt;&gt;<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This actually works surprisingly well. I use it more often than I like to admit. It feels better\nthan using the original <kbd>Caps Lock<\/kbd> key, because I get an (hard-to-ignore) overlay that\nalerts me that Caps Lock is turned on.<\/p>\n<h2 id=\"inserting-snippets\">Inserting Snippets<a class=\"headerlink\" href=\"#inserting-snippets\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Inserting snippets is an idea where a long and often used string is inserted by a rather short\nsequence of keys. In AutoHotkey, this is <em>usually<\/em> done using <a href=\"https:\/\/www.autohotkey.com\/docs\/Hotstrings.htm\" rel=\"noopener noreferrer\" target=\"_blank\">hotstrings<\/a>. Hotstrings work <em>okay<\/em>\nfor this actually, but they don&rsquo;t work on every application. For me particularly, I needed them to\nbe working with GVim (which is where I write most of my prose), which they weren&rsquo;t. So, with a lot\nof help from the Internet, I came up with a solution.<\/p>\n<p>Instead of hotstrings, I&rsquo;ll use a hotkey that summons an OSD (on-screen-display) with a list of keys\nand their expansions. When this window is focused, I can hit one of those keys and the windows is\nimmediately closed and the corresponding expansion is typed out. This has been working unchanged for\nover four years for me and has never failed me.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-12><label for=co-12><span class='btn show-full-code-btn'>Show remaining 9 lines<\/span><\/label><div class=filename><span>snippets.ahk<\/span><\/div><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">SnippetsInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Snips<\/span><span class=\"o\">:<\/span> <span class=\"n\">Default<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Font<\/span><span class=\"p\">,<\/span> <span class=\"n\">s18<\/span> <span class=\"n\">q5<\/span><span class=\"p\">,<\/span> <span class=\"n\">Consolas<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Color<\/span><span class=\"p\">,<\/span> <span class=\"n\">FF0000<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Margin<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"o\">+<\/span><span class=\"n\">AlwaysOnTop<\/span> <span class=\"o\">+<\/span><span class=\"n\">Owner<\/span> <span class=\"o\">+<\/span><span class=\"n\">ToolWindow<\/span> <span class=\"o\">-<\/span><span class=\"n\">Caption<\/span> <span class=\"o\">+<\/span><span class=\"n\">HwndSnippetsHwnd<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">ListView<\/span><span class=\"p\">,<\/span> <span class=\"n\">r8<\/span> <span class=\"n\">w900<\/span><span class=\"p\">,<\/span> <span class=\"n\">Hotkey<\/span><span class=\"o\">|<\/span><span class=\"n\">Text<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"nb\">IniRead<\/span><span class=\"p\">,<\/span> <span class=\"n\">configText<\/span><span class=\"p\">,<\/span> <span class=\"n\">snippets<\/span><span class=\"o\">.<\/span><span class=\"n\">ini<\/span><span class=\"p\">,<\/span> <span class=\"n\">master<\/span>\n<\/span><span>    <span class=\"nb\">Loop<\/span><span class=\"p\">,<\/span> <span class=\"n\">Parse<\/span><span class=\"p\">,<\/span> <span class=\"n\">configText<\/span><span class=\"p\">,<\/span> <span class=\"se\">`n<\/span><span class=\"p\">,<\/span> <span class=\"se\">`r<\/span>\n<\/span><span>    <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">parts<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">StrSplit<\/span><span class=\"p\">(<\/span><span class=\"nv\">A_LoopField<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;=&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot; `t&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nf\">LV_Add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">parts<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span> <span class=\"n\">parts<\/span><span class=\"p\">[<\/span><span class=\"mi\">2<\/span><span class=\"p\">])<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">SnippetsShow<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">global<\/span> <span class=\"n\">SnippetsMap<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Snips<\/span><span class=\"o\">:<\/span> <span class=\"n\">Show<\/span><span class=\"p\">,<\/span> <span class=\"n\">NoActivate<\/span>\n<\/span><span>    <span class=\"nb\">Input<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">L1<\/span> <span class=\"n\">T3<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Snips<\/span><span class=\"o\">:<\/span> <span class=\"n\">Hide<\/span>\n<\/span><span class=collapse>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nv\">ErrorLevel<\/span> <span class=\"o\">!=<\/span> <span class=\"s\">&quot;Timeout&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">IniRead<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">,<\/span> <span class=\"n\">snippets<\/span><span class=\"o\">.<\/span><span class=\"n\">ini<\/span><span class=\"p\">,<\/span> <span class=\"n\">master<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%key%<\/span><span class=\"p\">,<\/span> <span class=\"n\">__SNIPPETS_KEY_NOT_FOUND__<\/span>\n<\/span><span class=collapse>        <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">value<\/span> <span class=\"o\">!=<\/span> <span class=\"s\">&quot;__SNIPPETS_KEY_NOT_FOUND__&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">SendInput<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%value%<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">else<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">MsgBox<\/span><span class=\"p\">,<\/span> <span class=\"n\">No<\/span> <span class=\"n\">snippet<\/span> <span class=\"n\">found<\/span> <span class=\"n\">for<\/span> <span class=\"nv\">%key%<\/span><span class=\"o\">.<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I have the above in a module called <code>snippets.ahk<\/code>, which I include in my master script. To use,\nfirst, I need a <code>snippets.ini<\/code> file in the same directory with expansions. I have things like the\nfollowing:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">[master]<\/span>\n<\/span><span><span class=\"na\">u<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"s\">sharat87<\/span>\n<\/span><span><span class=\"na\">m<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"s\">yeahhereismyaddress@gmail.com<\/span>\n<\/span><span><span class=\"na\">i<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"s\">{+}91 AND MY PHONE NUMBER<\/span>\n<\/span><span><span class=\"na\">s<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"s\">https:\/\/sharats.me\/<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There&rsquo;s more snippets on my system, this is just a preview, of course, duh!<\/p>\n<p>The next step is to include this module in our master script:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#Include<\/span> <span class=\"n\">snippets<\/span><span class=\"o\">.<\/span><span class=\"n\">ahk<\/span>\n<\/span><span><span class=\"n\">SnippetsInit<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Finally, we define a hotkey to summon the snippets window. I use <kbd>^;<\/kbd>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">^<\/span><span class=\"p\">;<\/span><span class=\"o\">::<\/span><span class=\"n\">SnippetsShow<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>That&rsquo;s it! Here it is in action:<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/autohotkey-snippets.gif\"><img alt=\"Snippets tool demo\" src=\"https:\/\/sharats.me\/static\/autohotkey-snippets.gif\"><\/a><\/p>\n<h2 id=\"window-watcher\">Window Watcher<a class=\"headerlink\" href=\"#window-watcher\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>My window watcher module (written as a <code>window-watcher.ahk<\/code>) lets me define actions to be taken when\nnew windows with certain properties show up.<\/p>\n<p>For example, I want all command line windows to always be moved to the top right corner or the\nscreen. As another example, there&rsquo;s some windows that open up with a window size equal to the whole\nscreen, but are not maximized. This one is particularly annoying since I have a habit of throwing my\nmouse to the top right corner and clicking to close the window. But since this window is not\nmaximized, I end up accidentally closing the window behind. So, I want such windows to be maximized\nas soon as they open.<\/p>\n<p>To address this, I have a <code>window-watcher.ahk<\/code> module that defines the logic of constantly polling\nthe visible windows and detecting if anything is opened or closed. This module defines the function\n<code>WindowWatcherInit<\/code> (among others), which needs to be called once to initialize the polling timer.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-13><label for=co-13><span class='btn show-full-code-btn'>Show remaining 17 lines<\/span><\/label><div class=filename><span>window-watchers.ahk<\/span><\/div><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><span class=collapse>37\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">WindowWatcherInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">static<\/span> <span class=\"n\">initDone<\/span> <span class=\"o\">:=<\/span> <span class=\"nv\">false<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">initDone<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nb\">return<\/span>\n<\/span><span>    <span class=\"n\">initDone<\/span> <span class=\"o\">:=<\/span> <span class=\"nv\">true<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"nb\">SetTimer<\/span><span class=\"p\">,<\/span> <span class=\"n\">WindowWatcherPollForNewWindows<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">WindowWatcherTrigger<\/span><span class=\"p\">(<\/span><span class=\"n\">wParam<\/span><span class=\"p\">,<\/span> <span class=\"n\">hwnd<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">wParam<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Created&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">OnWindowCreated<\/span><span class=\"p\">(<\/span><span class=\"n\">hwnd<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"c1\">    ; } else if (wParam == &quot;Destroyed&quot;) {<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">WindowWatcherPollForNewWindows<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">static<\/span> <span class=\"n\">windows<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>    <span class=\"nb\">WinGet<\/span><span class=\"p\">,<\/span> <span class=\"n\">wins<\/span><span class=\"p\">,<\/span> <span class=\"n\">List<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"p\">,<\/span>\n<\/span><span class=collapse>    <span class=\"n\">newWindows<\/span> <span class=\"o\">:=<\/span> <span class=\"nf\">Object<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"nb\">Loop<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%wins%<\/span>\n<\/span><span class=collapse>    <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"n\">this_id<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">wins<\/span><span class=\"nv\">%A_Index%<\/span>\n<\/span><span class=collapse>        <span class=\"n\">newWindows<\/span><span class=\"p\">[<\/span><span class=\"n\">this_id<\/span><span class=\"p\">]<\/span> <span class=\"o\">:=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span class=collapse>        <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">windows<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"o\">!<\/span><span class=\"n\">windows<\/span><span class=\"p\">[<\/span><span class=\"n\">this_id<\/span><span class=\"p\">])<\/span>\n<\/span><span class=collapse>            <span class=\"n\">WindowWatcherTrigger<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Created&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">this_id<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">for<\/span> <span class=\"n\">wid<\/span><span class=\"p\">,<\/span> <span class=\"n\">p<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">windows<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">newWindows<\/span><span class=\"p\">[<\/span><span class=\"n\">wid<\/span><span class=\"p\">])<\/span>\n<\/span><span class=collapse>            <span class=\"n\">WindowWatcherTrigger<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Destroyed&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">wid<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">windows<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">newWindows<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>From then on, any time a new window is detected, the <code>OnWindowCreated<\/code> function is called with the\nnew window&rsquo;s <code>hwnd<\/code> passed as the only argument. In this function, I match this window ID with\nvarious types of windows and take the action I need. Here&rsquo;s a short preview of that function (in\nreality, the function is 81 lines long in my master script).<\/p>\n<div class=\"hl\"><input type=checkbox id=co-14><label for=co-14><span class='btn show-full-code-btn'>Show remaining 9 lines<\/span><\/label><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">OnWindowCreated<\/span><span class=\"p\">(<\/span><span class=\"n\">hwnd<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">global<\/span> <span class=\"n\">homedir<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\">    ; Close &quot;Illegal IP Address&quot; alerts.<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">WinExist<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Application Error ahk_exe jweblauncher.exe ahk_id &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">hwnd<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">PostMessage<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0x112<\/span><span class=\"p\">,<\/span> <span class=\"mh\">0xF060<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\">    ; Close &quot;Kyeboard History Utility&quot; alerts.<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">WinExist<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Keyboard History Utility ahk_exe WerFault.exe ahk_id &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">hwnd<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">ControlClick<\/span><span class=\"p\">,<\/span> <span class=\"nf\">Close<\/span> <span class=\"n\">the<\/span> <span class=\"n\">program<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\">    ; When a command window opens, move it to top-right.<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">WinExist<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;ahk_class ConsoleWindowClass ahk_id &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">hwnd<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">WinGetPos<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">w<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span>        <span class=\"n\">x<\/span> <span class=\"o\">:=<\/span> <span class=\"nv\">A_ScreenWidth<\/span> <span class=\"o\">-<\/span> <span class=\"n\">w<\/span>\n<\/span><span>        <span class=\"nb\">WinMove<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"nv\">%x%<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\">    ; Maximize windows that open unmaximized but occupy almost-entire screen.<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">WinExist<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;ahk_id &quot;<\/span> <span class=\"o\">.<\/span> <span class=\"n\">hwnd<\/span> <span class=\"o\">.<\/span> <span class=\"s\">&quot; ahk_group MaximizeOnOpen&quot;<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">WinMaximize<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">WinGetPos<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">width<\/span><span class=\"p\">,<\/span> <span class=\"n\">height<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span class=collapse>        <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">width<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"nv\">A_ScreenWidth<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"n\">height<\/span> <span class=\"o\">&gt;<\/span> <span class=\"o\">.<\/span><span class=\"mi\">9<\/span> <span class=\"o\">*<\/span> <span class=\"nv\">A_ScreenHeight<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">WinMaximize<\/span><span class=\"p\">,<\/span> <span class=\"n\">ahk_id<\/span> <span class=\"nv\">%hwnd%<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There are other methods to achieve the window-watching without polling and I encourage you to try\nthem out if you&rsquo;re not comfortable with this polling system, like with using <code>RegisterShellHookWindow<\/code>. In my\nexperience, such solutions seemed to miss some windows and were able to catch only a small limited\nset of the windows there were opening. So I went with polling, which was less efficient, but has\nbeen more reliable for me.<\/p>\n<h2 id=\"mess-with-images-in-clipboard\">Mess with Images in Clipboard<a class=\"headerlink\" href=\"#mess-with-images-in-clipboard\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is a little trick that&rsquo;s powered by <a href=\"https:\/\/imagemagick.org\/index.php\" rel=\"noopener noreferrer\" target=\"_blank\">ImageMagick<\/a>. I add a menu item in the tray icon&rsquo;s\ncontext menu called <code>\"Add border to image in clipboard\"<\/code>, which is quite self-explanatory!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">Menu<\/span><span class=\"p\">,<\/span> <span class=\"n\">Tray<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span> <span class=\"n\">border<\/span> <span class=\"n\">to<\/span> <span class=\"n\">image<\/span> <span class=\"ow\">in<\/span> <span class=\"nv\">clipboard<\/span><span class=\"p\">,<\/span> <span class=\"n\">AddBorderToImageInCb<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The callback for this menu item invokes the following function. Here, we just run the appropriate\nImageMagick command and show a little dialog when it&rsquo;s done, so we can go ahead and paste the\nbordered image.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">AddBorderToImageInCb<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">RunWait<\/span><span class=\"p\">,<\/span> <span class=\"n\">C<\/span><span class=\"o\">:<\/span>\\<span class=\"n\">tools<\/span>\\<span class=\"n\">ImageMagick<\/span>\\<span class=\"n\">magick<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span> <span class=\"n\">convert<\/span> <span class=\"nv\">clipboard<\/span><span class=\"o\">:<\/span><span class=\"n\">myimage<\/span> <span class=\"o\">-<\/span><span class=\"n\">bordercolor<\/span> <span class=\"s\">&quot;#0099FF&quot;<\/span> <span class=\"o\">-<\/span><span class=\"n\">border<\/span> <span class=\"mi\">6<\/span><span class=\"n\">x6<\/span> <span class=\"nv\">clipboard<\/span><span class=\"o\">:<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">Hide<\/span>\n<\/span><span>    <span class=\"nb\">MsgBox<\/span><span class=\"p\">,<\/span> <span class=\"n\">Added<\/span> <span class=\"n\">border<\/span> <span class=\"n\">to<\/span> <span class=\"n\">image<\/span> <span class=\"ow\">in<\/span> <span class=\"nv\">clipboard<\/span><span class=\"o\">.<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I use this a lot with screenshot snips (taken with the snipping tool or copied from paint), before\npasting into an email. Having a border around images in emails makes them stand out and have a\ndistinct visual.<\/p>\n<h2 id=\"periodic-time-display\">Periodic Time Display<a class=\"headerlink\" href=\"#periodic-time-display\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>As an alternative to the popular <a href=\"https:\/\/en.wikipedia.org\/wiki\/Pomodoro_Technique\" rel=\"noopener noreferrer\" target=\"_blank\">Pomodoro Technique<\/a>, I have a small non-intrusive OSD show up\nwith the current time at the bottom of my screen every 20 minutes. That is, I get a small blue OSD\nat <code>:00<\/code> times, a small green OSD at <code>:20<\/code> times and a small orange OSD at <code>:40<\/code> times. Here&rsquo;s\npreview of how this looks:<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/autohotkey-time-osd.png\"><img alt=\"Time OSD example view\" src=\"https:\/\/sharats.me\/static\/autohotkey-time-osd.png\"><\/a><\/p>\n<p>Again, for this, I have a separate module called <code>time-osd.ahk<\/code> which I <code>#Include<\/code> in the master\nscript and call its init function. (This init-function-in-a-separate-module is something I came up\nwith that was working well enough, I have no idea if it&rsquo;s a best practice).<\/p>\n<div class=\"hl\"><input type=checkbox id=co-15><label for=co-15><span class='btn show-full-code-btn'>Show remaining 23 lines<\/span><\/label><div class=filename><span>time-osd.ahk<\/span><\/div><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><span class=collapse>37\n<\/span><span class=collapse>38\n<\/span><span class=collapse>39\n<\/span><span class=collapse>40\n<\/span><span class=collapse>41\n<\/span><span class=collapse>42\n<\/span><span class=collapse>43\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">TimeOSDInit<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">global<\/span> <span class=\"n\">TimeOSDLabel<\/span>\n<\/span><span>    <span class=\"nb\">SetTimer<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSDPulse<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1000<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSD<\/span><span class=\"o\">:<\/span><span class=\"n\">Default<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"o\">+<\/span><span class=\"n\">LastFound<\/span> <span class=\"o\">+<\/span><span class=\"n\">AlwaysOnTop<\/span> <span class=\"o\">+<\/span><span class=\"n\">ToolWindow<\/span> <span class=\"o\">-<\/span><span class=\"n\">Caption<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Font<\/span><span class=\"p\">,<\/span> <span class=\"n\">s18<\/span><span class=\"p\">,<\/span> <span class=\"n\">Calibri<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Margin<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span>\n<\/span><span>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Add<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">cWhite<\/span> <span class=\"n\">vTimeOSDLabel<\/span> <span class=\"n\">gTimeOSDClose<\/span> <span class=\"n\">w250<\/span> <span class=\"n\">h36<\/span> <span class=\"n\">Center<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">TimeOSDPulse<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"nb\">static<\/span> <span class=\"n\">lastTime<\/span> <span class=\"o\">:=<\/span> <span class=\"s\">&quot;&quot;<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">IsFunc<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;IsWindowFullScreen&quot;<\/span><span class=\"p\">)<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"n\">IsWindowFullScreen<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;A&quot;<\/span><span class=\"p\">))<\/span>\n<\/span><span>        <span class=\"nb\">Return<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"nb\">FormatTime<\/span><span class=\"p\">,<\/span> <span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"p\">,<\/span> <span class=\"n\">h<\/span><span class=\"o\">:<\/span><span class=\"n\">mm<\/span> <span class=\"n\">tt<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">lastTime<\/span> <span class=\"o\">==<\/span> <span class=\"n\">currTime<\/span> <span class=\"o\">||<\/span> <span class=\"nv\">A_TimeIdlePhysical<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">600000<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nb\">Return<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;:00&quot;<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse>        <span class=\"n\">TimeOSDShow<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;268BD2&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;:20&quot;<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse>        <span class=\"n\">TimeOSDShow<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;859900&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">else<\/span> <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"nf\">RegExMatch<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;:40&quot;<\/span><span class=\"p\">))<\/span>\n<\/span><span class=collapse>        <span class=\"n\">TimeOSDShow<\/span><span class=\"p\">(<\/span><span class=\"n\">currTime<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;CB4B16&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"n\">lastTime<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">currTime<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">TimeOSDShow<\/span><span class=\"p\">(<\/span><span class=\"n\">timeText<\/span><span class=\"p\">,<\/span> <span class=\"n\">bg<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSD<\/span><span class=\"o\">:<\/span><span class=\"n\">Default<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Color<\/span><span class=\"p\">,<\/span> <span class=\"nv\">%bg%<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">GuiControl<\/span><span class=\"p\">,<\/span> <span class=\"n\">Text<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSDLabel<\/span><span class=\"p\">,<\/span> <span class=\"n\">It<\/span>&#39;<span class=\"n\">s<\/span> <span class=\"nv\">%timeText%<\/span> <span class=\"n\">already<\/span><span class=\"o\">!<\/span>\n<\/span><span class=collapse>    <span class=\"n\">y<\/span> <span class=\"o\">:=<\/span> <span class=\"nv\">A_ScreenHeight<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">120<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">Show<\/span><span class=\"p\">,<\/span> <span class=\"n\">xCenter<\/span> <span class=\"n\">y<\/span><span class=\"nv\">%y%<\/span> <span class=\"n\">NoActivate<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">SetTimer<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSDClose<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mi\">10000<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">TimeOSDClose<\/span><span class=\"p\">()<\/span> <span class=\"p\">{<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Gui<\/span><span class=\"p\">,<\/span> <span class=\"n\">TimeOSD<\/span><span class=\"o\">:<\/span><span class=\"n\">Cancel<\/span>\n<\/span><span class=collapse><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>With this, clicking on the OSDs will close them, or, they&rsquo;ll disappear in 10 seconds.<\/p>\n<p>To use this, I just include the following in my master script.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">#Include<\/span> <span class=\"n\">time<\/span><span class=\"o\">-<\/span><span class=\"n\">osd<\/span><span class=\"o\">.<\/span><span class=\"n\">ahk<\/span>\n<\/span><span><span class=\"n\">TimeOSDInit<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"vim-keys-for-sumatra-pdf\">Vim Keys for Sumatra PDF<a class=\"headerlink\" href=\"#vim-keys-for-sumatra-pdf\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This one probably only makes sense if your fingers are used to hitting <a href=\"https:\/\/www.vim.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">Vim<\/a>&rsquo;s hotkeys. I wanted\nsome of Vim&rsquo;s simple hotkeys for navigating the document on Sumatra PDF (my PDF reader of choice on\nWindows). The following snippet that I currently use, gets me <kbd>d<\/kbd> (like Vim&rsquo;s\n<kbd>&lt;C-d&gt;<\/kbd>), <kbd>e<\/kbd> (like Vim&rsquo;s <kbd>&lt;C-u&gt;<\/kbd>), <kbd>n<\/kbd>,\n<kbd>+n<\/kbd> (like Vim&rsquo;s <kbd>N<\/kbd>), <kbd>x<\/kbd> (to close a tab), <kbd>g<\/kbd> and\n<kbd>+g<\/kbd> (like Vim&rsquo;s <kbd>g<\/kbd> &amp; <kbd>G<\/kbd>).<\/p>\n<div class=\"hl\"><input type=checkbox id=co-16><label for=co-16><span class='btn show-full-code-btn'>Show remaining 23 lines<\/span><\/label><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><span class=collapse>37\n<\/span><span class=collapse>38\n<\/span><span class=collapse>39\n<\/span><span class=collapse>40\n<\/span><span class=collapse>41\n<\/span><span class=collapse>42\n<\/span><span class=collapse>43\n<\/span><\/pre><pre class=content><code><span><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">SumatraPDF<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">SUMATRA_PDF_FRAME<\/span>\n<\/span><span><span class=\"nl\">$d::<\/span>\n<\/span><span><span class=\"nl\">$e::<\/span>\n<\/span><span>    <span class=\"n\">SumatraKeys<\/span> <span class=\"o\">:=<\/span> <span class=\"p\">{<\/span><span class=\"n\">d<\/span><span class=\"o\">:<\/span> <span class=\"s\">&quot;j&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">e<\/span><span class=\"o\">:<\/span> <span class=\"s\">&quot;k&quot;<\/span><span class=\"p\">}<\/span>\n<\/span><span>    <span class=\"nb\">ControlGetFocus<\/span><span class=\"p\">,<\/span> <span class=\"n\">ctrl<\/span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit1&quot;<\/span> <span class=\"ow\">or<\/span> <span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit2&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"nb\">Send<\/span> <span class=\"nv\">%A_ThisHotkey%<\/span>\n<\/span><span>    <span class=\"p\">}<\/span> <span class=\"n\">else<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"n\">k<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">SumatraKeys<\/span><span class=\"p\">[<\/span><span class=\"n\">StrReplace<\/span><span class=\"p\">(<\/span><span class=\"nv\">A_ThisHotkey<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;$&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s\">&quot;&quot;<\/span><span class=\"p\">)]<\/span>\n<\/span><span>        <span class=\"nb\">Send<\/span> <span class=\"p\">{<\/span><span class=\"nv\">%k%<\/span> <span class=\"mi\">22<\/span><span class=\"p\">}<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span>    <span class=\"nb\">Return<\/span>\n<\/span><span>\n<\/span><span><span class=\"nl\">$n::<\/span>\n<\/span><span>    <span class=\"nb\">ControlGetFocus<\/span><span class=\"p\">,<\/span> <span class=\"n\">ctrl<\/span>\n<\/span><span>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit1&quot;<\/span> <span class=\"ow\">or<\/span> <span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit2&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span>\n<\/span><span>    <span class=\"nb\">else<\/span>\n<\/span><span>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"n\">F3<\/span><span class=\"p\">}<\/span>\n<\/span><span>    <span class=\"nb\">Return<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nl\">$+n::<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">ControlGetFocus<\/span><span class=\"p\">,<\/span> <span class=\"n\">ctrl<\/span>\n<\/span><span class=collapse>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit1&quot;<\/span> <span class=\"ow\">or<\/span> <span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit2&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"n\">N<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">else<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"o\">+<\/span><span class=\"p\">{<\/span><span class=\"n\">F3<\/span><span class=\"p\">}<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Return<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nl\">$x::<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">ControlGetFocus<\/span><span class=\"p\">,<\/span> <span class=\"n\">ctrl<\/span>\n<\/span><span class=collapse>    <span class=\"n\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit1&quot;<\/span> <span class=\"ow\">or<\/span> <span class=\"n\">ctrl<\/span> <span class=\"o\">==<\/span> <span class=\"s\">&quot;Edit2&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">else<\/span>\n<\/span><span class=collapse>        <span class=\"nb\">Send<\/span><span class=\"p\">,<\/span> <span class=\"o\">^<\/span><span class=\"n\">w<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">Return<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nl\">+g::<\/span><span class=\"n\">Send<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"n\">End<\/span> <span class=\"mi\">2<\/span><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nb\">#IfWinActive<\/span> <span class=\"n\">Go<\/span> <span class=\"n\">to<\/span> <span class=\"n\">page<\/span> <span class=\"n\">ahk_exe<\/span> <span class=\"n\">SumatraPDF<\/span><span class=\"o\">.<\/span><span class=\"n\">exe<\/span> <span class=\"n\">ahk_class<\/span> <span class=\"n\">#32770<\/span>\n<\/span><span class=collapse><span class=\"nl\">g::<\/span><span class=\"n\">Send<\/span><span class=\"p\">,<\/span> <span class=\"p\">{<\/span><span class=\"n\">Escape<\/span><span class=\"p\">}{<\/span><span class=\"n\">Home<\/span><span class=\"p\">}<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"nb\">#IfWinActive<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This looks like a sad, long, hairy piece of code (probably because it is), but it works, so I let it\nbe. This sentiment shows up a lot when dealing with AutoHotkey code. But it works, and it works\nreally well.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>AutoHotkey&rsquo;s language may have its quirks, but it&rsquo;s a very powerful tool when it comes to hotkeys.\nI have come to the point that working on Windows is practically hair-wrecking for me without\nAutoHotkey (and my scripts, of course). I encourage you to check it out and explore the\npossibilities.<\/p>\n<p class=\"note\">You can read the <a href=\"..\/the-magic-of-autohotkey-2\/\">Part 2<\/a> of this now!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"autohotkey"}},{"@attributes":{"term":"productivity"}},{"@attributes":{"term":"windows"}},{"@attributes":{"term":"automation"}},{"@attributes":{"term":"workflow"}}]},{"title":"Guide to Comprehensions in Python","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/guide-to-comprehensions-in-python\/","rel":"alternate"}},"published":"2020-02-23T00:00:00+05:30","updated":"2020-02-23T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-02-23:\/posts\/guide-to-comprehensions-in-python\/","summary":"<p>Comprehensions are a syntax construct used for applying some form of transformations and filtering\nover streams of data. The problems comprehensions solve can be done without them, using plain old\n<code>for<\/code>-loops, but where possible, comprehensions can improve readability and show the intent very\nwell.<\/p>\n<p>This article assumes some familiarity \u2026<\/p>","content":"<p>Comprehensions are a syntax construct used for applying some form of transformations and filtering\nover streams of data. The problems comprehensions solve can be done without them, using plain old\n<code>for<\/code>-loops, but where possible, comprehensions can improve readability and show the intent very\nwell.<\/p>\n<p>This article assumes some familiarity with Python (and comprehensions as well). I will go over the\nbasics of comprehensions quickly and jump into the meat of the article. Most of this article applies\nfor Python 3, unless otherwise specified.<\/p>\n<p class=\"note\">If you&rsquo;re here for the live converter or comprehension &hArr; <code>for<\/code>-loop code, <a href=\"#live-code-converter\">it&rsquo;s further down in\nthe page<\/a>.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#basic-syntax\">Basic Syntax<\/a><\/li>\n<li><a href=\"#different-collectors\">Different Collectors<\/a><\/li>\n<li><a href=\"#multiple-looping-constructs\">Multiple Looping Constructs<\/a><ul>\n<li><a href=\"#zipping-instead-of-cross-product\">Zipping instead of Cross Product<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#rewriting-comprehensions-map-filter-builtins\">Rewriting Comprehensions map &amp; filter Builtins<\/a><\/li>\n<li><a href=\"#reducing-with-assignment-expressions\">Reducing with Assignment Expressions<\/a><\/li>\n<li><a href=\"#set-operations-with-comprehensions\">Set Operations with Comprehensions<\/a><\/li>\n<li><a href=\"#generator-expressions\">Generator Expressions<\/a><\/li>\n<li><a href=\"#the-key-argument-for-sorted\">The key Argument for sorted<\/a><\/li>\n<li><a href=\"#no-side-effects-please\">No Side Effects Please<\/a><\/li>\n<li><a href=\"#looking-inside\">Looking Inside<\/a><\/li>\n<li><a href=\"#live-code-converter\">Live Code Converter<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"basic-syntax\">Basic Syntax<a class=\"headerlink\" href=\"#basic-syntax\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Let&rsquo;s go over the basic syntax for starters. It can be divided into three parts. The result\nexpression, the looping construct(s) and the filter expression. Of these, the filter expression is\noptional, but the other two are required. Let&rsquo;s look at a simple example to get an idea:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is a <em>list comprehension<\/em> with no filtering (<em>i.e.,<\/em> no <code>if<\/code> clause). Here, the <code>n ** 2<\/code> part\nis the result expression and the <code>for n in range(4)<\/code> is the looping construct. This comprehension\nexpression is the same as the following piece of code, written without comprehensions:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">squares<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">squares<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">squares<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Comprehensions also support conditions on the looping variables. For instance, in the example above,\nif we only wanted squares of even numbers, we could do:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)<\/span> <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">[0, 4]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this case, the result expression is not evaluated when the <code>n % 2 == 0<\/code> turns out to be <code>False<\/code>.<\/p>\n<p class=\"note\">The keen Pythonista might note that this can be accomplished more simply by using the <code>step<\/code>\nargument of the <code>range<\/code> builtin, but please excuse me for lacking in creativity for the examples!<\/p>\n<h2 id=\"different-collectors\">Different Collectors<a class=\"headerlink\" href=\"#different-collectors\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In addition to <code>list<\/code> comprehensions, Python supports <code>set<\/code> and <code>dict<\/code> comprehensions as well. Where\n<code>list<\/code> comprehensions collect the result values in a <code>list<\/code>, the latter two collect them in <code>set<\/code>s\nand <code>dict<\/code>s respectively.<\/p>\n<p>The syntax is almost exactly same as that of the list comprehensions. The only difference is that we\nuse braces for set and dict comprehensions, where we use square brackets for list comprehensions.\nThe looping and filtering constructs behave the same way. The result expression behaves the same way\nfor set comprehensions, but for dict comprehensions, we have to provide two expressions, the key and\nthe value, separate by a colon. Let&rsquo;s look at some examples:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">color<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">color<\/span> <span class=\"ow\">in<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Red&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;yellow&#39;<\/span><span class=\"p\">]]<\/span>\n<\/span><span><span class=\"go\">[&#39;blue&#39;, &#39;red&#39;, &#39;blue&#39;, &#39;yellow&#39;]<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">{<\/span><span class=\"n\">color<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">color<\/span> <span class=\"ow\">in<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Red&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;yellow&#39;<\/span><span class=\"p\">]}<\/span>\n<\/span><span><span class=\"go\">{&#39;blue&#39;, &#39;red&#39;, &#39;yellow&#39;}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The first expression in the above REPL session is a list comprehension and the second is a set\ncomprehension. Notice that the only difference in the first and third lines is the surrounding\nbracket type.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">{<\/span><span class=\"n\">color<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">():<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">color<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">color<\/span> <span class=\"ow\">in<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Red&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;yellow&#39;<\/span><span class=\"p\">]}<\/span>\n<\/span><span><span class=\"go\">{&#39;blue&#39;: 4, &#39;red&#39;: 3, &#39;yellow&#39;: 6}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is a dictionary comprehension. Notice here, the result expression is a <em>key-value pair of\nexpressions<\/em>, as opposed to a single expression for list and set comprehensions.<\/p>\n<p>Note that these two forms of comprehensions have been introduced in Python 2.7 &amp; 3. In the previous\nversions, we could replicate this by calling the <code>set<\/code> and <code>dict<\/code> builtins over list comprehensions.\nHere&rsquo;s an example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">set<\/span><span class=\"p\">([<\/span><span class=\"n\">color<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">color<\/span> <span class=\"ow\">in<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Red&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;yellow&#39;<\/span><span class=\"p\">]])<\/span>\n<\/span><span><span class=\"go\">{&#39;blue&#39;, &#39;red&#39;, &#39;yellow&#39;}<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">([(<\/span><span class=\"n\">color<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">(),<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">color<\/span><span class=\"p\">))<\/span> <span class=\"k\">for<\/span> <span class=\"n\">color<\/span> <span class=\"ow\">in<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Red&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;blue&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;yellow&#39;<\/span><span class=\"p\">]])<\/span>\n<\/span><span><span class=\"go\">{&#39;blue&#39;: 4, &#39;red&#39;: 3, &#39;yellow&#39;: 6}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>For dictionaries, we create a list of 2-tuples (key-value pairs) and pass that to <code>dict<\/code>.<\/p>\n<h2 id=\"multiple-looping-constructs\">Multiple Looping Constructs<a class=\"headerlink\" href=\"#multiple-looping-constructs\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In the previous examples, we&rsquo;ve only used one looping construct. However, it is possible to use\nmore than one looping construct. This works very similar to a nested <code>for<\/code>-loop. Let&rsquo;s look at an\nexample:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[(<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">[(0, 10), (0, 11), (0, 12), (1, 10), (1, 11), (1, 12), (2, 10), (2, 11), (2, 12)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This output is easy to visualize if you see the two <code>for<\/code>-loops nested. The following is a\nreproduction of the above, without comprehensions:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"k\">for<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>        <span class=\"n\">result<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">((<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">result<\/span>\n<\/span><span><span class=\"go\">[(0, 10), (0, 11), (0, 12), (1, 10), (1, 11), (1, 12), (2, 10), (2, 11), (2, 12)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This can go further levels of nesting, although if you have comprehensions with more three levels of\nnesting, you should probably rethink your data structures or the way you&rsquo;re working with them.<\/p>\n<p>Multiple looping constructs work just fine for set and dict comprehensions as well. Here&rsquo;s some\nexamples with set comprehensions and using a condition expression as well:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">{(<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">)}<\/span>\n<\/span><span><span class=\"go\">{(1, 12), (2, 11), (0, 12), (2, 10), (0, 11), (0, 10), (2, 12), (1, 10), (1, 11)}<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">{(<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">)<\/span> <span class=\"k\">if<\/span> <span class=\"n\">j<\/span> <span class=\"o\">-<\/span> <span class=\"n\">i<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">10<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"go\">{(0, 11), (1, 12), (0, 12)}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>A subtle point here that&rsquo;s not easy to notice in the comprehensions is that the <code>range(10, 13)<\/code> call\nin the above examples is called <em>three<\/em> times, whereas the <code>range(0, 3)<\/code> is called <em>once<\/em>. This\nbecomes obvious if you visualize this as the nested <code>for<\/code>-loop illustrated above. This is important\nwhen using generators or iterators that work single-pass, like <code>map<\/code> objects, or file objects (for\nwhich, we&rsquo;ll need <code>.seek<\/code>). Check out the following example to see what I mean:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">range_for_i<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">range_for_j<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">))<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[(<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">range_for_i<\/span> <span class=\"k\">for<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">range_for_j<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">[(&#39;0&#39;, &#39;10&#39;), (&#39;0&#39;, &#39;11&#39;), (&#39;0&#39;, &#39;12&#39;)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In this example, the <code>map<\/code> objects are destroyed once they have yielded all their results. That is\nwhy the <code>range_for_j<\/code> only produced the three numbers only once, which were enough to pair with just\n<code>'0'<\/code>, and there&rsquo;s no more to be paired with <code>'1'<\/code> and <code>'2'<\/code>.<\/p>\n<p>You&rsquo;re not likely to encounter this in real-world code, but it&rsquo;s good to know lest we end up facing\nit.<\/p>\n<h3 id=\"zipping-instead-of-cross-product\">Zipping instead of Cross Product<a class=\"headerlink\" href=\"#zipping-instead-of-cross-product\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Using multiple <code>for<\/code> loops like above creates a sort-of cross-product. This is by nature of the\nnested loop structure. But what if we&rsquo;re looking for a sort-of dot-product like result? Python\nprovides the <code>zip<\/code> builtin for this purpose. It is so specific to this problem, that using a\ncomprehension looks like unnecessary ceremony:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[(<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">zip<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">),<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">))]<\/span>\n<\/span><span><span class=\"go\">[(0, 10), (1, 11), (2, 12)]<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">zip<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">),<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">)))<\/span>\n<\/span><span><span class=\"go\">[(0, 10), (1, 11), (2, 12)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course, if we&rsquo;re doing some operation with <code>i<\/code> and <code>j<\/code> instead of just creating tuples, the\ncomprehension would still be very useful.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span> <span class=\"o\">*<\/span> <span class=\"n\">j<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">j<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">zip<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">),<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">13<\/span><span class=\"p\">))]<\/span>\n<\/span><span><span class=\"go\">[0, 11, 24]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"rewriting-comprehensions-map-filter-builtins\">Rewriting Comprehensions <code>map<\/code> &amp; <code>filter<\/code> Builtins<a class=\"headerlink\" href=\"#rewriting-comprehensions-map-filter-builtins\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Comprehensions can usually be a more-readable alternative to code written using <code>map<\/code> and\/or\n<code>filter<\/code> functions.<\/p>\n<p>I&rsquo;ve discussed the <code>map<\/code> builtin in more detail in <a href=\"..\/python-map-function\/\">a previous article<\/a>. Not all\nfeatures of a comprehension can be translated with just the <code>map<\/code> function. In particular, there&rsquo;s\nno way to apply a condition like we can in comprehensions, when using the <code>map<\/code> function alone. It\ncan be done if we also make use of the <code>filter<\/code> builtin. Here&rsquo;s an example of how such a\ncomprehension can be rewritten with <code>map<\/code> and <code>filter<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span> <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">[0, 4, 16, 36, 64]<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">n<\/span><span class=\"p\">:<\/span> <span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"nb\">filter<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">n<\/span><span class=\"p\">:<\/span> <span class=\"n\">n<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">))))<\/span>\n<\/span><span><span class=\"go\">[0, 4, 16, 36, 64]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Obviously, the comprehension reads much better, but I&rsquo;d urge you to not just throw away the <code>map<\/code>\nand <code>filter<\/code> builtins. They have their place and sometimes, code using them can read much better\nthan comprehensions. Check out my <a href=\"..\/python-map-function\/\">article on <code>map<\/code> function<\/a> for such examples and\nother rationales.<\/p>\n<h2 id=\"reducing-with-assignment-expressions\">Reducing with Assignment Expressions<a class=\"headerlink\" href=\"#reducing-with-assignment-expressions\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I&rsquo;ve actually stumbled on a version of this idea on Reddit. Unfortunately I don&rsquo;t have the source,\nso, wherever you are, thank you!<\/p>\n<p>The <code>functools<\/code> module from the standard library provides the <a href=\"https:\/\/docs.python.org\/3\/library\/functools.html#functools.reduce\" rel=\"noopener noreferrer\" target=\"_blank\"><code>reduce<\/code><\/a> callable\nwhich can be used to systematically aggregate values in collections. I won&rsquo;t go into details of how\nthis can be used, but I will show how such an affect can be reproduced with comprehensions.<\/p>\n<p>Let&rsquo;s look at an example of using the <code>functools.reduce<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">functools<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">functools<\/span><span class=\"o\">.<\/span><span class=\"n\">reduce<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">acc<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span><span class=\"p\">:<\/span> <span class=\"n\">acc<\/span> <span class=\"o\">*<\/span> <span class=\"n\">item<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">),<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">24<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>A simple implementation of the <code>reduce<\/code> function is provided at the official documentation and it&rsquo;s\na better explanation that I can provide here. Instead, we&rsquo;ll try and reproduce this with\ncomprehensions.<\/p>\n<p>For this, we have to first familiarize ourselves with the <a href=\"https:\/\/docs.python.org\/3\/faq\/design.html#why-can-t-i-use-an-assignment-in-an-expression\" rel=\"noopener noreferrer\" target=\"_blank\">walrus operator<\/a>. This is a new feature\nin Python 3.8, that lets us do assignments in expressions. This means we&rsquo;ll now be able to do\nassignment operations in places where only expressions (and not statements) are allowed, like the\nresult expression spot in comprehensions.<\/p>\n<p><em>By the power of the gray walrus<\/em>, we can reproduce <code>functools.reduce<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">acc<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">acc<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">acc<\/span> <span class=\"o\">*<\/span> <span class=\"n\">item<\/span> <span class=\"k\">for<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">[1, 2, 6, 24]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">_<\/span><span class=\"p\">[<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">24<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Although that works, and is quite nice, I&rsquo;m not sure how readable that is. But I can attribute my\ndiscomfort to the fact that this is uses a new language feature and like anything in life, needs\nsome getting used to. Also since it&rsquo;s new in version 3.8, it&rsquo;s probably best to stay away from it in\nproduction code for a little while.<\/p>\n<h2 id=\"set-operations-with-comprehensions\">Set Operations with Comprehensions<a class=\"headerlink\" href=\"#set-operations-with-comprehensions\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Comprehensions lend themselves quite well for set operations like intersection and difference.\nThey&rsquo;ll probably be less performant (and even less obvious to readers of such code), but\nnonetheless, it&rsquo;s a nice example to play with:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">rgb_colors<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s2\">&quot;red&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;green&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;blue&quot;<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ryb_colors<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s2\">&quot;red&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;yellow&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;blue&quot;<\/span><span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">intersection<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"n\">c<\/span> <span class=\"k\">for<\/span> <span class=\"n\">c<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">rgb_colors<\/span> <span class=\"k\">if<\/span> <span class=\"n\">c<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">ryb_colors<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">intersection<\/span>\n<\/span><span><span class=\"go\">{&#39;red&#39;, &#39;blue&#39;}<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">difference<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"n\">c<\/span> <span class=\"k\">for<\/span> <span class=\"n\">c<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">rgb_colors<\/span> <span class=\"k\">if<\/span> <span class=\"n\">c<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">ryb_colors<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">difference<\/span>\n<\/span><span><span class=\"go\">{&#39;green&#39;}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>These are the same results we&rsquo;d get if we used the standard set operators \/ methods:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">rgb_colors<\/span> <span class=\"o\">&amp;<\/span> <span class=\"n\">ryb_colors<\/span>\n<\/span><span><span class=\"go\">{&#39;red&#39;, &#39;blue&#39;}<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">rgb_colors<\/span> <span class=\"o\">-<\/span> <span class=\"n\">ryb_colors<\/span>\n<\/span><span><span class=\"go\">{&#39;green&#39;}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Again, use the standard set functionalities for this, not the comprehension based methods I\nillustrated above. If you do use the comprehension method of doing this in production, don&rsquo;t point\nto me or this article as inspiration.<\/p>\n<h2 id=\"generator-expressions\">Generator Expressions<a class=\"headerlink\" href=\"#generator-expressions\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>When comprehensions are wrapped in square brackets or braces, the result is a fully realized\ncollection, like a list or a set. However, when not wrapped as such, or when wrapped with just\nparentheses, the result is a generator expression, with none of result items realized. The result\nitems are realized as needed, like for example, if it&rsquo;s used in a <code>for<\/code>-loop.<\/p>\n<p>Consider the following example session:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9]<\/span>\n<\/span><span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">&lt;generator object &lt;genexpr&gt; at 0x0000000005768DC8&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We can use this generator object in a <code>for<\/code>-loop or, perhaps more typically, in an aggregation\nfunction, like <code>sum<\/code> or <code>max<\/code> etc.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">squares<\/span> <span class=\"o\">=<\/span> <span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">sum<\/span><span class=\"p\">(<\/span><span class=\"n\">squares<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">14<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course since this is a generator expression, it can be iterated over <em>only once<\/em>. If you want to\niterate over it multiple times, just turn it into a list.<\/p>\n<p>Generator expressions were introduced in <a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0289\/\" rel=\"noopener noreferrer\" target=\"_blank\">PEP-289<\/a>, which\ncontains a lot of examples. I recommend reviewing it for some cool use cases, which I won&rsquo;t\nreproduce here.<\/p>\n<p>One small note regarding passing generator expressions as an argument to functions is that, make it\na best practice to always wrap them with parentheses. The reason is, when using a generator\nexpression as an argument to a function, and when it is not the <em>only<\/em> argument to the function, we\nmay get an error that the generator expression is not parenthesized. Check out the following example\nif that doesn&rsquo;t make sense:<\/p>\n<p>In the following call to <code>sorted<\/code>, we pass in a generator expression as the sole argument, and we\nget the expected result.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">sorted<\/span><span class=\"p\">(<\/span><span class=\"n\">word<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">word<\/span> <span class=\"ow\">in<\/span> <span class=\"s2\">&quot;We are from planet Earth, what&#39;s up?&quot;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">())<\/span>\n<\/span><span><span class=\"go\">[&#39;are&#39;, &#39;earth,&#39;, &#39;from&#39;, &#39;planet&#39;, &#39;up?&#39;, &#39;we&#39;, &quot;what&#39;s&quot;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now to the same call, we add the <code>key<\/code> argument hoping to sort by the string lengths. Instead, we\nget a <code>SyntaxError<\/code> because our generator expression is not parenthesized.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">sorted<\/span><span class=\"p\">(<\/span><span class=\"n\">word<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">word<\/span> <span class=\"ow\">in<\/span> <span class=\"s2\">&quot;We are from planet Earth, what&#39;s up?&quot;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">(),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"nb\">len<\/span><span class=\"p\">)<\/span>\n<\/span><span>  File <span class=\"nb\">&quot;&lt;stdin&gt;&quot;<\/span>, line <span class=\"m\">1<\/span>\n<\/span><span><span class=\"gr\">SyntaxError<\/span>: <span class=\"n\">Generator expression must be parenthesized<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>So, if we add parentheses to the generator, it works fine and we get the expected result.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">sorted<\/span><span class=\"p\">((<\/span><span class=\"n\">word<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">word<\/span> <span class=\"ow\">in<\/span> <span class=\"s2\">&quot;We are from planet Earth, what&#39;s up?&quot;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">()),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"nb\">len<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">[&#39;we&#39;, &#39;are&#39;, &#39;up?&#39;, &#39;from&#39;, &#39;planet&#39;, &#39;earth,&#39;, &quot;what&#39;s&quot;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"the-key-argument-for-sorted\">The <code>key<\/code> Argument for <code>sorted<\/code><a class=\"headerlink\" href=\"#the-key-argument-for-sorted\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>sorted<\/code> builtin provides the <code>key<\/code> argument that can be set to a function. This function is\napplied to each item in the given list and the list items are sorted according to the sorting order\nof the results of these function calls. This is a very convenient feature of <code>sorted<\/code>.<\/p>\n<p>While this is probably a horrible thing to do, we could use comprehensions to recreate this effect\nwithout using the <code>key<\/code> argument. The idea is that we first create a sequence of 2-tuples, where the\nfirst items are the results of the <code>key<\/code> function and the second items are the original list items.\nWe then sort this sequence of tuples, extract the second items in each tuple and return that. Here&rsquo;s\nan example implementation doing just that:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">sad_sorted_with_key<\/span><span class=\"p\">(<\/span><span class=\"n\">items<\/span><span class=\"p\">,<\/span> <span class=\"n\">key_fn<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"p\">[<\/span><span class=\"n\">item<\/span> <span class=\"k\">for<\/span> <span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">sorted<\/span><span class=\"p\">((<\/span><span class=\"n\">key_fn<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">),<\/span> <span class=\"n\">item<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">items<\/span><span class=\"p\">)]<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">sad_sorted_with_key<\/span><span class=\"p\">(<\/span>\n<\/span><span>    <span class=\"p\">(<\/span><span class=\"n\">word<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">word<\/span> <span class=\"ow\">in<\/span> <span class=\"s2\">&quot;We are from planet Earth, what&#39;s up?&quot;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">()),<\/span>\n<\/span><span>    <span class=\"nb\">len<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This script would produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>[&#39;we&#39;, &#39;are&#39;, &#39;up?&#39;, &#39;from&#39;, &#39;earth,&#39;, &#39;planet&#39;, &quot;what&#39;s&quot;]\n<\/span><\/code><\/pre><\/div>\n\n<p>As usual, don&rsquo;t do this in production. This is just a sad experiment.<\/p>\n<h2 id=\"no-side-effects-please\">No Side Effects Please<a class=\"headerlink\" href=\"#no-side-effects-please\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>As best practice, please strive to have no side effects in your comprehension result expressions.\nCheck out the following example to see what I mean:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">0<\/span>\n<\/span><span><span class=\"go\">1<\/span>\n<\/span><span><span class=\"go\">4<\/span>\n<\/span><span><span class=\"go\">9<\/span>\n<\/span><span><span class=\"go\">[None, None, None, None]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>While this solves the purpose of printing the squares one per line, it also builds a list of\n<code>None<\/code>s. It&rsquo;s also counter-intuitive when we treat comprehensions as applying a <em>transformation<\/em>\nover each item in a collection. Calling <code>print<\/code> is not a transformation, it&rsquo;s a side effect.<\/p>\n<p>For use cases like this, it&rsquo;s best to use a traditional <code>for<\/code>-loop:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">0<\/span>\n<\/span><span><span class=\"go\">1<\/span>\n<\/span><span><span class=\"go\">4<\/span>\n<\/span><span><span class=\"go\">9<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The intent here is clearer, which is to print each square, not to make a list of some results.<\/p>\n<h2 id=\"looking-inside\">Looking Inside<a class=\"headerlink\" href=\"#looking-inside\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>As another likely-pointless exercise, let&rsquo;s look at these comprehensions as Python bytecode, and\ncompare it with the same solution written using traditional <code>for<\/code>-loop.<\/p>\n<p>First, let&rsquo;s define two functions that solve the same problem, but one uses comprehensions, and the\nother doesn&rsquo;t.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><\/pre><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">loop_squares<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"n\">result<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">result<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">comp_squares<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"p\">[<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s make sure they produce the same output:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">loop_squares<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">comp_squares<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now let&rsquo;s get the <a href=\"https:\/\/docs.python.org\/3\/library\/dis.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dis<\/code><\/a> module and disassemble both of these functions:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-10><label for=co-10><span class='btn show-full-code-btn'>Show remaining 28 lines<\/span><\/label><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">dis<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">dis<\/span><span class=\"o\">.<\/span><span class=\"n\">dis<\/span><span class=\"p\">(<\/span><span class=\"n\">loop_squares<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">  2           0 BUILD_LIST               0<\/span>\n<\/span><span><span class=\"go\">              2 STORE_FAST               0 (result)<\/span>\n<\/span><span>\n<\/span><span><span class=\"go\">  3           4 SETUP_LOOP              30 (to 36)<\/span>\n<\/span><span><span class=\"go\">              6 LOAD_GLOBAL              0 (range)<\/span>\n<\/span><span><span class=\"go\">              8 LOAD_CONST               1 (4)<\/span>\n<\/span><span><span class=\"go\">             10 CALL_FUNCTION            1<\/span>\n<\/span><span><span class=\"go\">             12 GET_ITER<\/span>\n<\/span><span><span class=\"go\">        &gt;&gt;   14 FOR_ITER                18 (to 34)<\/span>\n<\/span><span><span class=\"go\">             16 STORE_FAST               1 (n)<\/span>\n<\/span><span>\n<\/span><span><span class=\"go\">  4          18 LOAD_FAST                0 (result)<\/span>\n<\/span><span><span class=\"go\">             20 LOAD_METHOD              1 (append)<\/span>\n<\/span><span><span class=\"go\">             22 LOAD_FAST                1 (n)<\/span>\n<\/span><span><span class=\"go\">             24 LOAD_CONST               2 (2)<\/span>\n<\/span><span><span class=\"go\">             26 BINARY_POWER<\/span>\n<\/span><span><span class=\"go\">             28 CALL_METHOD              1<\/span>\n<\/span><span><span class=\"go\">             30 POP_TOP<\/span>\n<\/span><span class=collapse><span class=\"go\">             32 JUMP_ABSOLUTE           14<\/span>\n<\/span><span class=collapse><span class=\"go\">        &gt;&gt;   34 POP_BLOCK<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"go\">  5     &gt;&gt;   36 LOAD_FAST                0 (result)<\/span>\n<\/span><span class=collapse><span class=\"go\">             38 RETURN_VALUE<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">dis<\/span><span class=\"o\">.<\/span><span class=\"n\">dis<\/span><span class=\"p\">(<\/span><span class=\"n\">comp_squares<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse><span class=\"go\">  2           0 LOAD_CONST               1 (&lt;code object &lt;listcomp&gt; at 0x7f3958a76c00, file &quot;&lt;stdin&gt;&quot;, line 2&gt;)<\/span>\n<\/span><span class=collapse><span class=\"go\">              2 LOAD_CONST               2 (&#39;comp_squares.&lt;locals&gt;.&lt;listcomp&gt;&#39;)<\/span>\n<\/span><span class=collapse><span class=\"go\">              4 MAKE_FUNCTION            0<\/span>\n<\/span><span class=collapse><span class=\"go\">              6 LOAD_GLOBAL              0 (range)<\/span>\n<\/span><span class=collapse><span class=\"go\">              8 LOAD_CONST               3 (4)<\/span>\n<\/span><span class=collapse><span class=\"go\">             10 CALL_FUNCTION            1<\/span>\n<\/span><span class=collapse><span class=\"go\">             12 GET_ITER<\/span>\n<\/span><span class=collapse><span class=\"go\">             14 CALL_FUNCTION            1<\/span>\n<\/span><span class=collapse><span class=\"go\">             16 RETURN_VALUE<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"go\">Disassembly of &lt;code object &lt;listcomp&gt; at 0x7f3958a76c00, file &quot;&lt;stdin&gt;&quot;, line 2&gt;:<\/span>\n<\/span><span class=collapse><span class=\"go\">  2           0 BUILD_LIST               0<\/span>\n<\/span><span class=collapse><span class=\"go\">              2 LOAD_FAST                0 (.0)<\/span>\n<\/span><span class=collapse><span class=\"go\">        &gt;&gt;    4 FOR_ITER                12 (to 18)<\/span>\n<\/span><span class=collapse><span class=\"go\">              6 STORE_FAST               1 (n)<\/span>\n<\/span><span class=collapse><span class=\"go\">              8 LOAD_FAST                1 (n)<\/span>\n<\/span><span class=collapse><span class=\"go\">             10 LOAD_CONST               0 (2)<\/span>\n<\/span><span class=collapse><span class=\"go\">             12 BINARY_POWER<\/span>\n<\/span><span class=collapse><span class=\"go\">             14 LIST_APPEND              2<\/span>\n<\/span><span class=collapse><span class=\"go\">             16 JUMP_ABSOLUTE            4<\/span>\n<\/span><span class=collapse><span class=\"go\">        &gt;&gt;   18 RETURN_VALUE<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I won&rsquo;t discuss each instruction in the above outputs, check out the official documentation of the\n<a href=\"https:\/\/docs.python.org\/3\/library\/dis.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dis<\/code><\/a> module for that. But just skimming over the above, we can see one striking difference.\nThe comprehension function seems to have created a <code>code<\/code> object, which is doing the work of the\ncomprehension and passing (<em>returning<\/em>) the result to our <code>comp_squares<\/code> function. That sounds like\nthe <code>comp_squares<\/code> function is using an extra layer in the stack frame. We can confirm this by\nchanging the functions to the following:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">traceback<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">loop_squares<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"n\">traceback<\/span><span class=\"o\">.<\/span><span class=\"n\">print_stack<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"n\">result<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"n\">result<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">result<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">comp_squares<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"p\">[[<\/span><span class=\"n\">traceback<\/span><span class=\"o\">.<\/span><span class=\"n\">print_stack<\/span><span class=\"p\">()<\/span> <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span> <span class=\"k\">else<\/span> <span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span> <span class=\"o\">**<\/span> <span class=\"mi\">2<\/span><span class=\"p\">][<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">)]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s see the stack they print and make sure they still produce the same result:<\/p>\n<div class=\"hl\"><pre class=content><code><span>&gt;&gt;&gt; loop_squares()\n<\/span><span>  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;\n<\/span><span>  File &quot;&lt;stdin&gt;&quot;, line 2, in loop_squares\n<\/span><span>[0, 1, 4, 9]\n<\/span><span>&gt;&gt;&gt; comp_squares()\n<\/span><span>  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;\n<\/span><span>  File &quot;&lt;stdin&gt;&quot;, line 2, in comp_squares\n<\/span><span>  File &quot;&lt;stdin&gt;&quot;, line 2, in &lt;listcomp&gt;\n<\/span><span>[0, 1, 4, 9]\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">The stack shows the file as <code>\"&lt;stdin&gt;\"<\/code> because I defined the functions within a REPL session. If\nthey were in an actual file, we&rsquo;d obviously get the file name there.<\/p>\n<p>As we suspected, the comprehension function adds another layer to the stack frame, the <code>&lt;listcomp&gt;<\/code>,\nwhich is doing the work of the comprehension.<\/p>\n<h2 id=\"live-code-converter\">Live Code Converter<a class=\"headerlink\" href=\"#live-code-converter\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here&rsquo;s a little tool that converts your code written in the form of a list\/set\/dict comprehension,\ninto one that is written using traditional <code>for<\/code>-loops.<\/p>\n<div id=converterBox>\n<textarea id=compCodeEl onKeydown=\"setTimeout(updateLoopCode)\">[n ** 2 for n in range(9) if n % 2 == 0]<\/textarea>\n<textarea id=loopCodeEl readonly><\/textarea>\n<style>\n#converterBox {\n    display: flex;\n    flex-wrap: wrap;\n}\n#converterBox textarea {\n    flex-grow: 1;\n    margin: 6px;\n    height: 148px;\n    font-size: inherit;\n    font-variant-ligatures: none;\n}\n<\/style>\n<script defer>\nupdateLoopCode();\n\nfunction updateLoopCode() {\n    document.getElementById(\"loopCodeEl\").value = computeLoopCode(document.getElementById(\"compCodeEl\").value);\n}\n\nfunction computeLoopCode(code) {\n    code = code.trim();\n\n    const closers = {'\"': '\"', \"'\": \"'\", \"(\": \")\", \"[\": \"]\", \"{\": \"}\"};\n\n    if (code[0] !== \"[\" && code[0] !== \"{\")\n        return \"\";\n\n    if (code[code.length - 1] !== closers[code[0]])\n        return \"\";\n\n    let type = code[0] == \"[\" ? \"list\" : \"set\";\n    let i = 1;\n\n    let expr = '';\n    const stack = [], parts = [];\n\n    for (; i < code.length - 1; ++i) {\n        const ch = code[i];\n        if (stack.length > 0 && ch === stack[stack.length - 1]) {\n            expr += stack.pop();\n\n        } else if (ch.match(\/[\"'(\\[{]\/)) {\n            expr += ch;\n            stack.push(closers[ch]);\n\n        } else if (stack.length > 0) {\n            expr += ch;\n\n        } else if (stack.length === 0 && ch === \":\") {\n            type = \"dict\";\n            parts.push(expr);\n            expr = '';\n\n        } else {\n            const match = code.substr(i).match(\/^(for|if)\\b\/);\n            if (match) {\n                parts.push(expr);\n                expr = ch;\n\n            } else {\n                expr += ch;\n\n            }\n\n        }\n\n    }\n\n    if (expr.length)\n        parts.push(expr);\n\n    for (const i in parts)\n        parts[i] = parts[i].trim();\n\n    const loopCodeLines = [];\n\n    switch (type) {\n        case \"list\":\n            loopCodeLines.push(\"result = []\")\n            break;\n        case \"set\":\n            loopCodeLines.push(\"result = set()\")\n            break;\n        case \"dict\":\n            loopCodeLines.push(\"result = {}\")\n            break;\n    }\n\n    const resultPart = parts.shift(), resultValuePart = type === \"dict\" ? parts.shift() : null;\n\n    let indentLevel = 0;\n    for (const part of parts) {\n        loopCodeLines.push(makeIndent(indentLevel) + part + \":\");\n        ++indentLevel;\n    }\n\n    switch (type) {\n        case \"list\":\n            loopCodeLines.push(makeIndent(indentLevel) + \"result.append(\" + resultPart + \")\");\n            break;\n        case \"set\":\n            loopCodeLines.push(makeIndent(indentLevel) + \"result.add(\" + resultPart + \")\");\n            break;\n        case \"dict\":\n            loopCodeLines.push(makeIndent(indentLevel) + \"result[\" + resultPart + \"] = \" + resultValuePart);\n            break;\n    }\n\n    return loopCodeLines.join('\\n');\n}\n\nfunction makeIndent(level) {\n    level *= 4;\n    const spaces = [];\n    while (level--)\n        spaces.push(' ');\n    return spaces.join('');\n}\n<\/script>\n<\/div>\n\n<p>It&rsquo;s powered by an extremely light parser (doesn&rsquo;t even qualify to be called that), but it can help\nillustrate the point. It can also be helpful for visualizing nested loops and comprehensions with\nmultiple <code>for<\/code> statements.<\/p>\n<p>Here&rsquo;s some examples to try this with:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Comprehension Code (click to put in converter)<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>[n ** 2 for n in range(4)]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>[n ** 2 for n in range(4) if n % 2 == 0]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>{n ** 2 for n in range(4) if n % 2 == 0}<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>[r\"abc def\" for n in range(4)]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>[(1, 2) for n in range(4)]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>[n * m for n in range(4) for m in range(3) if n % 2 == 0]<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>{n * m for n in range(4) for m in range(3) if n % 2 == 0}<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>{n: n ** 2 for n in range(4) if n % 2 == 0}<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<style>\n#examplesTable a { text-decoration: none }\n<\/style>\n<script defer>\n{\nconst table = document.evaluate(\n    \"\/\/th[starts-with(text(),'Comprehension Code')]\", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)\n    .singleNodeValue.closest('table');\ntable.id = 'examplesTable';\ntable.addEventListener('click', (event) => {\n    if (event.target.tagName === 'A') {\n        document.getElementById('compCodeEl').value = event.target.innerText;\n        updateLoopCode();\n    }\n});\nfor (const codeEl of table.getElementsByTagName('code')) {\n    codeEl.insertAdjacentHTML('afterBegin', '<a href=\"#\"><\/a>');\n    codeEl.firstElementChild.append(codeEl.firstElementChild.nextSibling);\n}\n}\n<\/script>\n\n<!-- TODO: Asynchronous comprehensions https:\/\/www.python.org\/dev\/peps\/pep-0530\/ -->\n\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Comprehensions are a powerful feature in Python that can create very readable code when used\ncorrectly. However, like everything else, they have a place and time and it&rsquo;s not everywhere and\nall-the-time. It&rsquo;s important to understand them well if you&rsquo;re doing more than the trivial list\ncomprehension.<\/p>\n<p>Do check out the official documentation on <a href=\"https:\/\/docs.python.org\/3\/tutorial\/datastructures.html#list-comprehensions\" rel=\"noopener noreferrer\" target=\"_blank\">List Comprehensions<\/a>, which contains\na lot of <em>good<\/em> examples and ideas I didn&rsquo;t discuss here.<\/p>\n<p>Additionally, at the expense of repeating the same thing, there&rsquo;s some experiments on this page that\nare only intended for learning. Please do <strong>not<\/strong> use them in production code. Have pity on your\nfuture self.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"tutorial"}}]},{"title":"Automating the Vim workplace \u2014 Chapter \u2161","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/automating-the-vim-workplace-2\/","rel":"alternate"}},"published":"2020-02-16T00:00:00+05:30","updated":"2020-02-16T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-02-16:\/posts\/automating-the-vim-workplace-2\/","summary":"<p>This is a follow-up of the <a href=\"..\/automating-the-vim-workplace\/\">Automate the Vim workplace<\/a> article I published last\nmonth. As promised, here&rsquo;s a follow up with more on how I identified and addressed things in Vim\nthat could be improved to speed me up. Feel free to grab the ideas in this article \u2026<\/p>","content":"<p>This is a follow-up of the <a href=\"..\/automating-the-vim-workplace\/\">Automate the Vim workplace<\/a> article I published last\nmonth. As promised, here&rsquo;s a follow up with more on how I identified and addressed things in Vim\nthat could be improved to speed me up. Feel free to grab the ideas in this article or, better yet,\ntake inspiration and inspect your workflow to identify such opportunities.<\/p>\n<p>This article is part of a series:<\/p>\n<ol>\n<li><a href=\"..\/automating-the-vim-workplace\/\">Chapter \u2160<\/a>.<\/li>\n<li>Chapter \u2161 (this article).<\/li>\n<li><a href=\"..\/automating-the-vim-workplace-3\/\">Chapter \u2162<\/a>.<\/li>\n<\/ol>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#easier-alternative-to\">Easier Alternative to :<\/a><\/li>\n<li><a href=\"#repeat-key-mappings\">Repeat Key Mappings<\/a><\/li>\n<li><a href=\"#ruler-vs-status-line\">Ruler vs Status Line<\/a><\/li>\n<li><a href=\"#opening-switching-buffers\">Opening &amp; Switching Buffers<\/a><\/li>\n<li><a href=\"#change-cwd-smartly\">Change CWD Smartly<\/a><\/li>\n<li><a href=\"#jumping-over-paragraphs\">Jumping over Paragraphs<\/a><\/li>\n<li><a href=\"#vertical-line-selection\">Vertical Line Selection<\/a><\/li>\n<li><a href=\"#zoom-when-presenting\">Zoom When Presenting<\/a><\/li>\n<li><a href=\"#copy-lines-as-csv\">Copy Lines as CSV<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<p class=\"note\">Please note that all that I share below is what I&rsquo;m using with Vim (more specifically, GVim on\nWindows). I don&rsquo;t use Neovim (yet) and I can&rsquo;t speak for any of the below for Neovim.<\/p>\n<h2 id=\"easier-alternative-to\">Easier Alternative to <code>:<\/code><a class=\"headerlink\" href=\"#easier-alternative-to\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Going to the command-line mode for entering Ex commands is used very often, yet requires the hitting\nof <kbd>Shift<\/kbd> and <kbd>;<\/kbd> keys. This, while there&rsquo;s a giant blank key right under my\nthumbs that has no unique &amp; practical purpose in the normal mode, the <kbd>Space<\/kbd> key.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">noremap<\/span> <span class=\"p\">&lt;<\/span>Space<span class=\"p\">&gt;<\/span> :\n<\/span><\/code><\/pre><\/div>\n\n<p>This is likely my oldest mapping that survives even today. It&rsquo;s also the one I miss the most when\nworking with Vim on servers.<\/p>\n<p>Another popular alternative for this mapping is the <kbd>;<\/kbd> key. However, unlike the\n<kbd>Space<\/kbd> key, this one has a useful default functionality, which will be lost. (Look up <code>:h\n;<\/code> to find out, I won&rsquo;t repeat it here).<\/p>\n<p class=\"note\">Note that we use <code>noremap<\/code> here, not <code>nnoremap<\/code>. So this works when in visual mode as well.<\/p>\n<h2 id=\"repeat-key-mappings\">Repeat Key Mappings<a class=\"headerlink\" href=\"#repeat-key-mappings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>There&rsquo;s some mappings like <kbd>dd<\/kbd>, <kbd>cc<\/kbd> etc. that are made of two keys repeated\nsequentially. While the appear convenient, hitting them usually takes slightly longer than hitting\ntwo different keys in quick succession.<\/p>\n<p>So, for all these type of bindings (and then some), I have a predictable alternative that:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Maps that repeat a key can instead use the `.` key.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"k\">d<\/span>. dd\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"k\">y<\/span>. yy\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"k\">c<\/span>. <span class=\"k\">cc<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"k\">g<\/span>. gg\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"k\">v<\/span>. V\n<\/span><\/code><\/pre><\/div>\n\n<p>These bindings are a lot more convenient once our fingers get used to them and we get used to the\nmnemonic of the <kbd>.<\/kbd> here.<\/p>\n<h2 id=\"ruler-vs-status-line\">Ruler vs Status Line<a class=\"headerlink\" href=\"#ruler-vs-status-line\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is another topic that gets a lot of attention when one is setting up their Vim working\nenvironment. What with all the fancy status-line plugins in the wild, it is easy to get carried\naway.<\/p>\n<p>My recommendation (nothing unique, has been said by better people before), is that you look at your\nworking style first. How often do you make it a point to look at the status line while working? Now\ncompare this to the fact that the status line costs you one line of vertical space. Measure for\nyourself if it&rsquo;s worth it.<\/p>\n<p>If your question is, but what&rsquo;s the alternative? Where do I see stuff like the current line number,\ncolumn number, file type, the git branch, wi-fi status of the coffee shop across the street etc.\netc.? My answer is the same again, <em>firstly<\/em>, see what you need, identify what you&rsquo;ll miss and\nnarrow down to a minimal list of the stuff you need. Whatever you don&rsquo;t <strong>need<\/strong> is most likely just\na <strong>want<\/strong> and will end up being a distraction when you&rsquo;re in deep thought (the worst kind of\ndistraction). <em>Secondly<\/em>, we have the following other options.<\/p>\n<p><strong>One alternative<\/strong> is to use the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'ruler'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>ruler<\/code><\/a> option. This is similar to the status line,\nalthough not quite as flexible. But don&rsquo;t let that discourage you, for minimal information to be\nshown in the corner of your Vim, it&rsquo;s plenty powerful. By default, it just shows the current cursor\nposition, but can be configured to show anything with the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'rulerformat'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>rulerformat<\/code><\/a> option. I\nwon&rsquo;t go into detail on how to configure them (may be in the future \/ others have done it better\nthan I could).<\/p>\n<p>First, turn on <code>ruler<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">set<\/span> <span class=\"nb\">ruler<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Next, I set <code>rulerformat<\/code> as a variable since it&rsquo;s slightly easier this way when dealing with escape\ncharacters.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><\/pre><pre class=content><code><span><span class=\"k\">let<\/span> &amp;<span class=\"nb\">rulerformat<\/span> <span class=\"p\">=<\/span> <span class=\"s1\">&#39;%50(b%n %{&amp;ff} %{&amp;ft}&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%( %{len(getqflist()) ? (&quot;q&quot; . len(getqflist())) : &quot;&quot;}%)&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%( %{search(&quot;\\\\s$&quot;, &quot;cnw&quot;, 0, 200) ? &quot;\u2219$&quot; : &quot;&quot;}%)&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%( %{exists(&quot;b:stl_fn&quot;) ? call(b:stl_fn) : &quot;&quot;}%)&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%= L%l,%c%V %P %*%)&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Each line in the above snippet is a little piece of information that I need to know at a glance.\nHere&rsquo;s a run down:<\/p>\n<ol>\n<li>Buffer number, <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'fileformat'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>'fileformat'<\/code><\/a> (indicates line endings), <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'filetype'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>'filetype'<\/code><\/a>.<\/li>\n<li>A count of items in the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/quickfix.html#quickfix\" rel=\"noopener noreferrer\" target=\"_blank\">quickfix<\/a> list.<\/li>\n<li>An indicator for trailing whitespace in the current buffer.<\/li>\n<li>A buffer specific function that may be called for additional input to be shown. I hardly use this\n   currently.<\/li>\n<li>Cursor position information.<\/li>\n<\/ol>\n<p><strong>The second alternative<\/strong> is the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'titlestring'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>titlestring<\/code><\/a>. This defines what shows up in the\ntitle bar of the window-manager&rsquo;s window (not Vim <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/windows.html#windows\" rel=\"noopener noreferrer\" target=\"_blank\">window<\/a>). <\/p>\n<p>Using this is quite similar to using the ruler. Just turn it on and set a value to be shown. This is\nwhat I use currently:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">set<\/span> <span class=\"nb\">title<\/span>\n<\/span><span><span class=\"k\">let<\/span> &amp;<span class=\"nb\">titlestring<\/span> <span class=\"p\">=<\/span> <span class=\"s1\">&#39;%t%( %m%r%)%( &lt;%{get(g:, &quot;cur_project&quot;, &quot;&quot;)}&gt;%)&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%( (%{expand(&quot;%:~:.:h&quot;)})%)&#39;<\/span> .\n<\/span><span>            \\ <span class=\"s1\">&#39;%( (%{getcwd()})%)%( %a%) - %(%{v:servername}%)&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This contains the buffer&rsquo;s name, indicators for modified and read-only, value of the global variable\n<code>cur_project<\/code> (if set), path of the current buffer relative from current directory, the current\nworking directory itself, and finally, the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/eval.html#v:servername\" rel=\"noopener noreferrer\" target=\"_blank\"><code>servername<\/code><\/a>.<\/p>\n<p class=\"note\">Note that I use <code>titlestring<\/code> with GVim. If you want it to work when working with terminal Vim as\nwell, you might need to consult your terminal emulator&rsquo;s (or multiplexer&rsquo;s) documentation regarding\nthis.<\/p>\n<h2 id=\"opening-switching-buffers\">Opening &amp; Switching Buffers<a class=\"headerlink\" href=\"#opening-switching-buffers\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is a problem that is usually solved with one of the fuzzy finder plugins. The current most\npopular one appears to be a plugin based on fzf. I have used <a href=\"https:\/\/github.com\/wincent\/command-t\" rel=\"noopener noreferrer\" target=\"_blank\">Command-T<\/a>, <a href=\"https:\/\/github.com\/ctrlpvim\/ctrlp.vim\" rel=\"noopener noreferrer\" target=\"_blank\">ctrlp<\/a>, <a href=\"https:\/\/github.com\/Yggdroot\/LeaderF\" rel=\"noopener noreferrer\" target=\"_blank\">LeaderF<\/a>\nand even one that I made for myself. But then something happened on my system that broke the\nfuzzy-finder that I was using at the time (don&rsquo;t exactly remember which). Pressed for time, I chose\nto use the commands that come with Vim, and haven&rsquo;t bothered to investigate what broke the fuzzy\nfinder. The following has been enough to keep me happy and productive:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Simple mappings for buffer switching.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">d<\/span> :<span class=\"k\">b<\/span> *\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">l<\/span> :<span class=\"k\">ls<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span>\n<\/span><span><span class=\"c\">&quot; Find\/edit files<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">f<\/span> :find *\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">e<\/span> :edit **\/*\n<\/span><\/code><\/pre><\/div>\n\n<p>It may not seem as powerful when you put it beside the shiny screen recordings of the fuzzy finder\nplugins, but it just works &trade; and works perfectly fine. I took inspiration from <a href=\"https:\/\/vimways.org\/2018\/death-by-a-thousand-files\/\" rel=\"noopener noreferrer\" target=\"_blank\">this excellent\narticle<\/a> on the topic by <a href=\"https:\/\/github.com\/romainl\" rel=\"noopener noreferrer\" target=\"_blank\">romainl<\/a>. Thank you!<\/p>\n<h2 id=\"change-cwd-smartly\">Change CWD Smartly<a class=\"headerlink\" href=\"#change-cwd-smartly\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is another very old mapping that still survives. It comes in two flavors, I use <code>cm<\/code> and <code>cu<\/code>\nfor these. Briefly,<\/p>\n<ul>\n<li><code>cm<\/code> &ndash; <em>cd<\/em> to current buffer&rsquo;s directory.<\/li>\n<li><code>cu<\/code> &ndash; <em>cd<\/em> to the current <strong>project<\/strong>&rsquo;s root directory.<\/li>\n<\/ul>\n<p>The first one is fairly simple to implement:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Mapping to change pwd to the directory of the current buffer.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> cm :<span class=\"k\">call<\/span> <span class=\"k\">chdir<\/span><span class=\"p\">(<\/span>expand<span class=\"p\">(<\/span><span class=\"s1\">&#39;%:p:h&#39;<\/span><span class=\"p\">))<\/span> \\<span class=\"p\">|<\/span> <span class=\"k\">pwd<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>For the second one, it is important to understand how a project&rsquo;s root identified. To me, it&rsquo;s a\ndirectory containing the <code>.git<\/code> folder. That&rsquo;s not a perfect answer, but it hasn&rsquo;t failed me a lot\nso far. Nevertheless, my mapping below supports looking for a few other such <em>project markers<\/em>, like\n<code>.hg<\/code> for mercurial VCS, <code>.project<\/code> for Eclipse projects, <code>manage.py<\/code> for Django projects etc.<\/p>\n<p>There&rsquo;s a few plugins that do this as well, probably better than this, but I like to do these kind\nof simple things myself, to have control and to have it tuned to my habits.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><\/pre><pre class=content><code><span><span class=\"c\">&quot; Map to change pwd to the repo-root-directory of the current buffer.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> cu :<span class=\"k\">call<\/span> <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>CdToRepoRoot<span class=\"p\">()&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">let<\/span> <span class=\"k\">g<\/span>:markers <span class=\"p\">=<\/span> split<span class=\"p\">(<\/span><span class=\"s1\">&#39;.git .hg .svn .project .idea manage.py pom.xml&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">fun<\/span> s:CdToRepoRoot<span class=\"p\">()<\/span> abort\n<\/span><span>    <span class=\"k\">for<\/span> marker <span class=\"k\">in<\/span> <span class=\"k\">g<\/span>:markers\n<\/span><span>        <span class=\"k\">let<\/span> root <span class=\"p\">=<\/span> finddir<span class=\"p\">(<\/span>marker<span class=\"p\">,<\/span> expand<span class=\"p\">(<\/span><span class=\"s1\">&#39;%:p:h&#39;<\/span><span class=\"p\">)<\/span> . <span class=\"s1\">&#39;;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">if<\/span> <span class=\"p\">!<\/span>empty<span class=\"p\">(<\/span>root<span class=\"p\">)<\/span>\n<\/span><span>            <span class=\"k\">let<\/span> root <span class=\"p\">=<\/span> fnamemodify<span class=\"p\">(<\/span>root<span class=\"p\">,<\/span> <span class=\"s1\">&#39;:h&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>            <span class=\"k\">call<\/span> <span class=\"k\">chdir<\/span><span class=\"p\">(<\/span>root<span class=\"p\">)<\/span>\n<\/span><span>            echo <span class=\"s1\">&#39;cd &#39;<\/span> . root . <span class=\"s1\">&#39; (found &#39;<\/span> . marker . <span class=\"s1\">&#39;)&#39;<\/span>\n<\/span><span>            <span class=\"k\">return<\/span>\n<\/span><span>        <span class=\"k\">endif<\/span>\n<\/span><span>    <span class=\"k\">endfor<\/span>\n<\/span><span>    <span class=\"k\">echoerr<\/span> <span class=\"s1\">&#39;No repo root found.&#39;<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>What&rsquo;s happening here is that for each marker in <code>g:markers<\/code>, we navigate up from the current\nbuffer&rsquo;s directory until we find a folder that has the marker. If found, we <code>chdir<\/code> to it.\nOtherwise, we repeat the process for the next marker. If no marker was found, we just show an error\nmessage. Simple &amp; effective.<\/p>\n<h2 id=\"jumping-over-paragraphs\">Jumping over Paragraphs<a class=\"headerlink\" href=\"#jumping-over-paragraphs\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is one of the things I wanted for a long time, but couldn&rsquo;t figure out a robust solution. It&rsquo;s\nonly last year (IIRC) that I finally nailed it and this version works exactly how I want it.<\/p>\n<p>The idea is that the keys <kbd>&lt;C-j&gt;<\/kbd> and <kbd>&lt;C-k&gt;<\/kbd> will jump over\nparagraphs, and place the cursor at the start of the first line in the paragraph. I needed the\nfollowing to be true:<\/p>\n<ol>\n<li>After hitting either key, the cursor is positioned on the first line of a paragraph, <strong>never<\/strong> on\n   a blank line.<\/li>\n<li>When in the middle of a paragraph, <kbd>&lt;C-k&gt;<\/kbd> moves the cursor to the first line of\n   the <strong>current<\/strong> paragraph.<\/li>\n<li>Moves are <strong>not<\/strong> added to the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/motion.html#jumplist\" rel=\"noopener noreferrer\" target=\"_blank\">jumplist<\/a>.<\/li>\n<li>Cursor is placed on the first non-blank character of the paragraph. Like <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/motion.html#^\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>^<\/kbd><\/a>,\n   not <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/motion.html#0\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>0<\/kbd><\/a>.<\/li>\n<li>They should work just fine in both normal &amp; visual modes and the visual mode type should <strong>not<\/strong>\n   change when hitting the keys.<\/li>\n<\/ol>\n<p>Here&rsquo;s how I&rsquo;m doing this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">noremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>expr<span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">k<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">(<\/span>line<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> search<span class=\"p\">(<\/span><span class=\"s1\">&#39;^\\n.\\+$&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Wenb&#39;<\/span><span class=\"p\">))<\/span> . <span class=\"s1\">&#39;kzv^&#39;<\/span>\n<\/span><span><span class=\"nb\">noremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>expr<span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">j<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">(<\/span>search<span class=\"p\">(<\/span><span class=\"s1\">&#39;^\\n.&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Wen&#39;<\/span><span class=\"p\">)<\/span> <span class=\"p\">-<\/span> line<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">))<\/span> . <span class=\"s1\">&#39;jzv^&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I needed to use the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/map.html#:map-expression\" rel=\"noopener noreferrer\" target=\"_blank\"><code>&lt;expr&gt;<\/code><\/a> way of mapping keys here so as to satisfy the third and\nfifth of my requirements list above.<\/p>\n<p>The default mappings that come closest to this are the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/motion.html#{\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>{<\/kbd><\/a> and\n<a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/motion.html#}\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>}<\/kbd><\/a>. But they don&rsquo;t satisfy my first and third requirements, and I&rsquo;m <em>very<\/em> picky.\nI actually still use them, when they seem appropriate, but I hit the above custom mappings a lot\nmore often.<\/p>\n<h2 id=\"vertical-line-selection\">Vertical Line Selection<a class=\"headerlink\" href=\"#vertical-line-selection\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is one of my recent favorites (&lt; 2 years old). This is the use case, usually when I went\ninto visual block mode with <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/visual.html#CTRL-V\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>&lt;C-v&gt;<\/kbd><\/a>, I extend it upwards to the first line in\nparagraph and also downwards to the last line of the paragraph.<\/p>\n<p>The following GIF might make this easier to understand:<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/vim-vertical-selection-manual.gif\"><img alt=\"Vertical-line selection demo\" src=\"https:\/\/sharats.me\/static\/vim-vertical-selection-manual.gif\"><\/a><\/p>\n<p>This seems simple enough to do manually when there&rsquo;s just a few lines to deal with. But when there&rsquo;s\n&gt;15 lines and you notice yourself doing this a dozen times a day, you need a better way.<\/p>\n<p>The following mapping is my solution to this. When I hit <kbd>vm<\/kbd>, the following happens:<\/p>\n<ol>\n<li>Visual block selection is activated.<\/li>\n<li>Selection extends as a single column downwards until we hit a line that&rsquo;s shorter than the cursor\n   column position or we hit end of buffer.<\/li>\n<li>Selection extends in a similar fashion upwards.<\/li>\n<\/ol>\n<p>The way this is implemented is that firstly we compute the number of lines to be travelled upwards\nand downwards from the current position. Then we construct a normal mode command which will start\nthe visual-block mode and move the cursor so that the vertical line is selected. For example, in the\nGIF above, our function would construct the normal mode command <kbd>\\&lt;C-v&gt;2jo1k<\/kbd>. This\nworks quite well and doesn&rsquo;t affect the jumplist.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><\/pre><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>expr<span class=\"p\">&gt;<\/span> vm <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>VisualVLine<span class=\"p\">()<\/span>\n<\/span><span><span class=\"k\">fun<\/span><span class=\"p\">!<\/span> s:VisualVLine<span class=\"p\">()<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> lnum<span class=\"p\">,<\/span> <span class=\"k\">col<\/span>; _] <span class=\"p\">=<\/span> getcurpos<span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> line <span class=\"p\">=<\/span> getline<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">col<\/span> <span class=\"p\">+=<\/span> strdisplaywidth<span class=\"p\">(<\/span>line<span class=\"p\">)<\/span> <span class=\"p\">-<\/span> strwidth<span class=\"p\">(<\/span>line<span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">let<\/span> [from<span class=\"p\">,<\/span> <span class=\"k\">to<\/span>] <span class=\"p\">=<\/span> [lnum<span class=\"p\">,<\/span> lnum]\n<\/span><span>    <span class=\"k\">while<\/span> strdisplaywidth<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span>from <span class=\"p\">-<\/span> <span class=\"m\">1<\/span><span class=\"p\">))<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"k\">col<\/span>\n<\/span><span>        <span class=\"k\">let<\/span> from <span class=\"p\">-=<\/span> <span class=\"m\">1<\/span>\n<\/span><span>    <span class=\"k\">endwhile<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">while<\/span> strdisplaywidth<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span><span class=\"k\">to<\/span> <span class=\"p\">+<\/span> <span class=\"m\">1<\/span><span class=\"p\">))<\/span> <span class=\"p\">&gt;=<\/span> <span class=\"k\">col<\/span>\n<\/span><span>        <span class=\"k\">let<\/span> <span class=\"k\">to<\/span> <span class=\"p\">+=<\/span> <span class=\"m\">1<\/span>\n<\/span><span>    <span class=\"k\">endwhile<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"s2\">&quot;\\&lt;C-v&gt;&quot;<\/span> .\n<\/span><span>                \\ <span class=\"p\">(<\/span><span class=\"k\">to<\/span> <span class=\"p\">==<\/span> lnum ? <span class=\"s1\">&#39;&#39;<\/span> : <span class=\"p\">(<\/span><span class=\"k\">to<\/span> <span class=\"p\">-<\/span> lnum . <span class=\"s1\">&#39;jo&#39;<\/span><span class=\"p\">))<\/span> .\n<\/span><span>                \\ <span class=\"p\">(<\/span>from <span class=\"p\">==<\/span> lnum ? <span class=\"s1\">&#39;&#39;<\/span> : <span class=\"p\">(<\/span>lnum <span class=\"p\">-<\/span> from . <span class=\"s1\">&#39;k&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"zoom-when-presenting\">Zoom When Presenting<a class=\"headerlink\" href=\"#zoom-when-presenting\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Occasionally (read: more often than I like to admit), I end up having to present some code to a\nsmall audience with is slightly larger than my immediate team. Additionally, I also note down the\nproceedings of meetings in Vim and present them on screen sharing to get inputs and corrections,\nessentially steering the meeting.<\/p>\n<p>On such occasions, I need to increase the font size so it&rsquo;s visible to everyone in the audience \/\nmeeting. When presenting, I&rsquo;ve heard complaints from people sitting a bit far back, and when sharing\nmy screen, I&rsquo;ve heard complaints from people connecting from their mobile devices (!).<\/p>\n<p>The following two mappings are born out of this need.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><\/pre><pre class=content><code><span><span class=\"c\">&quot; Increase \/ Decrease font size.<\/span>\n<\/span><span><span class=\"k\">let<\/span> <span class=\"k\">g<\/span>:font_size_pat <span class=\"p\">=<\/span> s:iswin ? <span class=\"s1\">&#39;:h\\zs\\d\\+&#39;<\/span> : <span class=\"s1\">&#39;\\d\\+&#39;<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> z<span class=\"p\">+<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">let<\/span> &amp;<span class=\"nb\">guifont<\/span> <span class=\"p\">=<\/span> substitute<span class=\"p\">(<\/span>\n<\/span><span>            \\ &amp;<span class=\"nb\">guifont<\/span><span class=\"p\">,<\/span> <span class=\"k\">g<\/span>:font_size_pat<span class=\"p\">,<\/span>\n<\/span><span>            \\ <span class=\"s1\">&#39;\\=eval(submatch(0) + &#39;<\/span> . <span class=\"k\">v<\/span>:count1 . <span class=\"s1\">&#39;)&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>            \\ \\<span class=\"p\">|<\/span><span class=\"k\">simalt<\/span> <span class=\"p\">~<\/span><span class=\"k\">x<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> z<span class=\"p\">-<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">let<\/span> &amp;<span class=\"nb\">guifont<\/span> <span class=\"p\">=<\/span> substitute<span class=\"p\">(<\/span>\n<\/span><span>            \\ &amp;<span class=\"nb\">guifont<\/span><span class=\"p\">,<\/span> <span class=\"k\">g<\/span>:font_size_pat<span class=\"p\">,<\/span>\n<\/span><span>            \\ <span class=\"s1\">&#39;\\=eval(submatch(0) - &#39;<\/span> . <span class=\"k\">v<\/span>:count1 . <span class=\"s1\">&#39;)&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>            \\ \\<span class=\"p\">|<\/span><span class=\"k\">simalt<\/span> <span class=\"p\">~<\/span><span class=\"k\">x<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span>nmap z<span class=\"p\">&lt;<\/span>kPlus<span class=\"p\">&gt;<\/span> z<span class=\"p\">+<\/span>\n<\/span><span>nmap z<span class=\"p\">&lt;<\/span>kMinus<span class=\"p\">&gt;<\/span> z<span class=\"p\">-<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This snippet defines two mappings in normal mode, <kbd>z+<\/kbd> and <kbd>z-<\/kbd>, that work with\nthe keypad as well (which is what the last two lines are for).<\/p>\n<p>This works by calling substitute on the <code>guifont<\/code> option with a pattern tailored for how the font\nsize is specified on the current platform. The replacement for this pattern contains a\n<a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/change.html#sub-replace-expression\" rel=\"noopener noreferrer\" target=\"_blank\">sub-replace-expression<\/a> that spits out the new font size number.<\/p>\n<p>However, there was a quirk. Once the font size is changed, the Vim window is restored (not maximized\nanymore). This was annoying to me since I almost always keep my Vim maximized (especially when\npresenting). So, the following <code>simalt ~x<\/code> will maximize the window again.<\/p>\n<p>Another small additional feature in these mappings is that they accept a count. For example, hitting\n<kbd>z+<\/kbd> will increase the font size by 1 point, hitting <kbd>3z+<\/kbd> will increase it by 3\npoints.<\/p>\n<h2 id=\"copy-lines-as-csv\">Copy Lines as CSV<a class=\"headerlink\" href=\"#copy-lines-as-csv\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I write my notes, both work and study in Vim, as plain text, loosely Markdown (I&rsquo;ll write about that\nin a future article). Among these notes, there&rsquo;s occasionally lists of domain specific stuff for the\napplications or projects I&rsquo;m working with. I usually need these as reference for objects that I\noften look up in databases. For example, I have a note like the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span>| Object  | Database ID |\n<\/span><span>| ------- | ----------- |\n<\/span><span>| Mercury | 4           |\n<\/span><span>| Venus   | 32          |\n<\/span><span>| Earth   | 42          |\n<\/span><span>| Moon    | 44          |\n<\/span><\/code><\/pre><\/div>\n\n<p>From this I want do a visual-block selection of all the ID numbers and paste it into an SQL <code>SELECT<\/code>\nquery that looks something like:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">SELECT<\/span><span class=\"w\"> <\/span><span class=\"o\">*<\/span><span class=\"w\"> <\/span><span class=\"k\">FROM<\/span><span class=\"w\"> <\/span><span class=\"n\">celestial_objects<\/span><span class=\"w\"> <\/span><span class=\"k\">WHERE<\/span><span class=\"w\"> <\/span><span class=\"n\">id<\/span><span class=\"w\"> <\/span><span class=\"k\">IN<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">32<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">42<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">44<\/span><span class=\"p\">);<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Essentially, what I needed was to copy the visually selected lines as a comma separated string.\nIt might seem an overkill solution for the example I&rsquo;m demonstrating here, but when there&rsquo;s ID\nnumbers in the millions and Markdown tables with over a dozen rows as reference in my notes, it\nquickly adds up to being extremely annoying.<\/p>\n<p>So, I came up with the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Copy selected lines as CSV<\/span>\n<\/span><span>xnoremap <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">y<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> <span class=\"p\">&lt;<\/span>SID<span class=\"p\">&gt;<\/span>CopyLinesAsCSV<span class=\"p\">()&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span> s:CopyLinesAsCSV<span class=\"p\">()<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l1<span class=\"p\">,<\/span> c1<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&lt;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l2<span class=\"p\">,<\/span> c2<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&gt;&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"nb\">lines<\/span> <span class=\"p\">=<\/span> map<span class=\"p\">(<\/span>getline<span class=\"p\">(<\/span>l1<span class=\"p\">,<\/span> l2<span class=\"p\">),<\/span> {<span class=\"k\">i<\/span><span class=\"p\">,<\/span> <span class=\"k\">l<\/span> <span class=\"p\">-&gt;<\/span> trim<span class=\"p\">(<\/span><span class=\"k\">l<\/span>[c1<span class=\"m\">-1<\/span>:c2<span class=\"m\">-1<\/span>]<span class=\"p\">)<\/span>}<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">call<\/span> setreg<span class=\"p\">(<\/span><span class=\"k\">v<\/span>:<span class=\"k\">register<\/span><span class=\"p\">,<\/span> <span class=\"k\">join<\/span><span class=\"p\">(<\/span><span class=\"nb\">lines<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;, &#39;<\/span><span class=\"p\">),<\/span> <span class=\"s1\">&#39;l&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This defines a mapping in visual mode, <kbd>&lt;Leader&gt;y<\/kbd> (which can take a register, just\nlike the default <kbd>y<\/kbd>) that takes the selected lines (or selected block), joins them with\n<code>', '<\/code> and puts that in the register.<\/p>\n<p>Here&rsquo;s a preview of this in action:<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/vim-copy-as-csv.gif\"><img alt=\"Copy column as CSV demo\" src=\"https:\/\/sharats.me\/static\/vim-copy-as-csv.gif\"><\/a><\/p>\n<p>This combined with the <kbd>vm<\/kbd> explained in a previous section, it&rsquo;s really quick to take a\ncolumn of values as a comma separated string.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is a continuous process of identifying and honing the habits at work. Considering how\nprogrammable Vim can be when it comes to editing text, it&rsquo;s both fun and productive to introspect.\nAlthough I won&rsquo;t discourage you from it, I recommend not to just blindly copy everything here into\nyour own vimrc. Take only if you need, take only what you need, and do take everything you need.<\/p>\n<p>I plan to write the next chapter in this series next month, so stay tuned and remember to check\nback.<\/p>\n<p>Identify, optimize, repeat.<\/p>\n<p class=\"note\">Read the <a href=\"..\/automating-the-vim-workplace\/\">previous article<\/a>, or the <a href=\"..\/automating-the-vim-workplace-3\/\">next article<\/a> in this series.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"vim"}},{"@attributes":{"term":"productivity"}}]},{"title":"Python's `itertools.groupby` callable","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/python-itertools-groupby-callable\/","rel":"alternate"}},"published":"2020-02-09T00:00:00+05:30","updated":"2020-02-09T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-02-09:\/posts\/python-itertools-groupby-callable\/","summary":"<p>The <code>groupby<\/code> utility from the <a href=\"https:\/\/docs.python.org\/3\/library\/itertools.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>itertools<\/code><\/a> module can be used to group contiguous items in a\nsequence based on some property of the items.<\/p>\n<p>Python has several utilities for working with lists and other sequence data types. In addition to a\nlot of such utilities being directly available as builtins \u2026<\/p>","content":"<p>The <code>groupby<\/code> utility from the <a href=\"https:\/\/docs.python.org\/3\/library\/itertools.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>itertools<\/code><\/a> module can be used to group contiguous items in a\nsequence based on some property of the items.<\/p>\n<p>Python has several utilities for working with lists and other sequence data types. In addition to a\nlot of such utilities being directly available as builtins (like <a href=\"..\/python-map-function\/\"><code>map<\/code><\/a>, <code>filter<\/code>,\n<code>zip<\/code> etc), the <code>itertools<\/code> module is dedicated to this purpose. In this article, I&rsquo;ll show the\n<a href=\"https:\/\/docs.python.org\/3\/library\/itertools.html#itertools.groupby\" rel=\"noopener noreferrer\" target=\"_blank\"><code>groupby<\/code><\/a> callable from this standard library module. I hope to write more in the future\non the other awesome stuff from this module.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#basic-usage\">Basic Usage<\/a><\/li>\n<li><a href=\"#non-contiguous-groups\">Non-contiguous Groups<\/a><\/li>\n<li><a href=\"#groups-are-iterables\">Groups are Iterables<\/a><\/li>\n<li><a href=\"#a-really-bad-diy-implementation\">A Really Bad DIY Implementation<\/a><\/li>\n<li><a href=\"#usage-tips\">Usage Tips<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"basic-usage\">Basic Usage<a class=\"headerlink\" href=\"#basic-usage\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The point of <code>itertools.groupby<\/code> can be illustrated quite easily by applying to a list of zeroes and\nones, to be grouped by their values. Check out the following example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">numbers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">grouping_value<\/span><span class=\"p\">,<\/span> <span class=\"n\">group_items<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"n\">numbers<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;By&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">grouping_value<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-&gt;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">group_items<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>By 1 -&gt; 1 1 1\n<\/span><span>By 0 -&gt; 0 0\n<\/span><span>By 1 -&gt; 1\n<\/span><span>By 0 -&gt; 0 0 0\n<\/span><span>By 1 -&gt; 1\n<\/span><span>By 0 -&gt; 0\n<\/span><\/code><\/pre><\/div>\n\n<p>Now let&rsquo;s look at this, little by little. The <code>groupby<\/code> call takes one or, probably more often, two\narguments:<\/p>\n<dl>\n<dt>iterable<\/dt>\n<dd>An iterable (like a list or any other collection). Items in this collection will be grouped.<\/dd>\n<dt>key (defaults to <code>None<\/code>)<\/dt>\n<dd>A function that is applied to each element from <code>iterable<\/code>, the return values of which are used\nto do the grouping.<\/dd>\n<dt><em>returns<\/em><\/dt>\n<dd>A generator that yields tuples of <code>(grouping_value, iterable_of_group_elements)<\/code> for each group\nthat was found.<\/dd>\n<\/dl>\n<p>In the example above, we give the <code>numbers<\/code> list to the <code>groupby<\/code> call which yields six groups (as\ncan be seen from the six lines of output). Since we haven&rsquo;t provided a value for the <code>key<\/code> argument,\nthe grouping occurs on the elements themselves.<\/p>\n<p>So now the output should make sense. The first group, where the <code>grouping_value<\/code> is <code>1<\/code> will contain\nthree elements, the first three <code>1<\/code>s in our list. The next group, where the <code>grouping_value<\/code> is <code>0<\/code>\nwill contain the next two <code>0<\/code>s in our list. This goes on until the list passed to <code>groupby<\/code> is\nexhausted.<\/p>\n<p class=\"note\">It is important to note here that inside the tuples yielded by <code>groupby<\/code>, what we have are iterables\nthat yield the group&rsquo;s items. They are not lists. More specifically, the tuple contains an object of\ntype <code>itertools._grouper<\/code>, which is just an iterable over the values in the group. This point is\nelaborated in a <a href=\"#groups-are-iterables\">section further below<\/a>.<\/p>\n<h2 id=\"non-contiguous-groups\">Non-contiguous Groups<a class=\"headerlink\" href=\"#non-contiguous-groups\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This often comes up as a surprise to people new to <code>itertools.groupby<\/code> (it certainly did for me).\nThe groups created are of contiguous regions only. For example, if we are trying group even and odd\nnumbers from a collection ordered of numbers, just a call to <code>groupby<\/code> can produce surprising\nresults:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">is_even<\/span><span class=\"p\">,<\/span> <span class=\"n\">number_group<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Evens:&#39;<\/span> <span class=\"k\">if<\/span> <span class=\"n\">is_even<\/span> <span class=\"k\">else<\/span> <span class=\"s1\">&#39;Odds:&#39;<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">number_group<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This produces the following (probably unexpected) result:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Evens: 0\n<\/span><span>Odds: 1\n<\/span><span>Evens: 2\n<\/span><span>Odds: 3\n<\/span><span>Evens: 4\n<\/span><span>Odds: 5\n<\/span><span>Evens: 6\n<\/span><span>Odds: 7\n<\/span><span>Evens: 8\n<\/span><span>Odds: 9\n<\/span><\/code><\/pre><\/div>\n\n<p>What we would&rsquo;ve liked is something like the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Evens: 0 2 4 6 8\n<\/span><span>Odds: 1 3 5 7 9\n<\/span><\/code><\/pre><\/div>\n\n<p>If we search the ever helpful internet for a solution to this &ldquo;problem&rdquo;, the answer seems to be to\nsort the initial list with the same key function and then pass the result to <code>groupby<\/code>. This is how\nthat would work:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">is_even<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">n<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">is_even_val<\/span><span class=\"p\">,<\/span> <span class=\"n\">number_group<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"nb\">sorted<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"n\">is_even<\/span><span class=\"p\">),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"n\">is_even<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Evens:&#39;<\/span> <span class=\"k\">if<\/span> <span class=\"n\">is_even_val<\/span> <span class=\"k\">else<\/span> <span class=\"s1\">&#39;Odds:&#39;<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">number_group<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This produces an output much closer to what we wanted:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Odds: 1 3 5 7 9\n<\/span><span>Evens: 0 2 4 6 8\n<\/span><\/code><\/pre><\/div>\n\n<p>Now, ignoring the evil of pre-mature optimization, the fact that we are calling the key function\ntwice might cause terminally serious itches to some developers. One (possibly silly) way around this\nis to store the results of the key function right next to the values, as a tuple and then unpack the\nvalues once we&rsquo;re done grouping. This would look like:<\/p>\n<div class=\"hl\"><pre class=content><code><span>import itertools\n<\/span><span>\n<\/span><span>def is_even(n):\n<\/span><span>    return n % 2 == 0\n<\/span><span>\n<\/span><span>\n<\/span><span>numbers = range(10)\n<\/span><span>keyed_numbers = [(is_even(n), n) for n in numbers]\n<\/span><span>sorted_numbers = sorted(keyed_numbers)\n<\/span><span>\n<\/span><span>for is_even_val, pair_group in itertools.groupby(sorted_numbers, key=lambda pair: pair[0]):\n<\/span><span>    print(&#39;Evens:&#39; if is_even_val else &#39;Odds:&#39;, *(pair[1] for pair in pair_group))\n<\/span><\/code><\/pre><\/div>\n\n<p>This produces the same output as the previous example, but calls the key function (<code>is_even<\/code> in this\nexample&rsquo;s case) only <em>once<\/em> per item in our list.<\/p>\n<p class=\"note\">Before you attempt the above apparent <em>solution<\/em> to performance issues, prove to yourself that\nfirstly, you <strong>have a performance issue<\/strong> and that this piece of code <strong>is at least part of the\nreason<\/strong> for it. Otherwise you&rsquo;re probably just wasting your time.<\/p>\n<p>Since this is arguably more useful, let&rsquo;s create an alternative <code>groupby<\/code> that will sort first and\nthen call <code>itertools.groupby<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">sorted_groupby<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">yield from<\/span> <span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"nb\">sorted<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"n\">key<\/span><span class=\"p\">),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"n\">key<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We can use this function like:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">for<\/span> <span class=\"n\">is_even_val<\/span><span class=\"p\">,<\/span> <span class=\"n\">number_group<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">sorted_groupby<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">),<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Evens:&#39;<\/span> <span class=\"k\">if<\/span> <span class=\"n\">is_even_val<\/span> <span class=\"k\">else<\/span> <span class=\"s1\">&#39;Odds:&#39;<\/span><span class=\"p\">,<\/span> <span class=\"o\">*<\/span><span class=\"n\">number_group<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will produce the same output as below:<\/p>\n<div class=\"hl\"><pre class=content><code><span>Odds: 1 3 5 7 9\n<\/span><span>Evens: 0 2 4 6 8\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"groups-are-iterables\">Groups are Iterables<a class=\"headerlink\" href=\"#groups-are-iterables\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I have mentioned this earlier in this article, but it&rsquo;s important enough to stress again. The group\ncollections yielded by the <code>groupby<\/code> call <strong>are not lists<\/strong>. They are iterables that are rendered\nunusable upon yielding the next group. If you need the values, make sure you collect them before\ngoing to the next group.<\/p>\n<p>For example, consider the following snippet:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">pprint<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pprint<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">by_casing<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"n\">names<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"nb\">str<\/span><span class=\"o\">.<\/span><span class=\"n\">istitle<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">[<\/span><span class=\"kc\">True<\/span><span class=\"p\">]))<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">[<\/span><span class=\"kc\">False<\/span><span class=\"p\">]))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This produces the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>{False: &lt;itertools._grouper object at 0x0000000002B6D278&gt;,\n<\/span><span> True: &lt;itertools._grouper object at 0x0000000002B6BF28&gt;}\n<\/span><span>[]\n<\/span><span>[]\n<\/span><\/code><\/pre><\/div>\n\n<p>The seemingly strange thing to notice here, is that although <code>groupby<\/code> returned two groupings, their\ngrouped values are empty (hinted by the two empty lists output). But of course, <code>groupby<\/code> wouldn&rsquo;t\nreturn a group unless there&rsquo;s <em>at least<\/em> one item in the corresponding collection. So, what&rsquo;s going\non?<\/p>\n<p>This is the point I was getting at in the first paragraph of this section. The grouping collections\n(the values in the dictionary above) are <em>de facto<\/em> destroyed once we yield another group. So, if we\nwanted to construct a dictionary like this, we need to do something like the following:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">defaultdict<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">pprint<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pprint<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">by_casing<\/span> <span class=\"o\">=<\/span> <span class=\"n\">defaultdict<\/span><span class=\"p\">(<\/span><span class=\"nb\">list<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">is_title<\/span><span class=\"p\">,<\/span> <span class=\"n\">group_names<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">itertools<\/span><span class=\"o\">.<\/span><span class=\"n\">groupby<\/span><span class=\"p\">(<\/span><span class=\"n\">names<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"nb\">str<\/span><span class=\"o\">.<\/span><span class=\"n\">istitle<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">by_casing<\/span><span class=\"p\">[<\/span><span class=\"n\">is_title<\/span><span class=\"p\">]<\/span><span class=\"o\">.<\/span><span class=\"n\">extend<\/span><span class=\"p\">(<\/span><span class=\"n\">group_names<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">[<\/span><span class=\"kc\">True<\/span><span class=\"p\">])<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">by_casing<\/span><span class=\"p\">[<\/span><span class=\"kc\">False<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">{<\/span><span class=\"kc\">False<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">],<\/span> <span class=\"kc\">True<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">]}<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Just something to keep in mind.<\/p>\n<p class=\"note\">The above snippet of code uses <a href=\"https:\/\/docs.python.org\/3\/library\/collections.html#collections.defaultdict\" rel=\"noopener noreferrer\" target=\"_blank\"><code>collections.defaultdict<\/code><\/a>. I haven&rsquo;t written about\nthis yet, but I intend to, in the near future (most likely within the 21st century).<\/p>\n<h2 id=\"a-really-bad-diy-implementation\">A Really Bad DIY Implementation<a class=\"headerlink\" href=\"#a-really-bad-diy-implementation\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Let&rsquo;s try and create an implementation of our own version of <code>groupby<\/code>, called <code>insane_grouper<\/code>. It\nshould have the following characteristics:<\/p>\n<ol>\n<li>Take an iterable, and optionally a key function, interpreting like <code>itertools.groupby<\/code>.<\/li>\n<li>Group non-contiguous items as a single collections.<\/li>\n<li>Return a dictionary of each group&rsquo;s key value as the keys and the group&rsquo;s list of items as the\n   values.<ul>\n<li>This is great since it goes well with our point 2 above. For computing non-contiguous groups,\n  it is not possible to compute the groups lazily (why? is an exercise for the reader). So,\n  might as well return a dictionary with all the groups.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>This might look something like the following:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">itertools<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">defaultdict<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">pprint<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pprint<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">insane_grouper<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"n\">key<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">groups<\/span> <span class=\"o\">=<\/span> <span class=\"n\">defaultdict<\/span><span class=\"p\">(<\/span><span class=\"nb\">list<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">item<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">iterable<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">groups<\/span><span class=\"p\">[<\/span><span class=\"n\">item<\/span> <span class=\"k\">if<\/span> <span class=\"n\">key<\/span> <span class=\"ow\">is<\/span> <span class=\"kc\">None<\/span> <span class=\"k\">else<\/span> <span class=\"n\">key<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">)]<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">item<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">groups<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">names<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">insane_grouper<\/span><span class=\"p\">(<\/span><span class=\"n\">names<\/span><span class=\"p\">,<\/span> <span class=\"nb\">str<\/span><span class=\"o\">.<\/span><span class=\"n\">istitle<\/span><span class=\"p\">))<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">insane_grouper<\/span><span class=\"p\">(<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">),<\/span> <span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span> <span class=\"o\">%<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The output of this snippet is the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">{<\/span><span class=\"kc\">False<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;ford&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;zaphod&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;slartibartfast&#39;<\/span><span class=\"p\">],<\/span> <span class=\"kc\">True<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;Arthur&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Trillian&#39;<\/span><span class=\"p\">]}<\/span>\n<\/span><span><span class=\"p\">{<\/span><span class=\"kc\">False<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">7<\/span><span class=\"p\">,<\/span> <span class=\"mi\">9<\/span><span class=\"p\">],<\/span> <span class=\"kc\">True<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"mi\">8<\/span><span class=\"p\">]}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"usage-tips\">Usage Tips<a class=\"headerlink\" href=\"#usage-tips\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here&rsquo;s a few tips and cases where this can be used to quickly compute distinct collections of\nobjects:<\/p>\n<ol>\n<li>A list of dictionaries can be grouped by the value against a particular key present in all (or\n   some?) of the dictionaries in the list.<\/li>\n<li>The key function can return a tuple. This can be useful where we need to group the items by\n   multiple criteria, instead of just one.<\/li>\n<\/ol>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>While the default behaviour of <code>itertools.groupby<\/code> may not always be what one expects, it is still\nuseful. The important point to note is to understand the problem you&rsquo;re solving, consider the tools\nat your disposal and choose the right tool for the job. On that note, I&rsquo;ll leave you with another\nlink to the <a href=\"https:\/\/docs.python.org\/3\/library\/itertools.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>itertools<\/code><\/a> module.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"tutorial"}},{"@attributes":{"term":"python-itertools"}},{"@attributes":{"term":"itertools-groupby"}}]},{"title":"The `tar` Command Clipboard","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-tar-command-clipboard\/","rel":"alternate"}},"published":"2020-02-02T00:00:00+05:30","updated":"2020-02-02T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-02-02:\/posts\/the-tar-command-clipboard\/","summary":"<p>Recently, while doing an experiment with my blog&rsquo;s rendered output with a VPS instance, I needed to\ntransfer it to the server over SSH. While doing that, I experimented with archiving the folder a\nbit, so I&rsquo;m putting the outcome of that experience here, should I need it \u2026<\/p>","content":"<p>Recently, while doing an experiment with my blog&rsquo;s rendered output with a VPS instance, I needed to\ntransfer it to the server over SSH. While doing that, I experimented with archiving the folder a\nbit, so I&rsquo;m putting the outcome of that experience here, should I need it again in the future.<\/p>\n<p>All notes below assume GNU <code>tar v1.26<\/code>. More specifically, the output of <code>tar --version | head -1<\/code>\ngives:<\/p>\n<div class=\"hl\"><pre class=content><code><span>tar (GNU tar) 1.26\n<\/span><\/code><\/pre><\/div>\n\n<p>I&rsquo;m only listing the arguments and use-cases that I think are most frequently used (at least by me)\nand the ones I&rsquo;m most likely to need in the future. Please complement this with a healthy serving of\n<code>man tar<\/code> to keep your sanity.<\/p>\n<p class=\"note\">Check out this neat little tool to help generate often-used <code>tar<\/code> commands:\n<a href=\"https:\/\/cligen.sharats.me\" rel=\"noopener noreferrer\" target=\"_blank\">cligen.sharats.me<\/a>. Thanks!<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#creating-archives\">Creating Archives<\/a><ul>\n<li><a href=\"#create-a-tarbz2-archive\">Create a .tar.bz2 Archive<\/a><\/li>\n<li><a href=\"#exclude-git-directory\">Exclude .git Directory<\/a><\/li>\n<li><a href=\"#set-initial-directory\">Set Initial Directory<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#inspecting-archives\">Inspecting Archives<\/a><ul>\n<li><a href=\"#single-vs-multiple-top-levels\">Single vs Multiple Top Levels<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#extracting-archives\">Extracting Archives<\/a><ul>\n<li><a href=\"#extracting-to-different-directory\">Extracting to Different Directory<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#transferring-archives-directories\">Transferring Archives \/ Directories<\/a><ul>\n<li><a href=\"#local-to-remote\">Local to Remote<\/a><\/li>\n<li><a href=\"#remote-to-local\">Remote to Local<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"creating-archives\">Creating Archives<a class=\"headerlink\" href=\"#creating-archives\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>-c<\/code> (or <code>--create<\/code>) command is used to <strong>create<\/strong> archives.<\/p>\n<p class=\"note\">The <code>-<\/code> in front of the <code>c<\/code> can be omitted, but I find that ugly and prefer to include it. That way\nit&rsquo;s consistent with most other such GNU commands.<\/p>\n<p>Additional options after <code>-c<\/code>:<\/p>\n<ol>\n<li>\n<p><code>v<\/code> &ndash; Enable verbose output. Adding this will print each file as it is being added to the\n   archive.<\/p>\n<\/li>\n<li>\n<p><code>z<\/code> or <code>j<\/code> &ndash; Specify the compression format, if needed. Use <code>z<\/code> for <code>gz<\/code> archive or <code>j<\/code> for\n   <code>bz2<\/code> archive. This can also be <code>a<\/code> to infer the compression format from the file name, but only\n   if the <code>f<\/code> (explained in the next point) is also given. Other compression formats like <code>--xz<\/code>,\n   <code>--lzip<\/code> etc. can also be used.<\/p>\n<\/li>\n<li>\n<p><code>f<\/code> &ndash; Use the next argument as the file name of the archive. If this argument is not provided,\n   the archive content is written to the standard out.<\/p>\n<\/li>\n<li>\n<p><code>--remove-files<\/code> &ndash; Remove files after adding them to the archive. Be careful with this.<\/p>\n<\/li>\n<\/ol>\n<p>To illustrate the examples, I&rsquo;ll clone one of my public repositories and play around with creating\narchives of it.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>git<span class=\"w\"> <\/span>clone<span class=\"w\"> <\/span>git@github.com:sharat87\/just-a-calendar.git\n<\/span><span><span class=\"gp\">$ <\/span>du<span class=\"w\"> <\/span>-sh<span class=\"w\"> <\/span>just-a-calendar\n<\/span><span><span class=\"go\">248K    just-a-calendar\/<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"create-a-tarbz2-archive\">Create a <code>.tar.bz2<\/code> Archive<a class=\"headerlink\" href=\"#create-a-tarbz2-archive\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>To create a <code>bz2<\/code> archive of a folder:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-cjf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span>just-a-calendar\n<\/span><span><span class=\"gp\">$ <\/span>file<span class=\"w\"> <\/span>package.tar.bz2\n<\/span><span><span class=\"go\">package.tar.bz2: bzip2 compressed data, block size = 900k<\/span>\n<\/span><span><span class=\"gp\">$ <\/span>du<span class=\"w\"> <\/span>-sh<span class=\"w\"> <\/span>package.tar.bz2\n<\/span><span><span class=\"go\">76K     package.tar.bz2<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Since we are specifying the file name here, which includes the <code>.bz2<\/code> part at the end, we can tell\n<code>tar<\/code> to just figure out the compression we want to use. Instead of the <code>j<\/code> argument specifying the\ncompression, we&rsquo;d put in <code>a<\/code> to indicate this.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-caf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span>just-a-calendar\n<\/span><span><span class=\"gp\">$ <\/span>file<span class=\"w\"> <\/span>package.tar.bz2\n<\/span><span><span class=\"go\">package.tar.bz2: bzip2 compressed data, block size = 900k<\/span>\n<\/span><span><span class=\"gp\">$ <\/span>du<span class=\"w\"> <\/span>-sh<span class=\"w\"> <\/span>package.tar.bz2\n<\/span><span><span class=\"go\">76K     package.tar.bz2<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"exclude-git-directory\">Exclude <code>.git<\/code> Directory<a class=\"headerlink\" href=\"#exclude-git-directory\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Now, the archive also contains the <code>.git<\/code> directory that was present in our clone. We probably don&rsquo;t\nwhat that. The <code>tar<\/code> command provides <code>--exclude*<\/code> family of arguments to deal with this. For\nexample, as in our case, to ignore the folder <code>.git<\/code>, we could do:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-caf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span>--exclude<span class=\"o\">=<\/span>.git<span class=\"w\"> <\/span>just-a-calendar\n<\/span><span><span class=\"gp\">$ <\/span>du<span class=\"w\"> <\/span>-sh<span class=\"w\"> <\/span>package.tar.bz2\n<\/span><span><span class=\"go\">12K     package.tar.bz2<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This package doesn&rsquo;t contain the <code>.git<\/code> folder (and consequently is <em>much<\/em> smaller). However, for\nthis particular problem, there&rsquo;s perhaps an even better solution, the <code>--exclude-vcs<\/code> argument. This\nargument will ignore any VCS directories automatically and it knows about <code>.git<\/code>. So our command\nbecomes:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-caf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span>--exclude-vcs<span class=\"w\"> <\/span>just-a-calendar\n<\/span><\/code><\/pre><\/div>\n\n<p>Another similar useful argument is the <code>--eclude-backups<\/code>, which will <strong>exclude backup and lock\nfiles<\/strong> which also is usually what we want.<\/p>\n<h3 id=\"set-initial-directory\">Set Initial Directory<a class=\"headerlink\" href=\"#set-initial-directory\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <code>-C<\/code> (or <code>--directory<\/code>) argument sets the initial working directory before creating the archive.\nThis will influence the paths with which the files <em>inside<\/em> the archive are saved with. This is\nnormally only useful if for some reason you can&rsquo;t <code>cd<\/code> or <code>pushd<\/code> to that directory yourself, which\nis not very often.<\/p>\n<h2 id=\"inspecting-archives\">Inspecting Archives<a class=\"headerlink\" href=\"#inspecting-archives\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>-t<\/code> (or <code>--list<\/code>) can be used to list the contents of an archive without extracting it.<\/p>\n<p>Additional options after <code>-t<\/code>:<\/p>\n<ol>\n<li>\n<p><code>v<\/code> &ndash; Verbose listing. The affect of adding this option is like adding <code>-l<\/code> to the <code>ls<\/code> command.\n   That is, it will show each file&rsquo;s permissions, size, last modified <em>etc.<\/em> details.<\/p>\n<\/li>\n<li>\n<p><code>f<\/code> &ndash; Treat next argument as the archive file name. This argument is <em>usually<\/em> always needed\n   with the <code>-t<\/code> command (unless the archive is being piped in to the <code>tar -t<\/code> command).<\/p>\n<\/li>\n<\/ol>\n<p>Let&rsquo;s run this on our package archive created in the previous section.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-tf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>wc<span class=\"w\"> <\/span>-l\n<\/span><span><span class=\"go\">6<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"single-vs-multiple-top-levels\">Single vs Multiple Top Levels<a class=\"headerlink\" href=\"#single-vs-multiple-top-levels\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>There&rsquo;s one thing about extracting archives that&rsquo;s extremely annoying. If it contains multiple files\nat top level, it&rsquo;ll pollute the current directory with several objects. To combat this, if we make\nit a habit to create a new folder and extract inside it, it might turn out that the archive itself\ncontains a top level directory, so now we end up one useless directory in the tree.<\/p>\n<p>This situation is actually handled very well by the <code>aunpack<\/code> command from the <a href=\"https:\/\/www.nongnu.org\/atool\/\" rel=\"noopener noreferrer\" target=\"_blank\">atool<\/a> script.\nThis command takes an archive (of any of several different formats) and extracts it. If it contains\na single top level entry, it is extracted to your working directory. If it contains several top\nlevel entries, a new directory is created and the extraction happens inside that new directory. This\ncommand is extremely convenient, for this and several other reasons.<\/p>\n<p>To find out if an archive has a single top-level entry or multiple, the following snippet can be\nused:<\/p>\n<div class=\"hl\"><pre class=content><code><span>tar<span class=\"w\"> <\/span>-tf<span class=\"w\"> <\/span>package.tar.bz2<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>cut<span class=\"w\"> <\/span>-d\/<span class=\"w\"> <\/span>-f1<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>sort<span class=\"w\"> <\/span>-u\n<\/span><\/code><\/pre><\/div>\n\n<p>This will print out one top-level entry per line. If there&rsquo;s only one line in the output, then\nthere&rsquo;s only one top-level. How this works is that first, the <code>cut<\/code> command splits the listing with\n<code>\/<\/code> character, the file separator and only prints the first entry, which will be the top level\nentry. Then, the <code>sort<\/code> command will sort the top-levels and only print the <strong>unique<\/strong> entries\n(that&rsquo;s what the <code>-u<\/code> is for). We could further pipe this to <code>wc -l<\/code> and check if it results in <code>1<\/code>.<\/p>\n<h2 id=\"extracting-archives\">Extracting Archives<a class=\"headerlink\" href=\"#extracting-archives\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>-x<\/code> (or <code>--extract<\/code>) command is used to <strong>extract<\/strong> the contents of archives.<\/p>\n<p>This command takes the following arguments:<\/p>\n<ol>\n<li>\n<p><code>v<\/code> &ndash; Verbose logging. Prints each file path as it is being extracted.<\/p>\n<\/li>\n<li>\n<p><code>z<\/code> or <code>j<\/code> &ndash; Specify the compression format, if needed. Similar in working as with the <code>-c<\/code>\n   command.<\/p>\n<\/li>\n<li>\n<p><code>f<\/code> &ndash; Reads the next argument as the archive file name. This is almost always used with this\n   command to specify the archive to extract. If this is not provided, the archive content is\n   expected to be available from standard input.<\/p>\n<\/li>\n<li>\n<p><code>k<\/code> (or <code>--keep-old-files<\/code>) &ndash; Fail if any existing files will be overwritten by extracting. This\n   is useful if you don&rsquo;t want any of your existing files to be overwritten.<\/p>\n<\/li>\n<\/ol>\n<p>So, to extract our archive (in a separate location, of course):<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">$ <\/span>mkdir<span class=\"w\"> <\/span>spike<span class=\"w\"> <\/span><span class=\"o\">&amp;&amp;<\/span><span class=\"w\"> <\/span><span class=\"nb\">cd<\/span><span class=\"w\"> <\/span>spike\n<\/span><span><span class=\"gp\">$ <\/span>tar<span class=\"w\"> <\/span>-xaf<span class=\"w\"> <\/span>..\/package.tar.bz2\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"extracting-to-different-directory\">Extracting to Different Directory<a class=\"headerlink\" href=\"#extracting-to-different-directory\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The extract command also supports the <code>-C<\/code> (or <code>--directory<\/code>) argument that sets the initial working\ndirectory before extracting. This can be used to change the location where the extracted\nfiles\/folder will be saved.<\/p>\n<h2 id=\"transferring-archives-directories\">Transferring Archives \/ Directories<a class=\"headerlink\" href=\"#transferring-archives-directories\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In this section, I&rsquo;ll show a couple of quick examples where we need to transfer a folder tree\nbetween current local system and a remote system reachable by SSH.<\/p>\n<h3 id=\"local-to-remote\">Local to Remote<a class=\"headerlink\" href=\"#local-to-remote\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>We could create a <code>tar<\/code> file of the folder (and any other files as well), transfer the file to the\nremote system, login to the remote system and unpack it there.<\/p>\n<p>There&rsquo;s a couple of problems with this approach:<\/p>\n<ol>\n<li>Since we are creating an archive of the folder on our local disk, we need to have the necessary\n   free space for that archive. This may be less the size of the folder, but can still be\n   significant if the folder is large. The same problem will also appear on the remote system.<\/li>\n<li>We need write permissions on the local disk. If we want to just take a folder to a remote system,\n   we should only need write permission on the remote disk, not on the local disk.<\/li>\n<\/ol>\n<p>To avoid the above two problems, we can transfer the archive directly as a stream, without saving it\nto the local disk. Notice that if we don&rsquo;t provide a filename for the create (<code>-c<\/code>) command, the\narchive will be written to standard out. Similarly, if we don&rsquo;t provide a filename for the extract\n(<code>-x<\/code>) command, it will read the archive from standard input. Our solution below will leverage these\ntwo facts.<\/p>\n<div class=\"hl\"><pre class=content><code><span>tar<span class=\"w\"> <\/span>-cj<span class=\"w\"> <\/span>just-a-calendar<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>ssh<span class=\"w\"> <\/span>remote<span class=\"w\"> <\/span>tar<span class=\"w\"> <\/span>-xj\n<\/span><\/code><\/pre><\/div>\n\n<p>The first command (<code>tar -cj just-a-calendar<\/code>) creates a <code>bzip2<\/code>-compressed archive (we could&rsquo;ve used\n<code>z<\/code> here to use <code>gz<\/code> compression instead) and writes it to the standard out. This becomes the\nstandard input for the <code>ssh<\/code> command which will connect to the remote host, invoke the <code>tar -xj<\/code>\ncommand, and forwards it&rsquo;s own standard input to that <code>tar -xj<\/code> command. The <code>tar -xj<\/code> command\nextracts the archive from it&rsquo;s standard input, using <code>bzip2<\/code> for decompressing and writes the\nextracted contents to the remote user&rsquo;s home directory.<\/p>\n<p>For added measure, we could use the <code>-C<\/code> (or <code>--directory<\/code>) argument to <code>tar -xj<\/code> to set the\ndirectory where the extracted files would be saved.<\/p>\n<p>This method is extremely handy since the archive is not written to the disk anywhere, not on local,\nnot on remote. It&rsquo;s only processed as a stream of bytes.<\/p>\n<p>The <code>-j<\/code> argument to the <code>tar<\/code> commands is not strictly necessary. The whole thing will work even\nwithout it.  But since the archive is being transferred over network, it pays to spend a little\nprocessor time into compressing it so as to minimize network usage (and consequently, speed up the\noperation).<\/p>\n<p>We could&rsquo;ve added the <code>-v<\/code> argument to one (or both!?) <code>tar<\/code> commands to show the files as they are\nbeing archived\/extracted.<\/p>\n<h3 id=\"remote-to-local\">Remote to Local<a class=\"headerlink\" href=\"#remote-to-local\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This follows a similar method as in the previous section, but in the other way around. We run the\narchiver <code>tar<\/code> command on the remote host, and the extractor <code>tar<\/code> command on the local machine.<\/p>\n<div class=\"hl\"><pre class=content><code><span>ssh<span class=\"w\"> <\/span>remote<span class=\"w\"> <\/span>tar<span class=\"w\"> <\/span>-cj<span class=\"w\"> <\/span>just-a-calendar<span class=\"w\"> <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>tar<span class=\"w\"> <\/span>-xj\n<\/span><\/code><\/pre><\/div>\n\n<p>This will recreate the <code>just-a-calendar<\/code> folder on the remote host, onto the local disk. We could\nuse the <code>-C<\/code> argument to either <code>tar<\/code> command to set it&rsquo;s initial working directory.<\/p>\n<p>Of course, if wanted to just save the archive on the local disk, not extract it, we could just\nredirect the stream to a file.<\/p>\n<div class=\"hl\"><pre class=content><code><span>ssh remote tar -cj just-a-calendar &gt; package.tar.bz2\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>tar<\/code> command, in all it&rsquo;s variations, is irreplaceable in it&rsquo;s utility for these kind of\npurposes. The handiest resource for getting help while working with it is, of course, the man page.\nBut when we&rsquo;re in the mood to just copy-pasta (yes, pasta) a command to serve the purpose, I hope\nthis article will be helpful.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"shell"}},{"@attributes":{"term":"bash"}},{"@attributes":{"term":"tar"}},{"@attributes":{"term":"tutorial"}},{"@attributes":{"term":"command-clipboard"}}]},{"title":"Working with Strings in Python","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/working-with-strings-in-python\/","rel":"alternate"}},"published":"2020-01-26T00:00:00+05:30","updated":"2020-01-26T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-01-26:\/posts\/working-with-strings-in-python\/","summary":"<p>This article will be a practical rundown of working with strings in Python, made up of things I\nconstantly forget and have to look up on how to do. I hope it will serve as a super-quick reference\nfor me as well as for anybody else who stumbles here.<\/p>\n<p>This \u2026<\/p>","content":"<p>This article will be a practical rundown of working with strings in Python, made up of things I\nconstantly forget and have to look up on how to do. I hope it will serve as a super-quick reference\nfor me as well as for anybody else who stumbles here.<\/p>\n<p>This document is not intended for beginners to Python. Although you can still get something out of\nit, it&rsquo;s best suited for intermediate Python programmers. I tried to illustrate the concepts in a\ncrisp manner with minimum carry-over context from one section to the next.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#defining-strings\">Defining Strings<\/a><ul>\n<li><a href=\"#single-and-double-quoted-strings\">Single and Double Quoted Strings<\/a><\/li>\n<li><a href=\"#tripled-quoted-strings\">Tripled Quoted Strings<\/a><\/li>\n<li><a href=\"#escape-characters\">Escape Characters<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#auto-concatenated-strings\">Auto-concatenated Strings<\/a><\/li>\n<li><a href=\"#raw-strings\">Raw Strings<\/a><\/li>\n<li><a href=\"#concatenation\">Concatenation<\/a><\/li>\n<li><a href=\"#splitting\">Splitting<\/a><ul>\n<li><a href=\"#the-splitlines-method\">The .splitlines Method<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#substring-check\">Substring Check<\/a><ul>\n<li><a href=\"#prefix-and-suffix-check\">Prefix and Suffix Check<\/a><\/li>\n<li><a href=\"#regular-expressions-check\">Regular Expressions Check<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#learning-about-the-contents\">Learning About the Contents<\/a><ul>\n<li><a href=\"#numeric-checks\">Numeric Checks<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#transformations\">Transformations<\/a><\/li>\n<li><a href=\"#string-formatting\">String Formatting<\/a><\/li>\n<li><a href=\"#docstrings\">Docstrings<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"defining-strings\">Defining Strings<a class=\"headerlink\" href=\"#defining-strings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<h3 id=\"single-and-double-quoted-strings\">Single and Double Quoted Strings<a class=\"headerlink\" href=\"#single-and-double-quoted-strings\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>We&rsquo;ll refer to strings delimited by the <code>'<\/code> character as single quoted strings and those delimited\nby <code>\"<\/code> as double quoted strings.<\/p>\n<p>They are identical in all respects, except that single quote needs to be escaped in single quoted\nstrings and double quote needs to be escaped in double quoted strings.<\/p>\n<p>They cannot span multiple lines. A string&rsquo;s ending quote character must appear in the same line as\nit begins. This can be worked around by using a <code>\\<\/code> character at the end of the line. For example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;abc<\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"s1\">def&#39;<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will print:<\/p>\n<div class=\"hl\"><pre class=content><code><span>abc\n<\/span><span>def\n<\/span><\/code><\/pre><\/div>\n\n<p>But it&rsquo;s best to avoid breaking using <code>\\<\/code> to break strings into multiple lines. It&rsquo;s not pretty and\nthere&rsquo;s better way to do it. Especially <a href=\"#auto-concatenated-strings\">auto-concatenated strings<\/a>\n(discussed below).<\/p>\n<h3 id=\"tripled-quoted-strings\">Tripled Quoted Strings<a class=\"headerlink\" href=\"#tripled-quoted-strings\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Tripled quoted strings are a syntax for defining multi-line strings. There&rsquo;s no practical difference\nbetween defining strings with <code>'''<\/code> and <code>\"\"\"<\/code>.<\/p>\n<p>In practice, this syntax is commonly used for one of the following:<\/p>\n<ol>\n<li><a href=\"#docstrings\">Docstrings<\/a> (discussed below), for writing documentation for classes\/functions.<\/li>\n<li>Module level constant strings that contain long multi-line content. Can be used for small HTML\n   templates that are stored inline or complex SQL queries, long regular expression patterns etc.<\/li>\n<li>An <em>approximation<\/em> for multi-line comments. Python doesn&rsquo;t have multi-line comments (like <code>\/*<\/code>\n   and <code>*\/<\/code> in C-like languages). Wrapping whole code blocks with tripled quotes can turn it into a\n   pseudo-comment. I personally discourage this, but it&rsquo;s nonetheless used in real-world code.<\/li>\n<\/ol>\n<p>The string created when using tripled quoted strings will contain <em>everything<\/em> between the tripled\nquotes. This includes any indentation present due to Python block-style formatting. For example:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><\/pre><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">make_story<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;&#39;&#39;<\/span>\n<\/span><span><span class=\"s1\">    Once upon a time, there was a planet.<\/span>\n<\/span><span><span class=\"s1\">    Suddenly, it named itself Earth.<\/span>\n<\/span><span><span class=\"s1\">    And it hoped to live happily ever after.<\/span>\n<\/span><span><span class=\"s1\">    &#39;&#39;&#39;<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">text<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"nb\">repr<\/span><span class=\"p\">(<\/span><span class=\"n\">make_story<\/span><span class=\"p\">()))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>&#39;\\n    Once upon a time, there was a planet.\\n    Suddenly, it named itself Earth.\\n    And it hoped to live happily ever after.\\n    &#39;\n<\/span><\/code><\/pre><\/div>\n\n<p>There&rsquo;s three things to note in the string defined in this function:<\/p>\n<ol>\n<li>It starts with a newline character, the one that comes right after the opening <code>'''<\/code> on line 2.<ul>\n<li>This particular point can be easily addressed by adding a <code>\\<\/code> right after the opening <code>'''<\/code>.<\/li>\n<\/ul>\n<\/li>\n<li>Each line, except for the first, starts with four spaces, because of the indentation of the\n   <code>make_story<\/code> function.<ul>\n<li>The <a href=\"https:\/\/docs.python.org\/3\/library\/textwrap.html#textwrap.dedent\" rel=\"noopener noreferrer\" target=\"_blank\"><code>textwrap.dedent<\/code><\/a> function from standard library can help deal with this.\n  Details in the next paragraph.<\/li>\n<\/ul>\n<\/li>\n<li>It ends with a newline character and the four spaces from the line 6.<ul>\n<li>Calling <code>.strip<\/code> (or <code>.rstrip<\/code>) on the string can do this.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>Considering the above three points, we rewrite the previous code fragment as:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><\/pre><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">textwrap<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">make_story<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"n\">textwrap<\/span><span class=\"o\">.<\/span><span class=\"n\">dedent<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;&#39;&#39;<\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"s1\">    Once upon a time, there was a planet.<\/span>\n<\/span><span><span class=\"s1\">    Suddenly, it named itself Earth.<\/span>\n<\/span><span><span class=\"s1\">    And it hoped to live happily ever after.<\/span>\n<\/span><span><span class=\"s1\">    &#39;&#39;&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">rstrip<\/span><span class=\"p\">())<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">text<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that it is important to use <code>.rstrip<\/code> here, and not <code>.strip<\/code>. The reason is that <code>.strip<\/code> will\nremove the whitespace before <code>Once...<\/code> line and so the first line in the string won&rsquo;t have any\nindentation. Now the documentation of <code>textwrap.dedent<\/code> says:<\/p>\n<blockquote>\n<p>Remove any common leading whitespace from every line in text.<\/p>\n<\/blockquote>\n<p>But since our first line doesn&rsquo;t have the indentation anymore, there&rsquo;s no <em>common<\/em> leading\nwhitespace in <code>text<\/code>. So, this function won&rsquo;t remove the indentation. Another option would be to do\n<code>dedent<\/code> first, and then call <code>.strip<\/code> on the result of <code>dedent<\/code>.<\/p>\n<p>The output of this program would be:<\/p>\n<div class=\"hl\"><pre class=content><code><span>&#39;Once upon a time, there was a planet.\\nSuddenly, it named itself Earth.\\nAnd it hoped to live happily ever after.&#39;\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"escape-characters\">Escape Characters<a class=\"headerlink\" href=\"#escape-characters\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Backslash based escape characters behave exactly the same way in strings defined with any quote\ntype.<\/p>\n<p>Following is a list of <em>commonly used<\/em> escape characters. This list is <strong>not exhaustive<\/strong>.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Escape sequence<\/th>\n<th>Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>'\\'<\/code> (at end of line)<\/td>\n<td>String definition is continued to next line<\/td>\n<\/tr>\n<tr>\n<td><code>'\\n'<\/code><\/td>\n<td>Newline character<\/td>\n<\/tr>\n<tr>\n<td><code>'\\\\'<\/code><\/td>\n<td>Literal backslash character<\/td>\n<\/tr>\n<tr>\n<td><code>'\\''<\/code><\/td>\n<td>Single quote character, useful in single quoted strings, but works everywhere<\/td>\n<\/tr>\n<tr>\n<td><code>\"\\\"\"<\/code><\/td>\n<td>Double quote character, useful in double quoted strings, but works everywhere<\/td>\n<\/tr>\n<tr>\n<td><code>'\\xhh'<\/code><\/td>\n<td>Character by hex value given by the <code>hh<\/code> part<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Regarding escaping quote characters:<\/p>\n<ol>\n<li>Single quotes don&rsquo;t <em>have to<\/em> be escaped in double quote strings, but it&rsquo;s not an error to do so.<\/li>\n<li>Double quotes don&rsquo;t <em>have to<\/em> be escaped in single quote strings, but it&rsquo;s not an error to do so.<\/li>\n<li>Neither quotes <em>have to<\/em> be escaped in tripled quote strings, but it&rsquo;s not an error to do so.<\/li>\n<\/ol>\n<p>In tripled quote strings, the delimiters <strong>cannot be escaped<\/strong> to become part of the string. For\nexample, a <code>'''<\/code> sequence cannot be part of the string when the string is defined with <code>'''<\/code>. But it\nmay be part of the string, when it&rsquo;s defined with <code>\"<\/code> or <code>\"\"\"<\/code>. This behaviour cannot be escaped.<\/p>\n<h2 id=\"auto-concatenated-strings\">Auto-concatenated Strings<a class=\"headerlink\" href=\"#auto-concatenated-strings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python has a nice compiler level feature to auto-concatenate <em>literal<\/em> strings that are next to each\nother (or more correctly, forming a single expressions). Take a look at an example to illustrate the\npoint:<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><\/pre><pre class=content><code><span><span class=\"n\">query<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span>\n<\/span><span>    <span class=\"s1\">&#39;SELECT * FROM employees&#39;<\/span>\n<\/span><span>    <span class=\"s1\">&#39;  WHERE name = ?&#39;<\/span>\n<\/span><span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">query<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The string <code>query<\/code> is defined as two parts, each on lines 2 and 3. These two strings will be\nconcatenated automatically at compile-time. The output of the above program would be:<\/p>\n<div class=\"hl\"><pre class=content><code><span>SELECT * FROM employees  WHERE name = ?\n<\/span><\/code><\/pre><\/div>\n\n<p>Things to note regarding this behaviour:<\/p>\n<ol>\n<li>The strings don&rsquo;t have any operator between them, like <code>+<\/code> or <code>,<\/code> or something else.<\/li>\n<li>This works only with <em>string literals<\/em>, it won&rsquo;t work when applied to variables.<\/li>\n<li>This is a compile-time feature, and so is more performant than string concatenation using the <code>+<\/code>\n   operator.<\/li>\n<li>The multiple string literals should be part of the same expression. So, if we are writing them on\n   multiple lines, they have to wrapped in parentheses or we should use the <code>\\<\/code> character to tell\n   Python to treat multiple lines as a single expression.<\/li>\n<li>Works with combinations of ordinary strings, raw strings, format strings and any combinations of\n   them together.<\/li>\n<\/ol>\n<p>Thanks to this feature, there&rsquo;s almost never a reason to define long string constants by\nconcatenating several strings.<\/p>\n<h2 id=\"raw-strings\">Raw Strings<a class=\"headerlink\" href=\"#raw-strings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python&rsquo;s raw strings&rsquo; syntax is a small variation that disables the escaping behaviour of the <code>\\<\/code>\ncharacter. A string is treated as a raw string if the starting delimiter quote is prefixed with a\n<code>r<\/code> (or <code>R<\/code>) character.<\/p>\n<p>The following expressions create <em>equal<\/em> (as defined by <code>==<\/code> operator) string:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Unadorned string<\/th>\n<th>Raw string<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>'abc'<\/code><\/td>\n<td><code>r'abc'<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'abc\\ndef'<\/code><\/td>\n<td><em>not possible<\/em><\/td>\n<\/tr>\n<tr>\n<td><code>'abc\\\\ndef'<\/code><\/td>\n<td><code>r'abc\\ndef'<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>In other words, the special escaping behaviour of <code>\\<\/code> character cannot be used in raw strings. This\nis useful when you have a lot of <code>\\\\<\/code> in your unadorned string. Such a string&rsquo;s definition can be\nmuch simpler if using raw strings.<\/p>\n<p>Points to note regarding raw strings:<\/p>\n<ol>\n<li>Can be used with single, double or tripled quotes.<\/li>\n<li>The actual string object created is no different from the one when using unadorned string syntax.\n   It is just a syntax-level convenience.<\/li>\n<li>Delimiter quotes cannot be included in raw strings. In other words, single quotes cannot be a\n   part of raw single quote strings. For example, <code>r'abc\\'def'<\/code> gives the string <code>\"abc\\\\'def\"<\/code>. That\n   is, the string will contain one backslash, and one single quote, essentially it will be exactly\n   as it looks like in the definition.<\/li>\n<li>Cannot be defined to end with a single <code>\\<\/code>. The expression <code>r'abc\\'<\/code> will raise a <code>SyntaxError<\/code>.\n   The expression <code>r'abc\\\\'<\/code> will end with two backslash characters.<\/li>\n<\/ol>\n<p>The limitations above can be worked around by using raw and ordinary strings together.<\/p>\n<p>Most commonly useful scenarios for raw strings:<\/p>\n<ol>\n<li>Regular expression patterns, to be used with the <a href=\"https:\/\/docs.python.org\/3\/library\/re.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>re<\/code><\/a> module.<\/li>\n<li>Windows style file paths, where the separator is the backslash character. Note that the <code>open<\/code>\n   function works fine even with forward slashes on Windows, so this is <em>generally<\/em> not needed.<\/li>\n<li>SQL queries, especially when defined with tripled quotes as module level constants.<\/li>\n<\/ol>\n<h2 id=\"concatenation\">Concatenation<a class=\"headerlink\" href=\"#concatenation\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>+<\/code> operator can be used to concatenate two strings. This will create a new string object which\nis the result of the concatenation (<code>str<\/code> objects are immutable in Python).<\/p>\n<p>If there&rsquo;s several strings being concatenated, using the <code>+<\/code> operator may not be the best way to do\nthis. For example, consider the following snippet of code:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;&#39;<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">text<\/span> <span class=\"o\">+=<\/span> <span class=\"s1\">&#39;we have <\/span><span class=\"si\">%r<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">%<\/span> <span class=\"n\">i<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>When run, it produces the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>we have 0\n<\/span><span>we have 1\n<\/span><span>we have 2\n<\/span><span>we have 3\n<\/span><\/code><\/pre><\/div>\n\n<p>However, using the <code>+<\/code> operator here means that intermediate string objects are created at every\nconcatenation operation. This is needless memory allocation since these intermediate string objects\nare never used, and are ready for garbage collection rather quickly. For situations like this,\nthere&rsquo;s better options than concatenating strings using <code>+<\/code> operator.<\/p>\n<p><strong>One option<\/strong> is to use a list and then pass it to <code>''.join<\/code> method to concatenate them all in one\ngo. Using this option in the above code snippet, we get:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">fragments<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">fragments<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;we have <\/span><span class=\"si\">%r<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">%<\/span> <span class=\"n\">i<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">fragments<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Additionally, in this case, we could&rsquo;ve used <code>'\\n'.join<\/code> instead and avoid the trailing newline in\n<code>text<\/code> (<em>if<\/em> that&rsquo;s what is desired, don&rsquo;t do it just because we can).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">lines<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">lines<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;we have <\/span><span class=\"si\">%r<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">%<\/span> <span class=\"n\">i<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">lines<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p><strong>Another option<\/strong> is to use <a href=\"https:\/\/docs.python.org\/3\/library\/io.html#io.StringIO\" rel=\"noopener noreferrer\" target=\"_blank\"><code>io.StringIO<\/code><\/a> which is a file-like, in-memory, string\nbuffer that you can <code>.write<\/code> string content to and then turn it into a single string object when\ndone. Rewriting the above code snippet to use this option:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">io<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">buffer<\/span> <span class=\"o\">=<\/span> <span class=\"n\">io<\/span><span class=\"o\">.<\/span><span class=\"n\">StringIO<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">buffer<\/span><span class=\"o\">.<\/span><span class=\"n\">write<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;we have <\/span><span class=\"si\">%r<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">%<\/span> <span class=\"n\">i<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"n\">buffer<\/span><span class=\"o\">.<\/span><span class=\"n\">getvalue<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">text<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Both solutions are better than concatenating strings with <code>+<\/code> operator, but if you&rsquo;re just\nconcatenating two or three strings, it&rsquo;s probably simpler to just use <code>+<\/code> and move on. Premature\noptimisation is the root of all evil.<\/p>\n<h2 id=\"splitting\">Splitting<a class=\"headerlink\" href=\"#splitting\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python strings have the <a href=\"https:\/\/docs.python.org\/3.8\/library\/stdtypes.html#str.split\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.split<\/code><\/a> method that can be used to split strings into list of\ntokens or parts. There&rsquo;s three things to this method to understand:<\/p>\n<p><strong>First<\/strong>, it takes a separator argument, which can be a string of any length.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;a,b,c,d&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;,&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;a,b;c,d&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;;&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;a b c d&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39; &#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;a,,b,,,&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;,&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a,b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c,d&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that adjoining separators will produce empty strings in the returned list.<\/p>\n<p><strong>Second<\/strong>, not passing a value for the separator (or passing <code>None<\/code>) will split the string over\n<em>whitespace<\/em>. Note that this is not the same as splitting with the space character (<code>' '<\/code>). Consider\nthe following examples:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Expression<\/th>\n<th>Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>'a b c'.split()<\/code><\/td>\n<td><code>['a', 'b', 'c']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a    b         c'.split()<\/code><\/td>\n<td><code>['a', 'b', 'c']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a\\tb\\nc'.split()<\/code><\/td>\n<td><code>['a', 'b', 'c']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a b c  '.split()<\/code><\/td>\n<td><code>['a', 'b', 'c', '']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a b c  '.strip().split()<\/code><\/td>\n<td><code>['a', 'b', 'c']<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>If you&rsquo;re familiar with regular expressions, then this splitting over whitespace is similar to\nsplitting over non-overlapping matches of the pattern <code>\\s+<\/code>.<\/p>\n<p><strong>Third<\/strong>, there is a second argument, which is the maximum number of times the string will be cut\nwith the given separator (or whitespace). Thus, if we give <code>1<\/code> in the second argument, the result\nstring will contain <em>at most<\/em> two elements. Of course, not providing any second argument will mean\nthe string will be split at all occurrences of the separator.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Expression<\/th>\n<th>Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>'a,b,c,d'.split(',', 2)<\/code><\/td>\n<td><code>['a', 'b', 'c,d']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a,b,c,d'.split(',', 10)<\/code><\/td>\n<td><code>['a', 'b', 'c', 'd']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'hello'.split(',', 10)<\/code><\/td>\n<td><code>['hello']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a    b         c'.split(maxsplit=1)<\/code><\/td>\n<td><code>['a', 'b         c']<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h3 id=\"the-splitlines-method\">The <code>.splitlines<\/code> Method<a class=\"headerlink\" href=\"#the-splitlines-method\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <a href=\"https:\/\/docs.python.org\/3.8\/library\/stdtypes.html#str.splitlines\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.splitlines<\/code><\/a> method splits the strings into a list of lines. This method is a\nbetter version of just doing <code>.split('\\n')<\/code> since it handles many of the nasty end-of-line\ndifferences. For example, if your string contains <code>'\\r\\n'<\/code> at the end of each line, then doing a\n<code>.split('\\n')<\/code> will leave dangling <code>'\\r'<\/code> characters at end of each line. This is handled well by\nthe <code>.splitlines<\/code> method. The <a href=\"https:\/\/docs.python.org\/3.8\/library\/stdtypes.html#str.splitlines\" rel=\"noopener noreferrer\" target=\"_blank\">official documentation<\/a> has a list of separators\nthis method splits by, which I won&rsquo;t repeat here.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Expression<\/th>\n<th>Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>'a\\nb\\rc\\r\\nd'.splitlines()<\/code><\/td>\n<td><code>['a', 'b', 'c', 'd']<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>'a   b\\rc\\r\\nd'.splitlines()<\/code><\/td>\n<td><code>['a   b', 'c', 'd']<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h2 id=\"substring-check\">Substring Check<a class=\"headerlink\" href=\"#substring-check\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>To check if a string is wholly contained in another string, the <code>in<\/code> operator should be used. Note\nthat this operator is case-sensitive. If case-insensitivity is needed, the easiest option is to just\ncall <code>.casefold<\/code> (which is especially designed for this purpose) on both the strings.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">needle<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;back&#39;<\/span>\n<\/span><span><span class=\"n\">haystack<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Going back and forth all the time.&#39;<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">needle<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">haystack<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would print <code>True<\/code>, since the string <code>'back'<\/code> occurs in <code>haystack<\/code>. Note the intent here, for\nexample, consider the following example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">needle<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;back&#39;<\/span>\n<\/span><span><span class=\"n\">haystack<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Forwards is easier than backwards.&#39;<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">needle<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">haystack<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would again print <code>True<\/code>, but the intent seems to be to look for the <em>word &ldquo;back&rdquo;<\/em>. In that\ncase, we&rsquo;d expect <code>False<\/code> here and <code>True<\/code> in the previous example (since <em>back<\/em> is not a separate\nwork in the second example). Here again, a simple solution is to call <code>.split<\/code> on the <code>haystack<\/code>\nstring before the <code>in<\/code> operator check. The idea is that we&rsquo;d get a list of words out of <code>haystack<\/code>\nand we check if needle occurs in the list.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">needle<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;back&#39;<\/span>\n<\/span><span><span class=\"n\">haystack<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Forwards is easier than backwards.&#39;<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">needle<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">haystack<\/span><span class=\"o\">.<\/span><span class=\"n\">split<\/span><span class=\"p\">())<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This prints out <code>False<\/code>. This isn&rsquo;t anywhere near a foolproof word searching system, but does get\nyou a step ahead.<\/p>\n<h3 id=\"prefix-and-suffix-check\">Prefix and Suffix Check<a class=\"headerlink\" href=\"#prefix-and-suffix-check\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>We have the <code>.startswith<\/code> and <code>.endswith<\/code> methods on strings if we want to check if a string is not\njust <em>in<\/em> another string, but more specifically, if it starts\/ends with it.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;the&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"s1\">&#39;Hello there&#39;<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">False<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">endswith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ere&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Additionally, there&rsquo;s a useful twist to these two functions. Instead of a single string as argument,\nthey can accept a <code>tuple<\/code> of strings where it check if the original strings starts\/ends with <strong>any<\/strong>\nof the strings in the tuple. Check out the following examples:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">((<\/span><span class=\"s1\">&#39;He&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;hello there&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">((<\/span><span class=\"s1\">&#39;garbage from outer space&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;He&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>A less obvious fact here is that the original string <em>may<\/em> be shorter than the string being passed\nto <code>.startswith<\/code>\/<code>.endswith<\/code>. This sounds like a nobrainer, but there&rsquo;s one scenario where it&rsquo;s\nparticularly nice.<\/p>\n<p>Consider a situation where we want to check if the first character of a string is, say, <code>'A'<\/code>. One\noption to do this is <code>haystack[0] == 'A'<\/code>. But this runs the risk that if the <code>haystack = ''<\/code>, then\n<code>haystack[0]<\/code> will raise an <code>IndexError<\/code>, where we just wanted <code>False<\/code>. If we did\n<code>haystack.startswith('A')<\/code>, we&rsquo;d get <code>False<\/code> if haystack is empty.<\/p>\n<h3 id=\"regular-expressions-check\">Regular Expressions Check<a class=\"headerlink\" href=\"#regular-expressions-check\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Regular expressions are a much larger topic than can be fit under a third level header (may be a\nfuture article). So we&rsquo;ll just cover the substring checking part using regular expressions (in\nobviously limited scope).<\/p>\n<p>All regex (regular expression) operations in Python start from the <code>re<\/code> module. There&rsquo;s no special\nsyntax for defining regex patterns like there is in JavaScript. Patterns are instead written as\nstrings and the <code>re<\/code> module knows to interpret them as regex patterns.<\/p>\n<p>For our purpose of substring checking, the <code>re<\/code> module provides the <a href=\"https:\/\/docs.python.org\/3\/library\/re.html#re.search\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.search<\/code><\/a> function\nthat takes a regex pattern, the haystack string and optionally, any flags for the pattern.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">re<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;the&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;he&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">flags<\/span><span class=\"o\">=<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">IGNORECASE<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;hola&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would produce the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>&lt;re.Match object; span=(6, 9), match=&#39;the&#39;&gt;\n<\/span><span>&lt;re.Match object; span=(7, 9), match=&#39;he&#39;&gt;\n<\/span><span>&lt;re.Match object; span=(0, 2), match=&#39;He&#39;&gt;\n<\/span><span>None\n<\/span><\/code><\/pre><\/div>\n\n<p>A minor point to note here is that the return value is not of <em>boolean<\/em> type. We get an\n<a href=\"https:\/\/docs.python.org\/3\/library\/re.html#match-objects\" rel=\"noopener noreferrer\" target=\"_blank\"><code>re.Match<\/code><\/a> object if there is a <em>successful match<\/em>, else we get <code>None<\/code>. This is usually\na minor concern, because the match objects are <em>truth-y<\/em> and <code>None<\/code> is <em>false-y<\/em>. So, we can pretend\nit returns a <em>boolean<\/em> value if we need to.<\/p>\n<p>When using the <code>re.search<\/code> function this way, the <a href=\"https:\/\/docs.python.org\/3\/library\/re.html#re.escape\" rel=\"noopener noreferrer\" target=\"_blank\"><code>re.escape<\/code><\/a> function might also come\nin handy.  This function will escape any special characters in the give string. Special here means\nhaving special behaviour in the context of being a regex pattern.<\/p>\n<p>For example, if the needle is user input and we want to search our haystack such that the needle is\nat the end of an English sentence, we&rsquo;d do something like:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"n\">needle<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;[.!?:]&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">haystack<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But this runs the risk of <code>needle<\/code> having regex special characters like <code>.*<\/code> and that would match\neverything, which is <em>probably<\/em> not what we want. In this case, it&rsquo;s best to wrap the <code>needle<\/code> in\n<code>re.escape<\/code> and <em>then<\/em> concatenate the pattern with end-of-sentence markers.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">search<\/span><span class=\"p\">(<\/span><span class=\"n\">re<\/span><span class=\"o\">.<\/span><span class=\"n\">escape<\/span><span class=\"p\">(<\/span><span class=\"n\">needle<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;[.!?:]&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">haystack<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>As always, please think twice before using regular expressions to solve a problem, and if you do, if\nthe pattern is longer than five or six characters, please make use of <code>re.VERBOSE<\/code> and add comments\nto your pattern. You&rsquo;ll thank yourself later.<\/p>\n<h2 id=\"learning-about-the-contents\">Learning About the Contents<a class=\"headerlink\" href=\"#learning-about-the-contents\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python&rsquo;s strings have some nice methods to quickly check some facts about it&rsquo;s contents. Here&rsquo;s a\nrundown of such methods:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Returns <code>True<\/code> if<\/th>\n<th>On empty string<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isalnum\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isalnum<\/code><\/a><\/td>\n<td>all characters are alphanumeric<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isalpha\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isalpha<\/code><\/a><\/td>\n<td>all characters are alphabetic<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isascii\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isascii<\/code><\/a><\/td>\n<td>all characters are within ASCII range<\/td>\n<td><code>True<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isdecimal\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isdecimal<\/code><\/a><\/td>\n<td>all characters are decimal characters<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isdigit\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isdigit<\/code><\/a><\/td>\n<td>all characters are digits<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isidentifier\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isidentifier<\/code><\/a><\/td>\n<td>string can be a valid Python identifier<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.islower\" rel=\"noopener noreferrer\" target=\"_blank\"><code>islower<\/code><\/a><\/td>\n<td>has at least one <em>cased<\/em> character and they are all in lower case<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isnumeric\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isnumeric<\/code><\/a><\/td>\n<td>all characters are numeric characters<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isprintable\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isprintable<\/code><\/a><\/td>\n<td>all characters are printable<\/td>\n<td><code>True<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isspace\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isspace<\/code><\/a><\/td>\n<td>all characters are whitespace<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.istitle\" rel=\"noopener noreferrer\" target=\"_blank\"><code>istitle<\/code><\/a><\/td>\n<td>string is title-cased, <em>i.e.,<\/em> all words start with an upper case character<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.isupper\" rel=\"noopener noreferrer\" target=\"_blank\"><code>isupper<\/code><\/a><\/td>\n<td>has at least one <em>cased<\/em> character and they are all in upper case<\/td>\n<td><code>False<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Please use the links to official documentation in the above table to learn more about them. I won&rsquo;t\nbe repeating those details here.<\/p>\n<h3 id=\"numeric-checks\">Numeric Checks<a class=\"headerlink\" href=\"#numeric-checks\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>You might&rsquo;ve noticed that we have three different methods that all sound awfully similar to each\nother: <code>isdecimal<\/code>, <code>isdigit<\/code> and <code>isnumeric<\/code>. The official documentation regarding the difference\nbetween these three wasn&rsquo;t very helpful for me so I&rsquo;ll try explain it here.<\/p>\n<p><strong>Firstly<\/strong>, <code>isdecimal<\/code> will consider any character that can be used to build a number in the\n10-decimal system as <code>True<\/code>. That means it will give <code>True<\/code> for the <code>0<\/code> through <code>9<\/code> digits.\nAdditionally, it will also give <code>True<\/code> for characters that can be used for similar purpose in <em>other\nlanguages<\/em>. For example, the numbers from Unicode range 3174 to 3183 are of a south Indian language\ncalled Telugu (my mother tongue). The <code>isdecimal<\/code> method returns <code>True<\/code> for these characters as\nwell. However, note that it is not true for Roman numerals since they can&rsquo;t <em>technically<\/em> be used to\nconstruct 10-decimal numbers.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"c1\"># Arabic Numbers<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"nb\">chr<\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">48<\/span><span class=\"p\">,<\/span> <span class=\"mi\">58<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">&#39;0123456789&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">_<\/span><span class=\"o\">.<\/span><span class=\"n\">isdecimal<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"c1\"># Telugu Numbers<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"s1\">&#39;&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"nb\">chr<\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">3174<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3184<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">&#39;\u0c66\u0c67\u0c68\u0c69\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">_<\/span><span class=\"o\">.<\/span><span class=\"n\">isdecimal<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p><strong>Secondly<\/strong>, <code>isdigit<\/code> gives <code>True<\/code> for any character that <em>looks like<\/em> a <strong>digit<\/strong>, of any\nlanguage.  So, this includes any character that is <code>True<\/code>-ed by <code>isdecimal<\/code>. Additionally, this\nincludes characters like <code>\u00b9<\/code>, <code>\u00b2<\/code>, <code>\u00b3<\/code>, <em>etc.,<\/em> as well as <code>\u2460<\/code>, <code>\u2461<\/code>, <code>\u2462<\/code>. Notice that fraction\ncharacters are not considered as <em>digits<\/em>.<\/p>\n<p><strong>Thirdly<\/strong>, <code>isnumeric<\/code> gives <code>True<\/code> for any character that is <em>numeric<\/em> in nature. So, this\nincludes any character that is <code>True<\/code>-ed by <code>isdigit<\/code>. Additionally, this will give <code>True<\/code> for\nfraction characters such as <code>\u00bc<\/code>, <code>\u00bd<\/code>, <code>\u00be<\/code> <em>etc.<\/em>, as well as Roman numbers such as <code>\u2160<\/code>, <code>\u2161<\/code>, <code>\u2162<\/code>,\n<code>\u2163<\/code>, even <code>\u2169<\/code>, <code>\u216c<\/code>, <code>\u216d<\/code>, <code>\u216e<\/code>, <code>\u216f<\/code> (these are not ordinary alphabets, they are Unicode Roman number\ncharacters) <em>etc.<\/em><\/p>\n<p>This follows a neat fact regarding the character sets <code>True<\/code>-ed by the three methods: <code>isdecimal<\/code>\n&sub; <code>isdigit<\/code> &sub; <code>isnumeric<\/code>.<\/p>\n<h2 id=\"transformations\">Transformations<a class=\"headerlink\" href=\"#transformations\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This section is about methods that return a new string, which is the result of some transformation\napplied to the original string. Since strings in Python are immutable, transformations always return\na new string object. The original string is, always, obviously, left untouched.<\/p>\n<p>Here&rsquo;s a few commonly used transformation methods (this list is intentionally non-exhaustive):<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Transformation<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.rstrip\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.strip<\/code><\/a><\/td>\n<td>Strips <em>whitespace<\/em> (or characters from the string in first argument) at the start and end of the string.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.lstrip\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.lstrip<\/code><\/a><\/td>\n<td>Strips <em>whitespace<\/em> (or characters from the string in first argument) only at the start of the string.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.rstrip\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.rstrip<\/code><\/a><\/td>\n<td>Strips <em>whitespace<\/em> (or characters from the string in first argument) only at the end of the string.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.lower\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.lower<\/code><\/a><\/td>\n<td>All cased characters are converted to lower case, unless they are already in lower case.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.upper\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.upper<\/code><\/a><\/td>\n<td>All cased characters are converted to upper case, unless they are already in upper case.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.capitalize\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.capitalize<\/code><\/a><\/td>\n<td>The first letter is upper-cased and the rest are lower-cased.<\/td>\n<\/tr>\n<tr>\n<td><a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#str.title\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.title<\/code><\/a><\/td>\n<td>The first letter in each word in the string is upper-cased, <em>and<\/em> all others are converted to lower-cased.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Please use the links to official documentation in the above table to learn more about them. I won&rsquo;t\nbe repeating those details here. The official documentation refers to more methods on strings that I\nsuggest skimming over. I happened to reinvent the wheel with transforming strings because I didn&rsquo;t\nknow Python already provided a method for what I needed.<\/p>\n<h2 id=\"string-formatting\">String Formatting<a class=\"headerlink\" href=\"#string-formatting\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>String formatting in Python comes majorly in two flavors. <strong>First<\/strong> is the (now old) <code>printf<\/code>-style\nformatting that uses typed control characters prefixed with <code>%<\/code>, similar to the <code>printf<\/code> (more like\n<code>sprintf<\/code>) function in C. <strong>Second<\/strong> is the new <code>format<\/code> builtin function and the accompanying\n<code>str.format<\/code> method that is more suited to Python&rsquo;s dynamic typing, and arguably, is much easier to\nuse.<\/p>\n<p>Python&rsquo;s formatting capabilities are quite vast and powerful, warranting a whole separate article. I\nintend to do that some time in the coming weeks. Until then, the official documentation on\n<a href=\"https:\/\/docs.python.org\/3\/library\/stdtypes.html#printf-style-string-formatting\" rel=\"noopener noreferrer\" target=\"_blank\"><code>printf<\/code>-style\nformatting<\/a> and the\n<a href=\"https:\/\/docs.python.org\/3\/library\/functions.html#format\" rel=\"noopener noreferrer\" target=\"_blank\">format function<\/a> should serve you well.<\/p>\n<h2 id=\"docstrings\">Docstrings<a class=\"headerlink\" href=\"#docstrings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Docstrings are strings that serve as documentation for Python&rsquo;s modules, functions and classes.\nThere&rsquo;s nothing special in the syntax of these strings per se, but their uniqueness is more due to\nwhere they are positioned in a Python program.<\/p>\n<p>Consider the following function with a docstring on line 2<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><\/pre><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">triple<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"sd\">&quot;&quot;&quot;Triples the given number and returns the result.&quot;&quot;&quot;<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">n<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">3<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">triple<\/span><span class=\"p\">(<\/span><span class=\"mi\">4<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The string defined on line 2 in this program is not assigned to any variable. On the face of it, it\nappears pointless to create a string and just discard it. However, in this case, the fact that this\nstring literal is the first expression in the function definition, makes it a docstring. What that\nmeans is that the contents of this string are understood to be a human readable help text regarding\nthe usage of this function.<\/p>\n<p>It also doesn&rsquo;t have to be a string defined with <code>\"\"\"<\/code>. It may be using single quotes, double quotes\nor any other crazy variation we saw above. But, don&rsquo;t do that. It&rsquo;s usually a best practice to write\ndocstrings with <code>\"\"\"<\/code>, and I strongly suggest (and even beg) that you stick to using <code>\"\"\"<\/code> for\ndocstrings. Please.<\/p>\n<p>It&rsquo;s also not <em>entirely<\/em> true that this string is not assigned to a variable. Docstrings are saved\nto the <code>.__doc__<\/code> attribute of the function (or whatever object) they are documenting. In our\nexample above, we can get the docstring from <code>triple.__doc__<\/code>. But it&rsquo;s usually more practical to\ncall the <code>help<\/code> function to read the docstring.<\/p>\n<p>For classes, the docstring should be the first expression inside the class body, positioned\nsimilarly to that of a function. For modules, the docstring should be the first expression in the\nmodule (even before any imports).<\/p>\n<p>A minor note regarding docstrings regarding the formatting of their content is to use [ReST][rst]\n(also called <strong>reStructuredText<\/strong>). It is not strictly required, but I suggest you do so, in the\nevent that you choose to generate HTML help pages from your docstrings, you&rsquo;ll be glad you wrote\nthem in ReST.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>It&rsquo;s hard to imagine a Python program that doesn&rsquo;t have something to do with strings. As such, we\nhave been provided with a lot of utilities within the standard distribution for working with\nstrings. Even in an article of this size, I couldn&rsquo;t be exhaustive. As always, Python&rsquo;s official\ndocumentation is unreal good. It pays to occasionally open a random page and skim over it.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"reference"}},{"@attributes":{"term":"tutorial"}}]},{"title":"Automating the Vim workplace","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/automating-the-vim-workplace\/","rel":"alternate"}},"published":"2020-01-12T00:00:00+05:30","updated":"2020-01-12T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-01-12:\/posts\/automating-the-vim-workplace\/","summary":"<p>I majorly use two tools for my coding workflow and one of them is GVim (on Windows). It&rsquo;s my primary\nchoice for editing text for ten years now and in that time, I&rsquo;ve picked up several habits and tricks\nthat made me very productive.<\/p>\n<p>This article is part \u2026<\/p>","content":"<p>I majorly use two tools for my coding workflow and one of them is GVim (on Windows). It&rsquo;s my primary\nchoice for editing text for ten years now and in that time, I&rsquo;ve picked up several habits and tricks\nthat made me very productive.<\/p>\n<p>This article is part of a series:<\/p>\n<ol>\n<li>Chapter \u2160 (this article).<\/li>\n<li><a href=\"..\/automating-the-vim-workplace-2\/\">Chapter \u2161<\/a>.<\/li>\n<li><a href=\"..\/automating-the-vim-workplace-3\/\">Chapter \u2162<\/a>.<\/li>\n<\/ol>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#motivation\">Motivation<\/a><\/li>\n<li><a href=\"#switching-to-normal-mode\">Switching to Normal Mode<\/a><\/li>\n<li><a href=\"#start-gvim-maximized-in-windows\">Start GVim Maximized, in Windows<\/a><\/li>\n<li><a href=\"#save-all-buffers\">Save All Buffers<\/a><\/li>\n<li><a href=\"#copy-to-system-clipboard\">Copy to System Clipboard<\/a><\/li>\n<li><a href=\"#ensure-directory-exists-before-saving\">Ensure Directory Exists, Before Saving<\/a><\/li>\n<li><a href=\"#switching-to-alternate-buffer\">Switching to Alternate Buffer<\/a><\/li>\n<li><a href=\"#run-git-commands-in-terminal\">Run Git Commands in :terminal<\/a><\/li>\n<li><a href=\"#non-undo-able-insert-mode-commands\">Non-undo-able Insert Mode Commands<\/a><\/li>\n<li><a href=\"#quickly-open-ftplugin\">Quickly Open ftplugin<\/a><\/li>\n<li><a href=\"#sorting-over-motion\">Sorting over Motion<\/a><\/li>\n<li><a href=\"#reversing-over-motion\">Reversing over Motion<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"motivation\">Motivation<a class=\"headerlink\" href=\"#motivation\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Most of my text editing involves working with Python, Markdown, and JavaScript source files. When\nI&rsquo;m spending as much time as I am with Vim, it ceases to be just a tool in my mind. It becomes a\nstate of mind where I&rsquo;m able to translate my thoughts into actions much faster than it\/I can do with\nsomething else (besides being an excuse to be fancy with words). It becomes my workplace.<\/p>\n<p>Just like organizing one&rsquo;s desk or toolbox for maximum efficiency, we can mold Vim to help us\nachieve something similar with it. I try to notice things that I do often, that take more than 3-4\nseconds of thought and then a few more seconds of hitting hotkeys or commands. These are the ones I\ntry to create a command or a mapping. In my world, this is borderline automation.<\/p>\n<p>What I&rsquo;m sharing here is stuff I created\/scavenged through years of identifying patterns <em>very\nspecific<\/em> to my work style. My goal is not to share nice tidbits of Vim configuration. It is to\nencourage you to identify your work style and work towards optimising it, before you go find a\nplugin and <em>learn<\/em> the plugin&rsquo;s work style. As such, I don&rsquo;t expect you to resonate with the tips I\nshared here. Your own style of working deserves the first chance, let Vim learn it.<\/p>\n<p class=\"note\">Please note that all that I share below is what I&rsquo;m using with Vim (more specifically, GVim on\nWindows). I don&rsquo;t use Neovim (yet) and I can&rsquo;t speak for any of the below for Neovim.<\/p>\n<h2 id=\"switching-to-normal-mode\">Switching to Normal Mode<a class=\"headerlink\" href=\"#switching-to-normal-mode\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Probably the action that is done most often is switching to normal &amp; insert modes. Switching to\ninsert mode is usually with several different keys (<kbd>i<\/kbd>, <kbd>a<\/kbd>, <kbd>o<\/kbd> etc.),\nbut for switching to normal mode, we usually use one single key. My preference for this is\n<kbd>&lt;C-l&gt;<\/kbd>, since <kbd>l<\/kbd> is on the home row and the help pages already sort-of\nindicate that hitting it would go to the normal mode (if <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'insertmode'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>'insertmode'<\/code><\/a> is set, but\nwell, it&rsquo;s unused otherwise, See <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/insert.html#i_CTRL-L\" rel=\"noopener noreferrer\" target=\"_blank\"><code>:h i_CTRL-l<\/code><\/a>).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">l<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>Esc<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">This is a topic that often brings up an uncontrollable urge to be vocal about one&rsquo;s own choice of\nkeys to go to normal mode. I&rsquo;ve used several of them over the years, <kbd>jj<\/kbd>,\n<kbd>&lt;CapsLock&gt;<\/kbd> as <kbd>&lt;ESC&gt;<\/kbd>, <kbd>&lt;C-[&gt;<\/kbd>,\n<kbd>&lt;C-c&gt;<\/kbd>, mapping <kbd>&lt;C-k&gt;<\/kbd>, <em>xcape<\/em> in the background, etc. All of them\nfelt haphazard, and <kbd>&lt;C-l&gt;<\/kbd> worked the best for me. As I said, this article is about\nwhat worked best to <em>my<\/em> workflow. Go discover your own.<\/p>\n<p>Of course, now we need a quick way to open our <code>vimrc<\/code> file so we can add this mapping and then get\nback to whatever we are doing. Well,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> cv :<span class=\"k\">e<\/span> $MYVIMRC<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>cv<\/code> is a mnemonic for <em>change vimrc<\/em>.<\/p>\n<blockquote>\n<p>This mapping was originally defined as <code>:e $USERPROFILE\/vimfiles\/vimrc&lt;CR&gt;<\/code>. Thanks to the helpful\ncommunity at <a href=\"https:\/\/www.reddit.com\/r\/vim\/comments\/enlz8x\/automating_the_vim_workplace\/fe396x0\" rel=\"noopener noreferrer\" target=\"_blank\">r\/vim<\/a> and a comment here, I realized <code>$MYVIMRC<\/code> is a better fit here. Thank you\nfolks!<\/p>\n<\/blockquote>\n<p>This is what I&rsquo;m talking about when I say identify things that you often do. Even if you don&rsquo;t sit\ndown to automate it right away, put it on a sticky near your desk. Spend a few minutes thinking\nabout it. A few seconds in a time of intense focus is far more dear than a few minutes in slacking.<\/p>\n<p>Note that this mapping is not without it&rsquo;s quirks. It interferes with the line completion mapping,\n<kbd>&lt;C-x&gt;&lt;C-l&gt;<\/kbd>. It&rsquo;ll still work, but right after triggering\n<kbd>&lt;C-x&gt;&lt;C-l&gt;<\/kbd>, if you hit <kbd>&lt;C-l&gt;<\/kbd>, you won&rsquo;t go to normal mode.\nYou&rsquo;ll merely go to the next selected item in the completion popup. Other than this,\n<kbd>&lt;C-l&gt;<\/kbd> for going to normal mode works quite well.<\/p>\n<p>Now that the mapping is setup, I can hit <kbd>&lt;C-l&gt;<\/kbd> in insert mode to go to normal mode.\nThen I noticed something else in the way I <em>tried<\/em> to use it, subconsciously. I started hitting\n<kbd>&lt;C-l&gt;<\/kbd> in visual mode, operator pending mode etc. to go into normal mode. I realized\nI was using <kbd>&lt;C-l&gt;<\/kbd> essentially as a replacement of <kbd>&lt;ESC&gt;<\/kbd>. But of\ncourse it failed because I only created a mapping for insert mode.<\/p>\n<p>After a few iterations and shower thoughts, this is what I currently use:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Easier way to go to normal mode. Also, alternative to &lt;ESC&gt;.<\/span>\n<\/span><span><span class=\"nb\">noremap<\/span><span class=\"p\">!<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">l<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>ESC<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">vnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">l<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>ESC<span class=\"p\">&gt;<\/span>\n<\/span><span>onoremap <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">l<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>ESC<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I also wanted this from the command line, but I&rsquo;m still trying to get it to work. I currently have\nthe following but it&rsquo;s not very robust. Every time I hit <kbd>&lt;C-l&gt;<\/kbd> in the normal mode,\nthe cursor moves ahead by two characters. Still working on getting it to work well.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; &lt;ESC&gt; doesn&#39;t work and even this moves the cursor by two characters.<\/span>\n<\/span><span>cnoremap <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">l<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">c<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>It&rsquo;s a never ending process of learning and experimenting.<\/p>\n<h2 id=\"start-gvim-maximized-in-windows\">Start GVim Maximized, in Windows<a class=\"headerlink\" href=\"#start-gvim-maximized-in-windows\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>As another example, I wanted GVim to start maximized when I open it. On way to do this was to check\nthe Maximized checkbox in the GVim shortcut&rsquo;s properties. But that won&rsquo;t work when I start GVim from\na command line. The solution that worked even better:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Maximize gVim window.<\/span>\n<\/span><span><span class=\"k\">let<\/span> s:iswin <span class=\"p\">=<\/span> has<span class=\"p\">(<\/span><span class=\"s1\">&#39;win32&#39;<\/span><span class=\"p\">)<\/span> <span class=\"p\">||<\/span> has<span class=\"p\">(<\/span><span class=\"s1\">&#39;win64&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">if<\/span> exists<span class=\"p\">(<\/span><span class=\"s1\">&#39;:simalt&#39;<\/span><span class=\"p\">)<\/span> <span class=\"p\">&gt;<\/span> <span class=\"m\">0<\/span> &amp;&amp; s:iswin\n<\/span><span>  autocmd <span class=\"nb\">GUIEnter<\/span> * <span class=\"k\">simalt<\/span> <span class=\"p\">~<\/span><span class=\"k\">x<\/span>\n<\/span><span><span class=\"k\">endif<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"save-all-buffers\">Save All Buffers<a class=\"headerlink\" href=\"#save-all-buffers\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I often use the <code>:wa<\/code> command to save all my open buffers. But it has the nasty habit of throwing an\nerror when it&rsquo;s not able to save all buffers. This is annoying because I often have scratch buffers\nin vertical splits where I dump random pieces of copied text and thoughts. So, I prepared the\nfollowing hotkey that will execute the <code>:wa<\/code> command and, if that error comes up, shows a message\ninstead.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">m<\/span><span class=\"p\">&gt;<\/span> :<span class=\"k\">try<\/span>\\<span class=\"p\">|<\/span><span class=\"k\">wa<\/span>\\<span class=\"p\">|<\/span><span class=\"k\">catch<\/span> <span class=\"sr\">\/\\&lt;E141\\&gt;\/<\/span>\\<span class=\"p\">|<\/span><span class=\"k\">echomsg<\/span> <span class=\"s1\">&#39;Not all files saved!&#39;<\/span>\\<span class=\"p\">|<\/span><span class=\"k\">endtry<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This doesn&rsquo;t look like an ideal solution, but it hasn&rsquo;t failed me yet. The idea is not to create an\nperfect solution, but just one that works well with you.<\/p>\n<p class=\"note\">If you&rsquo;re using the above mapping, note that mapping to <kbd>&lt;C-m&gt;<\/kbd> is almost the same as\nmapping to the <kbd>&lt;Return&gt;<\/kbd> key on your keyboard. So hitting the return key in normal\nmode will also trigger the above mapping. Just something to keep in mind.<\/p>\n<h2 id=\"copy-to-system-clipboard\">Copy to System Clipboard<a class=\"headerlink\" href=\"#copy-to-system-clipboard\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I often have to copy stuff to system clipboard to paste into chat channels and emails. The standard\nway to do this would be something like <kbd>&ldquo;+yap<\/kbd> in normal mode, or <kbd>&ldquo;+y<\/kbd> in visual\nmode. This is annoying, not because it&rsquo;s three keys, but more because they are hard to type in order\nand they are (almost) all with the same hand. So I solved it with the following keys:<\/p>\n<div class=\"hl\"><pre class=content><code><span>xnoremap <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">c<\/span><span class=\"p\">&gt;<\/span> <span class=\"c\">&quot;+y<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"k\">cp<\/span> <span class=\"c\">&quot;+y<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> cpp <span class=\"c\">&quot;+yy<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>With this, <kbd>&lt;C-c&gt;<\/kbd> in visual mode copies selection to clipboard and <kbd>cp<\/kbd> can\nbe used with text objects. Much easier to hit.<\/p>\n<h2 id=\"ensure-directory-exists-before-saving\">Ensure Directory Exists, Before Saving<a class=\"headerlink\" href=\"#ensure-directory-exists-before-saving\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I often edit new files like <code>:e css\/styles.css<\/code>, without realizing that I have to create the <code>css<\/code>\nfolder before saving this. But that&rsquo;s not productive, my tool should do that automatically.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><\/pre><pre class=content><code><span><span class=\"c\">&quot; Create file&#39;s directory before saving, if it doesn&#39;t exist.<\/span>\n<\/span><span><span class=\"c\">&quot; Original: https:\/\/stackoverflow.com\/a\/4294176\/151048<\/span>\n<\/span><span>augroup BWCCreateDir\n<\/span><span>  autocmd<span class=\"p\">!<\/span>\n<\/span><span>  autocmd <span class=\"nb\">BufWritePre<\/span> * :<span class=\"k\">call<\/span> s:MkNonExDir<span class=\"p\">(<\/span>expand<span class=\"p\">(<\/span><span class=\"s1\">&#39;&lt;afile&gt;&#39;<\/span><span class=\"p\">),<\/span> <span class=\"p\">+<\/span>expand<span class=\"p\">(<\/span><span class=\"s1\">&#39;&lt;abuf&gt;&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span>augroup END\n<\/span><span><span class=\"k\">fun<\/span><span class=\"p\">!<\/span> s:MkNonExDir<span class=\"p\">(<\/span><span class=\"k\">file<\/span><span class=\"p\">,<\/span> <span class=\"k\">buf<\/span><span class=\"p\">)<\/span>\n<\/span><span>  <span class=\"k\">if<\/span> empty<span class=\"p\">(<\/span>getbufvar<span class=\"p\">(<\/span><span class=\"k\">a<\/span>:<span class=\"k\">buf<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;&amp;buftype&#39;<\/span><span class=\"p\">))<\/span> &amp;&amp; <span class=\"k\">a<\/span>:<span class=\"k\">file<\/span> <span class=\"p\">!~<\/span># <span class=\"s1\">&#39;\\v^\\w+\\:\\\/&#39;<\/span>\n<\/span><span>    <span class=\"k\">call<\/span> mkdir<span class=\"p\">(<\/span>fnamemodify<span class=\"p\">(<\/span><span class=\"k\">a<\/span>:<span class=\"k\">file<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;:h&#39;<\/span><span class=\"p\">),<\/span> <span class=\"s1\">&#39;p&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>  <span class=\"k\">endif<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s see what&rsquo;s going on here. Firstly, we define an <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/autocmd.html#autocmd.txt\" rel=\"noopener noreferrer\" target=\"_blank\"><code>autocmd<\/code><\/a> for the\n<a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/autocmd.html#BufWritePre\" rel=\"noopener noreferrer\" target=\"_blank\"><code>BufWritePre<\/code><\/a> event, which is fired just before a file is saved, to call the function\n<code>s:MkNonExDir<\/code>. In this function, we check for the buffer being a normal buffer (see <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/options.html#'buftype'\" rel=\"noopener noreferrer\" target=\"_blank\"><code>:h\nbuftype<\/code><\/a>) and if it is, create it&rsquo;s parent directory.<\/p>\n<p>Simple, non-intrusive, and effective.<\/p>\n<h2 id=\"switching-to-alternate-buffer\">Switching to Alternate Buffer<a class=\"headerlink\" href=\"#switching-to-alternate-buffer\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The default key-binding for <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/editing.html#CTRL-6\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>&lt;C-^&gt;<\/kbd><\/a> (or <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/editing.html#CTRL-6\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>&lt;C-6&gt;<\/kbd><\/a>)\nlets us quickly switch back-and-forth between two buffers. This is extremely handy and is likely one\nof my most used functionality for switching buffers within Vim.<\/p>\n<p>There&rsquo;s some annoying quirks to this mapping though. For example, if there&rsquo;s files in your buffer\nlist, but no <em>alternate<\/em> buffer, we&rsquo;ll get an error saying &ldquo;No alternate buffer&rdquo;. Which is not\nhelpful. So a few years ago I saw a mapping to go to the next buffer if there&rsquo;s no alternate buffer.\nIt worked to an extent, but there&rsquo;s more.<\/p>\n<p>When I delete a buffer with <code>:bd<\/code>, I get taken to a different buffer. Now if I hit\n<kbd>&lt;C-6&gt;<\/kbd> again, the buffer I just deleted is loaded again and I&rsquo;m back in it. This may\nbe what one usually wants, but for me, I want to be taken to the next buffer that&rsquo;s still <em>loaded<\/em>,\nnot deleted ones.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; My remapping of &lt;C-^&gt;. If there is no alternate file, and there&#39;s no count given, then switch<\/span>\n<\/span><span><span class=\"c\">&quot; to next file. We use `bufloaded` to check for alternate buffer presence. This will ignore<\/span>\n<\/span><span><span class=\"c\">&quot; deleted buffers, as intended. To get default behaviour, use `bufexists` in it&#39;s place.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">n<\/span><span class=\"p\">&gt;<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span>exe <span class=\"k\">v<\/span>:count ? <span class=\"k\">v<\/span>:count . <span class=\"s1\">&#39;b&#39;<\/span> : <span class=\"s1\">&#39;b&#39;<\/span> . <span class=\"p\">(<\/span>bufloaded<span class=\"p\">(<\/span><span class=\"m\">0<\/span><span class=\"p\">)<\/span> ? <span class=\"s1\">&#39;#&#39;<\/span> : <span class=\"s1\">&#39;n&#39;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is the mapping I use for switching between alternate buffers. I use <kbd>&lt;C-n&gt;<\/kbd> as\nit&rsquo;s easier to hit and there&rsquo;s a simpler key for it&rsquo;s default functionality anyway (<kbd>j<\/kbd>).<\/p>\n<p>Additionally if you&rsquo;re using the <a href=\"https:\/\/github.com\/tpope\/vim-eunuch\/\" rel=\"noopener noreferrer\" target=\"_blank\">eunuch plugin<\/a>, this\nmapping will not navigate to a buffer that&rsquo;s been <code>Delete<\/code>-ed.<\/p>\n<h2 id=\"run-git-commands-in-terminal\">Run Git Commands in <code>:terminal<\/code><a class=\"headerlink\" href=\"#run-git-commands-in-terminal\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Running git commands is another thing I often do, while working in Vim. Most of the time, it just a\n<code>status<\/code> or <code>diff<\/code>, so I needed something quicker than switching to a terminal and running the\ncommand.<\/p>\n<p>I initially used <a href=\"https:\/\/github.com\/tpope\/vim-fugitive\" rel=\"noopener noreferrer\" target=\"_blank\">fugitive<\/a>, but it felt slow on Windows (very likely because of the required\nanti-virus). It works fine when I&rsquo;m on Linux, but on Windows, it&rsquo;s not productive for me. Besides,\nit does a lot of things I don&rsquo;t usually need. The following is the mapping that serves <em>most<\/em> of\nwhat I need from within Vim.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span> :ter git <span class=\"p\">--<\/span>no<span class=\"p\">-<\/span>pager<span class=\"p\">&lt;<\/span>Space<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>So, what does this do? Well, I hit <kbd>,g<\/kbd> (because <kbd>,<\/kbd> is my\n<a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/map.html#mapleader\" rel=\"noopener noreferrer\" target=\"_blank\"><code>mapleader<\/code><\/a>) and the cursor is placed in the command line with the following\npre-filled:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">:<\/span>ter git <span class=\"p\">--<\/span>no<span class=\"p\">-<\/span>pager\n<\/span><\/code><\/pre><\/div>\n\n<p>Then I just hit <kbd>st&lt;Enter&gt;<\/kbd>, which will open a new <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/term.html\" rel=\"noopener noreferrer\" target=\"_blank\">terminal<\/a> within Vim which runs\n<code>git st<\/code> command asynchronously (which is an alias to <code>git status<\/code>).<\/p>\n<p>After seeing the output I noticed that I immediately issued another <kbd>,gdiff&lt;Enter&gt;<\/kbd>,\nwhich opens up another terminal split to run the <code>git diff<\/code> command. Such multiple splits quickly\ngot annoying again. Yeah, I&rsquo;m easily annoyed. I need this mapping to <em>not<\/em> open a new split if I&rsquo;m\nalready in a <code>git<\/code> output terminal window. Here&rsquo;s what I&rsquo;m using currently:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span>Leader<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span> :ter <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">r<\/span><span class=\"p\">&gt;=<\/span>&amp;<span class=\"nb\">buftype<\/span> <span class=\"p\">==<\/span> <span class=\"s1\">&#39;terminal&#39;<\/span>\n<\/span><span>            \\ &amp;&amp; job_info<span class=\"p\">(<\/span>term_getjob<span class=\"p\">(<\/span><span class=\"s1\">&#39;%&#39;<\/span><span class=\"p\">))<\/span>.cmd[<span class=\"m\">0<\/span>] <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;git&#39;<\/span> ? <span class=\"s1\">&#39;++curwin &#39;<\/span> : <span class=\"s1\">&#39;&#39;<\/span>\n<\/span><span>            \\ <span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>git <span class=\"p\">--<\/span>no<span class=\"p\">-<\/span>pager<span class=\"p\">&lt;<\/span>Space<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We check if the current buffer is a terminal and if the command is <code>git<\/code>, if yes, we tell <code>:ter<\/code> to\nopen the terminal in the current window instead of opening up a new split.<\/p>\n<h2 id=\"non-undo-able-insert-mode-commands\">Non-undo-able Insert Mode Commands<a class=\"headerlink\" href=\"#non-undo-able-insert-mode-commands\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In insert mode, <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/insert.html#i_CTRL-U\" rel=\"noopener noreferrer\" target=\"_blank\"><kbd>&lt;C-u&gt;<\/kbd><\/a> deletes everything from start of current line to\ncursor position (this is not <em>exactly<\/em> true, read <code>:h i_CTRL-U<\/code> for the exact behaviour, I won&rsquo;t\nrepeat it here). This is quite convenient and I use it a lot more than I like to admit. Often, when\nI start a statement in a new line, I have second thoughts middle of the line and I quickly hit\n<kbd>&lt;C-u&gt;<\/kbd> and start typing in the idea from my second thought. But then of course, I\nrealize that what I was doing originally was the right way. Now if I try to undo what&rsquo;s done by\n<kbd>&lt;C-u&gt;<\/kbd>, I can&rsquo;t.  Since it&rsquo;s all treated as one insert operation, it&rsquo;s all one undo\nstep.<\/p>\n<p>This is why I got this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; CTRL-U in insert mode deletes a lot. Put an undo-point before it.<\/span>\n<\/span><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">g<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">u<\/span><span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I don&rsquo;t recall the source of this but I found this after a bit of searching online for a solution\nand it works! Whoever came up with this, thank you!<\/p>\n<blockquote>\n<p>Thanks to this <a href=\"https:\/\/www.reddit.com\/r\/vim\/comments\/enlz8x\/automating_the_vim_workplace\/fe3973i\" rel=\"noopener noreferrer\" target=\"_blank\">kind person&rsquo;s\nhint<\/a>, I was\nable to find the source of this. It&rsquo;s actually in the <code>defaults.vim<\/code> file that is shipped with\nVim.<\/p>\n<\/blockquote>\n<h2 id=\"quickly-open-ftplugin\">Quickly Open <code>ftplugin<\/code><a class=\"headerlink\" href=\"#quickly-open-ftplugin\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is one that I don&rsquo;t use <em>as often<\/em> as some of the above, but when I do need it, it&rsquo;s extremely\nhandy. I use the <code>$VIMFILES\/after\/ftplugin<\/code> directory to put in my custom settings for specific file\ntypes. These files usually don&rsquo;t just contain changes in settings like indentation, but also\n<code>commentstring<\/code> and often some command(s) that makes editing that specific <code>filetype<\/code> a bit easier.<\/p>\n<p>These commands let me open the plugin file in that directory for the <code>filetype<\/code> I&rsquo;m currently\nworking with.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Edit my filetype\/syntax plugin files for current filetype.<\/span>\n<\/span><span>command <span class=\"p\">-<\/span>nargs<span class=\"p\">=<\/span>? <span class=\"p\">-<\/span><span class=\"nb\">complete<\/span><span class=\"p\">=<\/span><span class=\"k\">filetype<\/span> EditFileTypePlugin\n<\/span><span>            \\ exe <span class=\"s1\">&#39;keepj vsplit $VIMFILES\/after\/ftplugin\/&#39;<\/span> . <span class=\"p\">(<\/span>empty<span class=\"p\">(&lt;<\/span><span class=\"k\">q<\/span><span class=\"p\">-<\/span>args<span class=\"p\">&gt;)<\/span> ? &amp;<span class=\"k\">filetype<\/span> : <span class=\"p\">&lt;<\/span><span class=\"k\">q<\/span><span class=\"p\">-<\/span>args<span class=\"p\">&gt;)<\/span> . <span class=\"s1\">&#39;.vim&#39;<\/span>\n<\/span><span>command <span class=\"p\">-<\/span>nargs<span class=\"p\">=<\/span>? <span class=\"p\">-<\/span><span class=\"nb\">complete<\/span><span class=\"p\">=<\/span><span class=\"k\">filetype<\/span> Eft EditFileTypePlugin <span class=\"p\">&lt;<\/span>args<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The same thing for syntax plugin:<\/p>\n<div class=\"hl\"><pre class=content><code><span>command <span class=\"p\">-<\/span>nargs<span class=\"p\">=<\/span>? <span class=\"p\">-<\/span><span class=\"nb\">complete<\/span><span class=\"p\">=<\/span><span class=\"k\">filetype<\/span> EditSyntaxPlugin\n<\/span><span>            \\ exe <span class=\"s1\">&#39;keepj vsplit $VIMFILES\/after\/syntax\/&#39;<\/span> . <span class=\"p\">(<\/span>empty<span class=\"p\">(&lt;<\/span><span class=\"k\">q<\/span><span class=\"p\">-<\/span>args<span class=\"p\">&gt;)<\/span> ? &amp;<span class=\"k\">filetype<\/span> : <span class=\"p\">&lt;<\/span><span class=\"k\">q<\/span><span class=\"p\">-<\/span>args<span class=\"p\">&gt;)<\/span> . <span class=\"s1\">&#39;.vim&#39;<\/span>\n<\/span><span>command <span class=\"p\">-<\/span>nargs<span class=\"p\">=<\/span>? <span class=\"p\">-<\/span><span class=\"nb\">complete<\/span><span class=\"p\">=<\/span><span class=\"k\">filetype<\/span> Esy EditSyntaxPlugin <span class=\"p\">&lt;<\/span>args<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">Note that the <code>:Eft<\/code> and <code>:Esy<\/code> commands act like short aliases for these commands.<\/p>\n<p>These commands are obviously heavily inspired by the <code>:EditUltiSnipsFile<\/code> command from the\n<a href=\"https:\/\/github.com\/sirver\/UltiSnips\" rel=\"noopener noreferrer\" target=\"_blank\">UltiSnips<\/a> plugin (which is great at automation by the way).<\/p>\n<h2 id=\"sorting-over-motion\">Sorting over Motion<a class=\"headerlink\" href=\"#sorting-over-motion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Vim comes with the <a href=\"http:\/\/vimdoc.sourceforge.net\/htmldoc\/change.html#:sort\" rel=\"noopener noreferrer\" target=\"_blank\"><code>:sort<\/code><\/a> command that sorts the range of lines provided. So, for\nexample, to sort the whole file, we&rsquo;d do <code>:%sort<\/code>. To sort the first ten lines, something like\n<code>:1,10sort<\/code> should do. The range of lines given will be replaced with the sorted lines.<\/p>\n<p>This is convenient, but not very handy. But I&rsquo;d always wanted a way to sort over a motion, like\n<em>sort this paragraph<\/em> or <em>sort inside braces<\/em> etc. So, after some searching online and digging the\nVim documentation, I have the following in my <code>vimrc<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c\">&quot; Sort lines, selected or over motion.<\/span>\n<\/span><span>xnoremap <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> gs :<span class=\"k\">sort<\/span> <span class=\"k\">i<\/span><span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> gs :<span class=\"k\">set<\/span> <span class=\"nb\">opfunc<\/span><span class=\"p\">=<\/span>SortLines<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span>@\n<\/span><span><span class=\"k\">fun<\/span><span class=\"p\">!<\/span> SortLines<span class=\"p\">(<\/span>type<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"s1\">&#39;[,&#39;<\/span>]<span class=\"k\">sort<\/span> <span class=\"k\">i<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>With this, hitting <kbd>gsip<\/kbd> would sort the lines <em>inside<\/em> the current paragraph. Similarly,\n<kbd>gsiB<\/kbd> would sort lines inside the braces closest to the cursor (try this one in CSS!). If\nyou have the <a href=\"https:\/\/github.com\/michaeljsmith\/vim-indent-object\/\" rel=\"noopener noreferrer\" target=\"_blank\">vim-indent-object<\/a> plugin, you\ncould also do <kbd>gsii<\/kbd> to sort lines in current indent block.<\/p>\n<p>Additionally, we also have an <code>xnoremap<\/code> mapping definition which lets us use <kbd>gs<\/kbd> in\nvisual mode to sort the highlighted lines. I don&rsquo;t use this as often as the operator version above,\nbut it&rsquo;s nice to have nonetheless.<\/p>\n<h2 id=\"reversing-over-motion\">Reversing over Motion<a class=\"headerlink\" href=\"#reversing-over-motion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is very similar to the above. Instead of sorting, I&rsquo;m reversing the lines. Unfortunately, we\ndon&rsquo;t have a <code>:reverse<\/code> command like <code>:sort<\/code>, so this one is more DIY.<\/p>\n<div class=\"hl\"><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><\/pre><pre class=content><code><span><span class=\"c\">&quot; Reverse lines, selected or over motion.<\/span>\n<\/span><span><span class=\"nb\">nnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"k\">gr<\/span> :<span class=\"k\">set<\/span> <span class=\"nb\">opfunc<\/span><span class=\"p\">=<\/span>ReverseLines<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;<\/span><span class=\"k\">g<\/span>@\n<\/span><span><span class=\"nb\">vnoremap<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"k\">gr<\/span> :<span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">u<\/span><span class=\"p\">&gt;<\/span><span class=\"k\">call<\/span> ReverseLines<span class=\"p\">(<\/span><span class=\"s1\">&#39;vis&#39;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"k\">fun<\/span><span class=\"p\">!<\/span> ReverseLines<span class=\"p\">(<\/span>type<span class=\"p\">)<\/span> abort\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">marks<\/span> <span class=\"p\">=<\/span> <span class=\"k\">a<\/span>:type <span class=\"p\">==<\/span>? <span class=\"s1\">&#39;vis&#39;<\/span> ? <span class=\"s1\">&#39;&lt;&gt;&#39;<\/span> : <span class=\"s1\">&#39;[]&#39;<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l1<span class=\"p\">,<\/span> c1<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">0<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> [_<span class=\"p\">,<\/span> l2<span class=\"p\">,<\/span> c2<span class=\"p\">,<\/span> _] <span class=\"p\">=<\/span> getpos<span class=\"p\">(<\/span><span class=\"s2\">&quot;&#39;&quot;<\/span> . <span class=\"k\">marks<\/span>[<span class=\"m\">1<\/span>]<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">if<\/span> l1 <span class=\"p\">==<\/span> l2\n<\/span><span>        <span class=\"k\">return<\/span>\n<\/span><span>    <span class=\"k\">endif<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> line <span class=\"k\">in<\/span> getline<span class=\"p\">(<\/span>l1<span class=\"p\">,<\/span> l2<span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">call<\/span> setline<span class=\"p\">(<\/span>l2<span class=\"p\">,<\/span> line<span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"k\">let<\/span> l2 <span class=\"p\">-=<\/span> <span class=\"m\">1<\/span>\n<\/span><span>    <span class=\"k\">endfor<\/span>\n<\/span><span><span class=\"k\">endfun<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I mapped reversing to <kbd>gr<\/kbd>, which works similar to the <kbd>gs<\/kbd> from previous section,\nbut instead of sorting, the lines will be reversed. Everything in the above snippet can be looked up\nwith <code>:h<\/code> command within Vim. I&rsquo;ll leave the understanding-it&rsquo;s-working part as an exercise to the\nreader, if inclined.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This articles looks an awful lot like a list of Vim tips, but I implore you to see further. I picked\nthese specific things from my Vim setup (which is a lot bigger than this) to illustrate the idea of\nidentifying and then automating. Of course, these snippets I shared above, in my opinion are too\nsmall for a full blown plugin, yet not too insignificant to not be shared. I intend to follow up\nwith more ideas from my configuration, so stay tuned.<\/p>\n<p>I also encourage you to go over the Vim help pages often. They contain some awesome tips and ideas\nthat serve as great starter points to improve your workflow. So, just, you know, while that really\nlong build is running, grab a coffee and open the Vim docs!<\/p>\n<p>Identify, optimize, repeat.<\/p>\n<p class=\"note\">Read the <a href=\"..\/automating-the-vim-workplace-2\/\">next article<\/a> in this series.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"vim"}},{"@attributes":{"term":"productivity"}}]},{"title":"Python's `map` builtin function","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/python-map-function\/","rel":"alternate"}},"published":"2020-01-04T00:00:00+05:30","updated":"2020-01-04T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2020-01-04:\/posts\/python-map-function\/","summary":"<p>In this article, we&rsquo;ll take a look at Python&rsquo;s stream processing utility function, <code>map<\/code>. This\nfunction can enable us to write powerful list\/stream-processing routines that can be easy to read\nand understand.<\/p>\n<p>Let&rsquo;s go over the basics first so we have context when talking about them \u2026<\/p>","content":"<p>In this article, we&rsquo;ll take a look at Python&rsquo;s stream processing utility function, <code>map<\/code>. This\nfunction can enable us to write powerful list\/stream-processing routines that can be easy to read\nand understand.<\/p>\n<p>Let&rsquo;s go over the basics first so we have context when talking about them.<\/p>\n<h2 id=\"syntax\">Syntax<a class=\"headerlink\" href=\"#syntax\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Calling <code>map<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\"># From official docs<\/span>\n<\/span><span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"n\">function<\/span><span class=\"p\">,<\/span> <span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"o\">...<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Where<\/p>\n<dl>\n<dt>function<\/dt>\n<dd>Called with each item from <code>iterable<\/code>.<\/dd>\n<dt>iterable<\/dt>\n<dd>Use to take inputs for calling <code>function<\/code>.<\/dd>\n<dt><em>returns<\/em><\/dt>\n<dd>Iterable of return values from calling <code>function<\/code>.<\/dd>\n<\/dl>\n<h2 id=\"working-of-map-function\">Working of <code>map<\/code> Function<a class=\"headerlink\" href=\"#working-of-map-function\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here&rsquo;s a run-book for the <code>map<\/code> builtin function:<\/p>\n<ol>\n<li>Accepts two arguments, a function (or any callable) and a list (or any sequence) of objects.<\/li>\n<li>Call the function once per object in the list, pass the object to the function, and collect the\n   return value from each call.<\/li>\n<li>Return a generator that will yield the return values as collected by applying above step over and\n   over until the list from point 1 is exhausted.<\/li>\n<\/ol>\n<p class=\"note\">Note that in Python 2, <code>map<\/code> used to return a <code>list<\/code> object. However, in Python 3, it returns a\n<code>map<\/code> object which is a generator that lazily processes each item in the list as they are needed. If\nyou don&rsquo;t want to bother with this difference for now, remember to always wrap the result of a <code>map<\/code>\nfunction with a <code>list<\/code>. The official <code>2to3<\/code> tool handles this automatically.<\/p>\n<p>Let&rsquo;s look at some examples:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">&lt;map object at 0x0000000002DCD3C8&gt;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)))<\/span>\n<\/span><span><span class=\"go\">[&#39;0&#39;, &#39;1&#39;, &#39;2&#39;, &#39;3&#39;, &#39;4&#39;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice how in the first call to <code>map<\/code>, we get a <code>map<\/code> object show up in the result. In this case,\nnone of the items in <code>range(5)<\/code> have been processed by <code>str<\/code>. But when we wrap it in <code>list<\/code> the next\ntime, we get the list of all processed items.<\/p>\n<p>We can also pass in lambda functions just fine.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)))<\/span>\n<\/span><span><span class=\"go\">[0, 1, 4, 9, 16]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But don&rsquo;t do that, that&rsquo;s silly. We&rsquo;ll see why later down in this article, but, put simply,\n<em>comprehensions are almost always better than a map+lambda combination<\/em>.<\/p>\n<p>Additionally, <code>map<\/code> can also take more than one sequence in it&rsquo;s arguments. In that case, the items\nproduced by each of the other sequence make up for additional arguments for the given function.<\/p>\n<p>Consider the following call to <code>map<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">sum<\/span><span class=\"p\">,<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">],<\/span> <span class=\"p\">[<\/span><span class=\"mi\">7<\/span><span class=\"p\">,<\/span> <span class=\"mi\">8<\/span><span class=\"p\">,<\/span> <span class=\"mi\">9<\/span><span class=\"p\">],<\/span> <span class=\"p\">[<\/span><span class=\"mi\">100<\/span><span class=\"p\">,<\/span> <span class=\"mi\">200<\/span><span class=\"p\">,<\/span> <span class=\"mi\">300<\/span><span class=\"p\">]))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This will call the given <code>sum<\/code> function three times,<\/p>\n<div class=\"hl\"><pre class=content><code><span>sum(1, 7, 100)\n<\/span><span>sum(2, 8, 200)\n<\/span><span>sum(3, 9, 300)\n<\/span><\/code><\/pre><\/div>\n\n<p>It produces a result list of three items, the three return values of the above three calls to <code>sum<\/code>.<\/p>\n<p>Let&rsquo;s look at some useful ways we can use the <code>map<\/code> function in real world code.<\/p>\n<h2 id=\"using-unbound-methods\">Using Unbound Methods<a class=\"headerlink\" href=\"#using-unbound-methods\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If the function we want to call is a <em>method call<\/em> on each object in the given list, we could use\na comprehension or do it with map+lambda like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">protocols<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;http&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;tcp&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;xmpp&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;irc&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">protocol<\/span><span class=\"o\">.<\/span><span class=\"n\">upper<\/span><span class=\"p\">()<\/span> <span class=\"k\">for<\/span> <span class=\"n\">protocol<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">protocols<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">[&#39;HTTP&#39;, &#39;TCP&#39;, &#39;XMPP&#39;, &#39;IRC&#39;]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">protocol<\/span><span class=\"p\">:<\/span> <span class=\"n\">protocol<\/span><span class=\"o\">.<\/span><span class=\"n\">upper<\/span><span class=\"p\">(),<\/span> <span class=\"n\">protocols<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[&#39;HTTP&#39;, &#39;TCP&#39;, &#39;XMPP&#39;, &#39;IRC&#39;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But a much simpler way, is to provide the unbound method as the first argument to <code>map<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"o\">.<\/span><span class=\"n\">upper<\/span><span class=\"p\">,<\/span> <span class=\"n\">protocols<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[&#39;HTTP&#39;, &#39;TCP&#39;, &#39;XMPP&#39;, &#39;IRC&#39;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The reason this works is because calling unbound method with an instance as the first argument, is\nalmost the same thing as calling the bound method of that instance. In other words,\n<code>str.upper('http')<\/code> is more or less the same as <code>'http'.upper()<\/code>. This is true for any method on any\nclass (even <code>classmethod<\/code>s if you have a list of classes).<\/p>\n<h2 id=\"more-types-of-sequences\">More Types of Sequences<a class=\"headerlink\" href=\"#more-types-of-sequences\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Pass in sets, dictionaries (also <code>mydict.get<\/code> as function), file objects, a string (<code>map(ord,\n'abc')<\/code>) etc.<\/p>\n<p>The second argument to <code>map<\/code> can be any sequence data type, doesn&rsquo;t have to be a <code>list<\/code>. Here&rsquo;s some\ntypes that are quite useful with <code>map<\/code>:<\/p>\n<ol>\n<li>Sets (function called with each <em>item<\/em> in set)<\/li>\n<li>Dictionaries (function called with each <em>key<\/em> in the dictionary)<\/li>\n<li>Files (function called with each <em>line<\/em> in the open file object)<\/li>\n<li>Strings (function called with each <em>character<\/em> in the string)<\/li>\n<\/ol>\n<p>We can use dictionaries as the sequence to run a function over each <em>key<\/em> in the dictionary.\nAdditionally, we can use the <code>.items<\/code> or <code>.values<\/code> to have <code>map<\/code> run the function over each <code>(key,\nvalue)<\/code> tuple or just the values respectively.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">numbers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;one&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;three&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;four&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">4<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">,<\/span> <span class=\"n\">numbers<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[3, 3, 5, 4]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">numbers<\/span><span class=\"o\">.<\/span><span class=\"n\">values<\/span><span class=\"p\">()))<\/span>\n<\/span><span><span class=\"go\">[&#39;1&#39;, &#39;2&#39;, &#39;3&#39;, &#39;4&#39;]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">repr<\/span><span class=\"p\">,<\/span> <span class=\"n\">numbers<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">()))<\/span>\n<\/span><span><span class=\"go\">[&quot;(&#39;one&#39;, 1)&quot;, &quot;(&#39;two&#39;, 2)&quot;, &quot;(&#39;three&#39;, 3)&quot;, &quot;(&#39;four&#39;, 4)&quot;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We can use <code>map<\/code> to transform the lines of a file as we are reading over it. This is actually very\nuseful to do some small preprocessing on the lines, like removing trailing white space.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;contents.txt&#39;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">open_file<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">line<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">str<\/span><span class=\"o\">.<\/span><span class=\"n\">rstrip<\/span><span class=\"p\">,<\/span> <span class=\"n\">open_file<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"k\">pass<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We can map a function like <code>ord<\/code> (returns the Unicode code point for a single character) over a\nstring, to get the code points for each character in the string.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">ord<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;aluminium&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[97, 108, 117, 109, 105, 110, 105, 117, 109]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"dictionaries-as-transformers\">Dictionaries as Transformers<a class=\"headerlink\" href=\"#dictionaries-as-transformers\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is another neat trick where we have a dictionary and a list of some <em>keys<\/em>. We use <code>map<\/code> to\ntransform the list of keys to a list of values, referring to the dictionary.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">numbers<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;one&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;three&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;four&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">4<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">keys<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;three&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;four&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;five&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;four&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"n\">numbers<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">,<\/span> <span class=\"n\">keys<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[3, 4, 2, None, 4, 2]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice that when faced with a key like <code>'five'<\/code> that doesn&rsquo;t exist in the dictionary, we get <code>None<\/code>,\nwhich is how the <code>dict.get<\/code> behaves.<\/p>\n<p class=\"note\">Note that in this call to <code>map<\/code>, we are passing a <em>bound<\/em> method, <code>numbers.get<\/code>. This is essentially\nthe <code>dict.get<\/code> unbound method, which has been bound to the <code>dict<\/code> instance we are calling <code>numbers<\/code>.<\/p>\n<h2 id=\"infinite-sequences\">Infinite Sequences<a class=\"headerlink\" href=\"#infinite-sequences\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Since <code>map<\/code> is lazy from Python 3, it can work with infinite sequences just fine. For our purposes,\nlet&rsquo;s create a generator that will generate positive even numbers from zero to infinity:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">def<\/span> <span class=\"nf\">positive_evens<\/span><span class=\"p\">():<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">n<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"k\">while<\/span> <span class=\"kc\">True<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"gp\">... <\/span>        <span class=\"k\">yield<\/span> <span class=\"n\">n<\/span>\n<\/span><span><span class=\"gp\">... <\/span>        <span class=\"n\">n<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">2<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Since this generator never stops by itself, calling <code>list(positive_evens())<\/code> will never return. So,\nwe have to put a cap on the amount of data we generate ourselves. Of course, <code>map<\/code> doesn&rsquo;t care.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">e<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">positive_evens<\/span><span class=\"p\">():<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"k\">if<\/span> <span class=\"n\">e<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">3<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"gp\">... <\/span>        <span class=\"k\">break<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"go\">0<\/span>\n<\/span><span><span class=\"go\">2<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">math<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">e<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"n\">math<\/span><span class=\"o\">.<\/span><span class=\"n\">sqrt<\/span><span class=\"p\">,<\/span> <span class=\"n\">positive_evens<\/span><span class=\"p\">()):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"k\">if<\/span> <span class=\"n\">e<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">3<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"gp\">... <\/span>        <span class=\"k\">break<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">e<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"go\">0.0<\/span>\n<\/span><span><span class=\"go\">1.4142135623730951<\/span>\n<\/span><span><span class=\"go\">2.0<\/span>\n<\/span><span><span class=\"go\">2.449489742783178<\/span>\n<\/span><span><span class=\"go\">2.8284271247461903<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>map<\/code> function doesn&rsquo;t care that the generator we passed in is never ending. It only processes\nas many items as the <code>for<\/code> loop requests.<\/p>\n<p class=\"note\">Be careful with infinite generators though, it&rsquo;s very easy to end up in an infinite loop situation.<\/p>\n<h2 id=\"side-effect-operations\">Side Effect Operations<a class=\"headerlink\" href=\"#side-effect-operations\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>map<\/code> function is best used as a <em>transformation<\/em> done to each item in a sequence. In this\nsense, the function that&rsquo;s passed in is usually a pure function. Passing in functions that are\npurely intended for side effects (like <code>print<\/code>, <code>log.debug<\/code> etc.) is in bad taste (opinion alert!).<\/p>\n<p>This is mostly because of two reasons. First, we&rsquo;ll have to pass the return value of <code>map<\/code> to <code>list<\/code>\nto get our <code>print<\/code> calls to run. Second, we&rsquo;ll then have a list of <code>None<\/code>s that&rsquo;s just a sad waste.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">print<\/span><span class=\"p\">,<\/span> <span class=\"n\">protocols<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">http<\/span>\n<\/span><span><span class=\"go\">tcp<\/span>\n<\/span><span><span class=\"go\">xmpp<\/span>\n<\/span><span><span class=\"go\">irc<\/span>\n<\/span><span><span class=\"go\">[None, None, None, None]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The better way to do this is to just use a <code>for<\/code> loop and make the intention clear. The intention is\nto do something <em>with<\/em> each item in the sequence. Not to do something <em>to<\/em> each item in the sequence\nand collect their return value.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">for<\/span> <span class=\"n\">protocol<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">protocols<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">protocol<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">http<\/span>\n<\/span><span><span class=\"go\">tcp<\/span>\n<\/span><span><span class=\"go\">xmpp<\/span>\n<\/span><span><span class=\"go\">irc<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Much better.<\/p>\n<h2 id=\"string-join\">String join<a class=\"headerlink\" href=\"#string-join\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Since we can use bound methods with <code>map<\/code> as well, we can pass in methods bound string methods like\n<code>str.join<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">planets<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;one&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;un&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;two&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;deux&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;three&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;trois&#39;<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;:&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">,<\/span> <span class=\"n\">planets<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">()))<\/span>\n<\/span><span><span class=\"go\">[&#39;one:un&#39;, &#39;two:deux&#39;, &#39;three:trois&#39;]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"case-against-lambdamap\">Case Against <code>lambda<\/code>+<code>map<\/code><a class=\"headerlink\" href=\"#case-against-lambdamap\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Since <code>map<\/code> accepts any callable, it can be tempting to use <code>lambda<\/code> functions inside <code>map<\/code>. This is\nalmost always bad taste, and usually, comprehensions (along with <code>zip<\/code>) offer a more readable\nalternative.<\/p>\n<p>Consider the following use of <code>map<\/code> with <code>lambda<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">x<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)))<\/span>\n<\/span><span><span class=\"go\">[0, 2, 4, 6, 8]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now compare that with the same thing done with a comprehension:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"n\">x<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)]<\/span>\n<\/span><span><span class=\"go\">[0, 2, 4, 6, 8]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now, of course we can use comprehensions even if we are not using <code>lambda<\/code> in <code>map<\/code> by just calling\nit in the comprehension, true, but in that case, <code>map<\/code> just looks prettier ;).<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">[<\/span><span class=\"nb\">ord<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">c<\/span> <span class=\"ow\">in<\/span> <span class=\"s1\">&#39;hello&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">[104, 101, 108, 108, 111]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"nb\">ord<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;hello&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">[104, 101, 108, 108, 111]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In fact, any call to <code>map<\/code> can be translated to a comprehension:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">map<\/span><span class=\"p\">(<\/span><span class=\"n\">function<\/span><span class=\"p\">,<\/span> <span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"o\">...<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"c1\"># same as<\/span>\n<\/span><span><span class=\"p\">(<\/span><span class=\"n\">function<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">vals<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">vals<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">zip<\/span><span class=\"p\">(<\/span><span class=\"n\">iterable<\/span><span class=\"p\">,<\/span> <span class=\"o\">...<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But that doesn&rsquo;t mean <code>map<\/code> is not useful. We just have to pick the right option depending on the\nneed.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>map<\/code> function is powerful builtin, but should be used with care. If you find yourself nesting\nseveral different calls to <code>map<\/code>, you may want to rethink that strategy since it quickly becomes\nunreadable.<\/p>\n<p>But when it produces clear-to-understand code, <code>map<\/code> can be very useful tool.<\/p>\n<p>Thank you for reading! Do you have any clever examples of using <code>map<\/code>? Share in the comments!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"reference"}}]},{"title":"The Jython Pillow Guide","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/jython-pillow-guide\/","rel":"alternate"}},"published":"2018-01-09T00:00:00+05:30","updated":"2018-01-09T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2018-01-09:\/posts\/jython-pillow-guide\/","summary":"<p>This is a document with tips and usage details about Jython that I&rsquo;ve come across. I intend to\ndocument handy features of Python as well as some clever inter-op facilities provided by Jython.<\/p>\n<p>I&rsquo;m going to assume you&rsquo;re not a complete beginner to Java and Python languages \u2026<\/p>","content":"<p>This is a document with tips and usage details about Jython that I&rsquo;ve come across. I intend to\ndocument handy features of Python as well as some clever inter-op facilities provided by Jython.<\/p>\n<p>I&rsquo;m going to assume you&rsquo;re not a complete beginner to Java and Python languages. If you find\nanything off or have a suggestion to add, please do write to me. Thanks!<\/p>\n<h2 id=\"logging-and-printing\">Logging and Printing<a class=\"headerlink\" href=\"#logging-and-printing\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>When using Apache&rsquo;s <em>log4j<\/em>, we can get an instance of a <code>Logger<\/code> using the API just as we would in\nJava:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">from<\/span> <span class=\"nn\">org.apache.log4j<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Logger<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">log<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Logger<\/span><span class=\"o\">.<\/span><span class=\"n\">getLogger<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;jython_script&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>When getting a <code>Logger<\/code> instance for a module that is imported, a logger with a category specific to\nthat module can be obtained using the following code:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">log<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Logger<\/span><span class=\"o\">.<\/span><span class=\"n\">getLogger<\/span><span class=\"p\">(<\/span><span class=\"vm\">__name__<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>__name__<\/code> name is a variable containing the current module&rsquo;s name as a string. <em>Note<\/em> that\n<code>__name__<\/code> is set to the string <code>'__main__'<\/code> if the module is run as a script and not imported from\nanother script. This should be kept in mind when using the above code.<\/p>\n<p>The standard printing functions of Java can be imported into Python and used directly in the\nfollowing way:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">from<\/span> <span class=\"nn\">java.lang<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">System<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">System<\/span><span class=\"o\">.<\/span><span class=\"n\">out<\/span><span class=\"o\">.<\/span><span class=\"n\">println<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Hola&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">Hola<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">System<\/span><span class=\"o\">.<\/span><span class=\"n\">err<\/span><span class=\"o\">.<\/span><span class=\"n\">println<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Hello there&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">Hello<\/span> <span class=\"n\">there<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">System<\/span><span class=\"o\">.<\/span><span class=\"n\">out<\/span><span class=\"o\">.<\/span><span class=\"n\">print<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Hola<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">Hola<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>However, it&rsquo;s usually more convenient to use Python&rsquo;s <code>print<\/code> statement to output things to standard\noutput and error:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">print<\/span> <span class=\"s1\">&#39;Hello world!&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here&rsquo;s a table illustrating the <code>print<\/code> statement equivalents of the Java <code>print*<\/code> functions:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Java<\/th>\n<th>Python<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>System.out.println(\"!\")<\/code><\/td>\n<td><code>print '!'<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>System.out.print(\"!\")<\/code><\/td>\n<td><code>print '!',<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>System.err.println(\"!\")<\/code><\/td>\n<td><code>print &gt;&gt; sys.stderr, '!'<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>System.err.print(\"!\")<\/code><\/td>\n<td><code>print &gt;&gt; sys.stderr, '!',<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<h2 id=\"bean-properties\">Bean Properties<a class=\"headerlink\" href=\"#bean-properties\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Jython can implicitly call the <code>.get*<\/code> and <code>.set*<\/code> methods that are widely used in Java classes to\nget and set the values of instance attributes. Here&rsquo;s an illustration of how this inter-op works:<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Jython<\/th>\n<th>Java equivalent<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>obj.somePropertyValue<\/code><\/td>\n<td><code>obj.getSomePropertyValue()<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>obj.somePropertyValue = 123<\/code><\/td>\n<td><code>obj.setSomePropertyValue(123)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Of course, when such <code>.get*<\/code> and <code>.set*<\/code> methods are not available, this falls back gracefully to\ntrying get\/set the property values directly, just as Java would treat those statements.<\/p>\n<h2 id=\"strings\">Strings<a class=\"headerlink\" href=\"#strings\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Strings in Java (<em>i.e.,<\/em> objects of type <code>java.lang.String<\/code>) are converted to <code>unicode<\/code> objects when\npassed in to Python world. Whereas <code>str<\/code> and <code>unicode<\/code> objects in Python are converted to\n<code>java.lang.String<\/code> instances when passed in to Java world. This conversion is seamless and we\nusually don&rsquo;t have to worry about it.<\/p>\n<p>However, if needed, we can explicitly create an instance of <code>java.lang.String<\/code> from a <code>unicode<\/code>\nobject in Python:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">from<\/span> <span class=\"nn\">java.lang<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">String<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">greeting<\/span> <span class=\"o\">=<\/span> <span class=\"n\">String<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Hello&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">greeting<\/span>\n<\/span><span><span class=\"n\">Hello<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">greeting<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"o\">&lt;<\/span><span class=\"nb\">type<\/span> <span class=\"s1\">&#39;java.lang.String&#39;<\/span><span class=\"o\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>String formatting using <code>%<\/code> operator in Python cannot be applied to Java <code>String<\/code> objects. They have\nto converted to <code>str<\/code> or <code>unicode<\/code> first.<\/p>\n<h2 id=\"maps-as-dictionaries\">Maps as Dictionaries<a class=\"headerlink\" href=\"#maps-as-dictionaries\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>For the purposes of the following examples, let&rsquo;s work with the following\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Map.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Map<\/code><\/a>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">Map<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">String<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">Integer<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">data<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"k\">new<\/span><span class=\"w\"> <\/span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">HashMap<\/span><span class=\"o\">&lt;&gt;<\/span><span class=\"p\">();<\/span>\n<\/span><span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"na\">put<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;a&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"na\">put<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;b&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">2<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">data<\/span><span class=\"p\">.<\/span><span class=\"na\">put<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;c&quot;<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"mi\">3<\/span><span class=\"p\">);<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p><code>Map<\/code>s support the <em>getitem<\/em> syntax very well so it is usually convenient to think of them as\npython-style dictionaries. Here&rsquo;s an example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">print<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">]<\/span>  <span class=\"c1\"># data.get(&quot;a&quot;)<\/span>\n<\/span><span><span class=\"mi\">1<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">print<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">]<\/span>  <span class=\"c1\"># data.get(&quot;b&quot;)<\/span>\n<\/span><span><span class=\"mi\">2<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">4<\/span>  <span class=\"c1\"># data.put(&quot;d&quot;, 4)<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">]<\/span>  <span class=\"c1\"># data.get(&quot;d&quot;)<\/span>\n<\/span><span><span class=\"mi\">4<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>  <span class=\"c1\"># data.size()<\/span>\n<\/span><span><span class=\"mi\">4<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"s1\">&#39;c&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span>  <span class=\"c1\"># data.containsKey(&quot;c&quot;)<\/span>\n<\/span><span><span class=\"kc\">True<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"k\">del<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">]<\/span>  <span class=\"c1\"># data.remove(&quot;c&quot;)<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"s1\">&#39;c&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span>  <span class=\"c1\"># data.containsKey(&quot;c&quot;)<\/span>\n<\/span><span><span class=\"kc\">False<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">data<\/span>\n<\/span><span><span class=\"p\">{<\/span><span class=\"n\">a<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"n\">d<\/span><span class=\"o\">=<\/span><span class=\"mi\">4<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>  <span class=\"c1\"># data.size()<\/span>\n<\/span><span><span class=\"mi\">3<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Although this resembles the usage of a traditional python dictionary, the methods you&rsquo;d expect in a\ndictionary are not all available. This is a <code>Map<\/code> object after all and it has the methods of the\n<code>Map<\/code> class. However, it is easy to get see the parallels among some of the most used methods.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th><code>dict<\/code> method<\/th>\n<th><code>Map<\/code> method<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>.keys<\/code><\/td>\n<td><code>.keySet<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>.values<\/code><\/td>\n<td><code>.values<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>.clear<\/code><\/td>\n<td><code>.clear<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>.items<\/code> (gives 2-tuples)<\/td>\n<td><code>.entrySet<\/code> (gives <code>Entry<\/code> objects with <code>.key<\/code> and <code>.value<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>.update<\/code><\/td>\n<td><code>.putAll<\/code> (accepts <code>dict<\/code> as well as a <code>Map<\/code>)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>The <code>dict<\/code> builtin can be called on the <code>Map<\/code> object to get a python-style dictionary, if needed.\nAdditionally, just like a python dictionary, calling <code>list<\/code> (or <code>set<\/code>) on the <code>Map<\/code> object gives a\n<code>list<\/code> (or <code>set<\/code>) of the <em>keys<\/em> in the <code>Map<\/code>.<\/p>\n<p>Using <code>for<\/code> loops to iterate over <code>Map<\/code>s yields the keys in the <code>Map<\/code>, which is consistent with how\n<code>for<\/code> loops work with python dictionaries.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">for<\/span> <span class=\"n\">key<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"n\">key<\/span><span class=\"p\">]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Prints the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span>a 1\n<\/span><span>b 2\n<\/span><span>d 4\n<\/span><\/code><\/pre><\/div>\n\n<p>In python, the <code>.items<\/code> method returns each entry as a <code>tuple<\/code> which lets us write the for loop like\nthe following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\"># !!! Only works if `data` is a python-style dictionary, not if it is a `Map`.<\/span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But unfortunately, since <code>Map<\/code> doesn&rsquo;t have the <code>.items<\/code> method, this is not possible. However, we\ncan use the <code>.entrySet<\/code> method to construct something <em>slightly<\/em> similar.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">for<\/span> <span class=\"n\">entry<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"n\">entrySet<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">entry<\/span><span class=\"o\">.<\/span><span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">entry<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>To iterate over the values of a <code>Map<\/code>, since the method is called <code>.values<\/code> in both <code>dict<\/code> and\n<code>Map<\/code>, the same piece of code would work with any object.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">for<\/span> <span class=\"n\">value<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"n\">values<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">value<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Empty <code>Map<\/code> objects are treated as <code>False<\/code> in boolean contexts, just as with python&rsquo;s dictionaries.<\/p>\n<h2 id=\"collections\">Collections<a class=\"headerlink\" href=\"#collections\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The two main collection types in Python are <code>list<\/code> and <code>set<\/code>. The equivalents in java are the\ninterfaces <a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/List.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>List<\/code><\/a> and\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Set.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Set<\/code><\/a>. Let&rsquo;s prepare some data for\nour examples.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">List<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">String<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">planets<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"k\">new<\/span><span class=\"w\"> <\/span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">ArrayList<\/span><span class=\"o\">&lt;&gt;<\/span><span class=\"p\">();<\/span>\n<\/span><span><span class=\"n\">planets<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Mercury&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">planets<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Venus&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">planets<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Earth&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">Set<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">String<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"n\">colors<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"k\">new<\/span><span class=\"w\"> <\/span><span class=\"n\">java<\/span><span class=\"p\">.<\/span><span class=\"na\">util<\/span><span class=\"p\">.<\/span><span class=\"na\">HashSet<\/span><span class=\"o\">&lt;&gt;<\/span><span class=\"p\">();<\/span>\n<\/span><span><span class=\"n\">colors<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;White&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">colors<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Black&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">colors<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Red&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">colors<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Green&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><span><span class=\"n\">colors<\/span><span class=\"p\">.<\/span><span class=\"na\">add<\/span><span class=\"p\">(<\/span><span class=\"s\">&quot;Blue&quot;<\/span><span class=\"p\">);<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <em>getitem<\/em> syntax can be used with <code>List<\/code>s seamlessly:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">planets<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"sa\">u<\/span><span class=\"s1\">&#39;Mercury&#39;<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">planets<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"sa\">u<\/span><span class=\"s1\">&#39;Venus&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The slicing syntax, returns <code>List<\/code>s of the same type, not python-style <code>list<\/code>s.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">planets<\/span><span class=\"p\">[:<\/span><span class=\"mi\">2<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"n\">Mercury<\/span><span class=\"p\">,<\/span> <span class=\"n\">Venus<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">)<\/span>  <span class=\"c1\"># `_` is a variable set to the return value of last expression.<\/span>\n<\/span><span><span class=\"o\">&lt;<\/span><span class=\"nb\">type<\/span> <span class=\"s1\">&#39;java.util.ArrayList&#39;<\/span><span class=\"o\">&gt;<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">planets<\/span><span class=\"p\">[::<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"p\">[<\/span><span class=\"n\">Earth<\/span><span class=\"p\">,<\/span> <span class=\"n\">Venus<\/span><span class=\"p\">,<\/span> <span class=\"n\">Mercury<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">_<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"o\">&lt;<\/span><span class=\"nb\">type<\/span> <span class=\"s1\">&#39;java.util.ArrayList&#39;<\/span><span class=\"o\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>However, the <em>getitem<\/em> syntax is not supported for <code>Set<\/code>s as it doesn&rsquo;t make sense there since\n<code>Set<\/code>s are unordered collections. But the operator support available for <code>set<\/code>s in python are\navailable with Java <code>Set<\/code> objects as well.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"s1\">&#39;Red&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">colors<\/span>\n<\/span><span><span class=\"kc\">True<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">colors<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"mi\">5<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>for<\/code> loop can be used on any\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Collection.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Collection<\/code><\/a> type objects to\niterate over the object&rsquo;s contents.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">planets<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"o\">...<\/span>     <span class=\"nb\">print<\/span> <span class=\"n\">x<\/span>\n<\/span><span><span class=\"o\">...<\/span>\n<\/span><span><span class=\"n\">Mercury<\/span>\n<\/span><span><span class=\"n\">Venus<\/span>\n<\/span><span><span class=\"n\">Earth<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">enumerate<\/span><span class=\"p\">(<\/span><span class=\"n\">planets<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"o\">...<\/span>     <span class=\"nb\">print<\/span> <span class=\"n\">x<\/span>\n<\/span><span><span class=\"o\">...<\/span>\n<\/span><span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"sa\">u<\/span><span class=\"s1\">&#39;Mercury&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"sa\">u<\/span><span class=\"s1\">&#39;Venus&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"sa\">u<\/span><span class=\"s1\">&#39;Earth&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here&rsquo;s equivalents for some of the methods available in Java&rsquo;s <code>Collection<\/code>s and Python&rsquo;s collection\ntypes.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Java<\/th>\n<th>Jython<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>Collection.add<\/code><\/td>\n<td><code>list.append<\/code> \/ <code>set.add<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>Collection.addAll<\/code><\/td>\n<td><code>list.extend<\/code> \/ <code>set.update<\/code> (Prefer <code>list + list<\/code> or <code>set.union<\/code>)<\/td>\n<\/tr>\n<tr>\n<td><code>Collection.contains<\/code><\/td>\n<td><code>in list<\/code> or <code>in set<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>Collection.isEmpty<\/code><\/td>\n<td><code>bool(list)<\/code> or <code>bool(set)<\/code> (Can be used directly in a boolean context)<\/td>\n<\/tr>\n<tr>\n<td><code>Collection.size<\/code><\/td>\n<td><code>len(list)<\/code> or <code>len(set)<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>Empty <code>Collection<\/code>s are treated as <code>False<\/code> in boolean contexts, just as with python&rsquo;s collections.<\/p>\n<h3 id=\"java-arrays\">Java Arrays<a class=\"headerlink\" href=\"#java-arrays\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Just as Java&rsquo;s <code>List<\/code> is mirrored in Python with <code>list<\/code>, Java&rsquo;s arrays are mirrored using the array\nstructure available in Jython&rsquo;s <a href=\"http:\/\/www.jython.org\/docs\/library\/array.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>array<\/code><\/a> module.\nThat official documentation is quite exhaustive on this topic, so I suggest going over it to get an\nidea of handling arrays in Jython.<\/p>\n<h2 id=\"the-iteration-protocol\">The Iteration Protocol<a class=\"headerlink\" href=\"#the-iteration-protocol\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Java&rsquo;s <a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Iterator.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Iterator<\/code><\/a> style\niteration is supported by Jython&rsquo;s <code>for<\/code> statements. For example, consider the following Java\n<code>Iterator<\/code> that&rsquo;s trying to emulate a small fraction of Python&rsquo;s <code>range<\/code> function:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">package<\/span><span class=\"w\"> <\/span><span class=\"nn\">ssk.experiments<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"kn\">import<\/span><span class=\"w\"> <\/span><span class=\"nn\">java.util.Iterator<\/span><span class=\"p\">;<\/span>\n<\/span><span>\n<\/span><span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kd\">class<\/span> <span class=\"nc\">RangeIterator<\/span><span class=\"w\"> <\/span><span class=\"kd\">implements<\/span><span class=\"w\"> <\/span><span class=\"n\">Iterator<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Integer<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">private<\/span><span class=\"w\"> <\/span><span class=\"n\">Integer<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"nf\">RangeIterator<\/span><span class=\"p\">(<\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"na\">max<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nd\">@Override<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kt\">boolean<\/span><span class=\"w\"> <\/span><span class=\"nf\">hasNext<\/span><span class=\"p\">()<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nd\">@Override<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"n\">Integer<\/span><span class=\"w\"> <\/span><span class=\"nf\">next<\/span><span class=\"p\">()<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"o\">++<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Since classes are instantiated without a <code>new<\/code> keyword in Python, combined with the fact that\nJython&rsquo;s <code>for<\/code> statement supports Java&rsquo;s <code>Iterator<\/code>s, we can use the above in the following way:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">ssk.experiments<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">RangeIterator<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">n<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">RangeIterator<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">n<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This gives the following output:<\/p>\n<div class=\"hl\"><pre class=content><code><span>0\n<\/span><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><\/code><\/pre><\/div>\n\n<p>Since Jython&rsquo;s <code>for<\/code> statement supports iterating over Java&rsquo;s\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Enumeration.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Enumeration<\/code><\/a> type, the\nabove same <code>for<\/code> loop would work with a <code>RangeEnumeration<\/code> class as defined below:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">package<\/span><span class=\"w\"> <\/span><span class=\"nn\">ssk.experiments<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"kn\">import<\/span><span class=\"w\"> <\/span><span class=\"nn\">java.util.Enumeration<\/span><span class=\"p\">;<\/span>\n<\/span><span>\n<\/span><span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kd\">class<\/span> <span class=\"nc\">RangeEnumeration<\/span><span class=\"w\"> <\/span><span class=\"kd\">implements<\/span><span class=\"w\"> <\/span><span class=\"n\">Enumeration<\/span><span class=\"o\">&lt;<\/span><span class=\"n\">Integer<\/span><span class=\"o\">&gt;<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">private<\/span><span class=\"w\"> <\/span><span class=\"n\">Integer<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"nf\">RangeEnumeration<\/span><span class=\"p\">(<\/span><span class=\"kt\">int<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"na\">max<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nd\">@Override<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kt\">boolean<\/span><span class=\"w\"> <\/span><span class=\"nf\">hasMoreElements<\/span><span class=\"p\">()<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"w\"> <\/span><span class=\"o\">&lt;<\/span><span class=\"w\"> <\/span><span class=\"n\">max<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"nd\">@Override<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"n\">Integer<\/span><span class=\"w\"> <\/span><span class=\"nf\">nextElement<\/span><span class=\"p\">()<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"n\">current<\/span><span class=\"o\">++<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Jython seamlessly handles the getting of an instance of an <code>Iterator<\/code> from a Java\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/lang\/Iterable.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Iterable<\/code><\/a>. This is actually\nhow the <code>for<\/code> statement works with the <code>List<\/code> and <code>Set<\/code> collections discussed earlier (<code>Collection<\/code>\nis a sub-interface of <code>Iterable<\/code>). <\/p>\n<h2 id=\"patching-java-classes\">Patching Java Classes<a class=\"headerlink\" href=\"#patching-java-classes\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>In Python, new methods and attributes can be added to existing classes. This comes from the dynamic\nnature of the programming language and the runtime. The JVM is also a dynamic runtime, but the Java\nlanguage doesn&rsquo;t allow us to modify existing classes. This is where Jython comes in. Jython lets us\nadd and override methods on existing Java classes. Although this is seldom needed, this can\nillustrate the extent of Jython&rsquo;s integration with the JVM.<\/p>\n<p>Here&rsquo;s a Java class:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">package<\/span><span class=\"w\"> <\/span><span class=\"nn\">ssk.experiments<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"kn\">import<\/span><span class=\"w\"> <\/span><span class=\"nn\">java.util.List<\/span><span class=\"p\">;<\/span>\n<\/span><span>\n<\/span><span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kd\">class<\/span> <span class=\"nc\">Country<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">private<\/span><span class=\"w\"> <\/span><span class=\"n\">String<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">;<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"nf\">Country<\/span><span class=\"p\">(<\/span><span class=\"n\">String<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"na\">name<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"n\">String<\/span><span class=\"w\"> <\/span><span class=\"nf\">getName<\/span><span class=\"p\">()<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">return<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"kd\">public<\/span><span class=\"w\"> <\/span><span class=\"kt\">void<\/span><span class=\"w\"> <\/span><span class=\"nf\">setName<\/span><span class=\"p\">(<\/span><span class=\"n\">String<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"k\">this<\/span><span class=\"p\">.<\/span><span class=\"na\">name<\/span><span class=\"w\"> <\/span><span class=\"o\">=<\/span><span class=\"w\"> <\/span><span class=\"n\">name<\/span><span class=\"p\">;<\/span><span class=\"w\"> <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There&rsquo;s nothing fancy with the above class. It&rsquo;s a regular class with one property with a <code>.get<\/code> and\n<code>.set<\/code> methods. Now, let&rsquo;s add a new method to this class.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">ssk.experiments<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Country<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">upcase<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">name<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">name<\/span><span class=\"o\">.<\/span><span class=\"n\">upper<\/span><span class=\"p\">()<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"n\">Country<\/span><span class=\"o\">.<\/span><span class=\"n\">upcase<\/span> <span class=\"o\">=<\/span> <span class=\"n\">upcase<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Create a `Country` object and call `upper_name` method.<\/span>\n<\/span><span><span class=\"n\">largest_country<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Country<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Russia&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">largest_country<\/span><span class=\"o\">.<\/span><span class=\"n\">upcase<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"nb\">print<\/span> <span class=\"n\">largest_country<\/span><span class=\"o\">.<\/span><span class=\"n\">name<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would print <code>RUSSIA<\/code>, as expected.<\/p>\n<p>Note that this is an advanced feature and should be used with caution. In almost all cases, it is\nprobably a better idea to modify the original Java class definition directly. But when that is not\nan option, creating a simple Python function that works with these objects should be considered.\nModifying existing classes should only be used as a last resort.<\/p>\n<h2 id=\"operator-overloading\">Operator Overloading<a class=\"headerlink\" href=\"#operator-overloading\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>One nice and practical case for adding methods on existing Java classes is to leverage Python&rsquo;s\nsupport for operator overloading with Java classes. One good example for this is with the\n<code>BigDecimal<\/code> class. Mathematical operations on objects of <code>BigDecimal<\/code> are provided as individual\nmethods like <code>.add<\/code>, <code>.subtract<\/code> <em>etc<\/em>. We can add operator support  (in Jython) for these objects\nby adding the appropriate methods to the <code>BigDecimal<\/code> class.<\/p>\n<p>For instance, here&rsquo;s how we can add support for the <code>+<\/code> operator:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">java.math<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">BigDecimal<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">BigDecimal<\/span><span class=\"o\">.<\/span><span class=\"fm\">__add__<\/span> <span class=\"o\">=<\/span> <span class=\"k\">lambda<\/span> <span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">add<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">print<\/span> <span class=\"n\">BigDecimal<\/span><span class=\"p\">(<\/span><span class=\"mi\">42<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"n\">BigDecimal<\/span><span class=\"p\">(<\/span><span class=\"mi\">10<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This would print <code>52<\/code>, as expected. More methods can be added to support all the mathematical\noperators such as <code>__sub__<\/code> for subtraction and <code>__mul__<\/code> for multiplication <em>etc<\/em>. The full list of\nsuch method names can be found on the official <a href=\"http:\/\/www.jython.org\/docs\/reference\/datamodel.html#emulating-numeric-types\" rel=\"noopener noreferrer\" target=\"_blank\">data model documentation\npage<\/a>.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is not intended to be an exhaustive guide to what Jython can do. I hoped to give you a taste of\nhow well Jython handles inter-op with Java and hopefully I&rsquo;ve helped you write better Python - Java\ninter-op code. Thank you and any suggestions and feedback are very welcome.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"jython"}},{"@attributes":{"term":"java"}},{"@attributes":{"term":"polyglot"}}]},{"title":"The Python Dictionary","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-python-dictionary\/","rel":"alternate"}},"published":"2017-09-29T00:00:00+05:30","updated":"2017-09-29T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2017-09-29:\/posts\/the-python-dictionary\/","summary":"<p>The Python <a href=\"https:\/\/docs.python.org\/3.6\/tutorial\/datastructures.html#dictionaries\" rel=\"noopener noreferrer\" target=\"_blank\">Dictionary<\/a> is a key&ndash;value style data structure that is tightly integrated with the\nlanguage syntax and semantics. Understanding them well can help us use them better and investigate\nsubtle problems more efficiently.<\/p>\n<p>This is my attempt to document this topic in more depth. Though I included a \u2026<\/p>","content":"<p>The Python <a href=\"https:\/\/docs.python.org\/3.6\/tutorial\/datastructures.html#dictionaries\" rel=\"noopener noreferrer\" target=\"_blank\">Dictionary<\/a> is a key&ndash;value style data structure that is tightly integrated with the\nlanguage syntax and semantics. Understanding them well can help us use them better and investigate\nsubtle problems more efficiently.<\/p>\n<p>This is my attempt to document this topic in more depth. Though I included a small section about the\nsyntax and basic usage of dictionaries, it&rsquo;ll be helpful if you have some beginner&ndash;intermediate\nlevel experience with Python.<\/p>\n<p>This article is written for Python 3.6 installed via Anaconda on Xubuntu. Here&rsquo;s the platform\ndetails:<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python -V\n<\/span><span>Python 3.6.1 :: Anaconda custom (64-bit)\n<\/span><span>$ uname -isro\n<\/span><span>Linux 4.10.0-33-generic x86_64 GNU\/Linux\n<\/span><\/code><\/pre><\/div>\n\n<p>Note: This is not intended as a substitute for official documentation. The official documentation is\na reference and there will be some overlap. This document is intended as a supplement that covers\nmore depth and practical nuances.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#introduction\">Introduction<\/a><\/li>\n<li><a href=\"#usage\">Usage<\/a><ul>\n<li><a href=\"#syntax\">Syntax<\/a><\/li>\n<li><a href=\"#api\">API<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#contents\">Contents<\/a><ul>\n<li><a href=\"#key-types\">Key Types<\/a><\/li>\n<li><a href=\"#retrieving-keys\">Retrieving Keys<\/a><\/li>\n<li><a href=\"#using-tuples-for-keys\">Using Tuples for Keys<\/a><\/li>\n<li><a href=\"#retrieving-values\">Retrieving Values<\/a><\/li>\n<li><a href=\"#items-collection\">Items Collection<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#typing\">Typing<\/a><\/li>\n<li><a href=\"#creating-dictionaries\">Creating Dictionaries<\/a><ul>\n<li><a href=\"#calling-dict\">Calling dict<\/a><\/li>\n<li><a href=\"#comprehensions\">Comprehensions<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#public-appearance\">Public Appearance<\/a><ul>\n<li><a href=\"#keyword-arguments\">Keyword Arguments<\/a><\/li>\n<li><a href=\"#namespaces\">Namespaces<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#serialization\">Serialization<\/a><ul>\n<li><a href=\"#json\">JSON<\/a><\/li>\n<li><a href=\"#pickling\">Pickling<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#the-item-syntax\">The Item Syntax<\/a><\/li>\n<li><a href=\"#flavors\">Flavors<\/a><ul>\n<li><a href=\"#the-ordereddict\">The OrderedDict<\/a><\/li>\n<li><a href=\"#the-defaultdict\">The defaultdict<\/a><\/li>\n<li><a href=\"#the-chainmap\">The ChainMap<\/a><\/li>\n<li><a href=\"#the-counter\">The Counter<\/a><\/li>\n<li><a href=\"#custom-flavor\">Custom Flavor<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#disassembling\">Disassembling<\/a><\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<li><a href=\"#references\">References<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"introduction\">Introduction<a class=\"headerlink\" href=\"#introduction\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Dictionaries (type <code>dict<\/code>) are a very powerful data structure, not just in Python. They are present\nin almost every modern high level language, sometimes called maps, hashes or associative arrays.\nPython&rsquo;s syntax for dictionaries inspired the syntax of the JSON serialization format.<\/p>\n<p>Dictionaries are a fundamental part of Python language and integrate tightly with the semantics and\nAPIs of the standard library. This can be seen in the fact that we have a special syntax just to\ncreate these data structures.<\/p>\n<h2 id=\"usage\">Usage<a class=\"headerlink\" href=\"#usage\" title=\"Permanent link\">&para;<\/a><\/h2>\n<h3 id=\"syntax\">Syntax<a class=\"headerlink\" href=\"#syntax\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>As a quick primer, here&rsquo;s the syntax for defining a dictionary:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">country_currencies<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"s1\">&#39;India&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;Rupee&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"s1\">&#39;Russia&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;Ruble&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"s1\">&#39;USA&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;Dollar&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"s1\">&#39;Japan&#39;<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;Yen&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"api\">API<a class=\"headerlink\" href=\"#api\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Again, we quickly run down the common operations on dictionaries.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\"># Get the value of a key.<\/span>\n<\/span><span><span class=\"n\">indian_currency<\/span> <span class=\"o\">=<\/span> <span class=\"n\">country_currencies<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;India&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Set the value of a key.<\/span>\n<\/span><span><span class=\"n\">country_currencies<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;France&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Euro&#39;<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Delete a key.<\/span>\n<\/span><span><span class=\"k\">del<\/span> <span class=\"n\">country_currencies<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;USA&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Check for presence of a key.<\/span>\n<\/span><span><span class=\"s1\">&#39;Russia&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">country_currencies<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Get if key present, otherwise return `None`.<\/span>\n<\/span><span><span class=\"c1\"># (Takes a second parameter which is returned when key is missing).<\/span>\n<\/span><span><span class=\"n\">country_currencies<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;USA&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Set only if the key is not already present.<\/span>\n<\/span><span><span class=\"n\">country_currencies<\/span><span class=\"o\">.<\/span><span class=\"n\">setdefault<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;France&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Franc&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"contents\">Contents<a class=\"headerlink\" href=\"#contents\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The contents of dictionaries are made up two components. The keys and the values. The keys form the\nindex using which we can retrieve the values. Each key uniquely identifies a value within the\ndictionary.<\/p>\n<h3 id=\"key-types\">Key Types<a class=\"headerlink\" href=\"#key-types\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The keys form the index of the dictionary. In most practical cases, keys tend to be strings. Tuples\nare often used as well. In fact, values of any immutable, hashable types can be used as keys.<\/p>\n<p>So, what is a hashable type? The official documentation of the <a href=\"https:\/\/docs.python.org\/3\/reference\/datamodel.html#object.__hash__\" rel=\"noopener noreferrer\" target=\"_blank\"><code>__hash__<\/code> method<\/a> gives the\nfull detail of what it is and what are considered hashable. Simply put, if passing an object to the\n<code>hash<\/code> builtin function doesn&rsquo;t raise an exception, the object is hashable and <em>can<\/em> be used as a\nkey in a dictionary.<\/p>\n<p>However, in practice, we should avoid using mutable objects as keys (even if they are hashable).\nEspecially, if mutation changes the hash of the object.<\/p>\n<p>For example, consider the following <code>User<\/code> class.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">class<\/span> <span class=\"nc\">User<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">first_name<\/span><span class=\"p\">,<\/span> <span class=\"n\">last_name<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">first_name<\/span>\n<\/span><span>        <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">last_name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">last_name<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s inspect the hash values of <code>User<\/code> objects.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Ned&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Stark&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">hash<\/span><span class=\"p\">(<\/span><span class=\"n\">ned<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">8784834659087<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Robb&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">hash<\/span><span class=\"p\">(<\/span><span class=\"n\">ned<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">8784834659087<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">If you try the above code, you might see a different number. That&rsquo;s because Python default hashing\nalgorithm includes a random salt.<\/p>\n<p>As seen above, the hash value did not change even though the object was modified. These <code>User<\/code>\nobjects can be used as keys for a dictionary since they meet the requirement, but it should be kept\nin mind that they are mutable.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Ned&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Stark&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"n\">ned<\/span><span class=\"p\">:<\/span> <span class=\"mi\">123<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ned<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">123<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Robb&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ned<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">123<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>If that doesn&rsquo;t seem confusing, try this:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">robb<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ned<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Ned&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Start&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">robb<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span>\n<\/span><span><span class=\"go\">&#39;Robb&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">robb<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">d<\/span>  <span class=\"c1\"># Robb isn&#39;t in our dictionary!<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span>\n<\/span><span><span class=\"go\">&#39;Ned&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">d<\/span>  <span class=\"c1\"># We gave Ned Stark a value right?<\/span>\n<\/span><span><span class=\"go\">False<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This can quickly cause headaches and hard-to-find problems.<\/p>\n<p>To <em>fix<\/em> this, if someone later decides to customize the hashing of this class by adding the\nfollowing method:<\/p>\n<div class=\"hl\"><pre class=content><code><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__hash__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"nb\">hash<\/span><span class=\"p\">((<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">last_name<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Now, the hash of the object changes when we change the <code>first_name<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Ned&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Stark&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">hash<\/span><span class=\"p\">(<\/span><span class=\"n\">ned<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">4091961891370636651<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Robb&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">hash<\/span><span class=\"p\">(<\/span><span class=\"n\">ned<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">-7890115541605828979<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Using these objects as keys can be confusing as well:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span> <span class=\"o\">=<\/span> <span class=\"n\">User<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;Ned&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Stark&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"n\">ned<\/span><span class=\"p\">:<\/span> <span class=\"mi\">123<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ned<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">123<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Robb&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ned<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"gt\">Traceback (most recent call last):<\/span>\n<\/span><span>  File <span class=\"nb\">&quot;&lt;stdin&gt;&quot;<\/span>, line <span class=\"m\">1<\/span>, in <span class=\"n\">&lt;module&gt;<\/span>\n<\/span><span><span class=\"gr\">KeyError<\/span>: <span class=\"n\">&lt;__main__.User object at 0x7fd60e7c5828&gt;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">ned<\/span><span class=\"o\">.<\/span><span class=\"n\">first_name<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Ned&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"n\">ned<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">123<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In essence, using mutable types as keys in a dictionary can lead to confusing results in a fairly\nlarge codebase.<\/p>\n<p>So, to avoid these potential problems, it&rsquo;s best to use numbers, strings or tuples (containing\nnumbers or strings) as keys for dictionaries. If you <strong>have<\/strong> to use other types, keep the hashing\nsemantics in mind and document the reasons well.<\/p>\n<h3 id=\"retrieving-keys\">Retrieving Keys<a class=\"headerlink\" href=\"#retrieving-keys\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Dictionaries have a <a href=\"https:\/\/docs.python.org\/3.6\/library\/stdtypes.html#dict.keys\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.keys<\/code><\/a> method that returns an object of type <a href=\"https:\/\/docs.python.org\/3.6\/library\/stdtypes.html#dictionary-view-objects\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dict_keys<\/code><\/a>\nwhich is an iterable (technically, a <em>view<\/em>) of the keys of the dictionary. Note that this method\nused to return an ordinary <code>list<\/code> in Python 2.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">countries<\/span> <span class=\"o\">=<\/span> <span class=\"n\">country_currencies<\/span><span class=\"o\">.<\/span><span class=\"n\">keys<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">countries<\/span>\n<\/span><span><span class=\"go\">dict_keys([&#39;India&#39;, &#39;Russia&#39;, &#39;USA&#39;, &#39;Japan&#39;])<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">collections<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">countries<\/span><span class=\"p\">,<\/span> <span class=\"n\">collections<\/span><span class=\"o\">.<\/span><span class=\"n\">Iterable<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that the order of the keys is not retained\/defined. Don&rsquo;t rely on the order even if they seem\npredictable. It might vary across Python implementations and versions even. Use an <code>OrderedDict<\/code>\nwhen ordering is needed. More on this in a later section.<\/p>\n<p class=\"note\">It should be noted that starting in Python 3.6, order of keys <em>is<\/em> preserved. This is an unintended\nside affect of using a more efficient <code>dict<\/code> implementation. As such, the Python documentation\nexplicitly states that this is an implementation detail and should not be relied upon. <a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.6.html#whatsnew36-pep468\" rel=\"noopener noreferrer\" target=\"_blank\">Read\nmore<\/a>.<\/p>\n<p>So, what&rsquo;s special about <code>dict_keys<\/code>, as opposed to a <code>list<\/code>? Look look!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">countries<\/span>\n<\/span><span><span class=\"go\">dict_keys([&#39;India&#39;, &#39;Russia&#39;, &#39;USA&#39;, &#39;Japan&#39;])<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">country_currencies<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;France&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Euro&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">countries<\/span>\n<\/span><span><span class=\"go\">dict_keys([&#39;India&#39;, &#39;Russia&#39;, &#39;USA&#39;, &#39;Japan&#39;, &#39;France&#39;])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>See? The <code>dict_keys<\/code> object is a <em>view<\/em> of the keys of the original dictionary object. When the\ndictionary&rsquo;s keys change, so does the keys view. Of course, we can make a set of currently\navailable keys by passing it to <code>set<\/code> builtin. This set would be independent of the dictionary.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">set<\/span><span class=\"p\">(<\/span><span class=\"n\">countries<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">{&#39;Japan&#39;, &#39;USA&#39;, &#39;Russia&#39;, &#39;India&#39;, &#39;France&#39;}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">Most people would suggest and use <code>list<\/code> here, instead of <code>set<\/code>. I personally feel a <code>set<\/code> is\nsemantically more correct since a <code>list<\/code> indicates the contents have a specific ordering and does\nnot convey that the contents are hashable, immutable, and more importantly, <em>unique<\/em>. A <code>set<\/code> shares\nthese features of dictionary keys.<\/p>\n<p>Additionally, the <code>dict_keys<\/code> objects are themselves <code>set<\/code>-like. They implement the <a href=\"https:\/\/docs.python.org\/3.6\/library\/collections.abc.html#collections.abc.Set\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Set<\/code><\/a>\nabstraction. So, we don&rsquo;t need to convert them to a <code>set<\/code> in order to do set operations on them. For\nexample, here&rsquo;s an intersection operation:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">countries<\/span><span class=\"p\">,<\/span> <span class=\"n\">collections<\/span><span class=\"o\">.<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">Set<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">countries<\/span> <span class=\"o\">&amp;<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;India&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;China&#39;<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"go\">{&#39;India&#39;}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"using-tuples-for-keys\">Using Tuples for Keys<a class=\"headerlink\" href=\"#using-tuples-for-keys\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Here&rsquo;s a quick example of using tuples as keys in a dictionary:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;a1&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;a2&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">(<\/span><span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;b1&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">(<\/span><span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;b2&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">&#39;a2&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that only tuples that contain hashable types (or further such tuples) can be used as keys.\nLists or dictionaries, on the other hand, cannot be used since they are not hashable.<\/p>\n<h3 id=\"retrieving-values\">Retrieving Values<a class=\"headerlink\" href=\"#retrieving-values\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Values are what the keys index. Naturally, values don&rsquo;t have to be unique, unlike keys. There&rsquo;s no\nrestrictions on what types can be used as values in a dictionary.<\/p>\n<p>We can get a sequence of values in a <code>dict<\/code> with the <a href=\"https:\/\/docs.python.org\/3.6\/library\/stdtypes.html#dict.values\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.values<\/code><\/a> method. This returns a\n<a href=\"https:\/\/docs.python.org\/3.6\/library\/stdtypes.html#dictionary-view-objects\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dict_values<\/code><\/a> object.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">currencies<\/span> <span class=\"o\">=<\/span> <span class=\"n\">country_currencies<\/span><span class=\"o\">.<\/span><span class=\"n\">values<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">currencies<\/span>\n<\/span><span><span class=\"go\">dict_values([&#39;Rupee&#39;, &#39;Ruble&#39;, &#39;Dollar&#39;, &#39;Euro&#39;, &#39;Yen&#39;])<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">currencies<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">&lt;class &#39;dict_values&#39;&gt;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">currencies<\/span><span class=\"p\">,<\/span> <span class=\"n\">collections<\/span><span class=\"o\">.<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">Set<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">False<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is <em>live<\/em> as well!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">del<\/span> <span class=\"n\">country_currencies<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;France&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">currencies<\/span>\n<\/span><span><span class=\"go\">dict_values([&#39;Rupee&#39;, &#39;Ruble&#39;, &#39;Dollar&#39;, &#39;Yen&#39;])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This can be passed to <code>list<\/code> to get a list of values. Using <code>set<\/code> here is probably not a good idea\nsince unlike the keys, values don&rsquo;t have to be unique or hashable.<\/p>\n<h3 id=\"items-collection\">Items Collection<a class=\"headerlink\" href=\"#items-collection\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Dictionaries also provide a <a href=\"https:\/\/docs.python.org\/3.6\/library\/stdtypes.html#dict.items\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.items<\/code><\/a> method that returns all the key&ndash;value pairs as a\nsequence of 2-tuples.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">country_currencies<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span>\n<\/span><span><span class=\"go\">dict_items([(&#39;India&#39;, &#39;Rupee&#39;), (&#39;Russia&#39;, &#39;Ruble&#39;), (&#39;USA&#39;, &#39;Dollar&#39;), (&#39;Japan&#39;, &#39;Yen&#39;)])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Again, just like with <code>.keys<\/code> or <code>.values<\/code>, the sequence is <em>live<\/em> and the order of items is not\ndefined.<\/p>\n<p>The <code>.items<\/code> method is probably mostly used with the <code>for<\/code> statement to loop over the key&ndash;value\npairs.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">for<\/span> <span class=\"n\">country<\/span><span class=\"p\">,<\/span> <span class=\"n\">currency<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">country_currencies<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"sa\">f<\/span><span class=\"s2\">&quot;<\/span><span class=\"si\">{<\/span><span class=\"n\">country<\/span><span class=\"si\">}<\/span><span class=\"s2\">&#39;s currency is <\/span><span class=\"si\">{<\/span><span class=\"n\">currency<\/span><span class=\"si\">}<\/span><span class=\"s2\">.&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">The above code uses <a href=\"https:\/\/docs.python.org\/3.6\/reference\/lexical_analysis.html#f-strings\" rel=\"noopener noreferrer\" target=\"_blank\">f-strings<\/a> introduced in Python 3.6. In older versions of Python, the\n<code>.format<\/code> method or the modulo (<code>%<\/code>) operator should be used.<\/p>\n<p>The <code>dict_items<\/code> object also implements the <code>Set<\/code> abstraction.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">pairs<\/span><span class=\"p\">,<\/span> <span class=\"n\">collections<\/span><span class=\"o\">.<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">Set<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>However, the abstraction&rsquo;s methods only work if the dictionary&rsquo;s values are hashable, not just the\nkeys. So, for the dictionary we are working with, the <code>pairs<\/code> object can be used as a set.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span> <span class=\"o\">&amp;<\/span> <span class=\"p\">{(<\/span><span class=\"s1\">&#39;India&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Rupee&#39;<\/span><span class=\"p\">),<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;UK&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Pound&#39;<\/span><span class=\"p\">)}<\/span>\n<\/span><span><span class=\"go\">{(&#39;India&#39;, &#39;Rupee&#39;)}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But if we try this on a dictionary whose values are not <code>hash<\/code>able, say, lists, then it fails.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">number_types<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"s1\">&#39;even&#39;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">,<\/span> <span class=\"mi\">8<\/span><span class=\"p\">],<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"s1\">&#39;odd&#39;<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">,<\/span> <span class=\"mi\">7<\/span><span class=\"p\">,<\/span> <span class=\"mi\">9<\/span><span class=\"p\">],<\/span>\n<\/span><span><span class=\"gp\">... <\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">number_types<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span>\n<\/span><span><span class=\"go\">dict_items([(&#39;even&#39;, [2, 4, 6, 8]), (&#39;odd&#39;, [1, 3, 5, 7, 9])])<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">pairs<\/span><span class=\"p\">,<\/span> <span class=\"n\">collections<\/span><span class=\"o\">.<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">Set<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s try intersecting this with an empty set.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pairs<\/span> <span class=\"o\">&amp;<\/span> <span class=\"nb\">set<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gt\">Traceback (most recent call last):<\/span>\n<\/span><span>  File <span class=\"nb\">&quot;&lt;stdin&gt;&quot;<\/span>, line <span class=\"m\">1<\/span>, in <span class=\"n\">&lt;module&gt;<\/span>\n<\/span><span><span class=\"gr\">TypeError<\/span>: <span class=\"n\">unhashable type: &#39;list&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>As the error says, <code>list<\/code> is not hashable. So, although the <code>isinstance<\/code> tells us that this is a\n<code>Set<\/code>, whether it can actually be used as such, depends on it&rsquo;s contents. This is <em>not incorrect<\/em>,\nactually, I feel it&rsquo;s just a consequence of Python&rsquo;s dynamic nature.<\/p>\n<h2 id=\"typing\">Typing<a class=\"headerlink\" href=\"#typing\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Dictionaries in Python are what I call a <em>homogeneous<\/em> data structure. What that means is that they\nare best used by having all the keys be of the same type and similarly for values. This is enforced\nin comparable data structures in statically typed languages like Java&rsquo;s <code>Map<\/code> or Haskell&rsquo;s\n<code>HashMap<\/code>. But since Python is a dynamic language, such restrictions are not placed. We can have\nkeys \/ values of several different types within the same dictionary.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"mi\">42<\/span><span class=\"p\">:<\/span> <span class=\"s1\">&#39;yay!&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"p\">(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">):<\/span> <span class=\"kc\">True<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is still a valid dictionary, although an extremely sad and ugly one (totally my opinion :D).<\/p>\n<p>If using homogeneous dictionaries, the type annotations syntax can be used to declare the type\nsignatures. We use <a href=\"https:\/\/docs.python.org\/3\/library\/typing.html#typing.Dict\" rel=\"noopener noreferrer\" target=\"_blank\"><code>typing.Dict<\/code><\/a> for this purpose as illustrated below.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">,<\/span> <span class=\"n\">Tuple<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">number_map<\/span><span class=\"p\">:<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">[<\/span><span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"mi\">1<\/span><span class=\"p\">:<\/span> <span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">:<\/span> <span class=\"mi\">20<\/span><span class=\"p\">,<\/span> <span class=\"mi\">3<\/span><span class=\"p\">:<\/span> <span class=\"mi\">30<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"n\">data_map<\/span><span class=\"p\">:<\/span> <span class=\"n\">Dict<\/span><span class=\"p\">[<\/span><span class=\"n\">Tuple<\/span><span class=\"p\">[<\/span><span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">],<\/span> <span class=\"nb\">str<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;a1&#39;<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">):<\/span> <span class=\"s1\">&#39;a2&#39;<\/span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is new in Python 3.6. Before 3.6, annotations are only supported for function arguments. <a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.6.html#pep-526-syntax-for-variable-annotations\" rel=\"noopener noreferrer\" target=\"_blank\">Read\nmore<\/a>.<\/p>\n<p class=\"note\">Additionally, the <code>typing<\/code> module itself is new in Python 3.5. <a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.5.html#whatsnew-pep-484\" rel=\"noopener noreferrer\" target=\"_blank\">Read\nmore<\/a>.<\/p>\n<p>The general structure is <code>Dict[&lt;key-type&gt;, &lt;value-type&gt;]<\/code>. So, <code>Dict[str, int]<\/code> denotes a dictionary\nthat maps string keys to integer values.<\/p>\n<p>Note that these type annotations are not checked at runtime. They&rsquo;re mere help to IDEs, static\ncheckers and human readers. Python&rsquo;s dynamic nature is not affected by these annotations.<\/p>\n<p>However, if such type annotations are declared, you could use a static analyzer like <a href=\"http:\/\/www.mypy-lang.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">mypy<\/a> to\nperform type checks. I won&rsquo;t be discussing that here.<\/p>\n<h2 id=\"creating-dictionaries\">Creating Dictionaries<a class=\"headerlink\" href=\"#creating-dictionaries\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>There are a few other ways to create dictionaries besides the <code>{}<\/code> syntax. Here&rsquo;s a few of them.<\/p>\n<h3 id=\"calling-dict\">Calling <code>dict<\/code><a class=\"headerlink\" href=\"#calling-dict\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <code>dict<\/code> callable can be used to create dictionaries from a list of tuples or bypassing the keys\nand values as keyword arguments.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">([(<\/span><span class=\"s1\">&#39;Chromium&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">24<\/span><span class=\"p\">),<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;Phosphorus&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">15<\/span><span class=\"p\">),<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;Silver&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">47<\/span><span class=\"p\">)])<\/span>\n<\/span><span><span class=\"go\">{&#39;Chromium&#39;: 24, &#39;Phosphorus&#39;: 15, &#39;Silver&#39;: 47}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is obviously more convenient than the dictionary syntax <em>only<\/em> if we already have such a list.\nIf we have the keys and corresponding values in different lists, we can <code>zip<\/code> them up and pass the\nresult to <code>dict<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"nb\">zip<\/span><span class=\"p\">(<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">[<\/span><span class=\"s1\">&#39;Sulfer&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Calcium&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;Gold&#39;<\/span><span class=\"p\">],<\/span>  <span class=\"c1\"># Keys<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"p\">[<\/span><span class=\"mi\">16<\/span><span class=\"p\">,<\/span> <span class=\"mi\">20<\/span><span class=\"p\">,<\/span> <span class=\"mi\">79<\/span><span class=\"p\">],<\/span>  <span class=\"c1\"># Values<\/span>\n<\/span><span><span class=\"gp\">... <\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"go\">{&#39;Sulfer&#39;: 16, &#39;Calcium&#39;: 20, &#39;Gold&#39;: 79}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course, we can pass keyword arguments directly to <code>dict<\/code>, in addition to the above even.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"nb\">dict<\/span><span class=\"p\">([(<\/span><span class=\"s1\">&#39;Chromium&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">24<\/span><span class=\"p\">),<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;Phosphorus&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">15<\/span><span class=\"p\">)]),<\/span> <span class=\"n\">Sodium<\/span><span class=\"o\">=<\/span><span class=\"mi\">11<\/span><span class=\"p\">,<\/span> <span class=\"n\">Nitrogen<\/span><span class=\"o\">=<\/span><span class=\"mi\">7<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">{&#39;Chromium&#39;: 24, &#39;Phosphorus&#39;: 15, &#39;Sodium&#39;: 11, &#39;Nitrogen&#39;: 7}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">Sodium<\/span><span class=\"o\">=<\/span><span class=\"mi\">11<\/span><span class=\"p\">,<\/span> <span class=\"n\">Nitrogen<\/span><span class=\"o\">=<\/span><span class=\"mi\">7<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">{&#39;Sodium&#39;: 11, &#39;Nitrogen&#39;: 7}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The second form is better written using the Python syntax. That is more natural to a potential\nfuture reader, and, <em>slightly<\/em> faster<sup id=\"fnref:1\"><a class=\"footnote-ref\" href=\"#fn:1\">1<\/a><\/sup> as well.<\/p>\n<h3 id=\"comprehensions\">Comprehensions<a class=\"headerlink\" href=\"#comprehensions\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Python 3 (and 2.7) added support for dict comprehensions which are very similar to list\ncomprehensions, but with a small variation in syntax.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">((<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">i<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">))<\/span>  <span class=\"c1\"># Using the `dict` builtin.<\/span>\n<\/span><span><span class=\"go\">{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"p\">{<\/span><span class=\"n\">i<\/span><span class=\"p\">:<\/span> <span class=\"n\">i<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">5<\/span><span class=\"p\">)}<\/span>  <span class=\"c1\"># Using a dict comprehension.<\/span>\n<\/span><span><span class=\"go\">{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The above two examples create the same dictionary. However, as pointed out in <a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0274\/\" rel=\"noopener noreferrer\" target=\"_blank\">PEP 274<\/a>, the dict\ncomprehension is more succinct and makes the intent clearer.<\/p>\n<h2 id=\"public-appearance\">Public Appearance<a class=\"headerlink\" href=\"#public-appearance\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Unsurprisingly, dictionaries pop up in a lot of places in Python. Here&rsquo;s a few ones.<\/p>\n<h3 id=\"keyword-arguments\">Keyword Arguments<a class=\"headerlink\" href=\"#keyword-arguments\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>When defining a function that takes arbitrary keyword arguments, they are passed to the function as\na dictionary.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">def<\/span> <span class=\"nf\">construct<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">counts<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">counts<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">counts<\/span><span class=\"p\">),<\/span> <span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">counts<\/span><span class=\"p\">))<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">construct<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"n\">c<\/span><span class=\"o\">=<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">{&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}<\/span>\n<\/span><span><span class=\"go\">3 &lt;class &#39;dict&#39;&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course, we can pass a dictionary&rsquo;s data as keyword arguments to a function using similar syntax.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">kw_args<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">construct<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">kw_args<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">{&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}<\/span>\n<\/span><span><span class=\"go\">3 &lt;class &#39;dict&#39;&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"namespaces\">Namespaces<a class=\"headerlink\" href=\"#namespaces\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <code>globals<\/code> builtin function gives a dictionary of all names and their values in the current\nglobal namespace. We can modify this dictionary to define new names or delete existing ones,\nalthough that&rsquo;s probably a bad idea.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"nb\">globals<\/span><span class=\"p\">())<\/span>\n<\/span><span><span class=\"go\">25<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">globals<\/span><span class=\"p\">()[<\/span><span class=\"s1\">&#39;x&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">123<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">x<\/span>\n<\/span><span><span class=\"go\">123<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">del<\/span> <span class=\"nb\">globals<\/span><span class=\"p\">()[<\/span><span class=\"s1\">&#39;x&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">x<\/span>\n<\/span><span><span class=\"gt\">Traceback (most recent call last):<\/span>\n<\/span><span>  File <span class=\"nb\">&quot;&lt;stdin&gt;&quot;<\/span>, line <span class=\"m\">1<\/span>, in <span class=\"n\">&lt;module&gt;<\/span>\n<\/span><span><span class=\"gr\">NameError<\/span>: <span class=\"n\">name &#39;x&#39; is not defined<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>locals<\/code> builtin returns a dictionary of names and values from the local scope, for e.g., the\nprivate local scope inside of a function or method.<\/p>\n<p>The <code>vars<\/code> builtin takes an object as an argument and returns the names available as properties on\nthis objects. Specifically, it returns the <code>__dict__<\/code> property&rsquo;s value of the given object. When\ncalled without any arguments, then it returns names and values from the local scope. In other words,\n<code>vars() is locals()<\/code> return <code>True<\/code>.<\/p>\n<h2 id=\"serialization\">Serialization<a class=\"headerlink\" href=\"#serialization\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Dictionaries, being key&ndash;value data structures, extend naturally to be stored into key&ndash;value\ndatabases and other NoSQL data stores. However, here we&rsquo;ll look at forms of serializing them into\ntext and binary forms for transmission or for saving to disk.<\/p>\n<h3 id=\"json\">JSON<a class=\"headerlink\" href=\"#json\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Nowadays, the thought of serializing a python dictionary is usually followed by using the\n<a href=\"https:\/\/docs.python.org\/3\/library\/json.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>json<\/code><\/a> module to <a href=\"https:\/\/docs.python.org\/3\/library\/json.html#json.dump\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dump<\/code><\/a> and <a href=\"https:\/\/docs.python.org\/3\/library\/json.html#json.load\" rel=\"noopener noreferrer\" target=\"_blank\"><code>load<\/code><\/a> using the <a href=\"http:\/\/json.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">JSON\nformat<\/a>. No surprise since it&rsquo;s extremely convenient and there&rsquo;s quality parsers and writers\nfor almost every programming language today. The syntax as well, although not too convenient to\nwrite by hand, is still very simple, lightweight and easy to read. It helps that the syntax is quite\nclose to Python&rsquo;s own syntax for dictionaries.<\/p>\n<p>Here&rsquo;s a quick example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">json<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">country_currencies<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">&#39;{&quot;India&quot;: &quot;Rupee&quot;, &quot;Russia&quot;: &quot;Ruble&quot;, &quot;USA&quot;: &quot;Dollar&quot;, &quot;Japan&quot;: &quot;Yen&quot;}&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">country_currencies<\/span><span class=\"p\">))<\/span> <span class=\"o\">==<\/span> <span class=\"n\">country_currencies<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In short, these four functions from <code>json<\/code> module are enough to know the basic usage.<\/p>\n<div class=\"table-wrapper\">\n<table>\n<thead>\n<tr>\n<th>Method<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>.dump(obj, fp)<\/code><\/td>\n<td>Turn <code>obj<\/code> into JSON and write it to the <code>fp<\/code> file-like object.<\/td>\n<\/tr>\n<tr>\n<td><code>.dumps(obj)<\/code><\/td>\n<td>Turn <code>obj<\/code> into JSON and return the resulting string.<\/td>\n<\/tr>\n<tr>\n<td><code>.load(fp)<\/code><\/td>\n<td>Read valid JSON from <code>fp<\/code> file-like object and return the resulting object.<\/td>\n<\/tr>\n<tr>\n<td><code>.loads(data)<\/code><\/td>\n<td>Parse <code>data<\/code> as a valid JSON string and return the resulting object.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>As convenient as this is, it is important to know the changes to data types that will result because\nof this. JSON only supports numbers, strings and booleans as primary data types and arrays &amp; maps as\nanalogues to <code>list<\/code>s and <code>dict<\/code>s. As a result of this, if there are tuples somewhere in the\ndictionary, then they will be turned into lists when the <code>dict<\/code> is serialized and deserialized with\nJSON. A similar situation occurs for dates and any other data type not directly supported by the\nJSON spec.<\/p>\n<h3 id=\"pickling\">Pickling<a class=\"headerlink\" href=\"#pickling\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Unlike the above, pickling (using the <a href=\"https:\/\/docs.python.org\/3\/library\/pickle.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>pickle<\/code><\/a> module) serializes objects into binary\ndata and can handle a much wider range of data types. For this reason, pickled data can only be\nloaded by Python, not other languages (well, not yet at least).<\/p>\n<p>The <code>pickle<\/code> module has similar <code>dump<\/code>, <code>dumps<\/code>, <code>load<\/code> and <code>loads<\/code> methods just like for the above\ndiscussed <code>json<\/code> module.<\/p>\n<h2 id=\"the-item-syntax\">The Item Syntax<a class=\"headerlink\" href=\"#the-item-syntax\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The syntax used to get an item from a dictionary, given it&rsquo;s index, is <code>data[key]<\/code>. This is mostly\nequivalent to calling the <code>__getitem__<\/code> method, like the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"fm\">__getitem__<\/span><span class=\"p\">(<\/span><span class=\"n\">key<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>But obviously, we&rsquo;d prefer the square bracket syntax. But understanding that underneath the syntax,\nit&rsquo;s just a method call, lets us implement the <code>__getitem__<\/code> method in our own classes and get the\nitem syntax on our objects.<\/p>\n<p>Here&rsquo;s a simple example:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"k\">class<\/span> <span class=\"nc\">Store<\/span><span class=\"p\">:<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"k\">def<\/span> <span class=\"fm\">__getitem__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">):<\/span>\n<\/span><span><span class=\"gp\">... <\/span>            <span class=\"k\">return<\/span> <span class=\"n\">name<\/span><span class=\"o\">.<\/span><span class=\"n\">upper<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">...<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">store<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Store<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">store<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;Hello there!&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">&#39;HELLO THERE!&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Similar to this is the <code>__setitem__<\/code> which is used to set the value using the item syntax.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"c1\"># The following two are equivalent.<\/span>\n<\/span><span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"n\">key<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n<\/span><span><span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"fm\">__setitem__<\/span><span class=\"p\">(<\/span><span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that this should be used responsibly. This feature gets into borderline operator overloading\ncategory. In almost all cases (including the above example), using a normal named method on your\nclasses should be a better option than overriding the item syntax. Since a normal method would have\na name which makes the intent clearer.<\/p>\n<h2 id=\"flavors\">Flavors<a class=\"headerlink\" href=\"#flavors\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Python&rsquo;s standard library comes with a few flavors of dictionaries that provide some nice additional\nfunctionality. These data structures are all available in the <a href=\"https:\/\/docs.python.org\/3\/library\/collections.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>collections<\/code><\/a> module.<\/p>\n<p>The following are subclasses of <code>dict<\/code> and have all the features of Python&rsquo;s dictionaries.<\/p>\n<h3 id=\"the-ordereddict\">The <code>OrderedDict<\/code><a class=\"headerlink\" href=\"#the-ordereddict\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <a href=\"https:\/\/docs.python.org\/3\/library\/collections.html#collections.OrderedDict\" rel=\"noopener noreferrer\" target=\"_blank\"><code>collections.OrderedDict<\/code><\/a> is a dictionary that remembers the order in which keys\nare <em>inserted<\/em>. The order remembered is the <em>insertion<\/em> order. So, if we add a new key to the dict,\nit will be at the end of the key sequence. But if we change the value of an existing key, it&rsquo;s\nposition in the ordering is unchanged.<\/p>\n<p>Create a new <code>OrderedDict<\/code>:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">OrderedDict<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">planet_satellites<\/span> <span class=\"o\">=<\/span> <span class=\"n\">OrderedDict<\/span><span class=\"p\">(<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Mercury<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Venus<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Earth<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Mars<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Jupiter<\/span><span class=\"o\">=<\/span><span class=\"mi\">69<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Saturn<\/span><span class=\"o\">=<\/span><span class=\"mi\">62<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Uranus<\/span><span class=\"o\">=<\/span><span class=\"mi\">27<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span>    <span class=\"n\">Neptune<\/span><span class=\"o\">=<\/span><span class=\"mi\">14<\/span><span class=\"p\">,<\/span>\n<\/span><span><span class=\"gp\">... <\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">from<\/span> <span class=\"nn\">pprint<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pprint<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">planet_satellites<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">OrderedDict([(&#39;Mercury&#39;, 0),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Venus&#39;, 0),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Earth&#39;, 1),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Mars&#39;, 2),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Jupiter&#39;, 69),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Saturn&#39;, 62),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Uranus&#39;, 27),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Neptune&#39;, 14)])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Note that we use the <a href=\"https:\/\/docs.python.org\/3\/library\/pprint.html#pprint.pprint\" rel=\"noopener noreferrer\" target=\"_blank\"><code>pprint<\/code><\/a> function to show the <code>OrderedDict<\/code> objects in a convenient\nway.<\/p>\n<p>They are just dictionaries under the hood.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">planet_satellites<\/span><span class=\"p\">,<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">True<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">planet_satellites<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;Mars&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">2<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>These objects support being reversed as well:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">rev_planets<\/span> <span class=\"o\">=<\/span> <span class=\"n\">OrderedDict<\/span><span class=\"p\">(<\/span><span class=\"nb\">reversed<\/span><span class=\"p\">(<\/span><span class=\"n\">planet_satellites<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">()))<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">pprint<\/span><span class=\"p\">(<\/span><span class=\"n\">rev_planets<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"go\">OrderedDict([(&#39;Neptune&#39;, 14),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Uranus&#39;, 27),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Saturn&#39;, 62),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Jupiter&#39;, 69),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Mars&#39;, 2),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Earth&#39;, 1),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Venus&#39;, 0),<\/span>\n<\/span><span><span class=\"go\">             (&#39;Mercury&#39;, 0)])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The results of <code>.keys<\/code> and <code>.values<\/code> methods also retain the ordering. Refer to the official\ndocumentation linked above for full details.<\/p>\n<h3 id=\"the-defaultdict\">The <code>defaultdict<\/code><a class=\"headerlink\" href=\"#the-defaultdict\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p class=\"note\">The name <code>defaultdict<\/code> is unfortunate as it doesn&rsquo;t adhere to any naming conventions. I&rsquo;d love to\nsee it renamed to <code>default_dict<\/code> or even <code>DefaultDict<\/code>, but it&rsquo;s probably easier to just live with\nit.<\/p>\n<p>A <code>defaultdict<\/code> can understand how to initialize new keys. Consider the following code. Here, we\nhave a piece of text and we want a dictionary mapping each letter in the text to it&rsquo;s count of\noccurrences.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;lorem ipsum dolor sit amet&#39;<\/span>\n<\/span><span><span class=\"n\">counts<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">letter<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">text<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"n\">letter<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">counts<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">counts<\/span><span class=\"p\">[<\/span><span class=\"n\">letter<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n<\/span><span>    <span class=\"n\">counts<\/span><span class=\"p\">[<\/span><span class=\"n\">letter<\/span><span class=\"p\">]<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">counts<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p class=\"note\">Of course, there&rsquo;s better ways to do this, but for the sake of example, let&rsquo;s bear with this\nimplementation.<\/p>\n<p>Notice how we check if the letter is not already present in the dict and if so, we initialize it to\nzero. A <code>defaultdict<\/code> can learn this method of initialization. It takes a function as its first\nargument which returns the value of a new key when accessed. So, we can replace the above code to\nuse <code>defaultdict<\/code> like:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">defaultdict<\/span>\n<\/span><span><span class=\"n\">text<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;lorem ipsum dolor sit amet&#39;<\/span>\n<\/span><span><span class=\"n\">counts<\/span> <span class=\"o\">=<\/span> <span class=\"n\">defaultdict<\/span><span class=\"p\">(<\/span><span class=\"nb\">int<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">letter<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">text<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"n\">counts<\/span><span class=\"p\">[<\/span><span class=\"n\">letter<\/span><span class=\"p\">]<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">counts<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>When we try to get the value of a letter from <code>counts<\/code>, and that letter doesn&rsquo;t already exist in\n<code>counts<\/code>, <code>defaultdict<\/code> will call <code>int<\/code>, with no arguments, and puts the return value into\n<code>counts[letter]<\/code>. Precisely what we were doing in our previous example. So, what does <code>int<\/code> return\nwhen called with no arguments? You guessed it, zero!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">int<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">0<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">float<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">0.0<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">str<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">&#39;&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">bool<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">False<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">list<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">[]<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">dict<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">{}<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">set<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"go\">set()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>As illustrated above, calling the data type builtins with no arguments return the falsy value of\nthat data type. We can use this fact and pass these builtins to <code>defaultdict<\/code> constructor depending\non the need. If we wanted a different initial value, say <code>42<\/code>, we could use a lambda function like\n<code>lambda: 42<\/code> instead.<\/p>\n<h3 id=\"the-chainmap\">The <code>ChainMap<\/code><a class=\"headerlink\" href=\"#the-chainmap\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The <code>ChainMap<\/code> is an abstraction over a chain of dictionaries in order of precedence. Essentially,\nit holds a list of dictionaries and when a key is indexed, each of these dictionaries are searched\nfor this key and the value of the first match is returned.<\/p>\n<p>This is better illustrated with an example. Let&rsquo;s create a <code>ChainMap<\/code> with dummy data:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ChainMap<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ChainMap<\/span><span class=\"p\">({<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">3<\/span><span class=\"p\">},<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">30<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;d&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">40<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;e&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">50<\/span><span class=\"p\">})<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span>\n<\/span><span><span class=\"go\">ChainMap({&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}, {&#39;c&#39;: 30, &#39;d&#39;: 40, &#39;e&#39;: 50})<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"n\">maps<\/span>  <span class=\"c1\"># A list of maps in the chain.<\/span>\n<\/span><span><span class=\"go\">[{&#39;a&#39;: 1, &#39;b&#39;: 2, &#39;c&#39;: 3}, {&#39;c&#39;: 30, &#39;d&#39;: 40, &#39;e&#39;: 50}]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Let&rsquo;s try indexing:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">1<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;e&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">50<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">3<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, the <code>'a'<\/code> is indexed from the first dictionary, <code>'e'<\/code> is indexed from the second dictionary\nand <code>'c'<\/code> is indexed from the first dictionary.<\/p>\n<p>As mentioned in the documentation, writes, updates and deletes, however, operate on the first\ndictionary alone.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">91<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span>\n<\/span><span><span class=\"go\">ChainMap({&#39;a&#39;: 91, &#39;b&#39;: 2, &#39;c&#39;: 3}, {&#39;c&#39;: 30, &#39;d&#39;: 40, &#39;e&#39;: 50})<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;e&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">951<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span>\n<\/span><span><span class=\"go\">ChainMap({&#39;a&#39;: 91, &#39;b&#39;: 2, &#39;c&#39;: 3, &#39;e&#39;: 951}, {&#39;c&#39;: 30, &#39;d&#39;: 40, &#39;e&#39;: 50})<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">93<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span>\n<\/span><span><span class=\"go\">ChainMap({&#39;a&#39;: 91, &#39;b&#39;: 2, &#39;c&#39;: 93, &#39;e&#39;: 951}, {&#39;c&#39;: 30, &#39;d&#39;: 40, &#39;e&#39;: 50})<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course, if we explicitly want to modify the last dictionary, it can be indexed directly:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"o\">.<\/span><span class=\"n\">maps<\/span><span class=\"p\">[<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">][<\/span><span class=\"s1\">&#39;c&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">999<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span>\n<\/span><span><span class=\"go\">ChainMap({&#39;a&#39;: 91, &#39;b&#39;: 2, &#39;c&#39;: 93, &#39;e&#39;: 951}, {&#39;c&#39;: 999, &#39;d&#39;: 40, &#39;e&#39;: 50})<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The <code>ChainMap<\/code> is useful to hold tiers of configuration parameters for an application, in a form\nsimilar to the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">ChainMap<\/span><span class=\"p\">(<\/span><span class=\"n\">user_settings<\/span><span class=\"p\">,<\/span> <span class=\"n\">default_settings<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We can have multiple tiers depending the situation. The user can modify the dictionary as they fit\nand all writes and updates will be made only on the first dictionary, <code>user_settings<\/code>. Whereas, when\none tries to get the value of a configuration parameter, it automatically falls back to\n<code>default_settings<\/code> if it isn&rsquo;t present in <code>user_settings<\/code>.<\/p>\n<h3 id=\"the-counter\">The <code>Counter<\/code><a class=\"headerlink\" href=\"#the-counter\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p><code>Counter<\/code> dictionaries can be used to keep counts of any (hashable) objects. The keys are these\nhashable objects and the values are their counts. The <a href=\"https:\/\/docs.python.org\/3\/library\/collections.html#collections.Counter\" rel=\"noopener noreferrer\" target=\"_blank\">official docs<\/a> on this gives some\nclever examples and uses so I recommend you go read this up there, instead of redoing it here.<\/p>\n<h3 id=\"custom-flavor\">Custom Flavor<a class=\"headerlink\" href=\"#custom-flavor\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Although rarely needed in practice, we can create our own flavors of dictionary types. One way to\nachieve this would be to extend the <code>dict<\/code> type directly, but usually the easier way to deal with\nthis is to use the <a href=\"https:\/\/docs.python.org\/3\/library\/collections.html#collections.UserDict\" rel=\"noopener noreferrer\" target=\"_blank\"><code>UserDict<\/code><\/a> class.<\/p>\n<p>Here&rsquo;s an example dictionary type that works with string keys and is case-insensitive. A good use\nfor something like this is for HTTP headers. (The <a href=\"http:\/\/docs.python-requests.org\/en\/master\/\" rel=\"noopener noreferrer\" target=\"_blank\">requests<\/a> library does <a href=\"https:\/\/github.com\/requests\/requests\/blob\/master\/requests\/structures.py\" rel=\"noopener noreferrer\" target=\"_blank\">something\nsimilar<\/a>.)<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">collections<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">UserDict<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">class<\/span> <span class=\"nc\">CaselessDict<\/span><span class=\"p\">(<\/span><span class=\"n\">UserDict<\/span><span class=\"p\">):<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__getitem__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"n\">name<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()]<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">def<\/span> <span class=\"fm\">__setitem__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">):<\/span>\n<\/span><span>        <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"n\">name<\/span><span class=\"o\">.<\/span><span class=\"n\">lower<\/span><span class=\"p\">()]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>As seen above, the <code>UserDict<\/code> class provides a <code>.data<\/code> attribute that can be used as the underlying\nstore dictionary.<\/p>\n<p>Let&rsquo;s try it out.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CaselessDict<\/span><span class=\"p\">(<\/span><span class=\"n\">accept<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;application\/json&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;accept&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">&#39;application\/json&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;Accept&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">&#39;application\/json&#39;<\/span>\n<\/span><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;ACCEPT&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"go\">&#39;application\/json&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"disassembling\">Disassembling<a class=\"headerlink\" href=\"#disassembling\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Now, let&rsquo;s disassemble a few common operations on dictionaries. I won&rsquo;t be going into the details of\nhow to interpret the disassembled instructions in this article. We use the <a href=\"https:\/\/docs.python.org\/3\/library\/dis.html#dis.dis\" rel=\"noopener noreferrer\" target=\"_blank\"><code>dis<\/code><\/a> function\n(from the aptly named <code>dis<\/code> module) for this.<\/p>\n<p>Let&rsquo;s try this a very simple function.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">dis<\/span><span class=\"o\">.<\/span><span class=\"n\">dis<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">})<\/span>\n<\/span><span><span class=\"go\">  1           0 LOAD_CONST               1 (&#39;a&#39;)<\/span>\n<\/span><span><span class=\"go\">              2 LOAD_CONST               2 (1)<\/span>\n<\/span><span><span class=\"go\">              4 BUILD_MAP                1<\/span>\n<\/span><span><span class=\"go\">              6 RETURN_VALUE<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, we see the <a href=\"https:\/\/docs.python.org\/3\/library\/dis.html#opcode-BUILD_MAP\" rel=\"noopener noreferrer\" target=\"_blank\"><code>BUILD_MAP<\/code><\/a> opcode that takes a count which is the length of the\ndictionary to build. From the official docs,<\/p>\n<blockquote>\n<p>Pushes a new dictionary object onto the stack. Pops <code>2 * count<\/code> items so that the dictionary holds\n<em>count<\/em> entries: <code>{..., TOS3: TOS2, TOS1: TOS}<\/code>.<\/p>\n<\/blockquote>\n<p>Now let&rsquo;s do this with two elements in the dict.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">dis<\/span><span class=\"o\">.<\/span><span class=\"n\">dis<\/span><span class=\"p\">(<\/span><span class=\"k\">lambda<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span><span class=\"s1\">&#39;a&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;b&#39;<\/span><span class=\"p\">:<\/span> <span class=\"mi\">2<\/span><span class=\"p\">})<\/span>\n<\/span><span><span class=\"go\">  1           0 LOAD_CONST               1 (1)<\/span>\n<\/span><span><span class=\"go\">              2 LOAD_CONST               2 (2)<\/span>\n<\/span><span><span class=\"go\">              4 LOAD_CONST               3 ((&#39;a&#39;, &#39;b&#39;))<\/span>\n<\/span><span><span class=\"go\">              6 BUILD_CONST_KEY_MAP      2<\/span>\n<\/span><span><span class=\"go\">              8 RETURN_VALUE<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, we see a different opcode, <a href=\"https:\/\/docs.python.org\/3\/library\/dis.html#opcode-BUILD_CONST_KEY_MAP\" rel=\"noopener noreferrer\" target=\"_blank\"><code>BUILD_CONST_KEY_MAP<\/code><\/a> which also takes the\nlength of the dict as an argument. This is also explained best from the docs,<\/p>\n<blockquote>\n<p>The version of <code>BUILD_MAP<\/code> specialized for constant keys. <em>count<\/em> values are consumed from the\nstack. The top element on the stack contains a tuple of keys.<\/p>\n<\/blockquote>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Dictionaries in Python (or any other language for that matter) are a very powerful multi-purpose\ndata structure and are extremely handy and easy to use in Python. I hoped to put the things I\nlearned about them in this article. If you see any inaccuracies or if there&rsquo;s something that makes\nfor a good addition to this article, let me know in the comments below.<\/p>\n<p>Thank you for reading. Please let me know what you think. If you have any topics you&rsquo;d like me to\ncover in a future article, put in a comment.<\/p>\n<h2 id=\"references\">References<a class=\"headerlink\" href=\"#references\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The official documentation, mostly. Wikipedia for data used in examples.<\/p>\n<div class=\"footnote\">\n<hr>\n<ol>\n<li id=\"fn:1\">\n<p>I read the proof for this a long time ago, but I don&rsquo;t remember where :).&#160;<a class=\"footnote-backref\" href=\"#fnref:1\" title=\"Jump back to footnote 1 in the text\">&#8617;<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"data-structures"}},{"@attributes":{"term":"reference"}}]},{"title":"Migrate from Pelican to Hugo","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/migrate-from-pelican-to-hugo\/","rel":"alternate"}},"published":"2017-08-23T00:00:00+05:30","updated":"2017-08-23T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2017-08-23:\/posts\/migrate-from-pelican-to-hugo\/","summary":"<p class=\"note\"><strong>Update:<\/strong> I have now moved to using a self-made Python program that compiles my markdown article\ndocuments into the website you see. I&rsquo;m keeping this article as a journal of my then experience.<\/p>\n<p>I recently got around to resurrecting my blog up after around five years of death. As \u2026<\/p>","content":"<p class=\"note\"><strong>Update:<\/strong> I have now moved to using a self-made Python program that compiles my markdown article\ndocuments into the website you see. I&rsquo;m keeping this article as a journal of my then experience.<\/p>\n<p>I recently got around to resurrecting my blog up after around five years of death. As part of that,\nI chose to migrate my blog to Hugo, from the current Pelican builder. The first post after\nresurrection will be about the migration.<\/p>\n<p>If you&rsquo;re wondering why the long break, well, I could blame it on life and work, but it was just me\nbeing lazy. Hopefully, that won&rsquo;t happen again.<\/p>\n<h2 id=\"why-hugo\">Why Hugo<a class=\"headerlink\" href=\"#why-hugo\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>When I decided to start writing again, I couldn&rsquo;t remember who I was building the site. That&rsquo;s\nprobably entirely my fault for not documenting it for myself, but I ended up being almost new to\nPelican. So, instead of directly going to Pelican&rsquo;s homepage, I checked out\n<a href=\"https:\/\/www.staticgen.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">StaticGen<\/a> to see the current landscape of static site generators. The\nmost popular (measure by GitHub stars) is obvious, Jekyll. Then came <a href=\"https:\/\/gohugo.io\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo<\/a>, a\nname I didn&rsquo;t recognize. Other than Pelican, all the ones in the top-ten are built on Ruby or\nJavaScript (node.js). I wasn&rsquo;t keen on either. Hugo was in a unique position since it is written in\na compiled language, so multiplatform binaries are relatively easy to come by.<\/p>\n<p>I read the documentation on a weekend and I was impressed. Hugo it is. The thing that struck me most\nin Hugo is that it does it&rsquo;s primary thing only. Generating HTML files from Markdown files. It\ndoesn&rsquo;t force a blog-like website or a documentation-like website. That&rsquo;s up to you. Hugo is like a\nbridge between your markdown files and the output HTML files. The structure of the output is a\nmirror image of your source files and the <code>config.toml<\/code> file (or <code>config.yaml<\/code>).<\/p>\n<h2 id=\"migration\">Migration<a class=\"headerlink\" href=\"#migration\" title=\"Permanent link\">&para;<\/a><\/h2>\n<h3 id=\"a-new-site\">A new site<a class=\"headerlink\" href=\"#a-new-site\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Issued the command <code>hugo new site sharats.me<\/code>.<\/p>\n<h3 id=\"configuration\">Configuration<a class=\"headerlink\" href=\"#configuration\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Hugo&rsquo;s default configuration is of the <a href=\"https:\/\/github.com\/toml-lang\/toml\" rel=\"noopener noreferrer\" target=\"_blank\">TOML<\/a> format. I read the\nREADME and wasn&rsquo;t convinced. Thankfully, Hugo supports configuration in <a href=\"http:\/\/yaml.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">YAML<\/a>.<\/p>\n<p>So, this is what I came up with in my <code>config.yaml<\/code> file.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nt\">baseURL<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">http:\/\/sharats.me\/<\/span>\n<\/span><span><span class=\"nt\">languageCode<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">en-us<\/span>\n<\/span><span><span class=\"nt\">title<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;The<\/span><span class=\"nv\"> <\/span><span class=\"s\">Sharat&#39;s&quot;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The current <code>config.yaml<\/code> is much longer and can be viewed on the github repo of this site.<\/p>\n<h3 id=\"change-metadata-format\">Change metadata format<a class=\"headerlink\" href=\"#change-metadata-format\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The article metadata in my Pelican site looks like the following:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nt\">Title<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">Serializing python-requests&#39; Session objects for fun and profit<\/span>\n<\/span><span><span class=\"nt\">Date<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">18.2.2012<\/span>\n<\/span><span><span class=\"nt\">Tags<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">python, python-requests, python-pickle<\/span>\n<\/span><span><span class=\"nt\">Reddit<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">true<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There&rsquo;s a lot of things in this that I wouldn&rsquo;t do if I wrote that article today, but meh.<\/p>\n<p>Hugo calls these <em>frontmatter<\/em> and I needed it to look like the following to make it happy.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nn\">---<\/span>\n<\/span><span><span class=\"nt\">title<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">Serializing python-requests&#39; Session objects for fun and profit<\/span>\n<\/span><span><span class=\"nt\">date<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">2012-02-18<\/span>\n<\/span><span><span class=\"nt\">tags<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s\">&#39;python&#39;<\/span><span class=\"err\">,<\/span><span class=\"w\"> <\/span><span class=\"s\">&#39;python-requests&#39;<\/span><span class=\"err\">,<\/span><span class=\"w\"> <\/span><span class=\"s\">&#39;python-pickle&#39;<\/span>\n<\/span><span><span class=\"nt\">reddit<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"l l-Scalar l-Scalar-Plain\">true<\/span>\n<\/span><span><span class=\"nn\">---<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The following <code>awk<\/code> script did the trick:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">BEGIN<\/span> <span class=\"p\">{<\/span> <span class=\"nb\">FS<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;:&quot;<\/span><span class=\"p\">;<\/span> <span class=\"nb\">OFS<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot;:&quot;<\/span><span class=\"p\">;<\/span> <span class=\"kr\">print<\/span> <span class=\"s2\">&quot;---&quot;<\/span> <span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"o\">!<\/span><span class=\"nx\">c<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"sr\">\/^$\/<\/span> <span class=\"p\">{<\/span> <span class=\"kr\">print<\/span> <span class=\"s2\">&quot;---\\n&quot;<\/span><span class=\"p\">;<\/span> <span class=\"nx\">c<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span> <span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"nx\">c<\/span> <span class=\"p\">{<\/span> <span class=\"kr\">print<\/span><span class=\"p\">;<\/span> <span class=\"kr\">next<\/span> <span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span><span class=\"o\">!<\/span><span class=\"nx\">c<\/span> <span class=\"p\">{<\/span>\n<\/span><span>    <span class=\"o\">$<\/span><span class=\"mi\">1<\/span> <span class=\"o\">=<\/span> <span class=\"kr\">tolower<\/span><span class=\"p\">(<\/span><span class=\"o\">$<\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">$<\/span><span class=\"mi\">1<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;date&quot;<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n<\/span><span>        <span class=\"o\">$<\/span><span class=\"mi\">2<\/span> <span class=\"o\">=<\/span> <span class=\"kr\">gensub<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/ ([^.]+)\\.([^.]+).([^.]+)\/<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot; \\\\3-\\\\2-\\\\1&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"o\">$<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"o\">$<\/span><span class=\"mi\">2<\/span> <span class=\"o\">=<\/span> <span class=\"kr\">gensub<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/-([0-9])-\/<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;-0\\\\1-&quot;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"o\">$<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"p\">}<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">$<\/span><span class=\"mi\">1<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">&quot;tags&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span>        <span class=\"o\">$<\/span><span class=\"mi\">2<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">&quot; [&quot;<\/span> <span class=\"kr\">gensub<\/span><span class=\"p\">(<\/span><span class=\"sr\">\/[-a-z]+\/<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;&#39;\\\\0&#39;&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;g&quot;<\/span><span class=\"p\">,<\/span> <span class=\"kr\">substr<\/span><span class=\"p\">(<\/span><span class=\"o\">$<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">))<\/span> <span class=\"s2\">&quot;]&quot;<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"kr\">print<\/span>\n<\/span><span><span class=\"p\">}<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"change-code-blocks\">Change code blocks<a class=\"headerlink\" href=\"#change-code-blocks\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>All my code blocks were of the following format:<\/p>\n<div class=\"hl\"><pre class=content><code><span>    :::python\n<\/span><span>    import this\n<\/span><\/code><\/pre><\/div>\n\n<p>But, I needed them like this:<\/p>\n<div class=\"hl\"><pre class=content><code><span>```python\n<\/span><span>import this\n<\/span><span>```\n<\/span><\/code><\/pre><\/div>\n\n<p>So, the following little python script did the trick:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-2><label for=co-2><span class='btn show-full-code-btn'>Show remaining 17 lines<\/span><\/label><pre class=linenos><span>1\n<\/span><span>2\n<\/span><span>3\n<\/span><span>4\n<\/span><span>5\n<\/span><span>6\n<\/span><span>7\n<\/span><span>8\n<\/span><span>9\n<\/span><span>10\n<\/span><span>11\n<\/span><span>12\n<\/span><span>13\n<\/span><span>14\n<\/span><span>15\n<\/span><span>16\n<\/span><span>17\n<\/span><span>18\n<\/span><span>19\n<\/span><span>20\n<\/span><span class=collapse>21\n<\/span><span class=collapse>22\n<\/span><span class=collapse>23\n<\/span><span class=collapse>24\n<\/span><span class=collapse>25\n<\/span><span class=collapse>26\n<\/span><span class=collapse>27\n<\/span><span class=collapse>28\n<\/span><span class=collapse>29\n<\/span><span class=collapse>30\n<\/span><span class=collapse>31\n<\/span><span class=collapse>32\n<\/span><span class=collapse>33\n<\/span><span class=collapse>34\n<\/span><span class=collapse>35\n<\/span><span class=collapse>36\n<\/span><span class=collapse>37\n<\/span><\/pre><pre class=content><code><span><span class=\"ch\">#!\/usr\/bin\/env python3<\/span>\n<\/span><span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">sys<\/span>\n<\/span><span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">process<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">cb<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">False<\/span>\n<\/span><span>    <span class=\"n\">empties<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n<\/span><span>    <span class=\"n\">output<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">line<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"o\">.<\/span><span class=\"n\">rstrip<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>        <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">line<\/span><span class=\"p\">:<\/span>\n<\/span><span>            <span class=\"n\">empties<\/span> <span class=\"o\">+=<\/span> <span class=\"mi\">1<\/span>\n<\/span><span>            <span class=\"k\">continue<\/span>\n<\/span><span>\n<\/span><span>        <span class=\"n\">prefix<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;&#39;<\/span>\n<\/span><span>        <span class=\"k\">if<\/span> <span class=\"n\">line<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;    &#39;<\/span><span class=\"p\">):<\/span>\n<\/span><span>            <span class=\"n\">line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"p\">[<\/span><span class=\"mi\">4<\/span><span class=\"p\">:]<\/span>\n<\/span><span>            <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">cb<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>                <span class=\"n\">cb<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">True<\/span>\n<\/span><span class=collapse>                <span class=\"n\">line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">line<\/span><span class=\"o\">.<\/span><span class=\"n\">replace<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;:::&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;```&#39;<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span> <span class=\"k\">if<\/span> <span class=\"n\">line<\/span><span class=\"o\">.<\/span><span class=\"n\">startswith<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;:::&#39;<\/span><span class=\"p\">)<\/span> <span class=\"k\">else<\/span> <span class=\"p\">(<\/span><span class=\"s1\">&#39;```<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">+<\/span> <span class=\"n\">line<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>        <span class=\"k\">elif<\/span> <span class=\"n\">cb<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>            <span class=\"n\">cb<\/span> <span class=\"o\">=<\/span> <span class=\"kc\">False<\/span>\n<\/span><span class=collapse>            <span class=\"n\">prefix<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;```<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>        <span class=\"n\">output<\/span><span class=\"o\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">prefix<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span> <span class=\"o\">*<\/span> <span class=\"n\">empties<\/span> <span class=\"o\">+<\/span> <span class=\"n\">line<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"n\">empties<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>    <span class=\"k\">return<\/span> <span class=\"s1\">&#39;<\/span><span class=\"se\">\\n<\/span><span class=\"s1\">&#39;<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">output<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"k\">for<\/span> <span class=\"n\">file_name<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">sys<\/span><span class=\"o\">.<\/span><span class=\"n\">argv<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">:]:<\/span>\n<\/span><span class=collapse>    <span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"n\">file_name<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">f<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>        <span class=\"n\">output<\/span> <span class=\"o\">=<\/span> <span class=\"n\">process<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">output<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Yeah, didn&rsquo;t have the patience to do it with <code>awk<\/code> this time.<\/p>\n<h2 id=\"the-theme\">The Theme<a class=\"headerlink\" href=\"#the-theme\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I tried the themes over at the <a href=\"http:\/\/themes.gohugo.io\/\" rel=\"noopener noreferrer\" target=\"_blank\">Hugo themes page<\/a>, but just as I thought,\nnone of them were to my liking. I found the <strong>nofancy<\/strong> theme to be easy to get started and modify\nto what I want, so that&rsquo;s what happened. Hugo&rsquo;s documentation is very good. I have to say, the\ndocumentation is one of the reasons I&rsquo;m loving Hugo.<\/p>\n<p>Hope to be writing more articles in the coming weeks.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"hugo"}},{"@attributes":{"term":"meta"}},{"@attributes":{"term":"awk"}},{"@attributes":{"term":"python"}}]},{"title":"The ever useful and neat subprocess module","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/the-ever-useful-and-neat-subprocess-module\/","rel":"alternate"}},"published":"2012-04-29T00:00:00+05:30","updated":"2012-04-29T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2012-04-29:\/posts\/the-ever-useful-and-neat-subprocess-module\/","summary":"<p>Python&rsquo;s <a href=\"http:\/\/docs.python.org\/library\/subprocess.html\" rel=\"noopener noreferrer\" target=\"_blank\">subprocess<\/a> module is one of my favourite modules in the standard library. If you have\never done some decent amount of coding in python, you might have encountered it. This module is used\nfor dealing with external commands, intended to be a replacement to the old <a href=\"http:\/\/docs.python.org\/library\/os.html#os.system\" rel=\"noopener noreferrer\" target=\"_blank\"><code>os.system \u2026<\/code><\/a><\/p>","content":"<p>Python&rsquo;s <a href=\"http:\/\/docs.python.org\/library\/subprocess.html\" rel=\"noopener noreferrer\" target=\"_blank\">subprocess<\/a> module is one of my favourite modules in the standard library. If you have\never done some decent amount of coding in python, you might have encountered it. This module is used\nfor dealing with external commands, intended to be a replacement to the old <a href=\"http:\/\/docs.python.org\/library\/os.html#os.system\" rel=\"noopener noreferrer\" target=\"_blank\"><code>os.system<\/code><\/a>\nand the like.<\/p>\n<p>The most trivial use might be to get the output of a small shell command like <code>ls<\/code> or <code>ps<\/code>. Not that\nthis is the best way to get a list of files in a directory (think <a href=\"http:\/\/docs.python.org\/library\/os.html#os.listdir\" rel=\"noopener noreferrer\" target=\"_blank\"><code>os.listdir<\/code><\/a>), but you\nget the point.<\/p>\n<p>I am going to put my notes and experiences about this module here. Please note, I wrote this with\nPython 2.7 in mind. Things <strong>are<\/strong> slightly different in other versions (even 2.6). If you find any\nerrors or suggestions, please let me know.<\/p>\n<div class=\"toc\"><span class=\"toctitle\">Table of Contents<\/span><ul>\n<li><a href=\"#a-simple-usage\">A simple usage<\/a><\/li>\n<li><a href=\"#popen-class\">Popen class<\/a><\/li>\n<li><a href=\"#running-via-the-shell\">Running via the shell<\/a><\/li>\n<li><a href=\"#getting-the-return-code-aka-exit-status\">Getting the return code (aka exit status)<\/a><\/li>\n<li><a href=\"#io-streams\">IO Streams<\/a><ul>\n<li><a href=\"#reading-error-stream\">Reading error stream<\/a><\/li>\n<li><a href=\"#watching-both-stdout-and-stderr\">Watching both stdout and stderr<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#passing-an-environment\">Passing an environment<\/a><ul>\n<li><a href=\"#merge-with-current-environment\">Merge with current environment<\/a><\/li>\n<li><a href=\"#unicode\">Unicode<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#execute-in-a-different-working-directory\">Execute in a different working directory<\/a><\/li>\n<li><a href=\"#killing-and-dying\">Killing and dying<\/a><ul>\n<li><a href=\"#auto-kill-on-death\">Auto-kill on death<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#launch-commands-in-a-terminal-emulator\">Launch commands in a terminal emulator<\/a><ul>\n<li><a href=\"#linux\">Linux<\/a><\/li>\n<li><a href=\"#windows\">Windows<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#conclusion\">Conclusion<\/a><\/li>\n<\/ul>\n<\/div>\n<h2 id=\"a-simple-usage\">A simple usage<a class=\"headerlink\" href=\"#a-simple-usage\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>For the sake of providing context, lets run the <code>ls<\/code> command from subprocess and get its output<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">subprocess<\/span>\n<\/span><span><span class=\"n\">ls_output<\/span> <span class=\"o\">=<\/span> <span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">check_output<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I&rsquo;ll cover getting output from a command in detail later. To give more command line arguments,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">check_output<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-l&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The first item in the list is the executable and rest are its command line arguments (<code>argv<\/code>\nequivalent). No quirky shell quoting and complex nested quote rules to digest. Just a plain python\nlist.<\/p>\n<p>However, not having shell quoting implies you don&rsquo;t also have the shell niceties. Like piping for\none. The following won&rsquo;t work the way one would expect it to.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">check_output<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;|&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;wc&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-l&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Here, the <code>ls<\/code> command gets its first command as <code>|<\/code> and I have no idea what ls would do with it.\nPerhaps complain that no such file exists. So, instead, we have to use the <code>shell<\/code> boolean argument.\nMore later down in the article.<\/p>\n<h2 id=\"popen-class\">Popen class<a class=\"headerlink\" href=\"#popen-class\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If there&rsquo;s just one thing in the subprocess module that you should be concerned with, its the\n<a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.Popen\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Popen<\/code><\/a> class. The other functions like <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>call<\/code><\/a>, <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.check_call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>check_output<\/code><\/a>, and\n<a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.check_call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>check_call<\/code><\/a> use <code>Popen<\/code> internally. Here&rsquo;s the signature from the docs.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">class<\/span> <span class=\"nc\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">,<\/span> <span class=\"n\">bufsize<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"n\">executable<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">stdin<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">stdout<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">stderr<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">preexec_fn<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">close_fds<\/span><span class=\"o\">=<\/span><span class=\"kc\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">shell<\/span><span class=\"o\">=<\/span><span class=\"kc\">False<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">cwd<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">env<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">universal_newlines<\/span><span class=\"o\">=<\/span><span class=\"kc\">False<\/span><span class=\"p\">,<\/span> <span class=\"n\">startupinfo<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">creationflags<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I suggest you read the docs for this class. As with all python docs, its really good.<\/p>\n<h2 id=\"running-via-the-shell\">Running via the shell<a class=\"headerlink\" href=\"#running-via-the-shell\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Subprocess can also run command-line instructions via a shell program. This is usually <code>dash<\/code>\/<code>bash<\/code>\non Linux and <code>cmd<\/code> on windows.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls | wc -l&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">shell<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice that in this case we pass a string, not a list. This is because we want the shell to\ninterpret the whole of our command. You can even use shell style quoting if you like. It is up to\nthe shell to decide how to best split the command line into executable and command line arguments.<\/p>\n<blockquote>\n<p>On windows, if you pass a list for args, it will be turned into a string using the same rules as\nthe MS C runtime. See the doc-string for <code>subprocess.list2cmdline<\/code> for more on this. Whereas on\nunix-like systems, even if you pass a string, its turned into a list of one item :).<\/p>\n<\/blockquote>\n<p>The behaviour of the <code>shell<\/code> argument can sometimes be confusing so I&rsquo;ll try to clear it a bit here.\nSomething I wished I had when I first encountered this module.<\/p>\n<p>Firstly, lets consider the case where <code>shell<\/code> is set to <code>False<\/code>, the default. In this case, if\n<code>args<\/code> is a string, it is assumed to be the name of the executable file. Even if it contains spaces.\nConsider the following.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls -l&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This won&rsquo;t work because subprocess is looking for an executable file called <code>ls -l<\/code>, but obviously\ncan&rsquo;t find it. However, if <code>args<\/code> is a list, then the first item in this list is considered as the\nexecutable and the rest of the items in the list are passed as command line arguments to the\nprogram.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-l&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>does what you think it will.<\/p>\n<p>Second case, with <code>shell<\/code> set to <code>True<\/code>, the program that actually gets executed is the OS default\nshell, <code>\/bin\/sh<\/code> on Linux and <code>cmd.exe<\/code> on windows. This can be changed with the <code>executable<\/code>\nargument.<\/p>\n<p>When using the shell, <code>args<\/code> is usually a string, something that will be parsed by the shell\nprogram. The <code>args<\/code> string is passed as a command line argument to the shell (with a <code>-c<\/code> option on\nLinux) such that the shell will interpret it as a shell command sequence and process it accordingly.\nThis means you can use all the shell builtins and goodies that your shell offers.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls -l&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">shell<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>is similar to<\/p>\n<div class=\"hl\"><pre class=content><code><span>$<span class=\"w\"> <\/span>\/bin\/sh<span class=\"w\"> <\/span>-c<span class=\"w\"> <\/span><span class=\"s1\">&#39;ls -l&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>In the same vein, if you pass a list as <code>args<\/code> with <code>shell<\/code> set to <code>True<\/code>, all items in the list are\npassed as command line arguments to the shell.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-l&#39;<\/span><span class=\"p\">],<\/span> <span class=\"n\">shell<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>is similar to<\/p>\n<div class=\"hl\"><pre class=content><code><span>$<span class=\"w\"> <\/span>\/bin\/sh<span class=\"w\"> <\/span>-c<span class=\"w\"> <\/span>ls<span class=\"w\"> <\/span>-l\n<\/span><\/code><\/pre><\/div>\n\n<p>which is the same as<\/p>\n<div class=\"hl\"><pre class=content><code><span>$<span class=\"w\"> <\/span>\/bin\/sh<span class=\"w\"> <\/span>-c<span class=\"w\"> <\/span>ls\n<\/span><\/code><\/pre><\/div>\n\n<p>since <code>\/bin\/sh<\/code> takes just the argument next to <code>-c<\/code> as the command line to execute.<\/p>\n<h2 id=\"getting-the-return-code-aka-exit-status\">Getting the return code (aka exit status)<a class=\"headerlink\" href=\"#getting-the-return-code-aka-exit-status\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If you want to run an external command and its return code is all you&rsquo;re concerned with, the\n<a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>call<\/code><\/a> and <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.check_call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>check_call<\/code><\/a> functions are what you&rsquo;re looking for. They both\nreturn the return code after running the command. The difference is, <code>check_call<\/code> raises a\n<code>CalledProcessError<\/code> if the return code is non-zero.<\/p>\n<p>If you&rsquo;ve read the docs for these functions, you&rsquo;ll see that its not recommended to use\n<code>stdout=PIPE<\/code> or <code>stderr=PIPE<\/code>. And if you don&rsquo;t, the <code>stdout<\/code> and <code>stderr<\/code> of the command are just\nredirected to the parent&rsquo;s (Python VM in this case) streams.<\/p>\n<p>If that is not what you want, you have to use the <code>Popen<\/code> class.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">proc<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The moment the <code>Popen<\/code> class is instantiated, the command starts running. You can wait for it and\nafter its done, access the return code via the <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.Popen.returncode\" rel=\"noopener noreferrer\" target=\"_blank\"><code>returncode<\/code><\/a> attribute.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">wait<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"nb\">print<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">returncode<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>If you are trying this out in a python REPL, you won&rsquo;t see a need to call <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.Popen.wait\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.wait()<\/code><\/a> since\nyou can just wait yourself in the REPL till the command is finished and then access the\n<code>returncode<\/code>. Surprise!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">proc<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">file1<\/span> <span class=\"n\">file2<\/span>\n<\/span><span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">print<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">returncode<\/span>\n<\/span><span><span class=\"kc\">None<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"c1\"># wat?<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The command is definitely finished. Why don&rsquo;t we have a return code?<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">wait<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"mi\">0<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"nb\">print<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">returncode<\/span>\n<\/span><span><span class=\"mi\">0<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>The reason for this is the <code>returncode<\/code> is not automatically set when a process ends. You have to\ncall <code>.wait<\/code> or <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.Popen.poll\" rel=\"noopener noreferrer\" target=\"_blank\"><code>.poll<\/code><\/a> to realize if the program is done and set the <code>returncode<\/code>\nattribute.<\/p>\n<h2 id=\"io-streams\">IO Streams<a class=\"headerlink\" href=\"#io-streams\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The simplest way to get the output of a command, as seen previously, is to use the\n<a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.check_call\" rel=\"noopener noreferrer\" target=\"_blank\"><code>check_output<\/code><\/a> function.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">output<\/span> <span class=\"o\">=<\/span> <span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">check_output<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;ls&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Notice the <code>check_<\/code> prefix in the function name? Ring any bell? That&rsquo;s right, this function will\nraise a <code>CalledProcessError<\/code> if the return code is non-zero.<\/p>\n<p>This may not always be the best solution to get the output from a command. If you do get a\n<code>CalledProcessError<\/code> from this function call, unless you have the contents of <code>stderr<\/code> you probably\nhave little idea what went wrong. You&rsquo;ll want to know what&rsquo;s written to the command&rsquo;s <code>stderr<\/code>.<\/p>\n<h3 id=\"reading-error-stream\">Reading error stream<a class=\"headerlink\" href=\"#reading-error-stream\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>There are two ways to get the error output. First is redirecting <code>stderr<\/code> to <code>stdout<\/code> and only being\nconcerned with <code>stdout<\/code>. This can be done by setting the <code>stderr<\/code> argument to\n<a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.STDOUT\" rel=\"noopener noreferrer\" target=\"_blank\"><code>subprocess.STDOUT<\/code><\/a>.<\/p>\n<p>Second is to create a <code>Popen<\/code> object with <code>stderr<\/code> set to <a href=\"http:\/\/docs.python.org\/library\/subprocess.html#subprocess.PIPE\" rel=\"noopener noreferrer\" target=\"_blank\"><code>subprocess.PIPE<\/code><\/a> (optionally\nalong with <code>stdout<\/code> argument) and read from its <code>stderr<\/code> attribute which is a readable file-like\nobject. There is also a convenience method on <code>Popen<\/code> class, called <code>.communicate<\/code>, which optionally\ntakes a string to be sent to the process&rsquo;s <code>stdin<\/code> and returns a tuple of <code>(stdout_content, stderr_content)<\/code>.<\/p>\n<h3 id=\"watching-both-stdout-and-stderr\">Watching both <code>stdout<\/code> and <code>stderr<\/code><a class=\"headerlink\" href=\"#watching-both-stdout-and-stderr\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>However, all of these assume that the command runs for some time, prints out a couple of lines of\noutput and exits, so you can get the output(s) in strings. This is sometimes not the case. If you\nwant to run a network intensive command like an svn checkout, which prints each file as and when\ndownloaded, you need something better.<\/p>\n<p>The initial solution one can think of is this.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">proc<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;svn co svn+ssh:\/\/myrepo&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">stdout<\/span><span class=\"o\">=<\/span><span class=\"n\">PIPE<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"k\">for<\/span> <span class=\"n\">line<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"nb\">print<\/span> <span class=\"n\">line<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This works, for the most part. But, again, if there is an error, you&rsquo;ll want to read <code>stderr<\/code> too.\nIt would be nice to read <code>stdout<\/code> and <code>stderr<\/code> simultaneously. Just like a shell seems to be doing.\nAlas, this remains a not so straightforward problem as of today, at least on non-Linux systems.<\/p>\n<p>On Linux (and where its supported), you can use the <a href=\"http:\/\/docs.python.org\/library\/select.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>select<\/code><\/a> module to keep an eye on\nmultiple file-like stream objects. But this isn&rsquo;t available on windows. A more platform independent\nsolution that I found works well, is using threads and a <a href=\"http:\/\/docs.python.org\/library\/queue.html#queue-objects\" rel=\"noopener noreferrer\" target=\"_blank\"><code>Queue<\/code><\/a>.<\/p>\n<div class=\"hl\"><input type=checkbox id=co-9><label for=co-9><span class='btn show-full-code-btn'>Show remaining 15 lines<\/span><\/label><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">subprocess<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">,<\/span> <span class=\"n\">PIPE<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">threading<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Thread<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">Queue<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Queue<\/span><span class=\"p\">,<\/span> <span class=\"n\">Empty<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">io_q<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Queue<\/span><span class=\"p\">()<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">stream_watcher<\/span><span class=\"p\">(<\/span><span class=\"n\">identifier<\/span><span class=\"p\">,<\/span> <span class=\"n\">stream<\/span><span class=\"p\">):<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">line<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">stream<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">io_q<\/span><span class=\"o\">.<\/span><span class=\"n\">put<\/span><span class=\"p\">((<\/span><span class=\"n\">identifier<\/span><span class=\"p\">,<\/span> <span class=\"n\">line<\/span><span class=\"p\">))<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">stream<\/span><span class=\"o\">.<\/span><span class=\"n\">closed<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">stream<\/span><span class=\"o\">.<\/span><span class=\"n\">close<\/span><span class=\"p\">()<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">proc<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;svn co svn+ssh:\/\/myrepo&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">stdout<\/span><span class=\"o\">=<\/span><span class=\"n\">PIPE<\/span><span class=\"p\">,<\/span> <span class=\"n\">stderr<\/span><span class=\"o\">=<\/span><span class=\"n\">PIPE<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">Thread<\/span><span class=\"p\">(<\/span><span class=\"n\">target<\/span><span class=\"o\">=<\/span><span class=\"n\">stream_watcher<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;stdout-watcher&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>        <span class=\"n\">args<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;STDOUT&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">stdout<\/span><span class=\"p\">))<\/span><span class=\"o\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">()<\/span>\n<\/span><span><span class=\"n\">Thread<\/span><span class=\"p\">(<\/span><span class=\"n\">target<\/span><span class=\"o\">=<\/span><span class=\"n\">stream_watcher<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;stderr-watcher&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>        <span class=\"n\">args<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;STDERR&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">stderr<\/span><span class=\"p\">))<\/span><span class=\"o\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">()<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"k\">def<\/span> <span class=\"nf\">printer<\/span><span class=\"p\">():<\/span>\n<\/span><span class=collapse>    <span class=\"k\">while<\/span> <span class=\"kc\">True<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>        <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>            <span class=\"c1\"># Block for 1 second.<\/span>\n<\/span><span class=collapse>            <span class=\"n\">item<\/span> <span class=\"o\">=<\/span> <span class=\"n\">io_q<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"kc\">True<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">)<\/span>\n<\/span><span class=collapse>        <span class=\"k\">except<\/span> <span class=\"n\">Empty<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>            <span class=\"c1\"># No output in either streams for a second. Are we done?<\/span>\n<\/span><span class=collapse>            <span class=\"k\">if<\/span> <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">poll<\/span><span class=\"p\">()<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"kc\">None<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>                <span class=\"k\">break<\/span>\n<\/span><span class=collapse>        <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n<\/span><span class=collapse>            <span class=\"n\">identifier<\/span><span class=\"p\">,<\/span> <span class=\"n\">line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">item<\/span>\n<\/span><span class=collapse>            <span class=\"nb\">print<\/span> <span class=\"n\">identifier<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;:&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">line<\/span>\n<\/span><span class=collapse>\n<\/span><span class=collapse><span class=\"n\">Thread<\/span><span class=\"p\">(<\/span><span class=\"n\">target<\/span><span class=\"o\">=<\/span><span class=\"n\">printer<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;printer&#39;<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">start<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Fair bit of code. This is a typical producer-consumer thing. Two threads producing lines of output\n(one each from <code>stdout<\/code> and <code>stderr<\/code>) and pushing them into a queue. One thread watching the queue\nand printing the lines until the process itself finishes.<\/p>\n<h2 id=\"passing-an-environment\">Passing an environment<a class=\"headerlink\" href=\"#passing-an-environment\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The <code>env<\/code> argument to <code>Popen<\/code> (and others) lets you customize the environment of the command being\nrun. If it is not set, or is set to <code>None<\/code>, the current process&rsquo;s environment is used, just as\ndocumented.<\/p>\n<p>You might not agree with me, but I feel there are some subtleties with this argument that should\nhave been mentioned in the documentation.<\/p>\n<h3 id=\"merge-with-current-environment\">Merge with current environment<a class=\"headerlink\" href=\"#merge-with-current-environment\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>One is that if you provide a mapping to <code>env<\/code>, whatever is in this mapping is all that&rsquo;s available\nto the command being run. For example, if you don&rsquo;t give a <code>TOP_ARG<\/code> in the <code>env<\/code> mapping, the\ncommand won&rsquo;t see a <code>TOP_ARG<\/code> in its environment. So, I frequently find myself doing this<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">p<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Popen<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;command&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">env<\/span><span class=\"o\">=<\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">environ<\/span><span class=\"p\">,<\/span> <span class=\"n\">my_env_prop<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;value&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This makes sense once you realize it, but I wish it were at least <em>hinted at<\/em> in the documentation.<\/p>\n<h3 id=\"unicode\">Unicode<a class=\"headerlink\" href=\"#unicode\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>Another one, is to do with Unicode (Surprise surprise!). And windows. If you use <code>unicode<\/code>s in the\n<code>env<\/code> mapping, you get an error saying you can <em>only<\/em> use strings in the environment mapping. The\nworst part about this error is that it only seems to happen on windows and not on Linux. If its an\nerror to use <code>unicode<\/code>s in this place, I wish it break on both platforms.<\/p>\n<p>This issue is very painful if you&rsquo;re like me and use <code>unicode<\/code> <em>all the time<\/em>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">__future__<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">unicode_literals<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>That line is present in all my python source files. The error message doesn&rsquo;t even bother to mention\nthat you have <code>unicode<\/code>s in your <code>env<\/code> so it&rsquo;s very hard to understand what&rsquo;s going wrong.<\/p>\n<h2 id=\"execute-in-a-different-working-directory\">Execute in a different working directory<a class=\"headerlink\" href=\"#execute-in-a-different-working-directory\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>This is handled by the <code>cwd<\/code> argument. You set the location of the directory which you want as the\nworking directory of the program you are launching.<\/p>\n<p>The docs do mention that the working directory is changed <em>before<\/em> the command even starts running.\nBut that you <em>can&rsquo;t<\/em> specify program&rsquo;s path relative to the <code>cwd<\/code>. In reality, I found that you\n<em>can<\/em> do this.<\/p>\n<p>Either I&rsquo;m missing something with this or the docs really are inaccurate. Anyway, this works<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;.\/ls&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">cwd<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;\/bin&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Prints out all the files in <code>\/bin<\/code>. Of course, the following doesn&rsquo;t work when the working directory\nis not <code>\/bin<\/code>.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">subprocess<\/span><span class=\"o\">.<\/span><span class=\"n\">call<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;.\/ls&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>So, if you are giving something explicitly to <code>cwd<\/code> and are using a relative path for the\nexecutable, this is something to keep in mind.<\/p>\n<h2 id=\"killing-and-dying\">Killing and dying<a class=\"headerlink\" href=\"#killing-and-dying\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>A simple<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">terminate<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Or for some dramatic umphh!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">kill<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Will do the trick to end the process. As noted in the documentation, the former sends a <code>SIGTERM<\/code>\nand later sends a <code>SIGKILL<\/code> on unix, but both do some native windows-y thing on windows.<\/p>\n<h3 id=\"auto-kill-on-death\">Auto-kill on death<a class=\"headerlink\" href=\"#auto-kill-on-death\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>The processes you start in your python program, stay running even after your program exits. This is\n<em>usually<\/em> what you want, but when you want all your sub processes killed automatically on exit with\n<code>Ctrl+C<\/code> or the like, you have to use the <a href=\"http:\/\/docs.python.org\/library\/atexit.html\" rel=\"noopener noreferrer\" target=\"_blank\"><code>atexit<\/code><\/a> module.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">procs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<\/span><span>\n<\/span><span><span class=\"nd\">@atexit<\/span><span class=\"o\">.<\/span><span class=\"n\">register<\/span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">kill_subprocesses<\/span><span class=\"p\">():<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">proc<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">procs<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">proc<\/span><span class=\"o\">.<\/span><span class=\"n\">kill<\/span><span class=\"p\">()<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>And add all the <code>Popen<\/code> objects created to the <code>procs<\/code> list. This is the only solution I found that\nworks best.<\/p>\n<h2 id=\"launch-commands-in-a-terminal-emulator\">Launch commands in a terminal emulator<a class=\"headerlink\" href=\"#launch-commands-in-a-terminal-emulator\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>On one occasion, I had to write a script that would launch multiple svn checkouts and then run many\nant builds (~20-35) on the checked out projects. In my opinion, the best and easiest way to do this\nis to fire up multiple terminal emulator windows each running an individual checkout\/ant-build. This\nallows us to monitor each process and even cancel any of them by simply closing the corresponding\nterminal emulator window.<\/p>\n<h3 id=\"linux\">Linux<a class=\"headerlink\" href=\"#linux\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>This is pretty trivial actually. On Linux, you can use <code>xterm<\/code> for this.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">Popen<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;xterm&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;-e&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;sleep 3s&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<h3 id=\"windows\">Windows<a class=\"headerlink\" href=\"#windows\" title=\"Permanent link\">&para;<\/a><\/h3>\n<p>On windows, its not as straight forward. The first solution for this would be<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">Popen<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;cmd&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;\/K&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;command&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<blockquote>\n<p><code>\/K<\/code> option tells <code>cmd<\/code> to run the command and keep the command window from closing. You may use\n<code>\/C<\/code> instead to close the command window after the command finishes.<\/p>\n<\/blockquote>\n<p>As simple as it looks, it has some weird behavior. I don&rsquo;t completely understand it, but I&rsquo;ll try to\nexplain what I have. When you try to run a python script with the above <code>Popen<\/code> call, in a command\nwindow like this<\/p>\n<div class=\"hl\"><pre class=content><code><span>python<span class=\"w\"> <\/span>main.py\n<\/span><\/code><\/pre><\/div>\n\n<p>you <em>don&rsquo;t<\/em> see a new command window pop up. Instead, the sub command runs in the same command\nwindow. I have no idea what happens when you run multiple sub commands this way. (I have only\nlimited access to windows).<\/p>\n<p>If instead you run it in something like an IDE or IDLE (<kbd>F5<\/kbd>), you have a new command\nwindow open up. I believe one each for each command you run this way. Just the way you expect.<\/p>\n<p>But I gave up on <code>cmd.exe<\/code> for this purpose and learnt to use the <a href=\"https:\/\/code.google.com\/p\/mintty\/\" rel=\"noopener noreferrer\" target=\"_blank\"><code>mintty<\/code><\/a> utility that\ncomes with <a href=\"http:\/\/www.cygwin.com\/\" rel=\"noopener noreferrer\" target=\"_blank\">cygwin<\/a> (I think 1.7+). <code>mintty<\/code> is awesome. Really. Its been a while since I felt\nthat way about a command line utility on windows.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"n\">Popen<\/span><span class=\"p\">([<\/span><span class=\"s1\">&#39;mintty&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--hold&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;error&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;--exec&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;command&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This. A new <code>mintty<\/code> console window opens up running the command and it closes automatically, <em>if<\/em>\nthe command exits with zero status (that&rsquo;s what <code>--hold error<\/code> does). Otherwise, it stays on. Very\nuseful.<\/p>\n<h2 id=\"conclusion\">Conclusion<a class=\"headerlink\" href=\"#conclusion\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>The subprocess module is a very useful thing. Spend some time understanding it better. This is my\nattempt at helping people with it, and turned out to be way longer than I&rsquo;d expected. If there are\nany inaccuracies in this, or if you have anything to add, please leave a comment.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"programming"}},{"@attributes":{"term":"python-subprocess"}},{"@attributes":{"term":"tutorial"}}]},{"title":"Serializing python-requests' Session objects for fun and profit","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/serializing-python-requests-session-objects-for-fun-and-profit\/","rel":"alternate"}},"published":"2012-02-18T00:00:00+05:30","updated":"2012-02-18T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2012-02-18:\/posts\/serializing-python-requests-session-objects-for-fun-and-profit\/","summary":"<h2 id=\"prepare\">Prepare<a class=\"headerlink\" href=\"#prepare\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If you haven&rsquo;t checked out @kennethreitz&rsquo;s excellent <a href=\"http:\/\/docs.python-requests.org\/en\/latest\/index.html\" rel=\"noopener noreferrer\" target=\"_blank\">python-requests<\/a>\nlibrary yet, I suggest you go do that immediately. Go on, I&rsquo;ll wait for you.<\/p>\n<p>Had your candy? That is one of the most beatiful piece of python code I&rsquo;ve read.\nAnd its an excellent library with \u2026<\/p>","content":"<h2 id=\"prepare\">Prepare<a class=\"headerlink\" href=\"#prepare\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If you haven&rsquo;t checked out @kennethreitz&rsquo;s excellent <a href=\"http:\/\/docs.python-requests.org\/en\/latest\/index.html\" rel=\"noopener noreferrer\" target=\"_blank\">python-requests<\/a>\nlibrary yet, I suggest you go do that immediately. Go on, I&rsquo;ll wait for you.<\/p>\n<p>Had your candy? That is one of the most beatiful piece of python code I&rsquo;ve read.\nAnd its an excellent library with a very humane API.<\/p>\n<p>Recently, I have been using this library for a few of my company&rsquo;s internal\nprojects and at a point I needed to serialize and save <code>Session<\/code> objects for\nlater. That wasn&rsquo;t as straightforward as I first thought it&rsquo;d be, so I am\nsharing my experience here.<\/p>\n<p>First off, let&rsquo;s make a simple http server which we are going to contact with\npython-requests. The server should be able to handle cookie based sessions and\nalso have basic auth, as these things are handled by python-requests&rsquo; Session\nobjects on the client side. I won&rsquo;t discuss the code for the server here, you\ncan get it from <a href=\"https:\/\/gist.github.com\/2660997#file_server.py\" rel=\"noopener noreferrer\" target=\"_blank\">the gist<\/a>.<\/p>\n<p>Once you have the server running, now for the client, lets do requests!<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">requests<\/span> <span class=\"k\">as<\/span> <span class=\"nn\">req<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">URL_ROOT<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;http:\/\/localhost:5050&#39;<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">get_logged_in_session<\/span><span class=\"p\">(<\/span><span class=\"n\">name<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">session<\/span> <span class=\"o\">=<\/span> <span class=\"n\">req<\/span><span class=\"o\">.<\/span><span class=\"n\">session<\/span><span class=\"p\">(<\/span><span class=\"n\">auth<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;user&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;pass&#39;<\/span><span class=\"p\">))<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">login_response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">session<\/span><span class=\"o\">.<\/span><span class=\"n\">post<\/span><span class=\"p\">(<\/span><span class=\"n\">URL_ROOT<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;\/login&#39;<\/span><span class=\"p\">,<\/span> <span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"p\">{<\/span><span class=\"s1\">&#39;name&#39;<\/span><span class=\"p\">:<\/span> <span class=\"n\">name<\/span><span class=\"p\">})<\/span>\n<\/span><span>    <span class=\"n\">login_response<\/span><span class=\"o\">.<\/span><span class=\"n\">raise_for_status<\/span><span class=\"p\">()<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">session<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">get_whoami<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">response<\/span> <span class=\"o\">=<\/span> <span class=\"n\">session<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">URL_ROOT<\/span> <span class=\"o\">+<\/span> <span class=\"s1\">&#39;\/whoami&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">raise_for_status<\/span><span class=\"p\">()<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">response<\/span><span class=\"o\">.<\/span><span class=\"n\">text<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I defined two functions here. The <code>get_logged_in_session<\/code> will create a new\nsession and login to the http server and return that session. Any subsequent\nrequests using this sesssion will be made as if you have logged in. That&rsquo;s what\nwill be tested with the <code>get_whoami<\/code> function, which will just return the\nresponse from <code>\/whoami<\/code>.<\/p>\n<p>Lets test this out. Make sure the <code>server.py<\/code> is running and in another\nterminal,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"err\">$<\/span> <span class=\"n\">python<\/span> <span class=\"o\">-<\/span><span class=\"n\">i<\/span> <span class=\"n\">client<\/span><span class=\"o\">.<\/span><span class=\"n\">py<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">s<\/span> <span class=\"o\">=<\/span> <span class=\"n\">get_logged_in_session<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;sharat&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">get_whoami<\/span><span class=\"p\">(<\/span><span class=\"n\">s<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"sa\">u<\/span><span class=\"s1\">&#39;You are sharat&#39;<\/span>\n<\/span><span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">get_whoami<\/span><span class=\"p\">(<\/span><span class=\"n\">req<\/span><span class=\"o\">.<\/span><span class=\"n\">session<\/span><span class=\"p\">(<\/span><span class=\"n\">auth<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;user&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;pass&#39;<\/span><span class=\"p\">)))<\/span>\n<\/span><span><span class=\"sa\">u<\/span><span class=\"s1\">&#39;You are a guest&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Works perfectly. If we pass it the logged in session, it gives us the username\nand if we pass it a new session, it gives us <code>a guest<\/code>.<\/p>\n<p>Now, lets assume we have two functions, <code>serialize_session<\/code> and\n<code>deserialize_session<\/code> which do exactly what their names say. We can test them\nout by running a small test.py, as<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">from<\/span> <span class=\"nn\">client<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">get_logged_in_session<\/span><span class=\"p\">,<\/span> <span class=\"n\">get_whoami<\/span>\n<\/span><span><span class=\"kn\">from<\/span> <span class=\"nn\">serializer<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">deserialize_session<\/span><span class=\"p\">,<\/span> <span class=\"n\">serialize_session<\/span>\n<\/span><span>\n<\/span><span><span class=\"n\">session<\/span> <span class=\"o\">=<\/span> <span class=\"n\">get_logged_in_session<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;sharat&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"n\">dsession<\/span> <span class=\"o\">=<\/span> <span class=\"n\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">serialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">))<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">assert<\/span> <span class=\"n\">get_whoami<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"n\">get_whoami<\/span><span class=\"p\">(<\/span><span class=\"n\">dsession<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"nb\">print<\/span> <span class=\"s1\">&#39;Success&#39;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>and a dummy serializer.py<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">serialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">session<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">session<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>And with that, of course, the test will not fail<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python test.py\n<\/span><span>Success\n<\/span><\/code><\/pre><\/div>\n\n<h2 id=\"serializing\">Serializing<a class=\"headerlink\" href=\"#serializing\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Now, to implement the functions in <code>serializer.py<\/code>. A simple one, would be to\nuse pickle. Lets try<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">pickle<\/span> <span class=\"k\">as<\/span> <span class=\"nn\">pk<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">serialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">pk<\/span><span class=\"o\">.<\/span><span class=\"n\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">pk<\/span><span class=\"o\">.<\/span><span class=\"n\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>If you run <code>test.py<\/code> now, python is going to yell at you.<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python test.py\n<\/span><span>Traceback (most recent call last):\n<\/span><span>    File &quot;test.py&quot;, line 10, in &lt;module&gt;\n<\/span><span>    dsession = deserialize_session(serialize_session(session))\n<\/span><span>[ ... ]\n<\/span><span>    raise TypeError, &quot;can&#39;t pickle %s objects&quot; % base.__name__\n<\/span><span>TypeError: can&#39;t pickle lock objects\n<\/span><\/code><\/pre><\/div>\n\n<p>Oh well, it was worth a try I suppose.<\/p>\n<p><strong>Update<\/strong>: The Session class can be made to\n<a href=\"#update-pickling-can-also-work\">implement<\/a> the pickle protocol if you want to\nuse pickle.<\/p>\n<p>Next plan I had was to pick up attributes and data from a <code>Session<\/code> object, just\nenough to recreate this object using the Session constructor, and serialize\nthose attributes as a JSON. After all, the Session&rsquo;s API is very easy to use,\nhow hard can picking attributes from it be? :)<\/p>\n<p>So, I dug in the <a href=\"https:\/\/github.com\/kennethreitz\/requests\/blob\/develop\/requests\/sessions.py#L50\" rel=\"noopener noreferrer\" target=\"_blank\">sessions.py<\/a> module of python-requests library. And here&rsquo;s\nwhat the signature of the constructor for <code>Session<\/code> objects looks like<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"fm\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">cookies<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">auth<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">timeout<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">proxies<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">hooks<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">params<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">config<\/span><span class=\"o\">=<\/span><span class=\"kc\">None<\/span><span class=\"p\">,<\/span>\n<\/span><span>    <span class=\"n\">verify<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"c1\"># ...<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>So, if I pick up just these values, I should be able to recreate the session\nobject. Sweet.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"kn\">import<\/span> <span class=\"nn\">json<\/span>\n<\/span><span><span class=\"kn\">import<\/span> <span class=\"nn\">requests<\/span> <span class=\"k\">as<\/span> <span class=\"nn\">req<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">serialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">attrs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;headers&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;cookies&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;timeout&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;proxies&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;hooks&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>        <span class=\"s1\">&#39;params&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;config&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;verify&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"n\">session_data<\/span> <span class=\"o\">=<\/span> <span class=\"p\">{}<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">attr<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">attrs<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"n\">attr<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">getattr<\/span><span class=\"p\">(<\/span><span class=\"n\">session<\/span><span class=\"p\">,<\/span> <span class=\"n\">attr<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">dumps<\/span><span class=\"p\">(<\/span><span class=\"n\">session_data<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">req<\/span><span class=\"o\">.<\/span><span class=\"n\">session<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>And let&rsquo;s try this out<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python test.py\n<\/span><span>Traceback (most recent call last):\n<\/span><span>    File &quot;test.py&quot;, line 12, in &lt;module&gt;\n<\/span><span>    assert get_whoami(session) == get_whoami(dsession)\n<\/span><span>[ ... ]\n<\/span><span>[...]requests\/models.py&quot;, line 447, in send\n<\/span><span>    r = self.auth(self)\n<\/span><span>TypeError: &#39;list&#39; object is not callable\n<\/span><\/code><\/pre><\/div>\n\n<p>Okay, that error message is very weird. Why would anyone <em>call<\/em> a list object?<\/p>\n<p>Go dig in the <a href=\"https:\/\/github.com\/kennethreitz\/requests\/blob\/develop\/requests\/models.py#L447\" rel=\"noopener noreferrer\" target=\"_blank\">models.py<\/a> module. See this<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">[<\/span> <span class=\"o\">...<\/span> <span class=\"p\">]<\/span>\n<\/span><span><span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">auth<\/span><span class=\"p\">,<\/span> <span class=\"nb\">tuple<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">auth<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span><span class=\"p\">:<\/span>\n<\/span><span>    <span class=\"c1\"># special-case basic HTTP auth<\/span>\n<\/span><span>    <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">auth<\/span> <span class=\"o\">=<\/span> <span class=\"n\">HTTPBasicAuth<\/span><span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">auth<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"c1\"># Allow auth to make its changes.<\/span>\n<\/span><span><span class=\"n\">r<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">auth<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"p\">[<\/span> <span class=\"o\">...<\/span> <span class=\"p\">]<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There. Its not a list that&rsquo;s being called. Not directly at least. The problem\nhere is that the <code>auth<\/code> we are passing to <code>session()<\/code> is not a tuple. Duh!\nWhile I like it that <code>auth<\/code> is restricted to be a tuple, I wish there was a\nbetter error message for when <code>auth<\/code> is a list instead of a tuple. I personally\nwouldn&rsquo;t want it to accept a <code>list<\/code> for <code>auth<\/code> though.<\/p>\n<p>So, what went wrong? <code>json<\/code> does not differentiate between a tuple and a list.\nIt only does lists. So, when serializing and deserializing, the <code>auth<\/code> tuple is\nturned to a <code>list<\/code>. Lets turn it back<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">session_data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"s1\">&#39;auth&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">session_data<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">tuple<\/span><span class=\"p\">(<\/span><span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">req<\/span><span class=\"o\">.<\/span><span class=\"n\">session<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">session_data<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>And<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python test.py\n<\/span><span>Traceback (most recent call last):\n<\/span><span>  File &quot;test.py&quot;, line 12, in &lt;module&gt;\n<\/span><span>    assert get_whoami(session) == get_whoami(dsession)\n<\/span><span>  [ ... ]\n<\/span><span>  File &quot;\/usr\/lib\/python2.7\/string.py&quot;, line 493, in translate\n<\/span><span>    return s.translate(table, deletions)\n<\/span><span>TypeError: translate() takes exactly one argument (2 given)\n<\/span><\/code><\/pre><\/div>\n\n<p>Wait. What? Now we have an error from stdlib? This just keeps getting better and\nbetter. If this looks like something that can frustrate you, go get some coffee\n:)<\/p>\n<p>If you look at the complete stack trace, the second file from bottom,<\/p>\n<div class=\"hl\"><pre class=content><code><span>  <span class=\"n\">File<\/span> <span class=\"s2\">&quot;[...]site-packages\/requests\/packages\/oreos\/monkeys.py&quot;<\/span><span class=\"p\">,<\/span> <span class=\"n\">line<\/span> <span class=\"mi\">470<\/span><span class=\"p\">,<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">set<\/span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"s2\">&quot;&quot;<\/span> <span class=\"o\">!=<\/span> <span class=\"n\">translate<\/span><span class=\"p\">(<\/span><span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">idmap<\/span><span class=\"p\">,<\/span> <span class=\"n\">LegalChars<\/span><span class=\"p\">):<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This thing seems to be calling the <code>translate<\/code> method incorrectly. With a bit of\ndebugging and yelling at my monitor, I found out the problem and for a moment,\nlost my grip on reality.<\/p>\n<p><code>str.translate<\/code> takes 2 arguments, but <code>unicode.translate<\/code> takes only 1. I have\nno idea why this is done this way but I sure as hell didn&rsquo;t enjoy it. The code\nin <code>oreos\/monkeys.py<\/code> assumes that the <code>key<\/code> is a <code>str<\/code>. However, what\n<code>json.loads<\/code> gives you, is unicode stuff. So, we need to convert just the parts\nin the deserialized dict we get from <code>json.loads<\/code> which are being used by the\n<code>oreos\/monkeys.py<\/code>, from <code>unicode<\/code> to <code>str<\/code>.<\/p>\n<p>Reading a bit more code around the oreos library, it didn&rsquo;t take long to figure\nout that those were the keys in the <code>cookies<\/code> dict. Lo<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">deserialize_session<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">session_data<\/span> <span class=\"o\">=<\/span> <span class=\"n\">json<\/span><span class=\"o\">.<\/span><span class=\"n\">loads<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"s1\">&#39;auth&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">session_data<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">tuple<\/span><span class=\"p\">(<\/span><span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">])<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">if<\/span> <span class=\"s1\">&#39;cookies&#39;<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">session_data<\/span><span class=\"p\">:<\/span>\n<\/span><span>        <span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;cookies&#39;<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">((<\/span><span class=\"n\">key<\/span><span class=\"o\">.<\/span><span class=\"n\">encode<\/span><span class=\"p\">(),<\/span> <span class=\"n\">val<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">key<\/span><span class=\"p\">,<\/span> <span class=\"n\">val<\/span> <span class=\"ow\">in<\/span>\n<\/span><span>                <span class=\"n\">session_data<\/span><span class=\"p\">[<\/span><span class=\"s1\">&#39;cookies&#39;<\/span><span class=\"p\">]<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">())<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"n\">req<\/span><span class=\"o\">.<\/span><span class=\"n\">session<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">session_data<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>And so<\/p>\n<div class=\"hl\"><pre class=content><code><span>$ python test.py\n<\/span><span>Success\n<\/span><\/code><\/pre><\/div>\n\n<p><strong>!<\/strong><\/p>\n<p>All the code is on a <a href=\"https:\/\/gist.github.com\/2660997\" rel=\"noopener noreferrer\" target=\"_blank\">gist<\/a>.<\/p>\n<h2 id=\"update-pickling-can-also-work\">Update: Pickling can also work<a class=\"headerlink\" href=\"#update-pickling-can-also-work\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>As <em>Daslch<\/em> pointed out in his <a href=\"http:\/\/www.reddit.com\/r\/Python\/comments\/pv1lf\/serializing_pythonrequests_session_objects_for\/c3sh5bb\" rel=\"noopener noreferrer\" target=\"_blank\">comment<\/a> on reddit, by implementing the pickle\nprotocol on the Session class, we can get pickling to work. From the\n<a href=\"http:\/\/docs.python.org\/library\/pickle.html#object.__getstate__\" rel=\"noopener noreferrer\" target=\"_blank\">documentation<\/a>, we need two methods, <code>__getstate__<\/code> and <code>__setstate__<\/code>.<\/p>\n<p>Adding those methods as follows to <code>sessions.Session<\/code> class<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">def<\/span> <span class=\"nf\">__getstate__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"n\">attrs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s1\">&#39;headers&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;cookies&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;auth&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;timeout&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;proxies&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;hooks&#39;<\/span><span class=\"p\">,<\/span>\n<\/span><span>        <span class=\"s1\">&#39;params&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;config&#39;<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;verify&#39;<\/span><span class=\"p\">]<\/span>\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"nb\">dict<\/span><span class=\"p\">((<\/span><span class=\"n\">attr<\/span><span class=\"p\">,<\/span> <span class=\"nb\">getattr<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">attr<\/span><span class=\"p\">))<\/span> <span class=\"k\">for<\/span> <span class=\"n\">attr<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">attrs<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">def<\/span> <span class=\"nf\">__setstate__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">state<\/span><span class=\"p\">):<\/span>\n<\/span><span>    <span class=\"k\">for<\/span> <span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">state<\/span><span class=\"o\">.<\/span><span class=\"n\">items<\/span><span class=\"p\">():<\/span>\n<\/span><span>        <span class=\"nb\">setattr<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">name<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">poolmanager<\/span> <span class=\"o\">=<\/span> <span class=\"n\">PoolManager<\/span><span class=\"p\">(<\/span>\n<\/span><span>        <span class=\"n\">num_pools<\/span><span class=\"o\">=<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">config<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;pool_connections&#39;<\/span><span class=\"p\">),<\/span>\n<\/span><span>        <span class=\"n\">maxsize<\/span><span class=\"o\">=<\/span><span class=\"bp\">self<\/span><span class=\"o\">.<\/span><span class=\"n\">config<\/span><span class=\"o\">.<\/span><span class=\"n\">get<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;pool_maxsize&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>with this as the version of <code>serializer.py<\/code> that uses pickle, we do get a\n<code>Success<\/code>.<\/p>\n<p>The creation of new poolmanager in <code>__setstate__<\/code> is a piece of code copied from\n<code>__init__<\/code> of the same class. This should probably be turned to a method to\navoid code repetition.<\/p>\n<p><strong>Update 2<\/strong>: Created an <a href=\"https:\/\/github.com\/kennethreitz\/requests\/issues\/439\" rel=\"noopener noreferrer\" target=\"_blank\">issue<\/a> about this.<\/p>\n<p><strong>Update 3<\/strong>: This has been merged and Session objects are pickleable as of\nversion 0.10.3. See <a href=\"https:\/\/github.com\/kennethreitz\/requests\/blob\/develop\/HISTORY.rst\" rel=\"noopener noreferrer\" target=\"_blank\">requests history<\/a>.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"python"}},{"@attributes":{"term":"python-requests"}},{"@attributes":{"term":"python-pickle"}}]},{"title":"Dependency graph of all installed gems","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/dependency-graph-of-all-installed-gems\/","rel":"alternate"}},"published":"2011-09-30T00:00:00+05:30","updated":"2011-09-30T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2011-09-30:\/posts\/dependency-graph-of-all-installed-gems\/","summary":"<p>Every other application written using ruby these days seem to come with this\ninstallation instruction:<\/p>\n<div class=\"hl\"><pre class=content><code><span>gem install my-super-awesome-app\n<\/span><\/code><\/pre><\/div>\n\n<p>and then going on to describing how awesome the app is. But, installing the app\nin the above way installs all its bazillion dependencies, which, unfortunately\nare not uninstalled when you uninstall \u2026<\/p>","content":"<p>Every other application written using ruby these days seem to come with this\ninstallation instruction:<\/p>\n<div class=\"hl\"><pre class=content><code><span>gem install my-super-awesome-app\n<\/span><\/code><\/pre><\/div>\n\n<p>and then going on to describing how awesome the app is. But, installing the app\nin the above way installs all its bazillion dependencies, which, unfortunately\nare not uninstalled when you uninstall this app with<\/p>\n<div class=\"hl\"><pre class=content><code><span>gem uninstall the-same-damn-app\n<\/span><\/code><\/pre><\/div>\n\n<p>And so, you have huge mess of gems installed which you have no idea why they\nare there in the first place. Finding out stale gems that are left out because\nof this can be a pain.<\/p>\n<p>So, I decided a neat flowchart visualising the dependency relationships between\nall the installed jars would give me a picture. And yes, it did.<\/p>\n<p class=\"img\"><a href=\"https:\/\/sharats.me\/static\/gem-dependency-graph.png\"><img alt=\"Gem dependency graph\" src=\"https:\/\/sharats.me\/static\/gem-dependency-graph.png\"><\/a><\/p>\n<p>Here&rsquo;s how I got the flowchart: (save this in say, gem-graph.sh)<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"ch\">#!\/bin\/bash<\/span>\n<\/span><span>\n<\/span><span>gem<span class=\"w\"> <\/span>list<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>cut<span class=\"w\"> <\/span>-d<span class=\"se\">\\ <\/span><span class=\"w\"> <\/span>-f1<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>xargs<span class=\"w\"> <\/span>gem<span class=\"w\"> <\/span>dep<span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>awk<span class=\"w\"> <\/span><span class=\"s1\">&#39;\\<\/span>\n<\/span><span><span class=\"s1\">        BEGIN { print &quot;digraph gems {&quot; } \\<\/span>\n<\/span><span><span class=\"s1\">        \/^Gem \/ { cur=$2; sub(\/-[0-9\\.]+$\/, &quot;&quot;, cur); print &quot;  \\&quot;&quot; cur &quot;\\&quot;;&quot; } \\<\/span>\n<\/span><span><span class=\"s1\">        ! \/^Gem \/ &amp;&amp; $0 != &quot;&quot; { print &quot;  \\&quot;&quot; cur &quot;\\&quot; -&gt; \\&quot;&quot; $1 &quot;\\&quot;;&quot; } \\<\/span>\n<\/span><span><span class=\"s1\">        END { print &quot;}&quot; }&#39;<\/span><span class=\"w\"> <\/span><span class=\"se\">\\<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">|<\/span><span class=\"w\"> <\/span>dot<span class=\"w\"> <\/span>-Tpng<span class=\"w\"> <\/span>-o<span class=\"w\"> <\/span>gems.png\n<\/span><\/code><\/pre><\/div>\n\n<p>Assuming you have <a href=\"http:\/\/www.graphviz.org\/\" rel=\"noopener noreferrer\" target=\"_blank\">GraphViz<\/a> installed, you can just\ndo<\/p>\n<div class=\"hl\"><pre class=content><code><span>chmod +x gem-graph.sh\n<\/span><span>.\/gem-graph.sh\n<\/span><\/code><\/pre><\/div>\n\n<p>and the graph will be saved in gems.png. Happy gem cleaning :).<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"ruby"}},{"@attributes":{"term":"gem"}},{"@attributes":{"term":"graphviz"}},{"@attributes":{"term":"bash"}},{"@attributes":{"term":"tips"}}]},{"title":"Implementing an expressive search system with clojure","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/implementing-an-expressive-search-system-with-clojure\/","rel":"alternate"}},"published":"2011-09-28T00:00:00+05:30","updated":"2011-09-28T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2011-09-28:\/posts\/implementing-an-expressive-search-system-with-clojure\/","summary":"<h2 id=\"backstory\">Backstory<a class=\"headerlink\" href=\"#backstory\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I have recently learned <a href=\"http:\/\/clojure.org\" rel=\"noopener noreferrer\" target=\"_blank\">Clojure<\/a> and its the first time I&rsquo;ve been exposed to\nlisp and the code-as-data way of life. I was eager to use Clojure to make an\napp, any app, a simple silly personal tool to help me out with a tedious task.<\/p>\n<p>One such \u2026<\/p>","content":"<h2 id=\"backstory\">Backstory<a class=\"headerlink\" href=\"#backstory\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I have recently learned <a href=\"http:\/\/clojure.org\" rel=\"noopener noreferrer\" target=\"_blank\">Clojure<\/a> and its the first time I&rsquo;ve been exposed to\nlisp and the code-as-data way of life. I was eager to use Clojure to make an\napp, any app, a simple silly personal tool to help me out with a tedious task.<\/p>\n<p>One such tool I created was <a href=\"http:\/\/classypants.sharats.me\" rel=\"noopener noreferrer\" target=\"_blank\">classypants<\/a>. Its a small swing based GUI tool\nthat helps one to make sense out of the values of <code>PATH<\/code> like variables. The\nvalues of these variables are a list of paths of files\/directories joined with\n<code>:<\/code> in *nix systems and <code>;<\/code> on windows. Have you ever seen <code>CLASSPATH<\/code> entries\nthat have ~100 jars\/directories in it? Even if these values have just 20 items,\nits very hard to make any sense out of it.<\/p>\n<p>Classypants is basically a pretty bare window carrying only 4 top level\ncontrols, one of which is an input box for searching through the entries. That\nsearch is what I want to talk about in this post.<\/p>\n<h2 id=\"superpowers\">Superpowers<a class=\"headerlink\" href=\"#superpowers\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Initially, the search box was just a filter box. I type some text and the\nentries that contain that text and shown, rest hidden. This quickly became\nannoying as I wanted to search for entries with <code>jaxb<\/code> and <code>jar<\/code>, which was not\npossible with the then implementation.<\/p>\n<p>The implementation of the search I have today can do much more than even that.\nIts a powerful query language at work, using which we can filter entries that\npoint to non-existing files, entries that point to directories that contain a\nsaid file and other weirdos.<\/p>\n<h2 id=\"how-is-it-done\">How is it done?<a class=\"headerlink\" href=\"#how-is-it-done\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I want to share how I went about evolving the search functionality. Let&rsquo;s talk\nabout one function here,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">(<\/span><span class=\"kd\">defn <\/span><span class=\"nv\">matches?<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">[<\/span><span class=\"nv\">search-str<\/span><span class=\"w\"> <\/span><span class=\"nv\">entry<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">(<\/span><span class=\"nb\">-&gt; <\/span><span class=\"nv\">resource<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">(<\/span><span class=\"nf\">.indexOf<\/span><span class=\"w\"> <\/span><span class=\"nv\">search-str<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">(<\/span><span class=\"nb\">not= <\/span><span class=\"mi\">-1<\/span><span class=\"p\">)))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>This is the first incarnation of the search implementation. It just checks if\nthe given <code>search-str<\/code> is present inside the <code>entry<\/code>.<\/p>\n<p>That is nice and useful. But we want more power. We want a nice minimal query\nlanguage to describe what we want to find, and it should be easy to remember.\nLets work on negation of search results first, thinking up the simplest of\nsyntaxes,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">not <\/span><span class=\"nv\">resource<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>should match entries that do <em>not<\/em> contain <code>resource<\/code>. This doesn&rsquo;t look good,\nas it might also mean to search for entries that contain <code>not<\/code> or <code>resource<\/code>. We\nneed some sugar to identify the <code>not<\/code> part as a directive that modifies how the\nsearch is done. Lets try again,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"ss\">:not<\/span><span class=\"w\"> <\/span><span class=\"nv\">resource<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Ah, the <code>:<\/code> in from of <code>not<\/code> gives it the special behaviour we need. Don&rsquo;t worry\ntoo much about why the syntax isn&rsquo;t <code>not: resource<\/code> or something else, it will\nbecome clear in a moment, if it hasn&rsquo;t already. Now that we have a search\nsyntax, its time to get it work. Imagine a function, <code>digest<\/code>, which takes a\nsearch string and returns a <em>function<\/em>, which takes an entry and tells if its a\nmatch or not. I suck at writing, read that again.<\/p>\n<p>Essentially, <code>(digest \":not resource\")<\/code> should return a function, which more or\nless works like<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">(<\/span><span class=\"k\">fn <\/span><span class=\"p\">[<\/span><span class=\"nv\">entry<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">(<\/span><span class=\"nb\">not <\/span><span class=\"p\">(<\/span><span class=\"nf\">matches?<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;resource&quot;<\/span><span class=\"w\"> <\/span><span class=\"nv\">entry<\/span><span class=\"p\">)))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>We see if there is a match, and <code>not<\/code> its result. Lets try writing the <code>digest<\/code>\nfunction,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">(<\/span><span class=\"kd\">defn <\/span><span class=\"nv\">digest<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">[<\/span><span class=\"nv\">search-str<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">(<\/span><span class=\"nf\">read-string<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">str <\/span><span class=\"s\">&quot;(&quot;<\/span><span class=\"w\"> <\/span><span class=\"nv\">search-str<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;)&quot;<\/span><span class=\"p\">)))<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>What we do above is wrap the <code>search-str<\/code> in parenthesis and read it into a\nClojure <code>list<\/code>. Lets try out our function in the REPL.<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nv\">user=&gt;<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">digest<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;:not resource&quot;<\/span><span class=\"p\">)<\/span>\n<\/span><span><span class=\"p\">(<\/span><span class=\"ss\">:not<\/span><span class=\"w\"> <\/span><span class=\"nv\">resource<\/span><span class=\"p\">)<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Yep, just what we expected. Now, lets take this further ahead<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"p\">(<\/span><span class=\"kd\">defn <\/span><span class=\"nv\">digest<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">[<\/span><span class=\"nv\">search-str<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"w\">  <\/span><span class=\"p\">(<\/span><span class=\"k\">let <\/span><span class=\"p\">[<\/span><span class=\"nv\">spec<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nf\">read-string<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">str <\/span><span class=\"s\">&quot;(&quot;<\/span><span class=\"w\"> <\/span><span class=\"nv\">search-str<\/span><span class=\"w\"> <\/span><span class=\"s\">&quot;)&quot;<\/span><span class=\"p\">))]<\/span>\n<\/span><span><span class=\"w\">    <\/span><span class=\"p\">(<\/span><span class=\"nf\">cond<\/span>\n<\/span><span><span class=\"w\">      <\/span><span class=\"p\">(<\/span><span class=\"nb\">= <\/span><span class=\"p\">(<\/span><span class=\"nb\">first <\/span><span class=\"nv\">spec<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"ss\">:not<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"k\">fn <\/span><span class=\"p\">[<\/span><span class=\"nv\">e<\/span><span class=\"p\">]<\/span>\n<\/span><span><span class=\"w\">                              <\/span><span class=\"p\">(<\/span><span class=\"nb\">not <\/span><span class=\"p\">(<\/span><span class=\"nf\">matches?<\/span><span class=\"w\"> <\/span><span class=\"p\">(<\/span><span class=\"nb\">nth <\/span><span class=\"nv\">spec<\/span><span class=\"w\"> <\/span><span class=\"mi\">1<\/span><span class=\"p\">)<\/span><span class=\"w\"> <\/span><span class=\"nv\">e<\/span><span class=\"p\">))))))<\/span>\n<\/span><\/code><\/pre><\/div>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"clojure"}}]},{"title":"Vim undo breaks with auto-close plugins","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/vim-undo-breaks-with-auto-close-plugins\/","rel":"alternate"}},"published":"2011-09-28T00:00:00+05:30","updated":"2011-09-28T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2011-09-28:\/posts\/vim-undo-breaks-with-auto-close-plugins\/","summary":"<h2 id=\"prelude\">Prelude<a class=\"headerlink\" href=\"#prelude\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If you&rsquo;ve used IDEs or other heavy editors ever in your life, you&rsquo;d know how\nnice it is to have parentheses and brackets to get auto-closed. If you don&rsquo;t\nknow what I&rsquo;m talking about, its a feature usually present in IDEs like eclipse\nand easily \u2026<\/p>","content":"<h2 id=\"prelude\">Prelude<a class=\"headerlink\" href=\"#prelude\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>If you&rsquo;ve used IDEs or other heavy editors ever in your life, you&rsquo;d know how\nnice it is to have parentheses and brackets to get auto-closed. If you don&rsquo;t\nknow what I&rsquo;m talking about, its a feature usually present in IDEs like eclipse\nand easily recreated in vim with mappings like<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">(<\/span> <span class=\"p\">()&lt;<\/span>Left<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Of course, that&rsquo;s just a simple taste. There are vastly complicated plugins that\nachieve this.<\/p>\n<p>Now, what&rsquo;s really super annoying about these plugins is that they tend to\nbreak vim&rsquo;s amazingly powerful undo functionality. In other words, if you are\nusing an auto-close plugin, chances are, you can&rsquo;t rely on vim&rsquo;s undo anymore.<\/p>\n<p>Debugging this and finding the cause has been on my todo list for quite some\ntime and a few days ago, I finally sat down to explore. I am writing my\nexperience here. First, a simple test case to see if the auto-close plugin you\nuse breaks undo, open vim (a blank file) and hit the following keys:<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"k\">iabc<\/span>{<span class=\"p\">&lt;<\/span>CR<span class=\"p\">&gt;&lt;<\/span>ESC<span class=\"p\">&gt;<\/span><span class=\"k\">u<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Where instead of <code>&lt;CR&gt;<\/code> you&rsquo;d hit the return key and instead of <code>&lt;ESC&gt;<\/code> you&rsquo;d\nhit the Escape key. Decent knowledge of vim should tell you that after the above\nkeys, you should end up with a blank file again. Right?<\/p>\n<p>If instead, you see a closing brace dangling in the second line, your undo is\nbroken. MUHAHAHAHAHA! You can&rsquo;t rely on undo anymore until you get rid of that\none plugin!<\/p>\n<h2 id=\"whats-going-on\">What&rsquo;s going on?<a class=\"headerlink\" href=\"#whats-going-on\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>So, experimenting with many auto-close plugins and reading the source of at\nleast 3 of those, I say there are basically two different implementations of\nthis functionality, which all these plugins use. The first one is pretty much\nwhat was shown at the start of this article,<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">(<\/span> <span class=\"p\">()&lt;<\/span>Left<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"c\">&quot; or<\/span>\n<\/span><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">(<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">r<\/span><span class=\"p\">&gt;=<\/span><span class=\"s2\">&quot;()\\&lt;Left&gt;&quot;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>I&rsquo;m going to call this class of plugins, the critters. These do <em>not<\/em> break your\nundo. The next class of implementations, that do break your undo, the beasts, do\na bit of dark sorcery with stuff like<\/p>\n<div class=\"hl\"><pre class=content><code><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">(<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span><span class=\"k\">r<\/span><span class=\"p\">&gt;=<\/span>MyAwesomePairInseter<span class=\"p\">()&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>There is no dark sorcery here that is immediately apparent. The real sorcery is\n<em>inside<\/em> that function, where a call to <code>setline()<\/code> function is made to replace\nyour current line to contain the parentheses text at the cursor. Doesn&rsquo;t make\nsense?  Don&rsquo;t worry, you&rsquo;ll get it soon enough.<\/p>\n<h2 id=\"which-plugins-name-them\">Which plugins? Name them!<a class=\"headerlink\" href=\"#which-plugins-name-them\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>Here are a few ones that break undo:<\/p>\n<h3 id=\"beasts\">Beasts<a class=\"headerlink\" href=\"#beasts\" title=\"Permanent link\">&para;<\/a><\/h3>\n<ul>\n<li><a href=\"https:\/\/github.com\/vim-scripts\/AutoClose\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/vim-scripts\/AutoClose<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Raimondi\/delimitMate\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/Raimondi\/delimitMate<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Townk\/vim-autoclose\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/Townk\/vim-autoclose<\/a><\/li>\n<\/ul>\n<p>and these don&rsquo;t break undo<\/p>\n<h3 id=\"critters\">Critters<a class=\"headerlink\" href=\"#critters\" title=\"Permanent link\">&para;<\/a><\/h3>\n<ul>\n<li><a href=\"https:\/\/github.com\/vim-scripts\/ClosePairs\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/vim-scripts\/ClosePairs<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/vim-scripts\/simple-pairs\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/vim-scripts\/simple-pairs<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/vim-scripts\/Auto-Pairs\" rel=\"noopener noreferrer\" target=\"_blank\">https:\/\/github.com\/vim-scripts\/Auto-Pairs<\/a><\/li>\n<\/ul>\n<p>An initial look at them and you can tell, the ones that break undo are actually\nmore popular and have a relatively larger code base. So why doesn&rsquo;t anyone\ncomplain about breaking undo?  I think they do and I believe the root cause is\na bug with <em>vim<\/em> itself.<\/p>\n<p>The main difference in usability among these classes is again to do with undo.\nIn the beasts, typing a brace does not start a new undo action, but it does in\nthe critters (like hitting a <code>&lt;C-g&gt;u<\/code>). This might actually be playing a role in\nwhy undo breaks in beasts only, but the exact reason escapes me.<\/p>\n<h2 id=\"a-reproducible-test-case\">A reproducible test case<a class=\"headerlink\" href=\"#a-reproducible-test-case\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I wanted to reproduce this problem with a vanilla vim with no custom\nconfiguration (except for <code>nocompatible<\/code>). So, I checked out the latest version\n(vim73-353) from the mercurial repository, compiled (with python, ruby and\nusual shit) and opened it, with no plugins and a simple vimrc as the following:<\/p>\n<div class=\"hl\"><input type=checkbox id=co-8><label for=co-8><span class='btn show-full-code-btn'>Show remaining 6 lines<\/span><\/label><pre class=content><code><span><span class=\"k\">set<\/span> <span class=\"nb\">nocompatible<\/span>\n<\/span><span>\n<\/span><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">&lt;<\/span>buffer<span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> <span class=\"p\">(<\/span> <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span>R<span class=\"p\">&gt;=&lt;<\/span>SID<span class=\"p\">&gt;<\/span>InsertPair<span class=\"p\">(<\/span><span class=\"s2\">&quot;(&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;)&quot;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">&lt;<\/span>buffer<span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> [ <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span>R<span class=\"p\">&gt;=&lt;<\/span>SID<span class=\"p\">&gt;<\/span>InsertPair<span class=\"p\">(<\/span><span class=\"s2\">&quot;[&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;]&quot;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span><span class=\"nb\">inoremap<\/span> <span class=\"p\">&lt;<\/span>buffer<span class=\"p\">&gt;<\/span> <span class=\"p\">&lt;<\/span><span class=\"k\">silent<\/span><span class=\"p\">&gt;<\/span> { <span class=\"p\">&lt;<\/span>C<span class=\"p\">-<\/span>R<span class=\"p\">&gt;=&lt;<\/span>SID<span class=\"p\">&gt;<\/span>InsertPair<span class=\"p\">(<\/span><span class=\"s2\">&quot;{&quot;<\/span><span class=\"p\">,<\/span> <span class=\"s2\">&quot;}&quot;<\/span><span class=\"p\">)&lt;<\/span>CR<span class=\"p\">&gt;<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">function<\/span><span class=\"p\">!<\/span> s:InsertPair<span class=\"p\">(<\/span>opener<span class=\"p\">,<\/span> closer<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:save_ve <span class=\"p\">=<\/span> &amp;<span class=\"k\">ve<\/span>\n<\/span><span>    <span class=\"k\">set<\/span> <span class=\"k\">ve<\/span><span class=\"p\">=<\/span><span class=\"k\">all<\/span>\n<\/span><span>\n<\/span><span>    <span class=\"k\">call<\/span> s:InsertStringAtCursor<span class=\"p\">(<\/span><span class=\"k\">a<\/span>:closer<span class=\"p\">)<\/span>\n<\/span><span>\n<\/span><span>    exec <span class=\"s2\">&quot;set ve=&quot;<\/span> . <span class=\"k\">l<\/span>:save_ve\n<\/span><span>    <span class=\"k\">return<\/span> <span class=\"k\">a<\/span>:opener\n<\/span><span><span class=\"k\">endfunction<\/span>\n<\/span><span>\n<\/span><span><span class=\"k\">function<\/span><span class=\"p\">!<\/span> s:InsertStringAtCursor<span class=\"p\">(<\/span>str<span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:line <span class=\"p\">=<\/span> getline<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">)<\/span>\n<\/span><span>    <span class=\"k\">let<\/span> <span class=\"k\">l<\/span>:column <span class=\"p\">=<\/span> <span class=\"k\">col<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">)<\/span><span class=\"m\">-2<\/span>\n<\/span><span>\n<\/span><span class=collapse>    <span class=\"k\">if<\/span> <span class=\"k\">l<\/span>:column <span class=\"p\">&lt;<\/span> <span class=\"m\">0<\/span>\n<\/span><span class=collapse>        <span class=\"k\">call<\/span> setline<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">,<\/span> <span class=\"k\">a<\/span>:str . <span class=\"k\">l<\/span>:line<span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"k\">else<\/span>\n<\/span><span class=collapse>        <span class=\"k\">call<\/span> setline<span class=\"p\">(<\/span><span class=\"s1\">&#39;.&#39;<\/span><span class=\"p\">,<\/span> <span class=\"k\">l<\/span>:line[:<span class=\"k\">l<\/span>:column] . <span class=\"k\">a<\/span>:str . <span class=\"k\">l<\/span>:line[<span class=\"k\">l<\/span>:column<span class=\"p\">+<\/span><span class=\"m\">1<\/span>:]<span class=\"p\">)<\/span>\n<\/span><span class=collapse>    <span class=\"k\">endif<\/span>\n<\/span><span class=collapse><span class=\"k\">endfunction<\/span>\n<\/span><\/code><\/pre><\/div>\n\n<p>Which is a stripped down version of the auto-close functionality implemented in\ntownk&rsquo;s auto-close plugin. And opened vim<\/p>\n<div class=\"hl\"><pre class=content><code><span>vim<span class=\"w\"> <\/span>-u<span class=\"w\"> <\/span>undo-breaker-vimrc\n<\/span><\/code><\/pre><\/div>\n\n<p>and did the test here. Boom, a dangling brace character.<\/p>\n<p>For all I know, its the call to <code>setline()<\/code> that&rsquo;s making all the difference.\nBut I could be entirely wrong with that. I say this because that is the major\ndifference between the two classes of implementations.<\/p>\n<h2 id=\"next\">Next?<a class=\"headerlink\" href=\"#next\" title=\"Permanent link\">&para;<\/a><\/h2>\n<p>I use persistent-undo in vim73 and heavily depend on it. Combined with the\n<a href=\"http:\/\/sjl.bitbucket.org\/gundo.vim\" rel=\"noopener noreferrer\" target=\"_blank\">gundo<\/a> plugin by <a href=\"http:\/\/stevelosh.com\" rel=\"noopener noreferrer\" target=\"_blank\">Steve Losh<\/a>, I get a kind of nicely visualized version\nhistory that is centric to every file, which is quite handy in its own right.<\/p>\n<p>So, if there are others who have faced this, have a fix for it, perhaps a patch\nto vim, or if there is already a bug in vim&rsquo;s bug database on this, let me know.<\/p>\n<p>Thank you for reading.<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"vim"}},{"@attributes":{"term":"vim-plugins"}}]},{"title":"Installing Crunchbang Linux on my old lappy","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/installing-crunchbang-linux-on-my-old-lappy\/","rel":"alternate"}},"published":"2011-02-25T00:00:00+05:30","updated":"2011-02-25T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2011-02-25:\/posts\/installing-crunchbang-linux-on-my-old-lappy\/","summary":"<p>I managed to install Crunchbang linux, the recently released Stetler, after\nreading quite a positive review (I don&rsquo;t remember where). I am really liking\nit, especially the Openbox desktop environment. Also, coming from a lot of\nexperience on ubuntu, finding Crunchbang look so bare-bones and simple, yet so\ncustomizable \u2026<\/p>","content":"<p>I managed to install Crunchbang linux, the recently released Stetler, after\nreading quite a positive review (I don&rsquo;t remember where). I am really liking\nit, especially the Openbox desktop environment. Also, coming from a lot of\nexperience on ubuntu, finding Crunchbang look so bare-bones and simple, yet so\ncustomizable is very refreshing. I will put my experience with installing it\nand my initial thoughts, before I forget them :).<\/p>\n<p>Now my laptop&rsquo;s got a defective and unreliable disk drive, so I chose to\ninstall Crunchbang from USB with the help of unetbootin. After downloading the\n<code>#!<\/code> (Crunchbang) ISO file, I fired up unetbootin on my windows vista (on the\nsame laptop) and setup my 1GB pen drive to be bootable. After that, I had to\ncreate a couple of symlinks (using Cygwin) on the USB drive as following<\/p>\n<div class=\"hl\"><pre class=content><code><span>ln<span class=\"w\"> <\/span>-s<span class=\"w\"> <\/span>live\/vmlinuz1<span class=\"w\"> <\/span>vmlinuz\n<\/span><span>ln<span class=\"w\"> <\/span>-s<span class=\"w\"> <\/span>live\/initrd1.img<span class=\"w\"> <\/span>initrd.img\n<\/span><\/code><\/pre><\/div>\n\n<p>After that, the boot was pretty smooth, and I had to choose the graphical\ninstaller as the text based installer wouldn&rsquo;t load, which I have no idea why.<\/p>\n<p>Another interesting thing that happened was that at the end of the\ninstallation, <code>#!<\/code> asked me if I wanted to install the grub boot loader, and that\nit detects windows as another OS on the machine. However the grub it installed\ndoes not list windows in the boot menu. I asked a question about this on\n<a href=\"https:\/\/unix.stackexchange.com\" rel=\"noopener noreferrer\" target=\"_blank\">unix.stackexchange.com<\/a> and got to know that a\nsimple <code>sudo<\/code> update-grub added the windows item to my boot menu. Not a major\nset-back, but still.<\/p>\n<p>After that, using the OS is nothing but a pure pleasure. It feels amazingly\nsnappy and super productive. The conky based hotkey reference on the desktop is\na killer thing to look for. Oh, and Dropbox installation is easier than on my\nubuntu box, if you use Dropbox that is. Chrome, my browser of choice, is the\ndefault browser, what more can I ask? Awesome distribution. I am looking\nforward to exploring even more with my shiny new #!, and I seriously recommend\nyou give it a try :)<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"crunchbang"}},{"@attributes":{"term":"linux"}}]},{"title":"A tasty vim configuration setup with Vimpire and Pathogen","link":{"@attributes":{"href":"https:\/\/sharats.me\/posts\/a-tasty-vim-configuration-setup-with-vimpire-and-pathogen\/","rel":"alternate"}},"published":"2010-12-14T00:00:00+05:30","updated":"2010-12-14T00:00:00+05:30","author":{"name":"Shrikant Sharat Kandula"},"id":"tag:sharats.me,2010-12-14:\/posts\/a-tasty-vim-configuration-setup-with-vimpire-and-pathogen\/","summary":"<p>Managing vim plugins has always been a hassle. Until pathogen came along. If\nyou are using vim with quite a few vim plugins, then you should be using\npathogen, if you are not, you are seriously depriving yourself of sanity. No,\nseriously. You should.<\/p>\n<p>So, I assume you are also \u2026<\/p>","content":"<p>Managing vim plugins has always been a hassle. Until pathogen came along. If\nyou are using vim with quite a few vim plugins, then you should be using\npathogen, if you are not, you are seriously depriving yourself of sanity. No,\nseriously. You should.<\/p>\n<p>So, I assume you are also versioning your <code>.vim<\/code> directory, like on GitHub or\nBitBucket with git or mercurial respectively. If you are not, then you should.\nYou really really should.<\/p>\n<p>If your answer was no to both of the above, you better get the hell out of here\nbefore I get my lawn mowers.<\/p>\n<p>Okay, if you tried to version your <code>.vim<\/code> directory, but the plugin directories\ninside pathogen&rsquo;s bundle directory are repositories themselves, you won&rsquo;t be\nvery happy. You either have to version all the .git and .hg and what not\nversion directories from the plugins, or you just have to ignore them all and\nforgo versioning for individual plugins. But if you chose the latter, in which\ncase versioning your <code>.vim<\/code> will be easy, updating your plugins is a serious\npain.<\/p>\n<p>So, recently, <a href=\"http:\/\/vim-scripts.org\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/vim-scripts.org<\/a> came up and so did scripts like vundle and\nvim-update-bundles, as listed on the tools page on <a href=\"http:\/\/vim-scripts.org\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/vim-scripts.org<\/a>.\nThese let you list the plugins you use in your vimrc file and they take care of\nkeeping them up to date. The advantage is that you can version your <code>.vim<\/code>\ndirectory, and wherever you clone it, you can just run the script used and all\nyour plugins are set up, the latest versions of them, just like that. Awesome!<\/p>\n<p>Vimpire isn&rsquo;t much different from those tools. In fact, it is very similar to\nvim-update-bundles in functionality, but there are 2 main differences. First\noff, it is written in python. I won&rsquo;t spell out the implications of that. But,\nit is ruby-less. Second, it supports hg. Yay! So, you can get plugins not just\nfrom git, but also from hg.<\/p>\n<p>How to set it up and how to use it can be seen on the BitBucket page, via the\nREADME file.<\/p>\n<p>Hosted at <a href=\"http:\/\/bitbucket.org\/sharat87\/vimpire\/src\" rel=\"noopener noreferrer\" target=\"_blank\">http:\/\/bitbucket.org\/sharat87\/vimpire\/src<\/a><\/p>\n<p>Please note that this is still beta. Tested on windows 7. I am waiting to get\nback to Ubuntu, but until then, no idea if it works on unix like machines.<\/p>\n<p>Update: The latest version works perfectly with Ubuntu too!<\/p>","category":[{"@attributes":{"term":"posts"}},{"@attributes":{"term":"vim"}},{"@attributes":{"term":"vim-plugins"}},{"@attributes":{"term":"vimpire"}},{"@attributes":{"term":"pathogen"}}]}]}