s4-python: Format to PEP8, simplify tests.
[idra/samba.git] / source4 / scripting / python / samba_external / dnspython / dns / node.py
1 # Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc.
2 #
3 # Permission to use, copy, modify, and distribute this software and its
4 # documentation for any purpose with or without fee is hereby granted,
5 # provided that the above copyright notice and this permission notice
6 # appear in all copies.
7 #
8 # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
9 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
11 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
14 # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16 """DNS nodes.  A node is a set of rdatasets."""
17
18 import StringIO
19
20 import dns.rdataset
21 import dns.rdatatype
22 import dns.renderer
23
24 class Node(object):
25     """A DNS node.
26
27     A node is a set of rdatasets
28
29     @ivar rdatasets: the node's rdatasets
30     @type rdatasets: list of dns.rdataset.Rdataset objects"""
31
32     __slots__ = ['rdatasets']
33
34     def __init__(self):
35         """Initialize a DNS node.
36         """
37
38         self.rdatasets = [];
39
40     def to_text(self, name, **kw):
41         """Convert a node to text format.
42
43         Each rdataset at the node is printed.  Any keyword arguments
44         to this method are passed on to the rdataset's to_text() method.
45         @param name: the owner name of the rdatasets
46         @type name: dns.name.Name object
47         @rtype: string
48         """
49
50         s = StringIO.StringIO()
51         for rds in self.rdatasets:
52             print >> s, rds.to_text(name, **kw)
53         return s.getvalue()[:-1]
54
55     def __repr__(self):
56         return '<DNS node ' + str(id(self)) + '>'
57
58     def __eq__(self, other):
59         """Two nodes are equal if they have the same rdatasets.
60
61         @rtype: bool
62         """
63         #
64         # This is inefficient.  Good thing we don't need to do it much.
65         #
66         for rd in self.rdatasets:
67             if rd not in other.rdatasets:
68                 return False
69         for rd in other.rdatasets:
70             if rd not in self.rdatasets:
71                 return False
72         return True
73
74     def __ne__(self, other):
75         return not self.__eq__(other)
76
77     def __len__(self):
78         return len(self.rdatasets)
79
80     def __iter__(self):
81         return iter(self.rdatasets)
82
83     def find_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
84                       create=False):
85         """Find an rdataset matching the specified properties in the
86         current node.
87
88         @param rdclass: The class of the rdataset
89         @type rdclass: int
90         @param rdtype: The type of the rdataset
91         @type rdtype: int
92         @param covers: The covered type.  Usually this value is
93         dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
94         dns.rdatatype.RRSIG, then the covers value will be the rdata
95         type the SIG/RRSIG covers.  The library treats the SIG and RRSIG
96         types as if they were a family of
97         types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).  This makes RRSIGs much
98         easier to work with than if RRSIGs covering different rdata
99         types were aggregated into a single RRSIG rdataset.
100         @type covers: int
101         @param create: If True, create the rdataset if it is not found.
102         @type create: bool
103         @raises KeyError: An rdataset of the desired type and class does
104         not exist and I{create} is not True.
105         @rtype: dns.rdataset.Rdataset object
106         """
107
108         for rds in self.rdatasets:
109             if rds.match(rdclass, rdtype, covers):
110                 return rds
111         if not create:
112             raise KeyError
113         rds = dns.rdataset.Rdataset(rdclass, rdtype)
114         self.rdatasets.append(rds)
115         return rds
116
117     def get_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE,
118                      create=False):
119         """Get an rdataset matching the specified properties in the
120         current node.
121
122         None is returned if an rdataset of the specified type and
123         class does not exist and I{create} is not True.
124
125         @param rdclass: The class of the rdataset
126         @type rdclass: int
127         @param rdtype: The type of the rdataset
128         @type rdtype: int
129         @param covers: The covered type.
130         @type covers: int
131         @param create: If True, create the rdataset if it is not found.
132         @type create: bool
133         @rtype: dns.rdataset.Rdataset object or None
134         """
135
136         try:
137             rds = self.find_rdataset(rdclass, rdtype, covers, create)
138         except KeyError:
139             rds = None
140         return rds
141
142     def delete_rdataset(self, rdclass, rdtype, covers=dns.rdatatype.NONE):
143         """Delete the rdataset matching the specified properties in the
144         current node.
145
146         If a matching rdataset does not exist, it is not an error.
147
148         @param rdclass: The class of the rdataset
149         @type rdclass: int
150         @param rdtype: The type of the rdataset
151         @type rdtype: int
152         @param covers: The covered type.
153         @type covers: int
154         """
155
156         rds = self.get_rdataset(rdclass, rdtype, covers)
157         if not rds is None:
158             self.rdatasets.remove(rds)
159
160     def replace_rdataset(self, replacement):
161         """Replace an rdataset.
162
163         It is not an error if there is no rdataset matching I{replacement}.
164
165         Ownership of the I{replacement} object is transferred to the node;
166         in other words, this method does not store a copy of I{replacement}
167         at the node, it stores I{replacement} itself.
168         """
169
170         self.delete_rdataset(replacement.rdclass, replacement.rdtype,
171                              replacement.covers)
172         self.rdatasets.append(replacement)