Blog | Tristan Kernan

“That some of us should venture to embark on a synthesis of facts and theories, albeit with second-hand and incomplete knowledge of some of them – and at the risk of making fools of ourselves” (Erwin Schrödinger)

Wat

I use emacs, and within emacs I use the pytest plugin to run tests. When I need to debug tests, I turn to ipdb with a quick yasnippet, dropping in import ipdb; ipdb.set_trace(). When debugging with ipdb, I just love this little tool called wat. It makes inspecting objects a breeze, and is a must-have in all my projects now.

As an example, I was debugging the difference between Django's Request class and Django Rest Framework's Request class, and their interop. Dropping into a debugger in the view, I could quickly inspect the request object:

Python
ipdb> wat / request
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
value: <rest_framework.request.Request: GET '/osrm/route/v1/driving/-74.172400,40.735700%3B-74.027600,40.744000'>
type: rest_framework.request.Request

Public attributes:
  FILES: django.utils.datastructures.MultiValueDict = {}
  POST: django.http.request.QueryDict = {}
  accepted_media_type: str = 'application/json'
  data: dict = {}
  ... reduced for brevity

  def force_plaintext_errors(value)

Private attributes:
  _auth: NoneType = None
  _data: dict = {}
  _files: django.utils.datastructures.MultiValueDict = {}
  _request: django.core.handlers.wsgi.WSGIRequest = <WSGIRequest: GET '/osrm/route/v1/driving/-74.172400,40.735700%3B-74.027600,40.744000'>

  def _authenticate() # Attempt to authenticate the request using each authentication instance…
  class _content_type() # Placeholder for unset attributes.…
  ... reduced for brevity

Public and private attributes and methods are listed. Where available, types, classes, values and docstrings are displayed inline.

Auto import

It's tedious to have to import wat in every shell session, so I looked online and found that it can be automatically imported. There's two different configurations to apply.

For automatic import into ipython shells (i.e. manage.py shell), modify the ipython startup profile1, by creating a new file at ~/.ipython/profile_default/startup/00-first.py, with the contents from wat import wat.

For automatic import into debugger ipdb shells (i.e. ipdb.set_trace()), add from wat import wat to .pdbrc in your main repository folder.

And - don't forget to pip install the wat package in your repository 🙂


  1. Thanks to https://switowski.com/blog/ipython-startup-files/