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
« 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
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 typing import Any, Collection, Dict, Optional, Union, cast
22import dns.name
23import dns.rdataclass
24import dns.rdataset
25import dns.renderer
28class RRset(dns.rdataset.Rdataset):
30 """A DNS RRset (named rdataset).
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 """
39 __slots__ = ["name", "deleting"]
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."""
51 super().__init__(rdclass, rdtype, covers)
52 self.name = name
53 self.deleting = deleting
55 def _clone(self):
56 obj = super()._clone()
57 obj.name = self.name
58 obj.deleting = self.deleting
59 return obj
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 )
84 def __str__(self):
85 return self.to_text()
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)
95 def match(self, *args: Any, **kwargs: Any) -> bool: # type: ignore[override]
96 """Does this rrset match the specified attributes?
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.
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]
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
129 # pylint: disable=arguments-differ
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.
139 See ``dns.name.Name.choose_relativity`` for more information
140 on how *origin* and *relativize* determine the way names
141 are emitted.
143 Any additional keyword arguments are passed on to the rdata
144 ``to_text()`` method.
146 *origin*, a ``dns.name.Name`` or ``None``, the origin for relative
147 names.
149 *relativize*, a ``bool``. If ``True``, names will be relativized
150 to *origin*.
151 """
153 return super().to_text(
154 self.name, origin, relativize, self.deleting, **kw # type: ignore
155 )
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.
166 All keyword arguments are passed to ``dns.rdataset.to_wire()``; see
167 that function for details.
169 Returns an ``int``, the number of records emitted.
170 """
172 return super().to_wire(
173 self.name, file, compress, origin, self.deleting, **kw # type:ignore
174 )
176 # pylint: enable=arguments-differ
178 def to_rdataset(self) -> dns.rdataset.Rdataset:
179 """Convert an RRset into an Rdataset.
181 Returns a ``dns.rdataset.Rdataset``.
182 """
183 return dns.rdataset.from_rdata_list(self.ttl, list(self))
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.
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.
204 *origin*, a ``dns.name.Name`` (or ``None``), the
205 origin to use for relative names.
207 *relativize*, a ``bool``. If true, name will be relativized.
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.
212 Returns a ``dns.rrset.RRset`` object.
213 """
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
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.
239 Returns a ``dns.rrset.RRset`` object.
240 """
242 return from_text_list(
243 name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas)
244 )
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.
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.
260 Returns a ``dns.rrset.RRset`` object.
262 """
264 if isinstance(name, str):
265 name = dns.name.from_text(name, None, idna_codec=idna_codec)
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
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.
283 Returns a ``dns.rrset.RRset`` object.
284 """
286 return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas))