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

« back to all changes in this revision

Viewing changes to bin/ivle-addexercise

  • Committer: mattgiuca
  • Date: 2008-08-18 12:15:25 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:1027
Tutorial: Added new feature - previous attempt viewing. Allows users to see
    code they have previously submitted to tutorials.
    A new button ("View previous attempts") appears on each exercise box.
    This uses the getattempts and getattempt Ajax services checked in
    previously.
Note once again: Students are not (for the moment) able to see deactivated
attempts (this is a conservative approach - the ability to see deactivated
attempts can be turned on by setting HISTORY_ALLOW_INACTIVE = True in
tutorialservice).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
# IVLE - Informatics Virtual Learning Environment
3
 
# Copyright (C) 2007-2009 The University of Melbourne
4
 
#
5
 
# This program is free software; you can redistribute it and/or modify
6
 
# it under the terms of the GNU General Public License as published by
7
 
# the Free Software Foundation; either version 2 of the License, or
8
 
# (at your option) any later version.
9
 
#
10
 
# This program is distributed in the hope that it will be useful,
11
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
# GNU General Public License for more details.
14
 
#
15
 
# You should have received a copy of the GNU General Public License
16
 
# along with this program; if not, write to the Free Software
17
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 
19
 
# Author:  Nicholas Chadwick
20
 
 
21
 
"""Script to upload an exercise file into the database"""
22
 
 
23
 
import os, sys
24
 
import xml.dom.minidom as minidom
25
 
 
26
 
from ivle.database import Exercise, TestSuite, TestCase, TestSuiteVar, TestCasePart, get_store
27
 
 
28
 
class XMLMalformedError(Exception):
29
 
    """Error thrown when encountering malformed data."""
30
 
    
31
 
    def __init__(self, text):
32
 
        self.msg = text
33
 
 
34
 
def getTextData(element):
35
 
    """ Get the text and cdata inside an element
36
 
    Leading and trailing whitespace are stripped
37
 
    """
38
 
    data = ''
39
 
    for child in element.childNodes:
40
 
        if child.nodeType == child.CDATA_SECTION_NODE:
41
 
            data += child.data
42
 
        elif child.nodeType == child.TEXT_NODE:
43
 
            data += child.data
44
 
        else:
45
 
            data += child.toxml()
46
 
 
47
 
    return unicode(data.strip())
48
 
 
49
 
def add_var(store, var_type, var_name=u"", var_value=u"", arg_no=0):
50
 
    """Given an var node, parse it into a storm object."""
51
 
    new_var = TestSuiteVar()
52
 
    new_var.var_name = unicode(var_name)
53
 
    new_var.var_value = unicode(var_value)
54
 
    new_var.var_type = unicode(var_type)
55
 
    new_var.arg_no = arg_no
56
 
    store.add(new_var)
57
 
    return new_var
58
 
 
59
 
def add_test_suite(suite_node, suite_num, store):
60
 
    """Given a test suite element, get all the cases it contains."""
61
 
    cases = []
62
 
    case_num = 0
63
 
    for case_node in suite_node.getElementsByTagName('function'):
64
 
        case_num += 1
65
 
        cases.append(add_test_case(case_node, case_num, store))
66
 
 
67
 
    ## ALLOWED TAGS ##
68
 
    # stdin     - Stdin for the suite - Unique - Text inside element
69
 
    # file      - File to add to the filespace - Name - List
70
 
    # var       - Variable for the suite - Name/Value - List
71
 
    # arg       - Argument to functions - Name/Value - ORDERED List
72
 
    # exception - Allowed exception name - Name - List
73
 
    # function  - An actual test case
74
 
    suite_vars = []
75
 
    
76
 
    # Add file nodes
77
 
    file_nodes = suite_node.getElementsByTagName('file')
78
 
    for file_node in file_nodes:
79
 
        suite_vars.append(add_var(store, 'file', file_node.getAttribute('name')))
80
 
    
81
 
    # Add vars
82
 
    var_nodes = suite_node.getElementsByTagName('var')
83
 
    for var_node in var_nodes:
84
 
        var_name = var_node.getAttribute('name')
85
 
        var_value = var_node.getAttribute('value')
86
 
        suite_vars.append(add_var(store, 'var', var_name, var_value))
87
 
    
88
 
    # Args need to be numbered as they are found, as this order matters
89
 
    arg_num = 0
90
 
    for arg_node in suite_node.getElementsByTagName('arg'):
91
 
        suite_vars.append(add_var(store, 'arg', arg_node.getAttribute('name'),
92
 
                          arg_node.getAttribute('value'), arg_num))
93
 
        arg_num += 1
94
 
         
95
 
    # Add allowed exceptions
96
 
    exception_nodes = suite_node.getElementsByTagName('exception')
97
 
    for exception_node in exception_nodes:
98
 
        name = exception_node.getAttribute('name')
99
 
        suite_vars.append(add_var(store, 'exception', name))
100
 
    
101
 
    # Can only have 0-1 stdin elements
102
 
    stdin = suite_node.getElementsByTagName('stdin')
103
 
    if len(stdin) > 1:
104
 
        raise XMLMalformedError('Too many stdin tags found.')
105
 
    if stdin:
106
 
        stdin = getTextData(stdin[0])
107
 
    else:
108
 
        stdin = ""
109
 
    
110
 
    new_suite = TestSuite()
111
 
    new_suite.description = unicode(suite_node.getAttribute('name'))
112
 
    new_suite.seq_no = suite_num
113
 
    new_suite.function = unicode(suite_node.getAttribute('function'))
114
 
    new_suite.stdin = unicode(stdin)
115
 
    for testcase in cases:
116
 
        new_suite.test_cases.add(testcase)
117
 
    for var in suite_vars:
118
 
        new_suite.variables.add(var)
119
 
    store.add(new_suite)
120
 
    return new_suite
121
 
 
122
 
def add_part(store, element_type, test_type, data, filename=u""):
123
 
    new_part = TestCasePart()
124
 
    new_part.element_type = element_type
125
 
    new_part.test_type = test_type
126
 
    new_part.data = data
127
 
    new_part.filename = unicode(filename)
128
 
    store.add(new_part)
129
 
    return new_part
130
 
 
131
 
def add_test_case(case_node, case_num, store):
132
 
    """Given a test case node, parse it int a storm object."""
133
 
    
134
 
    ## ALLOWED TAGS ##
135
 
    # A function is allowed to contain the following elements 
136
 
    # stdout
137
 
    # stderr
138
 
    # result
139
 
    # exception
140
 
    # file
141
 
    # code
142
 
    allowed_parts = ['stdout', 'stderr', 'result', 'exception', 'file', 'code']
143
 
    parts = []
144
 
    for child_node in case_node.childNodes:
145
 
        if child_node.nodeType != child_node.ELEMENT_NODE:
146
 
            continue
147
 
        
148
 
        if child_node.tagName == 'file':
149
 
            part_type = 'file'
150
 
            test_type = child_node.getAttribute('type')
151
 
            data = getTextData(child_node)
152
 
            filename = child_node.getAttribute('name')
153
 
            if filename == "":
154
 
                raise XMLMalformedException('file tag must have names')
155
 
            parts.append(add_part(store, element_type, test_type, data,
156
 
                                        filename))
157
 
            
158
 
        elif child_node.tagName in allowed_parts:
159
 
            part_type = child_node.tagName
160
 
            test_type = child_node.getAttribute('type')
161
 
            data = getTextData(child_node)    
162
 
            parts.append(add_part(store, part_type, test_type, data))
163
 
 
164
 
    #Now create the object to hold the data
165
 
    new_test_case = TestCase()
166
 
    new_test_case.passmsg = unicode(case_node.getAttribute(u'pass'))
167
 
    new_test_case.failmsg = unicode(case_node.getAttribute(u'fail'))
168
 
    new_test_case.test_default = unicode(case_node.getAttribute(u'default'))
169
 
    new_test_case.seq_no = case_num
170
 
    store.add(new_test_case)
171
 
    for part in parts:
172
 
        new_test_case.parts.add(part)
173
 
    return new_test_case
174
 
 
175
 
xmlfile = sys.argv[1]
176
 
try:
177
 
    filedom = minidom.parse(xmlfile)
178
 
except IOError, e:
179
 
    sys.exit('ivle-addexercise: error opening file ' + xmlfile + ': ' + e[1])
180
 
 
181
 
 
182
 
for child in filedom.childNodes:
183
 
    if child.nodeType == child.ELEMENT_NODE and child.tagName == 'exercise':
184
 
        exercise = child
185
 
    else:
186
 
        sys.exit('ivle-addexercise: error parsing XML: root node must be "exercise"')
187
 
 
188
 
exercisename = exercise.getAttribute('name')
189
 
rows = exercise.getAttribute('rows')
190
 
solution = None
191
 
partial_solution = None
192
 
include_code = None
193
 
description = None
194
 
test_suite_nodes = []
195
 
for child in exercise.childNodes:
196
 
    if child.nodeType != child.ELEMENT_NODE:
197
 
        continue
198
 
    if child.tagName == 'solution':
199
 
        if solution is not None:
200
 
            sys.exit('ivle-addexercise: error parsing XML: multiple "solution" nodes')
201
 
        solution = getTextData(child)
202
 
    elif child.tagName == 'include':
203
 
        if include_code is not None:
204
 
            sys.exit('ivle-addexercise: error parsing XML: multiple "include" nodes')
205
 
        include_code = getTextData(child)
206
 
    elif child.tagName == 'partial':
207
 
        if partial_solution is not None:
208
 
            sys.exit('ivle-addexercise: error parsing XML: multiple "include" nodes')
209
 
        partial_solution = getTextData(child)
210
 
    elif child.tagName == 'case':
211
 
        test_suite_nodes.append(child)
212
 
    elif child.tagName == 'desc':
213
 
        description = getTextData(child)
214
 
 
215
 
if solution is None:
216
 
    sys.exit("ivle-addexercise: error parsing XML: No solution given")
217
 
if len(test_suite_nodes) == 0:
218
 
    sys.exit("ivle-addexercise: error parsing XML:")
219
 
 
220
 
store = get_store()
221
 
new_exercise = Exercise()
222
 
new_exercise.id = unicode(xmlfile)
223
 
new_exercise.name = exercisename
224
 
new_exercise.num_rows = int(rows)
225
 
new_exercise.partial = partial_solution
226
 
new_exercise.solution = solution
227
 
new_exercise.include = include_code
228
 
new_exercise.description = description
229
 
new_exercise.partial = partial_solution
230
 
store.add(new_exercise)
231
 
suite_num = 0
232
 
for suite in test_suite_nodes:
233
 
    new_exercise.test_suites.add(add_test_suite(suite, suite_num, store))
234
 
    suite_num += 1
235
 
 
236
 
store.add(new_exercise)
237
 
store.commit()