From 8360f70024330eeeb5c53d29e4a05194f872b511 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 17 Oct 2016 15:15:22 +1300 Subject: [PATCH] First-order conversion to Python3-only - Zap various occurrences of Python2 in docs and scripts - Remove six from netlib, and some other places where obvious project-wide search and replace works. --- .appveyor.yml | 2 -- .travis.yml | 4 --- README.rst | 1 - docs/install.rst | 6 ++--- mitmproxy/console/common.py | 5 ++-- mitmproxy/contentviews.py | 3 +-- mitmproxy/contrib/tnetstring.py | 2 +- mitmproxy/flow/export.py | 4 +-- mitmproxy/flowfilter.py | 3 +-- mitmproxy/models/connections.py | 2 +- mitmproxy/protocol/tls.py | 2 +- netlib/basetypes.py | 4 +-- netlib/certutils.py | 1 - netlib/encoding.py | 3 +-- netlib/http/headers.py | 28 +++++++-------------- netlib/http/message.py | 29 +++++++++------------- netlib/http/request.py | 26 ++++++++------------ netlib/http/response.py | 7 +++--- netlib/http/url.py | 28 ++++++--------------- netlib/multidict.py | 7 ++---- netlib/strutils.py | 43 +++++++++------------------------ netlib/tcp.py | 21 +++++----------- netlib/tutils.py | 11 ++++----- netlib/version_check.py | 3 +-- netlib/websockets/frame.py | 14 ++--------- netlib/websockets/masker.py | 7 +----- netlib/wsgi.py | 11 ++++----- pathod/language/base.py | 3 +-- pathod/pathoc.py | 2 +- setup.py | 9 ------- tox.ini | 2 +- 31 files changed, 90 insertions(+), 203 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7fa65e1b5..388686289 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,8 +7,6 @@ environment: matrix: - PYTHON: "C:\\Python35" TOXENV: "py35" - - PYTHON: "C:\\Python27" - TOXENV: "py27" SNAPSHOT_HOST: secure: NeTo57s2rJhCd/mjKHetXVxCFd3uhr8txnjnAXD1tUI= diff --git a/.travis.yml b/.travis.yml index f7c5e839d..d160a96ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,10 +28,6 @@ matrix: env: TOXENV=py35 BDIST=1 - python: 3.5 env: TOXENV=py35 NO_ALPN=1 - - python: 2.7 - env: TOXENV=py27 - - python: 2.7 - env: TOXENV=py27 NO_ALPN=1 - python: 3.5 env: TOXENV=docs allow_failures: diff --git a/README.rst b/README.rst index 5234ef71e..e69b64135 100644 --- a/README.rst +++ b/README.rst @@ -110,7 +110,6 @@ The following tox environments are relevant for local testing: .. code-block:: text - tox -e py27 # runs all tests with Python 2.7 tox -e py35 # runs all tests with Python 3.5 tox -e docs # runs a does-it-compile check on the documentation tox -e lint # runs the linter for coding style checks diff --git a/docs/install.rst b/docs/install.rst index 6077c3fe1..5c823ef48 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -101,9 +101,9 @@ Installation On Windows **There is no interactive user interface on Windows.** -First, install the latest version of Python 2.7 from the `Python website`_. -If you already have an older version of Python 2.7 installed, make sure to install pip_ -(pip is included in Python 2.7.9+ by default). If pip aborts with an error, make sure you are using the current version of pip. +First, install the latest version of Python 3.5 from the `Python website`_. +If you already have an older version of Python 3.5 installed, make sure to install pip_ +(pip is included in Python by default). If pip aborts with an error, make sure you are using the current version of pip. >>> python -m pip install --upgrade pip diff --git a/mitmproxy/console/common.py b/mitmproxy/console/common.py index 25181cb70..e1366c1e1 100644 --- a/mitmproxy/console/common.py +++ b/mitmproxy/console/common.py @@ -6,7 +6,6 @@ import os import urwid import urwid.util -import six import netlib from mitmproxy import utils @@ -39,7 +38,7 @@ def is_keypress(k): """ Is this input event a keypress? """ - if isinstance(k, six.string_types): + if isinstance(k, str): return True @@ -110,7 +109,7 @@ def shortcuts(k): def fcol(s, attr): - s = six.text_type(s) + s = str(s) return ( "fixed", len(s), diff --git a/mitmproxy/contentviews.py b/mitmproxy/contentviews.py index f95efb99d..83e6a7ad0 100644 --- a/mitmproxy/contentviews.py +++ b/mitmproxy/contentviews.py @@ -22,7 +22,6 @@ import json import logging import lxml.etree import lxml.html -import six import subprocess import traceback from PIL import ExifTags @@ -56,7 +55,7 @@ def pretty_json(s): except ValueError: return None pretty = json.dumps(p, sort_keys=True, indent=4, ensure_ascii=False) - if isinstance(pretty, six.text_type): + if isinstance(pretty, str): # json.dumps _may_ decide to return unicode, if the JSON object is not ascii. # From limited testing this is always valid utf8 (otherwise json.loads will fail earlier), # so we can just re-encode it here. diff --git a/mitmproxy/contrib/tnetstring.py b/mitmproxy/contrib/tnetstring.py index 6c498c757..f5e1d5c10 100644 --- a/mitmproxy/contrib/tnetstring.py +++ b/mitmproxy/contrib/tnetstring.py @@ -121,7 +121,7 @@ def _rdumpq(q, size, value): write(b':') write(span) return size + 2 + len(span) + ldata - elif isinstance(value, six.text_type): + elif isinstance(value, str): data = value.encode("utf8") ldata = len(data) span = str(ldata).encode() diff --git a/mitmproxy/flow/export.py b/mitmproxy/flow/export.py index 731aaf0e9..eb2d38d28 100644 --- a/mitmproxy/flow/export.py +++ b/mitmproxy/flow/export.py @@ -12,10 +12,10 @@ import netlib.http def _native(s): if six.PY2: - if isinstance(s, six.text_type): + if isinstance(s, str): return s.encode() else: - if isinstance(s, six.binary_type): + if isinstance(s, bytes): return s.decode() return s diff --git a/mitmproxy/flowfilter.py b/mitmproxy/flowfilter.py index 27a3212ca..7080786fa 100644 --- a/mitmproxy/flowfilter.py +++ b/mitmproxy/flowfilter.py @@ -36,7 +36,6 @@ from __future__ import absolute_import, print_function, division import re import sys import functools -import six from mitmproxy.models.http import HTTPFlow from mitmproxy.models.tcp import TCPFlow @@ -510,7 +509,7 @@ def match(flt, flow): If flt is a string, it will be compiled as a filter expression. If the expression is invalid, ValueError is raised. """ - if isinstance(flt, six.string_types): + if isinstance(flt, str): flt = parse(flt) if not flt: raise ValueError("Invalid filter expression.") diff --git a/mitmproxy/models/connections.py b/mitmproxy/models/connections.py index a98711a15..9778b7f12 100644 --- a/mitmproxy/models/connections.py +++ b/mitmproxy/models/connections.py @@ -205,7 +205,7 @@ class ServerConnection(tcp.TCPClient, stateobject.StateObject): self.wfile.flush() def establish_ssl(self, clientcerts, sni, **kwargs): - if sni and not isinstance(sni, six.string_types): + if sni and not isinstance(sni, str): raise ValueError("sni must be str, not " + type(sni).__name__) clientcert = None if clientcerts: diff --git a/mitmproxy/protocol/tls.py b/mitmproxy/protocol/tls.py index 943fe837a..4792edb86 100644 --- a/mitmproxy/protocol/tls.py +++ b/mitmproxy/protocol/tls.py @@ -407,7 +407,7 @@ class TlsLayer(base.Layer): self._establish_tls_with_server() def set_server_tls(self, server_tls, sni=None): - # type: (bool, Union[six.text_type, None, False]) -> None + # type: (bool, Union[str, None, False]) -> None """ Set the TLS settings for the next server connection that will be established. This function will not alter an existing connection. diff --git a/netlib/basetypes.py b/netlib/basetypes.py index 9d6c60ba1..49892ffcd 100644 --- a/netlib/basetypes.py +++ b/netlib/basetypes.py @@ -1,9 +1,7 @@ -import six import abc -@six.add_metaclass(abc.ABCMeta) -class Serializable(object): +class Serializable(metaclass=abc.ABCMeta): """ Abstract Base Class that defines an API to save an object's state and restore it later on. """ diff --git a/netlib/certutils.py b/netlib/certutils.py index bdc2b77e4..23836cb50 100644 --- a/netlib/certutils.py +++ b/netlib/certutils.py @@ -3,7 +3,6 @@ import os import ssl import time import datetime -from six.moves import filter import ipaddress import sys diff --git a/netlib/encoding.py b/netlib/encoding.py index 9b8b38688..f0f7381d7 100644 --- a/netlib/encoding.py +++ b/netlib/encoding.py @@ -5,7 +5,6 @@ from __future__ import absolute_import import codecs import collections -import six from io import BytesIO import gzip @@ -91,7 +90,7 @@ def encode(decoded, encoding, errors='strict'): try: try: value = decoded - if not six.PY2 and isinstance(value, six.string_types): + if isinstance(value, str): value = decoded.encode() encoded = custom_encode[encoding](value) except KeyError: diff --git a/netlib/http/headers.py b/netlib/http/headers.py index b55874ca6..7d46a88e4 100644 --- a/netlib/http/headers.py +++ b/netlib/http/headers.py @@ -3,26 +3,19 @@ from __future__ import absolute_import, print_function, division import re import collections -import six from netlib import multidict from netlib import strutils # See also: http://lucumr.pocoo.org/2013/7/2/the-updated-guide-to-unicode/ -if six.PY2: # pragma: no cover - def _native(x): - return x - def _always_bytes(x): - strutils.always_bytes(x, "utf-8", "replace") # raises a TypeError if x != str/bytes/None. - return x -else: - # While headers _should_ be ASCII, it's not uncommon for certain headers to be utf-8 encoded. - def _native(x): - return x.decode("utf-8", "surrogateescape") +# While headers _should_ be ASCII, it's not uncommon for certain headers to be utf-8 encoded. +def _native(x): + return x.decode("utf-8", "surrogateescape") - def _always_bytes(x): - return strutils.always_bytes(x, "utf-8", "surrogateescape") + +def _always_bytes(x): + return strutils.always_bytes(x, "utf-8", "surrogateescape") class Headers(multidict.MultiDict): @@ -93,7 +86,7 @@ class Headers(multidict.MultiDict): # content_type -> content-type headers = { _always_bytes(name).replace(b"_", b"-"): _always_bytes(value) - for name, value in six.iteritems(headers) + for name, value in headers.items() } self.update(headers) @@ -113,9 +106,6 @@ class Headers(multidict.MultiDict): else: return b"" - if six.PY2: # pragma: no cover - __str__ = __bytes__ - def __delitem__(self, key): key = _always_bytes(key) super(Headers, self).__delitem__(key) @@ -167,9 +157,9 @@ class Headers(multidict.MultiDict): Returns: The number of replacements made. """ - if isinstance(pattern, six.text_type): + if isinstance(pattern, str): pattern = strutils.escaped_str_to_bytes(pattern) - if isinstance(repl, six.text_type): + if isinstance(repl, str): repl = strutils.escaped_str_to_bytes(repl) pattern = re.compile(pattern, flags) replacements = 0 diff --git a/netlib/http/message.py b/netlib/http/message.py index 0b64d4a60..13f908caa 100644 --- a/netlib/http/message.py +++ b/netlib/http/message.py @@ -3,24 +3,17 @@ from __future__ import absolute_import, print_function, division import re import warnings -import six - from netlib import encoding, strutils, basetypes from netlib.http import headers -if six.PY2: # pragma: no cover - def _native(x): - return x - def _always_bytes(x): - return x -else: - # While headers _should_ be ASCII, it's not uncommon for certain headers to be utf-8 encoded. - def _native(x): - return x.decode("utf-8", "surrogateescape") +# While headers _should_ be ASCII, it's not uncommon for certain headers to be utf-8 encoded. +def _native(x): + return x.decode("utf-8", "surrogateescape") - def _always_bytes(x): - return strutils.always_bytes(x, "utf-8", "surrogateescape") + +def _always_bytes(x): + return strutils.always_bytes(x, "utf-8", "surrogateescape") class MessageData(basetypes.Serializable): @@ -194,7 +187,7 @@ class Message(basetypes.Serializable): return "latin-1" def get_text(self, strict=True): - # type: (bool) -> six.text_type + # type: (bool) -> str """ The HTTP message body decoded with both content-encoding header (e.g. gzip) and content-type header charset. @@ -214,7 +207,7 @@ class Message(basetypes.Serializable): except ValueError: if strict: raise - return content.decode("utf8", "replace" if six.PY2 else "surrogateescape") + return content.decode("utf8", "surrogateescape") def set_text(self, text): if text is None: @@ -230,7 +223,7 @@ class Message(basetypes.Serializable): ct[2]["charset"] = "utf-8" self.headers["content-type"] = headers.assemble_content_type(*ct) enc = "utf8" - self.content = text.encode(enc, "replace" if six.PY2 else "surrogateescape") + self.content = text.encode(enc, "surrogateescape") text = property(get_text, set_text) @@ -269,9 +262,9 @@ class Message(basetypes.Serializable): Returns: The number of replacements made. """ - if isinstance(pattern, six.text_type): + if isinstance(pattern, str): pattern = strutils.escaped_str_to_bytes(pattern) - if isinstance(repl, six.text_type): + if isinstance(repl, str): repl = strutils.escaped_str_to_bytes(repl) replacements = 0 if self.content: diff --git a/netlib/http/request.py b/netlib/http/request.py index e0aaa8a9a..cccda13e1 100644 --- a/netlib/http/request.py +++ b/netlib/http/request.py @@ -1,9 +1,7 @@ from __future__ import absolute_import, print_function, division import re - -import six -from six.moves import urllib +import urllib from netlib import multidict from netlib import strutils @@ -34,19 +32,19 @@ class RequestData(message.MessageData): timestamp_start=None, timestamp_end=None ): - if isinstance(method, six.text_type): + if isinstance(method, str): method = method.encode("ascii", "strict") - if isinstance(scheme, six.text_type): + if isinstance(scheme, str): scheme = scheme.encode("ascii", "strict") - if isinstance(host, six.text_type): + if isinstance(host, str): host = host.encode("idna", "strict") - if isinstance(path, six.text_type): + if isinstance(path, str): path = path.encode("ascii", "strict") - if isinstance(http_version, six.text_type): + if isinstance(http_version, str): http_version = http_version.encode("ascii", "strict") if not isinstance(headers, nheaders.Headers): headers = nheaders.Headers(headers) - if isinstance(content, six.text_type): + if isinstance(content, str): raise ValueError("Content must be bytes, not {}".format(type(content).__name__)) self.first_line_format = first_line_format @@ -89,9 +87,9 @@ class Request(message.Message): Returns: The number of replacements made. """ - if isinstance(pattern, six.text_type): + if isinstance(pattern, str): pattern = strutils.escaped_str_to_bytes(pattern) - if isinstance(repl, six.text_type): + if isinstance(repl, str): repl = strutils.escaped_str_to_bytes(repl) c = super(Request, self).replace(pattern, repl, flags, count) @@ -147,10 +145,6 @@ class Request(message.Message): Setting the host attribute also updates the host header, if present. """ - - if six.PY2: # pragma: no cover - return self.data.host - if not self.data.host: return self.data.host try: @@ -160,7 +154,7 @@ class Request(message.Message): @host.setter def host(self, host): - if isinstance(host, six.text_type): + if isinstance(host, str): try: # There's no non-strict mode for IDNA encoding. # We don't want this operation to fail though, so we try diff --git a/netlib/http/response.py b/netlib/http/response.py index ec19640da..30bec2df4 100644 --- a/netlib/http/response.py +++ b/netlib/http/response.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, print_function, division -import six import time from email.utils import parsedate_tz, formatdate, mktime_tz from netlib import human @@ -27,13 +26,13 @@ class ResponseData(message.MessageData): timestamp_start=None, timestamp_end=None ): - if isinstance(http_version, six.text_type): + if isinstance(http_version, str): http_version = http_version.encode("ascii", "strict") - if isinstance(reason, six.text_type): + if isinstance(reason, str): reason = reason.encode("ascii", "strict") if not isinstance(headers, nheaders.Headers): headers = nheaders.Headers(headers) - if isinstance(content, six.text_type): + if isinstance(content, str): raise ValueError("Content must be bytes, not {}".format(type(content).__name__)) self.http_version = http_version diff --git a/netlib/http/url.py b/netlib/http/url.py index 076854b94..2878734a8 100644 --- a/netlib/http/url.py +++ b/netlib/http/url.py @@ -1,5 +1,4 @@ -import six -from six.moves import urllib +import urllib from netlib import utils @@ -41,7 +40,7 @@ def parse(url): if not parsed.hostname: raise ValueError("No hostname given") - if isinstance(url, six.binary_type): + if isinstance(url, bytes): host = parsed.hostname # this should not raise a ValueError, @@ -86,20 +85,14 @@ def encode(s): """ Takes a list of (key, value) tuples and returns a urlencoded string. """ - if six.PY2: - return urllib.parse.urlencode(s, False) - else: - return urllib.parse.urlencode(s, False, errors="surrogateescape") + return urllib.parse.urlencode(s, False, errors="surrogateescape") def decode(s): """ Takes a urlencoded string and returns a list of surrogate-escaped (key, value) tuples. """ - if six.PY2: - return urllib.parse.parse_qsl(s, keep_blank_values=True) - else: - return urllib.parse.parse_qsl(s, keep_blank_values=True, errors='surrogateescape') + return urllib.parse.parse_qsl(s, keep_blank_values=True, errors='surrogateescape') def quote(b, safe="/"): @@ -108,10 +101,7 @@ def quote(b, safe="/"): An ascii-encodable str. """ # type: (str) -> str - if six.PY2: - return urllib.parse.quote(b, safe=safe) - else: - return urllib.parse.quote(b, safe=safe, errors="surrogateescape") + return urllib.parse.quote(b, safe=safe, errors="surrogateescape") def unquote(s): @@ -122,11 +112,7 @@ def unquote(s): A surrogate-escaped str """ # type: (str) -> str - - if six.PY2: - return urllib.parse.unquote(s) - else: - return urllib.parse.unquote(s, errors="surrogateescape") + return urllib.parse.unquote(s, errors="surrogateescape") def hostport(scheme, host, port): @@ -136,7 +122,7 @@ def hostport(scheme, host, port): if (port, scheme) in [(80, "http"), (443, "https"), (80, b"http"), (443, b"https")]: return host else: - if isinstance(host, six.binary_type): + if isinstance(host, bytes): return b"%s:%d" % (host, port) else: return "%s:%d" % (host, port) diff --git a/netlib/multidict.py b/netlib/multidict.py index e9fec155a..b86267314 100644 --- a/netlib/multidict.py +++ b/netlib/multidict.py @@ -8,12 +8,10 @@ try: except ImportError: # pragma: no cover from collections import MutableMapping # Workaround for Python < 3.3 -import six from netlib import basetypes -@six.add_metaclass(ABCMeta) -class _MultiDict(MutableMapping, basetypes.Serializable): +class _MultiDict(MutableMapping, basetypes.Serializable, metaclass=ABCMeta): def __repr__(self): fields = ( repr(field) @@ -231,8 +229,7 @@ class MultiDict(_MultiDict): return key -@six.add_metaclass(ABCMeta) -class ImmutableMultiDict(MultiDict): +class ImmutableMultiDict(MultiDict, metaclass=ABCMeta): def _immutable(self, *_): raise TypeError('{} objects are immutable'.format(self.__class__.__name__)) diff --git a/netlib/strutils.py b/netlib/strutils.py index d43c2aab0..81e957928 100644 --- a/netlib/strutils.py +++ b/netlib/strutils.py @@ -2,11 +2,9 @@ from __future__ import absolute_import, print_function, division import re import codecs -import six - def always_bytes(unicode_or_bytes, *encode_args): - if isinstance(unicode_or_bytes, six.text_type): + if isinstance(unicode_or_bytes, str): return unicode_or_bytes.encode(*encode_args) elif isinstance(unicode_or_bytes, bytes) or unicode_or_bytes is None: return unicode_or_bytes @@ -21,14 +19,10 @@ def native(s, *encoding_opts): https://www.python.org/dev/peps/pep-3333/#a-note-on-string-types """ - if not isinstance(s, (six.binary_type, six.text_type)): + if not isinstance(s, (bytes, str)): raise TypeError("%r is neither bytes nor unicode" % s) - if six.PY2: - if isinstance(s, six.text_type): - return s.encode(*encoding_opts) - else: - if isinstance(s, six.binary_type): - return s.decode(*encoding_opts) + if isinstance(s, bytes): + return s.decode(*encoding_opts) return s @@ -45,11 +39,8 @@ for x in ("\r", "\n", "\t"): del _control_char_trans_newline[ord(x)] -if six.PY2: - pass -else: - _control_char_trans = str.maketrans(_control_char_trans) - _control_char_trans_newline = str.maketrans(_control_char_trans_newline) +_control_char_trans = str.maketrans(_control_char_trans) +_control_char_trans_newline = str.maketrans(_control_char_trans_newline) def escape_control_characters(text, keep_spacing=True): @@ -59,16 +50,11 @@ def escape_control_characters(text, keep_spacing=True): Args: keep_spacing: If True, tabs and newlines will not be replaced. """ - # type: (six.string_types) -> six.text_type - if not isinstance(text, six.string_types): + # type: (str) -> str + if not isinstance(text, str): raise ValueError("text type must be unicode but is {}".format(type(text).__name__)) trans = _control_char_trans_newline if keep_spacing else _control_char_trans - if six.PY2: - return u"".join( - six.unichr(trans.get(ord(ch), ord(ch))) - for ch in text - ) return text.translate(trans) @@ -107,16 +93,9 @@ def escaped_str_to_bytes(data): Raises: ValueError, if the escape sequence is invalid. """ - if not isinstance(data, six.string_types): - if six.PY2: - raise ValueError("data must be str or unicode, but is {}".format(data.__class__.__name__)) + if not isinstance(data, str): raise ValueError("data must be str, but is {}".format(data.__class__.__name__)) - if six.PY2: - if isinstance(data, unicode): - data = data.encode("utf8") - return data.decode("string-escape") - # This one is difficult - we use an undocumented Python API here # as per http://stackoverflow.com/a/23151714/934719 return codecs.escape_decode(data)[0] @@ -129,7 +108,7 @@ def is_mostly_bin(s): return sum( i < 9 or 13 < i < 32 or 126 < i - for i in six.iterbytes(s[:100]) + for i in s[:100] ) / len(s[:100]) > 0.3 @@ -158,7 +137,7 @@ def hexdump(s): for i in range(0, len(s), 16): offset = "{:0=10x}".format(i) part = s[i:i + 16] - x = " ".join("{:0=2x}".format(i) for i in six.iterbytes(part)) + x = " ".join("{:0=2x}".format(i) for i in part) x = x.ljust(47) # 16*2 + 15 part_repr = native(escape_control_characters( part.decode("ascii", "replace").replace(u"\ufffd", u"."), diff --git a/netlib/tcp.py b/netlib/tcp.py index 64b9ce3bd..e4e134c44 100644 --- a/netlib/tcp.py +++ b/netlib/tcp.py @@ -12,11 +12,9 @@ import binascii from typing import Optional # noqa from netlib import strutils -from six.moves import range import certifi from backports import ssl_match_hostname -import six import OpenSSL from OpenSSL import SSL @@ -30,10 +28,7 @@ from netlib import basethread # the latest version of pyOpenSSL is actually installed. version_check.check_pyopenssl_version() -if six.PY2: - socket_fileobject = socket._fileobject -else: - socket_fileobject = socket.SocketIO +socket_fileobject = socket.SocketIO EINTR = 4 if os.environ.get("NO_ALPN"): @@ -293,7 +288,7 @@ class Reader(_FileLike): try: return self.o.recv(length, socket.MSG_PEEK) except SSL.Error as e: - six.reraise(exceptions.TlsException, exceptions.TlsException(str(e)), sys.exc_info()[2]) + raise exceptions.TlsException(str(e)) else: raise NotImplementedError("Can only peek into (pyOpenSSL) sockets") @@ -445,12 +440,8 @@ class _Connection(object): # as it may just return what's left in the buffer and not all the bytes we want. # As a workaround, we just use unbuffered sockets directly. # https://mail.python.org/pipermail/python-dev/2009-June/089986.html - if six.PY2: - self.rfile = Reader(self.connection.makefile('rb', self.rbufsize)) - self.wfile = Writer(self.connection.makefile('wb', self.wbufsize)) - else: - self.rfile = Reader(socket.SocketIO(self.connection, "rb")) - self.wfile = Writer(socket.SocketIO(self.connection, "wb")) + self.rfile = Reader(socket.SocketIO(self.connection, "rb")) + self.wfile = Writer(socket.SocketIO(self.connection, "wb")) def __init__(self, connection): if connection: @@ -968,8 +959,8 @@ class TCPServer(object): """ # If a thread has persisted after interpreter exit, the module might be # none. - if traceback and six: - exc = six.text_type(traceback.format_exc()) + if traceback: + exc = str(traceback.format_exc()) print(u'-' * 40, file=fp) print( u"Error in processing of request from %s" % repr(client_address), file=fp) diff --git a/netlib/tutils.py b/netlib/tutils.py index 452766d62..5f598fa96 100644 --- a/netlib/tutils.py +++ b/netlib/tutils.py @@ -4,7 +4,6 @@ import os import time import shutil from contextlib import contextmanager -import six import sys from netlib import utils, tcp, http @@ -31,20 +30,20 @@ def tmpdir(*args, **kwargs): def _check_exception(expected, actual, exc_tb): - if isinstance(expected, six.string_types): + if isinstance(expected, str): if expected.lower() not in str(actual).lower(): - six.reraise(AssertionError, AssertionError( + raise AssertionError( "Expected %s, but caught %s" % ( repr(expected), repr(actual) ) - ), exc_tb) + ) else: if not isinstance(actual, expected): - six.reraise(AssertionError, AssertionError( + raise AssertionError( "Expected %s, but caught %s %s" % ( expected.__name__, actual.__class__.__name__, repr(actual) ) - ), exc_tb) + ) def raises(expected_exception, obj=None, *args, **kwargs): diff --git a/netlib/version_check.py b/netlib/version_check.py index 63f3e8766..7091146da 100644 --- a/netlib/version_check.py +++ b/netlib/version_check.py @@ -7,7 +7,6 @@ from __future__ import division, absolute_import, print_function import sys import inspect import os.path -import six import OpenSSL @@ -15,7 +14,7 @@ PYOPENSSL_MIN_VERSION = (0, 15) def check_pyopenssl_version(min_version=PYOPENSSL_MIN_VERSION, fp=sys.stderr): - min_version_str = u".".join(six.text_type(x) for x in min_version) + min_version_str = u".".join(str(x) for x in min_version) try: v = tuple(int(x) for x in OpenSSL.__version__.split(".")[:2]) except ValueError: diff --git a/netlib/websockets/frame.py b/netlib/websockets/frame.py index e62d0e879..2b36d461d 100644 --- a/netlib/websockets/frame.py +++ b/netlib/websockets/frame.py @@ -3,8 +3,6 @@ import os import struct import io -import six - from netlib import tcp from netlib import strutils from netlib import utils @@ -129,7 +127,7 @@ class FrameHeader(object): second_byte = utils.setbit(self.length_code, 7, self.mask) - b = six.int2byte(first_byte) + six.int2byte(second_byte) + b = bytes([first_byte, second_byte]) if self.payload_length < 126: pass @@ -148,17 +146,12 @@ class FrameHeader(object): b += self.masking_key return b - if six.PY2: - __str__ = __bytes__ - @classmethod def from_file(cls, fp): """ read a websockets frame header """ - first_byte = six.byte2int(fp.safe_read(1)) - second_byte = six.byte2int(fp.safe_read(1)) - + first_byte, second_byte = fp.safe_read(2) fin = utils.getbit(first_byte, 7) rsv1 = utils.getbit(first_byte, 6) rsv2 = utils.getbit(first_byte, 5) @@ -257,9 +250,6 @@ class Frame(object): b += self.payload return b - if six.PY2: - __str__ = __bytes__ - @classmethod def from_file(cls, fp): """ diff --git a/netlib/websockets/masker.py b/netlib/websockets/masker.py index bd39ed6a9..03b8f4353 100644 --- a/netlib/websockets/masker.py +++ b/netlib/websockets/masker.py @@ -1,7 +1,5 @@ from __future__ import absolute_import -import six - class Masker(object): """ @@ -19,10 +17,7 @@ class Masker(object): def mask(self, offset, data): result = bytearray(data) for i in range(len(data)): - if six.PY2: - result[i] ^= ord(self.key[offset % 4]) - else: - result[i] ^= self.key[offset % 4] + result[i] ^= self.key[offset % 4] offset += 1 result = bytes(result) return result diff --git a/netlib/wsgi.py b/netlib/wsgi.py index 0def75b58..17cbbf00e 100644 --- a/netlib/wsgi.py +++ b/netlib/wsgi.py @@ -2,9 +2,8 @@ from __future__ import (absolute_import, print_function, division) import time import traceback -import six -from io import BytesIO -from six.moves import urllib +import urllib +import io from netlib import http, tcp, strutils @@ -67,7 +66,7 @@ class WSGIAdaptor(object): environ = { 'wsgi.version': (1, 0), 'wsgi.url_scheme': strutils.native(flow.request.scheme, "latin-1"), - 'wsgi.input': BytesIO(flow.request.content or b""), + 'wsgi.input': io.BytesIO(flow.request.content or b""), 'wsgi.errors': errsoc, 'wsgi.multithread': True, 'wsgi.multiprocess': False, @@ -139,7 +138,7 @@ class WSGIAdaptor(object): def start_response(status, headers, exc_info=None): if exc_info: if state["headers_sent"]: - six.reraise(*exc_info) + raise exc_info[1] elif state["status"]: raise AssertionError('Response already started') state["status"] = status @@ -148,7 +147,7 @@ class WSGIAdaptor(object): self.error_page(soc, state["headers_sent"], traceback.format_tb(exc_info[2])) state["headers_sent"] = True - errs = six.BytesIO() + errs = io.BytesIO() try: dataiter = self.app( self.make_environ(request, errs, **env), start_response diff --git a/pathod/language/base.py b/pathod/language/base.py index 391558589..3446f74c1 100644 --- a/pathod/language/base.py +++ b/pathod/language/base.py @@ -3,7 +3,6 @@ import os import abc import pyparsing as pp -import six from six.moves import reduce from netlib import strutils from netlib import human @@ -342,7 +341,7 @@ class OptionsOrValue(_Component): # it to be canonical. The user can specify a different case by using a # string value literal. self.option_used = False - if isinstance(value, six.string_types): + if isinstance(value, str): for i in self.options: # Find the exact option value in a case-insensitive way if i.lower() == value.lower(): diff --git a/pathod/pathoc.py b/pathod/pathoc.py index e2627a613..59ae5fba8 100644 --- a/pathod/pathoc.py +++ b/pathod/pathoc.py @@ -461,7 +461,7 @@ class Pathoc(tcp.TCPClient): May raise a exceptions.NetlibException """ - if isinstance(r, six.string_types): + if isinstance(r, str): r = next(language.parse_pathoc(r, self.use_http2)) if isinstance(r, language.http.Request): diff --git a/setup.py b/setup.py index abc80b335..0c359f1c7 100644 --- a/setup.py +++ b/setup.py @@ -30,8 +30,6 @@ setup( "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: Implementation :: CPython", @@ -93,13 +91,6 @@ setup( ], ':sys_platform != "win32"': [ ], - # Do not use a range operator here: https://bitbucket.org/pypa/setuptools/issues/380 - # Ubuntu Trusty and other still ship with setuptools < 17.1 - ':python_version == "2.7"': [ - "enum34>=1.0.4, <2", - "ipaddress>=1.0.15, <1.1", - "typing==3.5.2.2", - ], 'dev': [ "tox>=2.3, <3", "mock>=2.0, <2.1", diff --git a/tox.ini b/tox.ini index f41ebfbd9..8747d2f0c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27, py35, docs, lint +envlist = py35, docs, lint skipsdist = True toxworkdir={env:TOX_WORK_DIR:.tox}