mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
bpo-33261: guard access to __code__ attribute in inspect (GH-6448)
This commit is contained in:
parent
487b73ab39
commit
fcef60f59d
4 changed files with 29 additions and 9 deletions
|
|
@ -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):
|
||||||
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:
|
||||||
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):
|
||||||
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))')
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue