Pragmatism in the real world

Prepending to the terminal's prompt

For some work I'm doing, I have been given access to a Linux box that is part of a legacy production system. The first thing I have done is updated the terminal prompt to include the word PRODUCTION in red, by adding this to .bashrc: export PS1="$(tput setaf 1)PRODUCTION $(tput sgr0)$PS1" The nice thing about doing it this way is that I don't have to worry about whatever is in PS1 already. Not the most… continue reading.

Parsing command line arguments in Python

This is one of those posts that I write so that I can look it up again as this information is all over the Internet, but it took me a little while to find what I was looking for. To accept command line arguments in a Python script, use the argparse package: import argparse You can then instantiate a parser and add arguments you want to accept: parser = argparse.ArgumentParser(description="Convert a JSON array to JSONL… continue reading.

Defining Python dependencies at the top of the file

Earlier in the year, I wrote about updating Flickr metadata using Python. For this script to work, I needed to install the flickrapi package first. I recently came across PEP 723 – Inline script metadata that makes this much easier for single file scripts like my sync-flickr-dates script. Essentially, we can now put a special comment block at the top of the file, before our import statements like this: # /// script # requires-python =… continue reading.

Selecting the correct iPhone to mirror in macOS Sequoia

There's a new feature in macOS Sequoia that allows mirroring of your iPhone to your Mac. This is a nice feature that allows you to fully interact with your iPhone as an app on you Mac's desktop. When I upgrade to Sequoia and run the iPhone Mirroring app, it selected Victory, my old iPhone 14 Pro Max which is running an older version of iOS. This didn't work and there is no way within the… continue reading.

Installing PyMuPDF on a prerelease Python

I recently installed Python 3.13.0 rc2 to test rst2pdf against it and found that I couldn't install PyMyPDF which is required for the tests. $ pip install pymupdf … This is because for a pre-release version, binary wheels are not provided to PyPI for the mupdf dependency which is written in C++. Hence, the compiler needs the headers. On my Mac, I had the CPATH environment variable set to /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include. For mypdf to compile, I… continue reading.

Scripting News is 30 years old

Last week, Dave Winer posted that Scripting News turned 30. That's an amazing milestone and Dave's still writing daily. 1994 seems like quite a while ago; the web was only 3 years old! I started blogging in 2003 on a personal domain and added this blog in 2005. I don't write daily though and I tip my hat to Dave. His writing is also really really good. Scripting News was the catalyst for the creation… continue reading.

Running Spectral lint in Gitlab CI

In my Makefile, I check for OpenAPI spec issues with this command: docker run –rm -it -v $(PWD):/tmp stoplight/spectral lint \ –ruleset /tmp/spec/.spectral.yaml /tmp/spec/openapi.yaml When running in GitLab CI, we set the image to stoplight/spectral:latest, and override the entry point so that we can run spectral directly: openapi-lint: stage: test image: name: stoplight/spectral:latest entrypoint: [""] script: – spectral lint –ruleset spec/.spectral.yaml spec/openapi.yaml Note that GitLab's CI running automatically sets the current working directly to the… continue reading.

Docker Compose DNS entries

Sometimes you need some additional DNS entries in your containers. This is how to do it in compose.yaml. Internal entries Within the containers, the name of the container in compose.yaml is resolvable via DNS. Given this compose.yaml: services: web: # … app: # … networks: myapp: driver: "bridge" We can ping web from within the app container. If we need to access the web container using another domain, we add it as a network alias:… continue reading.

Increase truncated body in a Guzzle exception

When Guzzle throws BadResponseException, the message includes information about the method, URL response code and then a truncated part of the body. For example: "Client error: `GET https://dev.clientproject.com:4444/oauth2/authorize?client_id=983e98d2fab8756a&scope=scope&response_type=code&redirect_uri=%2Fhome&code_challenge=some_code_challenge_here` resulted in a `400 Bad Request` response: {"error":"invalid_request","error_description":"The request is missing a required parameter, includes an invalid parame (truncated…) To retrieve the full text of the body, you grab it from the response property of the exception: $body = $e->getResponse()->getBody()->getContents(); Changing the truncation limit If you want… continue reading.

Fixing PhpStorm cannot find a local copy of Standard Input Code

Recently, I set up my PHP dev environment to allow me to step debug from unit tests that I run with make unit The relevant parts of Makefile look like this: # Set DEBUG=1 to enable Xdebug ifeq ($(origin DEBUG),undefined) XDEBUG := else XDEBUG := XDEBUG_SESSION=PHPSTORM endif unit: ## Run unit tests docker compose exec php bash -c "$(XDEBUG) vendor/bin/phpunit –testsuite=unit" I can now set a break point and run the unit tests with Xdebug… continue reading.