<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>til &amp;mdash; sandeepk</title>
    <link>https://blogs.dgplug.org/sandeepk/tag:til</link>
    <description></description>
    <pubDate>Thu, 30 Apr 2026 21:27:50 +0000</pubDate>
    <item>
      <title>Git Worktree</title>
      <link>https://blogs.dgplug.org/sandeepk/git-worktree</link>
      <description>&lt;![CDATA[A few days ago, during our office knowledge-sharing meeting, someone introduced the git worktree command. It lets you create a new branch parallel to your current working branch so you can start something new — or handle a hotfix — without stashing or committing your unfinished changes.&#xA;&#xA;It turned out to be incredibly useful. With git worktree, you can maintain multiple working directories linked to the same Git repository with almost no friction.&#xA;&#xA;---&#xA;&#xA;Why use worktrees?&#xA;&#xA;Imagine you&#39;re working on a long-running feature — say, an optimization — and suddenly you’re assigned an urgent production bug.&#xA;Typically, you would stash your changes or make a temporary commit, switch branches, fix the bug, then restore everything. It&#39;s annoying and error-prone.&#xA;&#xA;With worktrees, you can directly spin up a parallel working directory:&#xA;&#xA;git worktree add path&#xA;Example:&#xA;git worktree add ../hotfix&#xA;&#xA;This creates a new linked worktree, associated with your current repository, with its own metadata and branch checkout. Your original work remains untouched.&#xA;&#xA;---&#xA;&#xA;Removing a worktree&#xA;&#xA;Once you&#39;re done with the hotfix (or any task), removing the worktree is just as simple:&#xA;&#xA;git worktree remove path&#xA;&#xA;If you delete the directory manually, Git will eventually clean up its administrative files automatically (based on gc.worktreePruneExpire in git-config).&#xA;You can also remove stale entries explicitly:&#xA;&#xA;git worktree prune&#xA;&#xA;---&#xA;&#xA;Other useful worktree commands&#xA;&#xA;1. Create a throwaway worktree (detached HEAD)&#xA;&#xA;Perfect for quick experiments:&#xA;&#xA;git worktree add -d path&#xA;&#xA;2. Create a worktree for an existing branch&#xA;&#xA;git worktree add path branch&#xA;&#xA;This checks out the given branch into a new, isolated working directory.&#xA;&#xA;---&#xA;&#xA;Further reading&#xA;&#xA;To dive deeper into git worktree:&#xA;&#xA;Official docs: https://git-scm.com/docs/git-worktree&#xA;Or simply run:&#xA;&#xA;    git help worktree&#xA;  &#xA;&#xA;Cheers!&#xA;&#xA;#Git #TIL #Worktree]]&gt;</description>
      <content:encoded><![CDATA[<p>A few days ago, during our office knowledge-sharing meeting, someone introduced the <code>git worktree</code> command. It lets you create a new branch <em>parallel</em> to your current working branch so you can start something new — or handle a hotfix — <strong>without stashing or committing your unfinished changes</strong>.</p>

<p>It turned out to be incredibly useful. With <code>git worktree</code>, you can maintain multiple working directories linked to the same Git repository with almost no friction.</p>

<hr>

<h2 id="why-use-worktrees">Why use worktrees?</h2>

<p>Imagine you&#39;re working on a long-running feature — say, an optimization — and suddenly you’re assigned an urgent production bug.
Typically, you would stash your changes or make a temporary commit, switch branches, fix the bug, then restore everything. It&#39;s annoying and error-prone.</p>

<p>With worktrees, you can directly spin up a parallel working directory:</p>

<pre><code class="language-bash">git worktree add &lt;path&gt;
# Example:
git worktree add ../hotfix
</code></pre>

<p>This creates a <strong>new linked worktree</strong>, associated with your current repository, with its own metadata and branch checkout. Your original work remains untouched.</p>

<hr>

<h2 id="removing-a-worktree">Removing a worktree</h2>

<p>Once you&#39;re done with the hotfix (or any task), removing the worktree is just as simple:</p>

<pre><code class="language-bash">git worktree remove &lt;path&gt;
</code></pre>

<p>If you delete the directory manually, Git will eventually clean up its administrative files automatically (based on <code>gc.worktreePruneExpire</code> in <code>git-config</code>).
You can also remove stale entries explicitly:</p>

<pre><code class="language-bash">git worktree prune
</code></pre>

<hr>

<h2 id="other-useful-worktree-commands">Other useful worktree commands</h2>

<h3 id="1-create-a-throwaway-worktree-detached-head">1. Create a throwaway worktree (detached HEAD)</h3>

<p>Perfect for quick experiments:</p>

<pre><code class="language-bash">git worktree add -d &lt;path&gt;
</code></pre>

<h3 id="2-create-a-worktree-for-an-existing-branch">2. Create a worktree for an existing branch</h3>

<pre><code class="language-bash">git worktree add &lt;path&gt; &lt;branch&gt;
</code></pre>

<p>This checks out the given branch into a new, isolated working directory.</p>

<hr>

<h2 id="further-reading">Further reading</h2>

<p>To dive deeper into <code>git worktree</code>:</p>
<ul><li>Official docs: <a href="https://git-scm.com/docs/git-worktree" rel="nofollow">https://git-scm.com/docs/git-worktree</a></li>
<li>Or simply run:</li></ul>

<pre><code class="language-bash">  git help worktree
</code></pre>

<p>Cheers!</p>

<p><a href="/sandeepk/tag:Git" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Git</span></a> <a href="/sandeepk/tag:TIL" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">TIL</span></a> <a href="/sandeepk/tag:Worktree" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Worktree</span></a></p>
]]></content:encoded>
      <guid>https://blogs.dgplug.org/sandeepk/git-worktree</guid>
      <pubDate>Sun, 30 Nov 2025 13:27:11 +0000</pubDate>
    </item>
    <item>
      <title>Converting HTML Tables to CSV</title>
      <link>https://blogs.dgplug.org/sandeepk/converting-html-tables-to-csv</link>
      <description>&lt;![CDATA[Today, I decided to analyze my bank account statement by downloading it from the day I opened my bank account. To my surprise, it was presented as a web page. Initially, my inner developer urged me to write code to scrape that data. However, feeling a bit lazy, I postponed doing so.&#xA;&#xA;Later in the evening, I searched the web to find an alternate way to extract the data and discovered that HTML tables can be converted to CSV files. All I had to do was save the code in CSV format. I opened the Chrome browser&#39;s inspect code feature, copied the table, saved it with the CSV extension, and then opened the file with LibreOffice. Voila! I had the spreadsheet with all my transactions.&#xA;&#xA;Cheers!&#xA;&#xA;TIL&#xA;CSV&#xA;HTML Table&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Today, I decided to analyze my bank account statement by downloading it from the day I opened my bank account. To my surprise, it was presented as a web page. Initially, my inner developer urged me to write code to scrape that data. However, feeling a bit lazy, I postponed doing so.</p>

<p>Later in the evening, I searched the web to find an alternate way to extract the data and discovered that HTML tables can be converted to CSV files. All I had to do was save the code in CSV format. I opened the Chrome browser&#39;s inspect code feature, copied the table, saved it with the CSV extension, and then opened the file with LibreOffice. Voila! I had the spreadsheet with all my transactions.</p>

<p>Cheers!</p>

<p><a href="/sandeepk/tag:TIL" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">TIL</span></a>
<a href="/sandeepk/tag:CSV" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">CSV</span></a>
<a href="/sandeepk/tag:HTML" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">HTML</span></a> Table</p>
]]></content:encoded>
      <guid>https://blogs.dgplug.org/sandeepk/converting-html-tables-to-csv</guid>
      <pubDate>Sat, 15 Apr 2023 17:41:58 +0000</pubDate>
    </item>
    <item>
      <title>Exchange Image File Format(EXIF) Rotation</title>
      <link>https://blogs.dgplug.org/sandeepk/exchange-image-file-format-exif-rotation</link>
      <description>&lt;![CDATA[The other day, I was working with images which need me to use image EXIF rotation to show in right orientation. Which leads me to read about EXIF, so here are my notes about the same.&#xA;&#xA;What is EXIF&#xA;Exchange image file format is a protocol whose initial definition was produced by Japan Electronic Industries Development Association(JEIDA). It stores the various meta information of the images taken by a digital camera, which is stored as tag and value. There are many tags but for my problem  Orientation (rotation) tag is of interest. The orientation tag value can be from 1 to 8 which signifies different meanings according to the position of the camera while taking the image.&#xA;&#xA;EXIF Meta information from GIMP&#xA;Image metadata from GIMP tool&#xA;&#xA;Different Rotation&#xA;EXIF rotation helps the image viewer application to show the image in the right orientation if it&#39;s compatible with the EXIF metadata. Window users might have noticed that before Window 8 image shown is without rotation, but after Window 8 all images are shown in their right orientation because of the compatibility with EXIF.&#xA;&#xA;Different Rotation&#xA;Above image is taken from this blog&#xA;&#xA;| EXIF Orientation Tag Value |Row | Column |&#xA;| ----------- | ----------- |----------- |&#xA;| 1 | Top| Left Side |&#xA;| 3 |Bottom |Right Side |&#xA;|  6|Right Side |Top|&#xA;| 8 |Left Side | Bottom|&#xA;&#xA;What Problem I have and how EXIF meta helpful&#xA;So, the issue I am trying to solve is that we need to show the user&#39;s uploaded images that can have a different orientation, to fix this we need to rotate images which can be achieved at the server or the browser side. Working with Python makes it easy to handle the image with the help of Pillow library.&#xA;&#xA;Image with rotation 3&#xA;Image with different rotation&#xA;&#xA;from PIL import Image&#xA;&#xA;rotationdict = {3: 180, 6: 270, 8: 90}&#xA;EXIFORIENTATIONTAG = 274&#xA;image = Image.open(image)&#xA;exifdata = image.getexif()&#xA;if exifdata:&#xA;    rotationdegree = rotationdict.get(exifdata.get(EXIFORIENTATIONTAG))&#xA;    if rotationdegree:&#xA;        imagefile = imagefile.rotate(rotationdegree)&#xA;&#xA;This also can be achieved with CSS  image-orientation which can be used with mostly all browser&#xA;&#xA;/ keyword values /&#xA;image-orientation: none;&#xA;image-orientation: from-image; / Use EXIF data from the image /&#xA;&#xA;/ Global values /&#xA;image-orientation: inherit;&#xA;image-orientation: initial;&#xA;image-orientation: revert;&#xA;image-orientation: unset;&#xA;&#xA;At last, I go with the CSS solution, which solves our use case with the least effort/code changes.&#xA;&#xA;Cheers!&#xA;&#xA;100DaysToOffload&#xA;TIL&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>The other day, I was working with images which need me to use image EXIF rotation to show in right orientation. Which leads me to read about EXIF, so here are my notes about the same.</p>

<p><strong>What is EXIF</strong>
Exchange image file format is a protocol whose initial definition was produced by Japan Electronic Industries Development Association(<em>JEIDA</em>). It stores the various meta information of the images taken by a digital camera, which is stored as tag and value. There are many tags but for my problem  <em>Orientation (rotation)</em> tag is of interest. The orientation tag value can be from 1 to 8 which signifies different meanings according to the position of the camera while taking the image.</p>

<p><img src="https://raw.githubusercontent.com/Skchoudhary/blog-asset/master/dgplug-blog/exif-meta.png" alt="EXIF Meta information from GIMP">
<em>Image metadata from GIMP tool</em></p>

<p><strong>Different Rotation</strong>
EXIF rotation helps the image viewer application to show the image in the right orientation if it&#39;s compatible with the EXIF metadata. Window users might have noticed that before Window 8 image shown is without rotation, but after Window 8 all images are shown in their right orientation because of the compatibility with EXIF.</p>

<p><img src="https://raw.githubusercontent.com/Skchoudhary/blog-asset/master/dgplug-blog/orient_flag2.gif" alt="Different Rotation">
<em>Above image is taken from this <a href="https://www.impulseadventure.com/photo/exif-orientation.html" rel="nofollow">blog</a></em></p>

<table>
<thead>
<tr>
<th>EXIF Orientation Tag Value</th>
<th>Row</th>
<th>Column</th>
</tr>
</thead>

<tbody>
<tr>
<td>1</td>
<td>Top</td>
<td>Left Side</td>
</tr>

<tr>
<td>3</td>
<td>Bottom</td>
<td>Right Side</td>
</tr>

<tr>
<td>6</td>
<td>Right Side</td>
<td>Top</td>
</tr>

<tr>
<td>8</td>
<td>Left Side</td>
<td>Bottom</td>
</tr>
</tbody>
</table>

<p><strong>What Problem I have and how EXIF meta helpful</strong>
So, the issue I am trying to solve is that we need to show the user&#39;s uploaded images that can have a different orientation, to fix this we need to rotate images which can be achieved at the server or the browser side. Working with Python makes it easy to handle the image with the help of Pillow library.</p>

<p><img src="https://raw.githubusercontent.com/Skchoudhary/blog-asset/master/dgplug-blog/rotation-3.jpg" alt="Image with rotation 3">
<em>Image with different rotation</em></p>

<pre><code class="language-python">from PIL import Image

rotation_dict = {3: 180, 6: 270, 8: 90}
EXIF_ORIENTATION_TAG = 274
image = Image.open(image)
exif_data = image._getexif()
if exif_data:
    rotation_degree = rotation_dict.get(exif_data.get(EXIF_ORIENTATION_TAG))
    if rotation_degree:
        image_file = image_file.rotate(rotation_degree)

</code></pre>

<p>This also can be achieved with CSS  <code>image-orientation</code> which can be used with mostly all <a href="https://caniuse.com/?search=image-orientation" rel="nofollow">browser</a></p>

<pre><code class="language-css">/* keyword values */
image-orientation: none;
image-orientation: from-image; /* Use EXIF data from the image */

/* Global values */
image-orientation: inherit;
image-orientation: initial;
image-orientation: revert;
image-orientation: unset;
</code></pre>

<p>At last, I go with the CSS solution, which solves our use case with the least effort/code changes.</p>

<p>Cheers!</p>

<p><a href="/sandeepk/tag:100DaysToOffload" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">100DaysToOffload</span></a>
<a href="/sandeepk/tag:TIL" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">TIL</span></a></p>
]]></content:encoded>
      <guid>https://blogs.dgplug.org/sandeepk/exchange-image-file-format-exif-rotation</guid>
      <pubDate>Wed, 24 Nov 2021 06:33:50 +0000</pubDate>
    </item>
    <item>
      <title>Python : Data Class</title>
      <link>https://blogs.dgplug.org/sandeepk/python-data-class</link>
      <description>&lt;![CDATA[A data class is a class containing data only, from Python3.7 we can define a data class with the help of decorator @dataclass, which build the class with the basic functionality like init , repr, eq and more special methods.&#xA;&#xA;Let see how to define your data class with the decorator @dataclass&#xA;from dataclasses import dataclass&#xA;&#xA;@dataclass&#xA;class Batch:&#xA;    sku: int&#xA;    name: str&#xA;    qty: int&#xA;&#xA;      Batch(1, &#39;desk&#39;, 100)&#xA;Batch(sku=1, name=&#39;desk&#39;, qty=100)&#xA;We can also add the default value to the data class, which works exactly as if we do in the init  method of regular class. As you have noticed in the above we have defined the fields with type hints, which is kind of mandatory thing in the data class, if you do not do it will not take the field in your data class.&#xA;&#xA;@dataclass&#xA;class Batch:&#xA;    sku: int = 1&#xA;    name: str = &#39;desk&#39;&#xA;    qty: int = 100&#xA;&#xA;if you don&#39;t want to explicity type the fields you can use any&#xA;from typing import Any&#xA;class AnyBatch:&#xA;    sku: Any&#xA;    name: Any = &#39;desk&#39;&#xA;    qty: Any = 100&#xA;&#xA;If you want to define mutable default value in data class, it can be done with the help of defaultfactory and field. Field() is used to customize each field in data class, different parameter that can be passed to field are defaultfactory, compare, hash, init, you can check about them over here &#xA;from dataclasses import dataclass, field&#xA;from typing import List&#xA;&#xA;@dataclass()&#xA;class Batch:&#xA;    sku: int&#xA;    name: str&#xA;    qty: int = 0&#xA;    creator: List[str] = field(default_factory=function/mutable value)&#xA;&#xA;Immutable Data Class&#xA;we can also define our data class as immutable by setting frozen=True, which basically means we cannot assign value to the fields after creation&#xA;@dataclass(frozen=True)&#xA;class Batch:&#xA;    sku: int&#xA;    name: str&#xA;    qty: int = 0&#xA;&#xA;      b = Batch(12, &#39;desk&#39;, 100)&#xA;      b.qty &#xA;100&#xA;      b.qty = 90&#xA;dataclasses.FrozenInstanceError: cannot assign to field &#39;qty&#39;&#xA;Data class saves us from writing boilerplate code, help us to focus on logic, this new feature of Python3.7 is great, so what waiting for go and right some data classes.&#xA;&#xA;Cheers!&#xA;&#xA;100DaysToOffload&#xA;Python&#xA;DataClass&#xA;TIL&#xA;DGPLUG&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>A data class is a class containing data only, from Python3.7 we can define a data class with the help of decorator <code>@dataclass</code>, which build the class with the basic functionality like <code>__init__</code> , <code>__repr__</code>, <code>__eq__</code> and more special methods.</p>

<p>Let see how to define your data class with the decorator <code>@dataclass</code></p>

<pre><code class="language-python">from dataclasses import dataclass

@dataclass
class Batch:
    sku: int
    name: str
    qty: int

&gt;&gt;&gt; Batch(1, &#39;desk&#39;, 100)
Batch(sku=1, name=&#39;desk&#39;, qty=100)
</code></pre>

<p>We can also add the default value to the data class, which works exactly as if we do in the <code>__init__</code>  method of regular class. As you have noticed in the above we have defined the fields with type hints, which is kind of mandatory thing in the data class, if you do not do it will not take the field in your data class.</p>

<pre><code class="language-python">@dataclass
class Batch:
    sku: int = 1
    name: str = &#39;desk&#39;
    qty: int = 100

# if you don&#39;t want to explicity type the fields you can use any
from typing import Any
class AnyBatch:
    sku: Any
    name: Any = &#39;desk&#39;
    qty: Any = 100

</code></pre>

<p>If you want to define mutable default value in data class, it can be done with the help of <code>default_factory</code> and <code>field</code>. Field() is used to customize each field in data class, different parameter that can be passed to field are <code>default_factory</code>, <code>compare</code>, <code>hash</code>, <code>init</code>, you can check about them over <a href="https://docs.python.org/3/library/dataclasses.html#dataclasses.field" rel="nofollow">here </a></p>

<pre><code class="language-python">from dataclasses import dataclass, field
from typing import List

@dataclass()
class Batch:
    sku: int
    name: str
    qty: int = 0
    creator: List[str] = field(default_factory=&lt;function/mutable value&gt;)
</code></pre>

<p><strong>Immutable Data Class</strong>
we can also define our data class as immutable by setting <code>frozen=True</code>, which basically means we cannot assign value to the fields after creation</p>

<pre><code class="language-python">@dataclass(frozen=True)
class Batch:
    sku: int
    name: str
    qty: int = 0

&gt;&gt;&gt; b = Batch(12, &#39;desk&#39;, 100)
&gt;&gt;&gt; b.qty 
100
&gt;&gt;&gt; b.qty = 90
dataclasses.FrozenInstanceError: cannot assign to field &#39;qty&#39;
</code></pre>

<p>Data class saves us from writing boilerplate code, help us to focus on logic, this new feature of Python3.7 is great, so what waiting for go and right some data classes.</p>

<p>Cheers!</p>

<p><a href="/sandeepk/tag:100DaysToOffload" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">100DaysToOffload</span></a>
<a href="/sandeepk/tag:Python" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">Python</span></a>
<a href="/sandeepk/tag:DataClass" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">DataClass</span></a>
<a href="/sandeepk/tag:TIL" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">TIL</span></a>
<a href="/sandeepk/tag:DGPLUG" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">DGPLUG</span></a></p>
]]></content:encoded>
      <guid>https://blogs.dgplug.org/sandeepk/python-data-class</guid>
      <pubDate>Fri, 03 Sep 2021 12:54:52 +0000</pubDate>
    </item>
  </channel>
</rss>