diff options
author | Jeroen Demeyer <J.Demeyer@UGent.be> | 2019-04-02 14:03:42 (GMT) |
---|---|---|
committer | Petr Viktorin <encukou@gmail.com> | 2019-04-02 14:03:42 (GMT) |
commit | fcef60f59d04c63b3540b4c4886226098c1bacd1 (patch) | |
tree | 67f920ddc3764d2b2b99f869bc8aab513cf38859 | |
parent | 487b73ab39c80157474821ef9083f51e0846bd62 (diff) | |
download | cpython-fcef60f59d04c63b3540b4c4886226098c1bacd1.zip cpython-fcef60f59d04c63b3540b4c4886226098c1bacd1.tar.gz cpython-fcef60f59d04c63b3540b4c4886226098c1bacd1.tar.bz2 |
bpo-33261: guard access to __code__ attribute in inspect (GH-6448)
-rw-r--r-- | Lib/inspect.py | 23 | ||||
-rw-r--r-- | Lib/test/inspect_fodder.py | 11 | ||||
-rw-r--r-- | Lib/test/test_inspect.py | 1 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2018-04-11-11-41-52.bpo-33291.-xLGf8.rst | 3 |
4 files changed, 29 insertions, 9 deletions
diff --git a/Lib/inspect.py b/Lib/inspect.py index 8c398bd..d8475c6 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -168,23 +168,30 @@ def isfunction(object): __kwdefaults__ dict of keyword only parameters with defaults""" return isinstance(object, types.FunctionType) +def _has_code_flag(f, flag): + """Return true if ``f`` is a function (or a method or functools.partial + wrapper wrapping a function) whose code object has the given ``flag`` + set in its flags.""" + while ismethod(f): + f = f.__func__ + f = functools._unwrap_partial(f) + if not isfunction(f): + return False + return bool(f.__code__.co_flags & flag) + def isgeneratorfunction(obj): """Return true if the object is a user-defined generator function. Generator function objects provide the same attributes as functions. See help(isfunction) for a list of attributes.""" - obj = functools._unwrap_partial(obj) - return bool((isfunction(obj) or ismethod(obj)) and - obj.__code__.co_flags & CO_GENERATOR) + return _has_code_flag(obj, CO_GENERATOR) def iscoroutinefunction(obj): """Return true if the object is a coroutine function. Coroutine functions are defined with "async def" syntax. """ - obj = functools._unwrap_partial(obj) - return bool(((isfunction(obj) or ismethod(obj)) and - obj.__code__.co_flags & CO_COROUTINE)) + return _has_code_flag(obj, CO_COROUTINE) def isasyncgenfunction(obj): """Return true if the object is an asynchronous generator function. @@ -192,9 +199,7 @@ def isasyncgenfunction(obj): Asynchronous generator functions are defined with "async def" syntax and have "yield" expressions in their body. """ - obj = functools._unwrap_partial(obj) - return bool((isfunction(obj) or ismethod(obj)) and - obj.__code__.co_flags & CO_ASYNC_GENERATOR) + return _has_code_flag(obj, CO_ASYNC_GENERATOR) def isasyncgen(object): """Return true if the object is an asynchronous generator.""" diff --git a/Lib/test/inspect_fodder.py b/Lib/test/inspect_fodder.py index ff3f0e4..6675077 100644 --- a/Lib/test/inspect_fodder.py +++ b/Lib/test/inspect_fodder.py @@ -80,3 +80,14 @@ try: raise Exception() except: tb = sys.exc_info()[2] + +class Callable: + def __call__(self, *args): + return args + + def as_method_of(self, obj): + from types import MethodType + return MethodType(self, obj) + +custom_method = Callable().as_method_of(42) +del Callable diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py index bc675aa..7d74746 100644 --- a/Lib/test/test_inspect.py +++ b/Lib/test/test_inspect.py @@ -146,6 +146,7 @@ class TestPredicates(IsTestBase): self.istest(inspect.isfunction, 'mod.spam') self.istest(inspect.isfunction, 'mod.StupidGit.abuse') self.istest(inspect.ismethod, 'git.argue') + self.istest(inspect.ismethod, 'mod.custom_method') self.istest(inspect.ismodule, 'mod') self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory') self.istest(inspect.isgenerator, '(x for x in range(2))') diff --git a/Misc/NEWS.d/next/Library/2018-04-11-11-41-52.bpo-33291.-xLGf8.rst b/Misc/NEWS.d/next/Library/2018-04-11-11-41-52.bpo-33291.-xLGf8.rst new file mode 100644 index 0000000..1ffb9dd --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-04-11-11-41-52.bpo-33291.-xLGf8.rst @@ -0,0 +1,3 @@ +Do not raise AttributeError when calling the inspect functions +isgeneratorfunction, iscoroutinefunction, isasyncgenfunction on a method +created from an arbitrary callable. Instead, return False. |