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

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: me at id
  • Date: 2009-01-15 01:29:07 UTC
  • mto: This revision was merged to the branch mainline in revision 1090.
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:branches%2Fstorm:1147
ivle.makeuser: Don't create a local.auth. It wasn't used anywhere, and seems
    to have only been there for historical reasons.
setup.configure: Remove svn_auth_local from the config.py boilerplate; it was
    used solely by ivle.makeuser.

Show diffs side-by-side

added added

removed removed

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