I'm trialing the idea of Weeknotes, a weekly summary of what I've done / learned in the prior week. Inspired by Simon Willison who has an uncanny ability to respond to a tweet with a link to a weeknote of his containing just the information you needed. These will be a little rougher, a little less edited, than my usual content. But the point is to get something out there and to develop the habit of writing.
The investment for Textualize landed at the end of last year, just before Christmas. Naturally I was on a bit of a high. This last week-and-a-half I've come down to earth and settled in to a routine of going in to the office every day (something I swore I'd never do again). And it's not so bad.
I'm joined by @_darrenburns as my first employee. We will be working on Rich / Textual and the as-yet-unannounced Textualize we service.
This week we (mostly Darren) discovered two issues related to emojis in terminals.
Terminals have patchy support for multi-codepoint emojis. There are certain emojis which are composed of multiple codepoints that when combined produce a single glyph. Run the following code to illustrate this:
a = "🤚" b = "👨👩👧👧" print(len(a)) print(len(b)) print(a) print(b)
The output of the last two lines is highly dependent on which terminal you are using. It is not correlated to the unicode database used by the terminal. Some terminals just don't know how to render these emojis. It's unfortunate, but there isn't much that Rich or Textual could do to guarantee these render correctly.
The second discovery is more positive. Darren discovered that wcwidth has an error in transcribing certain emoji widths from the unicode database. Consequently a large number of emojis were being reported as 1 cell width that render as 2 cell widths. The emojis in question probably represented the majority of the emoji issues in the Rich repo. The fix will be in the next version of Rich.
I have been working on the server that will power our web service. I chose FastAPI as the stack for that because it has a really elegant way of exposing a REST API, and because it is built on Starlette which claims good support for websockets. The product I have in mind will really put that claim to the test.
One of the first tasks in this web service is to define packets that will be sent over the wire by websockets. There will be a large number of these packets, each of which require a class definition. Writing these out by hand is tedious and error prone. I'd rather use a declarative approach as championed by dataclasses, namedtuples, attrs, PyDantic, and friends. For my packets classes, I chose "none of the above".
My solution might horrify some folks, but I settled on code generation. I have a yml file that describes the packets, which is parsed and run through a Jinja2 template, processed by black, and finally spits out
packets.py. This resulting file is precisely what I need, as though I had hand written each class. But without any magic, which means there is no runtime cost when you import it, and future developers can see exactly how each class works.
The only downside is that I run a build step whenever I change the yml file, but it is a small price to pay. If anyone wants to talk me out of it, I will refer them to this tweet:
I like the auto-generated class idea.— David Beazley (@dabeaz) January 12, 2022
Next week I am going to tackle implementing a Windows driver for Textual, which is the most common request I get. In theory it will be relatively straightforward. Textual has an abstract "Driver" class which I can replace with a Windows version. There are also a number of TUI related Python projects I can refer to.
Follow @willmcgugan for more Weeknotes and Textual updates.