[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[dak/master] Simplify validation of not NULL constraints.



And derive more classes from ORMObject.

Signed-off-by: Torsten Werner <twerner@debian.org>
---
 daklib/dbconn.py            |  107 +++++++++++++++++++++++++++---------------
 tests/dbtest_fingerprint.py |    3 +-
 tests/dbtest_validation.py  |    2 +-
 3 files changed, 72 insertions(+), 40 deletions(-)

diff --git a/daklib/dbconn.py b/daklib/dbconn.py
index 0ecb669..5e04784 100755
--- a/daklib/dbconn.py
+++ b/daklib/dbconn.py
@@ -212,7 +212,7 @@ class ORMObject(object):
                 value = getattr(self, property)
                 if value is None:
                     # skip None
-                    pass
+                    continue
                 elif isinstance(value, ORMObject):
                     # use repr() for ORMObject types
                     value = repr(value)
@@ -245,12 +245,26 @@ class ORMObject(object):
         '''
         return '<%s %s>' % (self.classname(), self.json())
 
+    def not_null_constraints(self):
+        '''
+        Returns a list of properties that must be not NULL. Derived classes
+        should override this method if needed.
+        '''
+        return []
+
+    validation_message = \
+        "Validation failed because property '%s' must not be empty in object\n%s"
+
     def validate(self):
         '''
-        This function should be implemented by derived classes to validate self.
-        It may raise the DBUpdateError exception if needed.
+        This function validates the not NULL constraints as returned by
+        not_null_constraints(). It raises the DBUpdateError exception if
+        validation fails.
         '''
-        pass
+        for property in self.not_null_constraints():
+            if not hasattr(self, property) or getattr(self, property) is None:
+                raise DBUpdateError(self.validation_message % \
+                    (property, str(self)))
 
 __all__.append('ORMObject')
 
@@ -295,11 +309,8 @@ class Architecture(ORMObject):
     def properties(self):
         return ['arch_string', 'arch_id', 'suites_count']
 
-    def validate(self):
-        if self.arch_string is None or len(self.arch_string) == 0:
-            raise DBUpdateError( \
-                "Validation failed because 'arch_string' must not be empty in object\n%s" % \
-                str(self))
+    def not_null_constraints(self):
+        return ['arch_string']
 
 __all__.append('Architecture')
 
@@ -1213,14 +1224,8 @@ class PoolFile(ORMObject):
         return ['filename', 'file_id', 'filesize', 'md5sum', 'sha1sum', \
             'sha256sum', 'location', 'source', 'last_used']
 
-    def validate(self):
-        # sha1sum and sha256sum are not validated yet
-        if self.filename is None or len(self.filename) == 0 or \
-            self.filesize < 0 or self.md5sum is None or \
-            len(self.md5sum) == 0 or self.location is None:
-            raise DBUpdateError( \
-                "Validation failed because some properties must not be empty in object\n%s" % \
-                str(self))
+    def not_null_constraints(self):
+        return ['filename', 'md5sum', 'location']
 
 __all__.append('PoolFile')
 
@@ -1332,12 +1337,16 @@ __all__.append('add_poolfile')
 
 ################################################################################
 
-class Fingerprint(object):
+class Fingerprint(ORMObject):
     def __init__(self, fingerprint = None):
         self.fingerprint = fingerprint
 
-    def __repr__(self):
-        return '<Fingerprint %s>' % self.fingerprint
+    def properties(self):
+        return ['fingerprint', 'fingerprint_id', 'keyring', 'uid', \
+            'binary_reject']
+
+    def not_null_constraints(self):
+        return ['fingerprint']
 
 __all__.append('Fingerprint')
 
@@ -1622,14 +1631,17 @@ __all__.append('get_dbchange')
 
 ################################################################################
 
-class Location(object):
+class Location(ORMObject):
     def __init__(self, path = None):
         self.path = path
         # the column 'type' should go away, see comment at mapper
         self.archive_type = 'pool'
 
-    def __repr__(self):
-        return '<Location %s (%s)>' % (self.path, self.location_id)
+    def properties(self):
+        return ['path', 'archive_type', 'component', 'files_count']
+
+    def not_null_constraints(self):
+        return ['path', 'archive_type']
 
 __all__.append('Location')
 
@@ -1669,12 +1681,15 @@ __all__.append('get_location')
 
 ################################################################################
 
-class Maintainer(object):
+class Maintainer(ORMObject):
     def __init__(self, name = None):
         self.name = name
 
-    def __repr__(self):
-        return '''<Maintainer '%s' (%s)>''' % (self.name, self.maintainer_id)
+    def properties(self):
+        return ['name', 'maintainer_id']
+
+    def not_null_constraints(self):
+        return ['name']
 
     def get_split_maintainer(self):
         if not hasattr(self, 'name') or self.name is None:
@@ -2208,7 +2223,7 @@ __all__.append('get_sections')
 
 ################################################################################
 
-class DBSource(object):
+class DBSource(ORMObject):
     def __init__(self, source = None, version = None, maintainer = None, \
         changedby = None, poolfile = None, install_date = None):
         self.source = source
@@ -2218,8 +2233,14 @@ class DBSource(object):
         self.poolfile = poolfile
         self.install_date = install_date
 
-    def __repr__(self):
-        return '<DBSource %s (%s)>' % (self.source, self.version)
+    def properties(self):
+        return ['source', 'source_id', 'maintainer', 'changedby', \
+            'fingerprint', 'poolfile', 'version', 'suites_count', \
+            'install_date']
+
+    def not_null_constraints(self):
+        return ['source', 'version', 'maintainer', 'changedby', \
+            'poolfile', 'install_date']
 
 __all__.append('DBSource')
 
@@ -2591,13 +2612,16 @@ SUITE_FIELDS = [ ('SuiteName', 'suite_name'),
 
 # Why the heck don't we have any UNIQUE constraints in table suite?
 # TODO: Add UNIQUE constraints for appropriate columns.
-class Suite(object):
+class Suite(ORMObject):
     def __init__(self, suite_name = None, version = None):
         self.suite_name = suite_name
         self.version = version
 
-    def __repr__(self):
-        return '<Suite %s>' % self.suite_name
+    def properties(self):
+        return ['suite_name', 'version']
+
+    def not_null_constraints(self):
+        return ['suite_name', 'version']
 
     def __eq__(self, val):
         if isinstance(val, str):
@@ -3051,7 +3075,8 @@ class DBConn(object):
                                      # using lazy='dynamic' in the back
                                      # reference because we have A LOT of
                                      # files in one location
-                                     backref=backref('files', lazy='dynamic'))))
+                                     backref=backref('files', lazy='dynamic'))),
+                extension = validator)
 
         mapper(Fingerprint, self.tbl_fingerprint,
                properties = dict(fingerprint_id = self.tbl_fingerprint.c.id,
@@ -3060,7 +3085,8 @@ class DBConn(object):
                                  keyring_id = self.tbl_fingerprint.c.keyring,
                                  keyring = relation(Keyring),
                                  source_acl = relation(SourceACL),
-                                 binary_acl = relation(BinaryACL)))
+                                 binary_acl = relation(BinaryACL)),
+               extension = validator)
 
         mapper(Keyring, self.tbl_keyrings,
                properties = dict(keyring_name = self.tbl_keyrings.c.name,
@@ -3126,14 +3152,16 @@ class DBConn(object):
                                  archive = relation(Archive),
                                  # FIXME: the 'type' column is old cruft and
                                  # should be removed in the future.
-                                 archive_type = self.tbl_location.c.type))
+                                 archive_type = self.tbl_location.c.type),
+               extension = validator)
 
         mapper(Maintainer, self.tbl_maintainer,
                properties = dict(maintainer_id = self.tbl_maintainer.c.id,
                    maintains_sources = relation(DBSource, backref='maintainer',
                        primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.maintainer)),
                    changed_sources = relation(DBSource, backref='changedby',
-                       primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.changedby))))
+                       primaryjoin=(self.tbl_maintainer.c.id==self.tbl_source.c.changedby))),
+                extension = validator)
 
         mapper(NewComment, self.tbl_new_comments,
                properties = dict(comment_id = self.tbl_new_comments.c.id))
@@ -3178,7 +3206,8 @@ class DBConn(object):
                                                      primaryjoin=(self.tbl_source.c.id==self.tbl_dsc_files.c.source)),
                                  suites = relation(Suite, secondary=self.tbl_src_associations,
                                      backref='sources'),
-                                 srcuploaders = relation(SrcUploader)))
+                                 srcuploaders = relation(SrcUploader)),
+               extension = validator)
 
         mapper(SourceACL, self.tbl_source_acl,
                properties = dict(source_acl_id = self.tbl_source_acl.c.id))
@@ -3199,7 +3228,9 @@ class DBConn(object):
         mapper(Suite, self.tbl_suite,
                properties = dict(suite_id = self.tbl_suite.c.id,
                                  policy_queue = relation(PolicyQueue),
-                                 copy_queues = relation(BuildQueue, secondary=self.tbl_suite_build_queue_copy)))
+                                 copy_queues = relation(BuildQueue,
+                                     secondary=self.tbl_suite_build_queue_copy)),
+                extension = validator)
 
         mapper(SuiteSrcFormat, self.tbl_suite_src_formats,
                properties = dict(suite_id = self.tbl_suite_src_formats.c.suite,
diff --git a/tests/dbtest_fingerprint.py b/tests/dbtest_fingerprint.py
index 122ea62..72e081a 100755
--- a/tests/dbtest_fingerprint.py
+++ b/tests/dbtest_fingerprint.py
@@ -3,6 +3,7 @@
 from db_test import DBDakTestCase
 
 from daklib.dbconn import Fingerprint, Uid
+from daklib.dak_exceptions import DBUpdateError
 
 from sqlalchemy.exc import IntegrityError
 import unittest
@@ -55,7 +56,7 @@ class FingerprintTestCase(DBDakTestCase):
         self.session.flush()
 
     def test_exceptions(self):
-        self.assertRaises(IntegrityError, self.fingerprint_no_fingerprint)
+        self.assertRaises(DBUpdateError, self.fingerprint_no_fingerprint)
         self.session.rollback()
         self.assertRaises(IntegrityError, self.fingerprint_duplicate_fingerprint)
         self.session.rollback()
diff --git a/tests/dbtest_validation.py b/tests/dbtest_validation.py
index 32f47eb..8592124 100755
--- a/tests/dbtest_validation.py
+++ b/tests/dbtest_validation.py
@@ -25,7 +25,7 @@ class ValidatorTestCase(DBDakTestCase):
         self.session.add(architecture)
         self.session.flush()
         # before_update validation should fail
-        architecture.arch_string = ''
+        architecture.arch_string = None
         self.assertRaises(DBUpdateError, self.session.flush)
         self.session.rollback()
 
-- 
1.5.6.5



Reply to: