Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -862,9 +862,9 @@ def getfile(object):
if object.__module__ == '__main__':
raise OSError('source code not available')
raise TypeError('{!r} is a built-in class'.format(object))
if ismethod(object):
if hasattr(object, '__func__'):
object = object.__func__
if isfunction(object):
if hasattr(object, '__code__'):
object = object.__code__
if istraceback(object):
object = object.tb_frame
Expand Down Expand Up @@ -1022,9 +1022,9 @@ def findsource(object):
raise OSError('lineno is out of bounds')
return lines, lnum

if ismethod(object):
if hasattr(object, '__func__'):
object = object.__func__
if isfunction(object):
if hasattr(object, '__code__'):
object = object.__code__
if istraceback(object):
object = object.tb_frame
Expand Down
30 changes: 30 additions & 0 deletions Lib/test/test_inspect/inspect_fodder2.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,34 @@ def func394():
def func400():
return 401

# line 403
class FunctionLike:
# Like a function compiled by Cython: it provides __code__, but it is not
# an instance of types.FunctionType. It does not set __wrapped__, so
# inspect cannot unwrap it to get back to the original function.
def __init__(self, func):
self.__code__ = func.__code__

def __get__(self, instance, owner=None):
if instance is None:
return self
return MethodLike(self, instance)

class MethodLike:
# Provides __func__, but is not an instance of types.MethodType.
def __init__(self, func, instance):
self.__func__ = func
self.__self__ = instance

# line 422
@FunctionLike
def func424():
return 425

# line 427
class cls428:
@FunctionLike
def func430(self):
return 431

pass # end of file
8 changes: 8 additions & 0 deletions Lib/test/test_inspect/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,14 @@ def test_getsource_unwrap(self):
def test_decorator_with_lambda(self):
self.assertSourceEqual(mod2.func114, 113, 115)

def test_function_like_decorator(self):
# Test duck-typed functions and methods (as dummies for Cython functions)
self.assertEqual(inspect.getfile(mod2.func424), mod2.__file__)
self.assertSourceEqual(mod2.func424, 423, 425)
method = mod2.cls428().func430
self.assertEqual(inspect.getfile(method), mod2.__file__)
self.assertSourceEqual(method, 429, 431)

class TestOneliners(GetSourceBase):
fodderModule = mod2
def test_oneline_lambda(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Use duck-typing in ``inspect`` to support Cython functions in ``getfile`` and ``getsource``
Loading