151

I would like to use urllib.quote(). But python (python3) is not finding the module. Suppose, I have this line of code:

print(urllib.quote("châteu", safe=''))

How do I import urllib.quote?

import urllib or import urllib.quote both give

AttributeError: 'module' object has no attribute 'quote'

What confuses me is that urllib.request is accessible via import urllib.request

imrek
  • 2,930
  • 3
  • 20
  • 36

5 Answers5

249

In Python 3.x, you need to import urllib.parse.quote:

>>> import urllib.parse
>>> urllib.parse.quote("châteu", safe='')
'ch%C3%A2teu'

According to Python 2.x urllib module documentation:

NOTE

The urllib module has been split into parts and renamed in Python 3 to urllib.request, urllib.parse, and urllib.error.

falsetru
  • 357,413
  • 63
  • 732
  • 636
  • 1
    what `safe = ''` indiicates? – ajinzrathod Mar 07 '21 at 12:15
  • 4
    @ajinzrathod, I came from OP's code. According to [documentation](https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote), `The optional safe parameter specifies additional ASCII characters that should not be quoted — its default value is '/'.` -> `/` is not quoted by default, but with `safe=''`, `/` is quoted as `'%2F'`. – falsetru Mar 07 '21 at 15:50
73

If you need to handle both Python 2.x and 3.x you can catch the exception and load the alternative.

try:
    from urllib import quote  # Python 2.X
except ImportError:
    from urllib.parse import quote  # Python 3+

You could also use the python compatibility wrapper six to handle this.

from six.moves.urllib.parse import quote
eandersson
  • 25,781
  • 8
  • 89
  • 110
  • 2
    You should be more forward looking. Assume python3 and except 2.7. try: import urllib.parse as urlparse except ImportError: from urlparse import urlparse # python 2.7.11 – Lincoln Randall McFarland Dec 12 '19 at 19:41
  • @LincolnRandallMcFarland What you are talking about is such a irrelevant micro optimization. It makes it no harder or easier to completely drop Python 2.X support in the project in the future. – eandersson Dec 31 '19 at 19:26
  • 2
    If you want to make throwing and catching an exception the standard import process of your most common use case just because ..., it is no cycles off of my clock but know what you are doing: exceptions should be exceptional. It is the difference between making it work and making it better. – Lincoln Randall McFarland Jan 01 '20 at 23:51
  • This is such a meaningless discussion. Both are valid... if you catch the the Python 3 exception then try to import the Python 2.7 library, but for some reason both are missing the exception thrown will say that it's missing the Python 2.7 library. Very confusing. In reality if you care that much about exceptions there are better ways to handle this, e.g. six or checking the Python version instead of relying on an exception. but in reality if you care that much about something so meaningless you shouldn't be keeping Python 2 backwards compatibility at all because it's EOL this year anyway. – eandersson Jan 02 '20 at 18:53
14

urllib went through some changes in Python3 and can now be imported from the parse submodule

>>> from urllib.parse import quote  
>>> quote('"')                      
'%22'                               
Justin Fay
  • 2,576
  • 1
  • 20
  • 27
4

This is how I handle this, without using exceptions.

import sys
if sys.version_info.major > 2:  # Python 3 or later
    from urllib.parse import quote
else:  # Python 2
    from urllib import quote
Yutenji
  • 41
  • 3
  • 1
    There's no advantage to not using exceptions. Quite the contrary: using exceptions if actually more performant. – pfabri Jun 08 '21 at 12:13
1

Use six:

from six.moves.urllib.parse import quote

six will simplify compatibility problems between Python 2 and Python 3, such as different import paths.

JamesThomasMoon
  • 6,169
  • 7
  • 37
  • 63