diff -ur urlnorm-1.1.4.orig/setup.py urlnorm-1.1.4/setup.py
--- urlnorm-1.1.4.orig/setup.py	2016-08-05 20:07:24.000000000 +0200
+++ urlnorm-1.1.4/setup.py	2022-10-21 09:32:35.377477901 +0200
@@ -9,8 +9,15 @@
         description="Normalize a URL to a standard unicode encoding",
         py_modules=['urlnorm'],
         license='MIT License',
+        install_requires=['six'],
         author='Jehiah Czebotar',
         author_email='jehiah@gmail.com',
         url='http://github.com/jehiah/urlnorm',
         download_url="http://github.com/downloads/jehiah/urlnorm/urlnorm-%s.tar.gz" % version,
+        classifiers=[
+            'Operating System :: OS Independent',
+            'Programming Language :: Python :: 2.7',
+            'Programming Language :: Python :: 3',
+            'Programming Language :: Python :: 3.6',
+        ],
         )
diff -ur urlnorm-1.1.4.orig/urlnorm.py urlnorm-1.1.4/urlnorm.py
--- urlnorm-1.1.4.orig/urlnorm.py	2016-08-05 20:06:32.000000000 +0200
+++ urlnorm-1.1.4/urlnorm.py	2022-10-21 09:32:35.377477901 +0200
@@ -41,6 +41,10 @@
      - more fine-grained authority parsing and normalisation    
 """
 
+from __future__ import absolute_import
+from six import unichr
+import six
+from six.moves import range
 __license__ = """
 Copyright (c) 1999-2002 Mark Nottingham <mnot@pobox.com>
 Copyright (c) 2010 Jehiah Czebotar <jehiah@gmail.com>
@@ -67,8 +71,7 @@
 # also update in setup.py
 __version__ = "1.1.4"
 
-from urlparse import urlparse, urlunparse
-from string import lower
+from six.moves.urllib.parse import urlparse, urlunparse, unquote
 import re
 
 
@@ -108,8 +111,8 @@
 qs_unsafe_list = set('?&=+%#')
 fragment_unsafe_list = set('+%#')
 path_unsafe_list = set('/?;%+#')
-_hextochr = dict(('%02x' % i, chr(i)) for i in range(256))
-_hextochr.update(('%02X' % i, chr(i)) for i in range(256))
+_hextochr = dict((b'%02x' % i, six.int2byte(i)) for i in range(256))
+_hextochr.update((b'%02X' % i, six.int2byte(i)) for i in range(256))
 
 
 def unquote_path(s):
@@ -132,22 +135,23 @@
     """unquote percent escaped string except for percent escape sequences that are in unsafe_list"""
     # note: this build utf8 raw strings ,then does a .decode('utf8') at the end.
     # as a result it's doing .encode('utf8') on each block of the string as it's processed.
-    res = _utf8(s).split('%')
-    for i in xrange(1, len(res)):
+    unsafe_list = [_utf8(i) for i in unsafe_list]
+    res = _utf8(s).split(b'%')
+    for i in range(1, len(res)):
         item = res[i]
         try:
             raw_chr = _hextochr[item[:2]]
             if raw_chr in unsafe_list or ord(raw_chr) < 20:
                 # leave it unescaped (but uppercase the percent escape)
-                res[i] = '%' + item[:2].upper() + item[2:]
+                res[i] = b'%' + item[:2].upper() + item[2:]
             else:
                 res[i] = raw_chr + item[2:]
         except KeyError:
-            res[i] = '%' + item
+            res[i] = b'%' + item
         except UnicodeDecodeError:
             # note: i'm not sure what this does
             res[i] = unichr(int(item[:2], 16)) + item[2:]
-    o = "".join(res)
+    o = b"".join(res)
     return _unicode(o)
 
 
@@ -160,7 +164,7 @@
 
 def norm_tuple(scheme, authority, path, parameters, query, fragment):
     """given individual url components, return its normalized form"""
-    scheme = lower(scheme)
+    scheme = scheme.lower()
     if not scheme:
         raise InvalidUrl('missing URL scheme')
     authority = norm_netloc(scheme, authority)
@@ -203,7 +207,7 @@
         return '/'
     return path
 
-MAX_IP = 0xffffffffL
+MAX_IP = 0xffffffff
 
 
 def int2ip(ipnum):
@@ -238,7 +242,7 @@
     if '.' not in host and not (host[0] == '[' and host[-1] == ']'):
         raise InvalidUrl('host %r is not valid' % host)
 
-    authority = lower(host)
+    authority = host.lower()
     if 'xn--' in authority:
         subdomains = [_idn(subdomain) for subdomain in authority.split('.')]
         authority = '.'.join(subdomains)
@@ -260,14 +264,14 @@
 
 
 def _utf8(value):
-    if isinstance(value, unicode):
+    if isinstance(value, six.text_type):
         return value.encode("utf-8")
     assert isinstance(value, str)
     return value
 
 
 def _unicode(value):
-    if isinstance(value, str):
+    if isinstance(value, six.binary_type):
         return value.decode("utf-8")
-    assert isinstance(value, unicode)
+    assert isinstance(value, six.text_type)
     return value
