Skip to content

Commit 0f19202

Browse files
authored
Python 2 support.
Python 2 is dead, long live Python 2! Maintained by @Alexander255.
2 parents b139b77 + 5e0fba3 commit 0f19202

File tree

12 files changed

+85
-32
lines changed

12 files changed

+85
-32
lines changed

.travis.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
sudo: false
12
language: python
23
matrix:
34
include:
5+
- python: 2.7
6+
env: TOXENV=py27
47
- python: 3.4
58
env: TOXENV=py34
69
- python: 3.5
@@ -10,6 +13,11 @@ matrix:
1013
- python: 3.7
1114
env: TOXENV=py37
1215
dist: xenial
16+
- python: pypy3.5
17+
env: TOXENV=pypy3
18+
allow_failures:
19+
- python: 2.7
20+
env: TOXENV=py27
1321

1422
install:
1523
- pip install tox

CONTRIBUTING.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Before you submit a pull request, check that it meets these guidelines:
101101
2. If the pull request adds functionality, the docs should be updated. Put
102102
your new functionality into a function with a docstring, and add the
103103
feature to the list in README.rst.
104-
3. The pull request should work for Python 3.4+ and PyPy. Check
104+
3. The pull request should work for Python 2.7, 3.4+ and PyPy3. Check
105105
https://travis-ci.org/multiformats/py-multiaddr/pull_requests
106106
and make sure that the tests pass for all supported Python versions.
107107

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ lint:
5252
flake8 multiaddr/* tests/*
5353

5454
test:
55-
TOXENV=py37 tox
55+
TOXENV=py27 tox
5656

5757
test-all:
5858
tox

docs/conf.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
master_doc = 'index'
5656

5757
# General information about the project.
58-
project = 'Multiaddr'
59-
copyright = '2016, Steven Buss'
58+
project = u'Multiaddr'
59+
copyright = u'2016, Steven Buss'
6060

6161
# The version info for the project you're documenting, acts as replacement
6262
# for |version| and |release|, also used in various other places throughout
@@ -209,8 +209,8 @@
209209
# [howto/manual]).
210210
latex_documents = [
211211
('index', 'multiaddr.tex',
212-
'Multiaddr Documentation',
213-
'Steven Buss', 'manual'),
212+
u'Multiaddr Documentation',
213+
u'Steven Buss', 'manual'),
214214
]
215215

216216
# The name of an image file (relative to this directory) to place at
@@ -240,8 +240,8 @@
240240
# (source start file, name, description, authors, manual section).
241241
man_pages = [
242242
('index', 'multiaddr',
243-
'Multiaddr Documentation',
244-
['Steven Buss'], 1)
243+
u'Multiaddr Documentation',
244+
[u'Steven Buss'], 1)
245245
]
246246

247247
# If true, show URL addresses after external links.
@@ -255,8 +255,8 @@
255255
# dir menu entry, description, category)
256256
texinfo_documents = [
257257
('index', 'multiaddr',
258-
'Multiaddr Documentation',
259-
'Steven Buss',
258+
u'Multiaddr Documentation',
259+
u'Steven Buss',
260260
'multiaddr',
261261
'One line description of project.',
262262
'Miscellaneous'),

multiaddr/codec.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import idna
77
from netaddr import IPAddress
8+
import six
89

910
from .protocols import code_to_varint
1011
from .protocols import P_DNS
@@ -24,6 +25,23 @@
2425
from .protocols import read_varint_code
2526

2627

28+
if hasattr(os, "fsencode") and hasattr(os, "fsdecode"):
29+
fsencode = os.fsencode
30+
fsdecode = os.fsdecode
31+
else: # PY2
32+
import sys
33+
34+
def fsencode(path):
35+
if not isinstance(path, six.binary_type):
36+
path = path.encode(sys.getfilesystemencoding())
37+
return path
38+
39+
def fsdecode(path):
40+
if not isinstance(path, six.text_type):
41+
path = path.decode(sys.getfilesystemencoding())
42+
return path
43+
44+
2745
def string_to_bytes(string):
2846
if not string:
2947
return b''
@@ -150,6 +168,8 @@ def address_string_to_bytes(proto, addr_string):
150168
elif proto.code == P_P2P: # ipfs
151169
# the address is a varint prefixed multihash string representation
152170
try:
171+
if six.PY2 and isinstance(addr_string, unicode):
172+
addr_string = addr_string.encode("ascii")
153173
mm = base58.b58decode(addr_string)
154174
except Exception as ex:
155175
raise ValueError("failed to parse p2p addr: %s %s"
@@ -161,7 +181,7 @@ def address_string_to_bytes(proto, addr_string):
161181
raise ValueError("invalid P2P multihash: %s" % mm)
162182
return b''.join([size, mm])
163183
elif proto.code == P_UNIX:
164-
addr_string_bytes = os.fsencode(addr_string)
184+
addr_string_bytes = fsencode(addr_string)
165185
size = code_to_varint(len(addr_string_bytes))
166186
return b''.join([size, binascii.hexlify(addr_string_bytes)])
167187
elif proto.code in (P_DNS, P_DNS4, P_DNS6):
@@ -201,7 +221,7 @@ def address_bytes_to_string(proto, buf):
201221
elif proto.code == P_UNIX:
202222
buf = binascii.unhexlify(buf)
203223
size, num_bytes_read = read_varint_code(buf)
204-
return os.fsdecode(buf[num_bytes_read:])
224+
return fsdecode(buf[num_bytes_read:])
205225
elif proto.code in (P_DNS, P_DNS4, P_DNS6):
206226
buf = binascii.unhexlify(buf)
207227
size, num_bytes_read = read_varint_code(buf)

multiaddr/multiaddr.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import binascii
33
from copy import copy
44

5+
import six
6+
57
from .codec import size_for_addr
68
from .codec import string_to_bytes
79
from .codec import bytes_to_string
@@ -13,7 +15,7 @@ class ProtocolNotFoundException(Exception):
1315
pass
1416

1517

16-
class Multiaddr:
18+
class Multiaddr(object):
1719
"""Multiaddr is a representation of multiple nested internet addresses.
1820
1921
Multiaddr is a cross-protocol, cross-platform format for representing
@@ -37,9 +39,16 @@ def __init__(self, addr):
3739
addr : A string-encoded or a byte-encoded Multiaddr
3840
3941
"""
40-
if isinstance(addr, str):
42+
# On Python 2 text string will often be binary anyways so detect the
43+
# obvious case of a “binary-encoded” multiaddr starting with a slash
44+
# and decode it into text
45+
if six.PY2 and isinstance(addr, str) and addr.startswith("/"):
46+
import locale
47+
addr = addr.decode(locale.getpreferredencoding())
48+
49+
if isinstance(addr, six.text_type):
4150
self._bytes = string_to_bytes(addr)
42-
elif isinstance(addr, bytes):
51+
elif isinstance(addr, six.binary_type):
4352
self._bytes = addr
4453
else:
4554
raise ValueError("Invalid address type, must be bytes or str")
@@ -62,6 +71,16 @@ def __str__(self):
6271
raise ValueError(
6372
"multiaddr failed to convert back to string. corrupted?")
6473

74+
# On Python 2 __str__ needs to return binary text, so expose the original
75+
# function as __unicode__ and transparently encode its returned text based
76+
# on the current locale
77+
if six.PY2:
78+
__unicode__ = __str__
79+
80+
def __str__(self):
81+
import locale
82+
return self.__unicode__().encode(locale.getpreferredencoding())
83+
6584
def __repr__(self):
6685
return "<Multiaddr %s>" % str(self)
6786

multiaddr/protocols.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
LENGTH_PREFIXED_VAR_SIZE = -1
6868

6969

70-
class Protocol:
70+
class Protocol(object):
7171
__slots__ = [
7272
"code", # int
7373
"size", # int (-1 indicates a length-prefixed variable size)
@@ -77,13 +77,13 @@ class Protocol:
7777
]
7878

7979
def __init__(self, code, size, name, vcode, path=False):
80-
if not isinstance(code, int):
80+
if not isinstance(code, six.integer_types):
8181
raise ValueError("code must be an integer")
82-
if not isinstance(size, int):
82+
if not isinstance(size, six.integer_types):
8383
raise ValueError("size must be an integer")
84-
if not isinstance(name, str):
84+
if not isinstance(name, six.string_types):
8585
raise ValueError("name must be a string")
86-
if not isinstance(vcode, bytes):
86+
if not isinstance(vcode, six.binary_type):
8787
raise ValueError("vcode must be binary")
8888
if not isinstance(path, bool):
8989
raise ValueError("path must be a boolean")
@@ -179,8 +179,8 @@ def read_varint_code(buf):
179179
Protocol(P_UNIX, LENGTH_PREFIXED_VAR_SIZE, 'unix', code_to_varint(P_UNIX), path=True),
180180
]
181181

182-
_names_to_protocols = {proto.name: proto for proto in PROTOCOLS}
183-
_codes_to_protocols = {proto.code: proto for proto in PROTOCOLS}
182+
_names_to_protocols = dict((proto.name, proto) for proto in PROTOCOLS)
183+
_codes_to_protocols = dict((proto.code, proto) for proto in PROTOCOLS)
184184

185185

186186
def add_protocol(proto):

setup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,20 @@
3636
license='MIT License',
3737
zip_safe=False,
3838
keywords='multiaddr',
39-
python_requires='>=3.4',
39+
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
4040
classifiers=[
4141
'Development Status :: 2 - Pre-Alpha',
4242
'Intended Audience :: Developers',
4343
'License :: OSI Approved :: MIT License',
4444
'Natural Language :: English',
45+
'Programming Language :: Python :: 2',
46+
'Programming Language :: Python :: 2.7',
4547
'Programming Language :: Python :: 3',
48+
'Programming Language :: Python :: 3.3',
4649
'Programming Language :: Python :: 3.4',
4750
'Programming Language :: Python :: 3.5',
4851
'Programming Language :: Python :: 3.6',
4952
'Programming Language :: Python :: 3.7',
50-
'Programming Language :: Python :: 3 :: Only',
5153
],
5254
setup_requires=[
5355
'pytest-runner',

tests/test_codec.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- encoding: utf-8 -*-
12
import pytest
23

34
from multiaddr.codec import address_bytes_to_string
@@ -27,10 +28,10 @@
2728
# Additional test data
2829
(_names_to_protocols['dns4'],
2930
b'30786e2d2d34676272696d2e786e2d2d2d2d796d63626161616a6c6336646a3762786e6532632e786e2d2d776762683163',
30-
u'موقع.وزارة-الاتصالات.مصر'), # Explicietly mark as unicode to force it LTR
31+
u'موقع.وزارة-الاتصالات.مصر'), # Explicietly mark this as unicode to force the text to be LTR in editors
3132
(_names_to_protocols['dns4'],
3233
b'16786e2d2d667562616c6c2d6374612e6578616d706c65',
33-
'fußball.example'), # This will fail if IDNA-2003/NamePrep is used
34+
u'fußball.example'), # This will fail if IDNA-2003/NamePrep is used
3435
]
3536

3637
BYTES_MAP_STR_TEST_DATA = [

tests/test_multiaddr.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
3+
from __future__ import unicode_literals
4+
35
import pytest
6+
import six
47

58
from multiaddr.multiaddr import Multiaddr
69
from multiaddr.multiaddr import ProtocolNotFoundException
@@ -89,7 +92,7 @@ def test_invalid(addr_str):
8992
"/dns4/موقع.وزارة-الاتصالات.مصر"]) # nopep8
9093
def test_valid(addr_str):
9194
ma = Multiaddr(addr_str)
92-
assert str(ma) == addr_str.rstrip("/")
95+
assert six.text_type(ma) == addr_str.rstrip("/")
9396

9497

9598
def test_eq():
@@ -250,7 +253,7 @@ def test_get_value_too_many_fields_protocol(monkeypatch):
250253
that the constructor specifies is ignored by the test.
251254
"""
252255
monkeypatch.setattr("multiaddr.multiaddr.Multiaddr.__str__",
253-
lambda ignore: '/udp/1234/5678')
256+
lambda ignore: str('/udp/1234/5678'))
254257
a = Multiaddr("/ip4/127.0.0.1/udp/1234")
255258
with pytest.raises(ValueError):
256259
a.value_for_protocol(P_UDP)

0 commit comments

Comments
 (0)