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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

91 statements  

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 collections.abc import Collection 

21from typing import Any, cast 

22 

23import dns.name 

24import dns.rdata 

25import dns.rdataclass 

26import dns.rdataset 

27import dns.rdatatype 

28 

29 

30class RRset(dns.rdataset.Rdataset): 

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

32 

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

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

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

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

37 name. 

38 """ 

39 

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

41 

42 def __init__( 

43 self, 

44 name: dns.name.Name, 

45 rdclass: dns.rdataclass.RdataClass, 

46 rdtype: dns.rdatatype.RdataType, 

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

48 deleting: dns.rdataclass.RdataClass | None = None, 

49 ): 

50 """Create a new RRset.""" 

51 

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

53 self.name = name 

54 self.deleting = deleting 

55 

56 def _clone(self): 

57 obj = cast(RRset, super()._clone()) 

58 obj.name = self.name 

59 obj.deleting = self.deleting 

60 return obj 

61 

62 def __repr__(self): 

63 if self.covers == 0: 

64 ctext = "" 

65 else: 

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

67 if self.deleting is not None: 

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

69 else: 

70 dtext = "" 

71 return ( 

72 "<DNS " 

73 + str(self.name) 

74 + " " 

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

76 + " " 

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

78 + ctext 

79 + dtext 

80 + " RRset: " 

81 + self._rdata_repr() 

82 + ">" 

83 ) 

84 

85 def __str__(self): 

86 return self.to_text() 

87 

88 def __eq__(self, other): 

89 if isinstance(other, RRset): 

90 if self.name != other.name: 

91 return False 

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

93 return False 

94 return super().__eq__(other) 

95 

96 def match(self, *args: Any, **kwargs: Any) -> bool: 

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

98 

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

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

101 otherwise. 

102 

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

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

105 makes RRsets matchable as Rdatasets while preserving backwards 

106 compatibility.) 

107 """ 

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

109 return self.full_match(*args, **kwargs) 

110 else: 

111 return super().match(*args, **kwargs) 

112 

113 def full_match( 

114 self, 

115 name: dns.name.Name, 

116 rdclass: dns.rdataclass.RdataClass, 

117 rdtype: dns.rdatatype.RdataType, 

118 covers: dns.rdatatype.RdataType, 

119 deleting: dns.rdataclass.RdataClass | None = None, 

120 ) -> bool: 

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

122 type, covers, and deletion state. 

123 """ 

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

125 return False 

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

127 return False 

128 return True 

129 

130 # pylint: disable=arguments-differ 

131 

132 def to_text( # type: ignore 

133 self, 

134 origin: dns.name.Name | None = None, 

135 relativize: bool = True, 

136 want_comments: bool = False, 

137 style: dns.rdataset.RdatasetStyle | None = None, 

138 **kw: Any, 

139 ) -> str: 

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

141 

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

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

144 are emitted. 

145 

146 Any additional keyword arguments are passed on to the rdata 

147 ``to_text()`` method. 

148 

149 :param origin: The origin for relative names. 

150 :type origin: :py:class:`dns.name.Name` or ``None`` 

151 :param relativize: If ``True``, names will be relativized to *origin*. 

152 :type relativize: bool 

153 :param want_comments: If ``True``, emit comments for rdata which have 

154 them. The default is ``False``. 

155 :type want_comments: bool 

156 :param style: If specified, overrides the other parameters. 

157 :type style: :py:class:`dns.rdataset.RdatasetStyle` or ``None`` 

158 """ 

159 if style is None: 

160 kw = kw.copy() 

161 kw["origin"] = origin 

162 kw["relativize"] = relativize 

163 kw["want_comments"] = want_comments 

164 style = dns.rdataset.RdatasetStyle.from_keywords(kw) 

165 return self.to_styled_text(style) 

166 

167 def to_styled_text(self, style: dns.rdataset.RdatasetStyle) -> str: # type: ignore 

168 """Convert the RRset to styled text. 

169 

170 A new style is made from the specified style setting the ``override_rdclass`` 

171 attribute appropriately for the deleting status of the RRset. 

172 

173 *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If 

174 specified, the style overrides the other parameters. 

175 

176 :rtype: str 

177 """ 

178 if self.deleting is not None: 

179 style = style.replace(override_rdclass=self.deleting) 

180 return super().to_styled_text(style, self.name) 

181 

182 def to_wire( # type: ignore 

183 self, 

184 file: Any, 

185 compress: dns.name.CompressType | None = None, 

186 origin: dns.name.Name | None = None, 

187 **kw: Any, 

188 ) -> int: 

189 """Convert the RRset to wire format. 

190 

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

192 that function for details. 

193 

194 :returns: The number of records emitted. 

195 :rtype: int 

196 """ 

197 

198 return super().to_wire(self.name, file, compress, origin, self.deleting, **kw) 

199 

200 # pylint: enable=arguments-differ 

201 

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

203 """Convert an RRset into an Rdataset. 

204 

205 :rtype: :py:class:`dns.rdataset.Rdataset` 

206 """ 

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

208 

209 

210def from_text_list( 

211 name: dns.name.Name | str, 

212 ttl: int, 

213 rdclass: dns.rdataclass.RdataClass | str, 

214 rdtype: dns.rdatatype.RdataType | str, 

215 text_rdatas: Collection[str], 

216 idna_codec: dns.name.IDNACodec | None = None, 

217 origin: dns.name.Name | None = None, 

218 relativize: bool = True, 

219 relativize_to: dns.name.Name | None = None, 

220) -> RRset: 

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

222 the specified list of rdatas in text format. 

223 

224 :param idna_codec: Specifies the IDNA encoder/decoder. If ``None``, the 

225 default IDNA 2003 encoder/decoder is used. 

226 :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` 

227 :param origin: The origin to use for relative names. 

228 :type origin: :py:class:`dns.name.Name` or ``None`` 

229 :param relativize: If ``True``, names will be relativized. 

230 :type relativize: bool 

231 :param relativize_to: The origin to use when relativizing names. If not 

232 set, *origin* is used. 

233 :type relativize_to: :py:class:`dns.name.Name` or ``None`` 

234 :rtype: :py:class:`dns.rrset.RRset` 

235 """ 

236 

237 if isinstance(name, str): 

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

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

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

241 r = RRset(name, rdclass, rdtype) 

242 r.update_ttl(ttl) 

243 for t in text_rdatas: 

244 rd = dns.rdata.from_text( 

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

246 ) 

247 r.add(rd) 

248 return r 

249 

250 

251def from_text( 

252 name: dns.name.Name | str, 

253 ttl: int, 

254 rdclass: dns.rdataclass.RdataClass | str, 

255 rdtype: dns.rdatatype.RdataType | str, 

256 *text_rdatas: Any, 

257) -> RRset: 

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

259 the specified rdatas in text format. 

260 

261 :rtype: :py:class:`dns.rrset.RRset` 

262 """ 

263 

264 return from_text_list( 

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

266 ) 

267 

268 

269def from_rdata_list( 

270 name: dns.name.Name | str, 

271 ttl: int, 

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

273 idna_codec: dns.name.IDNACodec | None = None, 

274) -> RRset: 

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

276 the specified list of rdata objects. 

277 

278 :param idna_codec: Specifies the IDNA encoder/decoder. If ``None``, the 

279 default IDNA 2003 encoder/decoder is used. 

280 :type idna_codec: :py:class:`dns.name.IDNACodec` or ``None`` 

281 :rtype: :py:class:`dns.rrset.RRset` 

282 """ 

283 

284 if isinstance(name, str): 

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

286 

287 if len(rdatas) == 0: 

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

289 r = None 

290 for rd in rdatas: 

291 if r is None: 

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

293 r.update_ttl(ttl) 

294 r.add(rd) 

295 assert r is not None 

296 return r 

297 

298 

299def from_rdata(name: dns.name.Name | str, ttl: int, *rdatas: Any) -> RRset: 

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

301 the specified rdata objects. 

302 

303 :rtype: :py:class:`dns.rrset.RRset` 

304 """ 

305 

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