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
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
1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
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.
18"""DNS RRsets (an RRset is a named rdataset)"""
20from collections.abc import Collection
21from typing import Any, cast
23import dns.name
24import dns.rdata
25import dns.rdataclass
26import dns.rdataset
27import dns.rdatatype
30class RRset(dns.rdataset.Rdataset):
31 """A DNS RRset (named rdataset).
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 """
40 __slots__ = ["name", "deleting"]
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."""
52 super().__init__(rdclass, rdtype, covers)
53 self.name = name
54 self.deleting = deleting
56 def _clone(self):
57 obj = cast(RRset, super()._clone())
58 obj.name = self.name
59 obj.deleting = self.deleting
60 return obj
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 )
85 def __str__(self):
86 return self.to_text()
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)
96 def match(self, *args: Any, **kwargs: Any) -> bool:
97 """Does this rrset match the specified attributes?
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.
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)
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
130 # pylint: disable=arguments-differ
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.
142 See ``dns.name.Name.choose_relativity`` for more information
143 on how *origin* and *relativize* determine the way names
144 are emitted.
146 Any additional keyword arguments are passed on to the rdata
147 ``to_text()`` method.
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)
167 def to_styled_text(self, style: dns.rdataset.RdatasetStyle) -> str: # type: ignore
168 """Convert the RRset to styled text.
170 A new style is made from the specified style setting the ``override_rdclass``
171 attribute appropriately for the deleting status of the RRset.
173 *style*, a :py:class:`dns.rdataset.RdatasetStyle` or ``None`` (the default). If
174 specified, the style overrides the other parameters.
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)
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.
191 All keyword arguments are passed to ``dns.rdataset.to_wire()``; see
192 that function for details.
194 :returns: The number of records emitted.
195 :rtype: int
196 """
198 return super().to_wire(self.name, file, compress, origin, self.deleting, **kw)
200 # pylint: enable=arguments-differ
202 def to_rdataset(self) -> dns.rdataset.Rdataset:
203 """Convert an RRset into an Rdataset.
205 :rtype: :py:class:`dns.rdataset.Rdataset`
206 """
207 return dns.rdataset.from_rdata_list(self.ttl, list(self))
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.
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 """
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
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.
261 :rtype: :py:class:`dns.rrset.RRset`
262 """
264 return from_text_list(
265 name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas)
266 )
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.
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 """
284 if isinstance(name, str):
285 name = dns.name.from_text(name, None, idna_codec=idna_codec)
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
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.
303 :rtype: :py:class:`dns.rrset.RRset`
304 """
306 return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas))