Changeset 7536 for main/waeup.sirp/trunk


Ignore:
Timestamp:
30 Jan 2012, 07:41:17 (13 years ago)
Author:
Henrik Bettermann
Message:

Implement study level importer.

Location:
main/waeup.sirp/trunk/src/waeup/sirp/students
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.sirp/trunk/src/waeup/sirp/students/batching.py

    r7534 r7536  
    3737from waeup.sirp.students.interfaces import (
    3838    IStudent, IStudentStudyCourse,
    39     IStudentUpdateByRegNo, IStudentUpdateByMatricNo)
     39    IStudentUpdateByRegNo, IStudentUpdateByMatricNo,
     40    IStudentStudyLevel)
    4041from waeup.sirp.students.workflow import  IMPORTABLE_STATES
    4142from waeup.sirp.utils.batching import BatchProcessor
     
    268269        return self.getParent(row, site) is not None
    269270
    270 
    271271    def entryExists(self, row, site):
    272272        return self.getEntry(row, site) is not None
     
    274274    def getEntry(self, row, site):
    275275        student = self.getParent(row, site)
    276         if not student:
     276        if student is None:
    277277            return None
    278278        return student.get('studycourse')
     
    306306        return errs, inv_errs, conv_dict
    307307
     308class StudentStudyLevelProcessor(BatchProcessor):
     309    """A batch processor for IStudentStudyLevel objects.
     310    """
     311    grok.implements(IBatchProcessor)
     312    grok.provides(IBatchProcessor)
     313    grok.context(Interface)
     314    util_name = 'studylevelimporter'
     315    grok.name(util_name)
     316
     317    name = u'StudentStudyLevel Importer'
     318    iface = IStudentStudyLevel
     319    factory_name = 'waeup.StudentStudyLevel'
     320
     321    location_fields = []
     322
     323    mode = None
     324
     325    @property
     326    def available_fields(self):
     327        return sorted(list(set(
     328            ['student_id','reg_number','matric_number','level'] + getFields(
     329                self.iface).keys())))
     330
     331    def checkHeaders(self, headerfields, mode='ignore'):
     332        if not 'reg_number' in headerfields and not 'student_id' \
     333            in headerfields and not 'matric_number' in headerfields:
     334            raise FatalCSVError(
     335                "Need at least columns student_id " +
     336                "or reg_number or matric_number for import!")
     337        if not 'level' in headerfields:
     338            raise FatalCSVError(
     339                "Need level for import!")
     340        # Check for fields to be ignored...
     341        not_ignored_fields = [x for x in headerfields
     342                              if not x.startswith('--')]
     343        if len(set(not_ignored_fields)) < len(not_ignored_fields):
     344            raise FatalCSVError(
     345                "Double headers: each column name may only appear once.")
     346        return True
     347
     348    def getParent(self, row, site):
     349        if not 'students' in site.keys():
     350            return None
     351        if 'student_id' in row.keys() and row['student_id']:
     352            if row['student_id'] in site['students']:
     353                student = site['students'][row['student_id']]
     354                return student['studycourse']
     355        elif 'reg_number' in row.keys() and row['reg_number']:
     356            reg_number = row['reg_number']
     357            #import pdb; pdb.set_trace()
     358            cat = queryUtility(ICatalog, name='students_catalog')
     359            results = list(
     360                cat.searchResults(reg_number=(reg_number, reg_number)))
     361            if results:
     362                return results[0]['studycourse']
     363        elif 'matric_number' in row.keys() and row['matric_number']:
     364            matric_number = row['matric_number']
     365            cat = queryUtility(ICatalog, name='students_catalog')
     366            results = list(
     367                cat.searchResults(matric_number=(matric_number, matric_number)))
     368            if results:
     369                return results[0]['studycourse']
     370        return None
     371
     372    def parentsExist(self, row, site):
     373        return self.getParent(row, site) is not None
     374
     375    def entryExists(self, row, site):
     376        return self.getEntry(row, site) is not None
     377
     378    def getEntry(self, row, site):
     379        studycourse = self.getParent(row, site)
     380        if studycourse is None:
     381            return None
     382        return studycourse.get(row['level'])
     383
     384    def addEntry(self, obj, row, site):
     385        parent = self.getParent(row, site)
     386        obj.level = int(row['level'])
     387        parent[row['level']] = obj
     388        return
     389
     390    def checkConversion(self, row, mode='ignore'):
     391        """Validates all values in row.
     392        """
     393        converter = IObjectConverter(self.iface)
     394        errs, inv_errs, conv_dict =  converter.fromStringDict(
     395            row, self.factory_name)
     396        # We have to check if level is a valid integer.
     397        # This is not by the converter.
     398        try:
     399            level = int(row['level'])
     400            if level not in range(0,600,10):
     401                errs.append(('level','no valid integer'))
     402        except ValueError:
     403            errs.append(('level','no integer'))
     404        return errs, inv_errs, conv_dict
  • main/waeup.sirp/trunk/src/waeup/sirp/students/studycourse.py

    r7533 r7536  
    7272
    7373class StudentStudyCourseFactory(grok.GlobalUtility):
    74     """A factory for students.
     74    """A factory for student study courses.
    7575    """
    7676    grok.implements(IFactory)
  • main/waeup.sirp/trunk/src/waeup/sirp/students/studylevel.py

    r7304 r7536  
    2121"""
    2222import grok
     23from zope.component.interfaces import IFactory
    2324from waeup.sirp.students.interfaces import (
    2425    IStudentStudyLevel, IStudentNavigation, ICourseTicket)
     
    5859StudentStudyLevel = attrs_to_fields(StudentStudyLevel)
    5960
     61class StudentStudyLevelFactory(grok.GlobalUtility):
     62    """A factory for student study levels.
     63    """
     64    grok.implements(IFactory)
     65    grok.name(u'waeup.StudentStudyLevel')
     66    title = u"Create a new student study level.",
     67    description = u"This factory instantiates new student study level instances."
     68
     69    def __call__(self, *args, **kw):
     70        return StudentStudyLevel()
     71
     72    def getInterfaces(self):
     73        return implementedBy(StudentStudyLevel)
     74
    6075class CourseTicket(grok.Model):
    6176    """This is a course ticket which allows the
  • main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_batching.py

    r7534 r7536  
    3131from waeup.sirp.university.department import Department
    3232from waeup.sirp.students.batching import (
    33     StudentProcessor, StudentStudyCourseProcessor)
     33    StudentProcessor, StudentStudyCourseProcessor,
     34    StudentStudyLevelProcessor)
    3435from waeup.sirp.students.student import Student
    3536from waeup.sirp.testing import FunctionalLayer, FunctionalTestCase
     
    6970
    7071STUDENT_HEADER_FIELDS_MIGRATION = STUDENT_SAMPLE_DATA_MIGRATION.split(
     72    '\n')[0].split(',')
     73
     74STUDYLEVEL_SAMPLE_DATA = open(
     75    os.path.join(os.path.dirname(__file__), 'sample_studylevel_data.csv'),
     76    'rb').read()
     77
     78STUDYLEVEL_HEADER_FIELDS = STUDYLEVEL_SAMPLE_DATA.split(
    7179    '\n')[0].split(',')
    7280
     
    212220        shutil.rmtree(os.path.dirname(fin_file))
    213221
     222
    214223class StudentStudyCourseImporterTest(FunctionalTestCase):
    215224
     
    218227    def setUp(self):
    219228        super(StudentStudyCourseImporterTest, self).setUp()
     229        self.dc_root = tempfile.mkdtemp()
     230        self.workdir = tempfile.mkdtemp()
    220231        app = University()
    221         self.dc_root = tempfile.mkdtemp()
    222232        app['datacenter'].setStoragePath(self.dc_root)
    223 
    224233        self.getRootFolder()['app'] = app
    225234        self.app = self.getRootFolder()['app']
    226235        setSite(app)
    227 
    228         self.workdir = tempfile.mkdtemp()
    229         self.importer = StudentStudyCourseProcessor()
    230         self.csv_file = os.path.join(
    231             self.workdir, 'sample_studycourse_data.csv')
    232         open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
    233236
    234237        # Import students with subobjects
     
    249252        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
    250253            self.certificate)
     254
     255        self.importer = StudentStudyCourseProcessor()
     256        self.csv_file = os.path.join(
     257            self.workdir, 'sample_studycourse_data.csv')
     258        open(self.csv_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
    251259        return
    252260
     
    283291        shutil.rmtree(os.path.dirname(fin_file))
    284292
     293class StudentStudyLevelImporterTest(FunctionalTestCase):
     294
     295    layer = FunctionalLayer
     296
     297    def setUp(self):
     298        super(StudentStudyLevelImporterTest, self).setUp()
     299        self.dc_root = tempfile.mkdtemp()
     300        self.workdir = tempfile.mkdtemp()
     301        app = University()
     302        app['datacenter'].setStoragePath(self.dc_root)
     303        self.getRootFolder()['app'] = app
     304        self.app = self.getRootFolder()['app']
     305        setSite(app)
     306
     307        # Import students with subobjects
     308        student_file = os.path.join(self.workdir, 'sample_student_data.csv')
     309        open(student_file, 'wb').write(STUDENT_SAMPLE_DATA)
     310        num, num_warns, fin_file, fail_file = StudentProcessor().doImport(
     311            student_file, STUDENT_HEADER_FIELDS)
     312        shutil.rmtree(os.path.dirname(fin_file))
     313
     314        # Populate university
     315        self.certificate = createObject('waeup.Certificate')
     316        self.certificate.code = 'CERT1'
     317        self.certificate.application_category = 'basic'
     318        self.certificate.start_level = 200
     319        self.certificate.end_level = 500
     320        self.app['faculties']['fac1'] = Faculty()
     321        self.app['faculties']['fac1']['dep1'] = Department()
     322        self.app['faculties']['fac1']['dep1'].certificates.addCertificate(
     323            self.certificate)
     324
     325        # Update study courses
     326        studycourse_file = os.path.join(
     327            self.workdir, 'sample_studycourse_data.csv')
     328        open(studycourse_file, 'wb').write(STUDYCOURSE_SAMPLE_DATA)
     329        importer = StudentStudyCourseProcessor()
     330        num, num_warns, fin_file, fail_file = importer.doImport(
     331            studycourse_file, STUDYCOURSE_HEADER_FIELDS,'update')
     332        shutil.rmtree(os.path.dirname(fin_file))
     333
     334        self.importer = StudentStudyLevelProcessor()
     335        self.csv_file = os.path.join(
     336            self.workdir, 'sample_studylevel_data.csv')
     337        open(self.csv_file, 'wb').write(STUDYLEVEL_SAMPLE_DATA)
     338
     339    def tearDown(self):
     340        super(StudentStudyLevelImporterTest, self).tearDown()
     341        shutil.rmtree(self.workdir)
     342        shutil.rmtree(self.dc_root)
     343        clearSite()
     344        return
     345
     346    def test_interface(self):
     347        # Make sure we fulfill the interface contracts.
     348        assert verifyObject(IBatchProcessor, self.importer) is True
     349        assert verifyClass(
     350            IBatchProcessor, StudentStudyLevelProcessor) is True
     351
     352    def test_import(self):
     353        num, num_warns, fin_file, fail_file = self.importer.doImport(
     354            self.csv_file, STUDYLEVEL_HEADER_FIELDS,'create')
     355        self.assertEqual(num_warns,2)
     356        assert self.importer.entryExists(
     357            dict(reg_number='1', level='100'), self.app) is True
     358        studylevel = self.importer.getEntry(
     359            dict(reg_number='1', level='100'), self.app)
     360        self.assertEqual(studylevel.__parent__.certificate.code, u'CERT1')
     361        self.assertEqual(studylevel.level_session, 2008)
     362        self.assertEqual(studylevel.level_verdict, 'A')
     363        self.assertEqual(studylevel.level, 100)
     364        shutil.rmtree(os.path.dirname(fin_file))
     365       
     366
    285367def test_suite():
    286368    suite = unittest.TestSuite()
    287369    for testcase in [
    288370        StudentImporterTest,StudentStudyCourseImporterTest,
    289         ]:
     371        StudentStudyLevelImporterTest,]:
    290372        suite.addTest(unittest.TestLoader().loadTestsFromTestCase(
    291373                testcase
     
    293375        )
    294376    return suite
     377
     378
Note: See TracChangeset for help on using the changeset viewer.