0

I'm trying to inject a basic-authentication into an url by split-inject-join:

    url = urllib.parse.urlsplit(url)
    new_url = url._replace(username=user, password=password)

But I'm surprised about the behavior of the SplitResult I get from the urllib.parse.urlsplit method:

>>> v = urlsplit('http://a.b/c/d')
>>> v.username is None and v.password is None  # None, but accessible
True
>>> v._replace(scheme='ftp')  # beautiful!  Just like expected.
SplitResult(scheme='ftp', netloc='a.b', path='/c/d', query='', fragment='')

# however...
>>> v._replace(scheme='ftp', username='u', password='p')
...ValueError: Got unexpected field names: ['username', 'password']

It seems as if the None fields in this SplitResult can not be replaced. This is odd, since the documentation claims it to be a named tuple.

When I do the equivalent with a self-constructed named tuple, it appears that the 'None' fields can be replaced without problem.

>>> T = namedtuple("T", ("a", "b", "c"))
>>> t = T(a=1, b=2, c=None)
>>> t
T(a=1, b=2, c=None)
>>> t._replace(c=3)
T(a=1, b=2, c=3)

But the same exception can be triggered by replacing an unexisting field.

>>> t._replace(d=4)  # should raise, please
...ValueError: Got unexpected field names: ['d']
# I was expecting an AttributeError, but hey...

However, in this case, the unexpected field is really not accessible:

>>> t.d is None
...AttributeError: 'T' object has no attribute 'd'

Any idea what makes the SplitResult different?

xtofl
  • 40,723
  • 12
  • 105
  • 192

1 Answers1

1

The documentation doesn't list indices for the fields username, password, hostname, or port. This suggests they aren't actually part of the namedtuple, but instead are just attributes of the SplitResult object. Looking in the CPython implementation, it seems like SplitResult inherits from both the namedtuple containing the first few fields which have indices, as well as a mixin which adds the other fields as properties.

rchome
  • 2,623
  • 8
  • 21