diff --git a/rfc6266.py b/rfc6266.py index 31992ae..85d747a 100644 --- a/rfc6266.py +++ b/rfc6266.py @@ -1,5 +1,3 @@ -# vim: set fileencoding=utf-8 sw=4 ts=4 et : - """Implements RFC 6266, the Content-Disposition HTTP header. parse_headers handles the receiver side. @@ -13,8 +11,8 @@ from lepl import * from collections import namedtuple -from urllib import quote, unquote -from urlparse import urlsplit +from urllib.parse import quote, unquote +from urllib.parse import urlsplit from string import hexdigits, ascii_letters, digits import logging @@ -61,7 +59,7 @@ def percent_decode(string, **kwargs): return unquote(string, **kwargs).decode(encoding) -class ContentDisposition(object): +class ContentDisposition: """ Records various indications and hints about content disposition. @@ -83,7 +81,7 @@ def __init__(self, disposition='inline', assocs=None, location=None): self.assocs = {} else: # XXX Check that parameters aren't repeated - self.assocs = dict((key.lower(), val) for (key, val) in assocs) + self.assocs = {key.lower(): val for (key, val) in assocs} @property def filename_unsafe(self): @@ -160,7 +158,7 @@ def is_inline(self): return self.disposition.lower() == 'inline' def __repr__(self): - return 'ContentDisposition(%r, %r, %r)' % ( + return 'ContentDisposition({!r}, {!r}, {!r})'.format( self.disposition, self.assocs, self.location) @@ -256,7 +254,7 @@ def parse_ext_value(val): else: charset, coded = val langtag = None - if not PY3K and isinstance(coded, unicode): + if not PY3K and isinstance(coded, str): coded = coded.encode('ascii') decoded = percent_decode(coded, encoding=charset) return LangTagged(decoded, langtag) @@ -270,7 +268,7 @@ def CaseInsensitiveLiteral(lit): # RFC 2616 separator_chars = "()<>@,;:\\\"/[]?={} \t" -ctl_chars = ''.join(chr(i) for i in xrange(32)) + chr(127) +ctl_chars = ''.join(chr(i) for i in range(32)) + chr(127) nontoken_chars = separator_chars + ctl_chars # RFC 5987 @@ -306,7 +304,7 @@ def CaseInsensitiveLiteral(lit): # and all the others are defined with Any. qdtext = AnyBut('"' + ctl_chars) -char = Any(''.join(chr(i) for i in xrange(128))) # ascii range: 0-127 +char = Any(''.join(chr(i) for i in range(128))) # ascii range: 0-127 quoted_pair = Drop('\\') + char quoted_string = Drop('"') & (quoted_pair | qdtext)[:, ...] & Drop('"') @@ -428,26 +426,26 @@ def build_header( rv = disposition if is_token(filename): - rv += '; filename=%s' % (filename, ) + rv += '; filename={}'.format(filename) return rv elif is_ascii(filename) and is_lws_safe(filename): qd_filename = qd_quote(filename) - rv += '; filename="%s"' % (qd_filename, ) + rv += '; filename="{}"'.format(qd_filename) if qd_filename == filename: # RFC 6266 claims some implementations are iffy on qdtext's # backslash-escaping, we'll include filename* in that case. return rv elif filename_compat: if is_token(filename_compat): - rv += '; filename=%s' % (filename_compat, ) + rv += '; filename={}'.format(filename_compat) else: assert is_lws_safe(filename_compat) - rv += '; filename="%s"' % (qd_quote(filename_compat), ) + rv += '; filename="{}"'.format(qd_quote(filename_compat)) # alnum are already considered always-safe, but the rest isn't. # Python encodes ~ when it shouldn't, for example. - rv += "; filename*=utf-8''%s" % (percent_encode( - filename, safe=attr_chars_nonalnum, encoding='utf-8'), ) + rv += "; filename*=utf-8''{}".format(percent_encode( + filename, safe=attr_chars_nonalnum, encoding='utf-8')) # This will only encode filename_compat, if it used non-ascii iso-8859-1. return rv.encode('iso-8859-1') diff --git a/setup.py b/setup.py index 619e8aa..2787f58 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ - from setuptools import setup setup( @@ -13,16 +12,14 @@ platforms='OS-independent', py_modules=['rfc6266', 'test_rfc6266'], install_requires=['LEPL'], - use_2to3=True, long_description=open('README').read(), - classifiers=( - 'Programming Language :: Python :: 2', + classifiers=[ 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'Topic :: Internet :: WWW/HTTP', - ), + ], ) - diff --git a/test_rfc6266.py b/test_rfc6266.py index b610499..7a5e20d 100644 --- a/test_rfc6266.py +++ b/test_rfc6266.py @@ -1,5 +1,3 @@ -# vim: set fileencoding=utf-8 sw=4 ts=4 et : - from rfc6266 import ( parse_headers, parse_httplib2_response, parse_requests_response, build_header) @@ -14,13 +12,13 @@ def test_parsing(): 'attachment; filename=simple').filename_unsafe == 'simple' # test ISO-8859-1 - fname = parse_headers(u'attachment; filename="oyé"').filename_unsafe - assert fname == u'oyé', repr(fname) + fname = parse_headers('attachment; filename="oyé"').filename_unsafe + assert fname == 'oyé', repr(fname) cd = parse_headers( 'attachment; filename="EURO rates";' ' filename*=utf-8\'\'%e2%82%ac%20rates') - assert cd.filename_unsafe == u'€ rates' + assert cd.filename_unsafe == '€ rates' @pytest.mark.skipif("(3,0) <= sys.version_info < (3,3)") @@ -45,15 +43,15 @@ def test_requests(httpserver): def test_location_fallback(): assert parse_headers( None, location='https://foo/bar%c3%a9.py' - ).filename_unsafe == u'baré.py' + ).filename_unsafe == 'baré.py' assert parse_headers( None, location='https://foo/' - ).filename_unsafe == u'' + ).filename_unsafe == '' assert parse_headers( None, location='https://foo/%C3%A9toil%C3%A9/' - ).filename_unsafe == u'étoilé' + ).filename_unsafe == 'étoilé' def test_strict(): @@ -77,7 +75,7 @@ def test_relaxed(): cd = parse_headers( 'attachment; filename="spa ced";', relaxed=True) - assert cd.filename_unsafe == u'spa ced' + assert cd.filename_unsafe == 'spa ced' @@ -93,5 +91,5 @@ def assert_roundtrip(filename): assert_roundtrip('a b ') assert_roundtrip(' a b') assert_roundtrip('a\"b') - assert_roundtrip(u'aéio o♥u"qfsdf!') + assert_roundtrip('aéio o♥u"qfsdf!') diff --git a/tox.ini b/tox.ini index a30cc1e..b197923 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist=py27,py26,py32,py33,pypy +envlist=py38,pypi [testenv] deps= @@ -13,4 +13,3 @@ commands=py.test --pyargs test_rfc6266 # Changedir is a hack to prevent test discovery from finding the non-2to3 # source. We want tests to be import-based only. changedir=.tox -