Kaydet (Commit) fcef60f5 authored tarafından Jeroen Demeyer's avatar Jeroen Demeyer Kaydeden (comit) Petr Viktorin

bpo-33261: guard access to __code__ attribute in inspect (GH-6448)

üst 487b73ab
...@@ -168,23 +168,30 @@ def isfunction(object): ...@@ -168,23 +168,30 @@ def isfunction(object):
__kwdefaults__ dict of keyword only parameters with defaults""" __kwdefaults__ dict of keyword only parameters with defaults"""
return isinstance(object, types.FunctionType) 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): def isgeneratorfunction(obj):
"""Return true if the object is a user-defined generator function. """Return true if the object is a user-defined generator function.
Generator function objects provide the same attributes as functions. Generator function objects provide the same attributes as functions.
See help(isfunction) for a list of attributes.""" See help(isfunction) for a list of attributes."""
obj = functools._unwrap_partial(obj) return _has_code_flag(obj, CO_GENERATOR)
return bool((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_GENERATOR)
def iscoroutinefunction(obj): def iscoroutinefunction(obj):
"""Return true if the object is a coroutine function. """Return true if the object is a coroutine function.
Coroutine functions are defined with "async def" syntax. Coroutine functions are defined with "async def" syntax.
""" """
obj = functools._unwrap_partial(obj) return _has_code_flag(obj, CO_COROUTINE)
return bool(((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_COROUTINE))
def isasyncgenfunction(obj): def isasyncgenfunction(obj):
"""Return true if the object is an asynchronous generator function. """Return true if the object is an asynchronous generator function.
...@@ -192,9 +199,7 @@ def isasyncgenfunction(obj): ...@@ -192,9 +199,7 @@ def isasyncgenfunction(obj):
Asynchronous generator functions are defined with "async def" Asynchronous generator functions are defined with "async def"
syntax and have "yield" expressions in their body. syntax and have "yield" expressions in their body.
""" """
obj = functools._unwrap_partial(obj) return _has_code_flag(obj, CO_ASYNC_GENERATOR)
return bool((isfunction(obj) or ismethod(obj)) and
obj.__code__.co_flags & CO_ASYNC_GENERATOR)
def isasyncgen(object): def isasyncgen(object):
"""Return true if the object is an asynchronous generator.""" """Return true if the object is an asynchronous generator."""
......
...@@ -80,3 +80,14 @@ try: ...@@ -80,3 +80,14 @@ try:
raise Exception() raise Exception()
except: except:
tb = sys.exc_info()[2] 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
...@@ -146,6 +146,7 @@ class TestPredicates(IsTestBase): ...@@ -146,6 +146,7 @@ class TestPredicates(IsTestBase):
self.istest(inspect.isfunction, 'mod.spam') self.istest(inspect.isfunction, 'mod.spam')
self.istest(inspect.isfunction, 'mod.StupidGit.abuse') self.istest(inspect.isfunction, 'mod.StupidGit.abuse')
self.istest(inspect.ismethod, 'git.argue') self.istest(inspect.ismethod, 'git.argue')
self.istest(inspect.ismethod, 'mod.custom_method')
self.istest(inspect.ismodule, 'mod') self.istest(inspect.ismodule, 'mod')
self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory') self.istest(inspect.isdatadescriptor, 'collections.defaultdict.default_factory')
self.istest(inspect.isgenerator, '(x for x in range(2))') self.istest(inspect.isgenerator, '(x for x in range(2))')
......
Do not raise AttributeError when calling the inspect functions
isgeneratorfunction, iscoroutinefunction, isasyncgenfunction on a method
created from an arbitrary callable. Instead, return False.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment