Skip to content

Commit e3daea0

Browse files
committed
Drop six and any remaining mentions of Python 2
1 parent 1140b5a commit e3daea0

12 files changed

+37
-73
lines changed

docs/releasing.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ All of this has only been tested on Debian 11 (Linux).
77

88
## Building and updating the project
99

10-
### Python 3 with the `flit` project manager
10+
### The `flit` project manager
1111

1212
APT line: `sudo apt install python3-pip && sudo pip3 install flit`
1313
DNF line: `sudo dnf install python3-flit`

ipfshttpclient/client/base.py

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import functools
22

3-
import six
4-
53
from . import DEFAULT_ADDR, DEFAULT_BASE
64

75
from .. import multipart, http

ipfshttpclient/encoding.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
import codecs
1111
import json
1212

13-
import six
14-
1513
from . import exceptions
1614

1715

@@ -123,7 +121,7 @@ def encode(self, obj):
123121
-------
124122
bytes
125123
"""
126-
return six.b(str(obj))
124+
return str(obj).encode()
127125

128126

129127
class Json(Encoding):
@@ -149,7 +147,7 @@ def parse_partial(self, data):
149147
generator
150148
"""
151149
try:
152-
# Python 3 requires all JSON data to be a text string
150+
# Python requires all JSON data to text strings
153151
lines = self._decoder1.decode(data, False).split("\n")
154152

155153
# Add first input line to last buffer line, if applicable, to

ipfshttpclient/http.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66

77
import abc
88
import functools
9+
import http.client
910
import tarfile
10-
from six.moves import http_client
1111
import os
1212
import socket
1313
import urllib.parse
1414

1515
import multiaddr
1616
from multiaddr.protocols import (P_DNS, P_DNS4, P_DNS6, P_HTTP, P_HTTPS, P_IP4, P_IP6, P_TCP)
17-
import six
1817

1918
from . import encoding
2019
from . import exceptions
@@ -248,7 +247,7 @@ def _do_request(self, *args, **kwargs):
248247
raise exceptions.TimeoutError(error) from error
249248
except requests.ConnectionError as error:
250249
raise exceptions.ConnectionError(error) from error
251-
except http_client.HTTPException as error:
250+
except http.client.HTTPException as error:
252251
raise exceptions.ProtocolError(error) from error
253252

254253
def _do_raise_for_status(self, response):

ipfshttpclient/multipart.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55
import inspect
66
import os
77
import re
8-
from six.moves import urllib
8+
import urllib.parse
99
import uuid
1010

11-
import six
12-
1311
from . import utils
1412

1513

@@ -34,7 +32,7 @@ def content_disposition_headers(filename, disptype="form-data"):
3432
disptype : str
3533
Rhe disposition type to use for the file
3634
"""
37-
disp = '{}; filename="{}"'.format(
35+
disp = '{0}; filename="{1}"'.format(
3836
disptype,
3937
urllib.parse.quote(filename, safe='')
4038
)
@@ -604,8 +602,8 @@ def stream_directory_impl(directory, dirname=None):
604602
dirname=dirname, chunk_size=chunk_size)
605603
return stream.body(), stream.headers()
606604

607-
# Note that `os.fwalk` is never available on Windows and Python 2
608-
if hasattr(os, "fwalk") and not isinstance(directory, int): #PY3
605+
# Note that `os.fwalk` is never available on Windows
606+
if hasattr(os, "fwalk") and not isinstance(directory, int):
609607
def auto_close_iter_fd(fd, iter):
610608
try:
611609
yield from iter

ipfshttpclient/utils.py

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import collections.abc
66
import mimetypes
77
import os
8-
import six
98
from functools import wraps
109

1110

pyproject.toml

+3-7
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ keywords = "ipfs storage distribution development"
1212
license = "MIT License"
1313
description-file = "README.md"
1414

15-
requires-python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
15+
requires-python = ">=3.5"
1616
requires = [
1717
"multiaddr (>=0.0.7)",
18-
"requests (>=2.11)",
19-
"six"
18+
"requests (>=2.11)"
2019
]
2120

2221
classifiers = [
@@ -37,10 +36,7 @@ classifiers = [
3736

3837
# Specify the Python versions you support here. In particular, ensure
3938
# that you indicate whether you support Python 2, Python 3 or both.
40-
"Programming Language :: Python :: 2",
41-
"Programming Language :: Python :: 2.7",
42-
"Programming Language :: Python :: 3",
43-
"Programming Language :: Python :: 3.4",
39+
"Programming Language :: Python :: 3 :: Only",
4440
"Programming Language :: Python :: 3.5",
4541
"Programming Language :: Python :: 3.6",
4642
"Programming Language :: Python :: 3.7",

test/functional/test_block.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
try:
2-
import cid
3-
except ImportError:
4-
cid = None
1+
import cid
52
import io
63
import pytest
74

@@ -48,7 +45,6 @@ def test_put_str(client):
4845
assert res["Key"] == TEST2_CID_STR
4946

5047

51-
@pytest.mark.skipif(not cid, reason="requires py-cid (Python 3.5+ only)")
5248
@pytest.mark.run(after="test_put_str")
5349
def test_stat_cid_obj(client):
5450
assert len(client.block.get(TEST2_CID_OBJ)) == TEST2_SIZE

test/functional/test_files.py

+2-10
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
import shutil
33

44
import pytest
5-
try:
6-
import pytest_cid
7-
except ImportError:
8-
pytest_cid = None
5+
import pytest_cid
96

107
import ipfshttpclient.exceptions
118

@@ -112,14 +109,13 @@
112109

113110

114111
def calc_path_rel_to_cwd(p):
115-
p = str(p) # for Python < 3.5
112+
p = str(p) # PY35
116113
prefix = os.path.commonprefix([p, os.getcwd()])
117114
relpath = os.path.relpath(p, prefix)
118115
assert not os.path.isabs(relpath)
119116
return relpath
120117

121118

122-
@pytest.mark.skipif(not pytest_cid, reason="requires pytest-cid (Python 3.5+ only)")
123119
def test_add_single_from_str_with_dir(client, cleanup_pins):
124120
res = client.add(FAKE_FILE1_PATH, wrap_with_directory=True)
125121

@@ -132,7 +128,6 @@ def test_add_single_from_str_with_dir(client, cleanup_pins):
132128
assert dir_hash in client.pin.ls(type="recursive")["Keys"]
133129

134130

135-
@pytest.mark.skipif(not pytest_cid, reason="requires pytest-cid (Python 3.5+ only)")
136131
def test_only_hash_file(client):
137132
client.repo.gc()
138133

@@ -144,13 +139,11 @@ def test_only_hash_file(client):
144139
assert res["Hash"] not in list(map(lambda i: i["Ref"], client.unstable.refs.local()))
145140

146141

147-
@pytest.mark.skipif(not pytest_cid, reason="requires pytest-cid (Python 3.5+ only)")
148142
def test_add_multiple_from_list(client, cleanup_pins):
149143
res = client.add(FAKE_FILE1_PATH, FAKE_FILE2_PATH)
150144
assert pytest_cid.match(FAKE_FILES_HASH) == res
151145

152146

153-
@pytest.mark.skipif(not pytest_cid, reason="requires pytest-cid (Python 3.5+ only)")
154147
def test_add_with_raw_leaves(client, cleanup_pins):
155148
res = client.add(FAKE_FILE1_PATH, raw_leaves=True)
156149
check_add_with_raw_leaves(client, res)
@@ -188,7 +181,6 @@ def check_no_copy(client, res):
188181
# TODO: assert client.filestore.verify(res["Hash"])["Status"] == 0
189182

190183

191-
@pytest.mark.skipif(not pytest_cid, reason="requires pytest-cid (Python 3.5+ only)")
192184
def test_add_relative_path(client, cleanup_pins):
193185
res = client.add(calc_path_rel_to_cwd(FAKE_FILE1_PATH))
194186
assert pytest_cid.match(FAKE_FILE1_HASH) == res

test/unit/test_encoding.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import json
33

44
import pytest
5-
import six
65

76
import ipfshttpclient.encoding
87
import ipfshttpclient.exceptions
@@ -17,7 +16,7 @@ def json_encoder():
1716
def test_json_parse(json_encoder):
1817
"""Asserts parsed key/value json matches expected output."""
1918
data = {'key': 'value'}
20-
raw = six.b(json.dumps(data))
19+
raw = json.dumps(data).encode("utf-8")
2120
res = json_encoder.parse(raw)
2221
assert res['key'] == 'value'
2322

@@ -28,13 +27,13 @@ def test_json_parse_partial(json_encoder):
2827
data2 = {'key2': 'value2'}
2928

3029
# Try single fragmented data set
31-
data1_binary = six.b(json.dumps(data1))
30+
data1_binary = json.dumps(data1).encode("utf-8")
3231
assert list(json_encoder.parse_partial(data1_binary[:8])) == []
3332
assert list(json_encoder.parse_partial(data1_binary[8:])) == [data1]
3433
assert list(json_encoder.parse_finalize()) == []
3534

3635
# Try multiple data sets contained in whitespace
37-
data2_binary = six.b(json.dumps(data2))
36+
data2_binary = json.dumps(data2).encode("utf-8")
3837
data2_final = b" " + data1_binary + b" \r\n " + data2_binary + b" "
3938
assert list(json_encoder.parse_partial(data2_final)) == [data1, data2]
4039
assert list(json_encoder.parse_finalize()) == []
@@ -52,8 +51,8 @@ def test_json_with_newlines(json_encoder):
5251

5352
data_expected = json.loads(data1 + data2)
5453

55-
assert list(json_encoder.parse_partial(six.b(data1))) == []
56-
assert list(json_encoder.parse_partial(six.b(data2))) == [data_expected]
54+
assert list(json_encoder.parse_partial(data1.encode("utf-8"))) == []
55+
assert list(json_encoder.parse_partial(data2.encode("utf-8"))) == [data_expected]
5756
assert list(json_encoder.parse_finalize()) == []
5857

5958

@@ -73,7 +72,8 @@ def test_json_parse_chained(json_encoder):
7372
data1 = {'key1': 'value1'}
7473
data2 = {'key2': 'value2'}
7574
res = json_encoder.parse(
76-
six.b(json.dumps(data1)) + six.b(json.dumps(data2)))
75+
json.dumps(data1).encode("utf-8") + json.dumps(data2).encode("utf-8")
76+
)
7777
assert len(res) == 2
7878
assert res[0]['key1'] == 'value1'
7979
assert res[1]['key2'] == 'value2'
@@ -84,7 +84,8 @@ def test_json_parse_chained_newlines(json_encoder):
8484
data1 = {'key1': 'value1'}
8585
data2 = {'key2': 'value2'}
8686
res = json_encoder.parse(
87-
six.b(json.dumps(data1)) + b'\n' + six.b(json.dumps(data2)))
87+
json.dumps(data1).encode("utf-8") + b'\n' + json.dumps(data2).encode("utf-8")
88+
)
8889
assert len(res) == 2
8990
assert res[0]['key1'] == 'value1'
9091
assert res[1]['key2'] == 'value2'

test/unit/test_multipart.py

+12-21
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,12 @@
1414
import os
1515
import re
1616
import unittest
17-
import urllib
17+
import urllib.parse
1818

1919
import pytest
20-
import six
21-
22-
from six.moves import urllib_parse
2320

2421
import ipfshttpclient.multipart
2522

26-
ENC = "UTF-8"
27-
2823
class TestContentHelpers(unittest.TestCase):
2924
"""Tests the functionality of the three content-oriented helper functions.
3025
@@ -203,9 +198,9 @@ def do_test__gen_file(self, name, file_location, abspath):
203198
file.seek(0)
204199

205200
expected = b'--' + generator._boundary.encode() + b'\r\n'
206-
expected += b'Abspath: ' + name.encode(ENC) + b'\r\n' if abspath else b''
201+
expected += b'Abspath: ' + name.encode("utf-8") + b'\r\n' if abspath else b''
207202
expected += b'Content-Disposition: file; '\
208-
+ b'filename="' + urllib_parse.quote_plus(name).encode(ENC) + b'"\r\n'\
203+
+ b'filename="' + urllib.parse.quote_plus(name).encode("utf-8") + b'"\r\n'\
209204
+ b'Content-Type: text/plain\r\n'\
210205
+ b'\r\n' \
211206
+ b'!234\r\n'
@@ -229,8 +224,8 @@ def do_test__gen_file_start(self, name, file_location, abspath):
229224
generator = StreamFileMixinSub(name)
230225

231226
expected = b'--' + generator._boundary.encode() + b'\r\n'
232-
expected += b'Abspath: ' + file_location.encode(ENC) + b'\r\n' if abspath else b''
233-
expected += b'Content-Disposition: file; filename="' + name.encode(ENC) + b'"\r\n'\
227+
expected += b'Abspath: ' + file_location.encode("utf-8") + b'\r\n' if abspath else b''
228+
expected += b'Content-Disposition: file; filename="' + name.encode("utf-8") + b'"\r\n'\
234229
+ b'Content-Type: application/octet-stream\r\n'\
235230
+ b'\r\n'
236231

@@ -314,18 +309,14 @@ def test_body_relative(self):
314309
self.check_test_body(instance, abspath=False)
315310

316311
def check_test_body(self, instance, abspath):
317-
expected = r"(--\S+\r\n"
318-
expected += r"Abspath: \S+\r\n" if abspath else r""
319-
expected += r"Content-Disposition: file; filename=\"\S+\"\r\n"
320-
expected += r"Content-Type: application/\S+\r\n"
321-
expected += r"\r\n(.|\n)*\r\n)+--\S+--\r\n"
322-
actual = ""
312+
expected = rb"(--\S+\r\n"
313+
expected += rb"Abspath: \S+\r\n" if abspath else rb""
314+
expected += rb"Content-Disposition: file; filename=\"\S+\"\r\n"
315+
expected += rb"Content-Type: application/\S+\r\n"
316+
expected += rb"\r\n(.|\n)*\r\n)+--\S+--\r\n"
317+
actual = b""
323318
for i in instance.body():
324-
if type(i) is not str and type(i) is not memoryview:
325-
i = i.decode()
326-
elif six.PY3 and type(i) is memoryview:
327-
i = i.tobytes().decode()
328-
actual += i
319+
actual += bytes(i)
329320
assert re.search(expected, actual)
330321

331322

test/unit/test_utils.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import sys
1010
import unittest
1111

12-
import six
13-
1412
import ipfshttpclient.utils as utils
1513

1614
class TestUtils(unittest.TestCase):
@@ -66,9 +64,7 @@ def test_clean_file_unopened_binarypath(self):
6664
This test relies on the openability of the file 'fsdfgh'
6765
located in 'test/functional/fake_dir'.
6866
"""
69-
path = os.path.dirname(__file__)
70-
if isinstance(path, str): #PY3
71-
path = path.encode(sys.getfilesystemencoding())
67+
path = os.fsencode(os.path.dirname(__file__))
7268
path = os.path.join(path, b"..", b"functional", b"fake_dir", b"fsdfgh")
7369
f, opened = utils.clean_file(path)
7470
assert hasattr(f, 'read')

0 commit comments

Comments
 (0)