1
1
# -*- coding: utf-8 -*-
2
+ try :
3
+ import collections .abc
4
+ except ImportError : # pragma: no cover (PY2)
5
+ import collections
6
+ collections .abc = collections
2
7
from copy import copy
3
8
4
9
import six
10
15
from .transforms import bytes_to_string
11
16
12
17
13
- class Multiaddr (object ):
18
+ __all__ = ("Multiaddr" ,)
19
+
20
+
21
+
22
+ class MultiAddrKeys (collections .abc .KeysView , collections .abc .Sequence ):
23
+ def __contains__ (self , proto ):
24
+ proto = protocols .protocol_with_any (proto )
25
+ return collections .abc .Sequence .__contains__ (self , proto )
26
+
27
+ def __getitem__ (self , idx ):
28
+ if idx < 0 :
29
+ idx = len (self )+ idx
30
+ for idx2 , proto in enumerate (self ):
31
+ if idx2 == idx :
32
+ return proto
33
+ raise IndexError ("Protocol list index out of range" )
34
+
35
+ __hash__ = collections .abc .KeysView ._hash
36
+
37
+ def __iter__ (self ):
38
+ for proto , _ , _ in bytes_iter (self ._mapping .to_bytes ()):
39
+ yield proto
40
+
41
+
42
+ class MultiAddrItems (collections .abc .ItemsView , collections .abc .Sequence ):
43
+ def __contains__ (self , item ):
44
+ proto , value = item
45
+ proto = protocols .protocol_with_any (proto )
46
+ return collections .abc .Sequence .__contains__ (self , (proto , value ))
47
+
48
+ def __getitem__ (self , idx ):
49
+ if idx < 0 :
50
+ idx = len (self )+ idx
51
+ for idx2 , item in enumerate (self ):
52
+ if idx2 == idx :
53
+ return item
54
+ raise IndexError ("Protocol item list index out of range" )
55
+
56
+ def __iter__ (self ):
57
+ for proto , codec , part in bytes_iter (self ._mapping .to_bytes ()):
58
+ if codec .SIZE != 0 :
59
+ try :
60
+ # If we have an address, return it
61
+ yield proto , codec .to_string (proto , part )
62
+ except Exception as exc :
63
+ six .raise_from (exceptions .BinaryParseError (str (exc ), self ._mapping .to_bytes (), proto .name , exc ), exc )
64
+ else :
65
+ # We were given something like '/utp', which doesn't have
66
+ # an address, so return None
67
+ yield proto , None
68
+
69
+
70
+ class MultiAddrValues (collections .abc .ValuesView , collections .abc .Sequence ):
71
+ __contains__ = collections .abc .Sequence .__contains__
72
+
73
+ def __getitem__ (self , idx ):
74
+ if idx < 0 :
75
+ idx = len (self )+ idx
76
+ for idx2 , proto in enumerate (self ):
77
+ if idx2 == idx :
78
+ return proto
79
+ raise IndexError ("Protocol value list index out of range" )
80
+
81
+ def __iter__ (self ):
82
+ for _ , value in MultiAddrItems (self ._mapping ):
83
+ yield value
84
+
85
+
86
+
87
+ class Multiaddr (collections .abc .Mapping ):
14
88
"""Multiaddr is a representation of multiple nested internet addresses.
15
89
16
90
Multiaddr is a cross-protocol, cross-platform format for representing
@@ -53,16 +127,22 @@ def __eq__(self, other):
53
127
"""Checks if two Multiaddr objects are exactly equal."""
54
128
return self ._bytes == other ._bytes
55
129
56
- def __ne__ (self , other ):
57
- return not (self == other )
58
-
59
130
def __str__ (self ):
60
131
"""Return the string representation of this Multiaddr.
61
132
62
133
May raise a :class:`~multiaddr.exceptions.BinaryParseError` if the
63
134
stored MultiAddr binary representation is invalid."""
64
135
return bytes_to_string (self ._bytes )
65
136
137
+ def __contains__ (self , proto ):
138
+ return proto in MultiAddrKeys (self )
139
+
140
+ def __iter__ (self ):
141
+ return iter (MultiAddrKeys (self ))
142
+
143
+ def __len__ (self ):
144
+ return sum ((1 for _ in bytes_iter (self .to_bytes ())))
145
+
66
146
# On Python 2 __str__ needs to return binary text, so expose the original
67
147
# function as __unicode__ and transparently encode its returned text based
68
148
# on the current locale
@@ -82,7 +162,15 @@ def to_bytes(self):
82
162
83
163
def protocols (self ):
84
164
"""Returns a list of Protocols this Multiaddr includes."""
85
- return list (proto for proto , _ , _ in bytes_iter (self .to_bytes ()))
165
+ return MultiAddrKeys (self )
166
+
167
+ keys = protocols
168
+
169
+ def items (self ):
170
+ return MultiAddrItems (self )
171
+
172
+ def values (self ):
173
+ return MultiAddrValues (self )
86
174
87
175
def encapsulate (self , other ):
88
176
"""Wrap this Multiaddr around another.
@@ -125,24 +213,10 @@ def value_for_protocol(self, proto):
125
213
~multiaddr.exceptions.ProtocolLookupError
126
214
MultiAddr does not contain any instance of this protocol
127
215
"""
128
- if not isinstance (proto , protocols .Protocol ):
129
- if isinstance (proto , int ):
130
- proto = protocols .protocol_with_code (proto )
131
- elif isinstance (proto , six .string_types ):
132
- proto = protocols .protocol_with_name (proto )
133
- else :
134
- raise TypeError ("Protocol object, name or code expected, got {0!r}" .format (proto ))
135
-
136
- for proto2 , codec , part in bytes_iter (self .to_bytes ()):
137
- if proto2 == proto :
138
- if codec .SIZE != 0 :
139
- try :
140
- # If we have an address, return it
141
- return codec .to_string (proto2 , part )
142
- except Exception as exc :
143
- six .raise_from (exceptions .BinaryParseError (str (exc ), self .to_bytes (), proto2 .name , exc ), exc )
144
- else :
145
- # We were given something like '/utp', which doesn't have
146
- # an address, so return None
147
- return None
216
+ proto = protocols .protocol_with_any (proto )
217
+ for proto2 , value in self .items ():
218
+ if proto2 is proto or proto2 == proto :
219
+ return value
148
220
raise exceptions .ProtocolLookupError (proto , str (self ))
221
+
222
+ __getitem__ = value_for_protocol
0 commit comments