classification
Title: inspect.getsourcelines ignores context and returns wrong line #
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.4
process
Status: closed Resolution: duplicate
Dependencies: Superseder: inspect.getsource returns incorrect source for classes when class definition is part of multiline strings
View: 35113
Assigned To: Nosy List: iritkatriel, jedwards, pitrou, rhettinger, siming85, xtreak, yselivanov
Priority: normal Keywords:

Created on 2015-04-29 23:04 by siming85, last changed 2020-09-19 05:18 by xtreak. This issue is now closed.

Messages (6)
msg242254 - (view) Author: Siming Yuan (siming85) * Date: 2015-04-29 23:04
if the same class name is used within a module, but defined in different contexts (either class in class or class in function), inspect.getsourcelines() on the class object ignores the object context and only returns the first matched name.

reproduce:

a.py
----
class A(object):
    class B(object):
        pass

class C(object):
    class B(object):
        pass

------------------
>>> import inspect
>>> import a
>>> inspect.getsourcelines(a.C.B)
(['    class B(object):\n', '        pass\n'], 2)
msg242255 - (view) Author: Siming Yuan (siming85) * Date: 2015-04-29 23:08
according to inspect.py line 675 - this is only a best effort.

is this intended?

inspect.py @ 672
    if isclass(object):
        name = object.__name__
        pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
        # make some effort to find the best matching class definition:
        # use the one with the least indentation, which is the one
        # that's most probably not inside a function definition.
        candidates = []
        for i in range(len(lines)):
            match = pat.match(lines[i])
            if match:
                # if it's at toplevel, it's already the best one
                if lines[i][0] == 'c':
                    return lines, i
                # else add whitespace to candidate list
                candidates.append((match.group(1), i))
        if candidates:
            # this will sort by whitespace, and by line number,
            # less whitespace first
            candidates.sort()
            return lines, candidates[0][1]
        else:
            raise OSError('could not find class definition')
msg242335 - (view) Author: James Edwards (jedwards) * Date: 2015-05-01 17:14
Inspect could probably be updated to use 3.3's __qualname__ in the case of classes-in-classes; classes-in-functions or functions-in-functions would likely be harder, but I'm not sure it's impossible.
msg242337 - (view) Author: James Edwards (jedwards) * Date: 2015-05-01 17:18
Added Yury (inspect module) and Antoine (PEP 3155) to nosy -- apologies  if you're not interested.
msg377124 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2020-09-18 15:15
I think this was fixed under issue35113.
msg377150 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2020-09-19 05:18
Thanks iritkatriel for triaging. I can confirm it's fixed with the linked issue. Closing it as duplicate.

./python
Python 3.10.0a0 (heads/master:2b05361bf7, Sep 19 2020, 04:38:05) 
[GCC 7.5.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect, a
>>> inspect.getsourcelines(a.C.B)
(['    class B(object):\n', '        pass\n'], 6)
History
Date User Action Args
2020-09-19 05:18:22xtreaksetstatus: open -> closed
superseder: inspect.getsource returns incorrect source for classes when class definition is part of multiline strings
messages: + msg377150

resolution: duplicate
stage: resolved
2020-09-18 15:15:10iritkatrielsetnosy: + iritkatriel, xtreak
messages: + msg377124
2015-05-08 20:49:16rhettingersetnosy: + rhettinger
2015-05-01 17:18:26jedwardssetmessages: + msg242337
2015-05-01 17:16:14jedwardssetnosy: + pitrou, yselivanov
2015-05-01 17:14:09jedwardssetnosy: + jedwards
messages: + msg242335
2015-04-29 23:08:48siming85setmessages: + msg242255
2015-04-29 23:04:32siming85create