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.
This commit is contained in:
Aldo Cortesi 2016-10-17 15:15:22 +13:00
parent 4918feb725
commit 8360f70024
31 changed files with 90 additions and 203 deletions

View File

@ -7,8 +7,6 @@ environment:
matrix:
- PYTHON: "C:\\Python35"
TOXENV: "py35"
- PYTHON: "C:\\Python27"
TOXENV: "py27"
SNAPSHOT_HOST:
secure: NeTo57s2rJhCd/mjKHetXVxCFd3uhr8txnjnAXD1tUI=

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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.

View File

@ -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()

View File

@ -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

View File

@ -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.")

View File

@ -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:

View File

@ -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.

View File

@ -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.
"""

View File

@ -3,7 +3,6 @@ import os
import ssl
import time
import datetime
from six.moves import filter
import ipaddress
import sys

View File

@ -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:

View File

@ -3,25 +3,18 @@ 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):
# 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):
def _always_bytes(x):
return strutils.always_bytes(x, "utf-8", "surrogateescape")
@ -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

View File

@ -3,23 +3,16 @@ 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):
# 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):
def _always_bytes(x):
return strutils.always_bytes(x, "utf-8", "surrogateescape")
@ -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:

View File

@ -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

View File

@ -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

View File

@ -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,9 +85,6 @@ 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")
@ -96,9 +92,6 @@ 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')
@ -108,9 +101,6 @@ 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")
@ -122,10 +112,6 @@ 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")
@ -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)

View File

@ -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__))

View File

@ -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,13 +19,9 @@ 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):
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"."),

View File

@ -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,10 +440,6 @@ 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"))
@ -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)

View File

@ -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):

View File

@ -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:

View File

@ -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):
"""

View File

@ -1,7 +1,5 @@
from __future__ import absolute_import
import six
class Masker(object):
"""
@ -19,9 +17,6 @@ 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]
offset += 1
result = bytes(result)

View File

@ -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

View File

@ -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():

View File

@ -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):

View File

@ -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",

View File

@ -1,5 +1,5 @@
[tox]
envlist = py27, py35, docs, lint
envlist = py35, docs, lint
skipsdist = True
toxworkdir={env:TOX_WORK_DIR:.tox}