<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ansuman Jaiswal</title>
    <description>The latest articles on DEV Community by Ansuman Jaiswal (@iam-ansuman).</description>
    <link>https://dev.to/iam-ansuman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3984656%2Fd5d4c047-e462-44ef-a44b-bcbb6dd3006f.png</url>
      <title>DEV Community: Ansuman Jaiswal</title>
      <link>https://dev.to/iam-ansuman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iam-ansuman"/>
    <language>en</language>
    <item>
      <title>I cleaned India's Census 2011 data so you never have to</title>
      <dc:creator>Ansuman Jaiswal</dc:creator>
      <pubDate>Tue, 16 Jun 2026 12:36:40 +0000</pubDate>
      <link>https://dev.to/iam-ansuman/i-cleaned-indias-census-2011-data-so-you-never-have-to-4g2m</link>
      <guid>https://dev.to/iam-ansuman/i-cleaned-indias-census-2011-data-so-you-never-have-to-4g2m</guid>
      <description>&lt;p&gt;Every Indian data scientist hits the same wall.&lt;/p&gt;

&lt;p&gt;You need district-level population data. You go to censusindia.gov.in.&lt;br&gt;
You find hundreds of inconsistent Excel files with merged headers,&lt;br&gt;
footnote rows, and zero documentation.&lt;/p&gt;

&lt;p&gt;You spend a full day just loading the data before doing any actual analysis.&lt;/p&gt;

&lt;p&gt;I fixed that. Once. For everyone.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://huggingface.co/datasets/indiaset/census-2011" rel="noopener noreferrer"&gt;indiaset/census-2011&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
India's Census 2011 district data, clean, typed, and ready for pandas.&lt;br&gt;
640 districts · 29 columns · 0 missing values&lt;br&gt;
Validated against official India total · LGD codes attached&lt;/p&gt;
&lt;h2&gt;
  
  
  Load it in 4 lines
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;huggingface_hub&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hf_hub_download&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;

&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hf_hub_download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;repo_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;indiaset/census-2011&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;census_2011_districts_final.parquet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;repo_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dataset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_parquet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# (640, 29)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  What's in it
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state_code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Census 2011 state code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;state_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Official state/UT name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;district_code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Census 2011 district code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;district_name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;District name as per Census&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lgd_code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;LGD permanent district code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;district_name_lgd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;District name as per LGD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total population&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_male&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Male population&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_female&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Female population&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_under6_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Children under 6 years&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_sc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Caste population&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pop_st&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scheduled Tribe population&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;literate_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Literate persons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;literate_male&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Literate males&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;literate_female&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Literate females&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;illiterate_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Illiterate persons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workers_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Total workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workers_male&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Male workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workers_female&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Female workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;non_workers_total&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Non workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;literacy_rate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Literate / Total × 100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sex_ratio&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Females per 1000 males&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;workforce_participation&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Workers / Total × 100&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  The validation
&lt;/h2&gt;

&lt;p&gt;The most important test - do all 640 district populations&lt;br&gt;
sum to India's official total?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pop_total&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;# 1210854977 ✅ — exact match, zero discrepancy
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What the data actually shows
&lt;/h2&gt;

&lt;p&gt;Most literate district  → Pathanamthitta, Kerala    : 88.74%&lt;/p&gt;

&lt;p&gt;Least literate district → Alirajpur, Madhya Pradesh : 28.77%&lt;/p&gt;

&lt;p&gt;Literacy gap across India                           : 60 points&lt;br&gt;
Highest sex ratio → Mahe, Puducherry      : 1176 per 1000 males&lt;/p&gt;

&lt;p&gt;Lowest sex ratio  → Leh, Jammu &amp;amp; Kashmir  :  690 per 1000 males&lt;br&gt;
National population → 1,210,854,977&lt;/p&gt;

&lt;p&gt;Our district sum   → 1,210,854,977&lt;/p&gt;

&lt;p&gt;Difference         → 0 ✅&lt;/p&gt;
&lt;h2&gt;
  
  
  Why LGD codes matter
&lt;/h2&gt;

&lt;p&gt;Every district in this dataset carries an LGD code - the Government of India's permanent identifier for every administrative unit.&lt;/p&gt;

&lt;p&gt;Without LGD codes, joining two Indian datasets is a nightmare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# without LGD - name matching hell
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;district&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Leh(Ladakh)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# misses: "Leh Ladakh", "Leh", "LEH"
&lt;/span&gt;
&lt;span class="c1"&gt;# with LGD - bulletproof
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lgd_code&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# always works, regardless of spelling
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dataset has LGD codes for all 640 districts,&lt;br&gt;
including manual verification of Yanam and Mahe - two tiny Puducherry enclaves missing from the official LGD export.&lt;/p&gt;
&lt;h2&gt;
  
  
  Known limitations
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ This data reflects 2011 boundaries.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telangana does not exist here&lt;/strong&gt; - carved out of Andhra Pradesh in 2014&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New districts post-2011 are not present&lt;/strong&gt; - India had 640 then, 800+ now&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Population figures are from 2011&lt;/strong&gt; - use for structural comparisons,
not current headcounts&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The cleaning pipeline
&lt;/h2&gt;

&lt;p&gt;The full reproducible pipeline is on GitHub.&lt;br&gt;
Clone it, run the notebook, get the exact same parquet file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/indiaset/census-2011-pipeline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Raw file → filter → clean → validate → LGD join → parquet.&lt;br&gt;
Every step documented. Every decision explained.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;This is dataset #1 under &lt;strong&gt;indiaset&lt;/strong&gt; -&lt;br&gt;
India's open data layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dataset&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Census 2011 districts&lt;/td&gt;
&lt;td&gt;✅ Live&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indian Elections 1951–2024&lt;/td&gt;
&lt;td&gt;🔜 Coming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RBI Economic Series&lt;/td&gt;
&lt;td&gt;🔜 Coming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pip install indiaset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;🔜 Coming&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Citation
&lt;/h2&gt;

&lt;p&gt;Jaiswal, Ansuman. (2026). India Census 2011 - District Level&lt;br&gt;
[Dataset]. indiaset. Hugging Face.&lt;br&gt;
&lt;a href="https://huggingface.co/datasets/indiaset/census-2011" rel="noopener noreferrer"&gt;https://huggingface.co/datasets/indiaset/census-2011&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Licensed under &lt;strong&gt;CC-BY-4.0&lt;/strong&gt; - free to use, just credit the source.&lt;/p&gt;




&lt;p&gt;🔗 Dataset → &lt;a href="https://huggingface.co/datasets/indiaset/census-2011" rel="noopener noreferrer"&gt;https://huggingface.co/datasets/indiaset/census-2011&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 Pipeline → &lt;a href="https://github.com/indiaset/census-2011-pipeline" rel="noopener noreferrer"&gt;https://github.com/indiaset/census-2011-pipeline&lt;/a&gt;&lt;br&gt;&lt;br&gt;
🔗 Follow → &lt;a href="https://x.com/indiaset_data" rel="noopener noreferrer"&gt;https://x.com/indiaset_data&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>data</category>
      <category>opendata</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I got tired of rewriting the same Indian utilities. So I built bharatutils.</title>
      <dc:creator>Ansuman Jaiswal</dc:creator>
      <pubDate>Mon, 15 Jun 2026 04:58:36 +0000</pubDate>
      <link>https://dev.to/iam-ansuman/i-got-tired-of-rewriting-the-same-indian-utilities-so-i-built-bharatutils-40bn</link>
      <guid>https://dev.to/iam-ansuman/i-got-tired-of-rewriting-the-same-indian-utilities-so-i-built-bharatutils-40bn</guid>
      <description>&lt;p&gt;Every project. Same story.&lt;/p&gt;

&lt;p&gt;Format salary as ₹15 L instead of 1,500,000. Validate a GSTIN. Parse "Flat 302, Nr. SBI ATM, MG Road, Pune - 411001" into something a database can understand. Check if today is a public holiday.&lt;/p&gt;

&lt;p&gt;Every Indian developer has written these functions. Most of us have written them five times across five projects-slightly differently each time, untested, quietly breaking on the first NaN in a pandas column.&lt;/p&gt;

&lt;p&gt;I got tired of it. So I built &lt;strong&gt;bharatutils&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;bharatutils
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  💰 Indian number formatting
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bharatutils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;format_inr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indian_commas&lt;/span&gt;

&lt;span class="nf"&gt;format_inr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;# '₹15.0 L'
&lt;/span&gt;&lt;span class="nf"&gt;format_inr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# '₹5.0 Cr'
&lt;/span&gt;&lt;span class="nf"&gt;format_inr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;15,00,000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# handles messy strings
&lt;/span&gt;&lt;span class="nf"&gt;format_inr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# 'N/A' - never crashes on pandas NaN
&lt;/span&gt;&lt;span class="nf"&gt;indian_commas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;# '1,50,00,000' - banker's style
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🧾 GST validation with a real checksum
&lt;/h3&gt;

&lt;p&gt;Most validators only check the format pattern. bharatutils implements the &lt;strong&gt;official mod-36 check-digit algorithm&lt;/strong&gt; - meaning a single wrong character in a GSTIN fails validation, exactly as it should.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bharatutils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;validate_gstin_strict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parse_gstin&lt;/span&gt;

&lt;span class="nf"&gt;validate_gstin_strict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27AAAPZ2318J1ZI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# True
&lt;/span&gt;&lt;span class="nf"&gt;validate_gstin_strict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27AAAPZ2319J1ZI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# False - one typo, caught
&lt;/span&gt;
&lt;span class="nf"&gt;parse_gstin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;27AAAPZ2318J1ZI&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# {'state': 'Maharashtra', 'pan': 'AAAPZ2318J', 'entity_number': '1'}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🪪 PAN validation + holder type
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bharatutils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_pan&lt;/span&gt;

&lt;span class="nf"&gt;parse_pan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AAAPZ2318J&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# {'holder_type': 'Individual', 'name_initial': 'Z', 'is_individual': True}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 4th character of every PAN encodes who owns it: &lt;code&gt;P&lt;/code&gt; = person, &lt;code&gt;C&lt;/code&gt; = company, &lt;code&gt;T&lt;/code&gt; = trust, &lt;code&gt;G&lt;/code&gt; = government. Decoded for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  📍 Indian address parsing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bharatutils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_address&lt;/span&gt;

&lt;span class="nf"&gt;parse_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Flat 302, Nr. SBI ATM, MG Road, Pune - 411001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# {'pincode': '411001', 'state': 'Maharashtra', 'city': 'Pune'}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It handles space-broken pincodes (&lt;code&gt;700 016&lt;/code&gt;), ignores phone numbers sitting next to addresses, and &lt;strong&gt;always returns a dict&lt;/strong&gt; - never crashes, safe for pandas pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  🪔 One calendar for all of Bharat
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bharatutils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;next_festival&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days_until&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_festivals&lt;/span&gt;

&lt;span class="nf"&gt;next_festival&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# {'name': 'Muharram', 'date': date(2026, 6, 26)}
&lt;/span&gt;&lt;span class="nf"&gt;days_until&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Diwali&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="c1"&gt;# 150
&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_festivals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# 19 festivals
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Holi and Eid. Christmas and Guru Nanak Jayanti. Buddha Purnima and Diwali. One calendar, every celebration - verified against official Government of India holiday lists, 2023–2027.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned building this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. NaN is not None.&lt;/strong&gt;&lt;br&gt;
My first pandas test printed &lt;code&gt;₹nan&lt;/code&gt;. Turns out &lt;code&gt;float('nan') is not None&lt;/code&gt; - and the only clean way to catch NaN is &lt;code&gt;number != number&lt;/code&gt;, because NaN is the only value in Python not equal to itself. Spent 20 minutes on this, will never forget it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. PyPI versions are immutable.&lt;/strong&gt;&lt;br&gt;
I shipped a broken v0.1.0 on day one - an IndentationError in &lt;code&gt;__init__.py&lt;/code&gt; from a copy-paste mistake. Discovered you cannot re-upload the same version number, ever. Fixed it as v0.1.1. Both versions live in the release history forever - a permanent record of the mistake. Strangely, that felt right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Data needs verification, not memory.&lt;/strong&gt;&lt;br&gt;
The festival calendar started with dates from memory. A verification pass against official government holiday lists caught a one-day error in Eid ul-Fitr before it shipped. Every data library should have this step - checking a primary source before publishing is just engineering diligence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Checksum algorithms are beautiful.&lt;/strong&gt;&lt;br&gt;
GSTIN's mod-36 check digit isn't just validation - it's a mathematical fingerprint baked into every tax identification number in India. I verified my implementation by generating a valid GSTIN from the algorithm itself and confirming a single-character corruption fails. Self-verification under uncertainty feels very satisfying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The hardest part isn't the code.&lt;/strong&gt;&lt;br&gt;
It's packaging, licensing, README, pyproject.toml, PyPI tokens, version bumps, and doing all of it correctly while a friend's advice is echoing: &lt;em&gt;"shipping is 50% of the value."&lt;/em&gt; The code took 5 days. Getting it properly live took 2 more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it exists
&lt;/h2&gt;

&lt;p&gt;The global Python ecosystem was built for other conventions. Millions, not lakhs. Social Security numbers, not GSTINs. Thanksgiving, not Diwali. Nothing wrong with that - they built tools for their problems.&lt;/p&gt;

&lt;p&gt;The strange part is us. Millions of Indian developers, and we've collectively accepted our own conventions as edge cases in someone else's world. These problems are too small for Google to care about. Fine. They're ours to solve.&lt;/p&gt;

&lt;p&gt;bharatutils is MIT licensed - it's not mine, it's ours. Fork it, break it, fix it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is step one.&lt;/strong&gt; The goal: every "how do I do X in Python for India" question should eventually have one answer. Pincode-exact lookups, IFSC validation, regional festival calendars by state - that's the road ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/iam-ansuman/bharatutils" rel="noopener noreferrer"&gt;github.com/iam-ansuman/bharatutils&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/bharatutils" rel="noopener noreferrer"&gt;pypi.org/project/bharatutils&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's the utility &lt;em&gt;you&lt;/em&gt; keep rewriting in every project? That's the v0.2 roadmap.&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>india</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
