I Replaced 500 Lines of Code With These Python Libraries

Python Libraries That Save Time - My Code Diary

I Replaced 500 Lines of Code With These Python Libraries

My Code Diary


Three years ago, I spent an entire weekend writing a script to parse dates from messy CSV files. Edge cases everywhere. Timezones. Weird formats. By Sunday night, I had 200 lines of brittle, barely-working code and a mild headache.

On Monday, a colleague leaned over and said: “You know there’s a library for that, right?”

That was the moment I realized something uncomfortable. I had been doing things the hard way. Not because I was new to Python. I had been writing Python for years at that point. I did it because I never stopped to ask if someone had already solved this problem better than I could.

That question changed how I write code.

Now, before I build anything from scratch, I ask: “Is there a library that does this in ten lines instead of two hundred?” More often than not, the answer is yes. And the libraries that keep showing up on my radar are the ones in this article.

These are not the obvious ones. You already know about requests and pandas. I’m talking about the libraries that made me genuinely surprised someone had built something so thoughtful.


1. Arrow, Stop Fighting With Python Dates

Python’s built-in datetime module is technically capable. It is also genuinely painful to use. Timezone-aware objects, naive objects, strftime format strings you have to memorize, timezone conversions that require importing a separate library, it adds up.

arrow flattens all of that into a clean, readable interface.

import arrow

now = arrow.now()
print(now.to("Asia/Karachi"))           # Convert timezone instantly
print(now.shift(days=-7).humanize())    # "a week ago"
print(arrow.get("2024-03-15", "YYYY-MM-DD"))  # Parse any format cleanly

What used to take fifteen lines of datetime, pytz, and format string gymnastics now takes one. I replaced an entire date-parsing utility module 180 lines with eight lines using arrow. Not an exaggeration.

Pro tip: Use arrow.get() whenever you’re dealing with unknown date formats. It handles more edge cases out of the box than you’d expect.


2. Rich, Because Print Statements Are Embarrassing

At some point in every developer’s life, they write a CLI tool or a long-running script and think, “This output is unreadable.” Then they add more print() statements. Then it gets worse.

rich is the answer to that. It makes your terminal output look like it belongs in a product, not a school project.

from rich import print
from rich.table import Table
from rich.progress import track

table = Table(title="Processing Results")
table.add_column("File", style="cyan")
table.add_column("Status", style="green")
table.add_row("data.csv", "Done")
table.add_row("report.pdf", "Failed")

print(table)

for item in track(my_list, description="Processing..."):
    do_something(item)

Colored output, progress bars, formatted tables, syntax-highlighted code blocks, all built in. I used to write maybe 90 lines of formatting logic for internal tools. rich replaced that with a single import and a few method calls.

The progress bar feature alone has saved me from staring at a blinking cursor more times than I can count.


3. Pydantic, Data Validation That Actually Works

Here is a scenario I lived through for longer than I should have: building internal APIs and data pipelines where someone keeps passing in the wrong types. A string where you expected an integer. A missing field that brings the whole thing down. Null values that sneak through and crash something downstream.

My solution for a long time was manual validation. Messy if blocks. Custom exception classes. Repetitive boilerplate.

pydantic made all of that disappear.

from pydantic import BaseModel, ValidationError
from typing import Optional

class UserRecord(BaseModel):
    name: str
    age: int
    email: str
    score: Optional[float] = 0.0

try:
    user = UserRecord(name="Ali", age="twenty", email="ali@example.com")
except ValidationError as e:
    print(e)  # Clear, structured error message explaining what went wrong

It validates automatically based on the type hints you already write. Wrong type? It tells you exactly where. Missing required field? Same thing. It integrates with FastAPI out of the box and works beautifully for any data ingestion task where you’re not in control of the input.

I replaced a 130-line validation module with one pydantic model. The new version also caught three bugs the old version was silently letting through.


4. Tenacity, Retry Logic Without the Boilerplate

Networks fail. APIs rate-limit you. External services go down for thirty seconds and come back up. If you’ve built anything that talks to the outside world, you’ve written retry logic.

Most of the time, that retry logic looks something like a while loop with a counter, a time.sleep(), and a vague sense that this could be done better.

tenacity is how it’s done better.

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(5), wait=wait_exponential(multiplier=1, min=2, max=10))
def call_external_api(url):
    response = requests.get(url)
    response.raise_for_status()
    return response.json()

That decorator handles exponential backoff, maximum attempts, and clean failure after all retries are exhausted. What used to be forty or fifty lines of custom retry logic is now a four-line decorator.

I started using this on every function that touches an external service. It has quietly saved several production pipelines from blowing up over transient network errors.


5. Loguru, Logging That You’ll Actually Set Up

Be honest: how many of your projects have no logging because setting up Python’s built-in logging module is annoying enough that you just skipped it and used print() instead?

That was me. The built-in logging module requires boilerplate configuration, handler setup, formatter strings, and enough ceremony that it always felt like too much work for a small script. So I’d skip it. Then I’d need to debug something and have nothing to work with.

loguru makes logging something you actually want to do.

from loguru import logger

logger.add("app.log", rotation="10 MB", retention="7 days", level="WARNING")

logger.info("Script started")
logger.warning("Rate limit approaching")
logger.error("API call failed for user ", user_id=123)

One import, one line to configure file output, and you’re done. It auto-rotates logs, formats everything beautifully, and shows you the exact file and line number where something went wrong. I went from zero logging in most scripts to having it everywhere, simply because the barrier to entry dropped to almost nothing.


6. Humanize, Numbers That People Can Actually Read

This one is small. It is also the kind of thing that makes a finished product feel genuinely polished instead of developer-built.

import humanize

print(humanize.naturalsize(1_048_576))     # "1.0 MB"
print(humanize.intcomma(1000000))          # "1,000,000"
print(humanize.naturaltime(seconds_ago))   # "3 minutes ago"
print(humanize.naturalday(some_date))      # "yesterday"

Every time I’ve added a dashboard, a report, or a CLI tool, I’ve had to write formatting helpers. humanize is all of those helpers, already written and tested. It converts raw numbers into strings that actual humans find readable.


The Pattern Behind All of This

Looking back at these six libraries, there’s a common thread. Every one of them solves a problem that developers kept solving over and over in slightly different ways. Someone got tired of that, built the definitive solution, and released it for free.

The lesson I had to learn the hard way is that Python’s real superpower is not the language itself. It is the ecosystem around it. The thousands of people who got frustrated by the same things you’re frustrated by and then did something about it.

Before you write a new utility function, spend five minutes searching for a library that already does it. Not always, but more often than you’d expect, the answer is already out there and it’s better than what you would have written.

The 500 lines I replaced were not wasted. Writing them taught me what the problems actually were. But I’m not going to write them again.


What libraries have quietly saved you the most time? Drop them in the comments, I’m always looking for the next one.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top