<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Deepankar Sharma's Blog - Python, DevOps & Full-Stack Development Insights]]></title><description><![CDATA[By Deepankar Sharma - Here I share insights, tips and best practices for Software Development. Mainly focused on Full-Stack Development, Python, DevOps and Linux.]]></description><link>https://blog.deepankar.online</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1634994248345/5ShZil-Mf.jpeg</url><title>Deepankar Sharma&apos;s Blog - Python, DevOps &amp; Full-Stack Development Insights</title><link>https://blog.deepankar.online</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 25 Apr 2026 06:01:39 GMT</lastBuildDate><atom:link href="https://blog.deepankar.online/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Evolution of Python: Essential Features from 3.6 to 3.13]]></title><description><![CDATA[Remember 2016? While the world was busy with Pokemon Go and the Rio Olympics, I was a wide-eyed college student, writing my very first "Hello, World!" in Python. Back then, I had no idea what dictionary order preservation meant, let alone why the Pyt...]]></description><link>https://blog.deepankar.online/the-evolution-of-python-essential-features-from-36-to-313</link><guid isPermaLink="true">https://blog.deepankar.online/the-evolution-of-python-essential-features-from-36-to-313</guid><dc:creator><![CDATA[Deepankar Sharma]]></dc:creator><pubDate>Fri, 18 Oct 2024 10:17:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729246997493/97c64711-4e3c-48a5-9827-a86e9598f626.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Remember 2016? While the world was busy with Pokemon Go and the Rio Olympics, I was a wide-eyed college student, writing my very first "Hello, World!" in Python. Back then, I had no idea what dictionary order preservation meant, let alone why the Python community was buzzing about its inclusion in the upcoming 3.6 release. Now, looking back as a seasoned developer, it's amazing to see how far both Python and I have come.</p>
<p>From f-strings in 3.6 to the game-changing pattern matching in 3.10, and now to the free-threaded feature in 3.13, Python has consistently pushed the boundaries of what we can achieve with cleaner, more expressive code. It's like watching your favourite superhero get new powers with each movie – except instead of shooting webs or wielding a hammer, we're getting better tools to fight the real villains: code complexity and verbosity.</p>
<p>In this article, we're going to fire up our time machine and take a journey through the most significant features introduced in each Python version from 3.6 to 3.13. We'll look at the top features from each release, exploring how they've transformed the way we write Python code. Whether you're a seasoned Pythonista looking to reminisce or a newbie curious about the language's evolution, buckle up – we're in for an exciting ride through Python history!</p>
<p>By the end of this journey, you might just find yourself looking at your old code and thinking, "Wow, how did we ever live without these features? Let's dive in and see how our favourite snake has shed its skin over the years, emerging stronger and more powerful with each transformation.</p>
<h1 id="heading-python-36-the-one-with-f-strings">Python 3.6: The One With F-Strings</h1>
<h3 id="heading-1-f-strings-making-string-formatting-great-again-pep-498">1. F-Strings: Making String Formatting Great Again (PEP 498)</h3>
<p>If there's one feature that made Python developers collectively sigh with relief, it's f-strings. Remember the days of <code>.format()</code> and <code>%</code> formatting? F-strings swooped in to save us from verbose string formatting nightmares.</p>
<pre><code class="lang-py"><span class="hljs-comment"># The old ways</span>
name, language, year = <span class="hljs-string">"Alice"</span>, <span class="hljs-string">"Python"</span>, <span class="hljs-number">2016</span>
print(<span class="hljs-string">"{} started learning {} in {}"</span>.format(name, language, year))  <span class="hljs-comment"># .format()</span>
print(<span class="hljs-string">"%s started learning %s in %d"</span> % (name, language, year))      <span class="hljs-comment"># % formatting</span>

<span class="hljs-comment"># The f-string way</span>
print(<span class="hljs-string">f"<span class="hljs-subst">{name}</span> started learning <span class="hljs-subst">{language}</span> in <span class="hljs-subst">{year}</span>"</span>)

<span class="hljs-comment"># But wait, there's more! F-strings can handle expressions</span>
items = [<span class="hljs-string">"code"</span>, <span class="hljs-string">"coffee"</span>, <span class="hljs-string">"bugs"</span>]
print(<span class="hljs-string">f"Developer life: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(items[:<span class="hljs-number">-1</span>])}</span> and <span class="hljs-subst">{items[<span class="hljs-number">-1</span>]}</span>"</span>)
print(<span class="hljs-string">f"Hours coding today: <span class="hljs-subst">{<span class="hljs-number">8</span> * <span class="hljs-number">2</span>}</span>"</span>)  <span class="hljs-comment"># Math? No problem!</span>

<span class="hljs-comment"># They even work with method calls</span>
message = <span class="hljs-string">"  python rocks  "</span>
print(<span class="hljs-string">f"Confession: <span class="hljs-subst">{message.strip().title()}</span>"</span>)
</code></pre>
<h3 id="heading-2-underscores-in-numeric-literals-because-readability-counts-pep-515">2. Underscores in Numeric Literals: Because Readability Counts (PEP 515)</h3>
<p>For those of us who deal with large numbers, this feature was a game-changer. No more counting zeros on your screen!</p>
<pre><code class="lang-python"><span class="hljs-comment"># Before: Is this a billion or a million? 🤔</span>
old_budget = <span class="hljs-number">1000000000</span>

<span class="hljs-comment"># After: Crystal clear! 👌</span>
new_budget = <span class="hljs-number">1</span>_000_000_000

<span class="hljs-comment"># Works with different number types</span>
hex_address = <span class="hljs-number">0xFF</span>_FF_FF_FF  <span class="hljs-comment"># Much easier to read!</span>
binary_flag = <span class="hljs-number">0</span>b_1111_0000   <span class="hljs-comment"># Grouping bits? Yes please!</span>

<span class="hljs-comment"># Real-world example: Configuring a web server</span>
MAX_CONNECTIONS = <span class="hljs-number">1</span>_000
TIMEOUT_MS = <span class="hljs-number">30</span>_000
CACHE_SIZE_BYTES = <span class="hljs-number">100</span>_000_000
</code></pre>
<h3 id="heading-3-variable-annotations-hints-that-dont-hurt-pep-526">3. Variable Annotations: Hints That Don't Hurt (PEP 526)</h3>
<p>Type hints existed before, but Python 3.6 made them more flexible with variable annotations. It allowed cleaner type hinting, paving the way for better static analysis.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Before Python 3.6 (still works, but less flexible)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_user_data</span>(<span class="hljs-params">user_id: int</span>) -&gt; dict:</span>
    <span class="hljs-keyword">pass</span>

<span class="hljs-comment"># Python 3.6 style</span>
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> Dict, List, Optional

<span class="hljs-comment"># Class attributes with type hints</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDataAnalyzer</span>:</span>
    premium_users: List[int] = []
    cache: Dict[int, str] = {}
    last_analyzed: Optional[str] = <span class="hljs-literal">None</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">analyze_user</span>(<span class="hljs-params">self, user_id: int</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        <span class="hljs-comment"># Some analysis logic here</span>
        self.last_analyzed = <span class="hljs-string">"2024-10-07"</span>

<span class="hljs-comment"># Module level variables</span>
MAX_RETRIES: int = <span class="hljs-number">3</span>
API_VERSION: str = <span class="hljs-string">"v2"</span>
</code></pre>
<p>Bonus tip: These annotations don't affect runtime behaviour - they're hints for developers and tools. But they make your IDE's autocomplete work like magic! ✨</p>
<h1 id="heading-python-37-the-one-with-dataclasses">Python 3.7: The One With Dataclasses</h1>
<h3 id="heading-1-dataclasses-because-lifes-too-short-for-boilerplate-pep-557">1. Dataclasses: Because Life's Too Short for Boilerplate (PEP 557)</h3>
<p>Remember writing classes with a bunch of <code>__init__</code> parameters and then painstakingly assigning each one? Dataclasses simplified the creation of classes by auto-generating boilerplate code like <code>__init__</code>, <code>__repr__</code>, and <code>__eq__</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> dataclasses <span class="hljs-keyword">import</span> dataclass
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-comment"># Before dataclasses 😫</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OldBooking</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, id, destination, traveler, date, price</span>):</span>
        self.id = id
        self.destination = destination
        self.traveler = traveler
        self.date = date
        self.price = price

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__repr__</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">f"Booking(<span class="hljs-subst">{self.id}</span>, <span class="hljs-subst">{self.destination}</span>, <span class="hljs-subst">{self.traveler}</span>)"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__eq__</span>(<span class="hljs-params">self, other</span>):</span>
        <span class="hljs-keyword">return</span> isinstance(other, OldBooking) <span class="hljs-keyword">and</span> self.id == other.id

<span class="hljs-comment"># After dataclasses 😎</span>
<span class="hljs-meta">@dataclass</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Booking</span>:</span>
    id: int
    destination: str
    traveler: str
    date: datetime
    price: float

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">total_with_tax</span>(<span class="hljs-params">self, tax_rate: float = <span class="hljs-number">0.1</span></span>) -&gt; float:</span>
        <span class="hljs-keyword">return</span> self.price * (<span class="hljs-number">1</span> + tax_rate)

<span class="hljs-comment"># Using our dataclass</span>
trip = Booking(
    id=<span class="hljs-number">42</span>,
    destination=<span class="hljs-string">"Python Island"</span>,
    traveler=<span class="hljs-string">"Pythonista"</span>,
    date=datetime.now(),
    price=<span class="hljs-number">199.99</span>
)

print(<span class="hljs-string">f"Trip cost with tax: $<span class="hljs-subst">{trip.total_with_tax():<span class="hljs-number">.2</span>f}</span>"</span>)
</code></pre>
<h3 id="heading-2-postponed-evaluation-of-annotations-pep-563">2. Postponed Evaluation of Annotations (PEP 563)</h3>
<p>This feature sounds boring but solved a major headache: enabled forward references and improved performance with lazy evaluation.</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> __future__ <span class="hljs-keyword">import</span> annotations
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChessGame</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self.players: List[Player] = []  <span class="hljs-comment"># This now works!</span>
        self.board: Board = Board()      <span class="hljs-comment"># This too!</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_player</span>(<span class="hljs-params">self, player: Player</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.players.append(player)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_winner</span>(<span class="hljs-params">self</span>) -&gt; Player | <span class="hljs-keyword">None</span>:</span>  <span class="hljs-comment"># Python 3.10 union type just for fun!</span>
        <span class="hljs-comment"># Game logic here</span>
        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Player</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name: str, rating: int</span>):</span>
        self.name = name
        self.rating = rating

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Board</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        self.moves: List[tuple[Player, str]] = []
</code></pre>
<h3 id="heading-3-built-in-breakpoint-debugging-made-human-friendly-pep-553">3. Built-in breakpoint(): Debugging Made Human-Friendly (PEP 553)</h3>
<p>Gone are the days of typing <code>import pdb; pdb.set_trace()</code>. Now we can just drop a <code>breakpoint()</code> and get on with our lives!</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_universe_answer</span>():</span>
    numbers = list(range(<span class="hljs-number">43</span>))
    breakpoint()  <span class="hljs-comment"># Your IDE probably supports this better than pdb!</span>
    <span class="hljs-keyword">return</span> sum(numbers) - <span class="hljs-number">903</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">main</span>():</span>
    print(<span class="hljs-string">"Calculating the answer to life, universe, and everything..."</span>)
    result = calculate_universe_answer()
    print(<span class="hljs-string">f"The answer is: <span class="hljs-subst">{result}</span>"</span>)

<span class="hljs-comment"># When you run this, you'll drop into a debugger at the breakpoint</span>
<span class="hljs-comment"># Try these in the debugger:</span>
<span class="hljs-comment"># - 'numbers' to see the list</span>
<span class="hljs-comment"># - 'len(numbers)' to check its length</span>
<span class="hljs-comment"># - 'n' to go to next line</span>
<span class="hljs-comment"># - 'c' to continue execution</span>
</code></pre>
<p>Debugging Tip: Set the <code>PYTHONBREAKPOINT</code> environment variable to control breakpoint behavior:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Disable all breakpoints</span>
<span class="hljs-built_in">export</span> PYTHONBREAKPOINT=0

<span class="hljs-comment"># Use a different debugger (like IPython's)</span>
<span class="hljs-built_in">export</span> PYTHONBREAKPOINT=IPython.embed
</code></pre>
<hr />
<p>Python 3.7 might not have been as flashy as 3.6, but it brought some serious quality-of-life improvements. Dataclasses alone probably saved millions of keystrokes worldwide! Anything that makes debugging easier is worth its weight in gold-plated pythons.</p>
<h1 id="heading-python-38-the-one-with-the-walrus">Python 3.8: The One With the Walrus</h1>
<h3 id="heading-1-assignment-expressions-the-walrus-operator-pep-572">1. Assignment Expressions (:=) - The Walrus Operator (PEP 572)</h3>
<p>The most controversial yet powerful addition to Python. It allows you to assign values to variables as part of a larger expression. The walrus operator allows you to do two things at once:</p>
<ol>
<li><p>Assign a value to a variable</p>
</li>
<li><p>Use that value in a larger expression</p>
</li>
</ol>
<pre><code class="lang-python"><span class="hljs-comment"># Consider this code example:</span>
<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:
    user_input = input(<span class="hljs-string">"Enter something (or 'quit' to exit): "</span>)
    <span class="hljs-keyword">if</span> user_input == <span class="hljs-string">'quit'</span>:
        <span class="hljs-keyword">break</span>
    print(<span class="hljs-string">f"You entered: <span class="hljs-subst">{user_input}</span>"</span>)


<span class="hljs-comment"># We can simplify above code using walrus operator like this:</span>
<span class="hljs-keyword">while</span> (user_input := input(<span class="hljs-string">"Enter something (or 'quit' to exit): "</span>)) != <span class="hljs-string">'quit'</span>:
    print(<span class="hljs-string">f"You entered: <span class="hljs-subst">{user_input}</span>"</span>)
</code></pre>
<h3 id="heading-2-positional-only-parameters-because-sometimes-order-matters-pep-570">2. Positional-Only Parameters (/) - Because Sometimes Order Matters (PEP 570)</h3>
<p>When you want to say "these args go here, no questions asked!". You can specify arguments that must be passed by position, not by keyword. This feature enhances API design flexibility and can prevent breaking changes in function signatures.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">create_character</span>(<span class="hljs-params">name, /, health=<span class="hljs-number">100</span>, *, special_move</span>):</span>
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"<span class="hljs-subst">{name}</span>: <span class="hljs-subst">{health}</span>HP, Special: <span class="hljs-subst">{special_move}</span>"</span>

<span class="hljs-comment"># These work</span>
player1 = create_character(<span class="hljs-string">"Pythonista"</span>, special_move=<span class="hljs-string">"Code Sprint"</span>)
player2 = create_character(<span class="hljs-string">"Bug Slayer"</span>, health=<span class="hljs-number">120</span>, special_move=<span class="hljs-string">"Debug Strike"</span>)

<span class="hljs-comment"># This fails - name must be positional</span>
<span class="hljs-comment"># player3 = create_character(name="Syntax Error", special_move="Crash Game")</span>
</code></pre>
<h3 id="heading-3-f-strings-support-self-documenting-expressions">3. f-strings Support '=': Self-Documenting Expressions</h3>
<p>Added support for <code>=</code> inside f-strings, making debugging easier.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> random
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> datetime

<span class="hljs-comment"># Debugging game stats</span>
player_hp = random.randint(<span class="hljs-number">1</span>, <span class="hljs-number">100</span>)
potions = random.randint(<span class="hljs-number">0</span>, <span class="hljs-number">5</span>)
boss_hp = random.randint(<span class="hljs-number">50</span>, <span class="hljs-number">200</span>)
current_timestamp = datetime.now()

print(<span class="hljs-string">f"<span class="hljs-subst">{player_hp=}</span>, <span class="hljs-subst">{potions=}</span>, <span class="hljs-subst">{boss_hp=}</span>"</span>)
print(<span class="hljs-string">f"<span class="hljs-subst">{current_timestamp=:%Y-%m-%d %H:%M:%S}</span>"</span>)

<span class="hljs-comment"># Output:</span>
<span class="hljs-comment"># player_hp=9, potions=3, boss_hp=135</span>
<span class="hljs-comment"># current_timestamp=2024-10-18 02:20:12</span>
</code></pre>
<hr />
<p>The walrus operator let us write more concise code (though with great power comes great responsibility!), positional-only parameters gave us more control over our function interfaces, and f-string debugging made print-debugging actually pleasant.</p>
<h1 id="heading-python-39-the-merge-master">Python 3.9: The Merge Master</h1>
<h3 id="heading-1-dictionary-union-operators-pep-584">1. Dictionary Union Operators (PEP 584)</h3>
<p>Finally, Python gave us a clean way to merge dictionaries! Remember the days when we had to write <code>dict1.update(dict2)</code> or use <code>{**dict1, **dict2}</code>? Those days are behind us now.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Your gaming inventory</span>
inventory = {
    <span class="hljs-string">"health_potions"</span>: <span class="hljs-number">5</span>,
    <span class="hljs-string">"mana_potions"</span>: <span class="hljs-number">3</span>,
    <span class="hljs-string">"gold_coins"</span>: <span class="hljs-number">100</span>
}

<span class="hljs-comment"># You found a treasure chest!</span>
treasure = {
    <span class="hljs-string">"gold_coins"</span>: <span class="hljs-number">50</span>,  <span class="hljs-comment"># More coins!</span>
    <span class="hljs-string">"magic_sword"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-string">"dragon_scale"</span>: <span class="hljs-number">2</span>
}

<span class="hljs-comment"># The new | operator merges dictionaries</span>
updated_inventory = inventory | treasure
print(updated_inventory)
<span class="hljs-comment"># Output: {'health_potions': 5, 'mana_potions': 3, 'gold_coins': 50, </span>
<span class="hljs-comment">#          'magic_sword': 1, 'dragon_scale': 2}</span>

<span class="hljs-comment"># Notice how treasure's gold_coins overwrote inventory's value</span>
<span class="hljs-comment"># The right-hand dictionary takes precedence!</span>
</code></pre>
<h3 id="heading-2-type-hinting-generics-in-standard-collections-pep-585">2. Type Hinting Generics In Standard Collections (PEP 585)</h3>
<p>This addition eliminated the need for <code>typing.List</code>, <code>typing.Dict</code>, etc., simplifying type annotations.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Old way (pre-3.9) 🥱</span>
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> List, Dict, Tuple

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_user_data</span>(<span class="hljs-params">
    users: List[str],
    scores: Dict[str, int],
    coordinates: Tuple[float, float]
</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
    <span class="hljs-keyword">pass</span>

<span class="hljs-comment"># New way (3.9+) 😎</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_user_data</span>(<span class="hljs-params">
    users: list[str],
    scores: dict[str, int],
    coordinates: tuple[float, float]
</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
    <span class="hljs-keyword">pass</span>

<span class="hljs-comment"># Perfect for documenting game leaderboards!</span>
leaderboard: dict[str, int] = {
    <span class="hljs-string">"DragonSlayer"</span>: <span class="hljs-number">1000</span>,
    <span class="hljs-string">"WizardSupreme"</span>: <span class="hljs-number">850</span>,
    <span class="hljs-string">"QuestMaster"</span>: <span class="hljs-number">750</span>
}
</code></pre>
<h3 id="heading-3-string-methods-removeprefix-and-removesuffix-pep-616">3. String Methods: removeprefix() and removesuffix() (PEP 616)</h3>
<p>These might seem simple, but they're incredibly powerful for text processing. No more clunky string slicing or <code>replace()</code> calls with hardcoded lengths!</p>
<pre><code class="lang-python"><span class="hljs-comment"># Processing log files has never been easier</span>
log_entry = <span class="hljs-string">"ERROR: Database connection failed!"</span>
clean_message = log_entry.removeprefix(<span class="hljs-string">"ERROR: "</span>)
print(clean_message)  <span class="hljs-comment"># "Database connection failed!"</span>

<span class="hljs-comment"># Cleaning up file extensions</span>
filenames = [
    <span class="hljs-string">"photo_001.jpeg"</span>,
    <span class="hljs-string">"photo_002.jpeg"</span>,
    <span class="hljs-string">"not_a_photo.txt"</span>
]

jpeg_names = [
    name.removesuffix(<span class="hljs-string">".jpeg"</span>) 
    <span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> filenames 
    <span class="hljs-keyword">if</span> name.endswith(<span class="hljs-string">".jpeg"</span>)
]
print(jpeg_names)  <span class="hljs-comment"># ['photo_001', 'photo_002']</span>
</code></pre>
<h1 id="heading-python-310-the-pattern-master">Python 3.10: The Pattern Master</h1>
<p>Python 3.10 (released October 2021), brought some seriously awesome pattern matching features to the table.</p>
<h3 id="heading-1-structural-pattern-matching-pep-634">1. Structural Pattern Matching (PEP 634)</h3>
<p>Switch cases were so last decade. Pattern matching arrived like a Swiss Army knife for data structures. It's not just about matching values; it's about deconstructing data with the elegance of a code sommelier.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_api_response</span>(<span class="hljs-params">response</span>):</span>
    match response:
        case {<span class="hljs-string">"status"</span>: <span class="hljs-string">"success"</span>, <span class="hljs-string">"data"</span>: {<span class="hljs-string">"users"</span>: [{<span class="hljs-string">"name"</span>: str(name), <span class="hljs-string">"age"</span>: int(age)}, *_]}}:
            print(<span class="hljs-string">f"First user is <span class="hljs-subst">{name}</span>, <span class="hljs-subst">{age}</span> years old"</span>)
        case {<span class="hljs-string">"status"</span>: <span class="hljs-string">"error"</span>, <span class="hljs-string">"code"</span>: <span class="hljs-number">404</span>}:
            print(<span class="hljs-string">"Not found, please check the endpoint"</span>)
        case {<span class="hljs-string">"status"</span>: <span class="hljs-string">"error"</span>, <span class="hljs-string">"message"</span>: str(msg)}:
            print(<span class="hljs-string">f"Error occurred: <span class="hljs-subst">{msg}</span>"</span>)
        case _:
            print(<span class="hljs-string">"Unknown response format"</span>)

<span class="hljs-comment"># Let's try it out</span>
responses = [
    {
        <span class="hljs-string">"status"</span>: <span class="hljs-string">"success"</span>,
        <span class="hljs-string">"data"</span>: {
            <span class="hljs-string">"users"</span>: [
                {<span class="hljs-string">"name"</span>: <span class="hljs-string">"CodingWizard"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">25</span>},
                {<span class="hljs-string">"name"</span>: <span class="hljs-string">"ByteMaster"</span>, <span class="hljs-string">"age"</span>: <span class="hljs-number">30</span>}
            ]
        }
    },
    {
        <span class="hljs-string">"status"</span>: <span class="hljs-string">"error"</span>,
        <span class="hljs-string">"code"</span>: <span class="hljs-number">404</span>
    }
]

<span class="hljs-keyword">for</span> response <span class="hljs-keyword">in</span> responses:
    process_api_response(response)
<span class="hljs-comment"># Output:</span>
<span class="hljs-comment"># First user is CodingWizard, 25 years old</span>
<span class="hljs-comment"># Not found, please check the endpoint</span>
</code></pre>
<h3 id="heading-2-parenthesized-context-managers-clean-multi-context-handling-pep-343">2. Parenthesized Context Managers - Clean Multi-Context Handling (PEP 343)</h3>
<p>Python 3.10 introduced a clean way to handle multiple context managers using parentheses.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Old way (pre-3.10)</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_files</span>(<span class="hljs-params">input_path, output_path, log_path</span>):</span>
    <span class="hljs-keyword">with</span> open(input_path, <span class="hljs-string">'r'</span>) <span class="hljs-keyword">as</span> input_file:
        <span class="hljs-keyword">with</span> open(output_path, <span class="hljs-string">'w'</span>) <span class="hljs-keyword">as</span> output_file:
            <span class="hljs-keyword">with</span> open(log_path, <span class="hljs-string">'a'</span>) <span class="hljs-keyword">as</span> log_file:
                <span class="hljs-comment"># Process the files...</span>

<span class="hljs-comment"># Python 3.10 way - Clean and clear!</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">analyze_data</span>(<span class="hljs-params">config_path, data_path</span>):</span>
    <span class="hljs-keyword">with</span> (
        ProcessPoolExecutor(max_workers=<span class="hljs-number">4</span>) <span class="hljs-keyword">as</span> executor,
        open(config_path, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> config_file,
        open(data_path, encoding=<span class="hljs-string">'utf-8'</span>) <span class="hljs-keyword">as</span> data_file,
        PerformanceMonitor() <span class="hljs-keyword">as</span> perf_monitor,
        DatabaseConnection(timeout=<span class="hljs-number">30</span>) <span class="hljs-keyword">as</span> db
    ):
        raw_data = data_file.read()
        <span class="hljs-comment"># process data</span>
</code></pre>
<h3 id="heading-3-better-error-messages-with-precise-line-indicators">3. Better Error Messages with Precise Line Indicators</h3>
<p>Python decided that "AttributeError" wasn't helpful enough and opted for "Did you mean..." suggestions. It's like having a built-in code reviewer who actually wants to help rather than just point out your mistakes.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Pre-3.10 error message for:</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_score</span>(<span class="hljs-params">player_stats</span>)
    <span class="hljs-title">return</span> <span class="hljs-title">player_stats</span>['<span class="hljs-title">hits</span>'] / <span class="hljs-title">player_stats</span>['<span class="hljs-title">attempts</span>']
# <span class="hljs-title">Would</span> <span class="hljs-title">show</span>:</span> SyntaxError: invalid syntax

<span class="hljs-comment"># Python 3.10 shows:</span>
<span class="hljs-comment"># def calculate_score(player_stats)</span>
<span class="hljs-comment">#                               ^</span>
<span class="hljs-comment"># SyntaxError: expected ':'</span>

<span class="hljs-comment"># And for nested parentheses/brackets:</span>
result = (
    player_stats[<span class="hljs-string">'hits'</span>] /
    (player_stats[<span class="hljs-string">'attempts'</span>]
    * <span class="hljs-number">100</span>
<span class="hljs-comment"># Python 3.10 clearly shows:</span>
<span class="hljs-comment">#     * 100</span>
<span class="hljs-comment">#          ^</span>
<span class="hljs-comment"># SyntaxError: '(' was never closed</span>
</code></pre>
<hr />
<p><em>Fun fact: The pattern matching syntax was inspired by Rust and other functional programming languages, but Python made it more Pythonic. If you're coming from languages like Scala or Elixir, you'll feel right at home!</em></p>
<h1 id="heading-python-311-the-speedster">Python 3.11: The Speedster</h1>
<p>Python 3.11 brought something we'd all been craving – serious speed improvements! This release wasn't just fast; it was "up to 60% faster than Python 3.10" fast, and 25% faster on average. But that's not all it brought to the table. Let me walk you through the most exciting features that made this version special.</p>
<h3 id="heading-1-turbocharged-performance-pep-659">1. Turbocharged Performance (PEP 659) 🚀</h3>
<p>While this isn't a feature you can "see" in code, it's one you'll definitely feel. Python 3.11 introduced a specialized adaptive interpreter that makes your code run significantly faster. Here's a quick example to demonstrate:</p>
<pre><code class="lang-python"><span class="hljs-comment"># This code runs noticeably faster in Python 3.11</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_fibonacci</span>(<span class="hljs-params">n: int</span>) -&gt; int:</span>
    <span class="hljs-keyword">if</span> n &lt;= <span class="hljs-number">1</span>:
        <span class="hljs-keyword">return</span> n
    <span class="hljs-keyword">return</span> calculate_fibonacci(n<span class="hljs-number">-1</span>) + calculate_fibonacci(n<span class="hljs-number">-2</span>)

<span class="hljs-comment"># Time it in Python 3.10 vs 3.11</span>
<span class="hljs-keyword">import</span> time

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">measure_performance</span>(<span class="hljs-params">func, n</span>):</span>
    start = time.perf_counter()
    result = func(n)
    end = time.perf_counter()
    <span class="hljs-keyword">return</span> end - start

<span class="hljs-comment"># Running this with n=35 shows significant improvement in 3.11</span>
<span class="hljs-comment"># Python 3.10: ~2.5 seconds</span>
<span class="hljs-comment"># Python 3.11: ~1.6 seconds</span>
</code></pre>
<p>The speed improvement is particularly noticeable in CPU-intensive tasks, error handling, and deeply nested function calls. It's like Python hit the gym and came back buffer than ever! 💪</p>
<h3 id="heading-2-exception-groups-and-except-pep-654">2. Exception Groups and except* (PEP 654)</h3>
<p>This feature is a lifesaver when dealing with concurrent operations where multiple errors might occur simultaneously. Instead of catching just one exception, we can now handle multiple exceptions as a group!</p>
<pre><code class="lang-python"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">fetch_user_data</span>(<span class="hljs-params">user_ids: list[int]</span>) -&gt; dict:</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-keyword">async</span> <span class="hljs-keyword">with</span> aiohttp.ClientSession() <span class="hljs-keyword">as</span> session:
            <span class="hljs-comment"># Imagine these API calls happening concurrently</span>
            tasks = [fetch_user(session, uid) <span class="hljs-keyword">for</span> uid <span class="hljs-keyword">in</span> user_ids]
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> asyncio.gather(*tasks)
    <span class="hljs-keyword">except</span>* ConnectionError <span class="hljs-keyword">as</span> eg:
        <span class="hljs-comment"># Handle all connection errors as a group</span>
        print(<span class="hljs-string">f"Connection issues: <span class="hljs-subst">{len(eg.exceptions)}</span> failures"</span>)
        <span class="hljs-keyword">for</span> exc <span class="hljs-keyword">in</span> eg.exceptions:
            print(<span class="hljs-string">f"- Failed to connect to <span class="hljs-subst">{exc.host}</span>"</span>)
    <span class="hljs-keyword">except</span>* ValueError <span class="hljs-keyword">as</span> eg:
        <span class="hljs-comment"># Handle all value errors separately</span>
        print(<span class="hljs-string">f"Data validation issues: <span class="hljs-subst">{len(eg.exceptions)}</span> failures"</span>)

    <span class="hljs-keyword">raise</span>  <span class="hljs-comment"># Re-raise any unhandled exceptions</span>
</code></pre>
<h3 id="heading-3-fine-grained-error-locations-in-tracebacks">3. Fine-grained Error Locations in Tracebacks</h3>
<p>Python 3.11 improved developer productivity by pinpointing errors more precisely. It's like having a built-in debugging assistant!</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calculate_user_score</span>(<span class="hljs-params">stats</span>):</span>
    <span class="hljs-keyword">return</span> stats.points * stats.multiplier / stats.games_played

<span class="hljs-comment"># If stats.games_played is 0, instead of just showing:</span>
<span class="hljs-comment"># ZeroDivisionError: division by zero</span>

<span class="hljs-comment"># Python 3.11 shows:</span>
<span class="hljs-comment"># Traceback (most recent call last):</span>
<span class="hljs-comment">#   File "game.py", line 2, in calculate_user_score</span>
<span class="hljs-comment">#     return stats.points * stats.multiplier / stats.games_played</span>
<span class="hljs-comment">#            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~</span>
<span class="hljs-comment"># ZeroDivisionError: division by zero</span>

<span class="hljs-comment"># It even suggests fixes for common mistakes!</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">process_data</span>(<span class="hljs-params">data</span>)  # <span class="hljs-title">Missing</span> <span class="hljs-title">colon</span>
    <span class="hljs-title">return</span> <span class="hljs-title">data</span>.<span class="hljs-title">process</span>()

# <span class="hljs-title">Python</span> 3.11 <span class="hljs-title">suggests</span>:</span>
<span class="hljs-comment"># Did you forget a colon ':' at the end of the line?</span>
</code></pre>
<p>These error messages are particularly helpful when dealing with complex mathematical operations or nested method calls. No more counting parentheses manually!</p>
<p>Python 3.11 wasn't just another incremental update – it was a massive leap forward in terms of performance and developer experience. The speed improvements alone make it a compelling upgrade, but throw in the new exception handling capabilities and enhanced error messages, and you've got yourself a release that truly deserves the "The Speedster" title!</p>
<h1 id="heading-python-312-the-flexible-foundation">Python 3.12: The Flexible Foundation</h1>
<h3 id="heading-1-enhanced-f-strings-pep-701">1. Enhanced F-Strings (PEP 701)</h3>
<p>With Python 3.12, f-strings have become even better! Earlier versions had some limitations—no backslashes or comments inside f-strings, and complex expressions sometimes required workarounds.</p>
<ul>
<li><p>Backslashes can now be used inside f-strings, so you can handle escape sequences like newlines (\n) or tabs (\t) without issues.</p>
</li>
<li><p>Comments can be added inside f-string expressions using the usual # syntax, making your code more readable and maintainable.</p>
</li>
</ul>
<pre><code class="lang-python">attendees = [<span class="hljs-string">"Ram"</span>, <span class="hljs-string">"Shyam"</span>, <span class="hljs-string">"Guido"</span>]
<span class="hljs-comment"># You can now the same type of quotes used in the beginning/end</span>
print(<span class="hljs-string">f"Event Attendees:\n\t<span class="hljs-subst">{<span class="hljs-string">", "</span>.join(attendees)}</span>"</span>)

<span class="hljs-comment"># Or add useful comments</span>
number = <span class="hljs-number">121</span>
print(<span class="hljs-string">f"""Square root of <span class="hljs-subst">{number}</span> is <span class="hljs-subst">{
# You can calculate square root without using `math.sqrt` module
number**<span class="hljs-number">0.5</span>
}</span>"""</span>)
<span class="hljs-comment"># Output: Square root of 121 is 11.0</span>

<span class="hljs-comment"># In python 3.11, you'd get this error on running above code:</span>
<span class="hljs-comment"># SyntaxError: f-string expression part cannot include '#'</span>
</code></pre>
<h3 id="heading-2-type-parameter-syntax-pep-695">2. Type Parameter Syntax (PEP 695)</h3>
<p>You no longer need to explicitly import <code>TypeVar</code> or <code>Generic</code>, reducing the boilerplate and improving code readability without sacrificing functionality.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Before Python 3.12</span>
<span class="hljs-keyword">from</span> typing <span class="hljs-keyword">import</span> TypeVar, Generic

T = TypeVar(<span class="hljs-string">'T'</span>)

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Stack</span>(<span class="hljs-params">Generic[T]</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.items = []

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">push</span>(<span class="hljs-params">self, item: T</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.items.append(item)


<span class="hljs-comment"># New in Python 3.12</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Stack</span>[<span class="hljs-title">T</span>]:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.items: list[T] = []

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">push</span>(<span class="hljs-params">self, item: T</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.items.append(item)
</code></pre>
<h3 id="heading-3-per-interpreter-gil-pep-684">3. Per-Interpreter GIL (PEP 684)</h3>
<p>One of Python's longest-standing pain points has been the Global Interpreter Lock (GIL), a mechanism that allows only one thread to execute Python bytecode at a time. This has led to performance bottlenecks in multi-threaded programs, especially for CPU-bound tasks. However, Python 3.12 introduces a significant improvement: Per-Interpreter GIL.</p>
<p>In simple terms, the GIL prevents Python from truly executing multiple threads simultaneously. Even though threads are often used for I/O-bound operations (like reading files or making network requests), the GIL limits the benefits of multi-threading for CPU-heavy workloads. This has long been a challenge for Python developers who need to take advantage of multi-core processors.</p>
<p>With Python 3.12, interpreters now have their own GIL, allowing multiple interpreters in the same process to run in parallel without being constrained by a single global lock. This is especially useful for multi-core processing. However, Python 3.12 will only support the per-interpreter GIL through the C-API. Full Python-API support will be added in Python 3.13.</p>
<p>More about this feature:</p>
<ul>
<li><p><a target="_blank" href="https://youtu.be/3ywZjnjeAO4">A Per-Interpreter GIL: Concurrency and Parallelism with Subinterpreters</a></p>
</li>
<li><p><a target="_blank" href="https://docs.python.org/3.12/whatsnew/3.12.html#whatsnew312-pep684">PEP 684: A Per-Interpreter GIL</a></p>
</li>
</ul>
<hr />
<p>Python 3.12 might not have the immediate performance impact of 3.11, but its improvements to type system ergonomics and f-string capabilities make it a significant release for writing maintainable, type-safe code. These features are particularly valuable in larger projects where code clarity and type safety are crucial.</p>
<h1 id="heading-python-313-the-developers-delight">Python 3.13: The Developer's Delight</h1>
<h3 id="heading-1-improved-interactive-interpreter-repl">1. Improved Interactive Interpreter (REPL)</h3>
<p>Python 3.13 enhances the Read-Eval-Print-Loop (REPL), making it smarter and more user-friendly. Now, REPL can execute multiple lines of code more effectively, display better syntax suggestions, and provide an improved auto-complete experience.</p>
<p>The new REPL has the following new features:</p>
<ul>
<li><p>Supports block-level history and block-level editing</p>
</li>
<li><p>Automatically handles indentation when you're typing code interactively</p>
</li>
<li><p>Browse REPL history using <code>F2</code> key</p>
</li>
<li><p>Pasting large code blocks just works (no more weird errors due to blank lines)</p>
</li>
<li><p>Tracebacks and prompts are colorized</p>
</li>
<li><p>You can exit the REPL just by typing exit, no need to invoke <code>exit()</code> function</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729246243787/e9a1cc41-5407-4d62-bd06-a9d9c9f1d465.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-2-free-threaded-mode-experimental-pep-703">2. Free-Threaded Mode - Experimental (PEP 703)</h3>
<p>For years, Python developers have been caught in the delicate dance around the Global Interpreter Lock (GIL), a mechanism that prevents multiple native threads from executing Python bytecodes at once. While the GIL has its advantages, it's also been a bottleneck for multi-threaded applications.</p>
<p>The free-threading mode in Python 3.13 aims to break these chains by disabling the GIL. This allows true parallelism in multi-threaded Python programs. Essentially, your threads can now run simultaneously, making the most out of multi-core processors. In previous versions, the GIL would force these threads to run one at a time, effectively serializing the execution.</p>
<p>You can <a target="_blank" href="https://py-free-threading.github.io/installing_cpython/">download the installers for macOS or Windows</a> – they've got a free-threading option, or you can use <code>pyenv</code> to build and install from source (recommended): <code>pyenv install 3.13.0t</code></p>
<p><strong>Note</strong>: While the free-threaded mode is a major advancement in the evolution of Python, it's important to keep in mind its experimental status (expect some bugs). Moreover, free-threaded build comes with a 40% single-threaded performance hit due to the disabled specializing adaptive interpreter (PEP 659).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729246226777/a9b2f8ce-254d-4b1a-8ab4-c0238b504672.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-3-just-in-time-compiler-experimental-pep-744">3. Just-In-Time Compiler - Experimental (PEP 744)</h3>
<p>The experimental Just-In-Time (JIT) compiler marks another significant milestone in the evolution of Python. The JIT compiler works by dynamically translating Python bytecode into machine code during runtime. It does this using a technique called <a target="_blank" href="https://en.wikipedia.org/wiki/Copy-and-patch">"copy-and-patch"</a>. This means that frequently executed code paths are compiled on-the-fly, which <em>can</em> theoretically lead to substantial performance improvements for critical sections of your code.</p>
<p>Now, don't get too excited just yet. In its current form, the JIT compiler isn't meant to make your code faster – it's just aiming to keep up with regular Python performance. But it's doing this while adding an extra step to the process, which is pretty impressive. The Python team has big plans for this little engine, hoping to rev it up in future versions to give us some real speed gains without hogging memory. Right now, it's more about proving the concept and laying the groundwork for future optimizations.</p>
<h1 id="heading-wrapping-up-the-journey">Wrapping Up the Journey</h1>
<p>As we mark the release of Python 3.13, one thing is clear: Python's evolution isn't just about adding features – it's about making developers' lives easier, one release at a time. It's not just about writing code; it's about writing better code, more elegantly, and with fewer headaches.</p>
<p>So, fellow Pythonistas, let's not rest on our laurels. The Python of today is not the Python we learned yesterday, and tomorrow's Python might surprise us yet again. Keep exploring, keep learning, and keep pushing the boundaries of what's possible with those two simple words: <code>import this</code> 🐍</p>
]]></content:encoded></item><item><title><![CDATA[How to Manage Multiple GitHub/GitLab/Bitbucket Accounts Using SSH Keys]]></title><description><![CDATA[If you’ve used the Git command-line utility, you may have noticed that Git often needs user credentials to perform operations over HTTP, especially when the repository is private. It is possible to permanently store user credentials in Git credential...]]></description><link>https://blog.deepankar.online/how-to-manage-multiple-github-gitlab-bitbucket-accounts-using-ssh-keys</link><guid isPermaLink="true">https://blog.deepankar.online/how-to-manage-multiple-github-gitlab-bitbucket-accounts-using-ssh-keys</guid><category><![CDATA[Git]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[GitLab]]></category><category><![CDATA[Bitbucket]]></category><category><![CDATA[ssh]]></category><dc:creator><![CDATA[Deepankar Sharma]]></dc:creator><pubDate>Mon, 22 Jun 2020 03:31:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634965296467/H0a3pGRZE.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you’ve used the Git command-line utility, you may have noticed that Git often needs user credentials to perform operations over HTTP, especially when the repository is private. It is possible to permanently store user credentials in Git credential storage to avoid entering them again and again, but this approach won’t work if you have to work on a remote repository which exists on another account. This gets even more complicated for systems with two-factor authentication, where the token you use for a password is randomly generated and unpronounceable.</p>
<p>We can solve this problem by using SSH (secure shell). SSH uses a pair of keys to initiate a secure handshake between remote parties. Also, it is more secure than password based authentication.</p>
<p>In this article, I’ll explain the steps to set up multiple accounts of Git based code hosting platforms — GitHub, GitLab, Bitbucket, etc — on a single machine. The approach I am about to describe relies on segregation of work belonging to different accounts into different directories, and editing the <code>~/.gitconfig</code> file so Git can automatically recognize which directory belongs to which account. So, let’s get started!</p>
<h2 id="1-generate-a-new-ssh-key-pair">1. Generate a new SSH Key Pair</h2>
<p>You can generate a new SSH key pair using the below command on macOS, Linux and Windows:</p>
<pre><code class="lang-bash">$ ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"your_email@example.com"</span> -f ~/.ssh/id_rsa_github_personal
</code></pre>
<p>If you’re on Windows, you have to run this command in <em>Git Bash</em>. And remember to provide a meaningful file name while generating the keys. If you don’t use the <code>-f</code> option, the program will prompt you to enter a file name. The above command will generate two keys:</p>
<ul>
<li><p>Public key: <code>~/.ssh/id_rsa_github_personal.pub</code></p>
</li>
<li><p>Private key: <code>~/.ssh/id_rsa_github_personal</code></p>
</li>
</ul>
<p>The public key is analogous to a physical lock which you share with the remote server to encrypt your data, and the private key is stored at a secure location in your file system which will later be used to “unlock” the protected data. The only difference is that SSH uses public key cryptographic algorithms (RSA, DSA) to perform these tasks.</p>
<h2 id="2-add-ssh-public-key-to-your-account"><strong>2. Add SSH Public Key to Your Account</strong></h2>
<p>Share the public key (ending with<code>.pub</code>) with the remote server. Copy the contents of your public key to clipboard by opening the file in a text editor. Or you can copy it to clipboard directly from terminal like this:</p>
<ul>
<li><p><strong>macOS</strong>: <code>pbcopy &lt; ~/.ssh/id_rsa_github_personal.pub</code></p>
</li>
<li><p><strong>Linux</strong>: <code>xclip -sel clip &lt; ~/.ssh/id_rsa_github_personal.pub</code></p>
</li>
<li><p><strong>Windows (Git Bash)</strong>: <code>cat ~/.ssh/id_rsa_github_personal.pub | clip</code></p>
</li>
</ul>
<p>Now paste your SSH public key into your account. On GitHub, the UI looks like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1634965294456/AQwF_L4R9d.png" alt="Add new SSH key on GitHub" /><em>Add new SSH key on GitHub</em></p>
<p>After pasting your public key into the text box above, click ‘Add SSH key’. You can follow these direct links to add a new SSH key into your account:</p>
<ul>
<li><p><strong>GitHub</strong>: <a target="_blank" href="https://github.com/settings/ssh/new">Adding an SSH key to your GitHub account</a></p>
</li>
<li><p><strong>GitLab</strong>: <a target="_blank" href="https://docs.gitlab.com/ee/ssh/README.html#adding-an-ssh-key-to-your-gitlab-account">Adding an SSH key to your GitLab account</a></p>
</li>
<li><p><strong>Bitbucket</strong>: <a target="_blank" href="https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/">Adding an SSH key to your Bitbucket account</a></p>
</li>
</ul>
<p><strong><em>Follow the first two steps for all your personal and professional accounts, and remember to use a meaningful file name for your key (so you can recognize which key belongs to which account/website).</em></strong></p>
<h2 id="3-edit-gitconfig-file">3. Edit gitconfig file</h2>
<p>In this step, you have to edit the <code>.gitconfig</code> file. You will find this file here:</p>
<ul>
<li><p><strong>Linux and macOS</strong>: <code>~/.gitconfig</code></p>
</li>
<li><p><strong>Windows</strong>: <code>C:\Users\&lt;username&gt;\.gitconfig</code></p>
</li>
</ul>
<p>Open the file in a text editor to define multiple one-to-one mapping between directories and the Git config file. Git has a <code>[includeIf]</code> directive which allows you to use a different configuration file if the specified condition evaluates to <code>True</code>. This directive was introduced in Git version 2.13.0, so check your version before going any further: <code>git --version</code>. Upgrade your Git client if required.</p>
<p>This is how my <code>.gitconfig</code> file looks like:</p>
<pre><code><span class="hljs-section">[user]</span>
    <span class="hljs-attr">name</span> = Deepankar Sharma
    <span class="hljs-attr">email</span> = dash.srmk@gmail.com
    <span class="hljs-attr">username</span> = cquark7
<span class="hljs-section">[core]</span>
    <span class="hljs-attr">sshCommand</span> = <span class="hljs-string">"ssh -i ~/.ssh/id_rsa_github_personal"</span>

<span class="hljs-section">[includeIf "gitdir:~/work/github"]</span>
    <span class="hljs-attr">path</span> = ~/.gitconfig_github_work

<span class="hljs-section">[includeIf "gitdir:~/work/gitlab"]</span>
    <span class="hljs-attr">path</span> = ~/.gitconfig_gitlab

<span class="hljs-section">[includeIf "gitdir:~/work/bitbucket"]</span>
    <span class="hljs-attr">path</span> = ~/.gitconfig_bitbucket
</code></pre><p>Define the global (default) configuration in the beginning of the file. Set the path of your SSH private key using <code>sshCommand</code> variable. When this variable is set, <code>git fetch</code> and <code>git push</code> will use the specified command when they need to connect to a remote system. The global config will be used everywhere for performing Git operations, except when you’re present in a directory which matches the <code>[includeIf]</code> directive.</p>
<p>Create a separate Git config file for other accounts, and specify their filesystem path inside the <code>[includeIf]</code> directive. The config present inside this file will be used only when your present working directory matches the glob pattern specified after <code>gitdir:</code>. Read <a target="_blank" href="https://git-scm.com/docs/git-config#_includes">git-config documentation</a> for more details.</p>
<p>This is how an example <code>~/.gitconfig_github_work</code> file should look like:</p>
<pre><code><span class="hljs-section">[user]</span>
    <span class="hljs-attr">name</span> = Your name
    <span class="hljs-attr">email</span> = work_email@example.com
    <span class="hljs-attr">username</span> = UserName
<span class="hljs-section">[core]</span>
    <span class="hljs-attr">sshCommand</span> = <span class="hljs-string">"ssh -i ~/.ssh/id_rsa_github_work"</span>
</code></pre><p>Create a config file for all your accounts.</p>
<p>Now you can verify this setup by cloning a private repository, or by calling <code>git config user.email</code> inside existing repositories.</p>
<p><strong>Note:</strong> <code>[includeIf]</code> conditional config only works inside git repositories. It won’t reflect any change within plain directories and uses global config as fallback.</p>
<h2 id="conclusion">Conclusion</h2>
<p>This is it, guys! It’s nothing too complicated, and you no longer have to modify any config file manually while performing Git operations. Hope you found this useful! Please share your views and suggestions in the comment section below.</p>
]]></content:encoded></item><item><title><![CDATA[Why You Should Attend Tech Conferences?]]></title><description><![CDATA[If you have never attended a technical conference before, you might think that they are a waste of time. Or people who attend tech conferences are just looking for ways to procrastinate their work. In reality, conferences offer many life-changing opp...]]></description><link>https://blog.deepankar.online/why-you-should-attend-tech-conferences</link><guid isPermaLink="true">https://blog.deepankar.online/why-you-should-attend-tech-conferences</guid><category><![CDATA[learning]]></category><category><![CDATA[technology]]></category><category><![CDATA[networking]]></category><category><![CDATA[Career]]></category><category><![CDATA[conference]]></category><dc:creator><![CDATA[Deepankar Sharma]]></dc:creator><pubDate>Wed, 06 Mar 2019 14:50:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1634965306390/UzFCUlXDg.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have never attended a technical conference before, you might think that they are a waste of time. Or people who attend tech conferences are just looking for ways to procrastinate their work. In reality, conferences offer many life-changing opportunities for students, professionals and organizations.</p>
<p>In this blog, I am going to talk about the benefits of attending a tech conference.</p>
<h2 id="learning">Learning</h2>
<p><img src="https://cdn-images-1.medium.com/max/12032/1*ZXixptvL4rzkx3EDuj38xw.jpeg" alt="Photo by [Chris Ried](https://cdn.hashnode.com/res/hashnode/image/upload/v1634965302818/Mc2xxp5Ov.html) on [Unsplash](https://unsplash.com?utm_source=medium&amp;utm_medium=referral)" /><em>Photo by <a target="_blank" href="https://unsplash.com/@cdr6934?utm_source=medium&amp;utm_medium=referral">Chris Ried</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></em></p>
<p>This is the most motivating and important reason to attend a technical conference. You get to learn about state-of-the-art projects, ideas and technologies in the industry.</p>
<p>Conference speakers are experts in their field of work. They condense all their experience and knowledge in a single talk, which helps people in understanding complex concepts/ideas without much effort.</p>
<p>It is also encouraged to ask questions at tech conferences, so it is the best place for students to receive career advice from professionals.</p>
<h2 id="networking">Networking</h2>
<p><img src="https://cdn-images-1.medium.com/max/8000/0*J0RHUX-RNCOzMyCm" alt="Photo by [rawpixel](https://cdn.hashnode.com/res/hashnode/image/upload/v1634965304412/v0aIfpxKy.html) on [Unsplash](https://unsplash.com?utm_source=medium&amp;utm_medium=referral)" /><em>Photo by <a target="_blank" href="https://unsplash.com/@rawpixel?utm_source=medium&amp;utm_medium=referral">rawpixel</a> on <a target="_blank" href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></em></p>
<p>Some people think it’s futile to attend conferences when they can watch everything online, so why should they spend their time and money going to a conference? Well, conferences offer several opportunities for a person who is starting or looking to start their professional career. There will be many people who are interested in the same technology, programming language or platform as you, so this is the perfect place to meet like-minded people, make new friends and get recognized by professionals.</p>
<p>In tech industry, networking is often more important than technical skills, so make sure you don’t fall behind in this department while honing your technical skills ;)</p>
<h2 id="career-advancement">Career Advancement</h2>
<p>A lot of professionals attend these conferences. Sharing your resume and work experience with them may land you a job or internship in your dream company! Introducing yourself to recruiters and industry leaders personally will make a better impression than getting in touch with them through LinkedIn.</p>
<h2 id="promotion-and-recognition">Promotion and Recognition</h2>
<p>If you’re a professional, you can attend the conference as a speaker. Doing this will get you recognized by industry people and help you with jobs. Many companies give preference to candidates who had given a talk in tech conference. If you’re an organization, you can sponsor the event to promote your products and services.</p>
<h2 id="free-free-free">Free, Free, Free!!!</h2>
<p>You get free goodies and lunch at tech conferences! It may sound silly, but it can motivate some people. Who doesn’t like free stuff?</p>
]]></content:encoded></item></channel></rss>