def test_getfullargspec_signature_attr(self):
def test():
pass
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
test.__signature__ = inspect.Signature(parameters=(spam_param,))
self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)')
python类Parameter()的实例源码
def test_signature_str_positional_only(self):
P = inspect.Parameter
S = inspect.Signature
def test(a_po, *, b, **kwargs):
return a_po, kwargs
sig = inspect.signature(test)
new_params = list(sig.parameters.values())
new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY)
test.__signature__ = sig.replace(parameters=new_params)
self.assertEqual(str(inspect.signature(test)),
'(a_po, /, *, b, **kwargs)')
self.assertEqual(str(S(parameters=[P('foo', P.POSITIONAL_ONLY)])),
'(foo, /)')
self.assertEqual(str(S(parameters=[
P('foo', P.POSITIONAL_ONLY),
P('bar', P.VAR_KEYWORD)])),
'(foo, /, **bar)')
self.assertEqual(str(S(parameters=[
P('foo', P.POSITIONAL_ONLY),
P('bar', P.VAR_POSITIONAL)])),
'(foo, /, *bar)')
def test_signature_parameter_kinds(self):
P = inspect.Parameter
self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \
P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD)
self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY')
self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY))
def test_signature_parameter_object(self):
p = inspect.Parameter('foo', default=10,
kind=inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(p.name, 'foo')
self.assertEqual(p.default, 10)
self.assertIs(p.annotation, p.empty)
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
with self.assertRaisesRegex(ValueError, 'invalid value'):
inspect.Parameter('foo', default=10, kind='123')
with self.assertRaisesRegex(ValueError, 'not a valid parameter name'):
inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(TypeError, 'name must be a str'):
inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError,
'is not a valid parameter name'):
inspect.Parameter('$', kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_POSITIONAL)
p = inspect.Parameter('a', default=42,
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
p.replace(kind=inspect.Parameter.VAR_POSITIONAL)
self.assertTrue(repr(p).startswith('<Parameter'))
def test_signature_parameter_unhashable(self):
p = inspect.Parameter('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY)
with self.assertRaisesRegex(TypeError, 'unhashable type'):
hash(p)
def test_signature_parameter_replace(self):
p = inspect.Parameter('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY)
self.assertIsNot(p, p.replace())
self.assertEqual(p, p.replace())
p2 = p.replace(annotation=1)
self.assertEqual(p2.annotation, 1)
p2 = p2.replace(annotation=p2.empty)
self.assertEqual(p, p2)
p2 = p2.replace(name='bar')
self.assertEqual(p2.name, 'bar')
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError,
'name is a required attribute'):
p2 = p2.replace(name=p2.empty)
p2 = p2.replace(name='foo', default=None)
self.assertIs(p2.default, None)
self.assertNotEqual(p2, p)
p2 = p2.replace(name='foo', default=p2.empty)
self.assertIs(p2.default, p2.empty)
p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD)
self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD)
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError, 'invalid value for'):
p2 = p2.replace(kind=p2.empty)
p2 = p2.replace(kind=p2.KEYWORD_ONLY)
self.assertEqual(p2, p)
def test_signature_parameter_positional_only(self):
with self.assertRaisesRegex(TypeError, 'name must be a str'):
inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY)
def test_signature_parameter_immutability(self):
p = inspect.Parameter('spam', kind=inspect.Parameter.KEYWORD_ONLY)
with self.assertRaises(AttributeError):
p.foo = 'bar'
with self.assertRaises(AttributeError):
p.kind = 123
def test_signature_bind_positional_only(self):
P = inspect.Parameter
def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs):
return a_po, b_po, c_po, foo, bar, kwargs
sig = inspect.signature(test)
new_params = collections.OrderedDict(tuple(sig.parameters.items()))
for name in ('a_po', 'b_po', 'c_po'):
new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY)
new_sig = sig.replace(parameters=new_params.values())
test.__signature__ = new_sig
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
(1, 2, 4, 5, 6, {}))
self.assertEqual(self.call(test, 1, 2),
(1, 2, 3, 42, 50, {}))
self.assertEqual(self.call(test, 1, 2, foo=4, bar=5),
(1, 2, 3, 4, 5, {}))
with self.assertRaisesRegex(TypeError, "but was passed as a keyword"):
self.call(test, 1, 2, foo=4, bar=5, c_po=10)
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, 1, 2, c_po=4)
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, a_po=1, b_po=2)
def test_getfullargspec_signature_attr(self):
def test():
pass
spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
test.__signature__ = inspect.Signature(parameters=(spam_param,))
self.assertFullArgSpecEquals(test, args_e=['spam'], formatted='(spam)')
def test_signature_str_positional_only(self):
P = inspect.Parameter
S = inspect.Signature
def test(a_po, *, b, **kwargs):
return a_po, kwargs
sig = inspect.signature(test)
new_params = list(sig.parameters.values())
new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY)
test.__signature__ = sig.replace(parameters=new_params)
self.assertEqual(str(inspect.signature(test)),
'(a_po, /, *, b, **kwargs)')
self.assertEqual(str(S(parameters=[P('foo', P.POSITIONAL_ONLY)])),
'(foo, /)')
self.assertEqual(str(S(parameters=[
P('foo', P.POSITIONAL_ONLY),
P('bar', P.VAR_KEYWORD)])),
'(foo, /, **bar)')
self.assertEqual(str(S(parameters=[
P('foo', P.POSITIONAL_ONLY),
P('bar', P.VAR_POSITIONAL)])),
'(foo, /, *bar)')
def test_signature_parameter_kinds(self):
P = inspect.Parameter
self.assertTrue(P.POSITIONAL_ONLY < P.POSITIONAL_OR_KEYWORD < \
P.VAR_POSITIONAL < P.KEYWORD_ONLY < P.VAR_KEYWORD)
self.assertEqual(str(P.POSITIONAL_ONLY), 'POSITIONAL_ONLY')
self.assertTrue('POSITIONAL_ONLY' in repr(P.POSITIONAL_ONLY))
def test_signature_parameter_object(self):
p = inspect.Parameter('foo', default=10,
kind=inspect.Parameter.POSITIONAL_ONLY)
self.assertEqual(p.name, 'foo')
self.assertEqual(p.default, 10)
self.assertIs(p.annotation, p.empty)
self.assertEqual(p.kind, inspect.Parameter.POSITIONAL_ONLY)
with self.assertRaisesRegex(ValueError, 'invalid value'):
inspect.Parameter('foo', default=10, kind='123')
with self.assertRaisesRegex(ValueError, 'not a valid parameter name'):
inspect.Parameter('1', kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(TypeError, 'name must be a str'):
inspect.Parameter(None, kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError,
'is not a valid parameter name'):
inspect.Parameter('$', kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
inspect.Parameter('a', default=42,
kind=inspect.Parameter.VAR_POSITIONAL)
p = inspect.Parameter('a', default=42,
kind=inspect.Parameter.POSITIONAL_OR_KEYWORD)
with self.assertRaisesRegex(ValueError, 'cannot have default values'):
p.replace(kind=inspect.Parameter.VAR_POSITIONAL)
self.assertTrue(repr(p).startswith('<Parameter'))
def test_signature_parameter_unhashable(self):
p = inspect.Parameter('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY)
with self.assertRaisesRegex(TypeError, 'unhashable type'):
hash(p)
def test_signature_parameter_replace(self):
p = inspect.Parameter('foo', default=42,
kind=inspect.Parameter.KEYWORD_ONLY)
self.assertIsNot(p, p.replace())
self.assertEqual(p, p.replace())
p2 = p.replace(annotation=1)
self.assertEqual(p2.annotation, 1)
p2 = p2.replace(annotation=p2.empty)
self.assertEqual(p, p2)
p2 = p2.replace(name='bar')
self.assertEqual(p2.name, 'bar')
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError,
'name is a required attribute'):
p2 = p2.replace(name=p2.empty)
p2 = p2.replace(name='foo', default=None)
self.assertIs(p2.default, None)
self.assertNotEqual(p2, p)
p2 = p2.replace(name='foo', default=p2.empty)
self.assertIs(p2.default, p2.empty)
p2 = p2.replace(default=42, kind=p2.POSITIONAL_OR_KEYWORD)
self.assertEqual(p2.kind, p2.POSITIONAL_OR_KEYWORD)
self.assertNotEqual(p2, p)
with self.assertRaisesRegex(ValueError, 'invalid value for'):
p2 = p2.replace(kind=p2.empty)
p2 = p2.replace(kind=p2.KEYWORD_ONLY)
self.assertEqual(p2, p)
def test_signature_parameter_positional_only(self):
with self.assertRaisesRegex(TypeError, 'name must be a str'):
inspect.Parameter(None, kind=inspect.Parameter.POSITIONAL_ONLY)
def test_signature_parameter_immutability(self):
p = inspect.Parameter('spam', kind=inspect.Parameter.KEYWORD_ONLY)
with self.assertRaises(AttributeError):
p.foo = 'bar'
with self.assertRaises(AttributeError):
p.kind = 123
def test_signature_bind_positional_only(self):
P = inspect.Parameter
def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs):
return a_po, b_po, c_po, foo, bar, kwargs
sig = inspect.signature(test)
new_params = collections.OrderedDict(tuple(sig.parameters.items()))
for name in ('a_po', 'b_po', 'c_po'):
new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY)
new_sig = sig.replace(parameters=new_params.values())
test.__signature__ = new_sig
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
(1, 2, 4, 5, 6, {}))
self.assertEqual(self.call(test, 1, 2),
(1, 2, 3, 42, 50, {}))
self.assertEqual(self.call(test, 1, 2, foo=4, bar=5),
(1, 2, 3, 4, 5, {}))
with self.assertRaisesRegex(TypeError, "but was passed as a keyword"):
self.call(test, 1, 2, foo=4, bar=5, c_po=10)
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, 1, 2, c_po=4)
with self.assertRaisesRegex(TypeError, "parameter is positional only"):
self.call(test, a_po=1, b_po=2)
def parse_annotation(param: inspect.Parameter, default, arg: str, index: int, message: discord.Message):
""" Parse annotations and return the command to use.
index is basically the arg's index in shelx.split(message.content) """
if default is param.empty:
default = None
if param.annotation is not param.empty: # Any annotation is a function or Annotation enum
anno = override_annotation(param.annotation)
content = lambda s: utils.split(s, maxsplit=index)[-1].strip("\" ")
# Valid enum checks
if isinstance(anno, utils.Annotate):
if anno is utils.Annotate.Content: # Split and get raw content from this point
return content(message.content) or default
elif anno is utils.Annotate.LowerContent: # Lowercase of above check
return content(message.content).lower() or default
elif anno is utils.Annotate.CleanContent: # Split and get clean raw content from this point
return content(message.clean_content) or default
elif anno is utils.Annotate.LowerCleanContent: # Lowercase of above check
return content(message.clean_content).lower() or default
elif anno is utils.Annotate.Member: # Checks member names or mentions
return utils.find_member(message.server, arg) or default_self(anno, default, message)
elif anno is utils.Annotate.Channel: # Checks text channel names or mentions
return utils.find_channel(message.server, arg) or default_self(anno, default, message)
elif anno is utils.Annotate.VoiceChannel: # Checks voice channel names or mentions
return utils.find_channel(message.server, arg, channel_type="voice")
elif anno is utils.Annotate.Code: # Works like Content but extracts code
return utils.get_formatted_code(utils.split(message.content, maxsplit=index)[-1]) or default
try: # Try running as a method
if getattr(anno, "allow_spaces", False):
arg = content(message.content)
# Pass the message if the argument has this specified
if getattr(anno, "pass_message", False):
result = anno(message, arg)
else:
result = anno(arg)
# The function can be a coroutine
if inspect.isawaitable(result):
result = await result
return result if result is not None else default
except TypeError:
raise TypeError("Command parameter annotation must be either pcbot.utils.Annotate, a callable or a coroutine")
except AssertionError as e: # raise the error in order to catch it at a lower level
raise AssertionError(e)
except: # On error, eg when annotation is int and given argument is str
return None
return str(arg) or default # Return str of arg if there was no annotation
def __init__(self, func, types, typesentry_config):
# The Config object
self._tc = typesentry_config
# The original function that was inspected
self.function = func
# List of all parameters (Parameter objects), positional and keyword
self.params = []
# Parameter object for the return value
self.retval = Parameter("_return", kind="RETURN")
# Index of the vararg parameter in self.params
self._ivararg = None
# Index of the varkws parameter in self.params
self._ivarkws = None
self._iargs = dict()
# Maximum number of positional parameters (without varargs)
self._max_positional_args = 0
# Minimum number of arguments that must be supplied -- all the other
# have defaults and can be omitted.
self._min_positional_args = 0
# Names of keyword-only arguments that have no defaults
self._required_kwonly_args = set()
# 0 or 1 depending on whether the function has 'self' argument. This
# flag allows us to correctly report the number of arguments for a
# method (1 less than what the signature suggests).
self._num_self_args = 0
#--------------------------------------------------------
# This will initialize all of the arguments defined above
self._fill_from_inspection_spec(types)
# Function that can be invoked to check the type of the return value
self.return_checker = self._make_retval_checker()
# Function that can be invoked to check the arguments passed to the
# inspected function.
self.params_checker = self._make_args_checker()