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