I've made good progress on creating a notebook every day. Now I have so many notebooks that my index page needs an overhaul, including:
* Dates with datetime
* Cards with execnb to grab notebook titles
* The cache decorator to make that fast
* Subtle CSS tweaks to increase information density
Here I expand ~ into /Users/arg/, list files that end in .ipynb, and convert the generator object into a readable list with a fastcore L list.
Display the Notebooks List Nicely
fornbinnbs:print(nb.name)
If we just print the filenames, we can see my current approach of naming them with the date and TitleCase title.
New Approach
Doing this has given me insight about how to improve my site:
Keep naming files as before
Now for the index page, get the titles from the notebooks instead of the filenames
When there were just a few notebooks, these cards were great. Now I want a more information-dense layout with tighter cards, and with titles containing proper punctuation coming from the notebooks themselves.
Revisit Date Parsing
I'm currently getting dates from ISO 8601-prefixed filenames with this not-great code that I hacked together quickly:
I talked with Claude 3.5 Sonnet about it. It generated code that looked awesome at first but wasn't my favorite when I experimented with it carefully. But something good resulted: out of that I learned about datetime.fromisoformat and looked it up in the Python datetime docs.
d=datetime.fromisoformat('2025-01-04')d
It's actually nice to have datetime objects here because I can get the parts like:
d.year,d.month,d.day
And print them with f-strings:
print(f"{d:%a, %b %-d, %Y}")
I like that combination of readability and abbreviations. I'll try it and see if I still like it later.
Iterate on ISO 8601 Date Parsing
My improved function:
@cachedefget_date_from_iso8601_prefix(fname):"Gets date from first 10 chars YYYY-MM-DD of `fname`, where `fname` is like `2025-01-12-Get-Date-From-This.whatever"try:returndatetime.fromisoformat(str(fname)[:10])exceptValueError:returnNone
Note: on my first pass writing this notebook, I didn't use the @cache decorator. I waited until the end to cache, to make debugging easier for myself. It'll become clear in the next section on notebook titles why caching is good here.
Now let's test it by grabbing a filename and passing it in.
nbs[0]
nbs[0].name
d=get_date_from_iso8601_prefix(nbs[0].name)d
Iterate on Getting Notebook Titles
Instead of parsing filenames, I'm going to grab the first cell of each notebook and remove the # prefix.
nbc=read_nb(nbs[0].name)nbc.cells[0]
nbc.cells[0].source
nbc.cells[0].source.lstrip('# ')
Make That a Function
defget_title(fname):"Get title from `fname` notebook's cell 0 source by stripping '# ' prefix"nbc=read_nb(fname)returnnbc.cells[0].source.lstrip('# ')
@cachedefget_title(fname):"Get title from `fname` notebook's cell 0 source by stripping '# ' prefix"nbc=read_nb(fname)nbc=nbc.cells[0].source.lstrip('# ')if'\n'innbc:returnfirst(nbc.split('\n'))returnnbc
You can imagine how running this on every notebook would be slow! So we add @cache.
Here I had to set a root element so rem font sizes would show correctly here in nbclassic, where I'm working from. There's more to get it to look right here, but I'm getting a bit tired.
You may be wondering about how there's a lot of CSS getting repeated in each card instance. There aren't that many cards right now, and this is still way smaller than a React/Tailwind app. I have some interesting ideas here that I'll save for another day.
Bringing Changes Over to My Blog App
My blog app arg-blog-fasthtml has a main.py that isn't notebook-generated.
Note: At this point, considering how many functions I rewrote in this notebook, it would be nice to move that main.py to notebooks. I originally had started writing it in notebooks but had moved to the simple main.py to make troubleshooting deployment on a PaaS easier.
For now, I've updated main.py with all of the above manually. I'm like a manual version of nbdev_export and that tells me that I should automate.
Caching
With @cache on all the functions above, the index page is super snappy locally! Yes, that's the unbounded cache, but I have few and small enough things to cache that I won't worry about it for now. I can explore it another time.
Summary
I've made good progress improving my blog's index page!
Better date handling using datetime.fromisoformat() instead of regex parsing
Getting proper titles from notebook first cells instead of filenames
Tighter, more information-dense cards with improved typography
Caching with @cache to keep things snappy
It's working well locally, and we'll see what happens when I deploy. I manually updated my blog app's main.py with these changes, though doing this made me realize I should probably move that code into notebooks and use nbdev_export instead of copying by hand.
There's still room for improvement, but I'm happy with my progress!