24April14
24April14

Reputation: 177

python how to programmatically get line number of class definition

suppose I have a module named test.py. In this file, I know a class named dummy. How to get the line number of class dummy definition after I import it?

Is there an API can do such thing?

if dummy is a function, then dummy.__code__.co_firstlineno will return the line no. But if dummy is a class, it doesn't have__code__attribute

I wanna know is there a way which can return the line no without parsing the file.

Upvotes: 12

Views: 4394

Answers (4)

user459872
user459872

Reputation: 25039

Starting from python 3.13, You can use type.__firstlineno__ attribute.

The line number of the first line of the class definition, including decorators. Setting the __module__ attribute removes the __firstlineno__ item from the type’s dictionary.

Added in version 3.13.

from test import dummy

print(dummy.__firstlineno__)

Upvotes: 1

kxr
kxr

Reputation: 5548

inspect.findsource(test.dummy)[1] provides the line number via regex search in the source file (rather slow).

If you define the class, line numbers could be exposed like this:

class MyClass:
    def test_01(self):
        assert 1
    _classline_ = inspect.currentframe().f_code.co_firstlineno
    _thisline_ = inspect.currentframe().f_lineno

Update 2020 / Python 3.9+ : inspect.findsource now uses (slow) ast instead of regex. (bpo-35113 / commit 696136b9)

Upvotes: 7

Erotemic
Erotemic

Reputation: 5248

This requires static analysis code I wrote for the xdoctest module. I'm not sure it solves 100% of the cases, but I think it is more robust than a regex search.

def static_calldefs(modpath):
    from xdoctest import static_analysis as static
    calldefs = dict(static.parse_calldefs(fpath=modpath))
    return calldefs

def get_object_lineno(obj):
    try:
        # functions just 
        lineno = obj.__code__.co_firstlineno
    except AttributeError:
        attrname = obj.__name__
        modpath = sys.modules[obj.__module__].__file__
        calldefs = static_calldefs(modpath)
        ub.modpath_to_modname(modpath)
        calldef = calldefs[attrname]
        lineno = calldef.lineno
    return lineno

Upvotes: 1

Arthur
Arthur

Reputation: 583

Look at the Retrieving source code section of inspect. Try getsourcefile() and getsourcelines().

Upvotes: 3

Related Questions