Merge "Fixed issues with __repr__ and __str__ on objects"

This commit is contained in:
Zuul 2022-08-10 07:05:22 +00:00 committed by Gerrit Code Review
commit f3c29e8bce
26 changed files with 127 additions and 112 deletions

View File

@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_versionedobjects import base
@ -19,11 +20,10 @@ from oslo_versionedobjects.base import VersionedObjectDictCompat as DictObjectMi
from oslo_versionedobjects import exception
from oslo_versionedobjects import fields as ovoo_fields
from designate import exceptions
from designate.i18n import _
from designate.objects import fields
LOG = logging.getLogger(__name__)
@ -54,16 +54,15 @@ class DesignateObject(base.VersionedObject):
self.FIELDS = self.fields
@classmethod
def _make_obj_str(cls, keys):
msg = "<%(name)s" % {'name': cls.obj_name()}
for key in keys:
msg += " {0}:'%({0})s'".format(key)
def _make_obj_str(cls, data):
msg = "<%s" % cls.obj_name()
for key in cls.STRING_KEYS:
msg += " %s:'%s'" % (key, data.get(key))
msg += ">"
return msg
def __str__(self):
return (self._make_obj_str(self.STRING_KEYS)
% self)
def __repr__(self):
return self._make_obj_str(self.to_dict())
def save(self, context):
pass
@ -153,9 +152,6 @@ class DesignateObject(base.VersionedObject):
def __ne__(self, other):
return not (self.__eq__(other))
def __repr__(self):
return "OVO Objects"
# TODO(daidv): all of bellow functions should
# be removed when we completed migration.
def nested_sort(self, key, value):
@ -360,11 +356,13 @@ class ListObjectMixin(base.ObjectListBase):
return list_
def __str__(self):
return (_("<%(type)s count:'%(count)s' object:'%(list_type)s'>")
% {'count': len(self),
'type': self.LIST_ITEM_TYPE.obj_name(),
'list_type': self.obj_name()})
def __repr__(self):
return ("<%(type)s count:'%(count)s' object:'%(list_type)s'>" %
{
'type': self.LIST_ITEM_TYPE.obj_name(),
'count': len(self),
'list_type': self.obj_name()
})
def __iter__(self):
"""List iterator interface"""

View File

@ -66,11 +66,11 @@ class Record(base.DesignateObject, base.PersistentObjectMixin,
'id', 'recordset_id', 'data'
]
def __str__(self):
def __repr__(self):
record = self.to_dict()
record['data'] = record['data'][:35]
return (self._make_obj_str(self.STRING_KEYS)
% record)
if 'data' in record:
record['data'] = record['data'][:35]
return self._make_obj_str(record)
@base.DesignateRegistry.register

View File

@ -151,11 +151,11 @@ class RecordSet(base.DesignateObject, base.DictObjectMixin,
for record in old_records:
record_obj = record_cls()
try:
record_obj._from_string(record.data)
# The _from_string() method will throw a ValueError if there is not
record_obj.from_string(record.data)
# The from_string() method will throw a ValueError if there is not
# enough data blobs
except ValueError as e:
# Something broke in the _from_string() method
# Something broke in the from_string() method
# Fake a correct looking ValidationError() object
e = ValidationError()
e.path = ['records', i]

View File

@ -28,10 +28,7 @@ class A(Record):
'address': fields.IPV4AddressField()
}
def _to_string(self):
return self.address
def _from_string(self, value):
def from_string(self, value):
self.address = value
# The record type is defined in the RFC. This will be used when the record

View File

@ -28,10 +28,7 @@ class AAAA(Record):
'address': fields.IPV6AddressField()
}
def _to_string(self):
return self.address
def _from_string(self, value):
def from_string(self, value):
self.address = value
# The record type is defined in the RFC. This will be used when the record

View File

@ -30,11 +30,8 @@ class CAA(Record):
'prpt': fields.CaaPropertyField()
}
def _to_string(self):
return ("%(flag)s %(prpt)s" % self)
def _from_string(self, v):
flags, prpt = v.split(' ', 1)
def from_string(self, value):
flags, prpt = value.split(' ', 1)
self.flags = int(flags)
self.prpt = prpt

View File

@ -92,11 +92,8 @@ class CERT(Record):
raise ValueError('Cert certificate is not valid.')
return certificate
def _to_string(self):
return '%(cert_type)s %(key_tag)s %(cert_algo)s %(certificate)s' % self
def _from_string(self, v):
cert_type, key_tag, cert_algo, certificate = v.split(' ', 3)
def from_string(self, value):
cert_type, key_tag, cert_algo, certificate = value.split(' ', 3)
self.cert_type = self.validate_cert_type(cert_type)
self.key_tag = int(key_tag)

View File

@ -28,10 +28,7 @@ class CNAME(Record):
'cname': fields.DomainField(maxLength=255)
}
def _to_string(self):
return self.cname
def _from_string(self, value):
def from_string(self, value):
self.cname = value
# The record type is defined in the RFC. This will be used when the record

View File

@ -29,10 +29,7 @@ class MX(Record):
'exchange': fields.StringFields(maxLength=255),
}
def _to_string(self):
return '%(priority)s %(exchange)s' % self
def _from_string(self, value):
def from_string(self, value):
priority, exchange = value.split(' ')
if repr(int(priority)) != priority:

View File

@ -35,12 +35,10 @@ class NAPTR(Record):
'replacement': fields.DomainField(maxLength=255)
}
def _to_string(self):
return ("%(order)s %(preference)s %(flags)s %(service)s %(regexp)s "
"%(replacement)s" % self)
def _from_string(self, v):
order, preference, flags, service, regexp, replacement = v.split(' ')
def from_string(self, value):
order, preference, flags, service, regexp, replacement = (
value.split(' ')
)
self.order = int(order)
self.preference = int(preference)
self.flags = flags

View File

@ -34,10 +34,7 @@ class NS(Record):
'name': fields.DomainField(),
}
def _to_string(self):
return self.nsdname
def _from_string(self, value):
def from_string(self, value):
self.nsdname = value
# The record type is defined in the RFC. This will be used when the record

View File

@ -28,10 +28,7 @@ class PTR(Record):
'ptrdname': fields.DomainField(maxLength=255)
}
def _to_string(self):
return self.ptrdname
def _from_string(self, value):
def from_string(self, value):
self.ptrdname = value
# The record type is defined in the RFC. This will be used when the record

View File

@ -35,12 +35,10 @@ class SOA(Record):
'minimum': fields.IntegerFields(minimum=0, maximum=2147483647)
}
def _to_string(self):
return ("%(mname)s %(rname)s %(serial)s %(refresh)s %(retry)s "
"%(expire)s %(minimum)s" % self)
def _from_string(self, v):
mname, rname, serial, refresh, retry, expire, minimum = v.split(' ')
def from_string(self, value):
mname, rname, serial, refresh, retry, expire, minimum = (
value.split(' ')
)
self.mname = mname
self.rname = rname
self.serial = int(serial)

View File

@ -28,10 +28,7 @@ class SPF(Record):
'txt_data': fields.StringFields()
}
def _to_string(self):
return self.txt_data
def _from_string(self, value):
def from_string(self, value):
if not value.startswith('"') and not value.endswith('"'):
# value with spaces should be quoted as per RFC1035 5.1
for element in value:

View File

@ -37,10 +37,7 @@ class SRV(Record):
'name': fields.SRVField(maxLength=255, nullable=True)
}
def _to_string(self):
return "%(priority)s %(weight)s %(target)s %(port)s" % self
def _from_string(self, value):
def from_string(self, value):
priority, weight, port, target = value.split(' ')
self.priority = int(priority)
self.weight = int(weight)

View File

@ -30,10 +30,7 @@ class SSHFP(Record):
'fingerprint': fields.Sshfp(nullable=True),
}
def _to_string(self):
return "%(algorithm)s %(fp_type)s %(fingerprint)s" % self
def _from_string(self, value):
def from_string(self, value):
algorithm, fp_type, fingerprint = value.split(' ')
for value in {algorithm, fp_type}:

View File

@ -28,9 +28,6 @@ class TXT(Record):
'txt_data': fields.TxtField()
}
def _to_string(self):
return self.txt_data
@staticmethod
def _is_wrapped_in_double_quotes(value):
return value.startswith('"') and value.endswith('"')
@ -71,7 +68,7 @@ class TXT(Record):
'Quotation marks should be escaped with backslash.'
)
def _from_string(self, value):
def from_string(self, value):
if len(value) > 255:
# expecting record containing multiple strings as
# per rfc7208 3.3 and rfc1035 3.3.14

View File

@ -39,6 +39,10 @@ class TestObject(objects.DesignateObject):
'nested_list': fields.ObjectFields('TestObjectList', nullable=True),
}
STRING_KEYS = [
'id', 'name'
]
@base.DesignateRegistry.register
class TestObjectDict(TestObject, objects.DictObjectMixin):
@ -64,6 +68,36 @@ class TestValidatableObject(objects.DesignateObject):
class DesignateObjectTest(oslotest.base.BaseTestCase):
def test_obj_to_repr(self):
obj = TestObject.from_dict({
'id': 1, 'name': 'example'
})
self.assertEqual(
"<TestObject id:'1' name:'example'>",
repr(obj)
)
def test_obj_to_str(self):
obj = TestObject.from_dict({
'id': 1, 'name': 'example'
})
self.assertEqual(
"<TestObject id:'1' name:'example'>", str(obj)
)
def test_empty_obj_to_str(self):
self.assertEqual(
"<TestObject id:'None' name:'None'>", str(TestObject())
)
def test_record_to_str(self):
obj = objects.Record.from_dict({
'id': 1, 'recordset_id': '2', 'data': 'example'
})
self.assertEqual(
"<Record id:'1' recordset_id:'2' data:'example'>", str(obj)
)
def test_obj_cls_from_name(self):
cls = objects.DesignateObject.obj_cls_from_name('TestObject')
self.assertEqual(TestObject, cls)

View File

@ -28,6 +28,8 @@ LOG = logging.getLogger(__name__)
def create_test_recordset():
record_set = objects.RecordSet(
id='f6a2cbd6-7f9a-4e0c-a00d-98a02aa73fc8',
zone_id='74038683-cab1-4056-bdf8-b39bd155ff21',
name='www.example.org.',
type='A',
records=objects.RecordList(objects=[
@ -39,12 +41,20 @@ def create_test_recordset():
class RecordSetTest(oslotest.base.BaseTestCase):
def test_init(self):
record_set = create_test_recordset()
self.assertEqual('www.example.org.', record_set.name)
self.assertEqual('A', record_set.type)
def test_to_repr(self):
record_set = create_test_recordset()
self.assertEqual(
"<RecordSet id:'f6a2cbd6-7f9a-4e0c-a00d-98a02aa73fc8' type:'A' "
"name:'www.example.org.' "
"zone_id:'74038683-cab1-4056-bdf8-b39bd155ff21'>",
repr(record_set)
)
def test_not_managed(self):
record_set = create_test_recordset()
self.assertFalse(record_set.managed)

View File

@ -23,6 +23,19 @@ LOG = logging.getLogger(__name__)
class RRDataATest(oslotest.base.BaseTestCase):
def test_to_repr(self):
recordset = objects.RecordSet(
name='www.example.test.', type='A',
records=objects.RecordList(objects=[
objects.Record(data='192.168.0.1'),
])
)
recordset.validate()
self.assertEqual(
"<Record id:'None' recordset_id:'None' data:'192.168.0.1'>",
repr(recordset.records[0])
)
def test_valid_a_record(self):
recordset = objects.RecordSet(
name='www.example.test.', type='A',

View File

@ -24,14 +24,14 @@ LOG = logging.getLogger(__name__)
class RRDataCAATest(oslotest.base.BaseTestCase):
def test_parse_caa_issue(self):
caa_record = objects.CAA()
caa_record._from_string('0 issue ca.example.net')
caa_record.from_string('0 issue ca.example.net')
self.assertEqual(0, caa_record.flags)
self.assertEqual('issue ca.example.net', caa_record.prpt)
def test_parse_caa_issuewild(self):
caa_record = objects.CAA()
caa_record._from_string('1 issuewild ca.example.net; policy=ev')
caa_record.from_string('1 issuewild ca.example.net; policy=ev')
self.assertEqual(1, caa_record.flags)
self.assertEqual('issuewild ca.example.net; policy=ev',
@ -39,19 +39,19 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
def test_parse_caa_iodef(self):
caa_record = objects.CAA()
caa_record._from_string('0 iodef https://example.net/')
caa_record.from_string('0 iodef https://example.net/')
self.assertEqual(0, caa_record.flags)
self.assertEqual('iodef https://example.net/', caa_record.prpt)
caa_record = objects.CAA()
caa_record._from_string('0 iodef mailto:security@example.net')
caa_record.from_string('0 iodef mailto:security@example.net')
self.assertEqual(0, caa_record.flags)
self.assertEqual('iodef mailto:security@example.net', caa_record.prpt)
caa_record = objects.CAA()
caa_record._from_string('0 iodef mailto:security+caa@example.net')
caa_record.from_string('0 iodef mailto:security+caa@example.net')
self.assertEqual(0, caa_record.flags)
self.assertEqual('iodef mailto:security+caa@example.net',
@ -62,7 +62,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
"Property tag 1 2 must be 'issue', 'issuewild' or 'iodef'",
caa_record._from_string, '0 1 2'
caa_record.from_string, '0 1 2'
)
def test_parse_caa_issue_host_too_long(self):
@ -72,7 +72,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
ValueError,
'Host aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
'aaaaaaaaaa is too long',
caa_record._from_string, '0 issue %s.net' % hostname
caa_record.from_string, '0 issue %s.net' % hostname
)
def test_parse_caa_issue_domain_not_valid(self):
@ -80,7 +80,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Domain abc. is invalid',
caa_record._from_string, '0 issue abc.'
caa_record.from_string, '0 issue abc.'
)
def test_parse_caa_issue_key_value_not_valid(self):
@ -88,7 +88,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'def is not a valid key-value pair',
caa_record._from_string, '0 issue abc;def'
caa_record.from_string, '0 issue abc;def'
)
def test_parse_caa_iodef_mail_host_too_long(self):
@ -98,7 +98,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
ValueError,
'Host aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
'aaaaaaaaaa is too long',
caa_record._from_string, '0 iodef mailto:me@%s.net' % hostname
caa_record.from_string, '0 iodef mailto:me@%s.net' % hostname
)
def test_parse_caa_iodef_mail_domain_not_valid(self):
@ -106,7 +106,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Domain example.net. is invalid',
caa_record._from_string, '0 iodef mailto:me@example.net.'
caa_record.from_string, '0 iodef mailto:me@example.net.'
)
def test_parse_caa_iodef_http_host_too_long(self):
@ -116,7 +116,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
ValueError,
'Host aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
'aaaaaaaaaa is too long',
caa_record._from_string, '0 iodef https://%s.net/' % hostname
caa_record.from_string, '0 iodef https://%s.net/' % hostname
)
def test_parse_caa_iodef_http_domain_not_valid(self):
@ -124,7 +124,7 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Domain example.net. is invalid',
caa_record._from_string, '0 iodef https://example.net./'
caa_record.from_string, '0 iodef https://example.net./'
)
def test_parse_caa_iodef_not_valid_url(self):
@ -132,5 +132,5 @@ class RRDataCAATest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'https:// is not a valid URL',
caa_record._from_string, '0 iodef https://'
caa_record.from_string, '0 iodef https://'
)

View File

@ -25,7 +25,7 @@ LOG = logging.getLogger(__name__)
class RRDataCERTTest(oslotest.base.BaseTestCase):
def test_parse_cert(self):
cert_record = objects.CERT()
cert_record._from_string(
cert_record.from_string(
'DPKIX 1 RSASHA256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc='
)
@ -42,7 +42,7 @@ class RRDataCERTTest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Cert type value should be between 0 and 65535',
cert_record._from_string,
cert_record.from_string,
'99999 1 RSASHA256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc='
)
@ -51,7 +51,7 @@ class RRDataCERTTest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Cert type is not valid Mnemonic.',
cert_record._from_string,
cert_record.from_string,
'FAKETYPE 1 RSASHA256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc='
)
@ -60,7 +60,7 @@ class RRDataCERTTest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Cert algorithm value should be between 0 and 255',
cert_record._from_string,
cert_record.from_string,
'DPKIX 1 256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc='
)
@ -69,7 +69,7 @@ class RRDataCERTTest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Cert algorithm is not valid Mnemonic.',
cert_record._from_string,
cert_record.from_string,
'DPKIX 1 FAKESHA256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc='
)
@ -78,6 +78,6 @@ class RRDataCERTTest(oslotest.base.BaseTestCase):
self.assertRaisesRegex(
ValueError,
'Cert certificate is not valid.',
cert_record._from_string,
cert_record.from_string,
'DPKIX 1 RSASHA256 KR1L0GbocaIOOim1+qdHtOSrDcOsGiI2NCcxuX2/Tqc'
)

View File

@ -25,7 +25,7 @@ LOG = logging.getLogger(__name__)
class RRDataMXTest(oslotest.base.BaseTestCase):
def test_parse_mx(self):
mx_record = objects.MX()
mx_record._from_string('0 mail.example.org.')
mx_record.from_string('0 mail.example.org.')
self.assertEqual(0, mx_record.priority)
self.assertEqual('mail.example.org.', mx_record.exchange)

View File

@ -24,7 +24,7 @@ LOG = logging.getLogger(__name__)
class RRDataNAPTRTest(oslotest.base.BaseTestCase):
def test_parse_naptr(self):
naptr_record = objects.NAPTR()
naptr_record._from_string(
naptr_record.from_string(
'0 0 S SIP+D2U !^.*$!sip:customer-service@example.com! _sip._udp.example.com.') # noqa
self.assertEqual(0, naptr_record.order)

View File

@ -25,7 +25,7 @@ LOG = logging.getLogger(__name__)
class RRDataSSHTPTest(oslotest.base.BaseTestCase):
def test_parse_sshfp(self):
sshfp_record = objects.SSHFP()
sshfp_record._from_string(
sshfp_record.from_string(
'0 0 72d30d211ce8c464de2811e534de23b9be9b4dc4')
self.assertEqual(0, sshfp_record.algorithm)

View File

@ -66,13 +66,13 @@ class RRDataTXTTest(oslotest.base.BaseTestCase):
ValueError,
"TXT record is missing a double quote either at beginning "
"or at end.",
record._from_string,
record.from_string,
'"foo'
)
self.assertRaisesRegex(
ValueError,
"TXT record is missing a double quote either at beginning "
"or at end.",
record._from_string,
record.from_string,
'foo"'
)