Python: Make line number paths with inspect
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.
Newly updated: my book Boost Your Django DX now covers Django 5.0 and Python 3.12.
One summary email a week, no spam, I pinky promise.
Related posts: