Python: Make line number paths with inspect

Some kind of inspection device.

Many terminals and text editors support what I’ll call “line number paths” of the form <filename>:<lineno>. Opening that path, whether by clicking or passing to a CLI, opens the given file at that line.

Python’s inspect module has a couple of functions that can be combined to make such paths, for a given class or function. Here’s the recipe:

from inspect import getsourcefile, getsourcelines

print(f"{getsourcefile(obj)}:{getsourcelines(obj)[1]}")

getsourcefile() returns the file the object is defined in. getsourcelines() returns a tuple, containing the list of source code lines and the first line number, hence the [1] to select just the line number.

For example, to make a path for a function in Django:

In [1]: from django.utils.html import format_html

In [2]: from inspect import getsourcefile, getsourcelines
   ...: print(f"{getsourcefile(obj)}:{getsourcelines(obj)[1]}")
/.../.venv/site-packages/django/utils/html.py:95

I have found this recipe handy a couple of times for batch edits. For example, I recently upgraded django-import-export on a project. Due to an upstream change, I needed to check every subclass of django-import-export’s ModelResource class in the project. I could have searched the code for all such classes, but that can be complicated due to inheritance. Instead, I used class.__subclasses__() to find all subclasses and made “line number paths” for each:

In [1]: from inspect import getsourcefile, getsourcelines

In [2]: from import_export.resources import ModelResource

In [3]: for cls in ModelResource.__subclasses__():
   ...:     init = cls.__init__
   ...:     if init is not ModelResource.__init__:
   ...:         print(f"{getsourcefile(init)}:{getsourcelines(init)[1]}")
   ...:
/.../example/apples/resources.py:1136
/.../example/apples/resources.py:1239
/.../example/bananas/resources.py:351
/.../example/bananas/resources.py:502
/.../example/bananas/resources.py:1874
/.../example/cherries/resources.py:297
...

I was then free to edit each link in turn.

Fin

May you find more creative ways to use Python’s inspection features,

—Adam


Newly updated: my book Boost Your Django DX now covers Django 5.0 and Python 3.12.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: ,