Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/dns/rrset.py: 46%

78 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-02 06:07 +0000

1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license 

2 

3# Copyright (C) 2003-2017 Nominum, Inc. 

4# 

5# Permission to use, copy, modify, and distribute this software and its 

6# documentation for any purpose with or without fee is hereby granted, 

7# provided that the above copyright notice and this permission notice 

8# appear in all copies. 

9# 

10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 

11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 

12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 

13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 

14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 

15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 

16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

17 

18"""DNS RRsets (an RRset is a named rdataset)""" 

19 

20from typing import Any, Collection, Dict, Optional, Union, cast 

21 

22import dns.name 

23import dns.rdataclass 

24import dns.rdataset 

25import dns.renderer 

26 

27 

28class RRset(dns.rdataset.Rdataset): 

29 

30 """A DNS RRset (named rdataset). 

31 

32 RRset inherits from Rdataset, and RRsets can be treated as 

33 Rdatasets in most cases. There are, however, a few notable 

34 exceptions. RRsets have different to_wire() and to_text() method 

35 arguments, reflecting the fact that RRsets always have an owner 

36 name. 

37 """ 

38 

39 __slots__ = ["name", "deleting"] 

40 

41 def __init__( 

42 self, 

43 name: dns.name.Name, 

44 rdclass: dns.rdataclass.RdataClass, 

45 rdtype: dns.rdatatype.RdataType, 

46 covers: dns.rdatatype.RdataType = dns.rdatatype.NONE, 

47 deleting: Optional[dns.rdataclass.RdataClass] = None, 

48 ): 

49 """Create a new RRset.""" 

50 

51 super().__init__(rdclass, rdtype, covers) 

52 self.name = name 

53 self.deleting = deleting 

54 

55 def _clone(self): 

56 obj = super()._clone() 

57 obj.name = self.name 

58 obj.deleting = self.deleting 

59 return obj 

60 

61 def __repr__(self): 

62 if self.covers == 0: 

63 ctext = "" 

64 else: 

65 ctext = "(" + dns.rdatatype.to_text(self.covers) + ")" 

66 if self.deleting is not None: 

67 dtext = " delete=" + dns.rdataclass.to_text(self.deleting) 

68 else: 

69 dtext = "" 

70 return ( 

71 "<DNS " 

72 + str(self.name) 

73 + " " 

74 + dns.rdataclass.to_text(self.rdclass) 

75 + " " 

76 + dns.rdatatype.to_text(self.rdtype) 

77 + ctext 

78 + dtext 

79 + " RRset: " 

80 + self._rdata_repr() 

81 + ">" 

82 ) 

83 

84 def __str__(self): 

85 return self.to_text() 

86 

87 def __eq__(self, other): 

88 if isinstance(other, RRset): 

89 if self.name != other.name: 

90 return False 

91 elif not isinstance(other, dns.rdataset.Rdataset): 

92 return False 

93 return super().__eq__(other) 

94 

95 def match(self, *args: Any, **kwargs: Any) -> bool: # type: ignore[override] 

96 """Does this rrset match the specified attributes? 

97 

98 Behaves as :py:func:`full_match()` if the first argument is a 

99 ``dns.name.Name``, and as :py:func:`dns.rdataset.Rdataset.match()` 

100 otherwise. 

101 

102 (This behavior fixes a design mistake where the signature of this 

103 method became incompatible with that of its superclass. The fix 

104 makes RRsets matchable as Rdatasets while preserving backwards 

105 compatibility.) 

106 """ 

107 if isinstance(args[0], dns.name.Name): 

108 return self.full_match(*args, **kwargs) # type: ignore[arg-type] 

109 else: 

110 return super().match(*args, **kwargs) # type: ignore[arg-type] 

111 

112 def full_match( 

113 self, 

114 name: dns.name.Name, 

115 rdclass: dns.rdataclass.RdataClass, 

116 rdtype: dns.rdatatype.RdataType, 

117 covers: dns.rdatatype.RdataType, 

118 deleting: Optional[dns.rdataclass.RdataClass] = None, 

119 ) -> bool: 

120 """Returns ``True`` if this rrset matches the specified name, class, 

121 type, covers, and deletion state. 

122 """ 

123 if not super().match(rdclass, rdtype, covers): 

124 return False 

125 if self.name != name or self.deleting != deleting: 

126 return False 

127 return True 

128 

129 # pylint: disable=arguments-differ 

130 

131 def to_text( # type: ignore[override] 

132 self, 

133 origin: Optional[dns.name.Name] = None, 

134 relativize: bool = True, 

135 **kw: Dict[str, Any], 

136 ) -> str: 

137 """Convert the RRset into DNS zone file format. 

138 

139 See ``dns.name.Name.choose_relativity`` for more information 

140 on how *origin* and *relativize* determine the way names 

141 are emitted. 

142 

143 Any additional keyword arguments are passed on to the rdata 

144 ``to_text()`` method. 

145 

146 *origin*, a ``dns.name.Name`` or ``None``, the origin for relative 

147 names. 

148 

149 *relativize*, a ``bool``. If ``True``, names will be relativized 

150 to *origin*. 

151 """ 

152 

153 return super().to_text( 

154 self.name, origin, relativize, self.deleting, **kw # type: ignore 

155 ) 

156 

157 def to_wire( # type: ignore[override] 

158 self, 

159 file: Any, 

160 compress: Optional[dns.name.CompressType] = None, # type: ignore 

161 origin: Optional[dns.name.Name] = None, 

162 **kw: Dict[str, Any], 

163 ) -> int: 

164 """Convert the RRset to wire format. 

165 

166 All keyword arguments are passed to ``dns.rdataset.to_wire()``; see 

167 that function for details. 

168 

169 Returns an ``int``, the number of records emitted. 

170 """ 

171 

172 return super().to_wire( 

173 self.name, file, compress, origin, self.deleting, **kw # type:ignore 

174 ) 

175 

176 # pylint: enable=arguments-differ 

177 

178 def to_rdataset(self) -> dns.rdataset.Rdataset: 

179 """Convert an RRset into an Rdataset. 

180 

181 Returns a ``dns.rdataset.Rdataset``. 

182 """ 

183 return dns.rdataset.from_rdata_list(self.ttl, list(self)) 

184 

185 

186def from_text_list( 

187 name: Union[dns.name.Name, str], 

188 ttl: int, 

189 rdclass: Union[dns.rdataclass.RdataClass, str], 

190 rdtype: Union[dns.rdatatype.RdataType, str], 

191 text_rdatas: Collection[str], 

192 idna_codec: Optional[dns.name.IDNACodec] = None, 

193 origin: Optional[dns.name.Name] = None, 

194 relativize: bool = True, 

195 relativize_to: Optional[dns.name.Name] = None, 

196) -> RRset: 

197 """Create an RRset with the specified name, TTL, class, and type, and with 

198 the specified list of rdatas in text format. 

199 

200 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA 

201 encoder/decoder to use; if ``None``, the default IDNA 2003 

202 encoder/decoder is used. 

203 

204 *origin*, a ``dns.name.Name`` (or ``None``), the 

205 origin to use for relative names. 

206 

207 *relativize*, a ``bool``. If true, name will be relativized. 

208 

209 *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use 

210 when relativizing names. If not set, the *origin* value will be used. 

211 

212 Returns a ``dns.rrset.RRset`` object. 

213 """ 

214 

215 if isinstance(name, str): 

216 name = dns.name.from_text(name, None, idna_codec=idna_codec) 

217 rdclass = dns.rdataclass.RdataClass.make(rdclass) 

218 rdtype = dns.rdatatype.RdataType.make(rdtype) 

219 r = RRset(name, rdclass, rdtype) 

220 r.update_ttl(ttl) 

221 for t in text_rdatas: 

222 rd = dns.rdata.from_text( 

223 r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec 

224 ) 

225 r.add(rd) 

226 return r 

227 

228 

229def from_text( 

230 name: Union[dns.name.Name, str], 

231 ttl: int, 

232 rdclass: Union[dns.rdataclass.RdataClass, str], 

233 rdtype: Union[dns.rdatatype.RdataType, str], 

234 *text_rdatas: Any, 

235) -> RRset: 

236 """Create an RRset with the specified name, TTL, class, and type and with 

237 the specified rdatas in text format. 

238 

239 Returns a ``dns.rrset.RRset`` object. 

240 """ 

241 

242 return from_text_list( 

243 name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas) 

244 ) 

245 

246 

247def from_rdata_list( 

248 name: Union[dns.name.Name, str], 

249 ttl: int, 

250 rdatas: Collection[dns.rdata.Rdata], 

251 idna_codec: Optional[dns.name.IDNACodec] = None, 

252) -> RRset: 

253 """Create an RRset with the specified name and TTL, and with 

254 the specified list of rdata objects. 

255 

256 *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA 

257 encoder/decoder to use; if ``None``, the default IDNA 2003 

258 encoder/decoder is used. 

259 

260 Returns a ``dns.rrset.RRset`` object. 

261 

262 """ 

263 

264 if isinstance(name, str): 

265 name = dns.name.from_text(name, None, idna_codec=idna_codec) 

266 

267 if len(rdatas) == 0: 

268 raise ValueError("rdata list must not be empty") 

269 r = None 

270 for rd in rdatas: 

271 if r is None: 

272 r = RRset(name, rd.rdclass, rd.rdtype) 

273 r.update_ttl(ttl) 

274 r.add(rd) 

275 assert r is not None 

276 return r 

277 

278 

279def from_rdata(name: Union[dns.name.Name, str], ttl: int, *rdatas: Any) -> RRset: 

280 """Create an RRset with the specified name and TTL, and with 

281 the specified rdata objects. 

282 

283 Returns a ``dns.rrset.RRset`` object. 

284 """ 

285 

286 return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas))