__init__.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. # Copyright 2001-2013 Python Software Foundation; All Rights Reserved
  2. """Function signature objects for callables
  3. Back port of Python 3.3's function signature tools from the inspect module,
  4. modified to be compatible with Python 2.6, 2.7 and 3.3+.
  5. """
  6. from __future__ import absolute_import, division, print_function
  7. import itertools
  8. import functools
  9. import re
  10. import types
  11. try:
  12. from collections import OrderedDict
  13. except ImportError:
  14. from ordereddict import OrderedDict
  15. from funcsigs.version import __version__
  16. __all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature']
  17. _WrapperDescriptor = type(type.__call__)
  18. _MethodWrapper = type(all.__call__)
  19. _NonUserDefinedCallables = (_WrapperDescriptor,
  20. _MethodWrapper,
  21. types.BuiltinFunctionType)
  22. def formatannotation(annotation, base_module=None):
  23. if isinstance(annotation, type):
  24. if annotation.__module__ in ('builtins', '__builtin__', base_module):
  25. return annotation.__name__
  26. return annotation.__module__+'.'+annotation.__name__
  27. return repr(annotation)
  28. def _get_user_defined_method(cls, method_name, *nested):
  29. try:
  30. if cls is type:
  31. return
  32. meth = getattr(cls, method_name)
  33. for name in nested:
  34. meth = getattr(meth, name, meth)
  35. except AttributeError:
  36. return
  37. else:
  38. if not isinstance(meth, _NonUserDefinedCallables):
  39. # Once '__signature__' will be added to 'C'-level
  40. # callables, this check won't be necessary
  41. return meth
  42. def signature(obj):
  43. '''Get a signature object for the passed callable.'''
  44. if not callable(obj):
  45. raise TypeError('{0!r} is not a callable object'.format(obj))
  46. if isinstance(obj, types.MethodType):
  47. sig = signature(obj.__func__)
  48. if obj.__self__ is None:
  49. # Unbound method - preserve as-is.
  50. return sig
  51. else:
  52. # Bound method. Eat self - if we can.
  53. params = tuple(sig.parameters.values())
  54. if not params or params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
  55. raise ValueError('invalid method signature')
  56. kind = params[0].kind
  57. if kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY):
  58. # Drop first parameter:
  59. # '(p1, p2[, ...])' -> '(p2[, ...])'
  60. params = params[1:]
  61. else:
  62. if kind is not _VAR_POSITIONAL:
  63. # Unless we add a new parameter type we never
  64. # get here
  65. raise ValueError('invalid argument type')
  66. # It's a var-positional parameter.
  67. # Do nothing. '(*args[, ...])' -> '(*args[, ...])'
  68. return sig.replace(parameters=params)
  69. try:
  70. sig = obj.__signature__
  71. except AttributeError:
  72. pass
  73. else:
  74. if sig is not None:
  75. return sig
  76. try:
  77. # Was this function wrapped by a decorator?
  78. wrapped = obj.__wrapped__
  79. except AttributeError:
  80. pass
  81. else:
  82. return signature(wrapped)
  83. if isinstance(obj, types.FunctionType):
  84. return Signature.from_function(obj)
  85. if isinstance(obj, functools.partial):
  86. sig = signature(obj.func)
  87. new_params = OrderedDict(sig.parameters.items())
  88. partial_args = obj.args or ()
  89. partial_keywords = obj.keywords or {}
  90. try:
  91. ba = sig.bind_partial(*partial_args, **partial_keywords)
  92. except TypeError as ex:
  93. msg = 'partial object {0!r} has incorrect arguments'.format(obj)
  94. raise ValueError(msg)
  95. for arg_name, arg_value in ba.arguments.items():
  96. param = new_params[arg_name]
  97. if arg_name in partial_keywords:
  98. # We set a new default value, because the following code
  99. # is correct:
  100. #
  101. # >>> def foo(a): print(a)
  102. # >>> print(partial(partial(foo, a=10), a=20)())
  103. # 20
  104. # >>> print(partial(partial(foo, a=10), a=20)(a=30))
  105. # 30
  106. #
  107. # So, with 'partial' objects, passing a keyword argument is
  108. # like setting a new default value for the corresponding
  109. # parameter
  110. #
  111. # We also mark this parameter with '_partial_kwarg'
  112. # flag. Later, in '_bind', the 'default' value of this
  113. # parameter will be added to 'kwargs', to simulate
  114. # the 'functools.partial' real call.
  115. new_params[arg_name] = param.replace(default=arg_value,
  116. _partial_kwarg=True)
  117. elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and
  118. not param._partial_kwarg):
  119. new_params.pop(arg_name)
  120. return sig.replace(parameters=new_params.values())
  121. sig = None
  122. if isinstance(obj, type):
  123. # obj is a class or a metaclass
  124. # First, let's see if it has an overloaded __call__ defined
  125. # in its metaclass
  126. call = _get_user_defined_method(type(obj), '__call__')
  127. if call is not None:
  128. sig = signature(call)
  129. else:
  130. # Now we check if the 'obj' class has a '__new__' method
  131. new = _get_user_defined_method(obj, '__new__')
  132. if new is not None:
  133. sig = signature(new)
  134. else:
  135. # Finally, we should have at least __init__ implemented
  136. init = _get_user_defined_method(obj, '__init__')
  137. if init is not None:
  138. sig = signature(init)
  139. elif not isinstance(obj, _NonUserDefinedCallables):
  140. # An object with __call__
  141. # We also check that the 'obj' is not an instance of
  142. # _WrapperDescriptor or _MethodWrapper to avoid
  143. # infinite recursion (and even potential segfault)
  144. call = _get_user_defined_method(type(obj), '__call__', 'im_func')
  145. if call is not None:
  146. sig = signature(call)
  147. if sig is not None:
  148. # For classes and objects we skip the first parameter of their
  149. # __call__, __new__, or __init__ methods
  150. return sig.replace(parameters=tuple(sig.parameters.values())[1:])
  151. if isinstance(obj, types.BuiltinFunctionType):
  152. # Raise a nicer error message for builtins
  153. msg = 'no signature found for builtin function {0!r}'.format(obj)
  154. raise ValueError(msg)
  155. raise ValueError('callable {0!r} is not supported by signature'.format(obj))
  156. class _void(object):
  157. '''A private marker - used in Parameter & Signature'''
  158. class _empty(object):
  159. pass
  160. class _ParameterKind(int):
  161. def __new__(self, *args, **kwargs):
  162. obj = int.__new__(self, *args)
  163. obj._name = kwargs['name']
  164. return obj
  165. def __str__(self):
  166. return self._name
  167. def __repr__(self):
  168. return '<_ParameterKind: {0!r}>'.format(self._name)
  169. _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY')
  170. _POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD')
  171. _VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL')
  172. _KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY')
  173. _VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD')
  174. class Parameter(object):
  175. '''Represents a parameter in a function signature.
  176. Has the following public attributes:
  177. * name : str
  178. The name of the parameter as a string.
  179. * default : object
  180. The default value for the parameter if specified. If the
  181. parameter has no default value, this attribute is not set.
  182. * annotation
  183. The annotation for the parameter if specified. If the
  184. parameter has no annotation, this attribute is not set.
  185. * kind : str
  186. Describes how argument values are bound to the parameter.
  187. Possible values: `Parameter.POSITIONAL_ONLY`,
  188. `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
  189. `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
  190. '''
  191. __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg')
  192. POSITIONAL_ONLY = _POSITIONAL_ONLY
  193. POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD
  194. VAR_POSITIONAL = _VAR_POSITIONAL
  195. KEYWORD_ONLY = _KEYWORD_ONLY
  196. VAR_KEYWORD = _VAR_KEYWORD
  197. empty = _empty
  198. def __init__(self, name, kind, default=_empty, annotation=_empty,
  199. _partial_kwarg=False):
  200. if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
  201. _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
  202. raise ValueError("invalid value for 'Parameter.kind' attribute")
  203. self._kind = kind
  204. if default is not _empty:
  205. if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
  206. msg = '{0} parameters cannot have default values'.format(kind)
  207. raise ValueError(msg)
  208. self._default = default
  209. self._annotation = annotation
  210. if name is None:
  211. if kind != _POSITIONAL_ONLY:
  212. raise ValueError("None is not a valid name for a "
  213. "non-positional-only parameter")
  214. self._name = name
  215. else:
  216. name = str(name)
  217. if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I):
  218. msg = '{0!r} is not a valid parameter name'.format(name)
  219. raise ValueError(msg)
  220. self._name = name
  221. self._partial_kwarg = _partial_kwarg
  222. @property
  223. def name(self):
  224. return self._name
  225. @property
  226. def default(self):
  227. return self._default
  228. @property
  229. def annotation(self):
  230. return self._annotation
  231. @property
  232. def kind(self):
  233. return self._kind
  234. def replace(self, name=_void, kind=_void, annotation=_void,
  235. default=_void, _partial_kwarg=_void):
  236. '''Creates a customized copy of the Parameter.'''
  237. if name is _void:
  238. name = self._name
  239. if kind is _void:
  240. kind = self._kind
  241. if annotation is _void:
  242. annotation = self._annotation
  243. if default is _void:
  244. default = self._default
  245. if _partial_kwarg is _void:
  246. _partial_kwarg = self._partial_kwarg
  247. return type(self)(name, kind, default=default, annotation=annotation,
  248. _partial_kwarg=_partial_kwarg)
  249. def __str__(self):
  250. kind = self.kind
  251. formatted = self._name
  252. if kind == _POSITIONAL_ONLY:
  253. if formatted is None:
  254. formatted = ''
  255. formatted = '<{0}>'.format(formatted)
  256. # Add annotation and default value
  257. if self._annotation is not _empty:
  258. formatted = '{0}:{1}'.format(formatted,
  259. formatannotation(self._annotation))
  260. if self._default is not _empty:
  261. formatted = '{0}={1}'.format(formatted, repr(self._default))
  262. if kind == _VAR_POSITIONAL:
  263. formatted = '*' + formatted
  264. elif kind == _VAR_KEYWORD:
  265. formatted = '**' + formatted
  266. return formatted
  267. def __repr__(self):
  268. return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__,
  269. id(self), self.name)
  270. def __hash__(self):
  271. msg = "unhashable type: '{0}'".format(self.__class__.__name__)
  272. raise TypeError(msg)
  273. def __eq__(self, other):
  274. return (issubclass(other.__class__, Parameter) and
  275. self._name == other._name and
  276. self._kind == other._kind and
  277. self._default == other._default and
  278. self._annotation == other._annotation)
  279. def __ne__(self, other):
  280. return not self.__eq__(other)
  281. class BoundArguments(object):
  282. '''Result of `Signature.bind` call. Holds the mapping of arguments
  283. to the function's parameters.
  284. Has the following public attributes:
  285. * arguments : OrderedDict
  286. An ordered mutable mapping of parameters' names to arguments' values.
  287. Does not contain arguments' default values.
  288. * signature : Signature
  289. The Signature object that created this instance.
  290. * args : tuple
  291. Tuple of positional arguments values.
  292. * kwargs : dict
  293. Dict of keyword arguments values.
  294. '''
  295. def __init__(self, signature, arguments):
  296. self.arguments = arguments
  297. self._signature = signature
  298. @property
  299. def signature(self):
  300. return self._signature
  301. @property
  302. def args(self):
  303. args = []
  304. for param_name, param in self._signature.parameters.items():
  305. if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
  306. param._partial_kwarg):
  307. # Keyword arguments mapped by 'functools.partial'
  308. # (Parameter._partial_kwarg is True) are mapped
  309. # in 'BoundArguments.kwargs', along with VAR_KEYWORD &
  310. # KEYWORD_ONLY
  311. break
  312. try:
  313. arg = self.arguments[param_name]
  314. except KeyError:
  315. # We're done here. Other arguments
  316. # will be mapped in 'BoundArguments.kwargs'
  317. break
  318. else:
  319. if param.kind == _VAR_POSITIONAL:
  320. # *args
  321. args.extend(arg)
  322. else:
  323. # plain argument
  324. args.append(arg)
  325. return tuple(args)
  326. @property
  327. def kwargs(self):
  328. kwargs = {}
  329. kwargs_started = False
  330. for param_name, param in self._signature.parameters.items():
  331. if not kwargs_started:
  332. if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or
  333. param._partial_kwarg):
  334. kwargs_started = True
  335. else:
  336. if param_name not in self.arguments:
  337. kwargs_started = True
  338. continue
  339. if not kwargs_started:
  340. continue
  341. try:
  342. arg = self.arguments[param_name]
  343. except KeyError:
  344. pass
  345. else:
  346. if param.kind == _VAR_KEYWORD:
  347. # **kwargs
  348. kwargs.update(arg)
  349. else:
  350. # plain keyword argument
  351. kwargs[param_name] = arg
  352. return kwargs
  353. def __hash__(self):
  354. msg = "unhashable type: '{0}'".format(self.__class__.__name__)
  355. raise TypeError(msg)
  356. def __eq__(self, other):
  357. return (issubclass(other.__class__, BoundArguments) and
  358. self.signature == other.signature and
  359. self.arguments == other.arguments)
  360. def __ne__(self, other):
  361. return not self.__eq__(other)
  362. class Signature(object):
  363. '''A Signature object represents the overall signature of a function.
  364. It stores a Parameter object for each parameter accepted by the
  365. function, as well as information specific to the function itself.
  366. A Signature object has the following public attributes and methods:
  367. * parameters : OrderedDict
  368. An ordered mapping of parameters' names to the corresponding
  369. Parameter objects (keyword-only arguments are in the same order
  370. as listed in `code.co_varnames`).
  371. * return_annotation : object
  372. The annotation for the return type of the function if specified.
  373. If the function has no annotation for its return type, this
  374. attribute is not set.
  375. * bind(*args, **kwargs) -> BoundArguments
  376. Creates a mapping from positional and keyword arguments to
  377. parameters.
  378. * bind_partial(*args, **kwargs) -> BoundArguments
  379. Creates a partial mapping from positional and keyword arguments
  380. to parameters (simulating 'functools.partial' behavior.)
  381. '''
  382. __slots__ = ('_return_annotation', '_parameters')
  383. _parameter_cls = Parameter
  384. _bound_arguments_cls = BoundArguments
  385. empty = _empty
  386. def __init__(self, parameters=None, return_annotation=_empty,
  387. __validate_parameters__=True):
  388. '''Constructs Signature from the given list of Parameter
  389. objects and 'return_annotation'. All arguments are optional.
  390. '''
  391. if parameters is None:
  392. params = OrderedDict()
  393. else:
  394. if __validate_parameters__:
  395. params = OrderedDict()
  396. top_kind = _POSITIONAL_ONLY
  397. for idx, param in enumerate(parameters):
  398. kind = param.kind
  399. if kind < top_kind:
  400. msg = 'wrong parameter order: {0} before {1}'
  401. msg = msg.format(top_kind, param.kind)
  402. raise ValueError(msg)
  403. else:
  404. top_kind = kind
  405. name = param.name
  406. if name is None:
  407. name = str(idx)
  408. param = param.replace(name=name)
  409. if name in params:
  410. msg = 'duplicate parameter name: {0!r}'.format(name)
  411. raise ValueError(msg)
  412. params[name] = param
  413. else:
  414. params = OrderedDict(((param.name, param)
  415. for param in parameters))
  416. self._parameters = params
  417. self._return_annotation = return_annotation
  418. @classmethod
  419. def from_function(cls, func):
  420. '''Constructs Signature for the given python function'''
  421. if not isinstance(func, types.FunctionType):
  422. raise TypeError('{0!r} is not a Python function'.format(func))
  423. Parameter = cls._parameter_cls
  424. # Parameter information.
  425. func_code = func.__code__
  426. pos_count = func_code.co_argcount
  427. arg_names = func_code.co_varnames
  428. positional = tuple(arg_names[:pos_count])
  429. keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0)
  430. keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)]
  431. annotations = getattr(func, '__annotations__', {})
  432. defaults = func.__defaults__
  433. kwdefaults = getattr(func, '__kwdefaults__', None)
  434. if defaults:
  435. pos_default_count = len(defaults)
  436. else:
  437. pos_default_count = 0
  438. parameters = []
  439. # Non-keyword-only parameters w/o defaults.
  440. non_default_count = pos_count - pos_default_count
  441. for name in positional[:non_default_count]:
  442. annotation = annotations.get(name, _empty)
  443. parameters.append(Parameter(name, annotation=annotation,
  444. kind=_POSITIONAL_OR_KEYWORD))
  445. # ... w/ defaults.
  446. for offset, name in enumerate(positional[non_default_count:]):
  447. annotation = annotations.get(name, _empty)
  448. parameters.append(Parameter(name, annotation=annotation,
  449. kind=_POSITIONAL_OR_KEYWORD,
  450. default=defaults[offset]))
  451. # *args
  452. if func_code.co_flags & 0x04:
  453. name = arg_names[pos_count + keyword_only_count]
  454. annotation = annotations.get(name, _empty)
  455. parameters.append(Parameter(name, annotation=annotation,
  456. kind=_VAR_POSITIONAL))
  457. # Keyword-only parameters.
  458. for name in keyword_only:
  459. default = _empty
  460. if kwdefaults is not None:
  461. default = kwdefaults.get(name, _empty)
  462. annotation = annotations.get(name, _empty)
  463. parameters.append(Parameter(name, annotation=annotation,
  464. kind=_KEYWORD_ONLY,
  465. default=default))
  466. # **kwargs
  467. if func_code.co_flags & 0x08:
  468. index = pos_count + keyword_only_count
  469. if func_code.co_flags & 0x04:
  470. index += 1
  471. name = arg_names[index]
  472. annotation = annotations.get(name, _empty)
  473. parameters.append(Parameter(name, annotation=annotation,
  474. kind=_VAR_KEYWORD))
  475. return cls(parameters,
  476. return_annotation=annotations.get('return', _empty),
  477. __validate_parameters__=False)
  478. @property
  479. def parameters(self):
  480. try:
  481. return types.MappingProxyType(self._parameters)
  482. except AttributeError:
  483. return OrderedDict(self._parameters.items())
  484. @property
  485. def return_annotation(self):
  486. return self._return_annotation
  487. def replace(self, parameters=_void, return_annotation=_void):
  488. '''Creates a customized copy of the Signature.
  489. Pass 'parameters' and/or 'return_annotation' arguments
  490. to override them in the new copy.
  491. '''
  492. if parameters is _void:
  493. parameters = self.parameters.values()
  494. if return_annotation is _void:
  495. return_annotation = self._return_annotation
  496. return type(self)(parameters,
  497. return_annotation=return_annotation)
  498. def __hash__(self):
  499. msg = "unhashable type: '{0}'".format(self.__class__.__name__)
  500. raise TypeError(msg)
  501. def __eq__(self, other):
  502. if (not issubclass(type(other), Signature) or
  503. self.return_annotation != other.return_annotation or
  504. len(self.parameters) != len(other.parameters)):
  505. return False
  506. other_positions = dict((param, idx)
  507. for idx, param in enumerate(other.parameters.keys()))
  508. for idx, (param_name, param) in enumerate(self.parameters.items()):
  509. if param.kind == _KEYWORD_ONLY:
  510. try:
  511. other_param = other.parameters[param_name]
  512. except KeyError:
  513. return False
  514. else:
  515. if param != other_param:
  516. return False
  517. else:
  518. try:
  519. other_idx = other_positions[param_name]
  520. except KeyError:
  521. return False
  522. else:
  523. if (idx != other_idx or
  524. param != other.parameters[param_name]):
  525. return False
  526. return True
  527. def __ne__(self, other):
  528. return not self.__eq__(other)
  529. def _bind(self, args, kwargs, partial=False):
  530. '''Private method. Don't use directly.'''
  531. arguments = OrderedDict()
  532. parameters = iter(self.parameters.values())
  533. parameters_ex = ()
  534. arg_vals = iter(args)
  535. if partial:
  536. # Support for binding arguments to 'functools.partial' objects.
  537. # See 'functools.partial' case in 'signature()' implementation
  538. # for details.
  539. for param_name, param in self.parameters.items():
  540. if (param._partial_kwarg and param_name not in kwargs):
  541. # Simulating 'functools.partial' behavior
  542. kwargs[param_name] = param.default
  543. while True:
  544. # Let's iterate through the positional arguments and corresponding
  545. # parameters
  546. try:
  547. arg_val = next(arg_vals)
  548. except StopIteration:
  549. # No more positional arguments
  550. try:
  551. param = next(parameters)
  552. except StopIteration:
  553. # No more parameters. That's it. Just need to check that
  554. # we have no `kwargs` after this while loop
  555. break
  556. else:
  557. if param.kind == _VAR_POSITIONAL:
  558. # That's OK, just empty *args. Let's start parsing
  559. # kwargs
  560. break
  561. elif param.name in kwargs:
  562. if param.kind == _POSITIONAL_ONLY:
  563. msg = '{arg!r} parameter is positional only, ' \
  564. 'but was passed as a keyword'
  565. msg = msg.format(arg=param.name)
  566. raise TypeError(msg)
  567. parameters_ex = (param,)
  568. break
  569. elif (param.kind == _VAR_KEYWORD or
  570. param.default is not _empty):
  571. # That's fine too - we have a default value for this
  572. # parameter. So, lets start parsing `kwargs`, starting
  573. # with the current parameter
  574. parameters_ex = (param,)
  575. break
  576. else:
  577. if partial:
  578. parameters_ex = (param,)
  579. break
  580. else:
  581. msg = '{arg!r} parameter lacking default value'
  582. msg = msg.format(arg=param.name)
  583. raise TypeError(msg)
  584. else:
  585. # We have a positional argument to process
  586. try:
  587. param = next(parameters)
  588. except StopIteration:
  589. raise TypeError('too many positional arguments')
  590. else:
  591. if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
  592. # Looks like we have no parameter for this positional
  593. # argument
  594. raise TypeError('too many positional arguments')
  595. if param.kind == _VAR_POSITIONAL:
  596. # We have an '*args'-like argument, let's fill it with
  597. # all positional arguments we have left and move on to
  598. # the next phase
  599. values = [arg_val]
  600. values.extend(arg_vals)
  601. arguments[param.name] = tuple(values)
  602. break
  603. if param.name in kwargs:
  604. raise TypeError('multiple values for argument '
  605. '{arg!r}'.format(arg=param.name))
  606. arguments[param.name] = arg_val
  607. # Now, we iterate through the remaining parameters to process
  608. # keyword arguments
  609. kwargs_param = None
  610. for param in itertools.chain(parameters_ex, parameters):
  611. if param.kind == _POSITIONAL_ONLY:
  612. # This should never happen in case of a properly built
  613. # Signature object (but let's have this check here
  614. # to ensure correct behaviour just in case)
  615. raise TypeError('{arg!r} parameter is positional only, '
  616. 'but was passed as a keyword'. \
  617. format(arg=param.name))
  618. if param.kind == _VAR_KEYWORD:
  619. # Memorize that we have a '**kwargs'-like parameter
  620. kwargs_param = param
  621. continue
  622. param_name = param.name
  623. try:
  624. arg_val = kwargs.pop(param_name)
  625. except KeyError:
  626. # We have no value for this parameter. It's fine though,
  627. # if it has a default value, or it is an '*args'-like
  628. # parameter, left alone by the processing of positional
  629. # arguments.
  630. if (not partial and param.kind != _VAR_POSITIONAL and
  631. param.default is _empty):
  632. raise TypeError('{arg!r} parameter lacking default value'. \
  633. format(arg=param_name))
  634. else:
  635. arguments[param_name] = arg_val
  636. if kwargs:
  637. if kwargs_param is not None:
  638. # Process our '**kwargs'-like parameter
  639. arguments[kwargs_param.name] = kwargs
  640. else:
  641. raise TypeError('too many keyword arguments %r' % kwargs)
  642. return self._bound_arguments_cls(self, arguments)
  643. def bind(*args, **kwargs):
  644. '''Get a BoundArguments object, that maps the passed `args`
  645. and `kwargs` to the function's signature. Raises `TypeError`
  646. if the passed arguments can not be bound.
  647. '''
  648. return args[0]._bind(args[1:], kwargs)
  649. def bind_partial(self, *args, **kwargs):
  650. '''Get a BoundArguments object, that partially maps the
  651. passed `args` and `kwargs` to the function's signature.
  652. Raises `TypeError` if the passed arguments can not be bound.
  653. '''
  654. return self._bind(args, kwargs, partial=True)
  655. def __str__(self):
  656. result = []
  657. render_kw_only_separator = True
  658. for idx, param in enumerate(self.parameters.values()):
  659. formatted = str(param)
  660. kind = param.kind
  661. if kind == _VAR_POSITIONAL:
  662. # OK, we have an '*args'-like parameter, so we won't need
  663. # a '*' to separate keyword-only arguments
  664. render_kw_only_separator = False
  665. elif kind == _KEYWORD_ONLY and render_kw_only_separator:
  666. # We have a keyword-only parameter to render and we haven't
  667. # rendered an '*args'-like parameter before, so add a '*'
  668. # separator to the parameters list ("foo(arg1, *, arg2)" case)
  669. result.append('*')
  670. # This condition should be only triggered once, so
  671. # reset the flag
  672. render_kw_only_separator = False
  673. result.append(formatted)
  674. rendered = '({0})'.format(', '.join(result))
  675. if self.return_annotation is not _empty:
  676. anno = formatannotation(self.return_annotation)
  677. rendered += ' -> {0}'.format(anno)
  678. return rendered