Leonard Richardson's Blog

June 20, 2025

The Coffeeshop AU

My metafictional Great Gatsby fanfic "The Coffeeshop AU" is published in Solsitita issue #3, the appropriately named "Coffeeshop!AU" issue:


"He's in love with Daisy," said Jordan, with as much
certainty as if she'd added the tags and written the
content note herself. "Maybe Tom," she hedged, "but
Tom's an asshole. Daisy's nice enough." This belief of
Jordan's ��� that Daisy was any less obnoxious than Tom
��� was the first of many alarms I missed as I dropped
like a flipped coin on the unalterable trajectory of my
relationship with her.


Available for cheap as an EPUB or PDF!

 •  0 comments  •  flag
Share on Twitter
Published on June 20, 2025 10:41

March 15, 2025

The Crummy.com Review of Things 2024

It took me til March, but I pulled it off this year! Here are the best media I experienced (or created) in 2024:

I'll start by tooting my own horn, because why not. I had two stories published in 2024: "Expert Witness" (A Ravy Uvana Story) in Analog and "The Blanket Thief" (cozy fantasy) in the Winter 2024 issue of Baubles From Bones. You can hear me read "Expert Witness" on the Analog podcast.

I gave a talk at PyCon US, How to maintain a popular Python library for most of your life without with burning out", and I was honored with the Python Software Foundation Community Service Award. I wrote two as-yet-unpublished stories in 2024, "A Tomorrow Problem" and "Cause of Action" (both in the Ravy Uvana universe).

Now, on to things not created by me. The Crummy.com Game of the Year is Balatro, a game that doubles down on the part of roguelikes I enjoy the most: the clever creation of wacky, game-breaking combinations from randomly presented choices. Honorable mention to Slice & Dice, the roguelike I have on my phone to stop myself from doomscrolling.

Other games of note: Animal Well and Baldur's Gate 3. I was really into BG3 and played it exclusively up until the point of my Japan trip, but when I came back the spell had been broken and I can't get back into it to finish it.

The Crummy.com Book of the Year is Between Silk and Cyanide by Leo Marks. The story of the codebreakers of Bletchley Park has been well told, but I'd never before considered the parallel story of the people creating codes for Allied intelligence to use. This memoir was a fascinating look into bureaucratic infighting; logistics nightmares; the simultaneous invention of one-time pads; and the difficulties of trying to give cryptographic training to a rotating cast of strong-willed characters who, Wikipedia will tell you, frequently do not survive the war.

I spent a lot of 2024 reading comic crime novels for research. I read a bunch of Donald Westlake's Dortmunder books (Drowned Hopes stands out but I don't recommend that as your first one), Kyril Bonfiglioli's art scam trilogy (I tried to watch Mortdecai (2015) but couldn't get through the first friggin' scene), and the first three of Sarah Caudwell's academic/lawyer murder mysteries.

Also of note: the manga Yokohama Station SF, old issues of the trade publication The Soda Fountain, and the really funny The Husbands by my friend Holly Gramazio.

 •  0 comments  •  flag
Share on Twitter
Published on March 15, 2025 08:19

February 2, 2025

Beautiful Soup 4.13.0

After a beta period lasting nearly a year, I've released the biggest update to Beautiful Soup in many years. For version 4.13.0 I added type hints to the Python code, and in doing so uncovered a large number of very small inconsistencies in the code. I've fixed the inconsistencies, but the result is a larger-than-usual number of deprecations and changes that may break backwards compatibility.

The CHANGELOG for 4.13.0 is quite large so I'm writing this blog post to highlight just the most important changes, specifically the changes most likely to make you need (or want) to change your code.

Deprecations and backwards-incompatible changes


DeprecationWarning is issued on use for every deprecated method, attribute and class from the 3.0 and 2.0 major versions of Beautiful Soup. These have been deprecated for at least ten years, but they didn't issue DeprecationWarning when you tried to use them. Now they do, and they're all going away soon.

This version drops support for Python 3.6, which went EOL in December 2021. The minimum supported major Python version for Beautiful Soup is now Python 3.7, which went EOL in June 2023.

The storage for a tag's attribute values now modifies incoming values
to be consistent with the HTML or XML spec. This means that if you set an
attribute value to a number, it will be converted to a string
immediately, rather than being converted when you output the document.

More importantly for backwards compatibility, setting an HTML
attribute value to True will set the attribute's value to the
appropriate string per the HTML spec. Setting an attribute value to
False or None will remove the attribute value from the tag
altogether, rather than (effectively, as before) setting the value
to the string "False" or the string "None".

This means that some programs that modify documents will generate
different output than they would in earlier versions of Beautiful Soup,
but the new documents are more likely to represent the intent behind the
modifications.

To give a specific example, if you have code that looks something like this:

checkbox1['checked'] = True
checkbox2['checked'] = False

Then a document that used to look like this (with most browsers
treating both boxes as checked):


<input type="checkbox" checked="True"/>
<input type="checkbox" checked="False"/>


Will now look like this (with browsers treating only the first box
as checked):


<input type="checkbox" checked="checked"/>
<input type="checkbox"/>


You can get the old behavior back by instantiating a TreeBuilder
with attribute_dict_class=dict, or you can customize how Beautiful Soup
treats attribute values by passing in a custom subclass of dict.


If you pass an empty list as the attribute value when searching the
tree, you will now find all tags which have that attribute set to a value in
the empty list--that is, you will find nothing. This is consistent with other
situations where a list of acceptable values is provided. Previously, an
empty list was treated the same as None and False, and you would have
found the tags which did not have that attribute set at all.

When using one of the find() methods or creating a SoupStrainer,
if you specify the same attribute value in attrs and the
keyword arguments, you'll end up with two different ways to match that
attribute. Previously the value in keyword arguments would override the
value in attrs.

The 'html5' formatter is now much less aggressive about escaping
ampersands, escaping only the ampersands considered "ambiguous" by the HTML5
spec (which is almost none of them). This is the sort of change that
might break your unit test suite, but the resulting markup will be much more
readable and more HTML5-ish.

To quickly get the old behavior back, change code like this:


tag.encode(formatter='html5')


to this:

tag.encode(formatter='html5-4.12')

In the future, the 'html5' formatter may be become the default HTML
formatter, which will change Beautiful Soup's default output. This
will break a lot of test suites so it's not going to happen for a
while.



New features


The online documentation now includes full API documentation generated from Python docstrings.
The new ElementFilter class encapsulates Beautiful Soup's rules
about matching elements and deciding which parts of a document to
parse. This gives you direct access to Beautiful Soup's low-level matching API. See the documentation for details.

The new PageElement.filter() method provides a fully general way of
finding elements in a Beautiful Soup parse tree. You can specify a
function to iterate over the tree and an ElementFilter to determine
what matches.

The NavigableString class now has a .string property which returns the
string itself. This makes it easier to iterate over a mixed list
of Tag and NavigableString objects.

Defined a new warning class, UnusualUsageWarning, which is a superclass
for all of the warnings issued when Beautiful Soup notices something
unusual but not guaranteed to be wrong, like markup that looks like
a URL (MarkupResemblesLocatorWarning) or XML being run through an HTML
parser (XMLParsedAsHTMLWarning).

The text of these warnings has been revamped to explain in more
detail what is going on, how to check if you've made a mistake,
and how to make the warning go away if you are acting deliberately.

If these warnings are interfering with your workflow, or simply
annoying you, you can filter all of them by filtering
UnusualUsageWarning, without worrying about losing the warnings
Beautiful Soup issues when there *definitely* is a problem you
need to correct, such as use of a deprecated method.

Emit an UnusualUsageWarning if the user tries to search for an attribute
called _class; they probably mean class_.
 •  0 comments  •  flag
Share on Twitter
Published on February 02, 2025 10:34

January 20, 2025

“Experience keeps a dear school, yet Fools will learn in ...

“Experience keeps a dear school, yet Fools will learn in no other.” —Benjamin Franklin
 •  0 comments  •  flag
Share on Twitter
Published on January 20, 2025 03:39

January 19, 2025

Miscellaneous 2024 Pictures


Since I went through the trouble of finding a static gallery generator for my Japan photos, I made another portfolio of miscellaneous pictures from the rest of 2024.

Enjoy glimpses of amazing things that were part of my life last year, but which I didn't necessarily take the time to write about here.


the Rock 'N' Roll Hall of Fame
the Andy Warhol Museum
Storm King
a baseball game played under Brooklyn Atlantics1864 rules
the inaccurate geographic center of New York City
a visit to the Kaufman Astoria Studios prop trailer
and lots more!
 •  0 comments  •  flag
Share on Twitter
Published on January 19, 2025 14:45

January 12, 2025

2024 Japan trip


I've hinted at this before in NYCB but now I've got my photos organized and I'm ready to talk about the vacation I took in Japan last November. I was nominally on vacation with my friend James, but he was working most days, so I spent a lot of time walking around exploring before meeting him for dinner, which I found to be a great way to run a vacation.

I've put up a huge photo gallery of pictures full of wacky and interesting stuff, but in case you're planning your own visit, here are some of my recommendations:


Hibiya Park in Tokyo, where they have a replica of the Liberty Bell.
The Meguro Parasitalogical Museum
The playful architecture of Makoto Sei Watanabe: Aoyama Technical College, the Iidabashi subway station, and, uh, the K Museum. I knew the K Museum had been shut down, but after taking a long bus ride to see its corpse, I discovered that it was also covered in tarps and undergoing demolition. Oh well, I got to see a neighborhood of Tokyo I wouldn't have seen otherwise.
NTT DoCoMo History Square, featuring a timeline of hundreds of old cell phones. The moment in history where the iPhone is introduced looks like the mass extinction that wiped out the Ediacaran fauna. The guy who runs the museum was really excited to have a visitor, so check this one out!
Huge tonkatsu. It's delicious. I tried the Nagoya style but I prefer the original.
Between Tokyo and Kyoto we spent two nights at the Kashiawaya Ryokan in Shima Onsen, a place much like the onsen town in the movie River. It was great to have some downtime after a week of running around Tokyo.
The Kyoto Railway Museum.
The Kyoto Museum of Crafts and Design. Don't be fooled by the size of the building; this a really small museum in the basement a convention center. Great museum, though.
National Museum of Art in Osaka.
The Silver Ball Planet arcade, also in Osaka. I'm sure there are bigger pinball arcades in the United States but this was the biggest one I've been in.
The Atomic Bomb Dome in Hiroshima is rightfully famous but I was also struck by the actual hypocenter of the nuclear explosion, which just has a plaque next to a hospital and a parking garage.
The Toyota Museum in Nagoya, which is divided into two parts: looms and cars. A must for fans of lean manufacturing!
I don't want to contribute to Kyoto's overtourism problem, but the Fushimi Inari Shrine was amazing. I got there at 8:30 AM and it was pretty crowded already, but the further up the mountain you hike, the less crowded it is (and the more expensive the vending machine water is). I will tell you that I didn't get much out of the hike once I passed the scenic viewpoint about halfway up.
The other huge overtouristed site in Kyoto, the Arashiyama Bamboo Forest, is... not as amazing IMO. But, on the other side of the forest is the Arashiyama Park, which is really nice.

Why did I call it Beautiful Soup instead of Nuts DOM?
It took some planning but I got a great view of Mt. Fuji from the shinkansen on the way back to Tokyo. It's so much bigger than anything else in the landscape that it feels like someone landed an asteroid.
The Tokyo Printing Museum, a museum designed to showcase the wealth of Toppan, a big printing company. But it's some pretty cool wealth. In addition to lots of old-timey prints and oboks there was a really nice temporary exhibit about linotype machines, but I've got nothing but memories from that part since photos weren't allowed in the temporary exhibits.

There are two Tokyo neighborhoods with little whale statues, and I saw both of them in the same day: 1 2



Finally I want to mention a couple stores that I didn't take pictures of. B-Side Label has cool laptop stickers. There are a few locations; I went to the one in Kyoto.

Second, New Yorkers might remember City Bakery, which sold really great pastries including the legendary pretzel croissant, plus hot chocolate which was way too rich for my taste. In 2019 City Bakery went out of business, leaving Americans croissant-less. But there are twenty City Bakery locations in Japan! We were randomly walking through a mall in Nagoya—bam! City Bakery! Heading to the Kyoto shopping district—City Bakery! They're quite a nostalgia trip, with everything looking and tasting exactly like it did the old City Bakery on 19th street, or maybe 18th, I could never remember. Anyway, that's why I've now got a freezer full of pretzel croissants from halfway across the world.

 •  0 comments  •  flag
Share on Twitter
Published on January 12, 2025 09:56

January 5, 2025

2024 Film Roundup Roundup

I saw 73 movies in 2024, and twenty were good enough to be added to Film Roundup Roundup, my ever-growing list of over 300 really good movies.

Here's my top ten for 2024. A very big year for Japanese movies, but Hundreds of Beavers takes the gold home for the U.S. of A.


Hundreds of Beavers (2022)
Supermarket Woman (1996)
River (2023)
Tokyo Olympiad (1965)
Slacker (1990)
Dance With Me (2019)
The Big Clock (1948)
A Taxing Woman (1987)
Something Wild (1986)
The Fastest Gun Alive (1956)
 •  0 comments  •  flag
Share on Twitter
Published on January 05, 2025 08:51

January 3, 2025

The Eater of Meaning is now part of the olipy family

You know that email you get when a website you like is acquired by a big company and you know it's going to get shut down? This is like that, only the website shut down first and then got merged into a bigger project.

In May 2003 I created The Eater of Meaning, a web proxy that changes the words on a web page and renders the results. It was popular for a while in the "blogosphere" and then I kind of forgot about it for 20 years, until it broke in 2024.

Throughout 2024 I got occasional emails from poets about the Eater of Meaning and could I fix it. Upon reflection I decided that while running a public web proxy on my personal website in 2003 was kind of fun, doing so in 2024 is a bad idea. So the CGI script breaking was a blessing in disguise. But I didn't want the Eater of Meaning to disappear entirely because, as I've found out, it's important to some poets' artistic practice.

So I've rewritten the Eater of Meaning code in modern Python, and added it to olipy, my pack of art supplies. With basic Python skills (or even Python package-installing skills) you can have access to just about all of the Eater of Meaning's old functionality, as well as some new eaters based on the other olipy tools. I realize that this isn't as convenient as having it as a proxy on a website, but this is the best I can do for now.

 •  0 comments  •  flag
Share on Twitter
Published on January 03, 2025 06:46

October 24, 2024

(A) Stand-up to Protect Our Vote

This Saturday, my spouse Sumana will be performing a short comedy set as a fundraiser for the Election Protection Hotline. Donate to a good cause and enjoy some technical humor!
 •  0 comments  •  flag
Share on Twitter
Published on October 24, 2024 08:02

July 27, 2024

When does The Phantom Tollbooth take place?

I just read The Annotated Phantom Tollbooth, with annotations by Leonard S. Marcus. The annotations were excellent regarding earlier drafts of the manuscript, and the correspondence between Norton Juster and Jules Feiffer. But some of the annotations brought in scholarly analysis of the book's concepts, and I thought a lot of those fell flat compared to the gold standard of annotated children's books, Martin Gardner's The Annotated Alice.

However, a couple things I noticed as I reread the book with those annotations put me in the mood to answer a specific high-concept question: when does this story take place, exactly? I did come up with an exact answer: though published in 1961, The Phantom Tollbooth begins on Tuesday, April 11, 1967. But getting there requires several leaps of logic. I think these leaps make sense, but I also don't think the story was designed to support this kind of analysis. Certainly Norton Juster didn't plan this, since the answer relies on societal trends that played out after the book was published. But here we go:

How to interpret background assumptions?

Several of the inferences I'm going to make depend on an assumed geographic or cultural background. The Lands Beyond is, well, beyond, but it's an extremely American sort of fantasy world. Everyone speaks English, all the puns are in English, all the spellings are American, and Dictionopolis only recognizes the 26 characters of the Latin alphabet. Two characters in chapter 16 refer to American currency ("ten dollars apiece", "dollars or cents").

Specifically, I argue that the Lands Beyond are a New York tri-state area fantasy world, mainly because of the titular tollbooth. I grew up in Los Angeles, land of freeways, and when I first read this book as a child, a "tollbooth" seemed as weird and magical as a talking dodecohedron.

For this analysis I will assume that Milo lives in or near New York City, both for Doyleist reasons (that's where Norton Juster lived when he wrote the book) and Watsonian reasons (Milo lives in an apartment building with at least eight stories and knows what a turnpike tollbooth is). The background assumptions of the Lands Beyond are the midcentury East Coast American assumptions Milo will recognize; there's no Watsonian reason given for this but it seems indisputable. In the 1969 film, Milo lives in San Francisco, but that's only one of the problems with that movie.

What year?

Next, let's establish the year The Phantom Tollbooth takes place. In the absence of any internal cues, we tend to assume a book is set in the year the book came out: 1961 in this case. This assumption worked until I hit chapter 16, where I ran into a big problem: the average boy, of "ten dollars apiece" fame, who is the .58 in his 2.58-children household.

In 1961, worldwide fertility was 4.58 children per woman, and fertility in the United States was 3.52 children. The baby boom was winding down, and the Pill had been approved by the FDA the previous year, but no matter how you map "average fertility" to "size of family," I don't see how you get 2.58.

Norton Juster was 32 years old in 1961, and I think this bit, which reifies averages, is based on things he heard long before, at the start of the baby boom. Especially since the average child also says "A few years ago I was just .42". This is the detail that makes me very confident Juster wasn't meticulously piecing all of this stuff together so someone could figure it out 60 years later. Nonetheless, I press on, because I'm having fun.

As I see it we have two options. We can say The Phantom Tollbooth takes place in the future—say, 1967, when the US fertility rate was 2.52; or we can say it takes place much earlier than 1961: right after World War II, on the upswing of the baby boom. I really don't see how that second option can work, since the average child says "each family also has an average of 1.3 automobiles." I didn't look up the statistics for, say, 1947, but that sounds like 1950s-level prosperity at least. (On top of all the other things that would no doubt become anachronistic if this story took place in the 1940s.)

So I'm saying The Phantom Tollbooth takes place in 1967, six years in the future relative to when the book came out.

Where does this leave the statement "A few years ago I was just .42", if "a few years ago" refers to the 1940s? Well, this kid is an average, not an individual. He doesn't age; he waxes and wanes. In the 1940s he was .42, and by 1973 he, or one of his siblings, will disappear altogether.

What date?

The Phantom Tollbooth takes place in spring, based on this quote from the final chapter, when Milo returns to the real world from the Lands Beyond:


The tips of the trees held pale, young buds and the leaves were a rich deep green... there were... caterpillars to watch as they strolled through the garden.


Milo goes to school on the day he finds the Tollbooth. After school he spends several subjective weeks in the Lands Beyond, but he returns to the real world the evening of the day he left. He then goes to school the next day. So Milo leaves for the Lands Beyond during the school year, and not on a Friday, Saturday, or Sunday.

For the rest of this, I'm relying on what happens to Milo Inside the Lands Beyond. This is tricky because of the fairy-logic time dilation, not to mention that an entire week passes without notice in chapter 11. But I argue that we can nail it down using only clues before the missing week.

In the Doldrums, Milo learns that "smiling is permitted only on alternate Thursdays." This is right after he enters the Lands Beyond, so I think it's fair to assume this is happening on the same day he left. If it's a Thursday on the day you go past the Tollbooth, it seems like a reasonable assumption that it's still Thursday on the other side. But if Milo had left on a Thursday, this rule would have required clarification—"this isn't one of the Thursdays you can smile." So he probably didn't leave on a Thursday. (If you don't find this convincing: we don't need this clue to narrow it down, but my final answer is consistent with this analysis.)

Now it gets a little more complicated. I'm going to argue that the events of chapters 1-10, basically the first half of the book, happen in a single subjective day. This encompasses a ton of activity (another reason why I think Juster didn't meticulously plan out the timeline), but here's a summary of what happens in between all the clever conversations:

Milo arrives in the Lands Beyond while the sun is shining. He
drives to Dictionopolis, gets thrown in the dungeon, hears some
stories from the Which, then immediately escapes the dungeon to be
greeted by "a shaft of brilliant sunshine"—so it's still
daytime. There's a royal banquet and then Milo drives out of
Dictionopolis. At this point (chapter 9) it is "late afternoon." They
stop for the night, Milo watches Chroma conduct the sunset, and then
falls asleep.

So we have a lot of driving while the sun is out, a meal, more driving, and then watching the sunset. All, I would argue, over the course of a single day. You can argue that's too much to cram into a single day after school, and I agree, but the first half of the book has a pretty tight perspective on Milo's activities, and we only see him eat one meal and sleep once.

Now here's the important part: the sunrise the next day is scheduled for 5:23 AM. If it's the spring of 1967, this means the only day Milo can have entered the Lands Beyond is Tuesday, April 11. (Remember, the implicit assumptions of the Lands Beyond are calibrated for Milo's tri-state area self, which is why I'm using NYC as the location from which the time of sunrise is calculated.)

So, there's our answer: The Phantom Tollbooth begins on Tuesday, April 11, 1967. A spring day during the school year that's not a Thursday, Friday, Saturday, or Sunday.

Beyond that point things are less reliable, because of the week that's lost in chapter 11, but fortunately I only found one more clue that needs to be slotted in. In chapter 12 the Soundkeeper says her vault is open to the public "only on Mondays from two to four", with the strong implication that this is not Monday. But this looks like it happens on Milo's second day in the Lands Beyond (apart from the missing week), which would be Wednesday the... 19th, I guess. So that's consistent with an April 11 start date.

In Conclusions

I've said a couple times before but I'll repeat: I don't think The Phantom Tollbooth was meant to hold up to this kind of analysis. Here's another example: in chapter 18, Tock says they've been traveling for "days", and then we read this:


"Weeks," corrected the bug, flopping into a deep comfortable armchair, for it did seem that way to him.


The narrator clearly thinks "weeks" is an exaggeration, and I think that's correct, if you don't count the missing week from chapter 11 as an actual week. Looking at the map, and seeing how much happened on Milo's first day in the Lands Beyond, I think they could have made it to the Castle in the Air in 6-7 days, depending on how long they spent on time-sinks like swimming back from Conclusions and doing tasks for the Terrible Trivium. (They spent at least 21 hours in the grasp of the Trivium, by the way. I remember counting this up when I was a kid, so I've always been like this.)

After the return of Rhyme and Reason, there are three days of feasting, and then Milo heads back to the real world. At the beginning of chapter 20, "it suddenly occurred to Milo that he must have been gone for several weeks." But that's the same idea that was treated as a silly exaggeration just three days earlier, in chapter 18! In actual fact, Milo was gone for (lets say) 17 days by the calendar, and ten subjective days, since the missing week passed in a few seconds.

So... the timeline here is not exactly intended to snap together like a Lego set, is what I'm saying. But I am very happy that there seems to be a unique date where The Phantom Tollbooth began, even if Norton Juster didn't plan it that way and couldn't have anticipated that the question would ever have an answer.

 •  0 comments  •  flag
Share on Twitter
Published on July 27, 2024 10:10

Leonard Richardson's Blog

Leonard Richardson
Leonard Richardson isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Leonard Richardson's blog with rss.