I want to write a program to extract a list of clickable links from a PDF page.
#pypdf can list the link positions/sizes and target URLs. But in a PDF document, links are annotations, which are separate data from the document text.
To get the display text of a clickable link in a PDF, is the easiest way to convert the full page to PNG, crop it to the link's bounding box, and run that through OCR? Or am I missing something more reasonable?
I am working on a binary tree class for one of my algorithms class. I have gone a little off the rails and implemented generators for the different tree traversal techniques.
One thing I don't like though is all the redundancy. All of these generators are essentially the same but just the order in which nodes and trees are evaluated is changed. Is there anyway to simplify the code or reduce the redundancy?
🐍🏃➡️ We kicked off the first day of the #Python#CoreSprint at #Arm in #Cambridge with lots of talks and lots of discussion about talks!
Ken Jin - Building a JIT Community AND Demo [effect] of new C API @antocuni - Tracing JITs on real code @brettcannon - WASI update AND precompiled binaries from python.org Hood Chatham - Upstreaming Pyodide FFI @freakboy3742 - Managing cross-platform wheel builds Steering Council - PEP 793 and abi3/abi3t/abi4 Matthew Parkinson - Designing Deep Immutability
ALT text detailsBrett giving a talk to the core team.
ALT text detailsList of how far people travelled for the sprint.
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
🐍🏃➡️ We kicked off the first day of the #Python#CoreSprint at #Arm in #Cambridge with lots of talks and lots of discussion about talks!
Ken Jin - Building a JIT Community AND Demo [effect] of new C API @antocuni - Tracing JITs on real code @brettcannon - WASI update AND precompiled binaries from python.org Hood Chatham - Upstreaming Pyodide FFI @freakboy3742 - Managing cross-platform wheel builds Steering Council - PEP 793 and abi3/abi3t/abi4 Matthew Parkinson - Designing Deep Immutability
ALT text detailsBrett giving a talk to the core team.
ALT text detailsList of how far people travelled for the sprint.
As inscrições para os tutoriais da Python Brasil 2025 abrem dia 22 de setembro, às 8h da manhã 🐍 🔥 E serão realizadas pelo Eventbrite (mesmo link dos ingressos de palestras)
Tutoriais são atividades gratuitas, e você pode se inscrever em mais de um tutorial (desde que os horários não sejam conflitantes).
Confira a programação 📅 e planeje com calma em quais dessas atividades incríveis você quer participar ♥️
ALT text detailsFundo de foto oficial da Python Brasil de 2018, em Natal, fazendo o sinal de libras de Python.
Tutoriais - escrito em letras vermelhas
inscrições gratuitas dia 22 de setembro - escrito em letras pretas
Logo da Python Brasil 2025
Although I've used python's matplotlib for years, it has always been a case of hacking together code snippets from the web.
Why? Because I don't think there is a unified, coherent, consistent design philosophy. If there is, I have never found it in all these years.
I keep reading that the Grammar of Graphics is the solution - an actually designed framework which has been implemented first and foremost in R, but python implementations exist too.
What do people think?
I'd welcome your thoughts before I invest time in learning some grammar of graphics and maybe trying a library like plotnine.
Are my expectations of Grammar of Graphics too high?
Although I've used python's matplotlib for years, it has always been a case of hacking together code snippets from the web.
Why? Because I don't think there is a unified, coherent, consistent design philosophy. If there is, I have never found it in all these years.
I keep reading that the Grammar of Graphics is the solution - an actually designed framework which has been implemented first and foremost in R, but python implementations exist too.
What do people think?
I'd welcome your thoughts before I invest time in learning some grammar of graphics and maybe trying a library like plotnine.
Are my expectations of Grammar of Graphics too high?
As inscrições para os tutoriais da Python Brasil 2025 abrem dia 22 de setembro, às 8h da manhã 🐍 🔥 E serão realizadas pelo Eventbrite (mesmo link dos ingressos de palestras)
Tutoriais são atividades gratuitas, e você pode se inscrever em mais de um tutorial (desde que os horários não sejam conflitantes).
Confira a programação 📅 e planeje com calma em quais dessas atividades incríveis você quer participar ♥️
ALT text detailsFundo de foto oficial da Python Brasil de 2018, em Natal, fazendo o sinal de libras de Python.
Tutoriais - escrito em letras vermelhas
inscrições gratuitas dia 22 de setembro - escrito em letras pretas
Logo da Python Brasil 2025
ALT text detailsA imagem apresenta uma mulher chamada Bruna Ferreira(eu), que está sendo apresentada como a keynote speaker do evento PySul 2025 em Porto Alegre. Ela está segurando um cartão com a inscrição "Bugs" e está vestida com uma jaqueta preta. Ao fundo, há um banner com o logotipo do "Centro Universitário UNICESUSC" e a palavra "Pos" repetida, indicando um evento acadêmico. A imagem também inclui um desenho de um cavalo e o texto "PySul 2025 | Porto Alegre" na parte inferior, sugerindo um evento relacionado à comunidade de programação em Python.
Fornecido por @altbot, gerado localmente e de forma privada usando Ovis2-8B
🌱 Energia utilizada: 0.200 Wh
ALT text detailsA imagem apresenta uma mulher chamada Bruna Ferreira(eu), que está sendo apresentada como a keynote speaker do evento PySul 2025 em Porto Alegre. Ela está segurando um cartão com a inscrição "Bugs" e está vestida com uma jaqueta preta. Ao fundo, há um banner com o logotipo do "Centro Universitário UNICESUSC" e a palavra "Pos" repetida, indicando um evento acadêmico. A imagem também inclui um desenho de um cavalo e o texto "PySul 2025 | Porto Alegre" na parte inferior, sugerindo um evento relacionado à comunidade de programação em Python.
Fornecido por @altbot, gerado localmente e de forma privada usando Ovis2-8B
🌱 Energia utilizada: 0.200 Wh
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
@glyph Same laptop, same version of cpython (3.13), same requirements.txt file with pip:
real 2m5.404s user 0m42.650s sys 0m5.081s
So 125 seconds versus 14 seconds. Pip and uv calculate dependencies differently, though uv tries to be compatible. Pip did 253 packages and uv did 250. But pip works sequentially, one package at a time. One download at a time. Like many #rust programs, uv is "embarrassingly parallel."
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
So I just rebuilt my personal #pythonvenv in my home directory on my #linux daily driver laptop. I did pip freeze > requirements.txt to capture all the packages I had installed. Then I took away all the ==a,b.c versioning so I'd install the latest compatible version.
Then I ran uv pip install -r requirements.txt. This blew me way:
$ time uv pip install -r requirements.txt Resolved 250 packages in 2.38s Built python-ldap==3.4.4 Built py-cui==0.1.6 Built docopt==0.6.2 Built email-normalize==2.0.0 Built ecos==2.0.14 ... bunch of lines... real 0m14.028s user 0m11.605s sys 0m4.131s
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
This tutorial will guide you through building a simple ActivityPub bot using Python. The bot will listen for mentions and, when it receives a message in a specific format, it will schedule and send a reminder back to the user after a specified delay.
For example, if a user mentions the bot with a message like "@reminder@your.host.com 10m check the oven", the bot will reply 10 minutes later with a message like "🔔 Reminder for @user: check the oven".
Prerequisites
To follow this tutorial, you will need Python 3.10+ and the following libraries:
apkit[server]: A powerful toolkit for building ActivityPub applications in Python. We use the server extra, which includes FastAPI-based components.
uvicorn: An ASGI server to run our FastAPI application.
cryptography: Used for generating and managing the cryptographic keys required for ActivityPub.
uv: An optional but recommended fast package manager.
You can install these dependencies using uv or pip.
# Initialize a new project with uvuv init# Install dependenciesuv add "apkit[server]" uvicorn cryptography
Project Structure
The project structure is minimal, consisting of a single Python file for our bot's logic.
.├── main.py└── private_key.pem
main.py: Contains all the code for the bot.
private_key.pem: The private key for the bot's Actor. This will be generated automatically on the first run.
Code Walkthrough
Our application logic can be broken down into the following steps:
Imports and Configuration: Set up necessary imports and basic configuration variables.
Key Generation: Prepare the cryptographic keys needed for signing activities.
Actor Definition: Define the bot's identity on the Fediverse.
Server Initialization: Set up the apkit ActivityPub server.
Data Storage: Implement a simple in-memory store for created activities.
Reminder Logic: Code the core logic for parsing reminders and sending notifications.
Endpoint Definitions: Create the necessary web endpoints (/actor, /inbox, etc.).
Activity Handlers: Process incoming activities from other servers.
Application Startup: Run the server.
Let's dive into each section of the main.py file.
1. Imports and Configuration
First, we import the necessary modules and define the basic configuration for our bot.
Make sure to replace your.host.com with the actual domain where your bot will be hosted. These values determine your bot's unique identifier (e.g., @reminder@your.host.com).
2. Key Generation and Persistence
ActivityPub uses HTTP Signatures to secure communication between servers. This requires each actor to have a public/private key pair. The following code generates a private key and saves it to a file if one doesn't already exist.
# main.py (continued)# --- Key Persistence ---KEY_FILE = "private_key.pem"# Load the private key if it exists, otherwise generate a new oneif os.path.exists(KEY_FILE): logger.info(f"Loading existing private key from {KEY_FILE}.") with open(KEY_FILE, "rb") as f: private_key = crypto_serialization.load_pem_private_key(f.read(), password=None)else: logger.info(f"No key file found. Generating new private key and saving to {KEY_FILE}.") private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) with open(KEY_FILE, "wb") as f: f.write(private_key.private_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PrivateFormat.PKCS8, encryption_algorithm=crypto_serialization.NoEncryption() ))# Generate the public key from the private keypublic_key_pem = private_key.public_key().public_bytes( encoding=crypto_serialization.Encoding.PEM, format=crypto_serialization.PublicFormat.SubjectPublicKeyInfo).decode('utf-8')
3. Actor Definition
Next, we define the bot's Actor. The Actor is the bot's identity in the ActivityPub network. We use the Application type, as this entity is automated.
# main.py (continued)# --- Actor Definition ---actor = Application( id=f"https://{HOST}/actor", name="Reminder Bot", preferredUsername=USER_ID, summary="A bot that sends you reminders. Mention me like: @reminder 5m Check the oven", inbox=f"https://{HOST}/inbox", # Endpoint for receiving activities outbox=f"https://{HOST}/outbox", # Endpoint for sending activities publicKey=CryptographicKey( id=f"https://{HOST}/actor#main-key", owner=f"https://{HOST}/actor", publicKeyPem=public_key_pem ))
4. Server Initialization
We initialize the ActivityPubServer from apkit, providing it with a function to retrieve our Actor's keys for signing outgoing activities.
# main.py (continued)# --- Key Retrieval Function ---async def get_keys_for_actor(identifier: str) -> list[ActorKey]: """Returns the key for a given Actor ID.""" if identifier == actor.id: return [ActorKey(key_id=actor.publicKey.id, private_key=private_key)] return []# --- Server Initialization ---app = ActivityPubServer(apkit_config=AppConfig( actor_keys=get_keys_for_actor # Register the key retrieval function))
5. In-Memory Storage and Cache
To serve created activities, we need to store them somewhere. For simplicity, this example uses a basic in-memory dictionary as a store and a cache. In a production application, you would replace this with a persistent database (like SQLite or PostgreSQL) and a proper cache (like Redis).
# main.py (continued)# --- In-memory Store and Cache ---ACTIVITY_STORE = {} # A simple dict to store created activitiesCACHE = {} # A cache for recently accessed activitiesCACHE_TTL = timedelta(minutes=5) # Cache expiration time (5 minutes)
6. Reminder Parsing and Sending Logic
This is the core logic of our bot. The parse_reminder function uses a regular expression to extract the delay and message from a mention, and send_reminder schedules the notification.
# main.py (continued)# --- Reminder Parsing Logic ---def parse_reminder(text: str) -> tuple[timedelta | None, str | None, str | None]: """Parses reminder text like '5m do something'.""" # ... (implementation omitted for brevity)# --- Reminder Sending Function ---async def send_reminder(ctx: Context, delay: timedelta, message: str, target_actor: APKitActor, original_note: Note): """Waits for a specified delay and then sends a reminder.""" logger.info(f"Scheduling reminder for {target_actor.id} in {delay}: '{message}'") await asyncio.sleep(delay.total_seconds()) # Asynchronously wait logger.info(f"Sending reminder to {target_actor.id}") # Create the reminder Note reminder_note = Note(...) # Wrap it in a Create activity reminder_create = Create(...) # Store the created activities ACTIVITY_STORE[reminder_note.id] = reminder_note ACTIVITY_STORE[reminder_create.id] = reminder_create # Send the activity to the target actor's inbox keys = await get_keys_for_actor(f"https://{HOST}/actor") await ctx.send(keys, target_actor, reminder_create) logger.info(f"Reminder sent to {target_actor.id}")
7. Endpoint Definitions
We define the required ActivityPub endpoints. Since apkit is built on FastAPI, we can use standard FastAPI decorators. The main endpoints are:
Webfinger: Allows users on other servers to discover the bot using an address like @user@host. This is a crucial first step for federation.
/actor: Serves the bot's Actor object, which contains its profile information and public key.
/inbox: The endpoint where the bot receives activities from other servers. apkit handles this route automatically, directing activities to the handlers we'll define in the next step.
/outbox: A collection of the activities created by the bot. but this returns placeholder collection.
/notes/{note_id} and /creates/{create_id}: Endpoints to serve specific objects created by the bot, allowing other servers to fetch them by their unique ID.
Here is the code for defining these endpoints:
# main.py (continued)# The inbox endpoint is handled by apkit automatically.app.inbox("/inbox")@app.webfinger()async def webfinger_endpoint(request: Request, acct: WebfingerResource) -> Response: """Handles Webfinger requests to make the bot discoverable.""" if not acct.url: # Handle resource queries like acct:user@host if acct.username == USER_ID and acct.host == HOST: link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") else: # Handle resource queries using a URL if acct.url == f"https://{HOST}/actor": link = WebfingerLink(rel="self", type="application/activity+json", href=actor.id) wf_result = WebfingerResult(subject=acct, links=[link]) return JSONResponse(wf_result.to_json(), media_type="application/jrd+json") return JSONResponse({"message": "Not Found"}, status_code=404)@app.get("/actor")async def get_actor_endpoint(): """Serves the bot's Actor object.""" return ActivityResponse(actor)@app.get("/outbox")async def get_outbox_endpoint(): """Serves a collection of the bot's sent activities.""" items = sorted(ACTIVITY_STORE.values(), key=lambda x: x.id, reverse=True) outbox_collection = OrderedCollection( id=actor.outbox, totalItems=len(items), orderedItems=items ) return ActivityResponse(outbox_collection)@app.get("/notes/{note_id}")async def get_note_endpoint(note_id: uuid.UUID): """Serves a specific Note object, with caching.""" note_uri = f"https://{HOST}/notes/{note_id}" # Check cache first if note_uri in CACHE and (datetime.now() - CACHE[note_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[note_uri]["activity"]) # If not in cache, get from store if note_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[note_uri] # Add to cache before returning CACHE[note_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404) # Not Found@app.get("/creates/{create_id}")async def get_create_endpoint(create_id: uuid.UUID): """Serves a specific Create activity, with caching.""" create_uri = f"https://{HOST}/creates/{create_id}" if create_uri in CACHE and (datetime.now() - CACHE[create_uri]["timestamp"]) < CACHE_TTL: return ActivityResponse(CACHE[create_uri]["activity"]) if create_uri in ACTIVITY_STORE: activity = ACTIVITY_STORE[create_uri] CACHE[create_uri] = {"activity": activity, "timestamp": datetime.now()} return ActivityResponse(activity) return Response(status_code=404)
8. Activity Handlers
We use the @app.on() decorator to define handlers for specific activity types posted to our inbox.
on_create_activity: Parses incoming Create activities (specifically for Note objects) to schedule reminders.
# main.py (continued)# Handler for Follow activities@app.on(Follow)async def on_follow_activity(ctx: Context): """Automatically accepts follow requests.""" # ... (implementation omitted for brevity)# Handler for Create activities@app.on(Create)async def on_create_activity(ctx: Context): """Parses mentions to schedule reminders.""" activity = ctx.activity # Ignore if it's not a Note if not (isinstance(activity, Create) and isinstance(activity.object, Note)): return Response(status_code=202) note = activity.object # Check if the bot was mentioned is_mentioned = any( isinstance(tag, Mention) and tag.href == actor.id for tag in (note.tag or []) ) if not is_mentioned: return Response(status_code=202) # ... (Parse reminder text) delay, message, time_str = parse_reminder(command_text) # If parsing is successful, schedule the reminder as a background task if delay and message and sender_actor: asyncio.create_task(send_reminder(ctx, delay, message, sender_actor, note)) reply_content = f"<p>✅ OK! I will remind you in {time_str}.</p>" else: # If parsing fails, send usage instructions reply_content = "<p>🤔 Sorry, I didn\'t understand. Please use the format: `@reminder [time] [message]`.</p><p>Example: `@reminder 10m Check the oven`</p>" # ... (Create and send the reply Note)
Set the HOST and USER_ID variables in main.py to match your environment.
Run the server from your terminal:
uvicorn main:app --host 0.0.0.0 --port 8000
Your bot will be running at http://0.0.0.0:8000.
Now you can mention your bot from anywhere in the Fediverse (e.g., @reminder@your.host.com) to set a reminder.
Next Steps
This tutorial covers the basics of creating a simple ActivityPub bot. Since it only uses in-memory storage, all reminders will be lost on server restart. Here are some potential improvements:
Persistent Storage: Replace the in-memory ACTIVITY_STORE with a database like SQLite or PostgreSQL.
Robust Task Queuing: Use a dedicated task queue like Celery with a Redis or RabbitMQ broker to ensure reminders are not lost if the server restarts.
Advanced Commands: Add support for more complex commands, such as recurring reminders.
We hope this guide serves as a good starting point for building your own ActivityPub applications!
If a highly customisable #python, #scrum or #agile utility actually sounds like something you'd be keen on using, I'd actually really love to know. v0.2 has a couple of significant design changes that would effect calling it as a library or creating your own templates, and I'd love some feedback on the design (probably in a week or two) before I merge it in.
But - `pip install scrummd` will already give you the scrum tool nobody asked for!
If a highly customisable #python, #scrum or #agile utility actually sounds like something you'd be keen on using, I'd actually really love to know. v0.2 has a couple of significant design changes that would effect calling it as a library or creating your own templates, and I'd love some feedback on the design (probably in a week or two) before I merge it in.
But - `pip install scrummd` will already give you the scrum tool nobody asked for!
Sometimes, when coding your own thing, you do little things to make yourself happy even if it isn't _strictly in scope_ of the feature you're building.
I'm adding writing fields to #ScrumMD. I needed to rewrite the output code to make that work - which meant I'm moving (eventually) all output to Jinja2 templates rather.
And, to make me happy: I added ANSI color when using interactively to the new default template.
ALT text detailsScrumMD card in terminal. The headings and titles highlighted in color.
Text reads:
---
cli001: Display basic collection from cards
---
status: Done
# description
A basic collection is a folder in the `scrum` folder containing md cards.
By default, all cards are in the inventory. There's no filters being applied at the moment.
For now, a card must have a summary. Other fields are optional. Fields are defined either in obsidian style properties:
```md
---
Property 1: Value
Property 2: Value
---
```
or by the text following a hash header with.
A card's index is currently its filename.
# cucumber
**GIVEN** a collection of cards, and a collection folder _C_.
**WHEN** `sbl C` is run.
**THEN** a table showing the index and description all the cards in the collection is shown.
So #Zope released new versions of their packages, with pkg-resources style namespace removal.
Totally normal way to do the bumps:
1. At first, keep the existing testing hack (writing `__init__.py`). 2. Notice that the next package fails because it expects test paths relative to `zope` subdirectory. Skip it for now. 3. While doing the next package, realize you could remove that hack and simply run tests within the `zope` subdirectory! Go back and update all the previous packages, including the one that failed before. 4. Back to bumping. Notice that in the very next package you've had an even better solution: instead of `cd`, you just called `python -m unittest -s …`. Go back and update all the previous packages. 5. Back to bumping. The very next package turns out to actually expects test paths relative to the top-level site-packages directory. Well, you can use a hybrid of the `__init__.py` hack with `python -m unittest -s …`.
ALT text detailsA screenshot of a terminal showing the output of `inventory status` in the exosphere CLI showing an OpenBSD 7.7 system with 3 updates.
The output of `host show` follows, giving the platform details as fully supported, and a table listing package updates with the standard Name, Current Version, New Version, Security and Source columns.
The tables are nice colored curses-like, rich widgets.
Before Python-BPF, writing eBPF programs in Python typically involved embedding C code within multiline strings, often using libraries like bcc. eBPF allows for small programs to run based on kernel events, similar to kernel modules.
[…]
Python-BPF brings the true eBPF experience to Python by allowing the exact same functionality to be replaced by valid Python code. This is a significant improvement over multiline C strings, offering support from existing Python tools.
The lesson for me is not no #Python (yes, as a Python maintainer for SUSE, I am biased), but that I am always very worried about any efforts to generate Python code. And yes, in tabs versus spaces debate, at least for Python, I am strictly on the side of following PEP-8: no tabs at all, 4 spaces for indentation. No exceptions.
dear #python, i've only ever built cli tools in python. A couple of times I've looked at making a gui app, but unless it's a web ui (i understand html and css a bit) they all seem so very complicated. However i need to interact with local files so a web ui won't work. i'm never going to be a full fledged developer but i do want to make nice things. are there any gui frameworks that are easy-ish to get started with? actually fun/rewarding to use?
Ich arbeite inzwischen vier Monate bei pretix. Davon habe ich mir knapp einen Monat Urlaub genommen (offene Urlaubsregelung funktioniert). Ich habe schon einige Fehler gemacht und wurde nie dafür verurteilt, sondern bekam Unterstützung beim Lernen und Wiederhinbiegen. Das tut gut.
Beyond the Basics: Data Visualization in Python - Stefanie Molin
The human brain excels at finding patterns in visual representations, which is why visualizations are essential to any analysis. Come learn the skills to make customized visualizations using Python.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Beyond the Basics: Data Visualization in Python" no lado esquerdo
Foto à direita de uma mulher de cabelos ondulados escuros, usando uma blusa preta.
"Stefanie Molin", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"The human brain excels at finding patterns in visual representations, which is why visualizations are essential to any analysis. Come learn the skills to make customized visualizations using Python."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Ich arbeite inzwischen vier Monate bei pretix. Davon habe ich mir knapp einen Monat Urlaub genommen (offene Urlaubsregelung funktioniert). Ich habe schon einige Fehler gemacht und wurde nie dafür verurteilt, sondern bekam Unterstützung beim Lernen und Wiederhinbiegen. Das tut gut.
Beyond the Basics: Data Visualization in Python - Stefanie Molin
The human brain excels at finding patterns in visual representations, which is why visualizations are essential to any analysis. Come learn the skills to make customized visualizations using Python.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Beyond the Basics: Data Visualization in Python" no lado esquerdo
Foto à direita de uma mulher de cabelos ondulados escuros, usando uma blusa preta.
"Stefanie Molin", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"The human brain excels at finding patterns in visual representations, which is why visualizations are essential to any analysis. Come learn the skills to make customized visualizations using Python."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Análise e manipulação de tráfego web (HTTP) - Lidiane Monteiro
Aprenda a interceptar, analisar e modificar tráfego HTTP/HTTPS com Burp Suite e mitmproxy em um tutorial prático voltado para testes, automação, scraping e segurança web.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Análise e manipulação de tráfego web (HTTP)" no lado esquerdo
Foto à direita de uma mulher parda de cabelos pretos lisos amarrados em um rabo de cabalo, usando óculos de armação preto, brinco, batom rosado e uma jaqueta preta de couro.
"Lidiane Monteiro", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a interceptar, analisar e modificar tráfego HTTP/HTTPS com Burp Suite e mitmproxy em um tutorial prático voltado para testes, automação, scraping e segurança web."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Análise e manipulação de tráfego web (HTTP) - Lidiane Monteiro
Aprenda a interceptar, analisar e modificar tráfego HTTP/HTTPS com Burp Suite e mitmproxy em um tutorial prático voltado para testes, automação, scraping e segurança web.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Análise e manipulação de tráfego web (HTTP)" no lado esquerdo
Foto à direita de uma mulher parda de cabelos pretos lisos amarrados em um rabo de cabalo, usando óculos de armação preto, brinco, batom rosado e uma jaqueta preta de couro.
"Lidiane Monteiro", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a interceptar, analisar e modificar tráfego HTTP/HTTPS com Burp Suite e mitmproxy em um tutorial prático voltado para testes, automação, scraping e segurança web."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Nesse tutorial você aprenderá como criar um novo projeto utilizando Plone (Portal Modelo, Portal Padrão ou Portal Brasil), deixar o projeto com a sua cara e fazer o deploy em um ambiente remoto.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Da idéia ao deploy com Plone" no lado esquerdo
Foto à direita de um homem branco de cabelos e barba escuros, usando uma camisa branca.
"Érico Andrei", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Nesse tutorial você aprenderá como criar um novo projeto utilizando Plone (Portal Modelo, Portal Padrão ou Portal Brasil), deixar o projeto com a sua cara e fazer o deploy em um ambiente remoto."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Python com Microcontrolador" no lado esquerdo
Foto à direita de uma mulher branca de cabelos loiros curtos usando óculos e uma blusa floral.
"Quenia Gouevia", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda programação básica com MicroPython e ESP32 usando a plataforma BIPES. Ideal para iniciantes em IoT."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Nesse tutorial você aprenderá como criar um novo projeto utilizando Plone (Portal Modelo, Portal Padrão ou Portal Brasil), deixar o projeto com a sua cara e fazer o deploy em um ambiente remoto.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Da idéia ao deploy com Plone" no lado esquerdo
Foto à direita de um homem branco de cabelos e barba escuros, usando uma camisa branca.
"Érico Andrei", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Nesse tutorial você aprenderá como criar um novo projeto utilizando Plone (Portal Modelo, Portal Padrão ou Portal Brasil), deixar o projeto com a sua cara e fazer o deploy em um ambiente remoto."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Python com Microcontrolador" no lado esquerdo
Foto à direita de uma mulher branca de cabelos loiros curtos usando óculos e uma blusa floral.
"Quenia Gouevia", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda programação básica com MicroPython e ESP32 usando a plataforma BIPES. Ideal para iniciantes em IoT."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Adoro esse ponto reforçado pelo @lr, no Python Fluente! Sempre uso uma frase parecida com essa nas minhas aulas!
«Para entender uma atribuição em Python, leia primeiro o lado direito: é ali que o objeto é criado ou recuperado. Depois disso, a variável do lado esquerdo é vinculada ao objeto, como uma etiqueta colada a ele. Esqueça as caixas.» LR in Python Fluente: Variáveis não são caixas
ALT text detailsPara entender uma atribuição em Python, leia primeiro o lado direito: é ali que o objeto é criado ou recuperado. Depois disso, a variável do lado esquerdo é vinculada ao objeto, como uma etiqueta colada a ele. Esqueça as caixas.
Just released Drum Machine v1.5.0 and I'm excited.
You can finally export your beats as audio files! WAV, FLAC, OGG, MP3. Plus, you can add metadata like artist name, song title, and cover art. You can also set how many times your pattern repeats. So if you make a short 4-bar loop, you can export it as a 3 minute track!
I would love to hear what you create with it, so please tag me if you share your beats anywhere <3
Just released Drum Machine v1.5.0 and I'm excited.
You can finally export your beats as audio files! WAV, FLAC, OGG, MP3. Plus, you can add metadata like artist name, song title, and cover art. You can also set how many times your pattern repeats. So if you make a short 4-bar loop, you can export it as a 3 minute track!
I would love to hear what you create with it, so please tag me if you share your beats anywhere <3
Adoro esse ponto reforçado pelo @lr, no Python Fluente! Sempre uso uma frase parecida com essa nas minhas aulas!
«Para entender uma atribuição em Python, leia primeiro o lado direito: é ali que o objeto é criado ou recuperado. Depois disso, a variável do lado esquerdo é vinculada ao objeto, como uma etiqueta colada a ele. Esqueça as caixas.» LR in Python Fluente: Variáveis não são caixas
ALT text detailsPara entender uma atribuição em Python, leia primeiro o lado direito: é ali que o objeto é criado ou recuperado. Depois disso, a variável do lado esquerdo é vinculada ao objeto, como uma etiqueta colada a ele. Esqueça as caixas.
Exploring 2D and 3D geometry libraries in Python - Alexandre Villares e Jim Schmitz
This tutorial will explore the creation and manipulation of 2D and 3D geometric objects. Specifically, it will focus on the shapely and trimesh libraries in the context of creative coding using py5.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Exploring 2D and 3D geometry libraries in Python" no lado esquerdo
Foto à direita acima de um homem branco, de cabelos compridos, amarrados em um rabo, que usa barba e uma camisa xadrez azul escura.
"Alexandre Villares", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita abaixo de um homem branco, de cabelos curtos, usando uma camisa cinza, sobreposta por uma jaqueta preta.
"Jim Schmitz", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"This tutorial will explore the creation and manipulation of 2D and 3D geometric objects. Specifically, it will focus on the shapely and trimesh libraries in the context of creative coding using py5."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Exploring 2D and 3D geometry libraries in Python - Alexandre Villares e Jim Schmitz
This tutorial will explore the creation and manipulation of 2D and 3D geometric objects. Specifically, it will focus on the shapely and trimesh libraries in the context of creative coding using py5.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Exploring 2D and 3D geometry libraries in Python" no lado esquerdo
Foto à direita acima de um homem branco, de cabelos compridos, amarrados em um rabo, que usa barba e uma camisa xadrez azul escura.
"Alexandre Villares", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita abaixo de um homem branco, de cabelos curtos, usando uma camisa cinza, sobreposta por uma jaqueta preta.
"Jim Schmitz", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"This tutorial will explore the creation and manipulation of 2D and 3D geometric objects. Specifically, it will focus on the shapely and trimesh libraries in the context of creative coding using py5."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Just released Drum Machine v1.5.0 and I'm excited.
You can finally export your beats as audio files! WAV, FLAC, OGG, MP3. Plus, you can add metadata like artist name, song title, and cover art. You can also set how many times your pattern repeats. So if you make a short 4-bar loop, you can export it as a 3 minute track!
I would love to hear what you create with it, so please tag me if you share your beats anywhere <3
You can also buy stickers and other items... soon my "Python Reading Club" and "Python is also for artists!" designs will be available. This will help support my free and open source activities. I make free and open educational resources, I teach at several places and I need to make ends meet.
ALT text detailsRedbubble shopping catalog image of a smiling woman wearing a blue T-Shirt with an image of a "purple slab" with holes in a stencil font forming the words: "numpy, shapely, trimesh, & py5."
ALT text detailsFoto oficial da Python Brasil 2022 em preto e branco ao fundo
"Programação disponível" em vermelho em fonte que simula tinta.
e logo da Python Brasil 2025 embaixo.
Ensinar Python com Alegria: Didática e Vocação Viva - Fernando Masanori
Tutorial para quem quer ensinar Python com alegria, acolhimento e eficácia. Vamos falar de vocação, didática, erros comuns e como transformar vidas com código.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Ensinar Python com Alegria: Didática e Vocação Viva" no lado esquerdo
Foto à direita de um homem amarelo, de cabelos pretos, usando uma camisa verde exército e óculos de armação preta.
"Fernando Masanori", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Tutorial para quem quer ensinar Python com alegria, acolhimento e eficácia. Vamos falar de vocação, didática, erros comuns e como transformar vidas com código."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
ALT text detailsFoto oficial da Python Brasil 2022 em preto e branco ao fundo
"Programação disponível" em vermelho em fonte que simula tinta.
e logo da Python Brasil 2025 embaixo.
What people are using to install commands (Python programs and/or shell scripts that parses options, imports & uses modules of same package) of a package?
I am aware of "entry point" in "pyproject.toml"; am not asking for or help with that.
If nothing comes up, may have to do edit those files during installation to supply the python interpreter (either to run with or in shebang line) & "sys.path" via Makefile & such ...
Ever feel like your spreadsheets are holding you back? Python gives Excel users the tools to break through those limits.
Learn to translate your spreadsheet logic into code, clean and reshape data with pandas, automate reports, pull info from databases and APIs, and even create interactive dashboards.
It’s not about leaving Excel behind, but making your work faster, smarter, and more reliable.
ALT text detailsBook cover of Python for Excel Users by Tracy Stephens. The top portion has a pale yellow background with a green horizontal stripe. Title text in bold black reads: “PYTHON FOR EXCEL USERS.” Below in smaller font: “Know Excel? You can learn Python.” Author’s name, “Tracy Stephens,” is centered in white text on a black bar. The illustration shows a large robot breaking through a grid that resembles an Excel spreadsheet, with numbered rows and lettered columns. The robot has a humanoid shape with a square torso, round head with antenna, and rectangular arms. Pieces of the spreadsheet grid and small blocks fly outward as the robot smashes through. No Starch Press logo appears in the bottom right corner.
Ensinar Python com Alegria: Didática e Vocação Viva - Fernando Masanori
Tutorial para quem quer ensinar Python com alegria, acolhimento e eficácia. Vamos falar de vocação, didática, erros comuns e como transformar vidas com código.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Ensinar Python com Alegria: Didática e Vocação Viva" no lado esquerdo
Foto à direita de um homem amarelo, de cabelos pretos, usando uma camisa verde exército e óculos de armação preta.
"Fernando Masanori", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Tutorial para quem quer ensinar Python com alegria, acolhimento e eficácia. Vamos falar de vocação, didática, erros comuns e como transformar vidas com código."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
You can also buy stickers and other items... soon my "Python Reading Club" and "Python is also for artists!" designs will be available. This will help support my free and open source activities. I make free and open educational resources, I teach at several places and I need to make ends meet.
ALT text detailsRedbubble shopping catalog image of a smiling woman wearing a blue T-Shirt with an image of a "purple slab" with holes in a stencil font forming the words: "numpy, shapely, trimesh, & py5."
It's 2025 and I am still not 100% sure how to have #PyGame go to sleep and wait for *either* an event from the keyboard/mouse/controller *or* an event from the network *or* a vblank interrupt without some kind of hard-coded polling timeout. Various attempts I've made at this in the past have violated thread safety rules and I'm not sure the documentation even covers all the constraints I need to preserve. #python
Primeiros Passos com Python para Mulheres Iniciantes - PyLadies São Paulo
Um tutorial introdutório e acolhedor, conduzido por mulheres da comunidade PyLadies, voltado a iniciantes que desejam aprender a programar com Python do zero.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Primeiros Passos com Python para Mulheres Iniciantes" no lado esquerdo
Foto à direita da logo das PyLadies São Paulo.
"PyLadies São Paulo", nome do grupo de ministrantes, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Um tutorial introdutório e acolhedor, conduzido por mulheres da comunidade PyLadies, voltado a iniciantes que desejam aprender a programar com Python do zero."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Primeiros Passos com Python para Mulheres Iniciantes - PyLadies São Paulo
Um tutorial introdutório e acolhedor, conduzido por mulheres da comunidade PyLadies, voltado a iniciantes que desejam aprender a programar com Python do zero.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Primeiros Passos com Python para Mulheres Iniciantes" no lado esquerdo
Foto à direita da logo das PyLadies São Paulo.
"PyLadies São Paulo", nome do grupo de ministrantes, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Um tutorial introdutório e acolhedor, conduzido por mulheres da comunidade PyLadies, voltado a iniciantes que desejam aprender a programar com Python do zero."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Gostaríamos de fazer um pedido especial à comunidade.
Recebemos pedidos de instituições públicas e projetos sociais que ensinam programação para pessoas em situação de vulnerabilidade, que adorariam participar da Python Brasil. Infelizmente, não temos verba para custear os ingressos.
Se você tem condições, doe um ingresso e ajude a levar conhecimento e inclusão para quem mais precisa. Sua doação pode transformar a experiência de um estudante.
ALT text detailsFoto oficial da Python Brasil 2019,
Logo da Python Brasil na parte superior.
"Doe ingressos para estudantes" em cor branca e fonte que se assemelha a tinta.
Gostaríamos de fazer um pedido especial à comunidade.
Recebemos pedidos de instituições públicas e projetos sociais que ensinam programação para pessoas em situação de vulnerabilidade, que adorariam participar da Python Brasil. Infelizmente, não temos verba para custear os ingressos.
Se você tem condições, doe um ingresso e ajude a levar conhecimento e inclusão para quem mais precisa. Sua doação pode transformar a experiência de um estudante.
ALT text detailsFoto oficial da Python Brasil 2019,
Logo da Python Brasil na parte superior.
"Doe ingressos para estudantes" em cor branca e fonte que se assemelha a tinta.
Temos a honra de apresentar nossa segunda Keynote: Rafahela Bazzanella!
Rafahela é cofundadora da @associacaopythonbrasil, mantenedora do Portal Modelo, solução utilizada por 1200 casas legislativas no Brasil e mãe do Rodrigo 🥰
ALT text detailsFundo de parede grafitada.
Keynote escrito em fonte que simula tinta
Rafahela Bazzanella em vermelho sobre um spray preto.
"Cofundadora da APyB, mantenedora do portal modelo, solução utilizada por 1200 casas legislativas no Brasil" escrito em tipografia que simula máquina de escrever do lado esquerdo.
Foto de uma mulher branca de longos cabelos castanhos usando brincos de argola e maquiagem.
Temos a honra de apresentar nossa segunda Keynote: Rafahela Bazzanella!
Rafahela é cofundadora da @associacaopythonbrasil, mantenedora do Portal Modelo, solução utilizada por 1200 casas legislativas no Brasil e mãe do Rodrigo 🥰
ALT text detailsFundo de parede grafitada.
Keynote escrito em fonte que simula tinta
Rafahela Bazzanella em vermelho sobre um spray preto.
"Cofundadora da APyB, mantenedora do portal modelo, solução utilizada por 1200 casas legislativas no Brasil" escrito em tipografia que simula máquina de escrever do lado esquerdo.
Foto de uma mulher branca de longos cabelos castanhos usando brincos de argola e maquiagem.
Testes automatizados e qualidade de dados em data pipelines - Gabrielle Stephanie e Talissa Moura
Aprenda a criar pipelines de dados robustos com testes automatizados e validação de qualidade em python. Domine testes unitários, integração, performance e garantia de dados confiáveis.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Testes automatizados e qualidade de dados em data pipelines" no lado esquerdo
Foto à direita acima de uma mulher de cabelos escuros, usando óculos e fones de ouvido cor de rosa.
"Gabrielle Stephanie", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita de uma mulher parda abaixo, de cabelos curtos e usando óculos de armação preta.
"Talissa Moura", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a criar pipelines de dados robustos com testes automatizados e validação de qualidade em python. Domine testes unitários, integração, performance e garantia de dados confiáveis."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Primeiros passos com Padrões de Projeto (com TDD) - Vitor Buxbaum
Já sabe refatorar um código, mas ainda não entrou no mundo dos Padrões de Projeto? Essa é sua oportunidade de entender o motivo de existirem, e usá-los para melhorar um código existente.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Primeiros passos com Padrões de Projeto (com TDD)" no lado esquerdo
Foto à direita de um homem branco, de cabelos descoloridos, que usa barba e camiseta escura.
"Vitor Buxbaum", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Já sabe refatorar um código, mas ainda não entrou no mundo dos Padrões de Projeto? Essa é sua oportunidade de entender o motivo de existirem, e usá-los para melhorar um código existente."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Testes automatizados e qualidade de dados em data pipelines - Gabrielle Stephanie e Talissa Moura
Aprenda a criar pipelines de dados robustos com testes automatizados e validação de qualidade em python. Domine testes unitários, integração, performance e garantia de dados confiáveis.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Testes automatizados e qualidade de dados em data pipelines" no lado esquerdo
Foto à direita acima de uma mulher de cabelos escuros, usando óculos e fones de ouvido cor de rosa.
"Gabrielle Stephanie", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita de uma mulher parda abaixo, de cabelos curtos e usando óculos de armação preta.
"Talissa Moura", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a criar pipelines de dados robustos com testes automatizados e validação de qualidade em python. Domine testes unitários, integração, performance e garantia de dados confiáveis."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Primeiros passos com Padrões de Projeto (com TDD) - Vitor Buxbaum
Já sabe refatorar um código, mas ainda não entrou no mundo dos Padrões de Projeto? Essa é sua oportunidade de entender o motivo de existirem, e usá-los para melhorar um código existente.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Primeiros passos com Padrões de Projeto (com TDD)" no lado esquerdo
Foto à direita de um homem branco, de cabelos descoloridos, que usa barba e camiseta escura.
"Vitor Buxbaum", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Já sabe refatorar um código, mas ainda não entrou no mundo dos Padrões de Projeto? Essa é sua oportunidade de entender o motivo de existirem, e usá-los para melhorar um código existente."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Criando aplicações de linha de comando amáveis - Álvaro Justen
Aprenda a criar CLIs amigáveis e robustas, só com a stdlib. Vamos ver o que torna uma CLI boa (ou péssima), boas práticas da filosofia UNIX e como facilitar a vida de quem ama o terminal.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Criando aplicações de linha de comando amáveis" no lado esquerdo
Foto à direita de um homem branco de cabelos e barba escuros.
"Álvaro Justen", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a criar CLIs amigáveis e robustas, só com a stdlib. Vamos ver o que torna uma CLI boa (ou péssima), boas práticas da filosofia UNIX e como facilitar a vida de quem ama o terminal."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Criando aplicações de linha de comando amáveis - Álvaro Justen
Aprenda a criar CLIs amigáveis e robustas, só com a stdlib. Vamos ver o que torna uma CLI boa (ou péssima), boas práticas da filosofia UNIX e como facilitar a vida de quem ama o terminal.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Criando aplicações de linha de comando amáveis" no lado esquerdo
Foto à direita de um homem branco de cabelos e barba escuros.
"Álvaro Justen", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Aprenda a criar CLIs amigáveis e robustas, só com a stdlib. Vamos ver o que torna uma CLI boa (ou péssima), boas práticas da filosofia UNIX e como facilitar a vida de quem ama o terminal."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Python nas nuvens: validando infraestrutura AWS com código - Paula Silva, Maria Giovanna e Izabely Gama
Você já parou para pensar que não é só o código da sua aplicação que precisa ser testado? Vem com a gente descobrir como a validação da infraestrutura está transformando a forma de garantir qualidade.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Python nas nuvens: validando infraestrutura AWS com código" no lado esquerdo
Foto à direita na parte de cima de uma mulher parda, de cabelos castanhos longos e lisos, usando uma blusa cor de mostarda.
"Izabely Gama", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita no meio de uma mulher branca de cabelos castanhos lisos e maquiagem leve.
"Maria Giovanna ", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita na parte de baixo de uma mulher preta de cabelos castanhos lisos e longos usando uma blusa de gola alta azul marinho sem mangas.
"Paula Silva", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Você já parou para pensar que não é só o código da sua aplicação que precisa ser testado? Vem com a gente descobrir como a validação da infraestrutura está transformando a forma de garantir qualidade."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
Python nas nuvens: validando infraestrutura AWS com código - Paula Silva, Maria Giovanna e Izabely Gama
Você já parou para pensar que não é só o código da sua aplicação que precisa ser testado? Vem com a gente descobrir como a validação da infraestrutura está transformando a forma de garantir qualidade.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o título:
"Python nas nuvens: validando infraestrutura AWS com código" no lado esquerdo
Foto à direita na parte de cima de uma mulher parda, de cabelos castanhos longos e lisos, usando uma blusa cor de mostarda.
"Izabely Gama", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita no meio de uma mulher branca de cabelos castanhos lisos e maquiagem leve.
"Maria Giovanna ", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
Foto à direita na parte de baixo de uma mulher preta de cabelos castanhos lisos e longos usando uma blusa de gola alta azul marinho sem mangas.
"Paula Silva", nome da pessoa ministrante, escrito em tinta vermelha sobre spray preto.
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior.
ALT text detailsFundo que mostra uma parede cinza, com alguns sinais de grafitti.
Desenhos parecidos com grafos nas bordas superior e inferior direita.
"Tutorial" escrito na parte superior, em uma fonte preta que simula tinta.
Uma canto feito para simular um spray vermelho que delimita o conteúdo:
"Você já parou para pensar que não é só o código da sua aplicação que precisa ser testado? Vem com a gente descobrir como a validação da infraestrutura está transformando a forma de garantir qualidade."
E a logo da Python Brasil 2025 em vermelho e preto na parte inferior
I think the bug I resolved (I wouldn't say fixed) in @novelwriter today is the weirdest I've encountered so far.
The app uses @-based keywords to set meta data in the text. An auto-complete menu pops up to suggest which keyword when you type an @ on a new line.
In the current version (at least) if you have the editor "justified margins" set, type an @, then type backspace, then *and only then* will Qt/PyQt segfault and crash the app.
ALT text detailsBlack background promotional banner. Large white bold text at the top reads: “LABOR DAY SALE 35% OFF SITEWIDE.” Below, smaller yellow text reads: “USE CODE LABORDAY35.” Further down in white text: “ends 9/1/2025 23:59 PDT.” In the bottom left corner, there is the classic No Starch Press coffee robot.
ALT text detailsThe image shows a screenshot of a GitHub repository page for "The Algorithms - Python." The page is set against a dark background with text in white and blue. At the top, the repository name "TheAlgorithms" and the language "Python" are displayed. Below, the title "The Algorithms - Python" is prominently featured. Key information includes a Gitpod link for "Ready-to-Code," a repository size of 15.1 MiB, and 211 online users in the chat. The CI status is "passing," and pre-commit is enabled with the code style being "ruff." The page states that all algorithms are implemented in Python for educational purposes, noting that they may be less efficient than the Python standard library. A section titled "Getting Started" suggests reading the contribution guidelines before contributing. The "Community Channels" section mentions Discord and Gitter for community interaction.
ALT text detailsThe image displays a mobile device screen with a dark background and a list of items under the title "DIRECTORY.md." The screen is divided into two main sections: "Audio Filters" and "Backtracking." The "Audio Filters" section includes three items: "Butterworth Filter," "Iir Filter," and "Show Response," with the first two items highlighted in blue. The "Backtracking" section lists various algorithms and problems, such as "All Combinations," "All Permutations," "All Subsequences," "Coloring," "Combination Sum," "Crossword Puzzle Solver," "Generate Parentheses," "Generate Parentheses Iterative," "Hamiltonian Cycle," "Knight Tour," "Match Word Pattern," "Minimax," "N Queens," "N Queens Math," "Power Sum," and "Rat In Maze," with all items highlighted in blue. The top of the screen shows the time as 01:09, a battery level of 76%, and a 4G signal. The bottom of the screen features navigation buttons.
Provided by @altbot, generated privately and locally using Ovis2-8B
🌱 Energy used: 0.869 Wh
I have great news for everyone who likes to fuzz Python code. pysource-codegen 0.7.1 and pysource-minimize 0.10.0 have been released. Both support Python 3.14 and can now also generate/minimize template strings. Feel free to give it a try.
I have great news for everyone who likes to fuzz Python code. pysource-codegen 0.7.1 and pysource-minimize 0.10.0 have been released. Both support Python 3.14 and can now also generate/minimize template strings. Feel free to give it a try.
It talks about Python's origins, the founding of the PSF, the Python 2 to Python 3 transition, the struggle to increase diversity, Guido's resignation over the walrus operator, as well as Python's relevance as a language now and in the future.
It talks about Python's origins, the founding of the PSF, the Python 2 to Python 3 transition, the struggle to increase diversity, Guido's resignation over the walrus operator, as well as Python's relevance as a language now and in the future.
@pythonbrasil Seria legal incluir as tags #python#pythonbrasil#pybr2025 nos toots para dar mais visibilidade. Bastante gente segue a #python e as outras facilitam na hora de encontrar os toots da comunidade junto com os da conta oficial.
Outro detalhe é que esse toot foi publicado como English, talvez Português dê um pouco mais de alcance porque algumas pessoas filtram por linguagem (imagino que muito poucas na comunidade Python).
It's not hard to generate a static HTML page that loads your game to run on the browser with #pyodide (WASM). And it comes with an assets editor and a #chiptune making tool.
It's not hard to generate a static HTML page that loads your game to run on the browser with #pyodide (WASM). And it comes with an assets editor and a #chiptune making tool.
@raiderrobert I guess it's rather that I'm collecting new languages, depending on the problem at hand. I.e. while I still do lots of #C coding for efficiency at runtime, now #Python is entering for efficiency during development time. Then there is all that web stuff (#HTML, #CSS, #JS, and still #PHP as backend) for interactive display. And since about five years Verilog for #FPGA programming.
I wouldn't call any of these a "permanent" change.
Mesmo que não possa participar, siga a @pythonbrasil e dê boost nos toots para apoiar o evento. Mostre a força do fediverso na divulgação e conexão das comunidades técnicas/bamblers.
ALT text detailsFundo do edifício Banespa, respingos de tinta preta a partir do canto inferior esquerdo, logo da Python Brasil 2025 em letras de grafitti em cores branco, vermelho e borda preta.
No centro "Faltam 2 meses" em preto e vermelho.
👋 Hello Mastodon! Excited to be here. I’m a Data Science Expert specializing in Generative AI & Machine Learning. Skilled in Python, R, MySQL, Power BI & Analytics. I’ll share insights, projects & discussions on AI, ML, Data Science & Visualization. Looking forward to connecting & learning with this community 🚀
So I've been playing around with the #geminiprotocol and it occurred to me that I don't actually know how #TLS works. I want to know if the stream is still encrypted even if I skip cert verification (I also can't seem figure out #TOFU in #python). I was able to snoop on the stream with netcat but not I'm not sure what I'm looking at, after all it is a binary payload. Is there a tool for talking tls or am I stuck reading the RFC and doing it by hand?
Hey #python folks -- what's everyone's favorite python profiling tools these days? My goal is to capture data during a run so I can shove it in a flamegraph and identify where the actual bottlenecks are.
Você faz parte de um grupo sub-representado e quer ir à Python Brasil 2025 mas a grana está curta? Tente participar do Programa de Auxílio Financeiro:
""" Estão abertas as inscrições para o Programa de Auxílio Financeiro para Python Brasil 2025 que tem como objetivo beneficiar grupos historicamente sub-representados nas edições presenciais.
ALT text detailsImagem de divulgação do Programa de Auxílio Financeira da Python Brasil 2025. Em letras estilizadas, a palavra "Python" aparece em vermelho no topo da imagem e logo abaixo aparece em letras brancas "Brasil 2025". Num retângulo preto na parte inferior da imagem, está escrito "Programa de auxílio Financeiro" em branco e "Inscreva-se até 27 de agosto" em amarelo. O fundo da imagem é uma visão panorâmica de uma cidade em cinza.
Hi Pythonistas! Previously, I was able to use the Trove classifier Private :: Do Not Upload to prevent packages from being accidentally uploaded to PyPI. Is there a similar option with the PEP 639 licence expression? @pypi#Python
Can't wait for #PyOhio 2026? Throughout the year, there are many other regional #Python events you could try attending, so follow them for updates! If you've heard of other regional US conferences we should know about, please share them with us!
ALT text detailsPhoto of a lighted peg wall decorated in various patterns. PyOhio is spelled out in purple in the top center. Various other people's initials and smiley faces are scattered over the board.
Image credit: Photo from PyOhio 2025 by Mike Pirnat
Você faz parte de um grupo sub-representado e quer ir à Python Brasil 2025 mas a grana está curta? Tente participar do Programa de Auxílio Financeiro:
""" Estão abertas as inscrições para o Programa de Auxílio Financeiro para Python Brasil 2025 que tem como objetivo beneficiar grupos historicamente sub-representados nas edições presenciais.
ALT text detailsImagem de divulgação do Programa de Auxílio Financeira da Python Brasil 2025. Em letras estilizadas, a palavra "Python" aparece em vermelho no topo da imagem e logo abaixo aparece em letras brancas "Brasil 2025". Num retângulo preto na parte inferior da imagem, está escrito "Programa de auxílio Financeiro" em branco e "Inscreva-se até 27 de agosto" em amarelo. O fundo da imagem é uma visão panorâmica de uma cidade em cinza.
Once again I demonstrate that I do not know how to use social media, not even Mastodon. Let me try that again properly with the relevant metadata: I have done my first post-ZeroVer release of #DBXS, an #OpenSource#Python raw #SQL#database access library. If that collection of hashtags seems interesting to you, perhaps check it out!
Sábado dia 23/08 começa a primeira turma do treinamento Python para DevOps
Serão 4 meses de entrega de conteúdo em vídeo abordando os principais usos de #Python para Automações, #Testes, #DevOps com uma aula ao vivo a cada 15 dias.
ALT text detailsImagem de fundo da Python Brasil 2022, onde temos três homens e duas mulheres, parte participantes, parte organizadores, no palco do evento.
"Ajude a construir a Python Brasil 2025" escrito em uma fonte de grafite.
My #PyOhio 2025 talk is now on YouTube! I show how using #pytest with a test-first process taught me how #Django turns a request into a response for my #iubase web app.
ALT text detailsTitle slide for Carl James' PyOhio 2025 talk "How a Solo Hobbyist Learned to Love Testing". The slide shows event sponsors Meta, Intellovations, the Python Software Foundation and credits production by Next Day Video.
My #PyOhio 2025 talk is now on YouTube! I show how using #pytest with a test-first process taught me how #Django turns a request into a response for my #iubase web app.
ALT text detailsTitle slide for Carl James' PyOhio 2025 talk "How a Solo Hobbyist Learned to Love Testing". The slide shows event sponsors Meta, Intellovations, the Python Software Foundation and credits production by Next Day Video.
Well, I pushed through, here we are: Mastodon.py 2.1.0, with support for everything in Mastodon up to version 4.4.3, a bunch of new convenience methods, and some bugs fixed, is out! 🐍
@glyph@hynek it'd be interesting IMO to see the breakdown of how many people use YouTube by level of experience. My hypothesis is that there's a (positive) correlation between level of experience and preference for written documentation over video documentation - I think videos are reasonably well suited for tutorials (if you are the type of person who can learn from a video at all) but poorly suited for the reference documentation that more experienced devs are more likely to use.
Well, I pushed through, here we are: Mastodon.py 2.1.0, with support for everything in Mastodon up to version 4.4.3, a bunch of new convenience methods, and some bugs fixed, is out! 🐍
Well, I pushed through, here we are: Mastodon.py 2.1.0, with support for everything in Mastodon up to version 4.4.3, a bunch of new convenience methods, and some bugs fixed, is out! 🐍
Running a single user (or small) instance in the Fediverse? Relay instances acting as a spreading proxy can help you to find your content and also to make your posts visible to others - and you can easily join with #Mastodon, #snac and many other ones!
The https://fedi-relay.gyptazy.com relay is mostly for tech related content and just got updates to the manpageblog design.
Running a single user (or small) instance in the Fediverse? Relay instances acting as a spreading proxy can help you to find your content and also to make your posts visible to others - and you can easily join with #Mastodon, #snac and many other ones!
The https://fedi-relay.gyptazy.com relay is mostly for tech related content and just got updates to the manpageblog design.
Well, I pushed through, here we are: Mastodon.py 2.1.0, with support for everything in Mastodon up to version 4.4.3, a bunch of new convenience methods, and some bugs fixed, is out! 🐍
Running a single user (or small) instance in the Fediverse? Relay instances acting as a spreading proxy can help you to find your content and also to make your posts visible to others - and you can easily join with #Mastodon, #snac and many other ones!
The https://fedi-relay.gyptazy.com relay is mostly for tech related content and just got updates to the manpageblog design.
Running a single user (or small) instance in the Fediverse? Relay instances acting as a spreading proxy can help you to find your content and also to make your posts visible to others - and you can easily join with #Mastodon, #snac and many other ones!
The https://fedi-relay.gyptazy.com relay is mostly for tech related content and just got updates to the manpageblog design.
It's a great team with great leaders.The role is continuing to build out their core APIs and fusing their different data sources into some consistent models.
Preparing a post about lafleur, the CPython JIT fuzzer I develop.
It has found 4 JIT crashes so far: #136996: "JIT: `executor->vm_data.valid` assertion failure in `unlink_executor`". #137007: "JIT: assertion failure in _PyObject_GC_UNTRACK". #137728: "Assertion failure or `SystemError` in `_PyEval_EvalFrameDefault` in a JIT build". #137762: "Assertion failure in `optimize_uops` in a JIT build".
Galera, minha atividade aberta (presencial) de #Python no #SescAvPaulista está rolando às terças à tarde este semestre.
Todas as pessoas são bem-vindas, não precisa ter conhecimentos prévios, veja no link mais detalhes, um pouco do que vamos conversar (e tem alguns registros do que já conversamos):
Galera, minha atividade aberta (presencial) de #Python no #SescAvPaulista está rolando às terças à tarde este semestre.
Todas as pessoas são bem-vindas, não precisa ter conhecimentos prévios, veja no link mais detalhes, um pouco do que vamos conversar (e tem alguns registros do que já conversamos):
Am I the only one who didn't know that #Python list comprehensions (and presumably other types of comprehensions) can accept **multiple** conditional statements at the end?
It's a great team with great leaders.The role is continuing to build out their core APIs and fusing their different data sources into some consistent models.
I'm hosting office hours again in less than 12 hours. Have a question about #Python, Python Morsels, or anything else you think I might have thoughts on?
I'm hosting office hours again in less than 12 hours. Have a question about #Python, Python Morsels, or anything else you think I might have thoughts on?
ALT text detailsPatial view of Thonny IDE with Python code and a window with a recursive grid os squares containd circles, stars and other small elements.
ALT text detailsScreen capture of the course page showing on top:
6,106 students 57 Reviews 100% positive ratings
[showing some testimonials below]
ALT text detailsPatial view of Thonny IDE with Python code and a window with a recursive grid os squares containd circles, stars and other small elements.
ALT text detailsScreen capture of the course page showing on top:
6,106 students 57 Reviews 100% positive ratings
[showing some testimonials below]
1. Some packages, like Django, should be bound by minor instead of major versions.
2. Calendar versioning uses different logic, and I do not know how it plays with this setting.
3. Not every package needs an upper bound, especially when it constrains itself to another package that has been pinned (some Django extensions, for example).
4. The setting itself is in preview and may change its behavior at any time.
👾✨ Know a young person who’s curious about coding? ✨👨💻
On Saturday 20 Sept, PyCon UK 2025 is hosting a Young Coders’ Day alongside the main conference – a fun, hands-on intro to coding for people aged 8–16!
They’ll have the opportunity to 🎮 build games, 🎨 create art, 🛰️ code satellites, and share their projects with #PyConUK2025 attendees 🎉🐍
👾✨ Know a young person who’s curious about coding? ✨👨💻
On Saturday 20 Sept, PyCon UK 2025 is hosting a Young Coders’ Day alongside the main conference – a fun, hands-on intro to coding for people aged 8–16!
They’ll have the opportunity to 🎮 build games, 🎨 create art, 🛰️ code satellites, and share their projects with #PyConUK2025 attendees 🎉🐍
@fd93 👍 Probably a good idea to always use virtual environments regardless (and use them liberally, e.g. a different one for every program you install). Much of modern #Python packaging infrastructure is not designed to handle conflicting versions of packages in one environment.
@fd93 👍 Probably a good idea to always use virtual environments regardless (and use them liberally, e.g. a different one for every program you install). Much of modern #Python packaging infrastructure is not designed to handle conflicting versions of packages in one environment.
PSA: Python no longer behaves the same way in #Vercel Node 22.x images as it did in Node 18.x.
If you are using raw 'pip install -r requirements.txt' you'll need to switch over to 'source venv/bin/activate && pip install -r requirements.txt' or a similar pattern.
How does e.g. "tmux" do its "switch screen" stuff, and can I do it with #Python + Rich? I've found "pymux", which appears to be emulating vt100 in Python ... and then I guess re-rendering to the "real" screen? Is that what #tmux does (too much C for me to grok)?
After some years, things changed and my opinions changed a bit too:
#py5 is going super strong and the "new snake_case names" are not an issue for me anymore. I used to worry a lot about all the Processing Python mode examples and teaching materials out there, and some of my own, with "CamelCase Processing names" I'm not worried at all about it anymore!
For the record, Processing Python mode is just a legacy thing, no one should start anything new with it.
The great "pure Python" (no Java required) Processing implementation project #p5py seems stalled, latest release in Dec. 2023 :((( Advancing it was always going to be an uphill battle...
The unrelated #Brython based site p5py.com seems to be gone, so I removed it from the table.
I added a link to my own #pyp5js hack py5pjs/py5mode because this is the version of pyp5js I'm using most nowadays.
After some years, things changed and my opinions changed a bit too:
#py5 is going super strong and the "new snake_case names" are not an issue for me anymore. I used to worry a lot about all the Processing Python mode examples and teaching materials out there, and some of my own, with "CamelCase Processing names" I'm not worried at all about it anymore!
For the record, Processing Python mode is just a legacy thing, no one should start anything new with it.
The great "pure Python" (no Java required) Processing implementation project #p5py seems stalled, latest release in Dec. 2023 :((( Advancing it was always going to be an uphill battle...
The unrelated #Brython based site p5py.com seems to be gone, so I removed it from the table.
I added a link to my own #pyp5js hack py5pjs/py5mode because this is the version of pyp5js I'm using most nowadays.
"Python 3.13 is the newest major release of the Python programming language, and it contains many new features and optimizations compared to Python 3.12. 3.13.6 is the sixth maintenance release of 3.13, containing around 200 bugfixes, build improvements and documentation changes since 3.13.5."
"Python 3.13 is the newest major release of the Python programming language, and it contains many new features and optimizations compared to Python 3.12. 3.13.6 is the sixth maintenance release of 3.13, containing around 200 bugfixes, build improvements and documentation changes since 3.13.5."
New blog post: I've mentioned before that #litestar is by far my favorite of the new generation of #python web frameworks, and I've finally found time to write about why.
Sabe quem foi na #PythonCerrado2025 e apresentou uma palestra? Pedro, meu filho de 11 anos!
Tive que ajudar numa parte porque não tivemos tempo para ensaiar: o que seria uma palestra relâmpago foi promovida a palestra normal antes de ele treinar a parte que acabei apresentando.
5 minutos depois da palestra, ele tranquilão: "pai , você ainda está tremendo!".
Asking for an opinion from all my #python friends. The non-work Python project I'm developing has a few places where I need to find the most recent text above the current position that matches a #regex. I can either:
- Create a "match all the things from the beginning, but then only use the one whose match.start() is before the current position
The first is clearly cleaner, but requires users to add one more module (they're already needing to add two others for different stuff in the program). The second is a tad kludgy, slower (but only by maybe a tenth of a second), but requires no additional includes.
Opinions? Strong opinions? First-hand experience with the regex module?
Sabe quem foi na #PythonCerrado2025 e apresentou uma palestra? Pedro, meu filho de 11 anos!
Tive que ajudar numa parte porque não tivemos tempo para ensaiar: o que seria uma palestra relâmpago foi promovida a palestra normal antes de ele treinar a parte que acabei apresentando.
5 minutos depois da palestra, ele tranquilão: "pai , você ainda está tremendo!".
print(''. join( *[
map(lambda x: a[x ]
if x in a else x,[
s for s in input()]
)for a in [dict(**
a, **b)for a, b in
zip( *list ( zip ([
dict(dict( dict(**a
,**b),**c) ,**d)for
a,b,c,d in [( {i: j
for i,j in zip(a ,a
[: :-1])}, {i.upper
():j.upper ()for i,
j in zip(a ,a[ ::
-1])}, {j :i for
i , j in zip(a,a
[ : : -1] )},{j .
upper (): i.upper
()for i,j in zip(
a, a[ : :- 1 ] ) }
) for a in input (
).split()]] )))]]))
print(''. join( *[
map(lambda x: a[x ]
if x in a else x,[
s for s in input()]
)for a in [dict(**
a, **b)for a, b in
zip( *list ( zip ([
dict(dict( dict(**a
,**b),**c) ,**d)for
a,b,c,d in [( {i: j
for i,j in zip(a ,a
[: :-1])}, {i.upper
():j.upper ()for i,
j in zip(a ,a[ ::
-1])}, {j :i for
i , j in zip(a,a
[ : : -1] )},{j .
upper (): i.upper
()for i,j in zip(
a, a[ : :- 1 ] ) }
) for a in input (
).split()]] )))]]))
Anyone have suggestions for open source projects using Python that could use some junior-level assistance? I enjoy my hobby projects, but I'd like to get involved with doing something that has meaning to real users. Are smaller projects a better starting point, or would you recommend a larger one that has an existing community?
I've pushed another significant update to my patch reporting tool: the Dashboard is now fully reactive, scrolls, and can be resized dynamically, alongside mutiple small QoL changes in logging.
I've pushed another significant update to my patch reporting tool: the Dashboard is now fully reactive, scrolls, and can be resized dynamically, alongside mutiple small QoL changes in logging.
I am mucking around with writing a simple new thing that, in order to have type annotations that aren't *completely* useless, needs to deal with the fact that Protocol and Factory aren't annotated.
But adding annotations makes the entire framework notice that the pattern of paired-Protocol-and-Factory subclasses are inherently LSP violations, because .protocol and .factory are writable attributes and thus invariant.
The #NeuroFedora team has changed how it packages software for users. We now prioritise software that cannot easily be installed from upstream forges (like PyPi) for inclusion as #rpm packages into @fedora . Software that can be easily installed is tested to ensure that it functions on all the #Python versions supported by any Fedora release.
The #NeuroFedora team has changed how it packages software for users. We now prioritise software that cannot easily be installed from upstream forges (like PyPi) for inclusion as #rpm packages into @fedora . Software that can be easily installed is tested to ensure that it functions on all the #Python versions supported by any Fedora release.
@tartley progress report on my experiment. I have been religiously interacting with #Python only via #uv. No installing outside of uv environments. Then I had to interact with some projects using poetry. So I also had Python installed by Poetry. Are these the same binaries or not? I haven't investigated. Uv would likely re-use the ones installed by Poetry. Does it work the other way round? Probs not. Anyways, this remains a virgin system, because I haven't had any #julialang, #Jupiter or #Quarto on it yet - they're bound to be needed at some point and then it may break the harmony. Or just someone showing up with a good ol' pipenv. But at least starting from uv seems to delay the chaos.
@melissawm Conheci a Camila Maia @cmaiacd, ela disse que vocês têm várias coisas em comum. Hoje ela apresenta o KeyNote da #PythonCerrado2025, mais uma pra lista de coisas que as duas já fizeram :)
TIL you can embed #python dependencies in a gist and then run it as a one-shot script using uv. In screenshot 1 I've pulled in pyfiglet to create a snazzy message. You can inline your dependencies into your script using `uv add --script <dep>`. This adds the necessary preamble as a comment (screenshot 2). I came across this tip whilst surfing Simon Willison’s gists. I've linked to Simon's more detailed blog post and the documentation in #uv. https://simonwillison.net/2024/Dec/19/one-shot-python-tools/ https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies
ALT text detailspowershell prompt where I'm running a python script in gist. The script installs it dependency (pyfiglet) and prints a banner that reads, "no sploit today"
ALT text detailsThis is the source code to the script run in the previous screenshot. It shows the python dependencies as a preamble comment at the start of the script. Then the script it self imports pyfliglet, initialises the object to use the slant font and then renders the banner by printing the return value from the renderText method. You can see the full text here https://gist.github.com/booyaa/208a265f0f0ecc1ec21008145689ab62#file-how-long-before-pwn-py
What's the best way to write / deploy a local criss-platform webapp. Here's what I want: (1) Web app backend - FastAPI/Python connects to local SQLite database, local voice synth server etc. (2) Static HTML front end interface, used the local API, (3) All of this runs in a Docker container, (4) On the operating system - MacOS & Linux - the user clicks the app, launches the Docker container, starts the server, opens the web app (5) User doesnt need to have Docker installed #linux#python
ALT text detailsFoto de mulher branca de óculos e cabelos longos vestindo camiseta preta com uma das mão sobre um notebook numa mesa e a outra mão junto ao corpo. Apresenta um tutorial.
ALT text detailsFoto de um homem branco de barba e óculos vestindo camiseta preta e crachá da Python Cerrado. Ele gesticula com a mão aberta erguida enquanto apresenta o seu tutorial.
ALT text detailsThe Fowl logo: a cartoon chicken wearing part of the Magic Wormhole logo as a hat, with two blue ethernet plugs extending from behind, evoking the two peers involved in every connection.
ALT text detailsThe Fowl logo: a cartoon chicken wearing part of the Magic Wormhole logo as a hat, with two blue ethernet plugs extending from behind, evoking the two peers involved in every connection.
Incident Report of the recent #PyPI Phishing Campaign
TL,DR: • PyPI was not breached • PyPI users were targeted with phishing emails • A single project saw uploads with malicious code and those releases have been removed
ALT text detailsrotating turquoise volume with holes on a pink background, made from subtracting a rotated cube (shown in white wireframe) from a turquoise cube.
ALT text detailsrotating turquoise volume with holes on a pink background, made from subtracting a rotated cube (shown in white wireframe) from a turquoise cube.
Incident Report of the recent #PyPI Phishing Campaign
TL,DR: • PyPI was not breached • PyPI users were targeted with phishing emails • A single project saw uploads with malicious code and those releases have been removed
ALT text detailsFoto de mulher de pele parda e cabelos pretos, vestindo blusa de mangas longas preta, com um crachá da Python Cerrado pendurado no pescoço. Segura um microfone e gesticula com a mão aberta, enquanto apresenta um tutorial. O fundo é um quadro branco no qual é possível observar o reflexo da apresentadora.
ALT text detailsSlide do tutorial sobre análise de funil de conversão, com o título "Tipos de análise de dados" no canto superior esquerdo. Apresenta quatro caixas dispostas horizontalmente com textos sobre e dentro de cada caixa. Os textos são, para as caixas da esquerda para a direita, sobre e dentro da caixa, respectivamente: "descritiva" e "o que aconteceu?", "diagnóstica" e "porque aconteceu?", "preditiva" e "o que pode acontecer?", e "prescritiva" e "o que fazer?".
Is it really true that there's no way to get the current value from #Python's itertools.count()? All I can do is advance it and get the next value? The repr() shows the value, but I can't get an int?
ALT text detailsAnimation showing an interactive sketch with a prism that becomes a truncated pyramid, number of sides also varies, and under it the unfolded sides connected, with paper tabs for glue.
ALT text detailsAnimation showing an interactive sketch with a prism that becomes a truncated pyramid, number of sides also varies, and under it the unfolded sides connected, with paper tabs for glue.
Starts from a corpus of seed files (generated by fusi)l. It runs each file and parses the JIT debug output to record micro ops (UOPs) and edges between them.
Then it applies mutations to these files and when a mutation results in a new UOP or edge, it adds the mutated file to the corpus.
All the while, it monitors the execution of these files for crashes.
One obvious thing from fuzzing the CPython JIT with the lafleur fuzzer is that finding crashes is much lower probability than fuzzing CPython with fusil.
Whenever fusil found a crash, it would find hits for it again and again pretty quickly.
With lafleur, we only got 3 hits (2 issues) in thousands of fuzzing hours.
I'm throwing more compute at it, but maybe we'll need to improve the core ideas to get better results.
Hot take: #python should be put in a 5 year feature freeze until they figure out their packaging. Although it's so deeply fucked up that I don't know if there's any hope of saving it.
Ahem. By which I mean to say I usually do some #python#programming#streaming on that channel, using #emacs . One of these days I will remember how actually doing self-promotion works
Why does installing a new #python project always, *always* feel like i'm being hazed?😭
ALT text detailsscreenshot: "Ah, now we’re hitting the classic magic.h missing error — this one’s a rite of passage when dealing with libmagic-based Python packages. The file module you're trying to install wraps around the native libmagic C library, and it needs the development headers to compile properly."
ALT text detailsA screenshot showing thumbnails of a 10 page PDF document and a detail of page 10 with the number 10 big on the corner and lots of yellowish crescent shapes scattered on a purple background. The page thumbnails all show different colors.
ALT text detailsA screenshot showing thumbnails of a 10 page PDF document and a detail of page 10 with the number 10 big on the corner and lots of yellowish crescent shapes scattered on a purple background. The page thumbnails all show different colors.
I’m honored to be giving a keynote at their first charity event. 🎤 at a very special event supporting the newly formed @pyconasia (PAO) created by leaders @iqbalabd, @kwonhan, Manabu Terada and Freilla Mae Espinola. 🎟️ Support their mission by joining the online event on July 26. Tickets: €7 → https://events.pythonasia.org/charity-talks-h1-2025/
#JeRecrute un•e ingénieur•e data/backend #Python / #PostgreSQL pour Ecobalyse, la startup d’État qui calcule combien coûtent à la planète les mer^Wtrucs qu'on achète
PS: ça va faire super malpoli/yolo mais je me casse en vacances ce soir et j'ai vraiment besoin d'un gros break donc je laisse mes adorables collègues dont @vjousse vous filer toutes les infos complémentaires dont vous auriez besoin (désolé copain cœur sur tes mentions)
I love that @readeck has a well documented API. It means that someone like me with rudimentary enough Python skills can do stuff. By stuff I mean send my Mastodon bookmarks to a Readeck collection and also work with them in bulk (operations like marking things as read and archiving)
All 3 marked as "good first issue". They've clear signs of being created by or with help from AI, like tentative code ("# do this in case... ") and removing docstrings.
Merged one and gave feedback on 2, including tips on how to get AI to fix their issues.
I might get unfollows for this, but I welcome AI generated code as long as it's good enough. In fact, AI made this project viable.
--<-- I’m a little salty that neither Anthropic nor Google reached out to me before they released their terminal-based AI coding agents.
You see until recently I was the CEO of Textualize, a startup promoting rich applications for the terminal. Textualize didn’t make it as a company, but I take heart that we built something amazing. There is now a thriving community of folk building TUIs that I am still a part of.
So you will understand why when I finally got round to checking out Claude code and Gemini CLI, I was more interested in the terminal interface than the AI magic it was performing. And I was not impressed. Both projects suffer from jank and other glitches inherent to terminals that Textualize solved years ago.
....
I’m currently taking a year’s sabbatical. When Textualize wrapped up I genuinely thought I was sick of coding, and I would never gain be able to find joy in building things. I’m happy to be wrong about that. I still enjoy coding, and Toad feels like the perfect hobby project for my very particular set of skills. Something I can build while continuing to focus on my physical and mental health (running a startup is taxing).
What I have in mind is a universal front-end for AI in the terminal. This includes both AI chat-bots and agentic coding. The architecture I alluded to earlier is that the front-end built with Python and Textual connects to a back-end subprocess. The back-end handles the interactions with the LLM and performs any agentic coding, while the front-end provides the user interface. The two sides communicate with each other by sending and receiving JSON over stdout and stdin.
...
Toad isn’t quite ready for a public release. It remains a tadpole for now, incubating in a private repository. But you know I’m all about FOSS, and when its ready for a public beta I will release Toad under an Open Source license.
With a bit of luck, this sabbatical needn’t eat in to my retirement fund too much. If it goes well, it may even become my full-time gig.
I will shortly invite a few tech friends and collaborators to the project. These things can’t be the work of a single individual and I am going to need feedback as I work. If you would like to be a part of that, then feel free to reach out. But please note, I would like to prioritize folk in the Open Source community who have potentially related projects.
For everyone else, I will be posting updates regularly here and on my socials (link at the bottom of the page). Expect screenshots, videos, and long form articles. Please be patient—you will be agentic toading before too long.
#JeRecrute un•e ingénieur•e data/backend #Python / #PostgreSQL pour Ecobalyse, la startup d’État qui calcule combien coûtent à la planète les mer^Wtrucs qu'on achète
PS: ça va faire super malpoli/yolo mais je me casse en vacances ce soir et j'ai vraiment besoin d'un gros break donc je laisse mes adorables collègues dont @vjousse vous filer toutes les infos complémentaires dont vous auriez besoin (désolé copain cœur sur tes mentions)
--<-- I’m a little salty that neither Anthropic nor Google reached out to me before they released their terminal-based AI coding agents.
You see until recently I was the CEO of Textualize, a startup promoting rich applications for the terminal. Textualize didn’t make it as a company, but I take heart that we built something amazing. There is now a thriving community of folk building TUIs that I am still a part of.
So you will understand why when I finally got round to checking out Claude code and Gemini CLI, I was more interested in the terminal interface than the AI magic it was performing. And I was not impressed. Both projects suffer from jank and other glitches inherent to terminals that Textualize solved years ago.
....
I’m currently taking a year’s sabbatical. When Textualize wrapped up I genuinely thought I was sick of coding, and I would never gain be able to find joy in building things. I’m happy to be wrong about that. I still enjoy coding, and Toad feels like the perfect hobby project for my very particular set of skills. Something I can build while continuing to focus on my physical and mental health (running a startup is taxing).
What I have in mind is a universal front-end for AI in the terminal. This includes both AI chat-bots and agentic coding. The architecture I alluded to earlier is that the front-end built with Python and Textual connects to a back-end subprocess. The back-end handles the interactions with the LLM and performs any agentic coding, while the front-end provides the user interface. The two sides communicate with each other by sending and receiving JSON over stdout and stdin.
...
Toad isn’t quite ready for a public release. It remains a tadpole for now, incubating in a private repository. But you know I’m all about FOSS, and when its ready for a public beta I will release Toad under an Open Source license.
With a bit of luck, this sabbatical needn’t eat in to my retirement fund too much. If it goes well, it may even become my full-time gig.
I will shortly invite a few tech friends and collaborators to the project. These things can’t be the work of a single individual and I am going to need feedback as I work. If you would like to be a part of that, then feel free to reach out. But please note, I would like to prioritize folk in the Open Source community who have potentially related projects.
For everyone else, I will be posting updates regularly here and on my socials (link at the bottom of the page). Expect screenshots, videos, and long form articles. Please be patient—you will be agentic toading before too long.
Is there a way to get `ruff check` *not* to treat code guarded by `sys.platform` as unreachable if the check would fail on the platform running the lint?
I am looking at adding `ruff check` to a project in the wake of a `NameError` that slipped past, but it seems to be incapable of catching this problem if it is guarded behind a platform check.
(if you reply to this to tell me to run `ruff check` on both platforms, you will be ZOTted, I mean the question the way I asked it)
Is there a way to get `ruff check` *not* to treat code guarded by `sys.platform` as unreachable if the check would fail on the platform running the lint?
I am looking at adding `ruff check` to a project in the wake of a `NameError` that slipped past, but it seems to be incapable of catching this problem if it is guarded behind a platform check.
(if you reply to this to tell me to run `ruff check` on both platforms, you will be ZOTted, I mean the question the way I asked it)
Busy day, good day: the new CPython fuzzer lafleur found its first 2 crashes this morning!
Happiness only marred by the bad job I did reducing the testcases and making the reports reproducible. Thanks Brandt Bucher and and Ken Jin for the patience! Next bug reports will be more polished and reliable.
Also, we got 3 new PRs for the fuzzer but I didn't have time to review them, will have to leave that for tomorrow.
@glyph@mitsuhiko I can tell you that in #python on Libera.chat, we have had very mixed results. AFAIK, not one of those users has become a continuing part of that community, but the things that lead most reliably to these users getting the help that they want are:
1) Avoid criticism of the chatbots. No room for persuasion generally, and flamewar is likely.
2) Much more patience is required. Choose your questions carefully, "too many" questions will lead to withdrawal. The extreme case is a user who is consulting the chatbot and the community simultaneously.
It's impossible to draw general inferences from an environment as pathological as IRC, but I would say these two points apply equally well to interpersonal interactions I have had in the local user group.
The overall impression I am left with is that the tools themselves disincentivize participation in a community, and incentivize talking to other humans only for swapping tips about tools, or as a way to get someone to "just" produce source code that fixes the tool's errors.
Over the past few days in the small moments when I've been able to work I've been experimenting with porting Hasher-Matcher-Actioner from Flask to FastAPI, and I now have it mostly working with an existing database.
It's been interesting working with python because I don't work with it much, but FastAPI still feels very much like Express in terms of how things are written — lots of building your own framework essentially, instead of "here's the given path", which can be daunting.
I still need to work out Alembic and migrations, but I have it working against an existing database with the same schema. Also need to figure out building CLI tools that accompany the server, where flask has that built-in
Python jumped 10%+ on the TIOBE index this month 🤩🐍📈 thanks to the entire #Python community—maintainers, educators, contributors, and users—for helping make Python what it is today!
ALT text detailsGraph titled "TIOBE Programming Community Index" and subtitled "Source: www.tiobe.com", showing difference colored lines rising and falling. The left hand column shows "Ratings %" and the bottom row shows years, 2002 through 2024. Underneath, there is a line listing different programming languages, including Python. Underneath, there is a small chart showing Python as #1 with a rating of 26.98% and an increase of 10.85%.
I’m honored to be giving a keynote at their first charity event. 🎤 at a very special event supporting the newly formed @pyconasia (PAO) created by leaders @iqbalabd, @kwonhan, Manabu Terada and Freilla Mae Espinola. 🎟️ Support their mission by joining the online event on July 26. Tickets: €7 → https://events.pythonasia.org/charity-talks-h1-2025/
I’m honored to be giving a keynote at their first charity event. 🎤 at a very special event supporting the newly formed @pyconasia (PAO) created by leaders @iqbalabd, @kwonhan, Manabu Terada and Freilla Mae Espinola. 🎟️ Support their mission by joining the online event on July 26. Tickets: €7 → https://events.pythonasia.org/charity-talks-h1-2025/
It's a feedback driven fuzzer (using JIT debug output) with corpus prioritization and JIT-targeted AST-based mutations. Calling it "evolutionary" may be a stretch, but sounds good.
It's also a fuzzer that so far hasn't found any crashes or bugs. Still working on that ;)
If you want to understand how it works, there is a good amount of docs.
Ótimo encontrar os amigos @ramgarlic, @osantana e @villares para curtir pizza e Vini, aprender sobre ferromodelismo, discutir história e falar sobre #python. ¡Gracias a la vida!
ALT text detailsQuatro homens estão sentados em uma mesa de pizzaria com toalha xadrez vermelha e branca, sorrindo e brindando com taças de vinho tinto e garrafas de cerveja. Há três pizzas grandes sobre a mesa, cada uma com coberturas variadas. Ao fundo, é possível ver outras mesas ocupadas, pôsteres decorativos nas paredes azul-claro e um ambiente descontraído. À esquerda está Érico Andrei, segurando uma taça de vinho e olhando para a câmera. O homem ao lado dele, Luciano Ramalho,usa boné azul e faz um gesto com a mão enquanto sorri. À direita, dois outros homens, Osvaldo Santana e Alexandre Villares, também sorriem, um deles vestindo uma camiseta preta com estampa rosa e outro com casaco marrom e barba longa. A atmosfera da imagem é de confraternização entre amigos em um restaurante acolhedor.
I spent a lot of time creating a cheat sheet and article on f-strings, so I was kicking myself after a few of them that I should have known. There were definitely a couple surprise Python features for me though!
I spent a lot of time creating a cheat sheet and article on f-strings, so I was kicking myself after a few of them that I should have known. There were definitely a couple surprise Python features for me though!
Ótimo encontrar os amigos @ramgarlic, @osantana e @villares para curtir pizza e Vini, aprender sobre ferromodelismo, discutir história e falar sobre #python. ¡Gracias a la vida!
ALT text detailsQuatro homens estão sentados em uma mesa de pizzaria com toalha xadrez vermelha e branca, sorrindo e brindando com taças de vinho tinto e garrafas de cerveja. Há três pizzas grandes sobre a mesa, cada uma com coberturas variadas. Ao fundo, é possível ver outras mesas ocupadas, pôsteres decorativos nas paredes azul-claro e um ambiente descontraído. À esquerda está Érico Andrei, segurando uma taça de vinho e olhando para a câmera. O homem ao lado dele, Luciano Ramalho,usa boné azul e faz um gesto com a mão enquanto sorri. À direita, dois outros homens, Osvaldo Santana e Alexandre Villares, também sorriem, um deles vestindo uma camiseta preta com estampa rosa e outro com casaco marrom e barba longa. A atmosfera da imagem é de confraternização entre amigos em um restaurante acolhedor.
I'm sure someone has already invented a #python wiper that gets rid of all stray python installations, venvs and package managers. After two versions of poetry, a conda episode (better say: accident), a switch to uv, inconsistent use of pip, pipx and python installs via #homebrew, and installs via miniconda that #julialang and #quarto sneaked up on me, there is absolutely no way to make any path to anything work in any virtual environment and I need a new laptop. So what's the python wiper called?
Oh god I need to make an #introduction apparently 26 yo, bi ace transmasc NB, from Ohio but living in Berlin. I've got #ADHD, #neurodivergent#queer and proud.
My hobbies: - I fucking love to #conlang and it's also how I met my spouse. - I've started learning #embroidery and am hoping to get into #threadpainting - I enjoy #gaming, especially when it's an #indiegame. My favorites are narrative-driven games like #discoelysium or simulation games like #rimworld and #sims. I'm also interested in #gamedev, but I haven't dipped my toes yet.
Studied #linguistics in undergrad and switched to #NLP for grad school. I used to want to continue in academia but realized I'd rather make more money and have better work-life balance not doing that. Now I work in #datascience coding in #python for a tech startup and am generally pretty happy with that setup. My heart still calls out for #semantics and #pragmatics though.
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
Hey Leute, ich brauch eure Ideen! Mein Jüngster (13) probiert gerade #Programmieren aus, einfach um zu sehen ob das was für ihn ist. Am liebsten will er natürlich #Spiele programmieren. Ich habe ihm Coddy gezeigt, weil ich weiß dass das Spaß macht, und er hat sich spontan für #Python entschieden. Coddy macht ihn Spaß, Khan Academy ist eher etwas trocken, mehr fällt mir zu Python gerade nicht ein!
I got less traffic for my Python article than I expected, so I added "Python" to the title, and inserted some section headers to break things up a bit, and make the flow of my thinking a bit clearer.
ALT text detailsTwo Python snippets, showing before and after using the @re_sub decorator to simplify using the re.sub function. The first snippet shows the standard usage, creating a function that takes an re.Match object, and returns a string with the content that should replace the content matched by the regular expression. The first snippet also contains a function that calls re.sub with its 3 required arguments: a str containing the regular expression, the function to call for each match, and the string to be processed with the regular expression and the transforming function. The second snippet shows how the re_sub decorator encapsulates all this logic, so that only the regular expression and a simplified converter (using only Python strings instead of re.Match objects) need to be defined.
I move 1 along the x-axis, then rotate by an angle theta, I move 1/phi, rotate by theta, I move 1/phi², rotate by theta etc etc. Made with #python#numpy#matplotlib
I move 1 along the x-axis, then rotate by an angle theta, I move 1/phi, rotate by theta, I move 1/phi², rotate by theta etc etc. Made with #python#numpy#matplotlib
I got less traffic for my Python article than I expected, so I added "Python" to the title, and inserted some section headers to break things up a bit, and make the flow of my thinking a bit clearer.
ALT text detailsTwo Python snippets, showing before and after using the @re_sub decorator to simplify using the re.sub function. The first snippet shows the standard usage, creating a function that takes an re.Match object, and returns a string with the content that should replace the content matched by the regular expression. The first snippet also contains a function that calls re.sub with its 3 required arguments: a str containing the regular expression, the function to call for each match, and the string to be processed with the regular expression and the transforming function. The second snippet shows how the re_sub decorator encapsulates all this logic, so that only the regular expression and a simplified converter (using only Python strings instead of re.Match objects) need to be defined.
I have also progressed a little and have finally migrated all my Google Notes (a.k.a. "Google Keep") to an open source solution and YES including the images and YES preserving the created-dates. Tadaa! #python
So done is: ✅ Drive -> Nextcloud ✅ Notes -> Nextcloud
Next up: 🚧 Meet -> Jitsi 🚧 Mail -> Managed Mailcow
Still a bit lost here: ❓ Photos -> [tipps welcome]
Hi! I’m Wan Ching. I started coding in 2012 with #JavaScript, #Python, and #jQuery. Over the years, I’ve dived into #React, #TypeScript, and now #LLMs. They’re #ToolsNotMagic, and can never replace thinking. 💡 Fundamentals still matter. I’m always excited to learn and grow with every new tool.
I understand it is customary to #Introduction myself.
I'm trying to convert some python that I wrote many years ago to #PHP. The code takes a word (string) and converts it into IPA(International Phonetic Alphabet) based on an alphabet character=>IPA dictionary (array).
In Python every string is an array, but in PHP it's not.
How do I iterate over a string not just seeking for individual characters but also for groups of characters? For instance the word 'light' I'd want to seek for 'igh', which would be converted to 'aɪ'
Doing a little iterative code development in micropython on an emulated m68k mac... I might not be so happy with the loading time if a real floppy was involved, but in an emulator it's heckin' snappy.
Clearly I need to tackle the issue that you can't REALLY draw to the same window as the terminal....
ALT text detailsA black & white mac desktop runs micropython. first, the program is run. second, it's edited to change the parameters. then, it's run again. the program draws a moire pattern of lines.
Doing a little iterative code development in micropython on an emulated m68k mac... I might not be so happy with the loading time if a real floppy was involved, but in an emulator it's heckin' snappy.
Clearly I need to tackle the issue that you can't REALLY draw to the same window as the terminal....
ALT text detailsA black & white mac desktop runs micropython. first, the program is run. second, it's edited to change the parameters. then, it's run again. the program draws a moire pattern of lines.
I've been chasing out of memory issues in #Python for literally years at this point. Every 2-3 weeks I've needed to restart my app (lest I leave it to crash from running out of memory).
I've tried every trick in the book to find the "memory leak", and while I've made a few improvements, nothing has stopped the continual climb of memory use.
That is until a month ago. I gave jemalloc (an alternative memory allocator) a try.
The result? 30+ days of uptime with 11GB of RAM to spare 😎
I am currently looking for remote full time or contract work in #devops or backend #development. I'm US based but comfortable with international companies. I am proficient with #python, #linux, and a heap of other tech.
If you'd like more details or would like to connect, my resume and contact info is on my website: https://hobbsc.sdf-us.org
I am currently looking for remote full time or contract work in #devops or backend #development. I'm US based but comfortable with international companies. I am proficient with #python, #linux, and a heap of other tech.
If you'd like more details or would like to connect, my resume and contact info is on my website: https://hobbsc.sdf-us.org
Are there any folks with vintage Mac programming experience who'd like to collaborate on figuring out what's next with Micropython on Mac?
I think that might be: What's the minimal set of APIs to do a fun graphical demo.
Pointers to "how to"-ish documentation in Pascal and C would be great as well, I have failed at finding this kind of stuff. (I do have Inside Macintosh but it is not a great tutorial)
ALT text detailsIt's a 2x1m table with two remote controlled Mario Karts built with LEGO parts. Colors on the table make the karts spin or get speed boosts. A moving wall obstructs the course randomly.
ALT text detailsIt's a 2x1m table with two remote controlled Mario Karts built with LEGO parts. Colors on the table make the karts spin or get speed boosts. A moving wall obstructs the course randomly.
Are there any folks with vintage Mac programming experience who'd like to collaborate on figuring out what's next with Micropython on Mac?
I think that might be: What's the minimal set of APIs to do a fun graphical demo.
Pointers to "how to"-ish documentation in Pascal and C would be great as well, I have failed at finding this kind of stuff. (I do have Inside Macintosh but it is not a great tutorial)
Whee! Now we can import files from the filesystem, as well as reading and writing files. Still haven't wrapped my head around how folders work, still can't enumerate files ..
as usual, work pushed to my micropython fork on github (which is called circuitpython, because you can't have two different forks of the "same" original project, argh).
ALT text detailsCode:
append_images = (Image.new("RGB", (1, 1), color) for color in colors)
im_reloaded = roundtrip(im, save_all=True, append_images=append_images)
for im_expected in append_images:
im_reloaded.seek(im_reloaded.tell() + 1)
assert_image_similar(im_reloaded, im_expected, 1)
And then Codecov warns these last two lines weren't covered.
ALT text detailsCode:
append_images = (Image.new("RGB", (1, 1), color) for color in colors)
im_reloaded = roundtrip(im, save_all=True, append_images=append_images)
for im_expected in append_images:
im_reloaded.seek(im_reloaded.tell() + 1)
assert_image_similar(im_reloaded, im_expected, 1)
And then Codecov warns these last two lines weren't covered.
ALT text detailsCode:
append_images = (Image.new("RGB", (1, 1), color) for color in colors)
im_reloaded = roundtrip(im, save_all=True, append_images=append_images)
for im_expected in append_images:
im_reloaded.seek(im_reloaded.tell() + 1)
assert_image_similar(im_reloaded, im_expected, 1)
And then Codecov warns these last two lines weren't covered.
@glyph@zzzeek Yes! I have now several times wished for an "opinionated" guide to packaging ... _maybe_ refer to some major options, but mostly just say "do 1, then 2".
Two flavours: greenfield, and "I have a setup.py but heard some toml file is better, now what?"
(p.s. I say this as someone who releases several packages and started with Python 1.5-ish, so I can't imagine how a less-experienced Python person navigates this) #python
I'm writing my book on Python performance using Quarto (https://quarto.org/) and it's really great technical writing environment out of the box.
But beyond that, it's also extremely customizable.
Each document (an article or chapter) can be a Jupyter notebook, and I have written custom Jupyter magics that e.g. benchmark different functions and generate markdown tables of the results.
I'm writing my book on Python performance using Quarto (https://quarto.org/) and it's really great technical writing environment out of the box.
But beyond that, it's also extremely customizable.
Each document (an article or chapter) can be a Jupyter notebook, and I have written custom Jupyter magics that e.g. benchmark different functions and generate markdown tables of the results.
Keynote announcement for PyCon Finland 2025: "Muuttolintujen Kevät - Automatic Bird Sound Classifier" by Patrik Lauha from the University of Helsinki! ☀️ 🦉 🎤
Discover how an innovative convolutional neural network, trained in Python with TensorFlow, identifies vocalisations from 263 Finnish bird species, using over 14 million recordings containing 37 million bird observations collected by citizen scientists.
Keynote announcement for PyCon Finland 2025: "Muuttolintujen Kevät - Automatic Bird Sound Classifier" by Patrik Lauha from the University of Helsinki! ☀️ 🦉 🎤
Discover how an innovative convolutional neural network, trained in Python with TensorFlow, identifies vocalisations from 263 Finnish bird species, using over 14 million recordings containing 37 million bird observations collected by citizen scientists.
ALT text detailsA grid that shows the tracks I have run using a sport watch. They are categorized by distance and location and if the track matches, they are grouped!
I'm probably a little overexcited, but I've recently learned the basics of #Python and it feels like being a wizard. You write the programmer's equivalent of "abracadabra" and voila! a stunning graph visualising your research data appears.
I'm probably a little overexcited, but I've recently learned the basics of #Python and it feels like being a wizard. You write the programmer's equivalent of "abracadabra" and voila! a stunning graph visualising your research data appears.
Lovely. I managed to install my fledgling #python package and I can use it! Except that only in the vscode terminal. If I open a regular terminal it's not there. Why? I suspect because the vscode terminal is using python 3.10.16 and the regular terminal uses python 3.12.4. Why? Who the fuck knows. Both are using the base conda environment which I assumed was there to ensure a consistent environment.
Obligatory xkcd
ALT text detailsxkcd comic with a complicated flowchart trying to understand which python executable one is using at any time.
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
I have a #Python file that does not have a *.py extension. I would like to tell my #NeoVim that it is a Python script, so that it can do proper syntax highlighting.
I know that I achieve this by adding some special comments to the file, that are interpreted by NeoVim. But I don't remember how to do it and how the feature is called.
All the involved terms are bad for asking Google. Can somebody give me a hint please?
🥧 Free-threaded Python is officially supported! (PEP 779)
🥧 Subinterpreters in the stdlib! (PEP 734)
Do you maintain a Python package? Please test 3.14.
If you find a bug now, we can fix it before October, which helps everyone. And you might find some places in your code to update as well, which helps you.
Are you in Boston and want to hang with #Python people? Boston Python's project & collaboration night is June 24th. It's an informal gathering to talk together, work together, learn from each other, network, whatever. Tell your friends :)
GitHub Actions can come in handy for lots of things, and Python development is one of them! You can set up a CI pipeline to test against different versions of Python and make your app more reliable.
This guide is good for Fedora, CentOS, and RHEL. 👌
Just watched this rather awesome talk by @glyph at #NBPY
It's been a while since I wrote any #python code, but this is as much a talk about communities, delivering on the promises we make to the people we invite into them, and recognizing new ways to adapt to our changing technology landscape.
Just watched this rather awesome talk by @glyph at #NBPY
It's been a while since I wrote any #python code, but this is as much a talk about communities, delivering on the promises we make to the people we invite into them, and recognizing new ways to adapt to our changing technology landscape.
Oh my. I'm reading some #Python script and the author has used the hash() built-in function to hash strings. This function doesn't look at the data of the string! (Traditionally it returned the object's address in RAM! IIRC)
✨ Interactive input() support (useful for teaching Python) 🔄 New REPL options 🎯 Better kernel status and logs 🧹 Easier browser data management ⚡️ Improved multi-tab support and storage isolation
✨ Interactive input() support (useful for teaching Python) 🔄 New REPL options 🎯 Better kernel status and logs 🧹 Easier browser data management ⚡️ Improved multi-tab support and storage isolation
Just published the blog posts for the #Python Language Summit 2025. It's quite fun to cover this important event and contribute to the Python community in this unique way :)
Please take a look if you weren't able to attend the Language Summit in person:
Just published the blog posts for the #Python Language Summit 2025. It's quite fun to cover this important event and contribute to the Python community in this unique way :)
Please take a look if you weren't able to attend the Language Summit in person:
I upgraded my lenovo #T490 from #NixOS 24.11 to 25.05 within an hour or so.
I've lost "xdu" (custom package doesn't compile anymore), had to manually download a closed source binary once again, had to manually replace "okular" with "kdePackages.okular" and remove "services.locate.localuser".
The upgrade went somewhat fine. Didn't find any issues so far besides the usual Python annoyances (manual re-creation of all venv and so forth).
However, I'm looking forward to switching back to #Debian in a few months. My Debian upgrades didn't require that much time and effort AFAIR and #Python is working in a normal way.
I'm looking for a standard way to develop GTK-based apps on #Linux but haven't figured it out yet. I found the Workbench app but don't understand how to use it.
I also tried prototyping an idea using #Python and the #GTK library with Claude, but still haven't found a solid approach to build the foundation.
Another side-effect of this work is that now I can take this design back to the #python side, and remove the django parts of it and make it usable for other frameworks, or even the desktop applications.
I'm proud of my spouse @leonardr for his decades of service to the world. The #Python Software Foundation recently recognized some of that service by naming him a @ThePSF Fellow, and giving him the Community Service Award.
#PyOhio is always a Free to attend #Python#Conference. This year it will take place on Saturday & Sunday July 26 & 27, 2025 at the Cleveland State University Student Center in Cleveland, Ohio
You can donate to help support this free Python Conference even if you're unable to attend! We've got a lot upcoming, make sure you watch for more info!
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
This article is published on a website which is powered by BDServer. And I'm trying to make this website support ActivityPub, so you could for example, subscribe to me from your Mastodon account. Yet it is easier said than done.
If you have any experience with ActivityPub, web-development or Python, please consider helping me. We have BDServ...
#introduction: Benjamin Winkel (updated after I moved to a new instance)
Hi all, I'm a professional radio astronomer, working full-time in spectrum management (protecting radio astronomy frequencies from cell-phones, Starlink etc.). I like to write software with #Python. In my free time, I enjoy astro photography from my backyard.
My most important research projects are surveys of the neutral atomic hydrogen (using the famous 21-cm spectral line). #EBHIS#HI4PI
#introduction: Benjamin Winkel (updated after I moved to a new instance)
Hi all, I'm a professional radio astronomer, working full-time in spectrum management (protecting radio astronomy frequencies from cell-phones, Starlink etc.). I like to write software with #Python. In my free time, I enjoy astro photography from my backyard.
My most important research projects are surveys of the neutral atomic hydrogen (using the famous 21-cm spectral line). #EBHIS#HI4PI
Python is doing my head in. I have a csv that opens in one directory, but not another one (further down). Is there are a character limit on how long a file path can be? #python#help
The results point to interesting future ideas, including expanding fuzzing to new environments like subinterpreters, using more tools like Thread Sanitizer, and developing more advanced fuzzing techniques.
One finding I really like is the bug discovery pattern.
There wasn't a steady stream of bugs, but spikes of findings: 1st, a huge number of crashes as I started testing a CPython that hadn't been fuzzed by fusil in a decade.
Later, a new wave of issues tied to the addition of new features to the fuzzer, like support for "weird classes" and typing objects.
So periodic campaigns may have better cost-benefit than continuous fuzzing.
The credit for fusil's effective design goes all to Victor Stinner (@vstinner), who created it nearly two decades ago. It was responsible for finding release blockers way back in 2008. I just contributed a little to revive and enhance it.
Some enhancements included running generated code in threads and adopting new "interesting" objects and values as inputs, helping to discover more crashes.
All this was only possible due to the great response from the Python community.
Thanks to the developers efforts to triage, diagnose, and fix the problems, the campaign became a collaborative effort to improve Python.
The impact was considerable, mobilizing Core Devs and contributors to create 98 PRs to fix these bugs. The average time to fix an issue was about 20 days, with a median of just five days.
Happy to share the results of a fuzzing campaign targeting CPython that ran from Oct 2024 to May 2025. Using the fusil fuzzer, the goal was to find crashes and improve CPython's robustness.
I really like the results we got: the effort uncovered 52 unique crash-related issues. These reports approached 30% of all "type-crash" issues filed during that period. One of the crashes was classified as a Release Blocker, that was a nice result! :)
"Look, I don't think there's anything wrong with programming in #python or #javascript, but you should probably switch to #haskell when you hit like 3 or 4 months of experience
"Look, I don't think there's anything wrong with programming in #python or #javascript, but you should probably switch to #haskell when you hit like 3 or 4 months of experience
Thanks to the work of Python Release Managers and all the Developers-in-Residence we have a coordinated #Python#security release of all versions for 5 CVEs all in one day (1 critical, 3 high, 1 medium)
Calling all Python people! 👋 The PyBay 2025 Call for Proposals is closing in less than ONE WEEK! Share your knowledge with the Bay Area Python community. Submit your talk by SUNDAY, June 8th: https://sessionize.com/pybay2025#Python#PyBay
I'm proud of my spouse @leonardr for his decades of service to the world. The #Python Software Foundation recently recognized some of that service by naming him a @ThePSF Fellow, and giving him the Community Service Award.
Calling all Python people! 👋 The PyBay 2025 Call for Proposals is closing in less than ONE WEEK! Share your knowledge with the Bay Area Python community. Submit your talk by SUNDAY, June 8th: https://sessionize.com/pybay2025#Python#PyBay
This probably doesn't work on anyone's computer but my own but it's still probably academically interesting to other #Emacs#Python users to see how I developed a naming convention into a system for not having to constantly waste time by e.g. writing a new manual direnv for every new git repo I clone https://gist.github.com/glyph/0352baad69b931ed70554d6be4f8e920
I know, I know, I'm going to need to switch to a proper LSP integration at some point (among other reasons, the owner of this repo apparently hasn't even logged into github in like 3 years, it seems plausible that it will never be updated again) but I am still excited that I got #Emacs to stop gaslighting me about my #Python code by finally figuring out what was causing this extremely confusing behavior https://github.com/tkf/emacs-jedi/issues/376
Me when I began to implement a new cool feature in a #FOSS tool:
"How hard can it be?"
Me 2 months later after rewriting half of the file handler logic, dealing with half-baked or non-existing docs currently implementing a thread management class because the program never needed to even be able to stop a child process before I came around (still not knowing if the PR will even be accepted):
Me when I began to implement a new cool feature in a #FOSS tool:
"How hard can it be?"
Me 2 months later after rewriting half of the file handler logic, dealing with half-baked or non-existing docs currently implementing a thread management class because the program never needed to even be able to stop a child process before I came around (still not knowing if the PR will even be accepted):
ALT text detailsAntonio on stage, taking a selfie of himself and the audience, at the same time showing his webcam image on the screen along with a processed-outline version, running at 60fps with SPy.
ALT text detailsAntonio on stage, taking a selfie of himself and the audience, at the same time showing his webcam image on the screen along with a processed-outline version, running at 60fps with SPy.
Recently I find myself frequently reflecting on the fact that we tried to split up https://twisted.org/ too early (before #Python's packaging toolchain was sophisticated enough to support it) and in the wrong way. We thought everyone would want a-la-carte protocol implementations, so you'd have Twisted "core" which had all the general utilities and the reactor (i.e.: event loop), and then a bunch of add-on packages like Twisted Web (HTTP), Twisted Names (DNS), Twisted Words ("Chat", IRC/XMPP)
Watching @hynek‘s #pyconus talk/rant on domain design on the way to the next #Python event. Which has awesome readable slides you can totally watch on phone on a plane/train, so nothing can stop you from feeling guilty about your current production design choices. I can highly recommend it, especially if you’re a fan of Pydantic.
ALT text detailsiPad mini showing hynek‘s PyConUS talk with a qrcode for slides and a lot of links.
Watching @hynek‘s #pyconus talk/rant on domain design on the way to the next #Python event. Which has awesome readable slides you can totally watch on phone on a plane/train, so nothing can stop you from feeling guilty about your current production design choices. I can highly recommend it, especially if you’re a fan of Pydantic.
ALT text detailsiPad mini showing hynek‘s PyConUS talk with a qrcode for slides and a lot of links.
Certa vez chegando nos EUA o agente de fronteira perguntou qual era o propósito da minha viagem [...]. Falei que ia palestrar em um evento sobre Python e ele disparou:
ALT text detailsA screenshot showing the start of a fusil fuzzing instance targeting the h5py package, showing configuration options and the beginning of the first session. It's white text on a black background, with many lines of diagnostic output.
Abridged text in screenshot:
```
Fusil version 1.5 — GNU GPL v2
https: //github.com/devdanzin/fusil
Some Information about fusil configuration
Adding package: h5py
Known modules (41)
[0] [session 1] Start session
[0][session 1] Module filename: hSpy/_hl/datatype.py
[0][session 1] Test module h5py._hl.datatype
[0][session 1] —— Fuzzing script generation for h5py._hl.datatype complete ——
```
ALT text detailsScreen shot of a directory listing in the Midnight Commander file manager, with white text over a blue background.
The image shows directories that correspond to fusil hits, that is, Python modules for which fusil found a crash. Directories are named after the module where the crash happened, secondary issues (like CPU load) present, and the kind of crash.
For example, the first entry is named "h5py__conv-cpu_load-assertion". There are 18 directories showing, with columns for Size and Modify Time for each entry.
ALT text detailsScreenshot of a GDB debug session. It shows a Python console with the code:
```
import h5py.h5o
h5py.h5o._ObjMetaInfo()._hash()
```
Then a message: Thread 1 "python" received signal SIGSEGV, Segmentation fault.
Under this, a colorful backtrace of the crash is shown.
Certa vez chegando nos EUA o agente de fronteira perguntou qual era o propósito da minha viagem [...]. Falei que ia palestrar em um evento sobre Python e ele disparou:
🥧 Deferred type annotation evaluation! 🥧 T-strings! 🥧 Zstandard! 🥧 Syntax highlighting in the REPL! 🥧 Colour in unittest, argparse, json and calendar CLIs! 🥧 UUID v6-8! 🥧 And much more!
Do you maintain a Python package? Please test 3.14. If you find a bug now, we can fix it before October, which helps everyone. And you might find some places in your code to update as well, which helps you.
Day 1 of #BeethovenSprint kicks off with our stand-up! Many are already gathered at @kitconcept.bsky.social ’s office in Bonn 🇩🇪, and you can join remotely via #Plone’s Discord. Excited for a productive week of collaboration! #oss#cms#react#python @plone
Day 1 of #BeethovenSprint kicks off with our stand-up! Many are already gathered at @kitconcept.bsky.social ’s office in Bonn 🇩🇪, and you can join remotely via #Plone’s Discord. Excited for a productive week of collaboration! #oss#cms#react#python @plone
Stoked for my WebGL tutorial on Thursday morning at @pycon. 3:30h to show all the basic components of 3D graphics? Might be ambitious! But I'll do my best.
Hopefully the conference wi-fi won't betray us 🤞🏻🤞🏻
My son wanted to make Python remember the values that were assigned to a given variable. That is, after a few reassignments of a variable, you'd be able to show its history, containing each value it pointed to at any time.
So we pair-hacked a script together that does just that, recording simple assignments.
It uses `sys.monitoring` to process each line, then gets the variable name and value from the code disassembly (in a silly way).
Looking forward to videos getting posted so I can watch all the talks I ended up missing due to scheduling conflicts/practicing my talk/getting lost/meeting someone in the hallway.
Looking forward to videos getting posted so I can watch all the talks I ended up missing due to scheduling conflicts/practicing my talk/getting lost/meeting someone in the hallway.
It doesn't matter how long you play the open source game, the first bug report from a downstream redistributor for a new project is a somewhat surreal experience. For all its many challenges, the development of free and open source software is an utterly astonishing feat of global collaboration. #python#venvstacks#conda#foss
Looking forward to videos getting posted so I can watch all the talks I ended up missing due to scheduling conflicts/practicing my talk/getting lost/meeting someone in the hallway.
It doesn't matter how long you play the open source game, the first bug report from a downstream redistributor for a new project is a somewhat surreal experience. For all its many challenges, the development of free and open source software is an utterly astonishing feat of global collaboration. #python#venvstacks#conda#foss
The Official Python Documentary has published their teaser trailer at PyCon US 2025, and I'm so honored to be part of the story of Python along with other prominent Python figures.
Check the trailer, and watch the official launch of the documentary at EuroPython later this year.
Thank you #pyconus for having me as a speaker and for everyone who made that happen. I’m always happy to talk about using code for journalism and to hear how others are using #python in other spaces to understand the world.
The Official Python Documentary has published their teaser trailer at PyCon US 2025, and I'm so honored to be part of the story of Python along with other prominent Python figures.
Check the trailer, and watch the official launch of the documentary at EuroPython later this year.
The Official Python Documentary has published their teaser trailer at PyCon US 2025, and I'm so honored to be part of the story of Python along with other prominent Python figures.
Check the trailer, and watch the official launch of the documentary at EuroPython later this year.
The Official Python Documentary has published their teaser trailer at PyCon US 2025, and I'm so honored to be part of the story of Python along with other prominent Python figures.
Check the trailer, and watch the official launch of the documentary at EuroPython later this year.
The Official Python Documentary has published their teaser trailer at PyCon US 2025, and I'm so honored to be part of the story of Python along with other prominent Python figures.
Check the trailer, and watch the official launch of the documentary at EuroPython later this year.
Everyone at #PyConUS ! I created a "Creative Coding with Python" open space for tomorrow at 1 pm in room 315. Come by to talk about #python and #creativecoding. What tools are you using and what are you working on? Let's learn from each other and have fun sharing our work.
Everyone at #PyConUS ! I created a "Creative Coding with Python" open space for tomorrow at 1 pm in room 315. Come by to talk about #python and #creativecoding. What tools are you using and what are you working on? Let's learn from each other and have fun sharing our work.
Interested in attending an open space at #PyConUS? Here are the ones starting at 2:00 PM:
Room 309: Let's talk about the @qt Framework Room 315: Coding with LLMs Room 316: All things MCP! Room 318: @nixos_org + #Python = ♥️ Room 320: Python on GPUs Room 321: Diversity and Inclusion Working Group
Interested in attending an open space at #PyConUS? Here are the ones starting at 2:00 PM:
Room 309: Let's talk about the @qt Framework Room 315: Coding with LLMs Room 316: All things MCP! Room 318: @nixos_org + #Python = ♥️ Room 320: Python on GPUs Room 321: Diversity and Inclusion Working Group
Stop by the PSF booth @pycon US to meet the lovely folks from Python Asia Organization during their Meet & Greet session starting in a few minutes (May 16th, 5-6PM) and chat about the amazing things happening across Asia’s #Python community! #PyConUS
Stop by the PSF booth @pycon US to meet the lovely folks from Python Asia Organization during their Meet & Greet session starting in a few minutes (May 16th, 5-6PM) and chat about the amazing things happening across Asia’s #Python community! #PyConUS
The second one covers a project called "Audiofeeder" which was originally described as "janky as hell", a sentiment I know quite well from my own side projects.
if you're attending Pycon US, into electronics, collecting ICs, organizing your component collection, or how to use OCR to automatically identify components, come join us at an open space on Saturday
if you're attending Pycon US, into electronics, collecting ICs, organizing your component collection, or how to use OCR to automatically identify components, come join us at an open space on Saturday
Stop by the PSF Booth during the @pycon US opening reception for the PSF @pypi Team Meet & Greet session starting in a few minutes (May 15th, 6-7PM) 🥧🫛👁️ Get to know the team, ask questions, and learn how they keep #Python’s package ecosystem running smoothly! #PyConUS
Stop by the PSF Booth during the @pycon US opening reception for the PSF @pypi Team Meet & Greet session starting in a few minutes (May 15th, 6-7PM) 🥧🫛👁️ Get to know the team, ask questions, and learn how they keep #Python’s package ecosystem running smoothly! #PyConUS
Get to know the PSF Developers in Residence at a Meet & Greet session at the PSF Booth @pycon US, starting shortly (May 15th, 5-6PM)! Learn about their work supporting the Python community full-time and ask them all your burning #Python questions 🐍❓#PyConUS@ambv@miketheman@sethmlarson
Get to know the PSF Developers in Residence at a Meet & Greet session at the PSF Booth @pycon US, starting shortly (May 15th, 5-6PM)! Learn about their work supporting the Python community full-time and ask them all your burning #Python questions 🐍❓#PyConUS@ambv@miketheman@sethmlarson
There were layoffs at MS yesterday and 3 #Python core devs from the Faster CPython team were caught in them. If you know of any jobs, please send them their way (they kind of know Python, CPython, and its internals well 😉):
So over to the command line. First, a sudo apt update.
Debian fetches the updates as it should. It says:
"Reading package lists... Done Building dependency tree... Done Reading state information... Done 1 package can be upgraded. Run 'apt list --upgradable' to see it."
Apt list --upgradable mentions: monarx-agent/bookworm 4.2.72-master amd64 [upgradable from: 4.2.62-master]
Okay, so with that done, let's try the three commands YunoHost recommended:
sudo apt install --fix-broken produces the following output:
"Reading package lists... Done Building dependency tree... Done Reading state information... Done 0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded. 1 not fully installed or removed. After this operation, 0 B of additional disk space will be used. Setting up yunohost (12.0.16) ... Regenerating configuration, this might take a while... Traceback (most recent call last): File "/usr/bin/yunohost", line 108, in <module> main() File "/usr/bin/yunohost", line 97, in main yunohost.cli( File "/usr/lib/python3/dist-packages/yunohost/__init__.py", line 41, in cli ret = moulinette.cli( ^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/__init__.py", line 140, in cli ).run(args, output_as=output_as, timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/interfaces/cli.py", line 521, in run ret = self.actionsmap.process(args, timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/actionsmap.py", line 579, in process return func(**arguments) ^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 1755, in app_ssowatconf local_manifest = _get_manifest_of_app(setting_path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 2269, in _get_manifest_of_app manifest = _convert_v1_manifest_to_v2(manifest) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 2397, in _convert_v1_manifest_to_v2 install_questions = manifest["arguments"]["install"] ~~~~~~~~^^^^^^^^^^^^^ KeyError: 'arguments' dpkg: error processing package yunohost (--configure): installed yunohost package post-installation script subprocess returned error exit status 1 Errors were encountered while processing: yunohost E: Sub-process /usr/bin/dpkg returned an error code (1)"
Typing sudo dpkg --configure -a gives us the following:
Setting up yunohost (12.0.16) ... Regenerating configuration, this might take a while... Traceback (most recent call last): File "/usr/bin/yunohost", line 108, in <module> main() File "/usr/bin/yunohost", line 97, in main yunohost.cli( File "/usr/lib/python3/dist-packages/yunohost/__init__.py", line 41, in cli ret = moulinette.cli( ^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/__init__.py", line 140, in cli ).run(args, output_as=output_as, timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/interfaces/cli.py", line 521, in run ret = self.actionsmap.process(args, timeout=timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/moulinette/actionsmap.py", line 579, in process return func(**arguments) ^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 1755, in app_ssowatconf local_manifest = _get_manifest_of_app(setting_path) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 2269, in _get_manifest_of_app manifest = _convert_v1_manifest_to_v2(manifest) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/yunohost/app.py", line 2397, in _convert_v1_manifest_to_v2 install_questions = manifest["arguments"]["install"] ~~~~~~~~^^^^^^^^^^^^^ KeyError: 'arguments' dpkg: error processing package yunohost (--configure): installed yunohost package post-installation script subprocess returned error exit status 1 Errors were encountered while processing: yunohost"
And let's try sudo dpkg --audit:
"The following packages are only half configured, probably due to problems configuring them the first time. The configuration should be retried using dpkg --configure <package> or the configure menu option in dselect: yunohost manageable and configured self-hosting server"
ALT text detailsReading package lists... Done
Building dependency tree... Done
Reading state information... Done
1 package can be upgraded. Run 'apt list --upgradable' to see it.
There were layoffs at MS yesterday and 3 #Python core devs from the Faster CPython team were caught in them. If you know of any jobs, please send them their way (they kind of know Python, CPython, and its internals well 😉):
There were layoffs at MS yesterday and 3 #Python core devs from the Faster CPython team were caught in them. If you know of any jobs, please send them their way (they kind of know Python, CPython, and its internals well 😉):
Hey Mastodon #python friends, does anyone have a drop-in Python web app that can handle/record likes/posts from Mastodon?
If someone has seen one, I have a design that I want to connect to something that has enough IndieWeb / Mastodon smarts that I can wire it up tonight and I thought I'd ask here first.
I do NOT want to run my own Mastodon instance, but I'd love the pingback feature for a one or two page app.
The first #Python conferences I ever went to were the only ones in the world and had about 300 people there. Now I am at #RustWeek with comfortably more than double the size and it's just one of the Rust conferences in Europe.
I started with Rust about 5 years ago, and Rust was already a lot bigger at the time than Python was when I started with it.
Stoked for my WebGL tutorial on Thursday morning at @pycon. 3:30h to show all the basic components of 3D graphics? Might be ambitious! But I'll do my best.
Hopefully the conference wi-fi won't betray us 🤞🏻🤞🏻
Stoked for my WebGL tutorial on Thursday morning at @pycon. 3:30h to show all the basic components of 3D graphics? Might be ambitious! But I'll do my best.
Hopefully the conference wi-fi won't betray us 🤞🏻🤞🏻
There are many times working with #python where I wish the standard library logging included a `TRACE` level by default. Would like to be able to use `INFO` and `DEBUG` in my app more easily, without `DEBUG` getting swamped by other library `DEBUG` loggers. (yes I know I *could* do `logging.getLogger(<library path>).setLevel(...)` I just think it would be easier if there was one extra level of logging) (I also know the logging levels are numbers spaced 10 apart)
I'm writing a little tech report on the effort, and having some data about whether it's considered useful, a nuisance, impactful, low value etc. would make it much more interesting.
Who still writes Python 2.7 code in the year of the Lord 2025? Well, I did, to help a client remove obstacles for upgrading to Python 3.
This was a journey backward in time - in reverse order performing the steps you'd make, to upgrade from Python 2 to Python 3.
How do you create a modern add-on for Plone 6, that is also backward compatible with Plone 4.3 on #Python 2.7 with Archetypes?
In this blog post, I’ll explain the technical details of creating collective.collabora, making it work in many #Plone versions, while also providing continuous integration and 100% test coverage.
Who still writes Python 2.7 code in the year of the Lord 2025? Well, I did, to help a client remove obstacles for upgrading to Python 3.
This was a journey backward in time - in reverse order performing the steps you'd make, to upgrade from Python 2 to Python 3.
How do you create a modern add-on for Plone 6, that is also backward compatible with Plone 4.3 on #Python 2.7 with Archetypes?
In this blog post, I’ll explain the technical details of creating collective.collabora, making it work in many #Plone versions, while also providing continuous integration and 100% test coverage.
A couple of little known bits of Python history: Python's initial local package building client tools (distutils) were born in the late 20th century as a common build backend for Linux distro packaging of Python projects and its initial transitive dependency management tools (setuptools) were born in the early 21st as a plugin management tool for an open source Exchange competitor (OSAF's Chandler project). Evolving from those foundations has been... interesting :) #python
A couple of little known bits of Python history: Python's initial local package building client tools (distutils) were born in the late 20th century as a common build backend for Linux distro packaging of Python projects and its initial transitive dependency management tools (setuptools) were born in the early 21st as a plugin management tool for an open source Exchange competitor (OSAF's Chandler project). Evolving from those foundations has been... interesting :) #python
I've had a Kaggle account for years, but I only used it to pull down datasets to try out with my schemaless ORM-lite #Python package littetable. This past week I discovered you can also host Jupyter notebooks there, so I created several demo notebooks - fun! Here are a few links:
Another tidbit from the report I'm writing about #fusil:
The 52 issues filled correspond roughly to 30% of all the crashes (issues with "type-crash" label) and 2% of all issues (features requests, bugs and invalid issues) reported in the #CPython issue tracker during the six months period covered by the report.
Hits and new issues don't appear at a steady pace. It seems that there are long periods of no or nearly no new issues, followed by rapid finding of new results.
ALT text detailsA bar graph of issues filed by week number, with X axis ranging from week 44 to week 19 and Y axis ranging from zero to 10 issues. The distribution looks bi-modal, with a clump of high numbers of issues per week from week 44 to 50, zero issues for weeks 51 to 11 (except by two issues in week 6), and a smaller clump of medium numbers of issues from week 12 to 16.
so I thought to myself, I should try to use some of these tools at my disposal, I care about my friends and the folks I'm a fan of whomst I follow, but a lot of them are posting about doom more or less nonstop, maybe I should have a look at, like, the #python hashtag to get away from the fascist terrorism and the infosec breach nightmares and the AI slop and so on, maybe I can post some stuff that *others* can riff on if there's something good there
First, there is no such thing as "#ArtificialIntelligence". It's not artificial and it isn't intelligentce. As a pursuit, it is quite real, and what it produces is not intelligence, but detailed models based on huge amounts of related archived data. The important word here is "model". So every time you see output from #Gemini or #ChatGPT, put in your mind that it is a MODEL of a paragraph on a topic, a MODEL of a picture of a sparrow on a pear, a MODEL of #python code. 2/
You know how sometimes a little hobby side-project can get a bit out of hand? An unexpected performance regression on speed.python.org that only showed up on GCC 5 (and 7) led me to set up more rigorous tracking of Python performance when using different compilers. I'm still backfilling data but I think it's pretty awesome to see how much, and how consistently, free-threaded Python performance has improved since 3.13:
🥧 Deferred type annotation evaluation! 🥧 T-strings! 🥧 Zstandard! 🥧 Syntax highlighting in the REPL! 🥧 Colour in unittest, argparse, json and calendar CLIs! 🥧 UUID v6-8! 🥧 And much more!
You know how sometimes a little hobby side-project can get a bit out of hand? An unexpected performance regression on speed.python.org that only showed up on GCC 5 (and 7) led me to set up more rigorous tracking of Python performance when using different compilers. I'm still backfilling data but I think it's pretty awesome to see how much, and how consistently, free-threaded Python performance has improved since 3.13:
🥧 Deferred type annotation evaluation! 🥧 T-strings! 🥧 Zstandard! 🥧 Syntax highlighting in the REPL! 🥧 Colour in unittest, argparse, json and calendar CLIs! 🥧 UUID v6-8! 🥧 And much more!
🥧 Deferred type annotation evaluation! 🥧 T-strings! 🥧 Zstandard! 🥧 Syntax highlighting in the REPL! 🥧 Colour in unittest, argparse, json and calendar CLIs! 🥧 UUID v6-8! 🥧 And much more!
#Fusil works by generating source files with random calls, using interesting arguments, then monitoring their execution and output. It usually finds crashes resulting from the processing of invalid objects and unexpected call patterns.
Features added by me include running generated code in parallel threads, testing class instances in addition to classes and functions, and using new interesting objects/values as inputs.
Fuzzing #CPython with fusil shows it to be a valuable tool for finding and fixing crashers. It started in October 2024 and is ongoing, using free tier cloud instances and personal computers.
@ThePSF Developers-in-Residence Program now has a landing page! 💜
Today we cover the language runtime and security work, maybe there's a gap in the #Python ecosystem your organization would like to see worked on full-time at the PSF? Let's talk!
@ThePSF Developers-in-Residence Program now has a landing page! 💜
Today we cover the language runtime and security work, maybe there's a gap in the #Python ecosystem your organization would like to see worked on full-time at the PSF? Let's talk!
I was attracted to Python back in 1998 because made programming so much simpler, and I recaptured the joy of quick iterative development.
I was attracted to Rust even though I knew it would challenge me, and in return stretch my brain to become better and offer things other languages couldn't offer -- low level control to get performance combined with the memory safety Python gave me.
#Python 3.14.0 beta 1 release day! `main` branch is locked!
It's also the feature freeze, meaning lots of stuff got merged yesterday so it can be released in 3.14 in October 2025 and not 3.15 in October 2026. But first, a couple of reverts for not-so-important things that weren't quite ready and last-minute fixes.
#Python 3.14.0 beta 1 release day! `main` branch is locked!
It's also the feature freeze, meaning lots of stuff got merged yesterday so it can be released in 3.14 in October 2025 and not 3.15 in October 2026. But first, a couple of reverts for not-so-important things that weren't quite ready and last-minute fixes.
I'm looking for my next role as a program manager, team lead, or senior developer.
- 20+ years in open source - 6 years experience in web dev with #Python, #Django, HTML, bootstrap - 7 years experience in C, Linux kernel, embedded systems
My passions lie at the intersection of open source software development and creating welcoming spaces for people to learn and grow.
I'm currently the program manager for a technical internship program. I work remotely with a team of 4 people in New York, Brazil, and Nigeria.
Looking for a fully remote role. I'm open to relocation outside the USA.
I'm looking for my next role as a program manager, team lead, or senior developer.
- 20+ years in open source - 6 years experience in web dev with #Python, #Django, HTML, bootstrap - 7 years experience in C, Linux kernel, embedded systems
My passions lie at the intersection of open source software development and creating welcoming spaces for people to learn and grow.
I'm currently the program manager for a technical internship program. I work remotely with a team of 4 people in New York, Brazil, and Nigeria.
Looking for a fully remote role. I'm open to relocation outside the USA.
I'm looking for my next role as a program manager, team lead, or senior developer.
- 20+ years in open source - 6 years experience in web dev with #Python, #Django, HTML, bootstrap - 7 years experience in C, Linux kernel, embedded systems
My passions lie at the intersection of open source software development and creating welcoming spaces for people to learn and grow.
I'm currently the program manager for a technical internship program. I work remotely with a team of 4 people in New York, Brazil, and Nigeria.
Looking for a fully remote role. I'm open to relocation outside the USA.
ALT text detailsA chart showing PyPI downloads for the top 15k projects. It starts at around 1.2 billion, and quickly drops down around to near zero between rank 200-1000.
ALT text detailsSimilar but we can more clearly see it drops to around 100k downloads around rank 7,500.
ALT text detailsA chart showing PyPI downloads for the top 15k projects. It starts at around 1.2 billion, and quickly drops down around to near zero between rank 200-1000.
ALT text detailsSimilar but we can more clearly see it drops to around 100k downloads around rank 7,500.
I'm looking for my next role as a program manager, team lead, or senior developer.
- 20+ years in open source - 6 years experience in web dev with #Python, #Django, HTML, bootstrap - 7 years experience in C, Linux kernel, embedded systems
My passions lie at the intersection of open source software development and creating welcoming spaces for people to learn and grow.
I'm currently the program manager for a technical internship program. I work remotely with a team of 4 people in New York, Brazil, and Nigeria.
Looking for a fully remote role. I'm open to relocation outside the USA.
Southern California #PyLadies and #Python folks, I need your help!
I'm in the planning stages of forming a PyLadies chapter based in the San Gabriel Valley (that's Pasadena, Monrovia, Arcadia, but could also include Glendale and Burbank, and many more communities on the east side of Los Angeles).
Before I submit requests and get the ball rolling, I'd like to find a third person who's interested in signing on as an organizer. Initially there won't be much responsibility beyond getting the word out and helping to decide what our first events will be. It's a great opportunity for someone looking for leadership experience in a volunteer setting.
If you're interested, feel free to reach out to me here, or at my email address on mechanicalgirl.com, or even on the PyLadies or SoCal Python Slack spaces.
#Processing IDE comes with a rich collection of example sketches. A few years ago I have started converting the legacy Processing #Python mode examples to #py5 but I never finished it… would you like to help? It could be as easy as trying to run some examples and reporting if they work or not. And if you find a broken one I could help you fix it (or I could fix it myself…)
ALT text detailsAnimated screen capture showing an example sketch on Thonny IDE, that loads a rocket OBJ model and shows it spinning on another window.
#Processing IDE comes with a rich collection of example sketches. A few years ago I have started converting the legacy Processing #Python mode examples to #py5 but I never finished it… would you like to help? It could be as easy as trying to run some examples and reporting if they work or not. And if you find a broken one I could help you fix it (or I could fix it myself…)
ALT text detailsAnimated screen capture showing an example sketch on Thonny IDE, that loads a rocket OBJ model and shows it spinning on another window.
Southern California #PyLadies and #Python folks, I need your help!
I'm in the planning stages of forming a PyLadies chapter based in the San Gabriel Valley (that's Pasadena, Monrovia, Arcadia, but could also include Glendale and Burbank, and many more communities on the east side of Los Angeles).
Before I submit requests and get the ball rolling, I'd like to find a third person who's interested in signing on as an organizer. Initially there won't be much responsibility beyond getting the word out and helping to decide what our first events will be. It's a great opportunity for someone looking for leadership experience in a volunteer setting.
If you're interested, feel free to reach out to me here, or at my email address on mechanicalgirl.com, or even on the PyLadies or SoCal Python Slack spaces.
ALT text detailsTwo functions called test_get_install_to_run_with_platform. Same names, the second tests the case where windowed=True.
The first one is marked in red to indicate it wasn't run.
The second is green to indicate it was run.
ALT text detailsTwo functions called test_get_install_to_run_with_platform. Same names, the second tests the case where windowed=True.
The first one is marked in red to indicate it wasn't run.
The second is green to indicate it was run.
Someone asked about a deployment that failed using django-simple-deploy. The root cause was that their requirements.txt file had a UTF-16 encoding.
I'm currently parsing requirements.txt (when present) with path.read_text(), with no args. I could catch the UnicodeDecodeException, but is that worth supporting?
Is a UTF-16 encoded requirements file just going to cause problems for them down the road? I've never run into this before, and have no idea how common it is.
Someone asked about a deployment that failed using django-simple-deploy. The root cause was that their requirements.txt file had a UTF-16 encoding.
I'm currently parsing requirements.txt (when present) with path.read_text(), with no args. I could catch the UnicodeDecodeException, but is that worth supporting?
Is a UTF-16 encoded requirements file just going to cause problems for them down the road? I've never run into this before, and have no idea how common it is.
my colleague @DarkaMaul has put out a new post on the @trailofbits blog on how we worked with @pypi's maintainers to slash PyPI test run times from ~160s to ~30s despite overall test counts growing by 17% (3900 to 4700+):
this is some of my favorite kind of work: faster test suites means that developers run tests locally more often, and are less hesitant to add new tests (especially parametric ones). another great example of security and performance/reliability engineering dovetailing.
my colleague @DarkaMaul has put out a new post on the @trailofbits blog on how we worked with @pypi's maintainers to slash PyPI test run times from ~160s to ~30s despite overall test counts growing by 17% (3900 to 4700+):
this is some of my favorite kind of work: faster test suites means that developers run tests locally more often, and are less hesitant to add new tests (especially parametric ones). another great example of security and performance/reliability engineering dovetailing.
Do you maintain or contribute to a #Python package that includes a C extension? Would you like to run a fuzzer against it?
If so, let me know and I will run it, or help you to get it running.
The fuzzer is #fusil, which generates random code calling into your functions and methods. It's useful to check for crashes on invalid inputs or unexpected call patterns.
my colleague @DarkaMaul has put out a new post on the @trailofbits blog on how we worked with @pypi's maintainers to slash PyPI test run times from ~160s to ~30s despite overall test counts growing by 17% (3900 to 4700+):
this is some of my favorite kind of work: faster test suites means that developers run tests locally more often, and are less hesitant to add new tests (especially parametric ones). another great example of security and performance/reliability engineering dovetailing.
We are using plant genomics & transcriptomics to understand the genetics and the evolution of the specialized metabolism of plants. Many long read sequencing projects (#ONT) are going on in the lab. We also like reusing public data sets to answer biological questions. #Python is the dominant script language in the group. We use these scripts to perform analyses beyond the potential of existing tools. Check out our website and get in touch if you would like to join: https://www.izmb.uni-bonn.de/en/molecular-plant-sciences/contact
ALT text detailsBeautiful Poppelsdorf Palace in the Botanical Gardens belonging to the University of Bonn
Would you like to learn the very basics of #programming? I can teach you.
I like to teach #Python in the context of making drawings, if you already know how to program but would like to learn some Python or some #CreativeCoding, I can help! Maybe you know someone who would enjoy this?
Schedule a free chat with me and we can discuss further details like time availability and my rates. All my teaching materials are free and open, but I need income to keep producing them. Some generous people make small recurring donations. https://abav.lugaralgum.com/links
I was looking for an alternative to classic shell scripts, so I timed a Hello World program in different languages for fun. I thought you might want to know:
1 ms - #Bash 1 ms - #Perl 12 ms - #Python 33 ms - #Go (shebang calling `go run`) 38 ms - #C (shebang compiling to temporary file) 61 ms - #Rust (shebang compiling to temporary file)
Needless to say that this is a highly unfair and silly comparison. It's still interesting, though.
Is anyone I know going to the #Fastly Xcelerate event in L.A. on May 14? I'll be speaking there (on a customer panel, but it still counts). I'm excited to talk about some TLS tooling I built for Vox using #Python and #Flask (to automate the management of certs on our 400+ active domains).
Is anyone I know going to the #Fastly Xcelerate event in L.A. on May 14? I'll be speaking there (on a customer panel, but it still counts). I'm excited to talk about some TLS tooling I built for Vox using #Python and #Flask (to automate the management of certs on our 400+ active domains).
If an error in your #Python program seems impossible, double-check that you haven't edited the source after starting the program. Tracebacks re-read the source files to show the lines of code, so they can show you edited lines that aren't what you are running.
📚 Require Sphinx 7.3 📚 Add support for Python 3.14 📚 Drop support for Python 3.10-3.11 📚 Copy button for code samples 📚 PEP 639 licence metadata 📚 and more!
Would you like to learn the very basics of #programming? I can teach you.
I like to teach #Python in the context of making drawings, if you already know how to program but would like to learn some Python or some #CreativeCoding, I can help! Maybe you know someone who would enjoy this?
Schedule a free chat with me and we can discuss further details like time availability and my rates. All my teaching materials are free and open, but I need income to keep producing them. Some generous people make small recurring donations. https://abav.lugaralgum.com/links
Would you like to learn the very basics of #programming? I can teach you.
I like to teach #Python in the context of making drawings, if you already know how to program but would like to learn some Python or some #CreativeCoding, I can help! Maybe you know someone who would enjoy this?
Schedule a free chat with me and we can discuss further details like time availability and my rates. All my teaching materials are free and open, but I need income to keep producing them. Some generous people make small recurring donations. https://abav.lugaralgum.com/links
Finished my first #python program, it's a totally original (but tiny) ~150 line console word game that taught me a lot. Still have a lot more to learn, and excited to keep going.
Ever needed to simplify street networks? I did. And it is a pain. So we joined forces with @anavybor and @JamesGaboardi and wrote an algorithm that does that for us. And can do for you, as it is available as a Python package called `neatnet`.
Ever needed to simplify street networks? I did. And it is a pain. So we joined forces with @anavybor and @JamesGaboardi and wrote an algorithm that does that for us. And can do for you, as it is available as a Python package called `neatnet`.
New #introduction after migrating to Hachyderm.io - I work in data/research for a dog welfare and rehoming charity, mostly using #RStats, #Python and #SQL with occasional #QGIS.
I’m also interested in the environment, climate and wildlife. I don’t have loads of free time these days but I also enjoy music (see Bandcamp link!), books when I get round to reading them (see Bookwyrm link!), films (anything from highbrow to Highlander), cycling, yoga and #TaiChi (initially as ways to help manage #arthritis, before I began to appreciate both in their own rights).
We're going to be covering security and proviacy considerations for publishing mobile apps, built with #Python, in both the #iOS and #Android app stores
Because I do a fair amount of frontend work but think most frontend frameworks are overkill, I use #HTMX and #alpinejs a lot. And @glyph's #NBPy talk made me think about what a #PyScript package that combines both and provides #python handles to both would look like.
What could I build if I had a drop-in #django package that gave me all the interaction I wanted while writing python code?
Because I do a fair amount of frontend work but think most frontend frameworks are overkill, I use #HTMX and #alpinejs a lot. And @glyph's #NBPy talk made me think about what a #PyScript package that combines both and provides #python handles to both would look like.
What could I build if I had a drop-in #django package that gave me all the interaction I wanted while writing python code?
I'm about to go to bed before I set up for a #Python event that celebrates the joy of technology and the responsibility we have to use the skills we have to improve the world.
A while ago, I caught the news that former #Python release manager, @swearyanthony is in the ICU in a critical condition with an unclear prognosis. I'm a Python person because I had the fortune to meet Anthony at the right time, and I'll be keeping him in my thoughts as this year's #NBPy unfolds.
I'm about to go to bed before I set up for a #Python event that celebrates the joy of technology and the responsibility we have to use the skills we have to improve the world.
A while ago, I caught the news that former #Python release manager, @swearyanthony is in the ICU in a critical condition with an unclear prognosis. I'm a Python person because I had the fortune to meet Anthony at the right time, and I'll be keeping him in my thoughts as this year's #NBPy unfolds.
Welcome Emma Smith (@emmatyping) to the Triage team!
--<-- Emma has been very active in the typing community, as a contributor to mypy, and as a contributor to CPython’s PEP 585 implementation. Emma has also contributed WASM/Emscripten testing support, ZipFile improvements, and other contributions. Emma has a number of packaging related PEPs in flight and is active in the WheelNext initiative. ... ---->--
Welcome Emma Smith (@emmatyping) to the Triage team!
--<-- Emma has been very active in the typing community, as a contributor to mypy, and as a contributor to CPython’s PEP 585 implementation. Emma has also contributed WASM/Emscripten testing support, ZipFile improvements, and other contributions. Emma has a number of packaging related PEPs in flight and is active in the WheelNext initiative. ... ---->--
We're delighted to release Slint 1.11 with two exciting updates 🚀: ✅ Live-Preview features Color & Gradient pickers ✅ Python Bindings upgraded to Beta Speed up your UI development with visual color selection and more robust Python support. Check it out - https://slint.dev/blog/slint-1.11-released
"*BOSS (Big Open Source Sibling) é uma iniciativa de mentoria que visa engajar grupos sub representados na tecnologia para que comecem a contribuir para comunidades Open Source.
Nessa mentoria, muito mais do que desenvolver habilidades técnicas, as participantes aprendem competências úteis às comunidades Open Source, como se comunicar, trabalhar de forma assíncrona e remota, desenvolver coletivamente, etc."
"*BOSS (Big Open Source Sibling) é uma iniciativa de mentoria que visa engajar grupos sub representados na tecnologia para que comecem a contribuir para comunidades Open Source.
Nessa mentoria, muito mais do que desenvolver habilidades técnicas, as participantes aprendem competências úteis às comunidades Open Source, como se comunicar, trabalhar de forma assíncrona e remota, desenvolver coletivamente, etc."
Do you maintain or contribute to a #Python package that includes a C extension? Would you like to run a fuzzer against it?
If so, let me know and I will run it, or help you to get it running.
The fuzzer is #fusil, which generates random code calling into your functions and methods. It's useful to check for crashes on invalid inputs or unexpected call patterns.
Python devs, I'd like your opinion on putting extensive business logic in `__init__.py`.
It makes me feel a bit icky because it often leads to unavoidable imports. Sometimes, it gets mixed with import shortcut definitions and other administrative stuff.
Personally, I like my inits to be empty, as much as possible.
But maybe that is just me being silly.
So, what do you think of business logic in `__init__.py`?
What is HardTech? Hardtech is a #scifi project I have: a scifi documentation website; a website that describes in details fictional technologies. A kind of user manual for a spacecraft/space station. The aesthetics are rusty, unsafe, industrial. You must see wires in the spaceships/space station, you must not feel safe when you're on board. Main colors are various orange and black.
Hardtech is LowTech
Why? Because HardTech needs to know technologies in details to make them understandable for other people, but needs to stay technical and cryptic enough to keep the sense of wonder.
I will be streaming over at https://www.twitch.tv/glyph_official/ in a bit less than 21 hours, i.e. at 10AM US/Pacific on 4/22. Come on by tomorrow and comment on my #Python code, or perhaps learn something about #Emacs.
"One highlight of submitting a PR to #Python is that their infrastructure has more CI coverage than we could possibly dream of: a complete build of Python runs over 50+ toolchains and architectures. The flipside? We discovered some pretty annoying corner cases." https://jonathan.protzenko.fr/2025/04/18/python.html
"One highlight of submitting a PR to #Python is that their infrastructure has more CI coverage than we could possibly dream of: a complete build of Python runs over 50+ toolchains and architectures. The flipside? We discovered some pretty annoying corner cases." https://jonathan.protzenko.fr/2025/04/18/python.html
If you maintain an open source package, set up a standing search on scholar.google.com for your package name. You'll get gmail notifications of published papers referencing your package.
It's truly gratifying to see students and research teams making use of my pyparsing package to parse data sets and DSLs, so they can quickly get past the pesky parser development stage and get on with the business of their actual field of study. #pyparsing#python#google#oss#opensource
People have mocked #Perl for being a "write only" language, but I feel like the Perl community should take pride and own that slur - you don't need to constantly read and re-read and re-re-read (and edit) the Perl code, because it just keeps working.
Not so with #Python. Python will deprecate your shit and you will NEED to re-read that code so you can make pointless edits to keep it working.
I'm adding resources for future reading for mine and Marie's #Python#packaging tutorial for #PyConUS, and I realised that I don't know any good #pytest tutorials for beginners. Does anyone have any reccommendations?
I'm adding resources for future reading for mine and Marie's #Python#packaging tutorial for #PyConUS, and I realised that I don't know any good #pytest tutorials for beginners. Does anyone have any reccommendations?
I'm adding resources for future reading for mine and Marie's #Python#packaging tutorial for #PyConUS, and I realised that I don't know any good #pytest tutorials for beginners. Does anyone have any reccommendations?
People have mocked #Perl for being a "write only" language, but I feel like the Perl community should take pride and own that slur - you don't need to constantly read and re-read and re-re-read (and edit) the Perl code, because it just keeps working.
Not so with #Python. Python will deprecate your shit and you will NEED to re-read that code so you can make pointless edits to keep it working.
Roughly one day a week lately, I have been working with a friend to reboot some of the many https://pagekite.net things that had stalled while I had other priorities. It's been great!
When we started working together, she was a bit baffled at my complaints about the upgrade treadmill and the #Python community's wilful lack of fucks to give about long term stability.
It didn't take long, maybe 4-5 sessions, before she began to vehemently understand what I was moaning about...
Okay, yeah, so, that method was BS for two reasons: I'm formatting the milliseconds from the log record, but the rest of the timestamp from "now" (lol, ouch) – but also, the underlying problem is using time.strftime (like the base class) instead of the more modern datetime.datetime.strftime. Because the latter actually _does_ have a format string placeholder for microseconds (not milliseconds though).
So, after a bit of iteration, I think I'll be going with this one:
ALT text detailsThe class now sets its format string in a class attribute "default_time_format" just like the base class does. It's also using datetime.datetime.fromtimestamp() to convert record.created (a float) into a (naive) datetime object, and then calls .astimezone() without arguments to convert it into an aware datetime for the local timezone. After that, it's just a call to strftime with either the datefmt string passed to the method or the class-level default as its format string.
Code follows:
class ISOTimeFormatter(logging.Formatter):
default_time_format = "%Y-%m-%d %H:%M:%S.%f%z"
def formatTime(
self, record: logging.LogRecord, datefmt: str | None = None
) -> str:
return (
datetime.fromtimestamp(record.created)
.astimezone() # convert to aware object using local timezone
.strftime(datefmt or self.default_time_format)
)
ALT text detailsA Python class ISOTimeFormatter (extending logging.Formatter) that uses an f-string to inject record.msecs into the format string passed to time.strftime. Code follows:
class ISOTimeFormatter(logging.Formatter):
@staticmethod
def formatTime(
record: logging.LogRecord, datefmt: str | None = None
) -> str:
return time.strftime(f"%Y-%m-%d %H:%M:%S.{record.msecs:03.0f}%z")
Tried some 'vibe coding' today. Hmm. On the plus side I found out about a #python package I didn't know - https://pandas-market-calendars.readthedocs.io/en/latest/ - on the minus side it completely hallucinated a method that has never existed. So on balance probably neutral?
I also maintain a #Python convenience library for writing #macOS applications, QuickMacApp. I did a new release of it recently to add the new notifications API, and there's finally some documentation on the web: https://pypi.org/project/quickmacapp/2025.4.15/
Did you know that I maintain a #Python library for writing idiomatic, deterministic finite-state automata, where the inputs are method calls and the outputs are return values? Today there's a new release of it, with some minor updates and to officially add 3.13 to the support matrix (although it did work fine before): https://pypi.org/project/Automat/25.4.16/
ALT text details# The code below and a windows with the resulting execution, 4 rows of 10 circles, the rows are red, green, bluw and black (with white text with the numbers from 0 to 9).
def setup():
size(500, 200)
fill(200, 0, 0)
x = 25
for _ in range(10):
circle(x, 25, 40)
x = x + 50
fill(0, 200, 0)
for x in range(25, 500, 50):
circle(x, 75, 40)
fill(0, 0, 200)
for i in range(10):
circle(25 + i * 50, 125, 40)
text_align(CENTER, CENTER)
y = 175
w = 50
for i in range(10):
x = w / 2 + i * w
fill(0)
circle(x, y, w - 10)
fill(255)
text(i, x, y)
@ianthetechie@feld I can confirm that #Python on #FreeBSD behaves as one would expect. It consumes all RAM (with #ZFS releasing ARC as expected) and then dips into swap. As soon as Python releases memory after the ingestion routine, the swap is purged to near zero and the RAM then becomes available (and used) by the system. Far more predictable and reliable.
If you have big, vertical workloads, FreeBSD is where it is at.
🐍🇫🇮 The first PyCon Finland in nearly 10 years will take place on Friday, 17th October in Jyväskylä! It will be a special one-day event in cooperation with @ploneconf
🐍🇫🇮 The call for proposals and ticket sales are open now!
⚠️ ANNONCE ⚠️ J'ai une opportunité de fou mais incertaine. Je cherche un-e/des développeur-ses web qui pourrait améliorer le code de @pytition basé sur #Python avec un cahier des charges pour une ONG écologiste. Ça sera financé ! Et possible de le mettre dans le gitlab commun. + d'information : https://pytition.org/
Si quelqu'un-e est motivé-e, contactez moi en mp!
Le repouet aide à combattre Change et le capitalisme des pétitions ! ❤️✊
⚠️ ANNONCE ⚠️ J'ai une opportunité de fou mais incertaine. Je cherche un-e/des développeur-ses web qui pourrait améliorer le code de @pytition basé sur #Python avec un cahier des charges pour une ONG écologiste. Ça sera financé ! Et possible de le mettre dans le gitlab commun. + d'information : https://pytition.org/
Si quelqu'un-e est motivé-e, contactez moi en mp!
Le repouet aide à combattre Change et le capitalisme des pétitions ! ❤️✊
A quick #Python example of why you should only evaluate boolean expressions in a boolean context:
Since an empty list evaluates to `False`, people like to write code like this:
async def get_things() -> list[Thing]: ...
things = get_things() if things: ...
The above code will happily type check even though it is severely bugged. If you are properly explicit about the condition, the type checker will alert you to the error:
Memory management on #Linux is a bit borked. I tried to ingest 4GB of records from a file into a list (array) with #Python. Instead of the machine releasing RAM, it decided just to use swap and before I knew it, swapped was consumed and the Python process fell over.
I'll move the workload over to one of my #FreeBSD lab hosts tonight and re-run the script.
I've updated my "How to have a great first PyCon" blog post for 2025.
I linked to more blog posts from others on "how to PyCon", updated links to this year's PyCon website, added more updates around the implosion of Twitter, and updated some outdated references.
OH HEY I was traveling and I missed this but there are new #Python releases! 3.13.3 and 3.12.10 are downloadable and installable via MOPUp <https://github.com/glyph/mopup> but you already knew that right because you weren't traveling, and you are always to-the-minute up to date on security patches, right?
There was meant to be a 11.2.0 on 1st April, but we put too much good stuff in the wheels and hit the @pypi.org project limit before it could all be uploaded. That was yanked and now deleted and 11.2.1 is back to normal size.
We'll try and put the good stuff back for 11.3.0 on 1st July but take up less space.
Two things: we added AVIF support which made the wheels much bigger, and we hit the PyPI project size limit before the release could be fully updated.
11.2.1 instead has AVIF support but needs to be built from source. We'll look into including AVIF in wheels in a future release so that the size doesn't increase so much.
ALT text details11.2.1 (2025-04-12)
Warning
The release of Pillow 11.2.0 was halted prematurely, due to hitting PyPI’s project size limit and concern over the size of Pillow wheels containing libavif. The PyPI limit has now been increased and Pillow 11.2.1 has been released instead, without libavif included in the wheels. To avoid confusion, the incomplete 11.2.0 release has been removed from PyPI.
Security
Undefined shift when loading compressed DDS images
When loading some compressed DDS formats, an integer was bitshifted by 24 places to generate the 32 bits of the lookup table. This was undefined behaviour, and has been present since Pillow 3.4.0.
Deprecations
Image.Image.get_child_images()
Deprecated since version 11.2.1.
Image.Image.get_child_images() has been deprecated. and will be removed in Pillow 13 (2026-10-15). It will be moved to ImageFile.ImageFile.get_child_images(). The method uses an image’s file pointer, and so child images could only be retrieved from an PIL.ImageFile.ImageFile instance.
API Changes
append_images no longer requires save_all
Previously, save_all was required to in order to use append_images. Now, save_all will default to True if append_images is not empty and the format supports saving multiple frames:
im.save("out.gif", append_images=ims)
ALT text detailsOther Changes
Arrow support
Arrow is an in-memory data exchange format that is the spiritual successor to the NumPy array interface. It provides for zero-copy access to columnar data, which in our case is Image data.
To create an image with zero-copy shared memory from an object exporting the arrow_c_array interface protocol:
from PIL import Image
import pyarrow as pa
arr = pa.array([0]*(5*5*4), type=pa.uint8())
im = Image.fromarrow(arr, 'RGBA', (5, 5))
Pillow images can also be converted to Arrow objects:
from PIL import Image
import pyarrow as pa
im = Image.open('hopper.jpg')
arr = pa.array(im)
Reading and writing AVIF images
Pillow can now read and write AVIF images when built from source with libavif 1.0.0 or later.
ALT text detailsAPI Additions
"justify" multiline text alignment
In addition to "left", "center" and "right", multiline text can also be aligned using "justify" in ImageDraw:
from PIL import Image, ImageDraw
im = Image.new("RGB", (50, 25))
draw = ImageDraw.Draw(im)
draw.multiline_text((0, 0), "Multiline\ntext 1", align="justify")
draw.multiline_textbbox((0, 0), "Multiline\ntext 2", align="justify")
Specify window in ImageGrab on Windows
When using grab(), a specific window can be selected using the HWND:
from PIL import ImageGrab
ImageGrab.grab(window=hwnd)
Check for MozJPEG
You can check if Pillow has been built against the MozJPEG version of the libjpeg library, and what version of MozJPEG is being used:
from PIL import features
features.check_feature("mozjpeg") # True or False
features.version_feature("mozjpeg") # "4.1.1" for example, or None
Saving compressed DDS images
Compressed DDS images can now be saved using a pixel_format argument. DXT1, DXT3, DXT5, BC2, BC3 and BC5 are supported:
im.save("out.dds", pixel_format="DXT1")
ALT text detailsFANDANGO: Evolving Language-Based Testing
José Antonio Zamudio Amaya, Marius Smytzek, Andreas Zeller
Language-based fuzzers leverage formal input specifications (languages) to generate arbitrarily large and diverse sets of valid inputs for a program under test. Modern language-based test generators combine grammars and constraints to satisfy syntactic and semantic input constraints. ISLa, the leading input generator in that space, uses symbolic constraint solving to solve input constraints. Using solvers places ISLa among the most precise fuzzers but also makes it slow.
In this paper, we explore search-based testing as an alternative to symbolic constraint solving. We employ a genetic algorithm that iteratively generates candidate inputs from an input specification, evaluates them against defined constraints, evolving a population of inputs through syntactically valid mutations and retaining those with superior fitness until the semantic input constraints are met. This evolutionary procedure, analogous to natural genetic evolution, leads to progressively improved inputs that cover both semantics and syntax. This change boosts the efficiency of language-based testing: In our experiments, compared to ISLa, our search-based FANDANGO prototype is faster by one to three orders of magnitude without sacrificing precision...
I have made a release of "git-withme" which allows peer-to-peer Git usage over #magicWormhole
This uses short, human-memorable codes to invite peers to collaborate (push, pull, etc) in real-time on a Git repository with no external hosting providers. Creates a temporary bare repository on the host so it feels like GitLab style usage.
"pip install git-withme" or see the project pages:
I have made a release of "git-withme" which allows peer-to-peer Git usage over #magicWormhole
This uses short, human-memorable codes to invite peers to collaborate (push, pull, etc) in real-time on a Git repository with no external hosting providers. Creates a temporary bare repository on the host so it feels like GitLab style usage.
"pip install git-withme" or see the project pages:
I have made a release of "git-withme" which allows peer-to-peer Git usage over #magicWormhole
This uses short, human-memorable codes to invite peers to collaborate (push, pull, etc) in real-time on a Git repository with no external hosting providers. Creates a temporary bare repository on the host so it feels like GitLab style usage.
"pip install git-withme" or see the project pages:
Ugh, Python got over 500 #GSoC applications this year and so many of them are absolutely trash, didn't follow any of the instructions. Most years about half of our applications are like this. But usually we have a lot fewer applicants and the submissions were blank files not plausible AI nonsense.
So I'm stuck reading hundreds of incredibly low quality nonsensical submissions today in hopes to take some workload off my other unpaid volunteer mentors. This is not the volunteer gig I signed up for 15 years ago when it was mostly working with new contributors and not their AI chatbots and I'm grumpy.
Ugh, Python got over 500 #GSoC applications this year and so many of them are absolutely trash, didn't follow any of the instructions. Most years about half of our applications are like this. But usually we have a lot fewer applicants and the submissions were blank files not plausible AI nonsense.
So I'm stuck reading hundreds of incredibly low quality nonsensical submissions today in hopes to take some workload off my other unpaid volunteer mentors. This is not the volunteer gig I signed up for 15 years ago when it was mostly working with new contributors and not their AI chatbots and I'm grumpy.
I've updated my "How to have a great first PyCon" blog post for 2025.
I linked to more blog posts from others on "how to PyCon", updated links to this year's PyCon website, added more updates around the implosion of Twitter, and updated some outdated references.
I'm trying to learn #Python correctly. Coming from Pascal (and BASIC) as the main language I used when young (don't count Shell), it is very feature rich being able to import modules but the syntax and nuances are hard to get my head around.
Ugh, Python got over 500 #GSoC applications this year and so many of them are absolutely trash, didn't follow any of the instructions. Most years about half of our applications are like this. But usually we have a lot fewer applicants and the submissions were blank files not plausible AI nonsense.
So I'm stuck reading hundreds of incredibly low quality nonsensical submissions today in hopes to take some workload off my other unpaid volunteer mentors. This is not the volunteer gig I signed up for 15 years ago when it was mostly working with new contributors and not their AI chatbots and I'm grumpy.
Just released: Python 3.14.0a7 🚀 Just released: Python 3.13.3 🚀🚀 Just released: Python 3.12.10 🚀🚀🚀 Just released: Python 3.11.12 🚀🚀🚀🚀 Just released: Python 3.10.17 🚀🚀🚀🚀🚀 Just released: Python 3.9.22 🚀🚀🚀🚀🚀🚀
Last 3.14 alpha! Less than a month to get new features in before beta!
Last 3.12 bugfix release! Now in security fix only!
I've spent the afternoon writing an EPUB format writer for @novelwriter. It now has all the meta data XML files and can dump raw text of the novel without text formatting, so that's very good progress.
Next is of course to make it also format the text itself for the pages.
It's an interesting format to work with, and like ODT and DOCX is rather messy. Like DOCX, I get the feeling it's been modified a lot too.
I've spent the afternoon writing an EPUB format writer for @novelwriter. It now has all the meta data XML files and can dump raw text of the novel without text formatting, so that's very good progress.
Next is of course to make it also format the text itself for the pages.
It's an interesting format to work with, and like ODT and DOCX is rather messy. Like DOCX, I get the feeling it's been modified a lot too.
Great news 🎉: inline-snapshot gets its first insider feature that allow you to create and fix assertions without using snapshot(). This allows you to fix normal assertions in your existing code. And the best part is that you have a chance to win something 🎁 ...
I'm giving away a lifetime Insider membership to one of you who reposts this post. The winner will be chosen at random in one week. #python
ALT text detailsA self-similar plant drawing made with an L-System. It has white strokes and red circles, at the end of branches, on a black background.
#Python folks: if you want an interactive debugger, what do you use, and how do you set it up? Particularly on unfamiliar projects with something like tox/nox/Just which gets between you and the running process. Bonus points if you have a functioning #Emacs integration.
In principle I love the idea of interactive debuggers. In practice I have been burned so many times by configuration, path, and terminal interaction issues that I have an almost instinctual recoil from anything based on pdb.
I'm working on a project that is intended to encourage folk to make markdown text files which can be bundled together in different bundles of text files using a package manager.
Question for coders; Which package manager would you suggest I use?
Main criterias (in order) are:
1. Easy for someone with basic command line skills to edit the file and update version numbers and add additional packages.
2. All being equal, more commonly and easy to setup is preferred.
This means #Python now has a lock file standard that can act as an export target for all tools that can create some sort of lock file. And for some tools the format can act as their primary lock file format as well instead of some proprietary format.
I took part in #PyWeek 39 over the weekend and made a game in #PyScript. It's a single-tap rhythm game. Should work on any desktop browser and most new phones. It was a fun challenge to make a game where the realtime music sync is so important. You want to let people tap a little too late and still have the game allow it. You want it to be playable with Bluetooth headphones and keyboards that add a lot of latency.
ALT text detailsThe logo screen of the game. STREAMLINE is written in the middle. A single three-dimensional multisegment line spans into the horizon in the background. The aesthetic vaguely resembles the "cyberspace" from TRON or Hackers, with blue-ish green-ish colors dominating.
I took part in #PyWeek 39 over the weekend and made a game in #PyScript. It's a single-tap rhythm game. Should work on any desktop browser and most new phones. It was a fun challenge to make a game where the realtime music sync is so important. You want to let people tap a little too late and still have the game allow it. You want it to be playable with Bluetooth headphones and keyboards that add a lot of latency.
ALT text detailsThe logo screen of the game. STREAMLINE is written in the middle. A single three-dimensional multisegment line spans into the horizon in the background. The aesthetic vaguely resembles the "cyberspace" from TRON or Hackers, with blue-ish green-ish colors dominating.
So, just wondering: what is a decent European alternative for payment handling like #Stripe? (It must support both single payments and monthly subscriptions.)
I've been out of the loop and I am sure there are people with experience here.
Preferably one with a matured API (and a Python library would be a nice bonus).
#ProxLB - an opensource & advanced VM loadbalancer for #Proxmox clusters. Including affinity & anti-affinity rules, maintenance mode (evacuating nodes) and more. I just published my slides about it.
#ProxLB - an opensource & advanced VM loadbalancer for #Proxmox clusters. Including affinity & anti-affinity rules, maintenance mode (evacuating nodes) and more. I just published my slides about it.
@bshaurette@social.linux.pizza · Reply to Glyph's post
@glyph It’s really difficult to filter it all out and maintain a healthy mental attitude right now. I still end most days with a stress stomach ache. But what IS helping is reconnecting with community. This *waves around at all the #python folks* is my biggest community, and I’m trying to talk to as many people as I can every day, catch up on Zoom when I can, see people in person when I can. And I’m an introvert, but somehow connecting takes some of the fear away.
I am in urgent job search mode, so I'm gonna throw this out here and see if anything comes of it.
I am a #Canadian, fluent in both #English and #French. I have experience with several programming languages. My strongest proficiency is with #Haskell and #C. I also have a reasonable grasp of #HTML, #JavaScript, #SQL, #Python, #Lua, #Linux system administration, #bash scripting, #Perl, #AWK, some #Lisp (common, scheme, and emacs), and probably several others I've forgotten to mention.
I am not necessarily looking for something in tech. I just need something stable. I have done everything from software development, to customer support, to factory work, though my current circumstances make in-person work more difficult than remote work. I have been regarded as a hard worker in every job I have ever held.
I am in urgent job search mode, so I'm gonna throw this out here and see if anything comes of it.
I am a #Canadian, fluent in both #English and #French. I have experience with several programming languages. My strongest proficiency is with #Haskell and #C. I also have a reasonable grasp of #HTML, #JavaScript, #SQL, #Python, #Lua, #Linux system administration, #bash scripting, #Perl, #AWK, some #Lisp (common, scheme, and emacs), and probably several others I've forgotten to mention.
I am not necessarily looking for something in tech. I just need something stable. I have done everything from software development, to customer support, to factory work, though my current circumstances make in-person work more difficult than remote work. I have been regarded as a hard worker in every job I have ever held.
I am in urgent job search mode, so I'm gonna throw this out here and see if anything comes of it.
I am a #Canadian, fluent in both #English and #French. I have experience with several programming languages. My strongest proficiency is with #Haskell and #C. I also have a reasonable grasp of #HTML, #JavaScript, #SQL, #Python, #Lua, #Linux system administration, #bash scripting, #Perl, #AWK, some #Lisp (common, scheme, and emacs), and probably several others I've forgotten to mention.
I am not necessarily looking for something in tech. I just need something stable. I have done everything from software development, to customer support, to factory work, though my current circumstances make in-person work more difficult than remote work. I have been regarded as a hard worker in every job I have ever held.
ALT text detailsBefore: running "eol alpine" shows a wide table in the terminal, the last column made of long links to release notes.
ALT text detailsAfter: running "eol alpine" shows a narrower table in the terminal, no links column, and the release names in the first column are underlined and clickable.
Well, I had a minor stumble releasing #pyparsing 3.2.2 this past weekend, with a bug (Issue #600) that snuck past several thousand unit tests. So I added 1 new test with several hundred new cases that caught that bug, then fixed it (and a sibling bug 10 lines of code away from the first one). Great immediate notice of failing CI pipelines from diligent users, I was able to get 3.2.3 out with the fix Monday evening. And all's right with the world again (the #Python world, anyway).
I wrote up how to add it your workflows so you can start testing free-threaded Python 3.13 and 3.14 with either actions/setup-python or actions/setup-uv.
I wrote up how to add it your workflows so you can start testing free-threaded Python 3.13 and 3.14 with either actions/setup-python or actions/setup-uv.
I wrote up how to add it your workflows so you can start testing free-threaded Python 3.13 and 3.14 with either actions/setup-python or actions/setup-uv.
I wrote up how to add it your workflows so you can start testing free-threaded Python 3.13 and 3.14 with either actions/setup-python or actions/setup-uv.
Cheers, #CreativeCoding friends! I'm going to try out something, let's see what happens... next Saturday (2025-03-29) and possibly on some other Saturdays after that. I'm going to host an online space where I show something about Creative Coding with #Python and #py5. I'm calling it "Python Creative Coding Free Walking Tour". I'll also do some "py5 Office Hours", Q&A and on-boarding.
It will be free, and I'll accept donations, just like the free walking tour we have showing off nice spots of São Paulo for tourists. I hope it will be even better than that: as I studied architecture I find the tour guide's explanations a bit over the top and sometimes missing the point, but maybe mine will also be an over the top creative coding tour, who knows? you'll have to judge by yourselves.
The first, "walking tour" part will be from 11:00AM BRT (UCT -3) to 12:00 and then, the second, "office hours" part, will be from 12:15 to 13:00, when people will be able to ask me anything about py5 and I'll try to answer to the best of my knowledge, it will also be an opportunity to get help setting up your tools/environment in order to take your first steps drawing with code.
That's it for now — trying to take it easy on the self-promo for the moment because I think I'm getting close to actually launching one of these apps for real, and then I'll get REAL obnoxious. Maybe I'll even remember one of those hashtags like #python or #opensource next time
Cheers, #CreativeCoding friends! I'm going to try out something, let's see what happens... next Saturday (2025-03-29) and possibly on some other Saturdays after that. I'm going to host an online space where I show something about Creative Coding with #Python and #py5. I'm calling it "Python Creative Coding Free Walking Tour". I'll also do some "py5 Office Hours", Q&A and on-boarding.
It will be free, and I'll accept donations, just like the free walking tour we have showing off nice spots of São Paulo for tourists. I hope it will be even better than that: as I studied architecture I find the tour guide's explanations a bit over the top and sometimes missing the point, but maybe mine will also be an over the top creative coding tour, who knows? you'll have to judge by yourselves.
The first, "walking tour" part will be from 11:00AM BRT (UCT -3) to 12:00 and then, the second, "office hours" part, will be from 12:15 to 13:00, when people will be able to ask me anything about py5 and I'll try to answer to the best of my knowledge, it will also be an opportunity to get help setting up your tools/environment in order to take your first steps drawing with code.
@mrchrisadams In 2018, #python was chosen "unofficially" to be taught to all pupils in France (at the Lycée level, for 16 to 18 years old). In 2020 it became official, and not only for mathematics. I guess we're reaping some rewards now !
I have a code section where I must select one of 4 pyparsing classes based on the settings of 2 arguments - whether to match a string with or without case sensitivity, and as or as not a keyword.
See examples below - I had hoped to make this a poll, but apparently my client will only permit images _or_ polling :( So respond in replies please. #python
ALT text detailsTwo ways in Python to select 1 of 4 options based on values of 2 bool values
# 1 - nested if-else
if caseless:
if asKeyword:
parse_element_class = CaselessKeyword
else:
parse_element_class = CaselessLiteral
else:
if asKeyword:
parse_element_class = Keyword
else:
parse_element_class = Literal
# 2 - dict with bool tuples
parse_element_class = {
(True, True): CaselessKeyword,
(True, False): CaselessLiteral,
(False, True): Keyword,
(False, False): Literal,
}[(caseless, asKeyword)]
#Python dicts are ordered (as of 3.7) by insertion order. But Sets are not. Seems ilke an oversight...?
There are 102 comments on this suggestion to add an OrderedSet but why not just enhance Set to work like dict keys? (A lot of the comments aren't helpful either because they just say 'ah you rube, sets aren't ordered' which is appeal to mathematical definition instead of how people use them irl)
ALT text detailsTerminal output of running "pypistats python_minor pillow", showing a table of Python versions sorted by how many downloads each is responsible for.
Pyparsing 3.2.2 cleans up a formerly internal-only utility method make_compressed_re(), and makes it part of the public API. Given a list of strings, it generates a regex to match those strings and only those (so no cheating like ".*").
Here are before/after expressions for matching chemical symbols.
ALT text detailsA regular expression for matching chemical symbols:
Ac|Ag|Al|Am|Ar|As|At|Au|Ba|Be|Bh|Bi|Bk|Br|B|Ca|Cd|Ce|Cf|Cl|Cm|Cn|
Co|Cr|Cs|Cu|C|Db|Ds|Dy|Er|Es|Eu|Fe|Fl|Fm|Fr|F|Ga|Gd|Ge|He|Hf|Hg|
Ho|Hs|H|In|Ir|I|Kr|K|La|Li|Lr|Lu|Lv|Mc|Md|Mg|Mn|Mo|Mt|Na|Nb|Nd|Ne
|Nh|Ni|No|Np|N|Og|Os|O|Pa|Pb|Pd|Pm|Po|Pr|Pt|Pu|P|Ra|Rb|Re|Rf|Rg|
Rh|Rn|Ru|Sb|Sc|Se|Sg|Si|Sm|Sn|Sr|S|Ta|Tb|Tc|Te|Th|Ti|Tl|Tm|Ts|U|V|
W|Xe|Yb|Y|Zn|Zr
An optimized regular expression for matching chemical symbols:
A[cglmrstu]|B[aehikr]?|C[adeflmnorsu]?|D[bsy]|E[rsu]|F[elmr]?|G[ade]
|H[efgos]?|I[nr]?|Kr?|L[airuv]|M[cdgnot]|N[abdehiop]?|O[gs]?|P[abdmo
rtu]?|R[abefghnu]|S[bcegimnr]?|T[abcehilms]|U|V|W|Xe|Yb?|Z[nr]
It's probably nice that `psycopg2` decided to go with `%s` as the interpolator for prepared statements (even when one would expect other types like `%d`), but I have to wonder why it only supports those and not `?` like many other db interfaces, including the builtin `sqlite`. Does anyone know?
The Python version diagram has been updated to show the bugfix/security split for each release. (Before, the bars were either completely green or yellow.)
It's also zoomed in and shows fewer releases than before. There's another chart further down the page showing all of 2.6 to 3.14. And the wording in the status key has been refreshed to make it clearer.
ALT text detailsChart showing horizontal bars for Python releases, and time long the X axis. 2.7 and 3.6-3.8 are red because they're end-of-life. 3.9 and higher have their bar split into green and yellow segments. A vertical line for today crosses the yellow segment for 3.9-3.11, they're in the security phase. 3.12-3.13 are in bugfix.
ALT text detailsSimilar chart but showing all versions from 2.6 up to 3.14.
The Python version diagram has been updated to show the bugfix/security split for each release. (Before, the bars were either completely green or yellow.)
It's also zoomed in and shows fewer releases than before. There's another chart further down the page showing all of 2.6 to 3.14. And the wording in the status key has been refreshed to make it clearer.
ALT text detailsChart showing horizontal bars for Python releases, and time long the X axis. 2.7 and 3.6-3.8 are red because they're end-of-life. 3.9 and higher have their bar split into green and yellow segments. A vertical line for today crosses the yellow segment for 3.9-3.11, they're in the security phase. 3.12-3.13 are in bugfix.
ALT text detailsSimilar chart but showing all versions from 2.6 up to 3.14.
@pycharm has a handy feature like adding a name import by ⌥+Enter on an underlined unknown name. If you use it and suffer from the fact that the name is added to the existing "from" import at the end, and not in alphabetical order, as linters want, then this option will solve your problem. It is located in Editor → Code Style → #python → Imports.
ALT text detailsThe image displays a user interface with settings for optimizing imports in a coding environment. It highlights options such as sorting import statements and imported names, with checkboxes for enabling these features. The layout includes tabs labeled "Imports," "Other," and more.
If your test suite can run on #Python 3.14, and you use branch coverage measurement, please get Python 3.14.0a6 and coverage․py 7.7.0 and let me know how the speed compares to older versions! It will be faster!
If your test suite can run on #Python 3.14, and you use branch coverage measurement, please get Python 3.14.0a6 and coverage․py 7.7.0 and let me know how the speed compares to older versions! It will be faster!
@raiderrobert I'm making customized cms for few customers and I'm more friendly with #python than #php, so #wagtail looks as good solution than #wordpress. Wagtails StreamFields are AWESOME. Building selfhosted site right now - not easy, but i'm still surprised how it works ))
@mrchrisadams In 2018, #python was chosen "unofficially" to be taught to all pupils in France (at the Lycée level, for 16 to 18 years old). In 2020 it became official, and not only for mathematics. I guess we're reaping some rewards now !
This release brought to you by a Karelian pie (Karjalanpiirakka), a strawberry and gooseberry pie (mansikka-karviais piirakka) and a slice of blueberry pie (mustikkapiirakka).
This release brought to you by a Karelian pie (Karjalanpiirakka), a strawberry and gooseberry pie (mansikka-karviais piirakka) and a slice of blueberry pie (mustikkapiirakka).
ALT text detailsA map of a central part of São Paulo with most buildings gray and some buildings with saturated colors (probably only those that have an "amenity" text on OSM data)
ALT text detailsA map of a central part of São Paulo with most buildings gray and some buildings with saturated colors (probably only those that have an "amenity" text on OSM data)
The PSF is excited to share that Thomas Wouters has been awarded our Distinguished Service Award for his 25 years of service, dedication, and behind-the-scenes work which have helped shape the PSF and the #Python community into what they are today 👏👏 https://pyfound.blogspot.com/2025/03/dsa-thomas-wouters.html
I had many concerns about things **not** provided by #rustlang#rust when I started this journey. I tooted about them. You can look back at my history to see. As I have learned, I have seen what Rust has instead of each missing feature. #til about `catch_unwind` and looked deeper into `Result`s. So now I feel better about Rust not having #Python exceptions.
I still don’t see a replacement for Python’s keyword arguments or default values in function calls. Every time I mention this, people reply that I shouldn’t have so many arguments that I need these things. That’s absolutely not why I want them. I want them because they are better than comments at helping the reader understand what is happening without diving down into the function definition.
The PSF is excited to share that Thomas Wouters has been awarded our Distinguished Service Award for his 25 years of service, dedication, and behind-the-scenes work which have helped shape the PSF and the #Python community into what they are today 👏👏 https://pyfound.blogspot.com/2025/03/dsa-thomas-wouters.html
The PSF is excited to share that Thomas Wouters has been awarded our Distinguished Service Award for his 25 years of service, dedication, and behind-the-scenes work which have helped shape the PSF and the #Python community into what they are today 👏👏 https://pyfound.blogspot.com/2025/03/dsa-thomas-wouters.html
I’ll be giving a talk for Python Ireland this Wednesday, hosted by Pinterest Dublin!
I’ll be speaking about the new wave of open source social media platforms, such as Mastodon (a replacement for Twitter) and Pixelfed (a replacement for Instagram) and demonstrating how to build bots for them.
The talk is booked out at the moment but we’re anticipating some last minute drop outs, so keep an eye out for a free slot - register here: https://meetu.ps/e/NVRLh/JbmdX/i
I’ll be giving a talk for Python Ireland this Wednesday, hosted by Pinterest Dublin!
I’ll be speaking about the new wave of open source social media platforms, such as Mastodon (a replacement for Twitter) and Pixelfed (a replacement for Instagram) and demonstrating how to build bots for them.
The talk is booked out at the moment but we’re anticipating some last minute drop outs, so keep an eye out for a free slot - register here: https://meetu.ps/e/NVRLh/JbmdX/i
ALT text detailsscreenshot of the data art gallery website showing a grid of data art examples, including bob ross painting colours, and orca sightings.
pro tip: do you want to edit a #Python script which:
1. can only ever be a script 2. should never be imported as a module 3. you want to be recognized by your editor as a python file without faffing around with extra hints 4. for whatever reason you don't want to have a __main__ block?
As expected, here's a quick Mastodon.py release that fixes some issues people found, mostly pagination related. Upgrading from 2.0.0 to this should be perfectly safe, it's bugfixes only~ Thank you to everyone who reported an issue or even contributed a PR to immediately fix it <3 🐍
If you ever find yourself in the position to calculate mean sea surface temperatures using Python from global netCDF4 data provided by the National Oceanic and Atmospheric Administration (NOAA), here you go:
#Pyparsing API going back to version 1.0.0 (2003) has used a camelCase name scheme for its methods and argument names. In versions 3.0-3.1 (Oct 2021-Jun 2023), I added PEP8-compliant snake_case names, while maintaining synonym definitions for the legacy names for backward compatibility.
Soon, pyparsing will begin emitting DeprecationWarnings for the legacy names. To ease this transition, the next release 3.2.2 will include a utility to convert in place scripts that use the legacy names. #python
ALT text detailsscreenshot of the data art gallery website showing a grid of data art examples, including bob ross painting colours, and orca sightings.
It's our full program! 18 talks, a mix of talks sharing the joy of #Python, and broader topics that we think are super-important for the moment we're in right now.
It's our full program! 18 talks, a mix of talks sharing the joy of #Python, and broader topics that we think are super-important for the moment we're in right now.
As expected, here's a quick Mastodon.py release that fixes some issues people found, mostly pagination related. Upgrading from 2.0.0 to this should be perfectly safe, it's bugfixes only~ Thank you to everyone who reported an issue or even contributed a PR to immediately fix it <3 🐍
As expected, here's a quick Mastodon.py release that fixes some issues people found, mostly pagination related. Upgrading from 2.0.0 to this should be perfectly safe, it's bugfixes only~ Thank you to everyone who reported an issue or even contributed a PR to immediately fix it <3 🐍
Hey everyone, what's cooking in the open-source universe? 🤯 I just stumbled upon something that's seriously mind-blowing.
So, there's this Python library pretending to be a music tool (automslc), but get this – it's actually illegally downloading songs from Deezer! And the worst part? It turns your computer into an accomplice in a huge music piracy operation. Seriously, a digital pirate cove. 🏴☠️
And then there's this npm saga with @ton-wallet/create... Crypto wallet emptied, just like that! 💸
The moral of the story? Open source rocks, but blindly trusting everything is a recipe for disaster. Always double-check those dependencies! Automated scans are cool, but a real penetration test? That's pure gold. 🥇
Clients are always so appreciative when we can spot and fix this kind of stuff beforehand!
Now, I'm curious: What are your go-to methods for keeping your codebase squeaky clean and secure? Any tips or tricks you'd like to share?
"A few years ago, I encountered a situation with my personnal computer. Overnight, it started mounting my /home as read-only. Everything seems to indicate that my hard drive was about to fail. I was doing regular backups, but not nearly often enough… After making an emergency backup and changing the falty disk, it was time to consider a more reliable solution…"
Inspired by a woodland hike under the first blue skies we've seen this year, I got home and showed my kiddo how to draw an #svg tree with recursive #python functions. The shape is very sensitive to parameters like the factors by which each branch is thinner and shorter than its parents, but we tuned them until our results looked like the trees we'd seen in the afternoon. #GenArt
ALT text detailsVector graphics of clear blue skies behind the dark silhouette of a winter leafless fractal tree, bifurcating iteratively from a stout trunk to a flurry of tiny twigs.
I spent last week in Valtournenche with @antocuni and Hood Chatham and managed to use SPy to accelerate my #Python code in the browser. It's too early for general adoption, but not too early to get excited.
I spent last week in Valtournenche with @antocuni and Hood Chatham and managed to use SPy to accelerate my #Python code in the browser. It's too early for general adoption, but not too early to get excited.
I spent last week in Valtournenche with @antocuni and Hood Chatham and managed to use SPy to accelerate my #Python code in the browser. It's too early for general adoption, but not too early to get excited.
Does anyone out there on the fediverse happen to know how I could embed Sparkle in a #macOS#Python application using #PyObjC and packaged with #Py2App ? I gather that the --frameworks option is involved, but … is it just as simple as downloading the bundle from https://github.com/sparkle-project/Sparkle/releases/tag/2.6.4 and then pointing the `--frameworks` option at the `.framework` dir in there? If I do that, what is the right incantation to get some pyobjc bindings packaged and finding it both in dev and in dist?
You really do need to get your talk proposal submitted today! To help get my fellow procrastinators inspired, I’ve provided my own selection of favorite barn cat conference photos from the past year’s event.
You don’t want to miss it, and the best way to make that happen is to propose a talk that we want to hear!
ALT text detailsA very fluffy tan and black cat laying on its side on top of a picnic table, next to a person using their laptop.
ALT text detailsAn extremely fluffy cat sitting upright on a picnic table gazing into the camera, with conference attendees in the background.
ALT text detailsA shorthair orange and white cat sitting between two people at a picnic table patiently waiting for someone to share their delicious BBQ lunch.
You really do need to get your talk proposal submitted today! To help get my fellow procrastinators inspired, I’ve provided my own selection of favorite barn cat conference photos from the past year’s event.
You don’t want to miss it, and the best way to make that happen is to propose a talk that we want to hear!
ALT text detailsA very fluffy tan and black cat laying on its side on top of a picnic table, next to a person using their laptop.
ALT text detailsAn extremely fluffy cat sitting upright on a picnic table gazing into the camera, with conference attendees in the background.
ALT text detailsA shorthair orange and white cat sitting between two people at a picnic table patiently waiting for someone to share their delicious BBQ lunch.
Are there any good web accessibility checkers for python? We have received some really helpful feedback from blind and visually impaired people and I wanted to honor their time by adding tests to prevent regression, and i am finding I am wanting to write a bunch of the WCAG guidelines as selenium tests in pytest. I know that a lot of the guidelines can't necessarily be automated, but stuff like "all images have alt, headers are in correct order and start at h1, buttons have labels," etc. Can be. I figured there should be some tool that I can point at a webpage and be like "tell me whats busted here" like I can to some extent with the Firefox accessbility properties inspector but am not finding any. Any tips?
Are there any good web accessibility checkers for python? We have received some really helpful feedback from blind and visually impaired people and I wanted to honor their time by adding tests to prevent regression, and i am finding I am wanting to write a bunch of the WCAG guidelines as selenium tests in pytest. I know that a lot of the guidelines can't necessarily be automated, but stuff like "all images have alt, headers are in correct order and start at h1, buttons have labels," etc. Can be. I figured there should be some tool that I can point at a webpage and be like "tell me whats busted here" like I can to some extent with the Firefox accessbility properties inspector but am not finding any. Any tips?
PICTURE: Poppy Barn-cat is demanding to know why you haven't submitted a talk proposal for #NBPy yet, and also reminds you that you need to do so by Friday.
ALT text detailsPoppy, the orange-and-white barn cat, standing on a polished indoor concrete floor, which is reflecting blue skies from the top of the photo, has a very loud meow face and is looking at you.
You feel compelled to aquiesce to her demands, whatever they may be.
I've messed around with programmatic graphics to display on a 1.8" TFT panel connected to my Pi Cluster. Each node runs a cronjob of a python script to capture state into a .json file while a master node fetches those json files to then drive the LCD display.
I have a writeup for the whole build process of the Pi Cluster I created:
ALT text detailsA screenshot of a small LCD display showing some system information about four different devices, also demonstrating how the display information changes if a node hasn’t been reached past a predefined timeout period. When this happens the graph is set to all gray and the status text changes to the word DOWN in red.
I have seen careful and pedantic coders build impressive things with python and js while I tend to make a mess that's impossible to maintain. I also waste many hours debugging.
So for me, a strictly typed language leads to long term productivity. I also take on bigger problems with confidence.
Our call for talk proposals is open for another few days (until Friday), but it's already looking like a vintage #NBPy. Why not put your name in and maybe join us?
Started trying to learn Django (again( this evening and got frustrated about how different learning resources use different conventions. It got too confusing for me trying just to set an overall index page that I had to stop.
Why don't tutorials show you how to set up a main index page before diving in to the app part? Why do I have multiple apps in a site and multiple sites in a project? Tell me why we're doing these things!
ALT text details❯ python3.11
Python 3.11.9 (v3.11.9:de54cf5be3, Apr 2 2024, 07:12:50) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cgi
<stdin>:1: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
>>> ^D
❯ python3.12
Python 3.12.9 (v3.12.9:fdb81425a9a, Feb 4 2025, 12:21:36) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cgi
<stdin>:1: DeprecationWarning: 'cgi' is deprecated and slated for removal in Python 3.13
>>>
@simon Here's a real-life application of the new tail-calling interpreter in 3.14.0a5, a full build of the CPython docs is 1.26 times faster, saving 7.5 seconds!
ALT text detailsOutput of hyperfine, one running "make -C Doc clean venv html" with Python 3.14.0a5, the other running 3.13.
The new one averaged 28.457 seconds across 10 runs, the old one 35.985 seconds.
ALT text detailscircles of blues - some larger and other small with fading opacity as you go radially out and larger circles in the center - packed with a little pad.
Did you know that premier #Python talent uses @pycon Sponsors pages as a high-signal "Job Board"? Sponsoring a Python conference shows that your company is serious about Python and wants the community of practitioners to know it! 💜
This is how I found my previous job at #Elastic. Elastic was a Gold tier sponsor for PyCon 2019, thank you Elastic! 👏
So what Python talent are you missing out on by not having your name on this page, both this year and next? 🤔
Did you know that premier #Python talent uses @pycon Sponsors pages as a high-signal "Job Board"? Sponsoring a Python conference shows that your company is serious about Python and wants the community of practitioners to know it! 💜
This is how I found my previous job at #Elastic. Elastic was a Gold tier sponsor for PyCon 2019, thank you Elastic! 👏
So what Python talent are you missing out on by not having your name on this page, both this year and next? 🤔
Today is a good day. I built installers for #Python 3.14.0a5 for both Windows and macOS. My little fix to #xonsh immediately landed in a new release that was immediately picked up by #homebrew. They're also shipping Python 3.13.2. Upgrading was seamless.
I also upgraded to WezTerm yesterday and it's awesome. Images in the terminal? Why not! Let's make one with Alpha 5!
ALT text detailsWezterm with a vertical split. On the left you see bpytop, on the right some code golfing that produces a Mandelbrot set image from a Mandebrot set-looking piece of Python code. Executing with Python 3.14.
#Perl: There is more than one way to do it. #Python: There should be one obvious way to do it. #Nix: There is no straightforward way to do it. #Haskell: There is no way to do it.
We've extended our talk submissions window for another two weeks (until Feb 21st!) If you missed our original opening, fret not, and submit your talk ideas today! https://pretalx.northbaypython.org/nbpy-2025/cfp
Today is a good day. I built installers for #Python 3.14.0a5 for both Windows and macOS. My little fix to #xonsh immediately landed in a new release that was immediately picked up by #homebrew. They're also shipping Python 3.13.2. Upgrading was seamless.
I also upgraded to WezTerm yesterday and it's awesome. Images in the terminal? Why not! Let's make one with Alpha 5!
ALT text detailsWezterm with a vertical split. On the left you see bpytop, on the right some code golfing that produces a Mandelbrot set image from a Mandebrot set-looking piece of Python code. Executing with Python 3.14.
Today is a good day. I built installers for #Python 3.14.0a5 for both Windows and macOS. My little fix to #xonsh immediately landed in a new release that was immediately picked up by #homebrew. They're also shipping Python 3.13.2. Upgrading was seamless.
I also upgraded to WezTerm yesterday and it's awesome. Images in the terminal? Why not! Let's make one with Alpha 5!
ALT text detailsWezterm with a vertical split. On the left you see bpytop, on the right some code golfing that produces a Mandelbrot set image from a Mandebrot set-looking piece of Python code. Executing with Python 3.14.
We've extended our talk submissions window for another two weeks (until Feb 21st!) If you missed our original opening, fret not, and submit your talk ideas today! https://pretalx.northbaypython.org/nbpy-2025/cfp
Who's got a personal site living somewhere other than AWS or Google Cloud? I'm working on a Flask site that I want to launch on a smaller host, so if you're happy with yours, I'd love a recommendation #python#flask
Other credits: - ChatGPT helped me build this. - I’m hosting my bot on @tchambers Indieweb.social instance. - And finally, of course, I’m using @internetarchive's Wayback Machine for the content snapshots.
Other credits: - ChatGPT helped me build this. - I’m hosting my bot on @tchambers Indieweb.social instance. - And finally, of course, I’m using @internetarchive's Wayback Machine for the content snapshots.
Other credits: - ChatGPT helped me build this. - I’m hosting my bot on @tchambers Indieweb.social instance. - And finally, of course, I’m using @internetarchive's Wayback Machine for the content snapshots.
Hello, I'm Spencer Magnusson 👋🏻 CG pipeline engineer by day, Blender enthusiast by night. And weekends. I love solving problems and telling stories with digital mediums and 3D graphics -- animation, code, CGI, games.
Proud husband and father. Singleplayer gamer but terribly slow in catching trends. Past experience in web development and visual effects, both short films and TV.
Plus le temps passe et plus je trouve que le système de visibilité de Java/Kotlin (internal/private/public) est mauvais. Je préfèrerais un système à la Python où la visibilité n'est qu'indicative mais le langage ne t'empêche pas d'aller mettre tes mains dans les entrailles du système.
Combien de fois j'ai pu patcher des bugs ou des fonctionnalités manquantes dans Django parce que Python me le permettait ?
All languages have life cycles. Hell, some even go dormant and become popular — or unexpectedly critical – again.
What would qualities would a language need to have to eventually threaten Python's dominance? My fear is any innovative ideas will just get absorbed. Yes, I realize much of #Python's muscle is marketing by big industry players.
I'm a #Programmer/#SoftwareEngineer. I'm most fluent in #Python, have some basics in #Java and #C++, but I'm also taking up new languages like #Javascript and others in my eternal journey of getting better and minimising the impostor syndrome that befalls pretty much all programmers (I feel). I'm also very experienced in #CloudNative/#DevOps technologies, and have been the one devising solutions and maintaining infrastructure in a fast-paced startup environment in my previous employment.
I'm passionate in what I do and those that know me here or IRL would know that I'm always yapping about the things I'm learning or working on - I love discussing them, and I love helping people out - esp those on the same boat as me.
This passion has led me into writing and maintaining tons of #FOSS projects like Mango: a content distribution framework based on #Django for #Mastodon and #Bluesky that powers various bots of mine like @lowyat@mastodon.social and @waktusolat@mastodon.social, Charts: a #Helm chart repository for an easy and reproducible deployment strategy for all my projects and everything else I self-host on my #homelab, and Orked: O-tomated #RKE2 distribution, a collection of scripts I wrote that are comprehensively documented to enable everyone to self-host a production-grade #Kubernetes cluster for absolutely free in their homes.
I'm based in Malaysia, but I'm open to just about any on-site, hybrid, or remote job opportunities anywhere. In the meantime though, I'm actively looking for a job in countries like #Japan and #Singapore, in a bid for a desperate lifestyle change. I've linked below my Portfolio (which you too, could self-host your own!), for those who'd wish to connect/learn more of me. Thank you ❤️
I'm a #Programmer/#SoftwareEngineer. I'm most fluent in #Python, have some basics in #Java and #C++, but I'm also taking up new languages like #Javascript and others in my eternal journey of getting better and minimising the impostor syndrome that befalls pretty much all programmers (I feel). I'm also very experienced in #CloudNative/#DevOps technologies, and have been the one devising solutions and maintaining infrastructure in a fast-paced startup environment in my previous employment.
I'm passionate in what I do and those that know me here or IRL would know that I'm always yapping about the things I'm learning or working on - I love discussing them, and I love helping people out - esp those on the same boat as me.
This passion has led me into writing and maintaining tons of #FOSS projects like Mango: a content distribution framework based on #Django for #Mastodon and #Bluesky that powers various bots of mine like @lowyat@mastodon.social and @waktusolat@mastodon.social, Charts: a #Helm chart repository for an easy and reproducible deployment strategy for all my projects and everything else I self-host on my #homelab, and Orked: O-tomated #RKE2 distribution, a collection of scripts I wrote that are comprehensively documented to enable everyone to self-host a production-grade #Kubernetes cluster for absolutely free in their homes.
I'm based in Malaysia, but I'm open to just about any on-site, hybrid, or remote job opportunities anywhere. In the meantime though, I'm actively looking for a job in countries like #Japan and #Singapore, in a bid for a desperate lifestyle change. I've linked below my Portfolio (which you too, could self-host your own!), for those who'd wish to connect/learn more of me. Thank you ❤️
@xandra I'm so happy that someone's doing what I wanted to[1]. I'd be happy to write as well as contribute during review process if someone needs contributions.
Sadly, I've decided to post what I have worked on for #FlakeMag in my blog, but in the spirit of 5th code jam[2], I could write a how-to article about setting up swarms of virtual machines on #Linux.
Alternatively, I can write an entry-level article about how to archive web pages and scrape stuff easily with #python (ugh) and/or #typescript.
Even more alternatively, as the most "good-interenetey" option, I can write an article about how and why to use #zulip for team and community management: guidelines, topic structures, etc.
Accuracy! To counter regression dilution, a method is to add a constraint on the statistical modeling. Regression Redress restrains bias by segregating the residual values. My article: http://data.yt/kit/regression-redress.html
New OS. (My /home is a separate partition, but everything else is new.) New year (of the Snake). I wanna do things right from now on and run every Python thing in a venv and what not. Can I just, like, delete the ~/.local/lib/python-3*/site-packages directories and start over and be fine? I am okay with reinstalling everything.
(I'm not talking /usr/local/lib. JUST the stuff in my home directory.)
So I prepared a treasure hunt for my older daughter, which involved some form of coded message. I found a braille table I could 3D-print, using a real system instead of some made-up code gave me the opportunity to explain how/why this was used in reality, you find braille codes in lifts, staircase handrails.
Here are some emojidentifiers for your next Python code:
import math 乁_ツ_ㄏ = None 乁_益_ㄏ = math.nan
def minnums(values: list | 乁_ツ_ㄏ = 乁_ツ_ㄏ): if ( values is 乁_ツ_ㄏ or not all(isinstance(n, (float, int)) for n in values) ): return 乁_益_ㄏ return min(values)
There is some beauty in the fact that my oldest #Python project `first` is still in the top 1% of PyPI. The last release was six years ago, I don’t expect another one ever again, and yet its functionality never made it into the standard library due to gatekeeping.
this work was done by my teammate Facundo and is part of a larger multi-year arc of work dedicated to landing security and usability improvements on PyPI:
If you are familiar with python development, join the offpunk-devel list to help intregrate offpunk and unmerdify, a new library developed by @vjousse :
this work was done by my teammate Facundo and is part of a larger multi-year arc of work dedicated to landing security and usability improvements on PyPI:
Any #Blind programmers out there, I am seeking help. You see, one of my biggest projects was to learn how to code using #Python, but I don't know where to get started in an accessible way. I am looking to find accessible resources so that I can learn how to do this in a viable way, and I need help to find some as I've done my own research and can't really determine which ones are the best to use to get started with learning. Any help would be appreciated for sure.
If you are familiar with python development, join the offpunk-devel list to help intregrate offpunk and unmerdify, a new library developed by @vjousse :
Any #Blind programmers out there, I am seeking help. You see, one of my biggest projects was to learn how to code using #Python, but I don't know where to get started in an accessible way. I am looking to find accessible resources so that I can learn how to do this in a viable way, and I need help to find some as I've done my own research and can't really determine which ones are the best to use to get started with learning. Any help would be appreciated for sure.
I was tasked with a lot of the #innovation happening in my previous company, researching tools, librairies, patterns or general technologies either for our own #DeveloperExperience or for our products
I also wrote a lot of technical and non technical documentation and internal presentations, and even participated in a few meetups. You can read some of my writing on my blog: https://blog.adrianc.eu
You might also have seen me on a few Elixir-related Discord servers, or even Bluesky (@adrianc.eu) and Twitter ; either sharing tech news, helping people, reading in book clubs or just chatting
I’m open to full-time right now, contracting work can be discussed.
I'm looking for any developer position, not only #ElixirLang, even though it represents most of my experience. And if the technology you're using isn't on my resume, give me a chance! I'm a fast learner and I might anyway have studied it in class :P
DM me for more info, like github link, my resume or anything :)
I was tasked with a lot of the #innovation happening in my previous company, researching tools, librairies, patterns or general technologies either for our own #DeveloperExperience or for our products
I also wrote a lot of technical and non technical documentation and internal presentations, and even participated in a few meetups. You can read some of my writing on my blog: https://blog.adrianc.eu
You might also have seen me on a few Elixir-related Discord servers, or even Bluesky (@adrianc.eu) and Twitter ; either sharing tech news, helping people, reading in book clubs or just chatting
I’m open to full-time right now, contracting work can be discussed.
I'm looking for any developer position, not only #ElixirLang, even though it represents most of my experience. And if the technology you're using isn't on my resume, give me a chance! I'm a fast learner and I might anyway have studied it in class :P
DM me for more info, like github link, my resume or anything :)
Looking at PyPI download stats and Google Trends, it seems like Pipenv still has a very significant user base, albeit a stable one. But my sense of the zeitgeist is that it's not being adopted for new projects as much. What's your sense?
Looking at PyPI download stats and Google Trends, it seems like Pipenv still has a very significant user base, albeit a stable one. But my sense of the zeitgeist is that it's not being adopted for new projects as much. What's your sense?
Last week I reported about some #pandas accesors I released (#UnPaAc, #NuPaAc). Over the weekend, I thought about a generic approach to making class methods and properties available via series accessors, and wrote a prototype. I stuck to my naming pattern and called it "Dynamic Pandas Accessors" #DynPaAc.
Donc moi c'est Chloé, trans MtoF en évolution lennnnte (et non, je ne l'ai pas découvert il y a 3 mois, mais bien il y a 35 ans).
Comme avec ma génération il n'y avait *aucune* information sur la transidentité (rappel, le web n'existait pas); J'ai appris à me détester en interne et accepter cette enveloppe honnis comme identité publique. Donc le mégenrrage, l'appel par le dead-name, ça m'ennuie fort, mais j'en fait pas un drame.
J'orbite dans le développement logiciel (pas front), #fosdem , #python , #c++ . En ajoutant une pointe de SCRUM master et de manager.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
Hey all! I'm due for an (re-)introduction: I'm Jack, an engineer in the NYC area from a firmware & cybersecurity background, currently working in something like hardware-software co-design.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
RIP to Python core developer Michael Foord, who wrote & maintained the unittest.mock module, and suggested holding the Language Summits, which have ever since been an annual event at PyCon US.
Aunque llevo años por aquí, ésta es mi #presentación.
Soy ingeniero de software con +20 años programando en #PHP, haciendo mis pinitos en #NodeJS, #Python y #Golang, y trabajo en remoto desde 2007.
Escribí durante años en blogs profesionales (e incluso un libro), empecé en el #podcasting en el 2007 con @kafelog y madrugo para ir a hacer #fitboxing.
Me gusta la tecnología, comer bien, el café, el vermú, la ciencia ficción, el terror cósmico y las zapatillas.
Hallo! Ich lerne Deutsch und Python (101 haha) und möchte beides verbessern. Hat jemand eine Empfehlung für Ressourcen für mich? Zum Beispiel w3schools, aber auf Deutsch? Dankeschön! #Python
Hallo! Ich lerne Deutsch und Python (101 haha) und möchte beides verbessern. Hat jemand eine Empfehlung für Ressourcen für mich? Zum Beispiel w3schools, aber auf Deutsch? Dankeschön! #Python
So there was a time when if you wanted compiled extensions in your Python project, but you didn't want to install a _package_, you'd have a setup.py, and you'd do:
python setup.py build_ext -i
Thing is, calling setup.py directly is now deprecated.
Is there any way to do the above that isn't calling setup.py? I've seen a suggestion of calling setuptools internal API directly, which ... ok, I guess. But wondering what people do in practice. Just make everything compiled an installable package?
"pip install -e ." is not equivalent! E.g. if you're using setuptools-rust it will build in non-release mode.
EDIT: To clarify, what are people using setuptools doing? I understand other tools may have options for this.
TIL that the `uv pip install` is partially faster because it doesn't compile the bytecode for Python packages it installs.
Specifically, it has the opposite behavior of `pip install`: you can ask for byte compilation, it's opt-in rather than pip's opt-out. It actually uses more CPU than pip when you do bytecode compilation! Still faster on my computer cause I have lots of CPUs, but in CI it'd be slower I suspect.
Lack of bytecode compilation means slightly slower startup the first time you run the program (or _every_ time if you're using a Docker image and didn't opt-in to bytecode compile). Probably still worth it given how much faster uv is in other ways.
TIL that the `uv pip install` is partially faster because it doesn't compile the bytecode for Python packages it installs.
Specifically, it has the opposite behavior of `pip install`: you can ask for byte compilation, it's opt-in rather than pip's opt-out. It actually uses more CPU than pip when you do bytecode compilation! Still faster on my computer cause I have lots of CPUs, but in CI it'd be slower I suspect.
Lack of bytecode compilation means slightly slower startup the first time you run the program (or _every_ time if you're using a Docker image and didn't opt-in to bytecode compile). Probably still worth it given how much faster uv is in other ways.
PLEASE, do not ever automatically "fix" a problem by invoking pip. Give me an error message and suggest a command to me, if you think that command is appropriate.
I cannot overstate how badly this well-meaning but extremely poorly-implemented idea goes wrong when it does go wrong.
Je suis développeur, principalement #Python, #JavaScript et parfois C et ASM (surtout sur #GameBoy). Je suis aussi adminsys #Linux.
Je dev pas mal de logiciels libres et #OpenSource. Ça va de l'outil de configuration de souris gaming au générateur de playlist en passant par de l'optimisation d'images ou du shell PHP *hum*…
J'ai également un blog sur lequel je poste surtout du contenu technique mais j'aimerais bien diversifier un peu les sujets à l'avenir.
In #Python, @classmethod can used to create alternate constructors for making objects in other ways. Here's a simple example:
ALT text detailsAn example class called Pet with an alternate constructor. Full text at https://gist.github.com/nedbat/b83352b2e20e0dc297ea99a37e172a8c
Some things I'm especially proud of in plusminus (my Python package for parsing and evaluating infix notation arithmetic): - |absolute value| expressions - ° symbol as a unary postfix operator, to convert degrees to radians: sin(π/2) vs. sin(90°) - exponents ² and ³ - √ and ³√ operators (both unary and binary, so you can write 2√2) - mathematical constants e, π, φ, and τ - set operators ∈, ∉, ∩, and ∪ - safe eval of untrusted inputs Try it at https://ptmcg.pythonanywhere.com/plusminus #python#parsing#infix
I do some consulting on the side, and a fun bit of a recent project was to use pyparsing in Python to evaluate an algebraic expression that could include dice and variables. So 2+3d6-sin(foo^2) would be a valid expression that should produce a result (assuming that foo contained a value). That was my first time with pyparsing, and it was a joy to work with.
Surprise! I will be streaming some Python programming over at <https://www.twitch.tv/glyph_official/> in a little over 30 minutes. We are all gonna take a couple hours to STOP getting mad and depressed at recent events and START getting mad and depressed about cross-platform GUI #python development
Comparison operators in #Python can be chained together, but using them that way could be controversial. I wrote this this other day:
ALT text detailsChecking two variable are equal and not zero: n_passed == n_tests != 0. Full text at https://gist.github.com/nedbat/6f92fe29bdb47c0a36be0d29f5dd92ae
@wraptile I tried bottle, Flask is a POS. The sample code & libs do not work. I now avoid it and use #Deno instead.
When #AppEngine cost more than $10 and required more API changes (data api) I wrote my own static #HTML engine based on #Jeckyl (#Python) and when the compile times blew out re-wrote it in #Rust.
Static HTML is the fastest & pretty much hack proof. cc @bluetea
ALT text detailsFerrari Festival, Lygon St Melbourne
Last weekend took out the time to see the 2007 Grand Prix Ferrari Festival celebrating the 60th year of Ferrari in Lygon St in Melbourne.
Taken at the corner of Lygon & Argyle Place, Lygon St, near Case Del Gelato. In typical Melbourne style, the weather started warm, got a bit sunny then overcast and rained.
source https://www.flickr.com/photos/bootload/416173287/
ALT text detailsVideo showing two lasers illuminating sensors on the other side of H0-scale train tracks. The sensors are read by a micro:bit board that measures and displays the speed of the train converted to real scale. A 4-car SBB passenger train pulled by an Re460 locomotive goes by at 209km/h.
ALT text detailsVideo showing two lasers illuminating sensors on the other side of H0-scale train tracks. The sensors are read by a micro:bit board that measures and displays the speed of the train converted to real scale. A 4-car SBB passenger train pulled by an Re460 locomotive goes by at 209km/h.
Avis aux pythonistes en herbe, voici une initiation à #Pyxel, framework #Python pour créer des jeux à l'ancienne, comme sur la SNS ou la Gameboy Color.
Un éditeur de média est fourni.
Le moteur en #rust assure la fluidité, et l'API python est minimaliste.
Les jeux tourneront sur Linux/Mac/Windows et même dans un navigateur web, avec #wasm
I do some consulting on the side, and a fun bit of a recent project was to use pyparsing in Python to evaluate an algebraic expression that could include dice and variables. So 2+3d6-sin(foo^2) would be a valid expression that should produce a result (assuming that foo contained a value). That was my first time with pyparsing, and it was a joy to work with.
If a new year means a new open source #CMS for you, give Wagtail a try. With the power of #Python and a polished editing experience, we got a lot to offer people who need to manage custom #content at scale.
If a new year means a new open source #CMS for you, give Wagtail a try. With the power of #Python and a polished editing experience, we got a lot to offer people who need to manage custom #content at scale.
I just read there is a more accurate way to calculate a dog's age in human years than simply multiplying by 7 (which does produce a lot of oddities, especially when it comes to dogs giving birth at "7" years old lol). The progression through the first, second and then subsequent years are handled in a manner that is much closer to how dogs typically age compared to humans.
Here are #lisp and #python functions demonstrating the new calculations. Feel free to use them as you wish. Especially if you have one or more dogs.
Feel free to improve or comment on the code in the comments or elsewhere. I always post these kinds of functions for conversation and community, I'm just learning python, so don't bark too loudly.
The formats are:
(dogs-age years months) and dogs_age(years, months)
There is no error checking, so use zeros when necessary.
(defun dogs-age (years months) "Calculate the human age equivalent of a dog given its age in years and months." (let ((human-age 0)) (cond ((< years 1) (setq human-age (* (/ months 12.0) 15))) ((= years 1) (setq human-age (+ 15 (* (/ months 12.0) 9)))) ((>= years 2) (setq human-age (+ 15 9 (* (- years 2) 5) (* (/ months 12.0) 5))))) human-age))
def dogs_age(years, months): """ Calculate the human age equivalent of a dog given its age in years and months. """ if years < 1: human_age = months * (15 / 12) elif years == 1: human_age = 15 + months * (9 / 12) else: human_age = 15 + 9 + (years - 2) * 5 + months * (5 / 12)
return human_age
Hey, @praetor you might be interestd in this, even if it isn't about cats. If you change the subsequent years from 5 to 4, it'll work for cats just the same, apparently.
ALT text detailsA classic "synthwave sunset" with a hilly wireframe horizon and a segmented burning setting Sun in the middle. The road in the middle is flat, we're flying over it.
ALT text detailsA classic "synthwave sunset" with a hilly wireframe horizon and a segmented burning setting Sun in the middle. The road in the middle is flat, we're flying over it.
@wraptile I tried bottle, Flask is a POS. The sample code & libs do not work. I now avoid it and use #Deno instead.
When #AppEngine cost more than $10 and required more API changes (data api) I wrote my own static #HTML engine based on #Jeckyl (#Python) and when the compile times blew out re-wrote it in #Rust.
Static HTML is the fastest & pretty much hack proof. cc @bluetea
ALT text detailsFerrari Festival, Lygon St Melbourne
Last weekend took out the time to see the 2007 Grand Prix Ferrari Festival celebrating the 60th year of Ferrari in Lygon St in Melbourne.
Taken at the corner of Lygon & Argyle Place, Lygon St, near Case Del Gelato. In typical Melbourne style, the weather started warm, got a bit sunny then overcast and rained.
source https://www.flickr.com/photos/bootload/416173287/
Back in 2008, I whipped up this site with two hundred line hack using a newly created web framework called web.py and a brand new google project, App Engine. From 2008 to today, that’s how #seldomlogical worked.
From the user perspective it looked like plain HTML pages being served. Behind the scenes, code read markdown and converted it to HTML.
❝ Every time my blog ran, a little bit of Aarons code would execute
This was prior to the various web frameworks for python we take for granted today. Web.py utilised WSGI and I chose googles new toy, GAE to run it.
ALT text detailsAn autumn day in 2015 walking in the bush. Bracken in the foreground, trees behind framing a sharp blue sky.
source https://flickr.com/photos/bootload/17091172186
More than iron, more than lead, more than gold I need electricity. I need it more than I need lamb or pork or lettuce or cucumber. I need it for my dreams.
Originally offered as an AI, it is actually just a compositor with a rich set of templates.
Earlier today I posted about a spoof site of mine on #pythonanywhere, 𝐹º𝑛t 𝘔ⅸᵉ𝐫, which converts identifiers in ASCII #Python to equivalent identifiers by randomly selecting Unicode points that normalize back to the original ASCII, and are therefore directly runnable, even though they look like a ransom note. Remember, builtins and all stdlib names can be denormalized this way.
A Python script to convert WordPress blog posts to Markdown files for @obsidian. The script fetches posts from WordPress RSS feeds and organizes them into a year/month folder structure.
With the latest 3.2.1 release of pyparsing, I also cleaned up the README for the examples directory. Much improved over the hand-coded HTML from 20+ years ago!
Hi! 👋 Ich bin nicht wirklich #neuhier, aber gerade wieder von einer Sharkey-Instanz zurückgezogen und hatte bisher ohnehin kein neuhier-Posting. Im echten Leben ursprünglich aus #Karlsruhe und inzwischen mit der Lieblingsmenschin wohnhaft in #Norderstedt fühle ich mich eigentlich als #Hamburg|er. Das Futter für meine Mischlingshündin 🐶 (folgt dem #Hundenasenmontag!) verdiene ich mit #IT-Security, #Python und der #ISO27001. Privat verbringe ich die Nächte gerne auf den diversen norddeutschen #Grufti-Tanzflächen oder auf den einschlägigen Festivals 🦇. Musikalisch darf es dabei gerne schwarz, elektronisch und schnell sein. Auch sonst mag ich viel Schwarzes (fritz-kola, Klamotten, Humor, ...), aber keinen Kaffee.
ALT text detailsgrid map of europe. Each country is represented by a big circle and positioned approximately generating a geometric grid. Each circle is coloured by the first letter of their ISO name. Names are grouped into five categories: A-C (Black), D-G (Yellow), H-L (Red), M-Q (Pink), R-Z (Blue)
ALT text detailsgrid map of europe. Each country is represented by a big circle and positioned approximately generating a geometric grid. Each circle is coloured by the first letter of their ISO name. Names are grouped into five categories: A-C (Black), D-G (Yellow), H-L (Red), M-Q (Pink), R-Z (Blue)
I'm restarting my job search; I had an offer, but it fell through.
Remote US preferred, but hybrid Washington, DC works too. I have 17-ish YOE as a software engineer, and have worked on both frontend and backend, but I lean toward the backend.
I'm looking for an open source text-to-speech library I can run locally or in a server. I needs to be pretty pleasant to listen to even if generation takes a bit longer. Ideally #python as the language but I'm open to looking around.
I'm looking for an open source text-to-speech library I can run locally or in a server. I needs to be pretty pleasant to listen to even if generation takes a bit longer. Ideally #python as the language but I'm open to looking around.
I just released pyparsing 3.2.1 with a very cool addition to the railroad diagrams that pyparsing generates for its parsers - non-terminal diagram elements now link to their definitions elsewhere in the diagram! This is pretty handy when the diagram is for a complex parser, as in this demo of a parser/evaluator for time references like "3 weeks from today" or "0800 two days from now" or "in exactly twenty-four hours". #pyparsing#python#parser#railroaddiagram
ALT text detailsVideo showing navigation through a complex parser railroad diagram. Clicking on a non-terminal diagram element links to that element's definition!
I just released pyparsing 3.2.1 with a very cool addition to the railroad diagrams that pyparsing generates for its parsers - non-terminal diagram elements now link to their definitions elsewhere in the diagram! This is pretty handy when the diagram is for a complex parser, as in this demo of a parser/evaluator for time references like "3 weeks from today" or "0800 two days from now" or "in exactly twenty-four hours". #pyparsing#python#parser#railroaddiagram
ALT text detailsVideo showing navigation through a complex parser railroad diagram. Clicking on a non-terminal diagram element links to that element's definition!
ALT text detailsPrinting "Happy New Year 2025" with two different sums and powers using range(10). Full text at https://gist.github.com/nedbat/7eb9222bf0d3466f2bbf6381ccaf89ec
When I recently published a post on Mastodon, it had already been reposted 6 times within 2 minutes. Out of curiosity, I visited the profiles and noticed that at least one of them was a bot profile: How can bots on a platform make our everyday lives easier? And what are the risks? How I can use the Mastodon API to create a bot myself?
In this article, I provide a step-by-step guide with code examples and screenshots on how to create a Mastodon bot with Python and use the API.
@norbu I feel your pain, every new version means a lot of updating stuff and I always forget something that bites me later.
However, that usually happens between "major" versions (3.xx) and not minor ones (e.g. 3.13.xx). CPython doesn't use semver, so what looks like minor versions are actually major versions.
If you are having trouble between minor versions that's worth filling an issue, and I can do that for you if you want.
Another Python upgrade on my system, another set of many many packages that got broken. Why do #python devs don't understand the concept of **compatibility**. Linux does it. Perl does it. Windows does it. Python ... let me break everything every fu**ing minor version! #FAIL
I want to give huge thanks to everyone who supported all of us through this, who jumped in and had some really amazing discussions weighing all sorts of interesting trade-offs.
The end result is absolutely not something any one person could've reasonably come up with.
I hope y'all enjoy it <3
As part of this release, several implementations have already launched with full support for v2.0.0, so you can try it now!
There are around 8k .kdl files out on GitHub, which is a lot considering it's usually a config language!
I fully expect this to be the last version of KDL ever released. We really really tried, but I don't think there's anything we can reasonably improve on.
From here on out, the language is in the (stable!) hands of the ecosystem.
Also, we're hoping to have GitHub syntax highlighting support soon!
(Boosts welcome!!)
ALT text detailssyntax-highlighted zellij config ported to 2.0.0 format.
// This config is just like `zellij.kdl`, except it shows what it would look
// like if modifiers were done using `+` instead of spaces (thus needing to be
// quoted).
keybinds {
normal {
// uncomment this and adjust key if using copy_on_select=#false
/- bind Alt+c { Copy }
}
locked {
bind Ctrl+g { SwitchToMode Normal }
}
resize {
bind Ctrl+n { SwitchToMode Normal }
bind h Left { Resize Left }
bind j Down { Resize Down }
bind k Up { Resize Up }
bind l Right { Resize Right }
bind "=" + { Resize Increase }
bind - { Resize Decrease }
}
pane {
bind Ctrl+p { SwitchToMode Normal }
ALT text detailsa section of a syntax-highlighted example KDL document based on a GitHub Actions yaml configuration, ported to KDL 2.0.0.
steps {
step uses="actions/checkout@v1"
step "Install Rust" uses="actions-rs/toolchain@v1" {
profile minimal
toolchain "${{ matrix.rust }}"
components clippy
override #true
}
step Clippy { run cargo clippy --all -- -D warnings }
step "Run tests" { run cargo test --all --verbose }
step "Other Stuff" run="""
echo foo
echo bar
echo baz
"""
}
I’ve never understood or written #ruby bindings to other languages. But now, I’ve found motivation. The #taffy UI library written in #rust looks amazing, and #stretchable is a #python binding for it. Can anybody recommend books, videos, or other resources to learn the skills I’d need to write Ruby bindings for it?
ALT text detailsAnimation of rotating colored stars that grow and become transparent, in an attempt to create the illusion of the stars approaching the viewer.
ALT text detailsTwo cats are by a sliding glass window. The one towards the top of the frame (named Ophelia) is laying on a heat pad and staring at the second cat. The second cat (named Maya) is towards the bottom of the frame. She is sat on the entry rug with her body poked between the blinds on the window, so that she can look outside.
ALT text detailsThere are two cats in frame, near a very small cat tower. On top of the tower, Ophelia is laying down. Below, in a meercat-like pose, is Maya. She is trying to get a better view of the other cat. They didn't know each other very well at this time.
ALT text detailsA gray cat, Maya, is laying on the couch. She is curled up such that her belly and paws are all exposed, though her tail is tucked near her feet. She looks peacefully asleep
ALT text detailsA gray/gray-orange cat is laying on a white blanket. Her name is Ophelia, and she has one eye half open, which is a brilliant green-orange. She is very relaxed. You get the faint impression of a person's legs underneath the blanket
ALT text detailsAnimation of about 25 stars falling in straight lines from the top to the bottom of the image. The stars are randomly colored and sized, and have random numbers of points (from 4 to 8).
A huge thanks to @stefan for publishing the dataset on which we based our analysis!
NOTE: We are absolutely aware that the report has very little actual relevance, as the dataset contains a super limited amount of posts from one instance only. It was mainly an experimentation to test our data analysis skills.
ALT text detailsA geometric pattern created by a star that rotates, moves left to right and back, contracts and expands. The pattern has many points forming an almost circular shape, and it's possible to discern that each point was the point of a star that was drawn before. This image is tan with black lines delineating the old star shapes, all against a black background. Near the center there is a small star with a circle at its center and chubby points, because that's how they get when the star contracts.
ALT text detailsA multicolored geometric pattern created by a star that rotates, moves left to right and back, contracts, expands and changes colors. The pattern has many points forming an almost circular shape with visible layering, and it's possible to discern that each point was the point of a star that was drawn before. This image has many colors as the stars randomly change colors, all set against a black background. Near the center there is a medium star with a circle at its center and medium points, because its in the middle of the expansion-contraction cycle.
ALT text detailsAn animation of a five-pointed tan to pinkish star circumscribed in a circle and both contract and expand. There is a medium red circle behind the star and a yellow circle inside it. The circles and the star move horizontally while expanding and contracting, and the star also slowly rotates.
$ pip3 search something ... RuntimeError: PyPI no longer supports 'pip search' [...]. Please use https://pypi.org/search (via a browser) instead. [...]
Sure, no problem. Let's see …
»JavaScript is disabled in your browser. Please enable JavaScript to proceed.«
Urgh, but okay, #pip is a #Python package manager, they're good guys. Let me just open #NoScript and temporarily allow pypi.org ... oh no, it wants to run #JavaScript from …
So, after being laid off a few months ago, I find myself still looking for work.
If you are looking for a senior software engineer who has specialized in Python work for twenty years, and who has worked in virtually every area of software from embedded firmware to GUI applications, with almost 20 years as a full-time remote employee, contractor, and consultant, I'm available.
Full resume available, references upon request.
If you know someone looking for such, I'd appreciate you referring them to this.
ALT text detailsTerminal showing unit tests running on Python 3.13, all white text on black. Followed by the same in 3.14, which has green dots for passing tests, yellow s for skipped tests, red E for errors. The error tracebacks are now in colour (shades of reds and orange), plus the summary has failures in red and skips in yellow.
Announcing the Partition Principle of #Python Pedagogy:
No matter what you are showing people or how unusual it is, if it uses str.partition() most of the comments will be, "I didn't know about str.partition()!"
PyPI confirms no security flaws were exploited in the Ultralytics supply chain attack and the team is working on two new efforts to nudge developers towards more secure publishing configurations.
If you are interested in supporting my #Python#OpenSource development, or my writing projects on my blog, you can sign up at https://www.patreon.com/creatorglyph and you too will be able to read these weekly updates as well as have a surprisingly significant (BUT FOR LEGAL REASONS, VERY MUCH _NOT_ GUARANTEED) influence over which things I focus on at various times!
I discovered #pyinfra, and now I want to use it. It's like skipping using #yaml in #ansible. Similar to #fabric, but less low level. 😅
With pyinfra, you still have things like ansible roles abstractions. But you write your roles all in #python. 😎 All I know is here I go again with this rabbit hole. 🫠
ALT text detailsA Python function to unpack ranges like "1-5,7,9,10-13" into a list of numbers. Full text at https://gist.github.com/nedbat/01fe96aac4a7d35bbd95e0fe9d5c6649
#python Dec11 import numpy as n,PIL.Image as I p,A,h=2**-11,n.abs,.5 y,x,_=n.mgrid[h:-h:-p,-h:h:p,0:3] def W(x,y,z): s,d,w,e,l=1.5,x*0+9,2,.4,x*0 for i in range(1,9): g=((x*x+y*y+z*z)**h)-w l[g<d],d[g<d]=i,g[g<d] w*=e u=s*w x,y,z=A(x)-u,A(y)-u,A(z)-u return d,l t,r=y<1,.71 z=y*.0-6 s=(x*x+y*y+1)**-h u,v=x*1,y*1 while t.any(): d,l=W(r*u-r*z,v,r*u+r*z) n=d>.01 t&=n&(z<9) u[t],v[t],z[t]=(u+x*s*d)[t],(v+y*s*d)[t],(z+s*d)[t] I.fromarray((39*l*x*[7,3,9]*~n).astype('B')).save("d.png")
ALT text detailsA colourful 3D fractal made up from spheres all different colours, with smaller spheres at each corner. Background is black.
The traditional ETL-Process consist of Extract-Transform-Load. But in tools like Data Cloud from Salesforce there is now the Zero-ETL technology integrated: Instead of requiring these 3 traditional steps, data should now flow seamlessly between different systems.
Open source maintainers are drowning in junk bug reports written by AI - Python security developer-in-residence decries use of bots that 'cannot understand code'
ALT text detailsChart showing the members of each council over time.
This is the fifth year Pablo, fourth for Greg third for Emily, second (in a row) for Barry and first for Donghee.
ALT text detailsThe same chart but including Guido's 28 year stint as BDFL.
If you need an experienced backend developer who likes to get things shipped, please reach out! Main experience is in #Python + #Django, but I am comfortable in all parts of the stack.
A huge THANK YOU to our amazing community for making this event a massive success! 🙌💖 This year, we not only broke all the stats from last year, but we also created unforgettable memories and connections.
Feel free to drop by, but also please feel free to give me some suggestions for what to work on. Last week we had a comedy of errors due to a Patreon subscriber's suggestion that I do some cross-platform GUI work on Pomodouroboros
🔹#FCron support 🔹User manual migrated to a new format and build system 🔹User manual content improved (user callbacks & example scripts) 🔹GUI: English strings and their #translation improved 🔹#Serbian language available in both Latin and Cyrillic scripts 🔹Added #Interlingua (#Occidental) language 🔹Extensive refactoring of the code base 🔹#Python version supported raised to 3.9
I’m really enjoying looking at everyone’s #AdventOfCode. The most interesting part for me is how each language can more easily/naturally solve different aspects of the daily problems. I’m curious to hear from others what they think the strengths/facilities of their chosen language lends to that day’s problem.
Die Leute von @fsfwdresden haben bis zum 06. Januar 2025 noch für ihr #Schulstick Projekt einige Programmieraufgaben zu einer Lernsoftware zu verteilen. Bis dahin läuft noch eine Förderung des sächsischen Kultusministeriums für dieses Projekt. Wer Zeit und Lust hat, gegen eine übliche und angemessene Vergütung einige der zu erledigenden Aufgaben an diesem Projekt umzusetzen kann sich gerne bei der FSFW oder bei schulstick@c3d2.de melden.
Are any of you #Pythonistas aware of an array of sorts that Python processes always keep in memory, with a size of 8 bytes times the applicable nofiles (number of concurrently open file handles) ulimit? I don't know where to start looking/searching. If that rings any bell at all, please holler. Thanks!
Avis aux pythonistes en herbe, voici une initiation à #Pyxel, framework #Python pour créer des jeux à l'ancienne, comme sur la SNS ou la Gameboy Color.
Un éditeur de média est fourni.
Le moteur en #rust assure la fluidité, et l'API python est minimaliste.
Les jeux tourneront sur Linux/Mac/Windows et même dans un navigateur web, avec #wasm
ALT text detailsA latitude/longitude class that can be formatted in various ways. Full text at https://gist.github.com/nedbat/4deeb3c4277bb29bf55bf5fb1d11b33e
Just published #mashumaro 3.15 with the #JSONSchema plugin system! 🎉 I guess the next thing will be plugins for serialization and deserialization. Who knows, maybe this will be my ticket to strict validation and speeding up with #cython. On a side note, I believe I’m among the last developers to discontinue support for #python 3.8.
Buenas! Llevo varios días bicheando en esto del #fediverso y ando bastante asombrada de no haber sabido antes de su existencia. A modo de #presentación decir que suelo usar las redes en modo "voyeur": busco información interesante (o simplemente pasar el rato y dejarme sorprender) y no suelo postear mucho; así que no esperéis demasiado contenido por mi parte, pero si algun que otro like (se dice así por aquí?). Estoy empezando a aprender cositas de #python#git#pandas#sql y #data en general. Cuanto más aprendo más veo que no tengo ni idea de nada, pero me gusta leer tips&tricks y artículos (nivel principiante). Me gusta #cocinar, pero me gusta aún más comer así que si tienes #recetas o recomendaciones de #restaurantes en #Madrid (o cualquier otra ciudad) serán más que bienvenidas. Un saludo!
PyPI's support for PEP 740 now includes GitLab, extending support beyond the initial scope (which was GitHub). that means that, if you're a GitLab CI/CD user, you can now upload attestations to PyPI and the index will verify and re-serve them!
Support PyOhio, a PSF Fiscal Sponsoree, and help #PowerPython! 🐍 This annual, regional PyCon brings together #Python users from the Midwest, with content for all levels—from beginners to experts.
ALT text detailsOn the left side there is "Power Python" text inside of a yellow lightbulb graphic on a blue background. On the right side, a graphic in the shape of Ohio with "Py" inside, underneath It states "Support PyOhio, a Fiscal Sponsoree of the Python Software Foundation! Your donations make all the difference." Python Software Foundation Logo at the bottom.
ALT text detailsPatches the cat (domestic medium hair, white with black tail and black patch over left half of face) sits at a closed door with an expectant look on her face. She believes she could make it in the outside world. She is wrong.
It's a library for creating fuzzers. I've been using it to find crashers in #CPython (23 found so far) and #PyPy (15 found so far).
The #Python#fuzzer works by generating random code with function/method calls using random arbitrary (and interesting) values, then recording code execution and matching specific error messages.
I'm only #fuzzing Python, feel free to use it for whatever you want ;)
ALT text detailsSample output visualization from the Diceplot package.
More detailed description from Claude.ai “A dice plot matrix showing relationships between different pathology variables across brain cell types. The plot compares 10 biological processes (Signal Transduction, Neurotransmitter Release, Apoptosis, Synaptic Transmission, Cell Cycle, Inflammation, DNA Repair, Metabolism, Lipid Metabolism, and Protein Synthesis) against 5 cell types (Microglia, Oligodendrocyte, Endothelial, Neuron, and Astrocyte). Each intersection contains dice symbols showing Cancer (pink/gray), Stroke (gray), and Flu (red) markers. The background of each cell indicates if the relationship is Linked (dark gray), UnLinked (light gray), or Other (white). The visualization helps compare disease impacts across different cellular processes and brain cell types."
ALT text detailsDisplaying multidimensional categorical data often poses a challenge in life sciences to get a comprehensive overview of the underlying data. This is not limited to but holds in particular for pathway analysis across multiple conditions. Here we developed a visualization concept to create easy to understand and intuitive representation of such data. We provide the implementation as python as well as R package to ensure easy access and application.
For loops in #Python can assign to more than just plain names. Any assignment target is allowed:
ALT text detailsUsing `for params["page"] in ...` to move through paged results in a search API. Full text at https://gist.github.com/nedbat/d04b7d1bef5fb84542f23126424c814c
Hey! I'm Thea. I teach digital technologies / mathematics up in Meanjin / Brisbane. In the process of making a website to share all of my resources and lessons (mainly #Python related).
I'm curious what are all those people who got used to shorten to t.Callable, t.Mapping, t.Coroutine etc. going to write instead in the post-python 3.9 era when these imports will eventually be removed?
Write a Python program that creates a new database in a file called original.db containing a single table called Velocity, with a single field called reading, and inserts 100,000 random numbers between 10.0 and 25.0
If you have a large tree-structured #python project in @pycharm where you’ve changed or added many files, you can make it easier to find the modules that need unit tests written or updated by enabling the option to highlight directories with changes. Go to Version Control → Confirmation → Highlight directories that contain modified files in the Project tree. Don’t forget to add new directories or files to your future commit, otherwise they won’t be highlighted.
We've moved to Hetzner (from Digital Ocean) for our hosting. Tests so far show faster bandwidth and CPUs at a fraction of the cost. Details below (#python, cc @mkennedy):
If you are not using any Bash prompt customization yet, install Bash-it now and just switch to inretio theme by adding following to your profile config:
export BASH_IT_THEME='inretio'
Do you use any terminal prompt customizations already?
ALT text detailsInretio theme for Bash-it - shell configuration and prompt customization framework. Showing KDE terminal application Konsole with prompt styled with my theme: timestamp, penguin emoji, username, computer name, current folder are shown along with Python and Python version and venv name, as well as Git branch and status
Today, I organized the CPython sprint as the extension event of PyCon KR 2024: https://2024.pycon.kr Many people in Korea participated in the sprint, and people submitted around 8 PRs during the sprint :) I hope people have experienced the joy of contributing to the OSS project.
“Python becomes the most used language on GitHub, overtaking JavaScript after a 10-year run as the most used language. This is the first large-scale change we’ve seen in the top two languages since 2019…” 🏆
🪑 Add new themes to ColorTable 🪑 Drop support for Python 3.8 🪑 Deprecate hrule and tableStyle constants 🪑 Use SPDX license identifier 🪑 Add lots of type annotations 🪑 Generate __version__ at build to avoid slow importlib.metadata 🪑 Release to PyPI using Trusted Publishing and PEP 703 digital attestations 🪑 Fix drawing headerless coloured tables with title 🪑 And more!
ALT text detailsExamples of two new themes for ColorTable: High contrast has white text, blue horizontal lines, orange verticals and yellow joiners. Lavender has three shades of pink for the text and joiners, verticals, and horizontals.
#Python Pizza is coming to #Brno! 🍕 When? Feb 22, 2025 Where? Clubco, Brno The Call for Proposals is open until November 20, but we are doing a rolling CfP so we may accept talks before the end of the #CfP period! Find all the information here: https://brno.python.pizza/ https://brno.python.pizza/
@pyconasia@mariatta I found role models and a place where I belong when I attended PyLadies lunch. I see people who look like me. Women who code. Asian women who code.
ALT text detailsPSF booth.
A few people behind the booth from PSF. (Kwon Han, Georgi)
The other side are about a dozen Indonesia Python community members.
There's a newsletter and it asked for feedback on the topics you want to see next year - you have until Nov 1st to answer it and make your voice heard.
Hacemos reunión conjunta con MLOps Community Madrid.
El gran Alejandro Vidal nos hablará sobre su desarrollo de una feature store en Python, e Ignacio Peletier y Jesús Lópeznos hablarán sobre métodos psicométricos para evaluar el nivel de inglés.
Inscripciones en nuestro Meetup o en el Luma de MLOps Community Madrid:
ALT text detailsCartel de PyData Madrid, 🛒 Creando una Feature Store y métodos psicométricos para evaluar idiomas, jueves 24 de octubre de 2024, 18:30-20:30, logo the The Bridge
Setting up a new home on a personal instance, just like one of the big kids. 😂
Hi, I’m Daniel. I’m a Product exec, SFF writer, developer, voice actor, TTRPG player, and the producer/GM for the Numenera actual play podcast, Explorers Wanted.
I talk a little bit about all of the above with occasional shitposts for spice.
And once again some person forked an unmaintained #Python package, and published a new version on #PyPI using a different name.
Of course, what they didn't do was: • updating any of the visible metadata to indicate that it's a fork • updating URLs to point to the actual fork • requesting name transfer
And of course, now what we have instead are two different PyPI packages installing the same Python import name, with dozens of packages requiring the metadata to use the original name, and one package requiring it to use the new name.
And I'm too tired to even start working this shit around to bump the package introducing the conflicting dependency in #Gentoo.
ALT text detailsA CLI call of "eol python" showing a coloured table of each Python feature release, its latest x.y.z version and date, and the dates of when it enters security-only and EOL.
Professionally I'm a software developer and that's a topic I care about a lot. How to do it well, how to do it sustainably? I've worked on web backends for a long time and now I'm focused on databases. Used to be active in the #clojure community; now I'm using #python and #rust.
I read a lot, or at least regularly, (classics/literary fiction/sci-fi) and blog a bit. I like #hiking and paddle a #kayak. A year ago I got very into (indoors) #bouldering.
Professionally right now I work as an SME in a #PenTesting group for a regulatory company, but it's really not my bag of tea in the long run. That I can feel. I much prefer to be in an investigatory and tool-making field for something related to #DFIR . I was especially happy doing #ReverseEngineering of #malware .
I'm into reverse engineering, assembly languages like #IA32 and recently #ARM / #ARM64, programming (old classics like C/C++ / #Python but learning the newer stuff like #RustLang ), big into #forensics, #RasPi and #Arduino projects and such.
Still trying to figure out what I am career wise, though, like job title and such! It's all great fun to me, just haven't found the direct niche to sink into.
Hobby wise, I'm also really into #GuildWars2! Long time gamer at heart.
Today I find myself having to parse ~1 million SQL queries (of various complexity) using #python
Here's a runtime of the few options I tried, in case anyone is interested (incidentally, in the order in which I tried them):
- sqlparse: 1h estimated (I killed the process before it finished) - sqlglot: finished in about 15 min, failed to parse about 900 queries. - sqloxide: finished in 2 minutes (!!!), failed to parse 10 queries. 🏆
I know I'm singing to the choir here but as someone that hasn't used Python in my day job until recently, I continue to be happy with its extensibility and usefulness.
It is so obviously built by real people that use it to solve their everyday problems. Parsing files, creating reports, evaluating messy data. Wish I had this in my toolbox sooner.
#python question: is there any library allowing to have a precise JSON formatting? Like indentation but also handling some compact data that can be specified? (neither json nor pprint provide that)
ALT text details11.0.0 (2024-10-15)
Backwards Incompatible Changes
Python 3.8
Pillow has dropped support for Python 3.8, which reached end-of-life in October 2024.
Python 3.12 on macOS <= 10.12
The latest version of Python 3.12 only supports macOS versions 10.13 and later, and so Pillow has also updated the deployment target for its prebuilt Python 3.12 wheels.
PSFile
The PSFile class was removed in Pillow 11 (2024-10-15). This class was only made as a helper to be used internally, so there is no replacement. If you need this functionality though, it is a very short class that can easily be recreated in your own code.
PyAccess and Image.USE_CFFI_ACCESS
Since Pillow’s C API is now faster than PyAccess on PyPy, PyAccess has been removed. Pillow’s C API will now be used on PyPy instead.
Image.USE_CFFI_ACCESS, for switching from the C API to PyAccess, was similarly removed.
TiffImagePlugin IFD_LEGACY_API
An unused setting, TiffImagePlugin.IFD_LEGACY_API, has been removed.
WebP 0.4
Support for WebP 0.4 and earlier has been removed; WebP 0.5 is the minimum supported.
ALT text detailsDeprecations
FreeType 2.9.0
Deprecated since version 11.0.0.
Support for FreeType 2.9.0 is deprecated and will be removed in Pillow 12.0.0 (2025-10-15), when FreeType 2.9.1 will be the minimum supported.
We recommend upgrading to at least FreeType 2.10.4, which fixed a severe vulnerability introduced in FreeType 2.6 (CVE 2020-15999).
Get internal pointers to objects
Deprecated since version 11.0.0.
Image.core.ImagingCore.id and Image.core.ImagingCore.unsafe_ptrs have been deprecated and will be removed in Pillow 12 (2025-10-15). They were used for obtaining raw pointers to ImagingCore internals. To interact with C code, you can use Image.Image.getim(), which returns a Capsule object.
ICNS (width, height, scale) sizes
Deprecated since version 11.0.0.
Setting an ICNS image size to (width, height, scale) before loading has been deprecated. Instead, load(scale) can be used.
Image isImageType()
Deprecated since version 11.0.0.
Image.isImageType(im) has been deprecated. Use isinstance(im, Image.Image) instead.
ImageMath.lambda_eval and ImageMath.unsafe_eval options parameter
Deprecated since version 11.0.0.
The options parameter in lambda_eval() and unsafe_eval() has been deprecated. One or more keyword arguments can be used instead.
JpegImageFile.huffman_ac and JpegImageFile.huffman_dc
Deprecated since version 11.0.0.
See the release notes for more.
ALT text detailsAPI Changes
Default resampling filter for I;16* image modes
The default resampling filter for I;16, I;16L, I;16B and I;16N has been changed from Image.NEAREST to Image.BICUBIC, to match the majority of modes.
API Additions
Writing XMP bytes to JPEG and MPO
XMP data can now be saved to JPEG files using an xmp argument:
im.save("out.jpg", xmp=b"test")
The data can also be set through info, for use when saving either JPEG or MPO images:
im.info["xmp"] = b"test"
im.save("out.jpg")
Other Changes
Python 3.13
Pillow 10.4.0 had wheels built against Python 3.13 beta, available as a preview to help others prepare for 3.13, and to ensure Pillow could be used immediately at the release of 3.13.0 final (2024-10-07, PEP 719).
Pillow 11.0.0 now officially supports Python 3.13.
Support has also been added for the experimental free-threaded mode of PEP 703.
Python 3.13 only supports macOS versions 10.13 and later.
C-level Flags
Some compiling flags like WITH_THREADING, WITH_IMAGECHOPS, and other WITH_* were removed. These flags were not available through the build system, but they could be edited in the C source.
I'm a technology enthusiast from Vancouver Island, BC, Canada. By day I build software used to run #Genomics labs in #Python. I've also worked with #Lua and #PHP in the past. I've worked professionally as a web developer for fifteen years but I've been programming since I was eight (started with #HyperCard)!
I believe #science should be open and accessible, so I write about my ideas on a #Wordpress#blog, review relevant #books on #Goodreads, and publish my source code on #Github (links in my profile).
Keeping Beancount importers up to date often feels like an ongoing game of cat and mouse. Banks can rearrange their CSV exports at any time, leaving maintainers scrambling to update their importers — essentially CSV parsers — to keep up.
On a brighter note, I just published a newer version of beancount-n26. 🤷🏻♂️
🐍 Longtime #Python developer & maintainer of various popular libraries (Fabric, Paramiko, Invoke, &c) 💻 Longtime #Linux (#Unix) #sysadmin & #DevOps engineer (so many distros, currently experimenting with #NixOS) 😻 Owned by 2 #cats (and grew up with #dogs) 🇺🇸🗽 Resident of #NewJersey 🌹🍞 Bit of a #leftist and #antifascist who still votes #Democrat when necessary ⚔️🚀 #SFF fan & much more! ✨
This tool creates backports for CPython when the Miss Islington bot can't, usually due to a merge conflict.
🍒 Add support for #Python 3.13, drop EOL 3.8 🍒 Resolve usernames when remote ends with a trailing slash 🍒 Optimize validate_sha() with --max-count=1 🍒 Remove multiple commit prefixes 🍒 Handle whitespace when calculating usernames 🍒 Publish to PyPI using #TrustedPublishers 🍒 Generate #PEP740 attestations 🍒 And more!
I should probably make a proper #introduction post. So guess now is fine?
Hello! I am Ari Archer. I am an #LGBT 17-year-old #OpenSource#Autistic developer from #Lithuania who likes to mess around with #software, #backend development, and of course my favourite #programming languages: #C (ANSI #C89 is my favourite C standard) and #Python :) I can fuck around in Assembly too, although I tend to think it's not practical in most cases, although I don't do that much low level programming for it to matter, I do enjoy occasional #ProgrammingLanguage development, though.
I have a (shitty) #website on https://ari.lt/ (which I need to re-re-re-write (I need to rewrite it for the 3rd time, the 2nd time was fine I think, but I kinda made it bad now ;-; because it's basically all #JavaScript), I also have a #blog at https://blog.ari.lt/ which I post random #thoughts, #progress, #tutorials, #recipes, etc. on, could I call it #lifestyle content? I don't know. I also like #cats (and I have one named Tina and I love her very much), #cooking, and #researching random things which I yap about to my friends.
I am very pro-#selfhosting and feel like more people should do it, maybe not anything large or mainstream, but at least try to, #learning about things is fun, and self-hosting teaches you a lot, as well as making it easier for people to migrate to #foss easier, which I believe to be a good thing. Most of my beliefs are centred around "by people for people" as in everything should be accessible, open source, and #free as in #freedom.
I hope I enjoy my stay on #fedi these days as I haven't really been on fedi for a while now, in the mean time you can reach me on #email (ari@ari.lt), #matrix (@ari:ari.lt) or #Git/#GitHub (https://ari.lt/gh).
Hi, I'm Doro! I'm a #Physics PostDoc at the Max Planck Institute of Quantum Optics near #Munich, Germany! I play with ultracold atoms in lattices of laser light to simulate other quantum systems! I'm also a fan of open source software (#FOSS), #Linux, and I code in #python for work and for fun! I love SciFi in all forms, especially #StarTrek and #DoctorWho. No tolerance for discrimination of any kind.
ALT text detailsGráfico promocional para a Python Software Foundation (PSF) como Patrocinador Diamante. Ela apresenta o logotipo da PSF com o texto: “A missão da Python Software Foundation é promover, proteger e avançar a linguagem de programação Python, além de apoiar e facilitar o crescimento de uma comunidade diversificada e internacional de programadores Python.” Um link para o site da PSF (https://www.python.org/psf) é fornecido ao lado de um ícone do GitHub com o rótulo “psf”. Na parte inferior, os logotipos da Plone Conference Brasília e do Python Cerrado são exibidos juntos, indicando colaboração ou patrocínio conjunto. O design inclui elementos geométricos abstratos e um grande ícone de diamante, simbolizando o nível de patrocínio.
I'm a #software#engineer living in #Saskatchewan, #Canada, the middle of the prairies. I've worked in countless domains, but find #python generally useful for many of them, and have been using it for nearly 30 years.
I'm a #HouseRabbit enthusiast and have had them for more than 20 years.
ALT text detailsLena, a medium-sized white house rabbit, lays atop a pile of well-shredded cardboard in a living room. She is reaching towards the camera with her head, and her ears stick out at right angles from each other. The viewpoint is dramatized because the photo is taken from very short range with a wide-angle lens, making her nose and ears appear relatively huge.
ALT text detailsGracie, a large grey lopped-ear house rabbit, is poking her head out of the cardboard box she's currently using as a hidey-hole. She appears to be trying to determine if whoever is bothering her has brought her a snack.
ALT text detailsA "Super Computron 4500" light prop / toy, which is an array of 18x18 blinking blue LEDs. The LEDs all blink at slightly different rates, causing complex patterns to form and re-form continually.
I sell kits to build this, or the smaller 12x12 "Computron 3000", in a choice of colours or colour-morphing RGB, in my Etsy shop.
Who me? Just a #Maker, IT Consultant and "all-around-#nerd".
I grew up watching Saturday morning cartoons, original #StarTrek re-runs, reading #Fantasy & #SciFi (not SyFy), lots of #Lego and eventually graduated to #RPG and #tabletop gaming.
My first computer was a #Commodore Vic-20 - at school, we learned graphical #LOGO on PETS and Apple IIe's... crashed the Unisys ICON network often before getting my first PC - grudgingly - really wanted an #Amiga.
Eventually, it was time for college - I *thought* I would be heavily involved in the physical aspects of technology, circuit design, and hardware engineering - instead, I gravitated to #programming.
Wagtail is an #opensource content management system written in #python and built on top of the @django framework. We have a growing community of contributors and we're always excited to work with new folks.
Ah, this is the moment where a lot of #Python folks would start realizing their use cases were perfectly well handled by multiple processes or by C libraries doing threading for them, and GIL wasn't really the problem.
(But congrats to those who really needed GIL-less Python, for sure.)
🦛 Add sparkly new Python 3.13 🦛 Drop EOL Python 3.8 🦛 Add styling to datetime, date and time values for ODS 🦛 Add styling for date/time types for XLS 🦛 Fix time and datetime export in ODS format 🦛 Avoid normalizing input twice in import_set/book
uv is a tool written in Rust that replaces as a 95% drop-in replacement pip, pipx, pip-tools and a few other things.
So far it's looking pretty cool. It's faster, I guess, and the output is a bit neater and more "interactive" or "live".
One great thing is that you can have a globally installed uv and it will operate correctly in whatever your current Python environment, whereas with pip-tools you always need to take care to run the one installed in the environment you're compiling the pinned dependencies for, or it will calculate python version wrong for the dependencies that are conditional on that.
Wrote a quick blog post about making a python wrapper for the Ohio Department of Transportation's OHGO API (and built a bot that posts random images from traffic cams around Ohio, @ohgo)
I'm originally a physicist and studied gamma-ray bursts and their usefulness for cosmology. I used to carry a beeper to wake me up whenever our instrument detected a burst.
These days I do research in the advocacy world. At UCS I studied political interference in the work of federal scientists. I am currently the Research Manager for Greenpeace USA and focus a lot on climate and energy.
I wrote a lot of code in #Python. Dynamically typed, thoroughly unit tested. I think with a pretty low bug rate. I dared big refactorings. It was like riding my bicycle without hands, and I did that for two decades.
Then in the last 6 years, I slowly stepped into modern static typing. Here I have a lot more safety features. I still write lots of tests, but maybe a few less. And I start wondering whether I would still want to refactor without types and what that means.
That's why for almost a year now #CEPH users have a problem, because Rust parts of Cryptography are clashing with Rust parts of BCrypt. But it's great!
And the best thing is Cryptography authors' attitude — #PyO3 has to deal with it, let's close the bug and lock comments. We really should have more critical packages like that.
Hi! I’m Moof! And as I’ve changed to this server, an #introduction is in order I'm #British-ish, and speak (and write in) #en, #es, #fr & #cat. I live in #Barcelona, and I'm #queer (he/him) I programme boring things for interesting businesses centring around #Logistics, mostly in #Python on #Azure these days. I filter my life through #ADHD. I am an #introvert, and I drink oodles (and oolongs) of #tea both in mugs and #GongFu style. You can also expect me to get excited round #Eurovision time.
ICYMI, I just launched a project that's been several months in the making! #Python for Defenders, Pt. 2 is designed to empower #BlueTeam security professionals with the tools of programming and data science to better analyze their telemetry and forensic evidence.
This paid course ($14.99 USD) supports the work of @thetaggartinstitute to provide high-quality, low-cost technology training to people around the world.
🙏 ¡Gracias a la Xunta de Galicia por colaborar con #PyConES2024! 🌟 Su apoyo impulsa la innovación y fomenta el crecimiento del ecosistema tecnológico en Galicia 🌐💪 ¡Juntas seguimos construyendo comunidad y potenciando el talento local! ❤️
Hello Fosstodon & #GISChat! We are the user-friendly #Python movement data analysis library bringing you convenient data handling, processing, and visualization capabilities
ALT text detailsDirected chord diagram using the "summer" (yellow-green) colormap.
Chords are sorted by distance.
ALT text detailsUndirected chord diagram with a gap between arcs and chords.
It uses gradients to show the link between the two extremities of each chord.
Colormap is viridis.
Random request: Can anyone find me a link to a FOSS bug report (good, but not essential if it's in a mozilla product) that stayed open for a ridiculously long time (years?), but did eventually end up with a fix? #Python#FOSS#OpenSource
— Loris Cro 「 Python could very well continue relying on the support of the Big Tech industry for a very long time but, even if we were to set aside the otherwise extremely real problems of power dynamics between organizations, the long-term sustainability of an exponentially growing dataset still remains and Python is now mature enough to start inspecting and fixing the foundations its ecosystem is built upon 」
I’m Ádám, a #Python software engineer. My background is in mathematics and algorithmic modelling. I’ve worked with radars, satellites and now I’m in the nanotech field.
I like travelling, and moved around quite a bit, currently living in Austria.
:gt: @graph_tool is a comprehensive and efficient :python: Python library to work with networks, including structural, dynamical and statistical algorithms, as well as visualization.
It uses :cpp: C++ under the hood for the heavy lifting, making it quite fast.
Hey everyone! I recently joined and am excited to contribute to the community. After graduating with an art degree, I learned to program as an adult. It opened doors for me, but I learned many things the hard way. Now I'm helping people learn #python to give them the superpowers they can use every day to live the lives they want. I post resources at https://everydaysuperpowers.dev/
This is the Mastodon account for Kedro, an open source, opinionated Python framework for creating reproducible, maintainable and modular machine-learning code.
Follow this account for tips on how to make 🔶 Production ready data science with ease 🔶
The course covers an introduction to what Kedro is, a walkthrough of the Spaceflights tutorial using both Jupyter Notebook and VSCode, new stuff in Kedro 0.18 like dataset factories and the OmegaConfigLoader, how to use S3 and MinIO for your filepaths, and how to deploy Kedro to a Docker image or Airflow.
New blog post: Exploring our new release: Kedro 0.19 🔶
We recently unleashed a new major release of Kedro containing a host of new features, bug fixes, and documentation improvements.
Check out our blog post about Kedro 0.19 to find out more about recent enhancements and improvements to Kedro. We’ll walk you through changes to configuration management, dataset loading and more.
Here is my draft for future plans for the (unofficial) #Nextcloud Remote Client CLI. This is also some low hanging fruit for anyone that might want to contribute a bit of #python for a feature you might want to see land sooner than later.
Nun noch Mal eine #introduction. Ich bin Philip, mag #opensource und #opendata, programmiere nur noch in der Freizeit etwas #Python, interessiert an #machinelearning, Kochen und Selbermachen. Lebe im Raum Düsseldorf und trage gerne zu #OpenStreetMap und anderen Projekten bei. #neuHier Meine Pronomen sind er/ihm.
Trying to disprove Fermat's theorem. can you guys run this on your end so we can get through the numbers faster? thank you in advance
ALT text detailsScreenshot of python script:
import time
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # TODO: Add more numbers
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # TODO: Add more numbers
c = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # TODO: Add more numbers
n = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11] # TODO: Add more numbers
def test_equation(a, b, c, n) -> bool:
print("------------------\n")
print(f"Testing if {a}^{n} + {b}^{n} = {c}^{n}\n")
print("Simplifying equation...\n")
a_n = a**n
b_n = b**n
time.sleep(2) # Allow time for pc to process
print(f"Simplified equation: {a_n} + {b_n} = {c}^{n}\n")
print("Simplifying equation...\n")
c_n = c**n
a_b_n = a_n + b_n
time.sleep(2) # Allow time for pc to process
print(f"Simplified equation: {a_b_n} = {c_n}\n")
print("Checking result...")
result = a_b_n == c_n
time.sleep(2) # Allow time for pc to process
print(f"The equation is {result}")
print("------------------\n")
return result
for a_val in a:
for b_val in b:
for c_val in c:
for n_val in n:
if test_equation(a_val, b_val, c_val, n_val):
print("UH OH theorem disproven\n\n")
break
else:
print("Theorem needs more proving\n\n")
Since there has been a huge influx of new users, I decided to write a new #Introduction and actually pin it to my profile. I'm pushing 50 years old and I live in a Red State that is trying to make me illegal. I'm a #pansexual / #bisexual#transgender woman married to a heterosexual cisgender woman who frequently talks about the current hellscape for people like me in my Toots. I'm #NeuroDivergent / #ND which is probably why all of these sentences start with "I". I've worked in #InfoSec for a little over 20 years. I've had lots of roles in #SecEng, #SecOps, and #ThreatManagement. I taught myself #Perl, #Bash, #SQL, and #PowerShell. I'm decent at #JavaScript. I can read #Python and #Ruby. I enjoy automating things and turning manual processes into scripts. I've been the primary #CareGiver to my wife for 8 years since she developed a chronic condition and went on disability. My hobbies including #writing#paranormal short fiction, journaling my #dreams, and playing #PCGames on my laptop and #SteamDeck. I prefer #StarGate over #StarTrek over #StarWars. Still waiting for Amazon to do something, anything with the Stargate property. While we loved the #ArrowVerse including #Stargirl and #SwampThing, in general we prefer #Marvel over #DC. I'm a fan of #Horror / #HorrorFam, #HorrorMovies and #HorrorBooks, especially the existential dread of #CosmicHorror or #LovecraftianHorror. I tend to sympathize with the nameless terrors. I am not a fan of mindless slashers, unrelenting gore, or torture porn. Over-the-top, egregious gore that crosses into the absurd is fine, though, so I am a Sam Raimi fan, obvs. Also, #HorrorComedies are underappreciated. I'm slowly reconnecting with my #Pagan roots. I knew some stuff about #Tarot and had a friend who as a tree a lifetime ago and I'm trying to rekindle that. We've got #Cats and they are our kids. I also happen to love #Frogs, but we don't have any of those.
Is there a better way in #Python of converting a float to a decimal with specific precision that doesn't involve converting the value to a string first? #lazyweb
Wrote a few lines about my journey with uv yesterday and how I managed to setup my environment by just using uv. No homebrew. No pipx. No pyenv. I love it, that I can get up and running by just using a single tool.
My name is Austin and I love my family, Sports, Music, and Tech.
I am a software developer at #PayTheory. At my job currently I work primarily with #Javascript, #React, and #Python. I know some #Swift and hope to publish an app in the AppStore in 2023. I am going to try to #BuildInPublic here.
Acerca de mí: #introduction#presentation ¡Hola! Soy Mónica Gómez, también conocida como Autumn64. Soy una estudiante mexicana de Ingeniería en Sistemas Computacionales, soy una mujer transgénero y soy activista por el movimiento del #Software_Libre.
En redes me dedico a la promoción y difusión del Software Libre, así como de sus ventajas técnicas y éticas desde el punto de vista latinoamericano e hispanohablante.
Esta es mi cuenta principal, y además tengo otras cuentas en el #Fediverso. Si quieres verificar que realmente soy quien digo ser, por favor revisa mi clave pública: https://www.autumn64.xyz/src/es/key.html
After hiding under a rock since COVID hit I am finally coming out for fresh air. I am in search of a new job in the #kubernetes and/or #python spaces. Also aiming to reconnect with all the people in the Python community I have lost contact with. Expect some long overdue updates to my mod_wsgi and wrapt projects for Python, along with details of another project called Educates that I have been working on for the past 4+ years, and which was finally able to release as open source.
Tendremos charlas de Fiorella Piriz sobre orquestación de datos con Apache Airflow y de Jose Mussach sobre cómo hace para ponerse al día con cualquier tecnología en segundos con Python.
ALT text detailsCartel de PyData Madrid, título ✨ Orquestación con Airflow y aprendiendo cualquier tecnología en segundos, fotos de dos personas, fecha jueves 19 de septiembre de 2024 a las 19:00
Somos Python España, una asociación sin ánimo de lucro cuyo propósito es promover el uso del lenguaje de programación Python en nuestro país y servir como punto de encuentro a aquellas personas interesadas en su uso.
La asociación fue creada en 2013 y desde entonces ha prestado apoyo contable y organizativo a la PyConES, la conferencia nacional sobre el lenguaje Python, así como ayuda financiera a las comunidades locales.
🐍2️⃣🚀 The **final** release candidate of Python 3.13 is out!
➡️ Library maintainers, please upload wheels to PyPI **now**, especially if you have compiled extensions (there are no more ABI changes), so everything is in place for the big 3.13.0 release in 3 weeks!
🔒 Also! Security releases have been made for the full set of Python 3.8 - 3.12. Please upgrade!
I work as Product Manager for an #OpenSource project and have 10+ years of o̶b̶s̶e̶s̶s̶i̶o̶n̶ experience with the #Python ecosystem. I'm interested in #Degrowth, #Cooperatives, the #SolidarityEconomy, and anything that can offer an alternative to capitalism. You'll see occasional posts about #techno, #birds, and rants in Spanish.
I'm Victor, Clinical Data Scientist researching in #AI applied to medicine.
Although AI is something that interests me from many aspects (technical, mathematical and critical) I do not limit myself to write only about this as I have many other interests (#opensource, #python, #SocialJustice, #diversity, #books, #comics, #basketball, etc.).
Also, I speak SP, EN, DE & FR
Looking forward to interact with the Dair-community.
At long last, the PyBay 2024 speaker lineup you’ve been waiting for has arrived! Check out the lineup at https://pybay.org/speaking/ and purchase your tickets! 🐍 #Python#PyBay2024
My #introduction on my new shiny mathstodon.xyz account! I'm slowly deprecating my @alexmath account but I'm kinda bad at fediverse stuff 😅
Hi all! I am Alex (she/her), a #trans mathematician with a PhD in extremal combinatorics now working in as a data scientist. I am a deeply curious experimentalist and I love to learn different topics. My favorite programming languages are #rust and #python but I've had some fun with #cuda GPGPU, too :) I like machine learning as a scientific problem-solving tool, but not the stuff that involves weapons, theft, and violence.
Presently, I live in #Philly with my fluffy orange cat Angus and my partner. I got a new bike and wish I could lose the car forever. Still masking in public. Still getting vaccines. Eternally exhausted, but hopeful and curious.
ALT text detailsA gorgeous fluffy orange cat atop a kitchen counter. His mane poofs out, and his eyes, deep and black, peer down lovingly at the camera-holder.
Hi there! I'm ketmorco, a refugee from mastodon.technology! I'm a firm believer that all life is valuable, and humans all deserve to be happy, healthy, and safe! I used to love technology in its entirety, but I have seen how it gets misused. Most of what we need to be productive and happy already exists!
my main account for interactions is @villares@ciberlandia.pt you may tag it in your replies and I'll see them more readily (here I'll mostly just post my #py5 sketches and some #Python news)
Une #introduction brève : Je suis développeur #python à temps plein, je fais du logiciel libre sur mon temps perso (quand je trouve la force) autour de #XMPP / #jabber depuis plus de 10 ans, je suis secrétaire de l’association #JabberFR dont je co-administre le serveur. J’aime le chant mais j’en fais plus à cause du covid, et je fais de la #photo en amateur.
Ci-joint une photo de héron.
ALT text detailsUn héron perché au milieu de la loire
I thrive on humor, sarcasm, and embracing awkward moments. Having space to make mistakes and explore failures with kindness is vital to me. A firm "No" from me is an act of self-care, so don't hesitate to seek clarification if needed.
Committed to Imperfect Nonlinear Growth:
Embracing imperfection and nonlinear growth is central to my journey as a human being. I opt out of approaches that demand perfection or punishment.
Building Relationships:
I prioritize nurturing communicative relationships over time, fostering mutual understanding and support. Real-life, face-to-face interaction allows for a deeper connection and insight into each other's worlds.
Approach and Caution:
I urge caution in online interactions and forming parasocial relationships, as safety and ethics transcend titles or affiliations. Vigorously vetting individuals and content is crucial, although it doesn't guarantee complete safety.
Personal Health:
I prioritize wearing N95+ masks in public or crowded spaces.
Advocacy Stance:
I stand in solidarity with movements advocating for justice and equality, including Black Lives Matter, Indigenous Lives Matter, Trans Lives Matter, and Black Trans Lives Matter.
I'm Rye! I'm a genderqueer (Any Pronouns) Artisan, Solarpunk, Digital Sorcerer.
ALT text detailsA desert landscape at night with lightening streaking across the sky. The clouds are illuminated and the ground is brown dotted with green shrubs and trees
It’s about 90 min and covers - Core pytest features: Test Functions, Parametrization, Fixtures, Markers - Design for Testability: Modular Code, Isolating Complexity, Using APIs - Basic script param parsing with agrparse #Python#pytest
I currently work at the Icelandic Met Office as a #GIS Coordinator in #Reykjavik. In general, I help people make maps, find #geodata either with code (#python or #javascript) or with desktop software like #QGIS
I love the outdoors and enjoy hiking, climbing and biking. I've been involved with Icelandic Search & Rescue for many years, both on the frontline (mountain rescue) and as an instructor for new team members.
Father of twins since 2016
ALT text detailsFamily of 4 on a picknick in Iceland
Last month together with @jelmerborst and Leendert van Maanen we created a #python package to estimate the __by-trial__ onset of different processing stages in reaction times by relying on hidden semi-Markov models applied to electro-encephalographic #eeg data:
Collating data from my experiments. Reading from separate files to collate into one huge dataframe in python. How do I open files in a directory one after the other? In the past, I've assigned a different var for each file name and then looped through them. Is there another way to do this? #python#pandas
I don't only like using command line tools, I love writing my own too. Python's argparse is a nice built-in way to parse arguments, options and subcommands for custom CLI tools.
J'ai bien envie de travailler avec des équipes localisées au #québec en ce moment.
Si les quelques personnes vivant à #montréal qui me suivent ont des idées, je suis super ouvert.
Je sais faire des trucs autour de #python et du #web. J'aime accompagner des personnes dans l'acquisition de savoirs et d'autonomie autour de la technique. J'apprécie de concevoir des produits qui respectent et prennent en compte leurs utilisateur·ices.
I'm sharing a prototype of #Fedify written in #Python, codenamed “FediKit.” Many of the ideas for Fedify were already implemented in this prototype, albeit in a different language.
I'm an #OpenSource developer and maintainer, mostly working with #Python or #infosec related stuff. (My PhD is in Web Security.) I coordinate #GSoC for Python every summer & mentor some folk directly.
This is my work open source project that lets you scan for known vulnerabilities in your binaries, package lists and SBOMs. It's meant to make it easier (and cheaper!) to make secure open source software.
3.3 has new features from our Google Summer of Code 2023 contributors including EPSS metrics to help users assess risks associated with vulnerabilities, a new GitHub Action to make scanning easier, and a mirror of the NVD data backed by the same servers that do Linux distro mirroring so you don't have to deal with rate limits, downtime, and servers only located in the US.
#introduction Hello world! I'm daschoe and I've been hopping on and off making games for a decade. With some friends, I'm now finally making games worthy of showing to others (read that as actually finishing them). I'm mostly native in #python and currently working with #renpy but try to start also looking into #unrealengine ! During working hours I'm pursuing a PhD in Acoustics researching noise perception. I also volunteer in a local arcade museum repairing and maintaining the machines. Besides programming or playing games, I'm interested in fibrecrafts, #cosplay , pen and paper, reading fantasy novels, #hiking , and making stuff.
I've rewritten #Fedify several times and in several languages. The first time it was written in #TypeScript, then #Python, then C#, then back to TypeScript. (It was codenamed FediKit at the time of development.) I settled on TypeScript for the following reasons:
• It has a decent JSON-LD implementation. • Lots of people use it. (I wanted Fedify to be widely used.) • It's type-safe enough.
Even if I were to build Fedify again, I would choose TypeScript.
I have been using #Linux since I leaned #Gentoo in 2004. I've done end user desktop support, #Windows & Active Directory administration, Linux administration, networking, firewalling, a touch of programming, and a boat load of scripting in bash, #PowerShell, and #Python.
A new #introduction after moving! Feel like I've made my home at #hachyderm, after watching Local for a while.
I'm from Wales but have lived in the Midwest for over a decade now. My background is #astrophysics and I currently work for an #education non-profit. Mostly #requirements elicitation, defect triage and #UAT. I also help "automate the boring stuff", typically in #python or #R.
You'll likely find me posting about #privacy, #space or #RaspberryPi (this post is being written on one!)
Une petite #introduction : @hashbang est une #coopérative de services numériques basée à Lyon, spécialisée sur #Python (et en particulier #Django) et qui met ses compétences au service des structures de l'Économie Sociale et Solidaire, du développement durable et du logiciel libre.
@hashbang est impliquée dans l'@LesScopAura, la cress-aura.org, lagonette.org, et le label "Engagé à Lyon".
La coopérative est composée de 8 salarié·e·s dont 5 sociétaires (sur 7).
Hey folks, just got laid off after 4 years with my employer.
I’m a 25y veteran python developer (web, backend, and data processing) with many years of experience working remotely for companies in the US and Europe.
I have the most experience working with web, backend and data systems, and am also drawn to opportunities to improve internal tooling and web services that give coworkers the information and capabilities to do their thing better.
Previously worked in public sector management and policy, #unions, political #organizing (must all hash tags be in American english?), and personal training.
#Newhere. We are a research group at #BTU Cottbus - Senftenberg in #Senftenberg (Germany) working in the field of bioinformatics (#rstats, #python), functional bioanalytics and personalized medicine. Forensic research is also a topic with us.
I'm a 20-year-old from Bangladesh, part of the Gen Z generation. I’m passionate about privacy, FOSS, and freedom of speech. As a practicing Muslim, I find balance and peace in my faith.
I love programming, mainly in Python and C for now, and I'm an avid reader. Recently, I fell in love with chemistry after reading "The Disappearing Spoon."
I stand firmly against any forms of racism and genocide. As an introvert, I grew up feeling a bit lonely because I didn't find many people like me.
Looking forward to connecting with like-minded folks here!
I have to admit I've been a bit disappointed in the maturity of #ActivityPub libraries/frameworks for #Python though. I'm working on a fledgling AP project in Python and finding very little.
It seems that #BookWyrm and #PieFed have gone the route of writing their implementations from scratch. Its great reference material, but a common library we could all build from would be a huge boon for the community.
It seems that I have become, among other things, a #Python developer. I never expected or planned that. But I find myself writing more and more Python code and getting involved in more and more Python based projects. Is this just a testament to its popularity, or is it just really common in the niches I find myself in?
Presently an Engineering Manager, formerly a Data Engineer, Software Engineer, Web Archiving Engineer...I've been doing a disservice to the title of "Engineer" for a couple of decades, it seems.
I'm enthusiastic about #Python, #Rust and tech. generally with an overt fondness for infosec. and the occasional #CTF.
I use the phrase #HackThePlanet far too often and in a wholly non-ironic way.
Updated Python awhile back on this machine and didn't rerun a bunch of scripts until today. The joys of new warnings and errors along with packages not installed in the new venv. Warnings and errors were down to my laziness e.g. leaving “\s” in regex strings leading to Python going “that's not one of my escape sequences” #Python#BadProgrammer
👋 I'm excited to finally say hello to all you amazing folks of the #Fediverse 🌐 with my #Introduction post! Calling the southeastern U.S. home, my life is a vibrant mix of #graphicdesign, #3dprinting, #3Dmodeling, and delving into the fascinating intricacies of technology. I'm in the thick of my graduate studies in #cybersecurity leadership, focusing on integrating cybersecurity with product management processes for more resilient software and services. I passionately believe that breaking down the cybersecurity silo in organizations means leveraging #userexperience concepts, making cybersecurity practical and understandable for every role. I'm a sponge for knowledge, and I'm building my tech understanding in #python, #networking, cloud, and machine learning concepts. I'll be the first to admit I have much to learn. Reading is my haven 📖 - you'll find me lost in the spellbinding worlds of #NealStephenson, #WilliamGibson, the Dune series, and The Expanse 🚀. I also have a soft spot for #InfoSec books like 'The Cuckoo's Egg,' 'Spam Nation,' and 'Sandworm.' I'm always on the lookout for new recommendations! 📚 As an out #nonbinary individual, I'm committed to building inclusion around gender and feminist issues. I aim to help dismantle "male defaults" and foster more equitable work and community environments for a better future for everyone. The camaraderie and shared learning in the #Fediverse echo the Linux User Groups and Hackerspaces culture I cherish. It's an absolute joy to be a part of a community that upholds these principles. If you love dissecting the latest in #tech, exploring #opensource software, or immersing yourself in a gripping #scifi or #cybersecurity book, let's connect! Follow me and drop a comment about your favorite tech trend, current read, fediverse tip, or your efforts toward a more inclusive tech community. Can't wait to hear from you!
#introduction time - ahoy, I'm a fruitco eng, (formerly Dropboxer and repenting FBer) focused on all things non-consumer (❤️ #macOS and #Mac ❤️)
My github gists are full of horrible hacks and I've written ObjC bridging code in at least 5 or 6 languages at this point. And if you don't stop me, I'll friggin' do it again. I know more about #python, ctypes, and #pyobjc than is legally allowed.
I inhale #scifi and books. I have no shelf control. Pets outnumber humans 5 to 1 in this household. Say hi
In #Python, I tend to avoid map, filter, and reduce.
Why?
The map & filter functions predate Python's comprehension syntax, which I see as an alternative to map & filter that's often much more readable as well.
And reduce can often be replaced by a reduction function.
Instead of this:
single_word_names = list(map(str.lower, filter(lambda name: " " not in name, names)))
I'd prefer this:
single_word_names = [ name.lower() for name in names if " " not in names ]
Okay #python people - I know there are lots of you on fosstodon.
I’ve worked with Python professionally a few years back, and on my own projects occasionally, but now I’m wanting to get back to a true ‘flow’ state with the latest and greatest (ignoring packaging, as that’s always a mess).
Any suggestions as to where best to catch myself up, and see what I’ve missed ?
No ‘beginner’ things please, as I’ve been around a long time, but any cool/useful/important things from 3.6 onwards I guess.
"To help some of the newcomers make connections: name 5-7 things that interest you but aren't in your profile, as tags so they are searchable. Then boost this post or repeat its instructions so others know to do the same."
Had an unwilling flashback to early 2000-s style computing earlier today when I tried to install a package (pycddlib) for #python. Due to some weird dependency bug in the most recent versions of python, this ended up taking two hours of downloading various bits and pieces of software (in no particular order: cython; .NET SDK; gmp; MPIR; VSCode Solution Explorer; vcpkg (attempted, but abandoned); CMake (attempted, but abandoned); MSYS2; a single file longintrepr.h (manually downloaded from a github repo); several unrelated github projects that shared some of the dependencies (but did not ultimately advance the resolution, probably due to the lack of fundamental understanding of what I was actually doing at some stages of the process); and several manual compilations and "make"s, updates of PATH environment variables and reboots), as well as multiple google searches (mostly to stackexchange sites and similar) and consultations with AI, before finally succeeding (after three partial successes in which the immediate error message was resolved, only to encounter a fresh error message). This sort of extremely tedious problem-solving is a task which I will be very happy to see become a thing of the past when personalized AI-empowered digital assistants become commonplace!
Die zweite Auflage meine Buches über #Sphinx ist erschienen.
"Sphinx ist ein leistungsfähiges Werkzeug für die Dokumentation von Software. Ursprünglich geschrieben, um die Programmiersprache #Python zu dokumentieren, entwickelte sich Sphinx in der Python-Community schnell zum Standard. "
Father of two, make my own maps and computer tools, have my own home server, fix as many things as I can myself, love to drive and travel by car but not for the city, and much more.
Mostly boosts, in several languages, including some I can't speak, write or read.
ALT text detailsChatGPT 4o
Prompt: 9.11 and 9.9 — which is bigger
ChatGPT: 9.11 is bigger than 9.9. Prompt: subtract them
ChatGPT: To subtract 9.9 from 9.11, you perform the following calculation:
9.11 - 9.9 = 0.21
Prompt: use python
ChatGPT: The result of subtracting 9.9 from 9.11 in Python is —0.79. This discrepancy is due to the way floating-point arithmetic is handled in Python, which can lead to small precision errors. The actual intended result should be 0.21.
Hi #Lazyweb, my brain isn’t working today. What’s the simplest way (preferably in #python) to get my posts from an ActivityPub server - either #mastodon or #pixelfed? Do I need to have a full blown ActivityPub client or is there a simpler way to do it?
TUTORIAL: Run Python (and any other language) in CNCF wasmCloud. Now WASI 0.2.0 is in the wild, it's the perfect opportunity to walk through the steps we take to run a generic component - using #Python in this example - in wasmCloud. Dive in to this new post from @ericgregory
#Deno and #Bun people are putting an incredible amount of work modernizing server side js.
The energy is reminding me of early day #Python - so many new tools made with proper care behind rather than most of NodeJS ecosystem which is just glued together with band-aids and staples :blobcatgrimacing:
That being said, after working with Deno for the past week it still feels a bit too bleeding edge though it does work with #jupyter!
I find myself in that uncomfortable situation like many others who work in tech lately, and will be looking at a layoff in the next few months. If anyone is aware of cool jobs in Germany, probably remote-first, working with #Go (or even #rustlang#python#node ) please reach out. I have ~9 years of backend experience and consider myself someone who gets shit done. #fedihire
Unprofessionally I spend my time #parenting two children along with my wife and occasionally manage to find time to play #guitar 🎸 improve my use of #emacs and hack at too many half forgotten #maker projects.
I realize, that while I've been on this platform for a while, I haven't introduced myself, so here it goes.
I'm Nice Micro, scientist (semiconducting materials and semiconductor devices) by day, free software enthusiast, #bash script kiddie, #python wrangler, #Godot waiter and avid gym goer by whatever part of the day I'm not working.
So, eine Englische Vorstellung hab ich, dann fehlt jetzt noch das deutsche #NeuHier.
Während ich auf Englisch Richtung #DataScience und #Python unterwegs bin, geht's im Deutschen eher in den Bereich der #FediEltern und #Verkehrswende. Ich bin viel mit dem #Fahrrad unterwegs - #mdRzA und zur Kita - und möchte mich sicher auf den Straßen bewegen können! Beruflich bin ich sehr interessiert an der #Krankenhausreform, die ist daher auch ab und zu Thema bei mir.
Learn about Mona’s journey. She started learning to code at the age of 5, making video games using Scratch and Python. Even though Mona is still in high school, she is already a frequent public speaker at Python and tech conferences, and is inspiring other kids to code.
I used to teach with that book from 2017-2023 but it got quite old already, I'm looking for a fresh perspective (or just an updated version of the book)
Do you know any good #django tutorials explaining various scenarios of #database handling (structure and data save/retrieval)? Things to read and learn more on this topic?
Even though this account is over five years old, this is a start-over, so time for a #introduction!
I’m Hynek from Berlin, and (still) like computers. I strive to have informed and nuanced opinions.
I’m best known in the #Python community, where I wrote many blog posts, gave many conference talks/keynotes, created foundational projects like attrs, argon2-cffi, or structlog, and still help push the ecosystem forward.
Modern #CATMAID enables hundreds of #neuroscience researchers world wide to collaboratively map neuronal circuits in large datasets, e.g., 100 TB or larger, limited only by bandwidth and server-side storage. The goal: to map and analyse a whole brain #connectome.
Running client-side on #javascript and server-side on #django#python#postgresql, it's a pleasure to use–if I may say so–and easy to hack on to extend its functionality with further widgets.
The first minimally viable product was produced in 2007 by Stephan Saalfeld (what we now refer to, dearly, as "Ice Age CATMAID), who demonstrated to us all that the web, and javascript, where the way to go for distributed, collaborative annotation of large datasets accessed piece-wise. See the original paper: https://academic.oup.com/bioinformatics/article-abstract/25/15/1984/210794
I have just cast my vote in the @ThePSF Board of Directors Election. If you have not cast your vote please do so. Voting closes today at 2pm UTC. #python
thanks @ThePSF for supporting meetup.com for Cebu Python User Group ( PizzaPy ), they can re-construct User Group! if you have time to visit Cebu, Philippines meet them.
I'm originally from a rural town in middle Missouri but now call #SaintLouis my home. I have a love for the American southwest (my Mom is from New Mexico) and for the coastal city of #Savannah#Georgia.
I'm single, live alone with two #dachshunds (#dogs) named Amelia and Penelope. I'm a #progressive#liberal, can't stand money in #politics, and yearn for a day when the #Democrats improve their messaging and start fighting back.
This stuff matters. We have a moral obligation, as well as a practical need, to be as open, welcoming and inclusive as we can be. It's existential to the longevity of Python. Inclusivity is in the eye of the beholder, and so we _have_ to listen to feedback from everyone.
I'm looking for a new role. I've been working professionally with #python for 12 years. For the past year and a half I've also been working with #rust.
In open source, I've contributed multiple headline features to #django and I'm a maintainer of #pyo3.
I'm based in the UK and I'm comfortable with remote work or hybrid.
My ideal role would involve both Python and Rust. I'm open to considering other roles too.
🐍🧪 Python 3.13.0 is due out in October 2024 and work is underway to implement *experimental support* for PEP 703 "Making the Global Interpreter Lock Optional in CPython".
As the Steering Council noted in their acceptance of the PEP, to succeed it's important to have community support.
I wrote a little guide on how you can help test out the beta in your project, and help us find bugs in CPython:
Python 3.13 is now in beta, with the second of four beta releases out later today!
It's now time to start testing your libraries with 3.13 and report any problems back to CPython so they can be fixed before the big October release. And make any updates you need to upgrade your library; keep an eye out for removals and deprecations.
ALT text detailsSlide with a photo of my silhouette when cycling on the sea:
Should Python adopt CalVer?
Hugo van Kemenade
Helsinki
Dead Set Bit
Core developer since 2022
3.14 & 3.15 release manager
ALT text detailsThe view of the language summit from the lectern.
I'm a 50-something dad of 2 boys who play some combination of #baseball, #football, #basketball and #lacrosse. I've been married 18 years, living in #Virginia since 1997. We have a German Shepherd mix rescue; she is the best girl.
#Sports: Unfortunate #Caps fan #nhl. Favor the #Orioles over the #Nationals. I try to follow #F1 but cannot stand Verstappen. Since the older son plays, we find ourselves watching the #Commanders more often. They are terrible.
Since I'm moving here from Fosstodon, I suppose it's a good opportunity for a re-#introduction.
My name's Michał Górny. You may know me as a Gentoo developer, though my social media usage extended beyond that.
I've joined #Gentoo in 2010, back when I was still a student. You could say that we've both matured together, perhaps became less bleeding edge and more stable. There are some things that I'm still doing all these years later, notably the maintenance of #Python ecosystem in Gentoo (which is superior to other distributions, I must say), #LLVM, #XFCE and some other random packages, building Distribution Kernels. I also create #OpenSource software (mostly tools related to Gentoo package management), work in QA, and either do or have done a lot of random stuff that simply needed to be done.
Professionally, I used to be a programmer. However, I quit my last job in 2022 due to health breakdown and haven't managed to find a good job so far. Right now, I'm mostly surviving on what I've managed to save years ago, with some help from my gracious sponsors (thank you for your donations!). I've started a new job recently, though onboarding is taking quite long and it's not yet clear if I'll manage to actually make any profit.
I am very #introvert. I always enjoyed #hiking and fast walks around #nature, and since I've been diagnosed with #diabetes in 2022, this changed from just a pastime to a necessary exercise. That said, I don't like repeating the same routes too often, so I go around by #rail. My main interchange stations are #Poznań, #Leszno, #Głogów and #Wrocław.
A few years ago I adopted three stray #cat siblings: Blackie (or Lulu), Ruh and Mr. Gray (or Mr. Ek!). They are going to cyclically appear in my avatars and profile backgrounds. That said, they made me realize I'm actually a cat, and a big cat too (that's why the "territory" I keep patrolling has roughly 200 km radius).
I hate #politics and I'm quite angry that I am forced to take interest in it. I'm a strong believer in the #CarFree ideology (I don't even have a driver's license). I will sometimes rant in the #AntiCapitalism mood, with a sprinkle of #ecology and #degrowth in the face of #ClimateCrisis.
I enjoy reading #books (fiction and non-fiction alike), watching #movies or #series (though I usually don't manage more than 30 minutes at a time) or playing computer #games (preferably slower, older, single-player games these days).
I generally toot simultaneously in english and polish (except for word plays that don't make sense in the other language). My polish account is: https://pol.social/@mgorny
If you know little or nothing about #coding but want to learn, then check out https://whizkidzcc.com/summer. We've turned students that didn't think they could code to not only become proficient but to actually enjoy programming.
We offer one-week online workshops on #Python, #Java, #Web, #AI / #machinelearning, and more! These classes are taught by trained instructors. It is project-based and very hands-on. Use the coupon code "mastnew" for $100 off for first-time customers!
I'm a 19-year-old from Bangladesh, part of the Gen Z generation. I’m passionate about privacy, FOSS, and freedom of speech. As a practicing Muslim, I find balance and peace in my faith.
I love programming, mainly in Python and C for now, and I'm an avid reader 📚. Recently, I fell in love with chemistry after reading "The Disappearing Spoon."
I stand firmly against any forms of racism and genocide. As an introvert, I grew up feeling a bit lonely because I didn't find many people like me.
Looking forward to connecting with like-minded folks here!
Ich will alle Elemente von dieser Seite bekommen, dafür muss man ein paar mal den Button unten drücken. Ich versuche es mit #Python und cfscraper/requests und #BeautifulSoup, aber ich bekomme die richtige POST-Anfrage nicht hin.
:boost_requested: #GetFediHired#Jobs#SysAdmin#Python#FOSS#FLOSS Hey #FediHired, I'm on a #JobSearch. I'm a #Linux systems engineer and #Python developer with 15+ years' experience, based in #Melbourne, Australia. I have a high attention to detail & lots of experience working with people (15+ years community organising/Scout leading). Motivating values: free/ #OpenSource software, accessibility, diversity, equity, inclusion, privacy, and security, analysing/improving/automating systems/processes. Recent personal projects involve #Docker, #Django, #Ansible. Ideally seek remote role with communicative/cohesive team, variety, flexible hours, ideally max 4 days/week. LinkedIn: https://www.linkedin.com/in/mattcen/ Resume: https://blog.mattcen.com/resume/
👋 Hi all ! I am a research engineer at CNRS 🇫🇷, working at the UAR RIATE on the development of applications or libraries for the visualization or the processing of geographic information. I did my PhD in Grenoble 🏔️🚁 about Semantic Web and geovisualisation.
If you knew me prior to appearing over here on Mastodon, it was probably because of something related to #Python and #Django. I've served in a lot of roles within the Django project, though a couple years ago I stepped down from everything except the security team, where I still occasionally can weigh in with some institutional knowledge or bits of Unicode arcana.
A quick biographical sketch:
For a variety of mostly-economic reasons, I didn't have reliable access to the internet or even a PC until I went to college. I did a degree in philosophy, and have never taken a formal Computer Science or Software Engineering (or other "related field") course in my life. I got into web dev sort of by accident in the early 2000s, and almost didn't make it -- I was struggling to make ends meet freelancing, and only managed to stick around because I effectively won the lottery: I got interested in Django pretty quickly after it was open-sourced, and about six months later I was hired by the little newspaper company in Kansas where it was originally developed. I owe my entire subsequent career and success to a combination of privilege (I'm a white dude who could pass for middle-class, so a lot of doors opened, or opened more easily, for me) and that lucky break.
I believe tech hiring and interviewing are awful, and have worked to improve them both indirectly through writing/speaking about them, and directly at various employers over the years. I have no patience for gatekeepers, "your language/library/framework sucks" zealots, "brilliant assholes" and other assorted malefactors.
My politics are progressive but NOT populist, and that is an important distinction, because a lot of allegedly "progressive" causes and people... aren't.
I like baseball. I'm pretty bad at chess but enjoy it anyway. I read a lot, sometimes new things, sometimes old favorites. I like to cook.
I'm still figuring out what parts of myself I want to put into this account and what I want to get out of it.
Ouch. The voting page for the #Python Software Foundation (#PSF) Board of Directors 2024 Election is completely inaccessible with a keyboard.
It's hosted by OpaVote, which is presumably a third party. None of the director candidate checkboxes or bylaw change radio buttons can be navigated to, nor can their state be determined with a #screenReader to make sure I'm voting for the intended things. #accessibility
📢📢 Have an interesting proposal? There’s still time! Submit your proposal for #PyConAfrica2024 and present it at one of Africa’s largest Python conferences.
ALT text detailsblogmaker_lite.py, with colored rectangles highlighting 5 main sections: import statements, admin registration, view functions, URL patterns, and WSGI handler
OK so I'm staring at @ThePSF board of directors ballot and nominations page, and holy cow these all seem like sincerely amazing people in their own right:
I know y'all are now binging on those #PyConUS 2023 keynotes and talk videos which are now released on YouTube, but your experience won't be the same unless you also watch the welcome message from your conference chair 😊 (https://youtu.be/eZwHvBsoPn4)
We shared our 20 years of @pycon flashback 🤩. I get to introduce my #IceCreamSelfie tradition. 🍦🤳 I shared how PyCon has changed my life, and thus I wish for you to experience the magic of PyCon too ✨
I'm Sumana Harihareswara, a woman in #NYC New York City. I have a consultancy https://changeset.nyc, Changeset Consulting and provide short-term project management services for #freesoftware#FLOSS#opensource projects. I'm writing a book on maintainership skills and have accidentally developed expertise in #Python packaging tools.
I'm married, a stand-up comedian & fanvidder, a frequent poster on #MetaFilter & #Dreamwidth, Indian-American. Just moved from mastodon.social!
While we are talking about talk videos though, the youtube channels of every #Python conference have *weirdly* low view counts. If you write Python code, you should probably be subscribed to https://youtube.com/@northbaypython and https://youtube.com/@pyconus and probably a dozen regionals I haven’t been to. The value in these talks is massive, and I know a lot of people can’t be at the events live. You should peruse the catalog on https://pyvideo.org and see which ones capture your interest.
You can now watch the talk on "The Perfect Python Project" that I gave on Saturday at North Bay Python on YouTube. Please share and enjoy. https://www.youtube.com/watch?v=kcfERM6fcgU
Here's my #introductions... I'm into #retrocomputing and #retrocomputers, am a #6502 fan, but I like green spaces and days which not overcast, I like science and #sf - mostly #sfbooks and stories - #computerscience, aka #cs or #compsci, I like #brianeno for his music and his thoughtful writings and funny videos, I write just a little code in #python and #javascript and #assembly and generally spend a lot of time on the internet. Isn't the world a lovely place but in a fine old state though?
Since there has been a huge burst of new activity out there, and everyone has been doing #introductions I guess I should (re)do a hashtag-laden #introduction of my own.
I am a mid-century modern weirdo from #YYC aka #Calgary#Alberta#Canada that runs https://coales.co Hometown/Mastodon site out of the garage in his back yard (the servers are literally bolted to the ceiling in there...told you I was weird)
That said I often (sometimes mostly) post random and sometimes weird stuff. Occasionally political but put it behind content warnings. I am generally #AntiAuthoritarian and I dunno maybe #mutualist if I had to label it.
I am a #software#engineer in #Perth, mostly C/C++ (#CPlusPlus), #Python, learning #Rust and #Golang, dabbled in many others. Interested in image processing, #NLP, sports analytics, with a continuously growing list of side projects which may or may not ever get "finished".
When I'm not doing that I'm a #photographer who occasionally gets paid to shoot #sports events.
And while I have your attention, on a completely different note ...
Australia's Head of State should be an Australian, by birth or by choice.
Any Australian should be able to aspire to be our Head of State.
All Australians should have a say in who is our Head of State
New instance, I must repost and re-pin my #Introduction!
My background is in astrophysics. I worked in science policy in DC for about a decade: for my professional society, as a congressional fellow, and then at the Department of Energy Office of Science.
I changed careers to #DataScience in 2019 and now work in the private sector.
I learned #Rstats first, but now work and do my side projects with #Python. See all my side #projects here:
Have you ever wanted to know what happens behind-the-scenes at conferences like PyConAU? We're looking for volunteers to help out in November (After exam season!)
No prior experience required! It’s a fantastic opportunity to get to know the community, and learn something new!
I'm a geographer working as a mapmaker and codewriter for the open science in archaeology. #QGIS, #Python & #Django are my favorite tools right now.
Beside geospatial and web, I've worked before as a performer & artist. I'm into #sailing & I've been #livingaboard during a couple of years. I'm fluent in French, English & Spanish, and playing music is my happy place!
I'm also the admin of mapstodon.space. Quite excited to see y'all around here!
I regularly enjoy live sports/music (likely to post about), I code #Python & #Rust and am unafraid of low-level / reverse engineering, builder, breaker, cocktail shaker. Lefty af ☭. An aspiring cyberterrorist armchair general on main 🤘😜👍 #Introduction
Problems: @pydantic is great for modeling data!! but at the moment it doesn't support array data out of the box. Often array shape and dtype are as important as whether something is an array at all, but there isn't a good way to specify and validate that with the Python type system. Many data formats and standards couple their implementation very tightly with their schema, making them less flexible, less interoperable, and more difficult to maintain than they could be. The existing tools for parameterized array types like nptyping and jaxtyping tie their annotations to a specific array library, rather than allowing array specifications that can be abstract across implementations.
numpydantic is a super small, few-dep, and well-tested package that provides generic array annotations for pydantic models. Specify an array along with its shape and dtype and then use that model with any array library you'd like! Extending support for new array libraries is just subclassing - no PRs or monkeypatching needed. The type has some magic under the hood that uses pydantic validators to give a uniform array interface to things that don't usually behave like arrays - pass a path to a video file, that's an array. pass a path to an HDF5 file and a nested array within it, that's an array. We take advantage of the rest of pydantic's features too, including generating rich JSON schema and smart array dumping.
This is a standalone part of my work with @linkmlarrays and rearchitecting neurobio data formats like NWB to be dead simple to use and extend, integrating with the tools you already use and across the experimental process - specify your data in a simple yaml format, and get back high quality data modeling code that is standards-compliant out of the box and can be used with arbitrary backends. One step towards the wild exuberance of FAIR data that is just as comfortable in the scattered scripts of real experimental work as it is in carefully curated archives and high performance computing clusters. Longer term I'm trying to abstract away data store implementations to bring content-addressed p2p data stores right into the python interpreter as simply as if something was born in local memory.
ALT text details[This and the following images aren't very screen reader friendly with a lot of code in them. I'll describe what's going on in brackets and then put the text below.
In this image: a demonstration of the basic usage of numpydantic, declaring an "array" field on a pydantic model with an NDArray class with a shape and dtype specification. The model can then be used with a number of different array libraries and data formats, including validation.]
Numpydantic allows you to do this:
from pydantic import BaseModel
from numpydantic import NDArray, Shape
class MyModel(BaseModel):
array: NDArray[Shape["3 x, 4 y, * z"], int]
And use it with your favorite array library:
import numpy as np
import dask.array as da
import zarr
# numpy
model = MyModel(array=np.zeros((3, 4, 5), dtype=int))
# dask
model = MyModel(array=da.zeros((3, 4, 5), dtype=int))
# hdf5 datasets
model = MyModel(array=('data.h5', '/nested/dataset'))
# zarr arrays
model = MyModel(array=zarr.zeros((3,4,5), dtype=int))
model = MyModel(array='data.zarr')
model = MyModel(array=('data.zarr', '/nested/dataset'))
# video files
model = MyModel(array="data.mp4")
ALT text details[Further demonstration of validation and array expression, where a Union of NDArray specifications can specify a more complex data type - eg. an image that can be any shape in x and y, an RGB image, or a specific resolution of a video, each with independently checked dtypes]
For example, to specify a very special type of image that can either be
a 2D float array where the axes can be any size, or
a 3D uint8 array where the third axis must be size 3
a 1080p video
from typing import Union
from pydantic import BaseModel
import numpy as np
from numpydantic import NDArray, Shape
class Image(BaseModel):
array: Union[
NDArray[Shape["* x, * y"], float],
NDArray[Shape["* x, * y, 3 rgb"], np.uint8],
NDArray[Shape["* t, 1080 y, 1920 x, 3 rgb"], np.uint8]
]
And then use that as a transparent interface to your favorite array library!
Interfaces
Numpy
The Coca-Cola of array libraries
import numpy as np
# works
frame_gray = Image(array=np.ones((1280, 720), dtype=float))
frame_rgb = Image(array=np.ones((1280, 720, 3), dtype=np.uint8))
# fails
wrong_n_dimensions = Image(array=np.ones((1280,), dtype=float))
wrong_shape = Image(array=np.ones((1280,720,10), dtype=np.uint8))
# shapes and types are checked together, so this also fails
wrong_shape_dtype_combo = Image(array=np.ones((1280, 720, 3), dtype=float))
ALT text details[Demonstration of usage outside of pydantic as just a normal python type - you can validate an array against a specification by checking it the array is an instance of the array specification type]
And use the NDArray type annotation like a regular type outside of pydantic – eg. to validate an array anywhere, use isinstance:
array_type = NDArray[Shape["1, 2, 3"], int]
isinstance(np.zeros((1,2,3), dtype=int), array_type)
# True
isinstance(zarr.zeros((1,2,3), dtype=int), array_type)
# True
isinstance(np.zeros((4,5,6), dtype=int), array_type)
# False
isinstance(np.zeros((1,2,3), dtype=float), array_type)
# False
ALT text details[Demonstration of JSON schema generation using the sort of odd case of an array with a specific dtype but an arbitrary shape. It has to use a recursive JSON schema definition, where the items of a given JSON array can either be the innermost dtype or another instance of that same array. Since JSON Schema doesn't support extended dtypes like 8-bit integers, we encode that information as maximum and minimum constraints on the `integer` class and add it in the schema metadata. Since pydantic renders all recursive schemas like this in the same $defs block, we use a blake2b hash against the dtype specification to keep them deduplicated.]
numpydantic can even handle shapes with unbounded numbers of dimensions by using recursive JSON schema!!!
So the any-shaped array (using nptyping’s ellipsis notation):
class AnyShape(BaseModel):
array: NDArray[Shape["*, ..."], np.uint8]
is rendered to JSON-Schema like this:
{
"$defs": {
"any-shape-array-9b5d89838a990d79": {
"anyOf": [
{
"items": {
"$ref": "#/$defs/any-shape-array-9b5d89838a990d79"
},
"type": "array"
},
{"maximum": 255, "minimum": 0, "type": "integer"}
]
}
},
"properties": {
"array": {
"dtype": "numpy.uint8",
"items": {"$ref": "#/$defs/any-shape-array-9b5d89838a990d79"},
"title": "Array",
"type": "array"
}
},
"required": ["array"],
"title": "AnyShape",
"type": "object"
}
Re-doing my #introduction now since I'm trying to be here a bit more ...
G'day I'm Nick, from the NE suburbs of #Melbourne , Australia.
I work as an #opensource#developer (mostly #python) doing remote work for various clients, and I'm also interested in #retrocomputing or, as I like to call it, computers back when I was a kid.
I'm into #cycling (slowly) and working up to doing some #cycletouring miles around Victoria this summer, and eventually elsewhere in the world.
I'm into #music generally and I'm (also slowly) learning to play #ukulele and learning a bit of music theory along the way.
I'm also doing some set design & construction for a #musicaltheatre group my daughters & their friends all seem to be in!
I'll probably be posting about those things more than work, tbqh. Older stuff, mostly tech-related, is on my blog at https://nick.zoic.org/
We have 8 tickets left for the amount of food we've ordered. If you're thinking of coming to #NBPy, but have been leaving it to the last minute, try to get your order in tomorrow morning, so we might be able to order more food.
You may know me from conferences I've run: North Bay Python here in Petaluma, linux.conf.au in 2017, and PyCon AU 10ish years ago, or various talks at various PyCons.
I enjoy cooking, gardening, travel, and our cats: Pico & Astra.
We're welcoming your talk proposals from _right now_ until April 12th. Have something to share about Python, or that people who like Python need to hear? We want to hear from you!
ALT text detailsAn orange and white cat is walking at you, next to a black stage curtain along a polished concrete floor. Her tail is up, and she looks happy to see you. The background looks like it could be inside a barn.
So I prepared a treasure hunt for my older daughter, which involved some form of coded message. I found a braille table I could 3D-print, using a real system instead of some made-up code gave me the opportunity to explain how/why this was used in reality, you find braille codes in lifts, staircase handrails.
Satellite images of the on-going floods in #RioGrandeDoSul, Brazil. I wrote a post showing how to use #OpenData from #Landsat 8 and some #OpenSource#Python code to create RGB composites and an animation of before and during the floods:
ALT text detailsEin Diagramm von 6 Messkurven. Dargestellt ist die Intensität der Röntgenphotoelektronenspektroskopie über der Bindungsenergie. Hervorgehoben sind die spezifischen Linien der Elemente Kobalt, Sauerstoff, Kohlenstoff und Silizium. Die Kurven entsprechen den Temperaturen 100, 125, 150, 175, 200, und 250 °C.
Je wärmer es wird, desto höher werden die Peaks, die Kobalt repräsentieren.
🐣📱 This Easter, hatch something new with your device! 🐰✨ Dive into the beta release of #OpenAndroidInstaller v0.5.3-beta and give your phone a fresh start.
Now supporting a wider range of devices including #Xiaomi Mi A2, Redmi Note 10 Pro, and #Samsung Galaxy S5 mini. 🌼🔧
If you work with spectra or multivariate regression and don't want to reinvent the wheel, check it out. If it doesn't do what you need it to do, let me know and we can add capabilities to make it work for you! #python#spectroscopy#lpsc2024#data#OpenSource#DataAnalysis#ML
ALT text detailsLogo for PyHAT: the Python Hyperspectral Analysis Tool
"Quick" Question: If you would build a new #web#application, what would currently be "the best" development language and/or #framework (#webframework) for that?
"Best" as in reliable, #secure, easy to get personal and future proof?
I'm also available for #CreativeCoding & introductory #Python private classes and workshops.
PT: Se puder me apoiar, use os links acima. Estou tdisponível para aulas e oficinas de #ProgramaçãoCriativa e ensino introdutório de programação com Python!
My most recent employment was mostly using #ClojureScript and #TypeScript with #React, but I've also a lot of experience with #Python on the back-end. That said, the goal is usually more important to me than specific languages or technologies, since they can be learnt.
I'm a #FOSS advocate and sometime contributor, and a full-time #linux user.
I'm not a #FreeSoftware copyright lawyer, but I play one on the Internet.
ALT text detailsScreenshot of a page of the manuscript.
In the main part it shows a depiction of the (automatically) constructed knowledge graph. With ≈850 nodes and
≈8000 edges.
The caption reads:
Visualization of the whole knowledge graph. While it is impossible to extract meaningful details from this picture it illustrates the high degree of interconnection. Edges of type R3["is subclass of"] are blue, R4["is instance of"] are orange and all other edges types are colored black.
Sou de esquerda, apoio direitos humanos, justiça social e LGBTQIA+.
Programar é um hobby e uma forma de manter minha saúde mental. Adoro #Python. Em uma vida passada, ajudei bastante a fazer triagem dos bugs em https://bugs.python.org.
Sou autista e luto contra depressão e ansiedade.
Há muito tempo, achei que ia ser um fotógrafo. Quero voltar a fotografar.
We are a non-profit #Python community in #Turku, Finland. We bring together developers to meetups, sprints and social gatherings so we can learn from each other and have a jolly good time.
I guess I should have an #introduction on here as well:
I'm a programmer and #FreeSoftware enthusiast. I've been using #Linux as my main desktop and #Emacs as my... everything... since 2008. I started off with a lot of distro hopping, my journey took me through #Ubuntu, #Fedora, #Zenwalk, #Gentoo, and #Exherbo before settling on #ArchLinux, now with #Guix on top.
I love writing software in #Lisp (either #CommonLisp or #Scheme or any other), but I don't get enough of a chance to. Except #EmacsLisp, basically all my personal projects end up being written in that. Other than that I've enjoyed writing things in #CSharp, #PHP, #Python, #JavaScript, #Ruby, #Groovy, and several other languages.
My main account is @ryuslash, this is my account for experimenting with self-hosting.
Messing around with programmatic graphics to display on a 1.8" TFT display connected to my Pi Cluster. The is not a whole lot of pixel real estate to display much, but I think I've got the basics down.
Pink - current CPU temperature Orange - CPU utilization graph (span is about 30 minutes) Blue - Memory utilization graph (span is about 30 minutes)
Each node runs a python script from a cronjob. The master node uses ansible to fetch all the data JSON files.
ALT text detailsA black image split into for rows of text and graphics. Each row has white letters in the top left indicating the node hostname. Each row then has the CPU temperature in pink and either a green or red word indicating if the node is up or down. Each row also has a graph below the text where the orange filled line indicates the CPU utilization and the blue line indicates the memory utilization.
The third row down is unique in that it is indicating the node is down and all the text and graphics are dark gray except the word Down which is red, giving a good visual indication that something is wrong.
My posts are either: - cool stuff I learn - simplified concepts - tricks for 2D/3D - sometime my art/code
I try to help anyone curious about #art and/or #tech with what I learn
✨ Moar about me ✨ - I speak French and English 🇨🇦 - I work in a non-profit research center - I use #OpenSource tools most of the time - I like #python - I like #blender, #krita and #inkscape - I like tiny birds and big dogs - I like @adrian alot 🏳️🌈
Today I improved my #Python script to convert #png files in a folder to #gif, using a graphic interface with #PySimpleGUI (I have a CLI version too I have recently converted from #Pillow to #imageio) and during class I made a png to #mp4 version!
Hello Polymaths.social! For those of you that don't yet know me, my name is Rogue. 👋🏻
I'm a university student in the US studying Electrical Engineering, with a specific interest in radio frequency studies.
My main hobbies that I love to talk about are #AmateurRadio, #DartBlaster Modifications, and #Film. I also write some code on the side as well, in #JS and #Python and hope to learn other languages in the future.
I'm constantly working on side projects so expect my Polymaths feed to be a load of non-sense but I'm happy to be here :)
ALT text detailsA drawing of my foxcat fursona typing on a keyboard while grinning mischievously, with icons of Blender and Python in bubbles, implying I'm doing some scripting in Blender.
Estoy jubilado, soy curioso y tengo un interés casi universal por la vida, la tecnología y el arte. Me gusta tener ideas, hacer cosas y aprender como funcionan las cosas.
En esta red social busco personas interesadas en los mismos temas que yo para poder intercambiar conocimiento, experiencias y charlar de esos temas.
I finished my summer internship this week! I spent 4 months working with a team of biologists and statisticians at The Jackson Laboratory, building visualization software for their research needs. The lab I worked with focuses on analyzing genetics, the microbiome, and addiction-related traits. Here's an overview of some of the EDA tools I built for them in #Python ☺️ #genetics#biology#addiction#dataviz#computerscience#research#phd
If you're doing cool work with data vis + bio, lmk!
ALT text detailsA background section explaining the reasons for doing mouse research to understand human disease; the importance of understanding heritability for treating addiction; and introducing the complexities of the data being analyzed (large, k-partite, high dimensional)
ALT text detailsA summary of a project to use conditional inference trees to understand interactions between microbes in predicting certain behavioral traits
ALT text detailsAn overview of a project to create a Sankey diagram comparing clustering methods applied to differential co-expression data. Everyone has their favorite clustering method, so how do we find strong signals in gene-gene similarities? By creating tools to spot concordance across methods
ALT text detailsProject overview for a software tool that allows users to upload stacks of distance matrices, threshold on distances and features of interest, concatenate data as edgelist, and render interactive k-partite graphs to show association or anti-association between genes, microbes, and traits
Hi! I'm Kevin, a creative Dutch freelance developer with a passion for good design and intuitive, user friendly interfaces.
By day I use #Swift, #TypeScript, #Svelte, #SvelteKit, #Python, #Django and #HTMX to make apps for iOS and the web, and the APIs that drive them. At night I’m looking for the best burger in the world (recommendations always welcome!).
I've been building websites since 2000, and iOS apps since 2010.
Je viens de migrer sur eldritch.cafe. J'étais auparavant sur une autre instance mais pas assez active à mon goût. Je suis venu·e ici car j'apprécie la modération de eldritch.cafe, de ce que j'en connais et les valeurs défendues ici me plaisent ! En plus il y a tout plein de gens cool ici (dont mon incroyable future femme @Divine_lu) ! 😊
Je suis une personne non-binaire, développeur·euse (principalement en #Python). J'aime le logiciel libre et bidouiller. J'héberge d'ailleurs chez moi un serveur #XMPP et une instance Shaarli que vous pouvez retrouver ici : https://links.plaws.fr/. J'y partage des liens liés à l'actualité qui me semblent importants et qui pourront former un corpus quand on cherchera un sujet en particulier.
Sinon je joue un peu aux #échecs, si vous voulez faire une partie un jour, n'hésitez pas à me DM. Je joue également à #LoL et d'autres jeux vidéo.
Voilà et il y a tout plein d'autres choses que j'aime dans la vie mais l'idée c'était de faire une petite intro pas une liste exhaustive.
#Introduction Trained as a historian at the university of #Trier I started programming during my exchange year in Bordeaux, France. After my graduation I worked at the University of Trier and specialized in Historical GIS #hisgis#hgis. Currently I am working in the field of #spatialhumanities and #digitalhumanities at the Hessische Institut für Landesgeschichte in #Marburg, using Open Source Technologies (#Python, #QGIS, #Gdal, #GRASS, #OpenLayers, #Angular et. al.)
Why am I spending time on #Python Meetup organisation at the moment? What's my ulterior motive? It's about community and feeling connected to other people. I'm not hiring, not looking for students, no hidden agenda.
Hi Mastodon friends, we have joined to hang out here with some of our members and hopefully meet some new ones! We are the Berlin chapter of PyLadies, hosting events at https://www.meetup.com/pyladies-berlin/
Discussing all things Python, diversity, inclusion, and tech 😎 🐍
I'm here for more than a year now, and I still owe you a proper #introduction.
Hi, I'm Richard! I started #programming computers when I was about 9 years old. My first computer was a ZX81 (figure out how old I am now). #OpenSource and software development has always been my passion. My favorite programming languages are #Java, #Python, and #MC68000#Assembler. 😁
Hello I'm Pekka and I do experiments in computer graphics, video art, and machine learning. I also read a lot. I mostly post about my hobby projects (or #books I'm reading).
At the moment I'm working on #homebrew#N64 stuff and making some mashups tracks. Occasionally also #demoscene coding with or without #shaders :)
ALT text detailsThe Mona Lisa converted to a low poly model.
ALT text detailsA diagram of a machine learning system that uses tiny neural cellular automata (NCA) to combine a gbuffer+depth to a painterly color image.
ALT text detailsAn illustration showing how tree sprites are spawned in our demoscene production A New World Awaits (2021).
I'm Andreas, I've been here for quite some time now, in order to stay #independent I run my own #instance. I code and #architect#software for a living in #C or #Python (yes, those are more or less the extreme ends of the spectrum). During the first Covid lockdowns here in #Austria I started learning to play the guitar. I have built 4 or 5 (lost count) and one is currently in the works, #lutherie is amazing. The current #guitar count in our household is 7.5.
It's time for my #introduction post on the new server :)
I'm Gervasio, I'm a runner, an aspiring magician, a father and a software engineer.
I live in #Uruguay and I'm working at a small startup (you can see a beautiful "coming soon" page at sumble.com) and before this I worked at #StackOverflow twice.
I enjoy #csharp, but right now I'm working on #python. I'm after interesting problems more than interesting technologies :)
I came to mastodon multiple times, but this became my home in the end of 2022. I tried to build a community (discovered I don't have the skills to do so) and then settled on a single user instance.
One thing I noticed when I was spinning up my server was that I couldn't discover relevant content, so I built #FakeRelay (an API to import content into a Mastodon instance) and then #GetMoarFediverse (as an example to use FakeRelay).
If you're curious about those, I recommend you first check out #fedibuzz, as it's simpler to run. If you still want to use FakeRelay, hit me up and I can get you started.
- Individual sessions & workshops for groups on Python & Creative coding themes; - Licenses to use my artwork and I'm available for commissions of new work; - Consulting on generative design projects (subject to time constraints).
In case you want to check out some of my stuff, I’m on #GitHub and #Spotify under the same handle (nanobot567). (Warning for my Spotify account, all of the songs on there are incredibly cringe XD)
I also have one other account on the Fediverse:
Kbin: nanobot567@kbin.social
Been having fun on Mastodon so far! Hoping to make some more friends here in the future :)
Hello new instance neighbors (and imported followers)! I'm Scarlet, and I'm a fox. I'm an arctic fox, to be specific. We're cuddly, cute, and endangered (some populations at least), so please do what you can to save the environment.
Outside of my fursona, I'm a Black socialist non-binary person with a love for #python, #rustlang, and other technology things. I'm #actuallyautistic.
My other interests include toppling the patriarchy, trans rights, and economics.
I will do my best to post accessibly, including image descriptions and avoiding flashing lights.
I will CW for things like violence, nudity, and hate speech.
I will not CW for cursing, food, politics, or eye contact. If you need CWs for these things, it's okay not to follow me! I just do all of these things a lot, so you wouldn't see most of my posts anyway.
If I see you, and you make interesting original posts, I might follow you. If you post a lot of sexually graphic content, I probably won't. It's not personal.
Hey, #introduction time! I'm Andrew Kravchuk (pronounced "KRAHV-chook"), and I'm thrilled to make my first official post on Mastodon. I've been lurking here for quite some time now, and I have to say, I absolutely love it. It's like the blue bird site, but here I feel like I'm in the warm, weird (in a good way) company of like-minded individuals.
I'm a proud #tech#geek and #programmer by trade, currently teaching programming in #C and #Python. However, my true passion lies in the #Lisp family of languages. For the past three years, I've been working on a hobby #gamedev project, which is an action RPG similar to Diablo 2 in #CommonLisp. Needless to say, I use #Emacs (but with evil-mode, since I don't have forty alien fingers 😅). Also I'm a proud Microsoft hater and #UNIX lover.
I'm a big fan of #anime, and I believe that #Evangelion is the best dramatic piece of the 20th century. I enjoy reading #books, and I dream of writing #fiction someday.
I'm excited to join Mastodon and look forward to making friends 😊
P.S. This post may or may not have been written with the aid of LLM.
1. I'm bad at shitposting 2. Generally very #nerdy and enthusiastic about lots of topics. 3. Married, dad, #bisexual, he/him 4. Originally a scientist, now work for a non-profit, but the goal for this account is to not think (or post) about work too much 5. Activist left-wing politics 6. Formerly @crowsandpawns@mastodon.lol
Introduction: coverage.py is the coverage measurement tool for #Python. It's popular enough that people don't realize there's a already a coverage tool in the standard library!
Actualmente trabajo como developer para una empresa, principalmente me encargo del CRM, que esta hecho enteramente por mi en #HTML, #CSS, #JS, #PHP y #MySQL. Tambien he hecho cosas en #Python para el trabajo, principalmente para IoT con una Raspberry.
I suppose I should do an #introduction. I'm a software engineer, programming as a hobby since 2004 and professionally since 2016. I've done a bunch of #python, #rust, and #golang. Learning #electronics and #fpga. I'm interested in the lower levels of stack. My career was in #biomedical devices, and I now work in #space tech. Desktop #linux user since 2004. Father of a small one. Done #jujitsu for mad days. Enjoy #retrogaming, #retrocomputing, and #misterfpga. Glad to be here with y'all.
I just switched instances, so here is my #introduction:
I'm Paul and I live just outside of Minneapolis, MN.
I'm a maker who is into #podcasting and programming with #Python and #CircuitPython - there's just something about interacting with hardware that I love.
I love #music: I have a large #vinyl record collection and built silversaucer.com to interact with my record collection.
Other interests include retro gaming, building an arcade cabinet, reading, and cooking.
We're a data science consultancy company who specialise in R and Python development, training courses on programming, and managing infrastructure - amongst other things!
We'll be sharing our blogs on #RStats, #Python and all things #DataScience, alongside spotlighting some of our favourite blogs we've seen in the community! We'll also share information about our events and training courses here!
ALT text detailsCartoon robot with a light bulb on its head, sitting at a desk using a laptop
New server, new #Introduction. Which reminds me that I still need to create one of those on my current main account of @wolfensteijn@mastodon.wolfschouten.nl
I like to code, self-taught, and using mostly #RStats, but have dabbled in #python and love the #linux command-line.
My background is in experimental (neuro)biology with a transition to #genomics and #transposon / small RNA biology later on. My CV is best captured in this plot done 100% with code.
ALT text detailsLine plot showing my career from laboratory experimental work to my current status as 100% data analysis using code. I represent those states with icons.
Some time ago, I started putting it all together and created NEURHOME which is still in its infancy, but it gives me a purpose (or excuse) to spend time doing stuff I like.
I'm not new to the Fediverse but an introduction is never bad!
I'm a white male from Italy. I'm anti-fascist and vegetarian. Pronouns are he/they. I love using my bike to move around the city 🚴♂️
I'm dad of 2 children, and husband of my wife. I work for the Ministry of Culture. PhD in #Byzantine#Archaeology although I now work in Liguria. I maintain small open source tools, mostly in #Python and #RStats. I have a website and a #Gemini capsule (links are in the profile)
Please don't request to follow unless we know each other from previous interactions or offline.
Vivo a #Genova. Faccio l'archeologo. Lavoro al Ministero della #Cultura
Uso ə tutte le volte che mi pare. Gli #NFT sono cacca puzzolente.
I'm guessing I sorta need an #introduction after a server move? Maybe?
anyway, I'm CleoQc, a software dev who does more operationals/supply chain than actual software development, but if I were to write code, #python would be my language of choice. Otherwise French or English, equally. I tend to be a #RaspberryPi pusher in Montreal. I teach kids the basics of electronics and coding. I also train teachers in bringing code into their classroom #raspberryPi#Microbit
Wow this is so blank. Ok I've been active on the fediverse since 2017 but this will be my new account for politics and govtech and data science and complaining. I use #R#QGIS#GIS and #Python, all poorly. #introduction
Relatedly, as for re- #introduction. I’m a guy in the East Bay Area doing software in mainly #C#C++ and #ObjectiveC , #Swift sometimes; I also enjoy #python#UNIX and the #macintosh. Team #emacs. On the non-technical side I enjoy a good (or just interesting) #beer or #whiskey , petting my adorable asshole of a dog, eating dumplings (for example, burritos and beef Wellington) and telling the absolute worst, most groan-inducing jokes imaginable.
So this #introduction thing seems to be a thing -- been here a couple of weeks and was unaware.
Anyway: I am a #Canadian retired software developer (50 years on the job) having worked over the years on #PDP10#PDP11, 8088s, Cemcorp Icons, CP/M, #Asymetrix#Toolbook, #Zope,#Python and probably others that don't immediately come to mind. A father with 2 adult children with their own children. I am a Formula 1 fan, #Porsche#Boxster owner and active high performance driver education participant.
My new blog post, in which I compare and contrast the latest versions of the popular #Python#HTTP libraries #requests and #urllib3, and ask whether requests still offers anything unique in 2022.
Je suis amateur de programmation et micro-électroniques. D'habitude, je me spécialise dans #php et #python.
Je fais beaucoup de projects avec des ordinateurs monocartes et #CircuitPython.
J'aime apprendre, faire et enseigner les arts et les sciences pré-industriels et passer des week-ends vêtus de drôles de vêtements lors d'événements #SCA.
Je suis situé dans le centre-sud de la PA USA depuis 2018.
J'ai commencé à apprendre le français en nov 2020 avec #Duolingo.
I also enjoy learning, doing, and teaching pre-industrial #arts & sciences and I spend some weekends in funny clothes, hanging out with people at #SCA events.
Just realised that I've never done a #introduction here. So here it goes. I'm Parxevicj(the name has no meaning its just keyboard smash), I'm interested in programming(mostly #rust, but i also do #python sometimes), open source, light novels and manga. I'm usually a lurker, but I'll try to post on this account often.
Hákarl is the name of my musical project - guitar, oud, violin. Sounds like this: https://vimeo.com/394663122
I live in #Brighton (UK, boo). My politics are broadly (left-) anarchist. Trans rights are human rights, Black Lives Matter.
There's a longer story about it but I use 'they' pronouns online - I do identify IRL as cis (boo) but I'd rather people who don't know me didn't identify me with a gender.
#introduction on the occasion of switching instances. I'm Marcin, he/him, mostly #programming; #Go/#golang these days, earlier #Python, Javascript, C++, Perl, Java, to Pascal and Basic 30+ years ago. I burn through hobbies fast; photography and music stuck for longer, both in "I have no idea what I'm doing but this is fun" mode. Also #electronics and building stuff for festivals, from #blinkenlights to night clubs in Nowhere.
I'm excited and honored to be included in this group of authors - "Python in a Nutshell, 4th Ed" gets released this month! New features in this edition: - detailed coverage of Python versions 3.7 through 3.11 - all new material on recent Python features, including type annotations and structured pattern matching - an appendix cataloging changes by each version 3.7 through 3.11 - selected online chapters and all source code examples available in a Github repository #python#oreilly#pynutshell4
Day job is working in DevOps at Beta Technologies, an electric #aviation eVTOL startup. I also help out with telemetry and software verification. I work mostly in #Python and #C there.
Now that I’m somewhat-settled on my new instance, I’ll (re)introduce myself… If you know me from #RollerDerby I'm Hewlett Smackard or just Smacky. Otherwise I’m Andrew.
#Introduction: I’m Lucas, bi software developer and Wikimedian from Berlin. I like writing tools for #Wikimedia#Toolforge, mainly in #Python, though I’m also working on a #JavaScript library to use the MediaWiki API; on the projects, I’m mainly active on #Wikidata and #WikimediaCommons. I play the #piano and occasionally live-stream that or post recordings. I’m making my way through #Tolkien’s The History of Middle-earth. I speak German, English and some Portuguese. Nice to meet y’all 🙂
After two years of lurking, I think it's time for a proper #introduction.
I'm a software developer from Italy, I love #Python and #Django. I'm also some kind of #sysadmin, I maintain a wide range of services for myself and my friends, including a #nextcloud instance, a #minecraft server and this #mastodon instance.
Hi, I’m Andy, a planetary geologist living on Planet Houston. I currently work at NASA-JSC for a contractor company. I spend my time crafting maps for Artemis Program. Previously, I targeted CTX for a little over 5 years at MSSS. I mostly use #GDAL, #QGIS, #Python, and ImageMagick to get stuff done but am looking to always learn more #FOSS software.
Oh god I need to make an #introduction apparently 26 yo, bi ace transmasc NB, from Ohio but living in Berlin. I've got #ADHD, #neurodivergent#queer and proud.
My hobbies: - I fucking love to #conlang and it's also how I met my spouse. - I've started learning #embroidery and am hoping to get into #threadpainting - I enjoy #gaming, especially when it's an #indiegame. My favorites are narrative-driven games like #discoelysium or simulation games like #rimworld and #sims. I'm also interested in #gamedev, but I haven't dipped my toes yet.
Studied #linguistics in undergrad and switched to #NLP for grad school. I used to want to continue in academia but realized I'd rather make more money and have better work-life balance not doing that. Now I work in #datascience coding in #python for a tech startup and am generally pretty happy with that setup. My heart still calls out for #semantics and #pragmatics though.
This is the #introduction post for #py5, a new version of #Processing for #Python. The goal of py5 is to create a new version of Processing that is integrated into the Python ecosystem (python 3.8+). Py5 makes the #Java Processing jars available to the CPython interpreter using JPype. It can do just about all of the #2D and #3D drawing Processing can do, except with Python instead of Java code. Visit https://py5coding.org/ to learn more!
ALT text detailscube with multicolored sides at a slight angle
First, a little trivia: "Fatiando a Terra" is Portuguese for "Slicing the Earth", a reference to the project's Brazilian 🇧🇷 roots and ambitious goals to model the entire planet.
for tool in fatiando: help(tool)
ALT text detailsScreenshot of the Fatiando logo (the Earth with a slice cut off showing the inner layers).
Text says:
An open toolbox for the Geosciences. Fatiando provides Python libraries for data processing, modeling, and inversion across the Geosciences. It is built by a community of geoscientists and software developers with a passion for well-designed tools and helping our peers. All of our code is free and open-source, distributed under the permissive BSD 3-clause license.
Below it, there are the logos of our main Python tools: Verde, Pooch, Harmonica, Boule, and Ensaio.
Hello world! Been lurking a few days, time for an #introduction I guess.
Been in infosec for almost 14 years now (wow time flies!). Went the military way - studied computer engineering, then ended up in a infosec type junior leadership position straight out of uni.
Worked with some great people and had some awesome opportunities. Worked in forensics and building up training programs. But it was here where I largely realized I didn't want to play the promotion/leadership game. I like doing technical work more than people management work.
I worked in mil/government for a few more years, did some SIEM engineering work and then packet and malware analysis.
Now in the private sector but in a largely infra/operations role, working on automating all the things. Lots of work with #ansible, #python, #postgresql.
I think this toot is probably more text then I ever wrote on the birdsite over many years.
I love and occasionally make #music and #photography, noodling on the guitar and spinning basic electronica.
But I've done much less of that over the last few years and spent too much time doomscrolling instead, so hoping the demise of the other place might let me recover a bit of my creative life. (Although we’ll still have time for a bit of #politics, won’t we?)
We will be posting tips, news about the project, and cool plots. Stay tuned!
ALT text detailsThree dimensional schematic plot of the Earth and two orbits around it, one of them highly eccentric and inclined
ALT text detailsTwo dimensional schematic plot of the inner Solar System plus the trajectory of the Florence asteroid
ALT text detailsThree dimensional schematic plot of the Earth with several close debris fragments orbiting around it, plus the orbit of the International Space Station crossing the debris cloud
ALT text detailsPorkchop plot (contour plot) of an Earth - Mars launch window for the year 2005, showing energy, travel time, departure velocity, and more
I should actually re-post and pin this #introduction since my move from mastodon.social:
Hi, I’m Andy, a #devops techie from the UK with a particular obsession with over engineering my home network setup. I operate dimension.sh (a tilde/pubnix), I’m also a Disney parks fan, Texans fan, and when I get a spare moment I enjoy a bit of wood working.
Long term mission: The knowledge to solve any problem in the world might be hidden in scattered PDF files that are barely read. I want to contribute to the improvement of this unsatisfactory situation, especially in the (partly overlapping) domains of #engineering and #sustainability
Hello Fediverse! #Introduction time for me. Érico Andrei, a software developer, retrocomputing aficionado, and open source evangelist. Based in São Paulo, 🇧🇷. Nowadays, I'm a #Plone core developer, #Python developer, maintainer of #Cookiecutter, and member of the Brazilian #Plone and #Python communities. Former president of the @plone Foundation. Touts will be in #en and I may go off-topic and post about #politics, #scifi, #soccer and #Mooca. #LLAP
An #introduction might be in order, as I'm starting to settle in! 👋
At my day job I'm doing backend development (#rustlang / #python), some #data engineering / analytics, some #cloud#infrastructure , and helping to evolve our architecture as we grow.
Beyond that I find #3dprinting fun & often useful, I am an occasional #gamer (mostly console), and I enjoy home improvement projects.
Currently I'm really focusing on digging deeper into Rust, as I've enjoyed working with it a lot!
The websites also have links to the publishers' web stores if you prefer hard copies of these
ALT text detailsCover of the book Bayesian Data Analysis, 3rd ed
ALT text detailsThe cover of the book Regression and Other Stories
ALT text detailsCover of the book Active Statistics: Stories, Games, Problems, and Hands-on Demonstrations for Applied Regression and Causal Inference by Andrew Gelman and Aki Vehtari
ALT text detailsPicture of example #Python code that shows how to download a seismogram recording for a station in Europe for the devastating 2011 Tohoku earthquake that caused the Tsunami leading to the meltdown of the Fukushima nuclear plant.
Python code following:
from obspy import UTCDateTime
from obspy.clients.fdsn import Client
# this is when the earthquake started
origin_time = UTCDateTime("2011-03-11 05:46:24")
# it takes quite a while for the waves to get to this station
start = origin_time + 10 * 60
end = start + 70 * 60
client = Client("BGR")
st = client.get_waveforms("GR", "FUR", "", "BH?", start, end)
st.filter("lowpass", freq=1)
st.plot()
ALT text detailsPlot of the seismogram waveforms downloaded and displayed by the #Python code in the other image. The seismogram shows a three component recording with a mix of different phase arrivals, including both body waves that travel through the interior of the Earth and also surface waves that travel along the surface of the Earth and are slower but have larger amplitudes.
Posting an #introduction for a pseud is a bit weird. Expect a bit of everything. I’m trained in synthetic organic #chemistry . I’m an #NMR enthusiast, amateur #python programmer, enjoyer of various nerdy things such as #gameing with an ‘e’ and #chess. I enjoy cooking, and I sometimes post pictures of my cats.
I live in the #uk, detest #brexit and am getting more and more left-wing as I get older.
I’m interested in #ActiveTravel, #CargoBikes and #LivableCities (despite living in a small village in the countryside) and would one day love to build a sustainable, eco-home.
In my #introduction post I didn't realize the importance of hashtags yet, so here are a bunch of things I'm interested in! Follow me, I'll follow you, everyone wins!
#introduction time! I'm Jonathan Carroll, known around the sites as jonocarroll and on the bird site as carroll_jono (the other name was taken).
My PhD (2009) was in theoretical physics (Fortran90). I've since worked in fisheries (stats), then cancer immunology with Genentech, and most recently precision autoimmunology with a biotech startup HIBio. I'm mostly #rstats but learning #julia, #rust, and #python for fun. I work remotely from #australia and I blog at https://jcarroll.com.au
👋 Hi! I'm Katie (they/them). 🐨 I live in Naarm (Melbourne), Australia. 🧵 I craft a bunch (wool tapestry, cross-stitch, blackwork embroidery) 🧑💻 I work as a Developer Relations Engineer (My job explained poorly: "I get frustrated with new tech so you don't have to."). 🦜 I like emoji. Even made some! 🎤 I run and speak at a lot of #python, #django, and #devops events. Like, a lot. 👟 I also like running (events and trails!) ☕ I enjoy both coffee and tea (🧋 and 🍵 )
I studied #Architecture at university, and a love of computer aided design set me on course for an IT career. I've been in #infosec for about 20 years.
In the 'before times'™ I was a #paraglider 🪂 pilot and #hillwalker ⛰️ - hopefully I'll get back to that soon.
#introduction: I'm a software developer and occasional data scientist living in #Helsinki. Favourite technologies include #python, #matplotlib (I started the PDF backend way back), #go, #clojure. Currently employed as a consultant at Reaktor. I coach #math olympiad contestants and am trying to learn #taichi.
I am single-sided deaf because of an acoustic neuroma, so I'm not very good company at cafes or parties or on the phone, and get tired easily when talking to people.
I studied #physics and am now working as Solutions Engineer for Posit PBC (f.k.a. RStudio), I like riding my #bicycles, I am interested in #politics, I am concerned about the #climatecrisis (born at 329 ppm), I try to use #linux and more generally #FOSS as much as possible, I sometimes dabble with #datascience using #rstats or #python, I like good #typography and use #LaTeX to produce it, I am still looking for a way to get back into analog B&W #photography.
I never did proper #introduction post in the 3 years since joining. I'm a nerd of all trades (and master of none), so I'll just pick some: I like working with #embedded systems, and linking them across the Internet (which some call #IoT). As I want those to be efficient, interoperable and secure, I spend much time around the #CoAP stack of protocols -- both contributing to its specs at #IETF, and writing #FreeSoftware implementations in #RustLang, #Python and on @RIOT_OS (in C).
🐘 #introduction Hi there 👋! I'm a seasoned software engineer, educator, and author with a deep love for #golang, #python, and #java.
When I'm not immersed in code or bridging the gap between academia and the IT industry, you'll find me hitting the trails, indulging in my passion for long-distance running.
Beyond the tech and the tracks, I'm on a mission to spread positive vibes and #goodnews. In a world filled with noise, I believe in highlighting the good, the hopeful, and the inspiring.
I know just enough #statistics to be useful / dangerous, depending on your POV.
I use #rstats heavily (in a lab that mostly uses #python), and believe in the value of graphing your data, as well as making work reproducible and as open as possible.
I program for a living, mostly in #python these days. I love #scheme and the #guix system and have biases towards #foss. I'm currently trying to use #guile scheme more often to better understand this wonderful #lisp. My day job mostly involves hacking on proprietary #gis software and #kubernetes.
Other hobbies revolve around #bikes, #foraging, and travel. I'm especially obsessed with #mushrooms.
I live in #Norway, I'm a proud father of three, and I enjoy being a dad.
ALT text detailsAn Autarkic Wireless Sensor Network to Monitor Atmospheric CO2 Concentrations
Abstract
In this study an autarkic low-cost wireless network infrastructure suitable for areas spanning a couple of
hectares is introduced. Open source hard- and software components make up the infrastructure’s core,
rendering it very scalable in terms of cost and deployment density. The network is designed to operate
continuously throughout the year in a wide range of weather conditions.Four different embedded, low-cost
Sensirion SCD30 non-dispersive infrared (NDIR) CO 2 sensors are evaluated under laboratory conditions
and tested for cross-sensitivity on water vapour and linear characteristics, of which the Sensirion SCD30
sensor exhibits the best overall performance. An in-field comparison of eleven Sensirion sensors with
an eddy-covariance station verifies its outdoor applicability. The network’s suitability to monitor natural
CO 2 emissions was tested at a site in the upper Neckar Valley in southwestern Germany. A station with
a single Sensirion sensor observed a strong diurnal cycle of the near-surface CO 2 concentration over the
course of several months. While only slightly elevated CO 2 levels above 400 ppm prevailed during the day,
concentrations reached the sensor’s output limit of 40 000 ppm during the night when wind speeds are low.
ALT text detailsFigure 1: Aerial view of the Starzach site taken in summer 2019 by Martin Schön and map of Germany with part of the Neckar valley
region as orientation. Visible focused CO 2 exhalation spots are marked as yellow dots, their size loosely indicating the apparent intensity.
Fields of diffuse degassing are indicated as purple areas. Degassing spots appear in SW-NE direction across the site and are discussed by
Lübben and Leven (2018) to be associated with a geological fault line. Map data ' OpenStreetMap contributors (2021).
ALT text detailsFigure 3: Network infrastructure schematic. An on-site single-board
computer acts as a central station and establishes a Wireless Local
Area Network (WLAN) to which all stations connect. Stations store
their sensor data locally and transmit it wirelessly to the central
station, where data is logged to a database. The central station
maintains an internet connection to an off-site server to enable
remote maintenance and live data monitoring. This server mirrors
the on-site network traffic and relays a selection of the measurements
to the openSenseMap platform for data display and live monitoring.
ALT text detailsFigure 4: General design of a sensor station. (a) An ESP8266 microcontroller mounted on a custom circuit board in a weatherproof box
is powered externally via a 12 V two-wire cable. (b) A custom circuit board capable of holding up to eight Sensirion SCD30 CO 2 sensors
mounted below a simple radiation shield is connected to the microcontroller via a patch cable with RJ45 connector. (c) Radiation shield
holding a custom multi-sensor circuit board with Sensirion SCD30 CO2 sensor, Bosch BME280 environmental sensor (atmospheric pressure,
temperature, relative humidity), CUBIC CM1106 CO 2 sensor and theben CO 2 Sensor Module.
Я программист, сейчас на #typescript пишу всякие #web штуки. Последнее время упарываюсь в #web3, то есть #crypto, децентрализация и всякое такое. В вебе со времён #jquery и ES3, но про них обычно вспоминают как о страшном сне. Могу ещё писать на #python и #rust.
Но вообще когда-то давно хотел стать дизайнером. Не потому что творчество люблю, а потому что люблю делать красиво и удобно.
В свободное время... Скажем, что в свободное время я тюленю перед компом, пытаясь найти в интернете всякого интересненького. Не так давно нашёл вот Mastodon и потихоньку задумываюсь о том, чтобы сделать свой сайт в лучших традициях #indieweb
My main hobbies are #classicalguitar and the ancient game #go or #baduk -- I'm 1-5k, always looking for people who want to play in person regardless of level!
My occupation is software developer and project manager. Currently my hobbies are: programming (on diverse layers), 3D modeling, UAV (aka Drone) stuff, control theory, all kinds of simulations, embedded systems development, a bit of hardware hacking and photography.
Hi, I am known as dunkelstern almost everywhere, in real life just call me “jo”.
I am a backend-developer using #python and #javascript by day, but i am living on github by night too and working on one of those unfinished projects there (#rust, #c, python and #cad)
Hi, ich bin fast überall dunkelstern, im echten leben sagen die leute meistens Jo.
Ich arbeite als backend-entwickler mit #python und #javascript, bin aber auch privat auf github zuhause und kippe dort meine drölf millionen unfertige projekte ab (#rust, #c, python und #cad)
Wenn ich nicht an meinem #smarthome bastel dann wahrscheinlich an irgend nem #3d-drucker oder sonstigem #elektronik gebastel.
Am wochenende findet ihr mich im habitat in augsburg, meinem #makerspace
-=- I'm FiXato, a stay-at-home father of a two-year-old I often refer to as #BeardGrabber. While I was born in the Netherlands, I've been living in northern Norway for quite some time now.
What do I do?
-=- In day-to-day life I take care of our son while the missus is at work, and when I have some spare time and headspace, I like to tinker on my various coding projects.
I also make #videos. Mostly farm life, but I make videos for my clubs, church, school projects, too. I fly a #dji#mavic, and use a #gopro. Still have a lot to learn, but I'm pretty proud of my work.
I am new at this #mastodon instance: I'm an architect and PhD on social sciences who studies the commodifications between #cities, #technology and #society in the context of the Urban Studies and I am now pursuing a more data-scientist approach. I've been using #R for some years and I am now starting with #python
I'm looking for people with similar research interests or who can help me improving my skills.
Thanks @cxli for kindly introducing me to this nice ritual.
Hi! I'm mostly here for conversations, reflections, and geekery around subjects that catch my fancy. Recently that orbits technology (esp #Python, data services, networks), music (writ large), languages (esp ancient Greek), autism, and general silliness. Structural protection for the marginalized is close to my heart, but I've learned I need to engage gently to stay healthy. I try to keep shitposting to a minimum.