Weekly Report August 1 - 7
This week I spent helping 3.11.0rc1 get released. This included both reviewing PRs and helping release blockers get resolved. There were two in particular that I spent most time on so I’ll talk briefly about them now.
Cancel this task. Uh, nevermind… uncancel. UNCANCEL!
I talked before about except* being really exciting for Python 3.11 and since then task groups got added to CPython. It’s an awesome piece of structured concurrency that makes tracking running tasks automatic and bullet-proof. This solves a long-standing complication of managing asyncio programs.
There’s a pretty interesting tidbit in that piece of machinery that has to do with an async function that has an
async with block with a
TaskGroup. Something like:
async def do_things(): await some_code() async with asyncio.TaskGroup() as tg: tg.create_task(code_scheduled_within_the_task_group()) await other_code_awaited_on_within_the_task_group() await unrelated_code()
In Python 3.10 and older, when a task that we’re awaiting on got cancelled, the cancellation bubbled up to us as well. With task groups the problem is that we both want the cancellation and don’t want it: if
code_scheduled_within_the_task_group() gets cancelled for any reason, we do want to cancel
other_code_awaited_on_within_the_task_group() (because it’s structured concurrency: it’s organized as part of the task group) but we do not want to cancel
unrelated_code() that is outside of the task group.
But we can’t just cancel a block of code within an async function! Or can we? Turns out we can, with the help of the new
Task.uncancel method! The way it works is that it will cancel
do_things() but as soon as the task group
tg exits, it will uncancel
do_things() so it can continue running.
Fascinatingly, this ability is what held back a nice timeout context manager all this time. Now we can have it:
async def make_request_with_timeout(): try: async with asyncio.timeout(1): # Structured block affected by the timeout: await make_request() await make_another_request() except TimeoutError: log("There was a timeout") # Outer code not affected by the timeout: await unrelated_code()
I’m hoping to add this example to the docs.
Emails are weird
One problem I took care of this week, unrelated to CPython itself but affecting the core developer workflow, was the CLA bot’s handling of email address uniqueness.
You see, email addresses aren’t as bad as HTML, which as we all know cannot be parsed with regex. But the full RFC 5322 compliant regex for email addresses is quite a beast.
The particular problem we had was due to privacy-related features built into email addresses, namely
+suffixes for sorting task-specific emails and that dots don’t matter in Gmail addresses.
It turns out that people sometimes use a different email variant for git commits and a different email associated with their GitHub account. For example, one might be
firstname.lastname@example.org, and the other might be
email@example.com. And sometimes a new laptop got configured and the
user.email field in
~/.gitconfig got configured to yet another address, like
TylerDurden@ikea.com. We already make email address matching case insensitive but I had to also make
+suffixes irrelevant. For Gmail addresses the additional complication is that
firstname.lastname@example.org is the same as
As you can see in the PR for the required change, thanks to EdgeDB’s built-in migrations this was a rather simple thing to do. However, I had to split the process in two parts because the
normalized_email field in the schema needs to be unique and in 19 cases in our production database the new normalization would end up with duplicate addresses. So I had to add a short script to deduplicate the database before the final schema change was pushed to production.
Week in numbers
- issues: 2 closed
- PRs: 26 closed
- closed edgedb/cla-bot#51
- closed issue GH-95155
- closed issue GH-95376
- authored edgedb/cla-bot#53
- closed pull request GH-95442
- closed pull request GH-95652
- closed pull request GH-95648
- closed pull request GH-95614
- closed pull request GH-95687
- closed pull request GH-95663
- closed pull request GH-95686
- closed pull request GH-95683
- closed pull request GH-95692
- closed pull request GH-95696
- closed pull request GH-95701
- closed pull request GH-95700
- closed pull request GH-95699
- closed pull request GH-95492
- closed pull request GH-95515
- closed pull request GH-95668
- closed pull request GH-95705
- closed pull request GH-95284
- closed pull request GH-95412
- closed pull request GH-95726
- closed pull request GH-95718
- closed pull request GH-95743
- closed pull request GH-95742
- closed pull request GH-95745
- closed pull request GH-95744
- closed pull request GH-95747