· 7 years ago · Nov 28, 2018, 12:00 PM
1"""
2Created on 17/07/2012
3"""
4linesep = "\n"
5import os.path, os
6
7class enrol(object):
8 """A Python class named Enrol.
9
10 """
11
12
13 def __init__(self, datadir = 'data'): ########################################################### CLENAUP : remove default value
14 """Constructor
15 It accepts one (and only one) argument, i.e. the data directory where
16 enrolment records are kept. When the object is constructed, it should
17 read enrolment records from the specified directory.
18 """
19
20 self.datadir = datadir
21 # Lambda: Create a filepath string and read_table list from filename
22 fp_and_t = lambda fn: (os.path.join(datadir,fn), \
23 read_table(os.path.join(datadir,fn)))
24 # file_path, table
25 (self.sub_fp,self.sub_table) = fp_and_t('SUBJECTS')
26 (self.cla_fp,self.cla_table) = fp_and_t('CLASSES')
27 (self.ven_fp,self.ven_table) = fp_and_t('VENUES')
28
29
30 self.stu_dict = {}
31 # Create a dict of student lists with Key being the Class ID
32 for row in self.cla_table:
33 # row[0] being the Class ID,
34 try: self.students[row[0]] = read_table(row[0]+'.roll')
35 except:pass
36
37
38
39 def subjects(self):
40 """Returns unordered list of all subject codes in the enrolment system.
41 """
42 try: return [row[0] for row in self.sub_table]
43 # Nothing in row[0]? return an empty list. - Shouldn't ever happen...
44 except IndexError: return []
45
46 def subject_name(self,sub_code):
47 """
48 argument: a subject code (string).
49 Returns a string which is the name of the specified subject.
50 Raise KeyError if the specified subject code does not exist.
51 """
52 # Filter with a lambda that uses a pythonic ternary operator.
53 # Filter the table for rows where subject code == sub_code.
54 # Returns the subject name field from the first(only) match.
55 try: return filter(lambda sc: True if sc[0] == sub_code else False, \
56 self.sub_table).pop()[1]
57 except IndexError: raise KeyError
58
59
60 def classes(self,sub_code):
61 """
62 argument: a subject code (string).
63 Returns a list of class codes for the specified subject.
64 Raise KeyError if the specified subject code does not exist.
65 """
66 # For each row, append the row, if it contains the subject code.
67 rows_w_sc = filter(lambda sc: True if sc[1] == sub_code else False, \
68 self.cla_table)
69
70 # Nothing in the list? Throw a KeyError.
71 if (len(rows_w_sc) == 0): raise KeyError
72
73 # Return a list of only the class codes.
74 return [row[1] for row in rows_w_sc]
75
76
77 def class_info(self, cla_code):
78 """
79 argument: a class code (string).
80 Returns class information in a tuple of the form (subjectcode, time,
81 venue, tutor, students). The first four elements are strings.
82 The last item is a list of the student IDs enrolled in the class.
83 There is no specified order of the student IDs. Raise KeyError if the
84 specified class code does not exist.
85 """
86 # Get the class row from the class table.
87 try:cla_row = filter(lambda cc: True if cc[0] == cla_code else False, \
88 self.cla_table)[0]
89
90
91 except IndexError: raise KeyError
92
93 #Class ID (AKA cla_row[0]) being the key.
94 students = self.stu_dict[cla_row[0]]
95
96 # (subject id, time, venue, tutor, students)
97 return (cla_row[1],cla_row[2],cla_row[3],cla_row[4],students)
98
99
100 def check_student(self, stu_id, sub_code = None):
101 """arguments: student ID (string), subject code (string)<optional>
102 If a subject code is specified, returns the class code of the class
103 in which the student is enrolled for that subject;
104 if student isn't enrolled in any class of that subject, return None.
105
106 If no subject code is specified, returns list of zero or more
107 class codes the student is enrolled in across all possible subjects.
108 """
109
110 stu_classes = []
111 for cla_id in self.stu_dict:
112 for stu in self.stu_dict[cla_id]:
113 if stu == stu_id:
114 stu_classes.append(cla_id)
115 break
116
117 if sub_code == None: return stu_classes
118 else:
119 pass # TODO: ADD Additional use cases ############################################################# TODO
120
121
122 def enrol(self, stu_id, cla_code):
123 """arguments: a student ID (string) and a class code (string).
124 Returns 1 if successful, None if not. Before attempting to enrol a student into a class, it checks whether the
125 number of stu_dict in the class is less than the capacity of the venue of the class. If not, then there is no space in
126 the class and it fails. Otherwise, if the student is enrolled in any class(es) (including the specified class to be
127 enrolled into) in the same subject as the specified class, the student is removed from the current enrolled class(es)
128 before being placed into the new one (i.e. the one specified by the second argument).
129 Raise KeyError if the specified class code does not exist.
130 For better modularisation, you should write internal methods to be used by defined methods for common tasks.
131 Names for internal methods should start with a single underscore (_), to distinguish from "public" methods.
132 A possible example of your class in use, showing arguments accepted and results returned, is below:
133 >>> import enrol
134 >>> e = enrol.Enrol("/path/to/data")
135 >>> e.subjects()
136 ['bw101', 'bw110', 'bw232', 'bw290', 'bw660']
137 >>> e.subject_name('bw110')
138 "Introductory Basketweaving 1"
139 >>> e.classes('bw232')
140 ['bw232.1', 'bw232.2']
141 >>> e.class_info('bw232.1')
142 ('bw232', 'Mon 10.30', '66.3.1', 'Jim Derrida', ['1122345','1954231'])
143 >>> e.check_student('1122345','bw232')
144 "bw232.1"
145 >>> e.check_student('1122345')
146 ['bw232.1', 'bw660.group1', 'bw290_A']
147 >>> e.enrol('1122345','bw232.2')
148 """
149 pass
150
151
152
153
154
155
156
157
158
159
160def read_lines(filename):
161 """Returns a list of all lines in the specified file in its original order,
162 except for lines starting with a # or lines containing nothing.
163 """
164 fileh = open(filename,"r")
165 lines = []
166 for line in fileh.readlines():
167 #Should I trim the lines? YES
168 line = line.strip()
169 try:
170 if line[0] == "#":
171 pass
172 else:
173 lines.append(line)
174 except IndexError:
175 pass
176
177 fileh.close
178 return lines
179
180
181def read_table(filename):
182 """Reads a file of colon-delimited lines and returns a list of
183 lists in its original order, with each line being represented
184 as a list of strings, split on colons.
185 """
186 rows = read_lines(filename)
187 table = []
188 for row in rows:
189 table.append(row.split(":"))
190 return table
191
192
193
194def write_lines(filename,lines):
195 """Writes a list of strings safely to the specified file.
196 Overwrites the file if it already exists. If an error occurs
197 during writing (i.e. an exception is caught), it swallows the
198 exception and returns 0. Otherwise, it returns 1.
199 """
200 try:
201 fileh = open(filename,"w")
202 # Could put the rest outside of the try block... but no need.
203 for ln,line in enumerate(lines):
204 # On the last line, don't add an extra line separator.
205 if ln+1 == len(lines):
206 fileh.write(line)
207 # Every line before, do add it.
208 else:
209 fileh.write(line + linesep)
210 fileh.close()
211 return 1
212 except:
213 return 0