iToverDose/Software· 14 MAY 2026 · 12:05

Build your own license tracker instead of paying SaaS fees

A Python developer saved hundreds monthly by replacing overpriced asset management software with a simple desktop app that tracks expiration dates and sends native alerts.

DEV Community4 min read0 Comments

When the IT director forwarded an annual quote for a commercial Software Asset Management tool, the sticker shock came fast. Hundreds of dollars per month for what amounted to a SQL table, a scheduler, and a few emails. In a moment of frustration, a developer decided to see how much of that functionality could be rebuilt in a quiet Saturday afternoon. The result was LiMa—a lightweight PyQt5 desktop application that runs locally, tracks license expiration dates, and sends native system notifications without ever touching the cloud.

Why pay for what a spreadsheet can do

Commercial license tracking tools often bundle features most teams never use: multi-user dashboards, vendor integrations, or vendor-hosted databases. For small teams, those extras inflate costs without adding value. LiMa proves that a single Python script with SQLite and a few libraries can replace the core workflow: storing license names and expiration dates, calculating days remaining in real time, and triggering alerts before deadlines slip.

The original code started with PyQt5 and raw SQLite calls, but today the stack would likely use PyQt6 for native UI scaling and SQLAlchemy for a more maintainable ORM layer. That said, the value isn’t in the tech choices—it’s in avoiding recurring SaaS bills for functionality that can live entirely on one workstation.

Live data without stale caches

The heart of the app is a minimal SQLite table with just two columns: software name and expiration date.

CREATE TABLE licences (nom_logiciel TEXT, date_expiration TEXT);

Every time the window refreshes, the days remaining are computed on the fly from the expiration date, eliminating stale data risks. A background timer refreshes the view every 60 seconds—fast enough for license management, light enough to run silently in the background.

self.timer = QTimer(self)
self.timer.timeout.connect(self.actualiser_tableau)
self.timer.start(60_000)  # Refresh once per minute

As the table updates, rows fade to red when expiration nears, giving immediate visual feedback without manual reloads.

Native alerts across every desktop

Instead of building custom popups or relying on a third-party service, LiMa taps into native notification systems through the plyer library. The app segments alerts into six tiers based on urgency:

  • More than 14 days remaining: no alert
  • 14 to 30 days: “License about to expire”
  • 7 to 14 days: “Less than two weeks”
  • 3 to 7 days: “Less than one week”
  • 1 to 3 days: “Less than three days”
  • Expiring today: “Expires today”
  • Overdue: “Expired X days ago”

Each tier triggers a native OS notification that appears in Windows Action Center, macOS Notification Center, or Linux libnotify, depending on the user’s system. No extra windows, no browser tabs—just clean, OS-integrated alerts that work even when the app is minimized.

Automated email reports with inline charts

When licenses cross the red line, LiMa generates a pie chart showing expired versus active licenses and attaches it to an HTML-formatted email sent via the internal SMTP server or Gmail. The stack relies only on standard libraries: smtplib for delivery and MIME for message formatting. Matplotlib renders the visualization, which is saved as a PNG and embedded as an attachment.

def generer_graphique_pie(self):
    expirations = sum(1 for r in rows if int(r[2]) < 0)
    actives = sum(1 for r in rows if int(r[2]) >= 0)
    plt.pie([expirations, actives], labels=["Expired", "Active"], colors=["red", "green"])
    plt.savefig("graphique_pie.png")

email = MIMEMultipart()
email.attach(MIMEText(html_body, "html"))
with open("graphique_pie.png", "rb") as f:
    part = MIMEBase("application", "octet-stream")
    part.set_payload(f.read())
    encoders.encode_base64(part)
    part.add_header("Content-Disposition", "attachment; filename=graphique_pie.png")
    email.attach(part)

No tokens to rotate, no third-party APIs to call—just a clean message that lands in the recipient’s inbox with the chart embedded, exactly like premium commercial tools.

A finished tool, not a prototype

Before diving deeper, consider the menu bar that turns this script into a polished internal utility:

  • CSV import and export for bulk updates
  • One-click printing via QPrinter
  • A-Z and Z-A sorting for quick lookups
  • Toggle alerts on or off per license
  • Built-in dark and light modes
  • SMTP configuration dialog
  • About box with version and credits

All these features fit inside a single 300-line Python file named lima.py—no sprawling microservice, no vendor lock-in, and no monthly bill.

Dark mode in five lines of CSS

Switching between light and dark themes is achieved with a single stylesheet call in PyQt5, proving that dark mode doesn’t need external libraries or nightly builds.

def toggle_dark_mode(self):
    self.setStyleSheet("""
        QMainWindow { background: #222222; color: #FFFFFF; }
        QTableWidget { background-color: #333333; color: #FFFFFF; }
        QPushButton { background-color: #444444; color: #FFFFFF; }
    """)

The UI retains readability while reducing eye strain during long inventory sessions.

The bigger lesson: don’t SaaS what you can code overnight

LiMa started as a weekend project born out of frustration with bloated vendor quotes. It evolved into a practical tool that handles license tracking better than many paid platforms—all while staying offline, secure, and free to modify. The message isn’t anti-SaaS; it’s pro-autonomy. If your need is a simple data table plus notifications plus email, ask whether the cloud is adding value or merely padding the budget. Often, the answer is in your own editor.

For teams that need something ready to run, the code is open source and can be forked, adapted, or extended without licensing headaches. The next time you receive a renewal quote, open your IDE first.

AI summary

Yıllık binlerce dolar ödenen SaaS abonelikleri yerine kendi Python uygulamanızı geliştirin. LiMa projesiyle nasıl 100 dolarlık abonelikleri iptal ettiğimizi keşfedin.

Comments

00
LEAVE A COMMENT
ID #N5RKRL

0 / 1200 CHARACTERS

Human check

8 + 4 = ?

Will appear after editor review

Moderation · Spam protection active

No approved comments yet. Be first.