8

I want to change the port in given url.

OLD=http://test:7000/vcc3 NEW=http://test:7777/vcc3

I tried below code code, I am able to change the URL but not able to change the port.

>>> from urlparse import urlparse
>>> aaa = urlparse('http://test:7000/vcc3')
>>> aaa.hostname
test
>>> aaa.port
7000
>>>aaa._replace(netloc=aaa.netloc.replace(aaa.hostname,"newurl")).geturl()
'http://newurl:7000/vcc3'
>>>aaa._replace(netloc=aaa.netloc.replace(aaa.port,"7777")).geturl()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: expected a character buffer object

3 Answers3

8

It's not a particularly good error message. It's complaining because you're passing ParseResult.port, an int, to the string's replace method which expects a str. Just stringify port before you pass it in:

aaa._replace(netloc=aaa.netloc.replace(str(aaa.port), "7777"))

I'm astonished that there isn't a simple way to set the port using the urlparse library. It feels like an oversight. Ideally you'd be able to say something like parseresult._replace(port=7777), but alas, that doesn't work.

Community
  • 1
  • 1
Benjamin Hodgson
  • 42,952
  • 15
  • 108
  • 157
  • 1
    Are we suppose to use `_replace` method directly ? Rule of thumb is, you should not invoke private methods on objects directly. – Aashish P Jan 27 '16 at 10:25
  • 3
    @AashishP Good question. `namedtuple` flouts convention somewhat; [`_replace` is not intended to be a private method](https://docs.python.org/3/library/collections.html#collections.somenamedtuple._replace). It's named with an underscore to minimise the likelihood of name-conflicts with a field in the `namedtuple`. (Scroll up from the linked documentation and you'll find the sentence "To prevent conflicts with field names, the method and attribute names start with an underscore.") – Benjamin Hodgson Jan 27 '16 at 10:26
  • Thanks for your comment. – Aashish P Jan 27 '16 at 10:31
7

The details of the port are stored in netloc, so you can simply do:

>>> a = urlparse('http://test:7000/vcc3')
>>> a._replace(netloc='newurl:7777').geturl()
'http://newurl:7777/vcc3'
>>> a._replace(netloc=a.hostname+':7777').geturl()  # Keep the same host
'http://test:7777/vcc3'
AChampion
  • 29,683
  • 4
  • 59
  • 75
  • Much cleaner than the currently accepted answer, which I just edited to have a bit of dancing around in order to guard against edge cases – sinback Apr 07 '22 at 15:56
3

The problem is that the ParseResult 's 'port' member is protected and you can't change the attribute -don't event try to use private _replace() method. Solution is here:

from urllib.parse import urlparse, ParseResult

old = urlparse('http://test:7000/vcc3')
new = ParseResult(scheme=a.scheme, netloc="{}:{}".format(old.hostname, 7777),
                  path=old.path, params=old.params, query=old.query, fragment=old.fragment)
new_url = new.geturl()

The second idea is to convert ParseResult to list->change it later on like here:

Changing hostname in a url

BTW 'urlparse' library is not flexible in that area!

bukas
  • 161
  • 2
  • 2