Automerge Dependabot PRs on GitHub

· 3 min

Whether I’m trying out a new tool or just prototyping with a familiar stack, I usually create a new project on GitHub and run all the experiments there. Some examples of these are:

  • rubric: linter config initializer for Python
  • exert: declaratively apply converter functions to class attributes
  • hook-slinger: generic service to send, retry, and manage webhooks
  • think-async: exploring cooperative concurrency primitives in Python
  • epilog: container log aggregation with Elasticsearch, Kibana & Filebeat

While many of these prototypes become full-fledged projects, most end up being just one-time journies. One common theme among all of these endeavors is that I always include instructions in the readme.md on how to get the project up and running - no matter how small it is. Also, I tend to configure a rudimentary CI pipeline that runs the linters and tests. GitHub Actions and Dependabot make it simple to configure a basic CI workflow. Dependabot keeps the dependencies fresh and makes pull requests automatically when there’s a new version of a dependency used in a project.

Inspect docstrings with Pydoc

· 2 min

How come I didn’t know about the python -m pydoc command before today!

It lets you inspect the docstrings of any modules, classes, functions, or methods in Python.

I’m running the commands from a Python 3.10 virtual environment but it’ll work on any Python version. Let’s print out the docstrings of the functools.lru_cache function. Run:

python -m pydoc functools.lru_cache

This will print the following on the console:

Help on function lru_cache in functools:

functools.lru_cache = lru_cache(maxsize=128, typed=False)
    Least-recently-used cache decorator.

    If *maxsize* is set to None, the LRU features are disabled and
    the cache can grow without bound.

    If *typed* is True, arguments of different types will be cached
    separately. For example, f(3.0) and f(3) will be treated as
    distinct calls with distinct results.

    Arguments to the cached function must be hashable.

    View the cache statistics named tuple (hits, misses, maxsize,
    currsize) with f.cache_info().  Clear the cache and statistics
    with f.cache_clear(). Access the underlying function with
    f.__wrapped__.

Works for third party tools as well:

Don't add extensions to shell executables

· 1 min

I was browsing through the source code of Tom Christie’s typesystem library and discovered that the shell scripts of the project don’t have any extensions attached to them. At first, I found it odd, and then it all started to make sense.

Executable scripts can be written in any language and the users don’t need to care about that.

GitHub uses this scripts-to-rule-them-all pattern successfully to normalize their scripts. According to the pattern, every project should have a folder named scripts with a subset or superset of the following files:

Use 'command -v' over 'which' to find a program's executable

· 1 min

One thing that came to me as news is that the command which - which is the de-facto tool to find the path of an executable - is not POSIX compliant. The recent Debian which hunt brought it to my attention. The POSIX-compliant way of finding an executable program is command -v, which is usually built into most of the shells.

So, instead of doing this:

which python3.12

Do this: