When your IT director forwards an annual quote for a software asset management platform that only shows expiration dates, it’s time to question the subscription. A two-year-old side project called LiMa proves that a 100 % local, open-source tool can do the same job with four Python modules—no cloud, no fees.
LiMa started after an admin received a multi-hundred-euro monthly invoice for a tool that essentially offers: a table of dates, a cron job for notifications, and a monthly recap email. The developer’s reaction was pragmatic: “I can write that myself.” Instead of rewriting it today with PyQt6 and SQLAlchemy, the original design already delivers everything a small IT team needs—right on an office PC.
Keep the database minimal: two columns, zero redundancy
A license tracker does not require a complex schema. LiMa stores only two values per entry: software name and expiration date.
self.c.execute('''
CREATE TABLE licences (
nom_logiciel TEXT,
date_expiration TEXT
)
''')Days remaining are calculated on the fly each time the table refreshes. Storing the computed value would introduce the risk of stale data and the need for periodic cleanup. The view layer simply converts each date to an integer:
date_expiration = datetime.strptime(date_expiration_str, "%Y-%m-%d")
jours_restants = (date_expiration - datetime.now()).days
self.tableau_licences.setItem(row, 2, QTableWidgetItem(str(jours_restants)))A single QTimer refreshes the display every minute, which is more than fast enough for a static list of dates.
self.timer = QTimer(self)
self.timer.timeout.connect(self.actualiser_tableau)
self.timer.start(60_000) # one minuteThe developer admits the first version ran the timer every second—“a habit from early experiments”—but one-minute intervals consume far less CPU while keeping the UI responsive.
Native notifications with layered alerts
Cloud tools sell “smart alerting,” but LiMa achieves the same effect with native desktop notifications handled by the plyer library. Six thresholds trigger different messages without additional pop-ups.
if jours_restants <= 30 and jours_restants > 14:
notification.notify(
title="Licence sur le point d'expirer",
message=f"La licence pour {nom_logiciel} expirera dans moins de 1 mois.",
app_name="LiMa",
timeout=3,
)
elif jours_restants <= 14 and jours_restants > 7:
# two weeks leftEach alert appears in the operating system’s native notification center, visible even when the application is minimized, and requires no custom GUI work. Developers who tried to replicate this in Tkinter know the difference between a clean native notification and a floating window hack.
Auto-generated HTML reports with embedded charts
When licenses fall into the red zone, LiMa creates a summary email complete with a pie chart generated by Matplotlib. The PNG is saved temporarily, attached, and attached through Python’s built-in smtplib and email.mime modules.
# Build the chart
plt.pie(
[expirations, non_expirations],
labels=["Licences expirées", "Licences non expirées"],
colors=["red", "green"],
autopct='%1.1f%%'
)
plt.savefig("graphique_pie.png")
# Compose the message
email = MIMEMultipart()
email["Subject"] = subject
email.attach(MIMEText(html_body, "html"))
# Attach the chart
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 third-party APIs, no token renewals—just the organization’s SMTP server or a Gmail account handles delivery. The result is a professional-looking report that arrives in the inbox of the person who actually needs to renew the license.
A finished tool, not a proof of concept
LiMa’s menu bar demonstrates that the project is production-ready: CSV import/export, print preview via QPrinter, A-Z and Z-A sorting, alert toggles, dark/light mode, and an about dialog. All functionality lives in a single lima.py file—no dependencies beyond PyQt5, SQLite, Matplotlib, and Plyer.
When to pay for SaaS—and when to build
LiMa proves that simple automation tasks rarely justify a cloud subscription. The developer’s second-guessing—“I’d use PyQt6 and SQLAlchemy today”—highlights how easy it is to refactor a small tool as needs evolve. For internal workflows that don’t require multi-user access, real-time sync, or mobile clients, a 200-line Python script can replace a $240-per-month SaaS and still deliver polish. The next time a vendor quotes a “must-have” feature set, open a blank file instead of a purchase order.
AI summary
Yıllık yüzlerce euro ödemek yerine kendi lisans takip uygulamanızı PyQt5 ve Python ile sadece 100 satır kodla geliştirin. Veriler yerelde, abonelik yok.