~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: William Grant
  • Date: 2009-02-27 04:47:06 UTC
  • Revision ID: grantw@unimelb.edu.au-20090227044706-w4infz8hr6ui3lve
SubjectsView is now only accessible by people associated with subjects.
GroupsView uses the offering's permission calculator.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# IVLE - Informatics Virtual Learning Environment
 
2
# Copyright (C) 2007-2009 The University of Melbourne
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 
 
18
# Author: Matt Giuca, Will Grant
 
19
 
 
20
"""
 
21
Database Classes and Utilities for Storm ORM
 
22
 
 
23
This module provides all of the classes which map to database tables.
 
24
It also provides miscellaneous utility functions for database interaction.
 
25
"""
 
26
 
 
27
import md5
 
28
import datetime
 
29
 
 
30
from storm.locals import create_database, Store, Int, Unicode, DateTime, \
 
31
                         Reference, ReferenceSet, Bool, Storm, Desc
 
32
from storm.exceptions import NotOneError
 
33
 
 
34
import ivle.conf
 
35
 
 
36
__all__ = ['get_store',
 
37
            'User',
 
38
            'Subject', 'Semester', 'Offering', 'Enrolment',
 
39
            'ProjectSet', 'Project', 'ProjectGroup', 'ProjectGroupMembership',
 
40
            'Exercise', 'Worksheet', 'WorksheetExercise',
 
41
            'ExerciseSave', 'ExerciseAttempt',
 
42
            'TestCase', 'TestSuite', 'TestSuiteVar'
 
43
        ]
 
44
 
 
45
def _kwarg_init(self, **kwargs):
 
46
    for k,v in kwargs.items():
 
47
        if k.startswith('_') or not hasattr(self.__class__, k):
 
48
            raise TypeError("%s got an unexpected keyword argument '%s'"
 
49
                % (self.__class__.__name__, k))
 
50
        setattr(self, k, v)
 
51
 
 
52
def get_conn_string():
 
53
    """
 
54
    Returns the Storm connection string, generated from the conf file.
 
55
    """
 
56
 
 
57
    clusterstr = ''
 
58
    if ivle.conf.db_user:
 
59
        clusterstr += ivle.conf.db_user
 
60
        if ivle.conf.db_password:
 
61
            clusterstr += ':' + ivle.conf.db_password
 
62
        clusterstr += '@'
 
63
 
 
64
    host = ivle.conf.db_host or 'localhost'
 
65
    port = ivle.conf.db_port or 5432
 
66
 
 
67
    clusterstr += '%s:%d' % (host, port)
 
68
 
 
69
    return "postgres://%s/%s" % (clusterstr, ivle.conf.db_dbname)
 
70
 
 
71
def get_store():
 
72
    """
 
73
    Open a database connection and transaction. Return a storm.store.Store
 
74
    instance connected to the configured IVLE database.
 
75
    """
 
76
    return Store(create_database(get_conn_string()))
 
77
 
 
78
# USERS #
 
79
 
 
80
class User(Storm):
 
81
    """
 
82
    Represents an IVLE user.
 
83
    """
 
84
    __storm_table__ = "login"
 
85
 
 
86
    id = Int(primary=True, name="loginid")
 
87
    login = Unicode()
 
88
    passhash = Unicode()
 
89
    state = Unicode()
 
90
    admin = Bool()
 
91
    unixid = Int()
 
92
    nick = Unicode()
 
93
    pass_exp = DateTime()
 
94
    acct_exp = DateTime()
 
95
    last_login = DateTime()
 
96
    svn_pass = Unicode()
 
97
    email = Unicode()
 
98
    fullname = Unicode()
 
99
    studentid = Unicode()
 
100
    settings = Unicode()
 
101
 
 
102
    __init__ = _kwarg_init
 
103
 
 
104
    def __repr__(self):
 
105
        return "<%s '%s'>" % (type(self).__name__, self.login)
 
106
 
 
107
    def authenticate(self, password):
 
108
        """Validate a given password against this user.
 
109
 
 
110
        Returns True if the given password matches the password hash for this
 
111
        User, False if it doesn't match, and None if there is no hash for the
 
112
        user.
 
113
        """
 
114
        if self.passhash is None:
 
115
            return None
 
116
        return self.hash_password(password) == self.passhash
 
117
 
 
118
    @property
 
119
    def password_expired(self):
 
120
        fieldval = self.pass_exp
 
121
        return fieldval is not None and datetime.datetime.now() > fieldval
 
122
 
 
123
    @property
 
124
    def account_expired(self):
 
125
        fieldval = self.acct_exp
 
126
        return fieldval is not None and datetime.datetime.now() > fieldval
 
127
 
 
128
    @property
 
129
    def valid(self):
 
130
        return self.state == 'enabled' and not self.account_expired
 
131
 
 
132
    def _get_enrolments(self, justactive):
 
133
        return Store.of(self).find(Enrolment,
 
134
            Enrolment.user_id == self.id,
 
135
            (Enrolment.active == True) if justactive else True,
 
136
            Enrolment.offering_id == Offering.id,
 
137
            Offering.semester_id == Semester.id,
 
138
            Offering.subject_id == Subject.id).order_by(
 
139
                Desc(Semester.year),
 
140
                Desc(Semester.semester),
 
141
                Desc(Subject.code)
 
142
            )
 
143
 
 
144
    def _set_password(self, password):
 
145
        if password is None:
 
146
            self.passhash = None
 
147
        else:
 
148
            self.passhash = unicode(User.hash_password(password))
 
149
    password = property(fset=_set_password)
 
150
 
 
151
    @property
 
152
    def subjects(self):
 
153
        return Store.of(self).find(Subject,
 
154
            Enrolment.user_id == self.id,
 
155
            Enrolment.active == True,
 
156
            Offering.id == Enrolment.offering_id,
 
157
            Subject.id == Offering.subject_id).config(distinct=True)
 
158
 
 
159
    # TODO: Invitations should be listed too?
 
160
    def get_groups(self, offering=None):
 
161
        preds = [
 
162
            ProjectGroupMembership.user_id == self.id,
 
163
            ProjectGroup.id == ProjectGroupMembership.project_group_id,
 
164
        ]
 
165
        if offering:
 
166
            preds.extend([
 
167
                ProjectSet.offering_id == offering.id,
 
168
                ProjectGroup.project_set_id == ProjectSet.id,
 
169
            ])
 
170
        return Store.of(self).find(ProjectGroup, *preds)
 
171
 
 
172
    @property
 
173
    def groups(self):
 
174
        return self.get_groups()
 
175
 
 
176
    @property
 
177
    def active_enrolments(self):
 
178
        '''A sanely ordered list of the user's active enrolments.'''
 
179
        return self._get_enrolments(True)
 
180
 
 
181
    @property
 
182
    def enrolments(self):
 
183
        '''A sanely ordered list of all of the user's enrolments.'''
 
184
        return self._get_enrolments(False) 
 
185
 
 
186
    @staticmethod
 
187
    def hash_password(password):
 
188
        return md5.md5(password).hexdigest()
 
189
 
 
190
    @classmethod
 
191
    def get_by_login(cls, store, login):
 
192
        """
 
193
        Get the User from the db associated with a given store and
 
194
        login.
 
195
        """
 
196
        return store.find(cls, cls.login == unicode(login)).one()
 
197
 
 
198
    def get_permissions(self, user):
 
199
        if user and user.admin or user is self:
 
200
            return set(['view', 'edit'])
 
201
        else:
 
202
            return set()
 
203
 
 
204
# SUBJECTS AND ENROLMENTS #
 
205
 
 
206
class Subject(Storm):
 
207
    __storm_table__ = "subject"
 
208
 
 
209
    id = Int(primary=True, name="subjectid")
 
210
    code = Unicode(name="subj_code")
 
211
    name = Unicode(name="subj_name")
 
212
    short_name = Unicode(name="subj_short_name")
 
213
    url = Unicode()
 
214
 
 
215
    offerings = ReferenceSet(id, 'Offering.subject_id')
 
216
 
 
217
    __init__ = _kwarg_init
 
218
 
 
219
    def __repr__(self):
 
220
        return "<%s '%s'>" % (type(self).__name__, self.short_name)
 
221
 
 
222
    def get_permissions(self, user):
 
223
        perms = set()
 
224
        if user is not None:
 
225
            perms.add('view')
 
226
            if user.admin:
 
227
                perms.add('edit')
 
228
        return perms
 
229
 
 
230
class Semester(Storm):
 
231
    __storm_table__ = "semester"
 
232
 
 
233
    id = Int(primary=True, name="semesterid")
 
234
    year = Unicode()
 
235
    semester = Unicode()
 
236
    state = Unicode()
 
237
 
 
238
    offerings = ReferenceSet(id, 'Offering.semester_id')
 
239
    enrolments = ReferenceSet(id,
 
240
                              'Offering.semester_id',
 
241
                              'Offering.id',
 
242
                              'Enrolment.offering_id')
 
243
 
 
244
    __init__ = _kwarg_init
 
245
 
 
246
    def __repr__(self):
 
247
        return "<%s %s/%s>" % (type(self).__name__, self.year, self.semester)
 
248
 
 
249
class Offering(Storm):
 
250
    __storm_table__ = "offering"
 
251
 
 
252
    id = Int(primary=True, name="offeringid")
 
253
    subject_id = Int(name="subject")
 
254
    subject = Reference(subject_id, Subject.id)
 
255
    semester_id = Int(name="semesterid")
 
256
    semester = Reference(semester_id, Semester.id)
 
257
    groups_student_permissions = Unicode()
 
258
 
 
259
    enrolments = ReferenceSet(id, 'Enrolment.offering_id')
 
260
    members = ReferenceSet(id,
 
261
                           'Enrolment.offering_id',
 
262
                           'Enrolment.user_id',
 
263
                           'User.id')
 
264
    project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
 
265
 
 
266
    worksheets = ReferenceSet(id, 
 
267
        'Worksheet.offering_id', 
 
268
        order_by="Worksheet.seq_no"
 
269
    )
 
270
 
 
271
    __init__ = _kwarg_init
 
272
 
 
273
    def __repr__(self):
 
274
        return "<%s %r in %r>" % (type(self).__name__, self.subject,
 
275
                                  self.semester)
 
276
 
 
277
    def enrol(self, user, role=u'student'):
 
278
        '''Enrol a user in this offering.'''
 
279
        enrolment = Store.of(self).find(Enrolment,
 
280
                               Enrolment.user_id == user.id,
 
281
                               Enrolment.offering_id == self.id).one()
 
282
 
 
283
        if enrolment is None:
 
284
            enrolment = Enrolment(user=user, offering=self)
 
285
            self.enrolments.add(enrolment)
 
286
 
 
287
        enrolment.active = True
 
288
        enrolment.role = role
 
289
 
 
290
    def unenrol(self, user):
 
291
        '''Unenrol a user from this offering.'''
 
292
        enrolment = Store.of(self).find(Enrolment,
 
293
                               Enrolment.user_id == user.id,
 
294
                               Enrolment.offering_id == self.id).one()
 
295
        Store.of(enrolment).remove(enrolment)
 
296
 
 
297
    def get_permissions(self, user):
 
298
        perms = set()
 
299
        if user is not None:
 
300
            enrolment = self.get_enrolment(user)
 
301
            if enrolment or user.admin:
 
302
                perms.add('view')
 
303
            if (enrolment and enrolment.role in (u'tutor', u'lecturer')) \
 
304
               or user.admin:
 
305
                perms.add('edit')
 
306
        return perms
 
307
 
 
308
    def get_enrolment(self, user):
 
309
        try:
 
310
            enrolment = self.enrolments.find(user=user).one()
 
311
        except NotOneError:
 
312
            enrolment = None
 
313
 
 
314
        return enrolment
 
315
 
 
316
class Enrolment(Storm):
 
317
    __storm_table__ = "enrolment"
 
318
    __storm_primary__ = "user_id", "offering_id"
 
319
 
 
320
    user_id = Int(name="loginid")
 
321
    user = Reference(user_id, User.id)
 
322
    offering_id = Int(name="offeringid")
 
323
    offering = Reference(offering_id, Offering.id)
 
324
    role = Unicode()
 
325
    notes = Unicode()
 
326
    active = Bool()
 
327
 
 
328
    @property
 
329
    def groups(self):
 
330
        return Store.of(self).find(ProjectGroup,
 
331
                ProjectSet.offering_id == self.offering.id,
 
332
                ProjectGroup.project_set_id == ProjectSet.id,
 
333
                ProjectGroupMembership.project_group_id == ProjectGroup.id,
 
334
                ProjectGroupMembership.user_id == self.user.id)
 
335
 
 
336
    __init__ = _kwarg_init
 
337
 
 
338
    def __repr__(self):
 
339
        return "<%s %r in %r>" % (type(self).__name__, self.user,
 
340
                                  self.offering)
 
341
 
 
342
# PROJECTS #
 
343
 
 
344
class ProjectSet(Storm):
 
345
    __storm_table__ = "project_set"
 
346
 
 
347
    id = Int(name="projectsetid", primary=True)
 
348
    offering_id = Int(name="offeringid")
 
349
    offering = Reference(offering_id, Offering.id)
 
350
    max_students_per_group = Int()
 
351
 
 
352
    projects = ReferenceSet(id, 'Project.project_set_id')
 
353
    project_groups = ReferenceSet(id, 'ProjectGroup.project_set_id')
 
354
 
 
355
    __init__ = _kwarg_init
 
356
 
 
357
    def __repr__(self):
 
358
        return "<%s %d in %r>" % (type(self).__name__, self.id,
 
359
                                  self.offering)
 
360
 
 
361
class Project(Storm):
 
362
    __storm_table__ = "project"
 
363
 
 
364
    id = Int(name="projectid", primary=True)
 
365
    synopsis = Unicode()
 
366
    url = Unicode()
 
367
    project_set_id = Int(name="projectsetid")
 
368
    project_set = Reference(project_set_id, ProjectSet.id)
 
369
    deadline = DateTime()
 
370
 
 
371
    __init__ = _kwarg_init
 
372
 
 
373
    def __repr__(self):
 
374
        return "<%s '%s' in %r>" % (type(self).__name__, self.synopsis,
 
375
                                  self.project_set.offering)
 
376
 
 
377
class ProjectGroup(Storm):
 
378
    __storm_table__ = "project_group"
 
379
 
 
380
    id = Int(name="groupid", primary=True)
 
381
    name = Unicode(name="groupnm")
 
382
    project_set_id = Int(name="projectsetid")
 
383
    project_set = Reference(project_set_id, ProjectSet.id)
 
384
    nick = Unicode()
 
385
    created_by_id = Int(name="createdby")
 
386
    created_by = Reference(created_by_id, User.id)
 
387
    epoch = DateTime()
 
388
 
 
389
    members = ReferenceSet(id,
 
390
                           "ProjectGroupMembership.project_group_id",
 
391
                           "ProjectGroupMembership.user_id",
 
392
                           "User.id")
 
393
 
 
394
    __init__ = _kwarg_init
 
395
 
 
396
    def __repr__(self):
 
397
        return "<%s %s in %r>" % (type(self).__name__, self.name,
 
398
                                  self.project_set.offering)
 
399
 
 
400
class ProjectGroupMembership(Storm):
 
401
    __storm_table__ = "group_member"
 
402
    __storm_primary__ = "user_id", "project_group_id"
 
403
 
 
404
    user_id = Int(name="loginid")
 
405
    user = Reference(user_id, User.id)
 
406
    project_group_id = Int(name="groupid")
 
407
    project_group = Reference(project_group_id, ProjectGroup.id)
 
408
 
 
409
    __init__ = _kwarg_init
 
410
 
 
411
    def __repr__(self):
 
412
        return "<%s %r in %r>" % (type(self).__name__, self.user,
 
413
                                  self.project_group)
 
414
 
 
415
# WORKSHEETS AND EXERCISES #
 
416
 
 
417
class Exercise(Storm):
 
418
    __storm_table__ = "exercise"
 
419
    id = Unicode(primary=True, name="identifier")
 
420
    name = Unicode()
 
421
    description = Unicode()
 
422
    partial = Unicode()
 
423
    solution = Unicode()
 
424
    include = Unicode()
 
425
    num_rows = Int()
 
426
 
 
427
    worksheets = ReferenceSet(id,
 
428
        'WorksheetExercise.exercise_id',
 
429
        'WorksheetExercise.worksheet_id',
 
430
        'Worksheet.id'
 
431
    )
 
432
    
 
433
    test_suites = ReferenceSet(id, 'TestSuite.exercise_id')
 
434
 
 
435
    __init__ = _kwarg_init
 
436
 
 
437
    def __repr__(self):
 
438
        return "<%s %s>" % (type(self).__name__, self.name)
 
439
 
 
440
    def get_permissions(self, user):
 
441
        perms = set()
 
442
        if user is not None:
 
443
            if user.admin:
 
444
                perms.add('edit')
 
445
                perms.add('view')
 
446
        return perms
 
447
 
 
448
class Worksheet(Storm):
 
449
    __storm_table__ = "worksheet"
 
450
 
 
451
    id = Int(primary=True, name="worksheetid")
 
452
    offering_id = Int(name="offeringid")
 
453
    identifier = Unicode()
 
454
    name = Unicode()
 
455
    assessable = Bool()
 
456
    data = Unicode()
 
457
    seq_no = Int()
 
458
    format = Unicode()
 
459
 
 
460
    attempts = ReferenceSet(id, "ExerciseAttempt.worksheetid")
 
461
    offering = Reference(offering_id, 'Offering.id')
 
462
 
 
463
    all_worksheet_exercises = ReferenceSet(id,
 
464
        'WorksheetExercise.worksheet_id')
 
465
 
 
466
    # Use worksheet_exercises to get access to the *active* WorksheetExercise
 
467
    # objects binding worksheets to exercises. This is required to access the
 
468
    # "optional" field.
 
469
    @property
 
470
    def worksheet_exercises(self):
 
471
        return self.all_worksheet_exercises.find(active=True)
 
472
 
 
473
    __init__ = _kwarg_init
 
474
 
 
475
    def __repr__(self):
 
476
        return "<%s %s>" % (type(self).__name__, self.name)
 
477
 
 
478
    # XXX Refactor this - make it an instance method of Subject rather than a
 
479
    # class method of Worksheet. Can't do that now because Subject isn't
 
480
    # linked referentially to the Worksheet.
 
481
    @classmethod
 
482
    def get_by_name(cls, store, subjectname, worksheetname):
 
483
        """
 
484
        Get the Worksheet from the db associated with a given store, subject
 
485
        name and worksheet name.
 
486
        """
 
487
        return store.find(cls, cls.subject == unicode(subjectname),
 
488
            cls.name == unicode(worksheetname)).one()
 
489
 
 
490
    def remove_all_exercises(self, store):
 
491
        """
 
492
        Remove all exercises from this worksheet.
 
493
        This does not delete the exercises themselves. It just removes them
 
494
        from the worksheet.
 
495
        """
 
496
        store.find(WorksheetExercise,
 
497
            WorksheetExercise.worksheet == self).remove()
 
498
            
 
499
    def get_permissions(self, user):
 
500
        return self.offering.get_permissions(user)
 
501
 
 
502
class WorksheetExercise(Storm):
 
503
    __storm_table__ = "worksheet_exercise"
 
504
    
 
505
    id = Int(primary=True, name="ws_ex_id")
 
506
 
 
507
    worksheet_id = Int(name="worksheetid")
 
508
    worksheet = Reference(worksheet_id, Worksheet.id)
 
509
    exercise_id = Unicode(name="exerciseid")
 
510
    exercise = Reference(exercise_id, Exercise.id)
 
511
    optional = Bool()
 
512
    active = Bool()
 
513
    seq_no = Int()
 
514
    
 
515
    saves = ReferenceSet(id, "ExerciseSave.ws_ex_id")
 
516
    attempts = ReferenceSet(id, "ExerciseAttempt.ws_ex_id")
 
517
 
 
518
    __init__ = _kwarg_init
 
519
 
 
520
    def __repr__(self):
 
521
        return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
 
522
                                  self.worksheet.identifier)
 
523
 
 
524
    def get_permissions(self, user):
 
525
        return self.worksheet.get_permissions(user)
 
526
 
 
527
class ExerciseSave(Storm):
 
528
    """
 
529
    Represents a potential solution to an exercise that a user has submitted
 
530
    to the server for storage.
 
531
    A basic ExerciseSave is just the current saved text for this exercise for
 
532
    this user (doesn't count towards their attempts).
 
533
    ExerciseSave may be extended with additional semantics (such as
 
534
    ExerciseAttempt).
 
535
    """
 
536
    __storm_table__ = "exercise_save"
 
537
    __storm_primary__ = "ws_ex_id", "user_id"
 
538
 
 
539
    ws_ex_id = Int(name="ws_ex_id")
 
540
    worksheet_exercise = Reference(ws_ex_id, "WorksheetExercise.id")
 
541
 
 
542
    user_id = Int(name="loginid")
 
543
    user = Reference(user_id, User.id)
 
544
    date = DateTime()
 
545
    text = Unicode()
 
546
 
 
547
    __init__ = _kwarg_init
 
548
 
 
549
    def __repr__(self):
 
550
        return "<%s %s by %s at %s>" % (type(self).__name__,
 
551
            self.exercise.name, self.user.login, self.date.strftime("%c"))
 
552
 
 
553
class ExerciseAttempt(ExerciseSave):
 
554
    """
 
555
    An ExerciseAttempt is a special case of an ExerciseSave. Like an
 
556
    ExerciseSave, it constitutes exercise solution data that the user has
 
557
    submitted to the server for storage.
 
558
    In addition, it contains additional information about the submission.
 
559
    complete - True if this submission was successful, rendering this exercise
 
560
        complete for this user.
 
561
    active - True if this submission is "active" (usually true). Submissions
 
562
        may be de-activated by privileged users for special reasons, and then
 
563
        they won't count (either as a penalty or success), but will still be
 
564
        stored.
 
565
    """
 
566
    __storm_table__ = "exercise_attempt"
 
567
    __storm_primary__ = "ws_ex_id", "user_id", "date"
 
568
 
 
569
    # The "text" field is the same but has a different name in the DB table
 
570
    # for some reason.
 
571
    text = Unicode(name="attempt")
 
572
    complete = Bool()
 
573
    active = Bool()
 
574
    
 
575
    def get_permissions(self, user):
 
576
        return set(['view']) if user is self.user else set()
 
577
  
 
578
class TestSuite(Storm):
 
579
    """A Testsuite acts as a container for the test cases of an exercise."""
 
580
    __storm_table__ = "test_suite"
 
581
    __storm_primary__ = "exercise_id", "suiteid"
 
582
    
 
583
    suiteid = Int()
 
584
    exercise_id = Unicode(name="exerciseid")
 
585
    description = Unicode()
 
586
    seq_no = Int()
 
587
    function = Unicode()
 
588
    stdin = Unicode()
 
589
    exercise = Reference(exercise_id, Exercise.id)
 
590
    test_cases = ReferenceSet(suiteid, 'TestCase.suiteid')
 
591
    variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid')
 
592
 
 
593
class TestCase(Storm):
 
594
    """A TestCase is a member of a TestSuite.
 
595
    
 
596
    It contains the data necessary to check if an exercise is correct"""
 
597
    __storm_table__ = "test_case"
 
598
    __storm_primary__ = "testid", "suiteid"
 
599
    
 
600
    testid = Int()
 
601
    suiteid = Int()
 
602
    suite = Reference(suiteid, "TestSuite.suiteid")
 
603
    passmsg = Unicode()
 
604
    failmsg = Unicode()
 
605
    test_default = Unicode()
 
606
    seq_no = Int()
 
607
    
 
608
    parts = ReferenceSet(testid, "TestCasePart.testid")
 
609
    
 
610
    __init__ = _kwarg_init
 
611
 
 
612
class TestSuiteVar(Storm):
 
613
    """A container for the arguments of a Test Suite"""
 
614
    __storm_table__ = "suite_variable"
 
615
    __storm_primary__ = "varid"
 
616
    
 
617
    varid = Int()
 
618
    suiteid = Int()
 
619
    var_name = Unicode()
 
620
    var_value = Unicode()
 
621
    var_type = Unicode()
 
622
    arg_no = Int()
 
623
    
 
624
    suite = Reference(suiteid, "TestSuite.suiteid")
 
625
    
 
626
    __init__ = _kwarg_init
 
627
    
 
628
class TestCasePart(Storm):
 
629
    """A container for the test elements of a Test Case"""
 
630
    __storm_table__ = "test_case_part"
 
631
    __storm_primary__ = "partid"
 
632
    
 
633
    partid = Int()
 
634
    testid = Int()
 
635
    
 
636
    part_type = Unicode()
 
637
    test_type = Unicode()
 
638
    data = Unicode()
 
639
    filename = Unicode()
 
640
    
 
641
    test = Reference(testid, "TestCase.testid")
 
642
    
 
643
    __init__ = _kwarg_init