diff -r ad6be34ce8c9 Lib/test/test_urlparse.py --- a/Lib/test/test_urlparse.py Tue Apr 26 01:56:50 2016 +0200 +++ b/Lib/test/test_urlparse.py Mon Apr 25 23:39:03 2016 -0400 @@ -627,6 +627,23 @@ with self.assertRaises(ValueError): p.port + def test_invalid_args(self): + default_url = 'www.python.org' + invalid_args = [ + (999, 'http'), + ({}, 'http'), + ([], 'http'), + ((), 'http'), + (default_url, 999), + (default_url, {}), + (default_url, []), + (default_url, ()) + ] + + for arg1, arg2 in invalid_args: + with self.assertRaises(TypeError): + urllib.parse.urlparse(arg1, arg2) + def test_attributes_without_netloc(self): # This example is straight from RFC 3261. It looks like it # should allow the username, hostname, and port to be filled diff -r ad6be34ce8c9 Lib/urllib/parse.py --- a/Lib/urllib/parse.py Tue Apr 26 01:56:50 2016 +0200 +++ b/Lib/urllib/parse.py Mon Apr 25 23:39:03 2016 -0400 @@ -95,7 +95,16 @@ def _decode_args(args, encoding=_implicit_encoding, errors=_implicit_errors): - return tuple(x.decode(encoding, errors) if x else '' for x in args) + return tuple(x.decode(encoding, errors) if x != '' else '' for x in args) + +def _str_like(x): + if hasattr(x, 'encode'): + return True + elif hasattr(x, 'decode'): + return False + else: + raise TypeError('Arguments must be all str or all bytes like objects, ' + '{!r} is invalid'.format(x)) def _coerce_args(*args): # Invokes decode if necessary to create str args @@ -103,12 +112,12 @@ # an appropriate result coercion function # - noop for str inputs # - encoding function otherwise - str_input = isinstance(args[0], str) - for arg in args[1:]: - # We special-case the empty string to support the - # "scheme=''" default argument to some functions - if arg and isinstance(arg, str) != str_input: - raise TypeError("Cannot mix str and non-str arguments") + str_input = _str_like(args[0]) + + # We special-case the empty string to support the + # "scheme=''" default argument to some functions + if any(_str_like(x) != str_input for x in args[1:] if x != ''): + raise TypeError('Cannot mix str and non-str arguments') if str_input: return args + (_noop,) return _decode_args(args) + (_encode_result,)