In this week's adventure of "Will I be replaced by AI":
Copilot generated a really nice module using sqlalchemy to automate the db migration we use in my ETL shop. It took a few days going back and forth with copilot to get it to produce the DDL we the way we like it. I stopped myself from editing this module and I'm letting copilot manage it.
I still did the integration of it's use into our code base.
I'm still saying NO, AI cannot replace me YET.
#python #sql #copilot #llm #ai
More like a long overdue bugfix, than a new release, but here we go: https://pypi.org/project/bonsai/1.5.5/ #python #bonsai #ldap
Celonis is hiring Manager, Cloud Security
π§ #python #aws #azure #cicd #gcp #kubernetes #terraform #securityengineer
π Raleigh, North Carolina
β° Full-time
π’ Celonis
Job details https://jobsfordevelopers.com/jobs/manager-cloud-security-at-celonis-com-dec-9-2025-e549a4?utm_source=mastodon.world&utm_medium=social&utm_campaign=posting
#jobalert #jobsearch #hiring
I Built My Own iMessage Wrapped (And So Can You)
My daughter was joking that someone should build a Spotify Wrapped, but for iMessage β your year in emoji and reactions. My wife said my brother-in-law should build it since he works at Apple. (Every Apple problem is his fault in our house.)
From the other room, my daughter yelled: βI bet Dad could write this!β
Challenge accepted.
The Result
Thirty minutes later, I had a working script. Hereβs my 2025:
π iMessage Wrapped 2025
π± Messages
Total: 35,768
Sent: 12,191
Received: 23,577
π¬ Reactions
Given: 1,974
Received: 5,014
π Your Reaction Style
π 982
β€οΈ 398
π 275
βΌοΈ 126
β 19
π 16
π Messages by Month
Jan βββββββββββββββ 3,052
Feb βββββββββββββ 2,621
Mar βββββββββββββββββ 3,422
Apr ββββββββββββββββββ 3,696
May ββββββββββββββββββ 3,640
Jun ββββββββββββββββββββ 3,904
Jul βββββββββββββ 2,561
Aug ββββββββββββ 2,448
Sep ββββββββββββββ 2,790
Oct βββββββββββββββββ 3,466
Nov βββββββββββ 2,206
Dec ββββββββββ 1,962Some things I learned about myself:
How It Works
Your iMessage history lives in a SQLite database at ~/Library/Messages/chat.db. Itβs just sitting there, queryable.
The tricky bits:
associated_message_type set to a magic number (2000 = loved, 2001 = liked, etc.).associated_message_emoji.Once you know the schema, itβs just SQL.
The Script
Hereβs the full thing β about 100 lines of Python, no dependencies beyond the standard library:
#!/usr/bin/env python3
"""
iMessage Wrapped β Your year in emoji and reactions
Usage: python3 imessage-wrapped.py [year]
Requires: Full Disk Access for Terminal
"""
import sqlite3
import os
import sys
from datetime import datetime
from pathlib import Path
YEAR = int(sys.argv[1]) if len(sys.argv) > 1 else 2025
DB_PATH = Path.home() / "Library/Messages/chat.db"
APPLE_EPOCH_OFFSET = 978307200
TAPBACKS = {
2000: "β€οΈ", # Loved
2001: "π", # Liked
2002: "π", # Disliked
2003: "π", # Laughed
2004: "βΌοΈ", # Emphasized
2005: "β", # Questioned
}
def get_db():
if not DB_PATH.exists():
print(f"β Database not found at {DB_PATH}")
sys.exit(1)
return sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True)
def date_filter(year):
return f"""
datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch') >= '{year}-01-01'
AND datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch') < '{year + 1}-01-01'
"""
def main():
print(f"\nπ iMessage Wrapped {YEAR}\n")
db = get_db()
cur = db.cursor()
# Message counts
cur.execute(f"""
SELECT COUNT(*),
SUM(CASE WHEN is_from_me = 1 THEN 1 ELSE 0 END),
SUM(CASE WHEN is_from_me = 0 THEN 1 ELSE 0 END)
FROM message WHERE {date_filter(YEAR)} AND associated_message_type = 0
""")
total, sent, received = cur.fetchone()
print(f"π± Messages: {total:,} ({sent:,} sent, {received:,} received)")
# Reaction counts
cur.execute(f"""
SELECT SUM(CASE WHEN is_from_me = 1 THEN 1 ELSE 0 END),
SUM(CASE WHEN is_from_me = 0 THEN 1 ELSE 0 END)
FROM message WHERE {date_filter(YEAR)} AND associated_message_type >= 2000
""")
given, got = cur.fetchone()
print(f"π¬ Reactions: {given + got:,} ({given:,} given, {got:,} received)")
# Your tapback style
print(f"\nπ Your Reaction Style")
cur.execute(f"""
SELECT associated_message_type, COUNT(*) FROM message
WHERE {date_filter(YEAR)} AND associated_message_type BETWEEN 2000 AND 2005 AND is_from_me = 1
GROUP BY associated_message_type ORDER BY COUNT(*) DESC
""")
for type_id, cnt in cur.fetchall():
print(f" {TAPBACKS.get(type_id, '?')} {cnt:,}")
# Custom emoji
cur.execute(f"""
SELECT associated_message_emoji, COUNT(*) FROM message
WHERE {date_filter(YEAR)} AND associated_message_emoji IS NOT NULL AND is_from_me = 1
GROUP BY associated_message_emoji ORDER BY COUNT(*) DESC LIMIT 5
""")
customs = cur.fetchall()
if customs:
print(f"\nπ― Custom Reactions: {', '.join(f'{e} ({c})' for e, c in customs)}")
# Monthly volume
print(f"\nπ By Month")
cur.execute(f"""
SELECT strftime('%m', datetime(date/1000000000 + {APPLE_EPOCH_OFFSET}, 'unixepoch')), COUNT(*)
FROM message WHERE {date_filter(YEAR)} AND associated_message_type = 0
GROUP BY 1 ORDER BY 1
""")
months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
data = {row[0]: row[1] for row in cur.fetchall()}
max_cnt = max(data.values()) if data else 1
for i, name in enumerate(months, 1):
cnt = data.get(f"{i:02d}", 0)
bar = "β" * int(20 * cnt / max_cnt)
print(f" {name} {bar} {cnt:,}")
db.close()
if __name__ == "__main__":
main()Running It
imessage-wrapped.pypython3 imessage-wrapped.py # defaults to 2025
python3 imessage-wrapped.py 2024 # or any yearThatβs it. Your data never leaves your machine.
What Iβd Add Next
If I turn this into a proper app:
But honestly? The script is fun enough. Sometimes a quick hack that makes your daughter laugh is the whole point.
The script and a slightly more polished version are on GitHub if you want to grab it.
#Apple #iMessage #Messages #NerdyStuff #PythonLaid off :/
I know:
- Unity C#
- Rust
- Python
I can learn:
- Anything
I've 8 years of experience as an MIT software engineer specializing in research simulation platform projects. I would prefer: not creating the next big AI thing, not making weapons, never having to think about blockchain anything.
Anyone got anything?
#rust #softwaredevelopment #unity3d #python
Good News Everyone!
The #PyOhio 2026 Call for Proposals will be opening soon! We appreciate submissions on a wide variety of topics and perspectives having to do with #Python or Python-related subjects. Keep an eye on our social media channels or subscribe to our newsletter at https://newsletter.pyohio.org/ to stay up to date!

Python Tip #49 (of 365):
Tuple unpacking supports a list-like syntax.
Tuple unpacking optionally supports parens:
>>> point = (1, 2)
>>> x, y = point
>>> (x, y) = point
But did you know that it also works with a list-like syntax?
>>> [x, y] = point
Neat... but why???
Well, I usually prefer the list-like tuple unpacking syntax:
1. when unpacking a single-item iterable
2. to convey the fact that I'm unpacking list-like data
π§΅ (1/3)
J'étais complètement passé à côté, mais ils ont rajouté de la couleur dans l'aide générée par argparse dans #Python 3.14 !
CΓ©bΓ΄ ! ![]()

Fit an image to a target rectangle and center it in Python
(This is the first in a series of posts leading to a flash card application that you can use to learn about Japanese hiragana characters.)
https://rodstephensbooks.com/fit_image.html

ππ» Python Developer Wanted: Software Engineer (Python / Django) at Mirvie (South San Francisco, CA, USA) #pythonjob #sponsored #python
Have you been looking for a place to share your knowledge with other interested #python developers? π
Every 1st Tuesday of the month, #PyTexas has a meetup on Discord & we would love to hear what you would like to share! π
Learn more here: https://www.pytexas.org/meetup

Begging people to not return nested dicts more than two levels deep.
Named tuples or data classes or structs (maybe not) are so easy to write and comprehend!
Tabulated / numeric data? Send me an array or a series or a data frame or an xarray or β¦
More complicated? Reevaluate please.
/rant
#python