]> git.llucax.com Git - software/sercom-old.git/blob - src/sercom/sqlo.py
Bugfix: faltaba copiar las entradas al chroot de las pruebas.
[software/sercom-old.git] / src / sercom / sqlo.py
1 from sqlobject import *
2 from sqlobject.sqlbuilder import *
3 import errno
4 import os
5 from os import path
6 from datetime import datetime
7
8 __all__ = ('Curso', 'Inscripto', 'Docente', 'Ejercicio', 'Entrega',
9            'CasoDePrueba', 'Intento', 'Correccion', 'Prueba')
10
11 # Directorio con los datos por default
12 dir_base = '.'
13
14 class BaseSQLObject(SQLObject):
15
16     @classmethod
17     def by(cls, **kw):
18         try:
19             return cls.selectBy(**kw)[0]
20         except IndexError:
21             raise SQLObjectNotFound, "The object %s with columns %s does not exist" % (cls.__name__, kw)
22
23 class Curso(BaseSQLObject):
24     # Clave
25     anio            = IntCol()
26     cuatrimestre    = IntCol()
27     curso           = IntCol()
28     # Campos
29     descripcion     = StringCol()
30     # Joins
31     docentes        = RelatedJoin('Docente')
32     entregas        = MultipleJoin('Entrega')
33     inscriptos      = MultipleJoin('Inscripto')
34     ejercicios      = RelatedJoin('Curso', intermediateTable = 'entrega')
35
36 class Inscripto(BaseSQLObject):
37     # Clave
38     padron          = IntCol(alternateID=True)
39     # Campos
40     curso           = ForeignKey('Curso')
41     mail            = StringCol()
42     activo          = BoolCol(default=True)
43     # Joins
44     intentos        = MultipleJoin('Intento')
45     correcciones    = MultipleJoin('Correccion')
46
47 class Docente(BaseSQLObject):
48     # Clave
49     nombre          = StringCol(alternateID=True)
50     # Campos
51     mail            = StringCol()
52     corrige         = BoolCol()
53     # Joins
54     cursos          = RelatedJoin('Curso')
55     ejercicios      = MultipleJoin('Ejercicio')
56     correcciones    = MultipleJoin('Correccion')
57
58 class Ejercicio(BaseSQLObject):
59     # Clave
60     nombre          = Col()
61     # Campos
62     numero          = Col()
63     docente         = ForeignKey('Docente')
64     # Joins
65     casosDePrueba   = MultipleJoin('CasoDePrueba')
66     entregas        = MultipleJoin('Entrega')
67     cursos          = RelatedJoin('Curso', intermediateTable = 'entrega')
68
69     def _get_path(self):
70         return path.join(dir_base, 'ejercicios', str(self.id))
71
72 class Entrega(BaseSQLObject):
73     # Clave
74     curso           = ForeignKey('Curso')
75     nroEjercicio    = IntCol()
76     entrega         = IntCol()
77     # Campos
78     ejercicio       = ForeignKey('Ejercicio')
79     desde           = DateTimeCol()
80     hasta           = DateTimeCol()
81     finalizada      = BoolCol(default=False)
82     # Joins
83     cursos          = MultipleJoin('Curso')
84     correcciones    = MultipleJoin('Correccion')
85     intentos        = MultipleJoin('Intento')
86
87     @classmethod
88     def getPendientes(cls, connection=None):
89         return cls.select((cls.q.finalizada == False)
90             & (cls.q.hasta <= datetime.now()),
91             orderBy=cls.q.hasta, connection=connection)
92
93 class CasoDePrueba(BaseSQLObject):
94     # Clave
95     ejercicio       = ForeignKey('Ejercicio')
96     nombre          = StringCol()
97     # Campos
98     privado         = BoolCol()
99     activo          = BoolCol(default=True)
100     parametros      = StringCol(default=None)
101     codigoRetorno   = IntCol(default=False)
102     tiempoCpu       = FloatCol(default=None)
103     # Joins
104     pruebas         = MultipleJoin('Prueba')
105
106     def _get_path(self):
107         return path.join(self.ejercicio.path, 'casos_de_prueba', self.nombre)
108
109     def _get_pathEntradas(self):
110         return path.join(self.path, 'entradas')
111
112     def _get_pathSalidas(self):
113         return path.join(self.path, 'salidas')
114
115     def _get_archivosEntrada(self):
116         try:
117             return frozenset(os.listdir(self.pathEntradas))
118         except OSError, (err, msg):
119             if err == errno.ENOENT:
120                 return frozenset()
121             else:
122                 raise
123
124     def _get_archivosSalida(self):
125         try:
126             return frozenset(os.listdir(self.pathSalidas))
127         except OSError, (err, msg):
128             if err == errno.ENOENT:
129                 return frozenset()
130             else:
131                 raise
132
133 class Intento(BaseSQLObject):
134     # Clave
135     inscripto       = ForeignKey('Inscripto')
136     entrega         = ForeignKey('Entrega')
137     numero          = IntCol()
138     # Campos
139     llegada         = DateTimeCol()
140     inicioCompila   = DateTimeCol(default=None)
141     finCompila      = DateTimeCol(default=None)
142     inicioPruebas   = DateTimeCol(default=None)
143     finPruebas      = DateTimeCol(default=None)
144     compila         = BoolCol(default=None)
145     mailRespuesta   = StringCol()
146     observaciones   = StringCol(default=None)
147     # Joins
148     pruebas         = MultipleJoin('Prueba')
149
150     @classmethod
151     def getProximoAProbar(cls, connection=None):
152         try:
153             return cls.select(cls.q.compila == None, limit=1,
154                 orderBy=cls.q.llegada, connection=connection)[0]
155         except IndexError:
156             return None
157
158     @classmethod
159     def faltaCompilar(cls, entrega, connection=None):
160         no_compilados = cls.selectBy(entregaID=entrega.id, compila=None,
161             connection=connection).count()
162         no_probados = cls.selectBy(entregaID=entrega.id, compila=True,
163             finPruebas=None, connection=connection).count()
164         return no_compilados + no_probados
165
166     def chrootPath(self, caso_de_prueba):
167         return path.join(self.path, 'pruebas', caso_de_prueba.nombre)
168
169     def _get_path(self):
170         curso = self.inscripto.curso
171         entrega = self.entrega
172         return path.join(dir_base, 'intentos',
173             '%s.%s' % (curso.anio, curso.cuatrimestre),
174             '%s.%s.%s' % (curso.curso, entrega.nroEjercicio, entrega.entrega),
175             '%s.%s' % (self.inscripto.padron, self.numero))
176
177     def _get_pruebasPasadas(self):
178         if not self.compila: return False
179         for p in self.pruebas:
180             if not p.pasada: return False
181         return True
182
183     def _get_pruebasPublicasPasadas(self):
184         if not self.compila: return False
185         for p in self.pruebas:
186             if not p.pasada and not p.casoDePrueba.privado:
187                 return False
188         return True
189
190     def _get_pruebasPrivadasPasadas(self):
191         if not self.compila: return False
192         for p in self.pruebas:
193             if not p.pasada and p.casoDePrueba.privado:
194                 return False
195         return True
196
197 class Correccion(BaseSQLObject):
198     # Clave
199     entrega         = ForeignKey('Entrega')
200     inscripto       = ForeignKey('Inscripto')
201     # Campos
202     intento         = ForeignKey('Intento')
203     docente         = ForeignKey('Docente')
204     nota            = IntCol(default=None)
205     observaciones   = StringCol(default=None)
206
207 class Prueba(BaseSQLObject):
208     # Clave
209     intento         = ForeignKey('Intento')
210     casoDePrueba    = ForeignKey('CasoDePrueba')
211     # Campos
212     inicio          = DateTimeCol()
213     fin             = DateTimeCol(default=None)
214     pasada          = BoolCol(default=None)
215     observaciones   = StringCol(default=None)
216
217     def _get_archivosSalida(self):
218         ent = self.casoDePrueba.archivosEntrada
219         sal = self.casoDePrueba.archivosSalida
220         return frozenset([f for f in os.listdir(self.intento.chrootPath(self.casoDePrueba)) \
221                     if f in sal or f not in ent and f <> 'tp'])
222
223 # vim: set et sw=4 sts=4 :