Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/rfc3986/iri.py: 44%

50 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:04 +0000

1"""Module containing the implementation of the IRIReference class.""" 

2# Copyright (c) 2014 Rackspace 

3# Copyright (c) 2015 Ian Stapleton Cordasco 

4# Licensed under the Apache License, Version 2.0 (the "License"); 

5# you may not use this file except in compliance with the License. 

6# You may obtain a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 

13# implied. 

14# See the License for the specific language governing permissions and 

15# limitations under the License. 

16from collections import namedtuple 

17 

18from . import compat 

19from . import exceptions 

20from . import misc 

21from . import normalizers 

22from . import uri 

23 

24 

25try: 

26 import idna 

27except ImportError: # pragma: no cover 

28 idna = None 

29 

30 

31class IRIReference( 

32 namedtuple("IRIReference", misc.URI_COMPONENTS), uri.URIMixin 

33): 

34 """Immutable object representing a parsed IRI Reference. 

35 

36 Can be encoded into an URIReference object via the procedure 

37 specified in RFC 3987 Section 3.1 

38 

39 .. note:: 

40 The IRI submodule is a new interface and may possibly change in 

41 the future. Check for changes to the interface when upgrading. 

42 """ 

43 

44 slots = () 

45 

46 def __new__( 

47 cls, scheme, authority, path, query, fragment, encoding="utf-8" 

48 ): 

49 """Create a new IRIReference.""" 

50 ref = super().__new__( 

51 cls, 

52 scheme or None, 

53 authority or None, 

54 path or None, 

55 query, 

56 fragment, 

57 ) 

58 ref.encoding = encoding 

59 return ref 

60 

61 def __eq__(self, other): 

62 """Compare this reference to another.""" 

63 other_ref = other 

64 if isinstance(other, tuple): 

65 other_ref = self.__class__(*other) 

66 elif not isinstance(other, IRIReference): 

67 try: 

68 other_ref = self.__class__.from_string(other) 

69 except TypeError: 

70 raise TypeError( 

71 "Unable to compare {}() to {}()".format( 

72 type(self).__name__, type(other).__name__ 

73 ) 

74 ) 

75 

76 # See http://tools.ietf.org/html/rfc3986#section-6.2 

77 return tuple(self) == tuple(other_ref) 

78 

79 def _match_subauthority(self): 

80 return misc.ISUBAUTHORITY_MATCHER.match(self.authority) 

81 

82 @classmethod 

83 def from_string(cls, iri_string, encoding="utf-8"): 

84 """Parse a IRI reference from the given unicode IRI string. 

85 

86 :param str iri_string: Unicode IRI to be parsed into a reference. 

87 :param str encoding: The encoding of the string provided 

88 :returns: :class:`IRIReference` or subclass thereof 

89 """ 

90 iri_string = compat.to_str(iri_string, encoding) 

91 

92 split_iri = misc.IRI_MATCHER.match(iri_string).groupdict() 

93 return cls( 

94 split_iri["scheme"], 

95 split_iri["authority"], 

96 normalizers.encode_component(split_iri["path"], encoding), 

97 normalizers.encode_component(split_iri["query"], encoding), 

98 normalizers.encode_component(split_iri["fragment"], encoding), 

99 encoding, 

100 ) 

101 

102 def encode(self, idna_encoder=None): # noqa: C901 

103 """Encode an IRIReference into a URIReference instance. 

104 

105 If the ``idna`` module is installed or the ``rfc3986[idna]`` 

106 extra is used then unicode characters in the IRI host 

107 component will be encoded with IDNA2008. 

108 

109 :param idna_encoder: 

110 Function that encodes each part of the host component 

111 If not given will raise an exception if the IRI 

112 contains a host component. 

113 :rtype: uri.URIReference 

114 :returns: A URI reference 

115 """ 

116 authority = self.authority 

117 if authority: 

118 if idna_encoder is None: 

119 if idna is None: # pragma: no cover 

120 raise exceptions.MissingDependencyError( 

121 "Could not import the 'idna' module " 

122 "and the IRI hostname requires encoding" 

123 ) 

124 

125 def idna_encoder(name): 

126 if any(ord(c) > 128 for c in name): 

127 try: 

128 return idna.encode( 

129 name.lower(), strict=True, std3_rules=True 

130 ) 

131 except idna.IDNAError: 

132 raise exceptions.InvalidAuthority(self.authority) 

133 return name 

134 

135 authority = "" 

136 if self.host: 

137 authority = ".".join( 

138 [ 

139 compat.to_str(idna_encoder(part)) 

140 for part in self.host.split(".") 

141 ] 

142 ) 

143 

144 if self.userinfo is not None: 

145 authority = ( 

146 normalizers.encode_component(self.userinfo, self.encoding) 

147 + "@" 

148 + authority 

149 ) 

150 

151 if self.port is not None: 

152 authority += ":" + str(self.port) 

153 

154 return uri.URIReference( 

155 self.scheme, 

156 authority, 

157 path=self.path, 

158 query=self.query, 

159 fragment=self.fragment, 

160 encoding=self.encoding, 

161 )