A BubbleTea App to View CloudWatch Logs

My favourite way to view CloudWatch logs is with the awslogs tool. Unfortunately, when I last installed it with pipx it gave me errors about missing packages1, so I decided to do what any sane person would do and write a new version in a completely different programming language. I’m a big fan of python’s Textual library and TUIs in general, and I want 2024 to be my year of learning Go, so I’ve decided to look at using that along with BubbleTea.
Read more

Exploring Burp Project Files

It’s been a while since I’ve done any web app testing. A long while. Last time I used Burp, there was no such thing as project files. There was a state file, which was some strange psuedo-xml file format but the new project files look like they contain more information. A lot more information. So I’ve decided to have a prod and see whether I can extract any useful information from them.
Read more

sanic-kit

HTMx has been a revelation for writing web apps. I’d previously used my preferred DERP stack (Django, Ember, REST framework, postgresql) which produced nice enough apps but took a lot of effort and had lots of redundant code: Postgres tables needed to be Django models, which needed to be DRF serialisers, which needed Ember Data models, and then finally rendered to the DOM. Writing with htmx meant I could have most of the shiny but I only need to produce the html on the server.
Read more

Helix for vim users

Periodically, I have a go at using an editor other than vim. This normally results in me realising that I just needed a change of vim colour scheme but I’ve just discovered Helix which might be just enough like vim for me to stick around. My reason for giving it a go is that I want something with easy to use language server support. Neovim would probably be a sensible choice but helix seems to be nicely configured out of the box, so I’m going to try that first.
Read more

Textual in WSL

If you’re running textual apps under WSL there are two things needed to make sure they look pretty: make sure you’re using a good coding font with all the various Unicode characters make sure COLORTERM is set to truecolor in your environment.

Textual Screen Transitions

Textual brings a little bit of the web to the terminal. Apps have a DOM that is composed of widgets, and layout and styling is all handled with CSS. Apps can also be made up of multiple Screens, which could be thought of as separate URLs or pages within a web-app. With this in mind, I started wondering about whether it would be possible to animate a transition between two different screens.
Read more

URLs are harder than they should be

My current toy web-app is a webmail client. It provides the standard inbox view and then let’s you drill down to view actual mails. I also then have actions you can perform on these. The URLs for these are fairly basic: /mailbox/<ID> /mailbox/<ID>/<mail ID> /mailbox/<ID>/<mail ID>/delete So far, so whatever. The pain comes with how to construct the drill down urls from the current page. I can get the current URL in my templates with request.
Read more

Validating Input in Textual

Textual has a number of built in widgets to help capture user input. For text input, there is the standard Input widget. By default, this will let the user enter any characters that they wish. Whenever a new value is entered, textual will fire off an Input.Changed event, that you can handle with an on_input_changed method in your App (or wherever). You may then be tempted to use this handler to validate the user input - the Input has a reactive variable but there’s no easy way to wire something up to an instance’s methods.
Read more

Sanic Custom Route Parameters

Sanic supports path parameters like the majority of web frameworks. It supports a number of built-in types but you can define your own. Something like this from Adam on Discord: import re from typing import NamedTuple DIMENSIONS_PATTERN = re.compile(r"(?P<width>\d+)x(?P<height>\d+)") class Dimensions(NamedTuple): width: int height: int def _extract_dimensions(value: str) -> Dimensions: if match := DIMENSIONS_PATTERN.match(value): return Dimensions(**{k: int(v) for k, v in match.groupdict().items()}) raise ValueError("Not proper dimensions format") app.router.register_pattern( "dimensions", _extract_dimensions, DIMENSIONS_PATTERN ) @app.
Read more

Deploy Python With Deb

One of the worst parts about working with python is how to share your code, or deploy it on another machine. If you’re following preferred practices, then you’re probably developing using a virtual environment. But that means you need a way to have the same environment where your app is going to run. Either your users need to go through several steps to create a virtual environment and then install your app and its dependencies to it, or you need to ship the environment along with your app.
Read more