diff -r 824ba744b999 Lib/inspect.py --- a/Lib/inspect.py Tue Jan 28 23:32:40 2014 +0100 +++ b/Lib/inspect.py Tue Jan 28 17:57:08 2014 -0500 @@ -1486,7 +1486,14 @@ not param._partial_kwarg): new_params.pop(arg_name) - return wrapped_sig.replace(parameters=new_params.values()) + # We don't use '.replace' method here, as signatures for partial + # objects may bot be valid python signatures, i.e. parameters with + # defaults can be before parameters without defaults, etc. Therefore, + # we construct the Signature object manually, passing + # '__validate_parameters__ = False'. + return type(wrapped_sig)(parameters=new_params.values(), + return_annotation=wrapped_sig.return_annotation, + __validate_parameters__=False) def _signature_bound_method(sig): @@ -1918,6 +1925,7 @@ if __validate_parameters__: params = OrderedDict() top_kind = _POSITIONAL_ONLY + kind_defaults = False for idx, param in enumerate(parameters): kind = param.kind @@ -1927,9 +1935,19 @@ msg = 'wrong parameter order: {} before {}' msg = msg.format(top_kind, kind) raise ValueError(msg) - else: + elif kind > top_kind: + kind_defaults = False top_kind = kind + if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD): + if param.default is _empty: + if kind_defaults: + msg = 'non-default argument follows default ' \ + 'argument' + raise ValueError(msg) + else: + kind_defaults = True + if name in params: msg = 'duplicate parameter name: {!r}'.format(name) raise ValueError(msg) diff -r 824ba744b999 Lib/test/test_inspect.py --- a/Lib/test/test_inspect.py Tue Jan 28 23:32:40 2014 +0100 +++ b/Lib/test/test_inspect.py Tue Jan 28 17:57:08 2014 -0500 @@ -1522,11 +1522,13 @@ self.assertEqual(str(S()), '()') - def test(po, pk, *args, ko, **kwargs): + def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs): pass sig = inspect.signature(test) po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY) + pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY) pk = sig.parameters['pk'] + pkd = sig.parameters['pkd'] args = sig.parameters['args'] ko = sig.parameters['ko'] kwargs = sig.parameters['kwargs'] @@ -1549,6 +1551,12 @@ with self.assertRaisesRegex(ValueError, 'duplicate parameter name'): S((po, pk, args, kwargs2, ko)) + with self.assertRaisesRegex(ValueError, 'follows default argument'): + S((pod, po)) + + with self.assertRaisesRegex(ValueError, 'follows default argument'): + S((po, pkd, pk)) + def test_signature_immutability(self): def test(a): pass