Poner un ejercicio de Python que la clase ejecuta en el navegador

Una tarea de programación es un archivo, unas instrucciones que explican qué hay que hacer y, si quieres, unas pruebas que dicen si funciona. La escribes una vez y la asignas a tantas clases como quieras; cada alumno recibe su propia copia para romperla a su gusto. Todo lo que sigue vale también para las tareas de Java, Go, Node, TypeScript en Node y Bash; la página sobre los lenguajes explica en qué se diferencian.

Escribir el ejercicio

Pulsa «Nueva tarea» en el módulo, elige la tarjeta de Python y tendrás un editor con el código inicial a un lado y las instrucciones al otro. Las instrucciones admiten títulos, listas y código, para que un ejemplo parezca un ejemplo.

Lo que dejes en el archivo es el punto de partida de cada alumno: un esqueleto con una docstring, una función a medio escribir o un archivo vacío.

  1. Añadir la tarea. En la pestaña «Tareas» del módulo, pulsa «Nueva tarea» y las tarjetas se abren justo debajo: hay una para cada tipo, agrupadas en Código, Diagrama, Cuestionario y Laboratorio, así que un cuestionario o un laboratorio también se crean con un solo clic una vez elegido su grupo; Esc o «Cerrar» las recoge. Un módulo que aún no tiene tareas muestra las tarjetas directamente. Pulsa la de Python y la tarea se abre como untitled-python; ponle nombre cuando quieras con el lápiz que hay junto a su nombre, en la parte superior del editor. La página «Tareas» tiene las mismas tarjetas, donde primero eliges el curso y el módulo: útil cuando sabes qué quieres escribir antes de haber decidido en qué módulo va.
  2. Escribir el código inicial. Lo que cada alumno abre la primera vez.
  3. Escribir las instrucciones. Lo que se les pide que hagan, junto al código y no en una hoja aparte.
  4. Asignarla. Elige a los alumnos, o a toda la clase. Cada uno recibe su propia copia.
Un profesor escribiendo un ejercicio: las instrucciones a la izquierda con una vista previa en directo, y el código inicial a la derecha
Escribir el ejercicio. Las instrucciones admiten Markdown y muestran una vista previa mientras escribes; lo que haya en el editor es el punto de partida de cada alumno.

Añadir pruebas que lo califiquen por ti

Puedes adjuntar pruebas a cualquier tarea que ejecute un programa: pytest para Python, JUnit 5 para Java, go test para Go y el ejecutor de pruebas integrado en Node para JavaScript y TypeScript. En Bash, una prueba es un script que se supera cuando termina sin errores. El alumno pulsa «Ejecutar las pruebas» y ve cuáles se han superado; tú ves el mismo resultado en su página sin tener que preguntárselo.

Las pruebas pueden estar ocultas, que es justo lo que interesa en una evaluación: el alumno ve que ha superado cuatro de seis, no las aserciones que han fallado, así que el ejercicio sigue siendo el ejercicio.

Ocultas no significa que el alumno se quede sin forma de comprobar su trabajo. Su pestaña «Pruebas» es entonces un cuadro vacío suyo, que se guarda con su copia, y tiene dos botones: «Ejecutar mis pruebas» ejecuta su programa contra ese cuadro y no registra nada, y «Ejecutar las pruebas ocultas» ejecuta las tuyas, que son las que deciden si la tarea aparece como superada o no en su lista. Sus propias pruebas nunca pueden cambiar ese resultado, y los paquetes de la tarea se instalan en ambos casos. Si más adelante muestras tus pruebas, sustituyen el cuadro del alumno la siguiente vez que abra la tarea.

Darles un archivo de datos si lo necesitan

Una tarea puede llevar un archivo de datos que lee el programa, un CSV de mediciones o un archivo de texto cuyas palabras hay que contar. Al ejecutarse, está junto a su código, así que `open('data.csv')` hace lo que dice.

Tiene que ser texto sin formato, y la plataforma lo decide leyendo el archivo, no fiándose de su nombre: una imagen renombrada a data.csv se rechaza y un archivo de texto sin extensión se acepta. La marca de orden de bytes (BOM), que Excel escribe al principio de cada CSV que exporta, se elimina para que la primera línea se lea bien. Un alumno puede adjuntar su propio archivo de datos junto al tuyo, en su copia: solo uno a la vez, así que adjuntar otro lo sustituye, y su nombre debe ser distinto del tuyo. Un archivo de datos ocupa como máximo 64 KB.

Darle más de un archivo

Una tarea de programación no tiene por qué ser un solo archivo. Sus archivos forman un árbol junto al editor: «Nuevo archivo» y «Nueva carpeta» crean uno, «Subir» trae archivos de texto de tu ordenador y «Renombrar o mover» admite una ruta completa, de modo que lib/helpers.py pone el archivo en una carpeta llamada lib y el programa lo importa desde ahí. Una tarea admite hasta 50 archivos de 64 KB como máximo cada uno, 1 MB en total, y solo texto: lo que se sube se comprueba leyéndolo, así que una imagen renombrada data.csv se rechaza. Cada archivo se abre en su propio lenguaje: README.md en Markdown y un .csv como texto sin formato.

El programa es el archivo marcado «Aquí empieza la ejecución», y también puedes renombrarlo o moverlo a una carpeta. Su extensión sigue siendo la del lenguaje, y un programa de Java, C#, Haskell o Kotlin conserva su nombre vaya donde vaya. «Quitar» quita un archivo al momento, con «Deshacer» al lado durante unos segundos. Una carpeta existe mientras tenga algún archivo, así que una carpeta nueva empieza con su primer archivo. En el árbol, las flechas recorren los archivos y abren y cierran las carpetas, Intro abre un archivo, F2 le cambia el nombre y Supr lo quita.

Al asignar la tarea se copian todos los archivos a cada alumno, que ve el mismo árbol y puede editar cualquier archivo en su copia. Solo puede añadir archivos propios si la tarea permite más de un archivo, y los archivos que le diste conservan su nombre. Los archivos de práctica y los entornos de pruebas tienen el mismo árbol. Sigue habiendo un único archivo de pruebas y una única lista de paquetes, un archivo en la raíz del árbol marcado como «Paquetes» que se describe en «Todos los lenguajes en los que se puede poner una tarea». Una página web y una tarea de SQL no pueden tener archivos adicionales, porque sus paneles son de lo que están hechas. Para un ejercicio que debe seguir siendo un solo archivo, desmarca «Más de un archivo» en los ajustes de la tarea; los archivos que ya tiene se conservan y se pueden seguir renombrando y moviendo.

Los proyectos con carpetas, y los archivos de paquetes reales que usan, tienen su propia página en este manual, igual que cargar una tarea entera desde un repositorio Git.

Un cuaderno, para ciencia de datos

Elige Cuaderno al crear una tarea y obtienes un cuaderno de Jupyter: celdas de texto y celdas de Python, en un archivo que se abre en Jupyter, VS Code o Colab. Añades, mueves y quitas celdas, y editas una celda de texto en Markdown.

Ejecutar corre todas las celdas de código desde arriba, en orden, en un proceso limpio, y muestra la salida de cada celda debajo de ella: el texto impreso, el valor de su última línea, una tabla de pandas y una figura de matplotlib. Las celdas comparten sus variables como en Jupyter, pero no se guarda nada entre una pulsación y otra, así que lo que ve el estudiante es lo que el cuaderno hace de verdad. Si una celda falla, la ejecución se detiene ahí, nombra la celda y la línea, y dice que las siguientes no se ejecutaron.

Lo que se guarda son las celdas y nunca sus salidas, así que un cuaderno no puede mostrar un resultado que su código ya no produce. Un cuaderno nuevo declara pandas, numpy y matplotlib en requirements.txt, en la raíz de su árbol de archivos; quita lo que la tarea no necesite, porque cada paquete hace más lenta la primera ejecución. Una tarea que trae paquetes dispone de al menos 30 segundos, salvo que tú fijes un límite.

Las pruebas ocultas funcionan como en un programa: las celdas de código se unen en un solo archivo de Python y tus pruebas llaman por su nombre a las funciones del cuaderno. La entrega, la calificación, los grupos, los límites de tiempo y lo demás son los de cualquier programa.

También puedes ejecutar una celda cada vez. Cada celda de código tiene su propio botón Ejecutar, y Mayús+Intro ejecuta la celda y pasa a la siguiente. Un kernel activo conserva las variables entre celdas: cargas datos en una celda y los usas en la siguiente sin volver a cargarlos. Ejecutar todo ejecuta todas las celdas de código en orden, y Reiniciar el kernel lo olvida todo y empieza de cero. El botón Ejecutar de la página es distinto: siempre parte de nada y ejecuta todo el cuaderno, que es la comprobación de que se reproduce desde el principio. Un kernel se detiene tras 15 minutos sin usarse, o si una celda tarda más de un minuto o usa demasiada memoria; la celda lo dice y la siguiente empieza con un kernel limpio. Un `input()` en una celda falla en esa celda, y las líneas que empiezan por `%` o `!` se omiten y se avisa, salvo `%pip install nombre==1.2.3`, que instala una versión exacta de un paquete de la lista aprobada: no se puede añadir un paquete a un kernel en marcha, así que el kernel se reinicia y las variables de las celdas anteriores se pierden hasta que las ejecutes de nuevo. Un paquete que necesitan todos los estudiantes va mejor en requirements.txt. Interrumpir detiene una celda en ejecución y conserva el kernel y sus variables, y una tabla de pandas se dibuja como tabla.

Para traer un cuaderno que ya tienes, pulsa Importar .ipynb y elige el archivo: sus celdas sustituyen a las de la página (el historial restaura la versión anterior) y sus salidas guardadas se dejan de lado. Un cuaderno escrito para otro lenguaje, o de más de 200 celdas o 60 KB sin sus salidas, se rechaza con el motivo. Exportar .ipynb descarga el cuaderno para Jupyter, VS Code o Colab, con lo que las celdas muestran en ese momento.

Ponerla para grupos

Una tarea puede ponerse para grupos en lugar de para individuos. Cada grupo recibe una sola copia que cualquiera de sus miembros puede editar y entregar, y la nota es la del grupo. Los grupos se forman en la pestaña «Personas» de la tarea, en «Grupos»: automáticamente, a partir de todos los alumnos del módulo o de quienes estén conectados en ese momento, o a mano, moviendo a cada alumno bajo el encabezado de su grupo. Se guarda a medida que cambias.

Una tarea en grupo solo se tiene a través de un grupo, así que asignarla a alguien que no está en ninguno se rechaza y el mensaje lo nombra. Una tarea ya asignada a personas una por una no puede convertirse en trabajo en grupo hasta que las quites de ella, y la casilla lo dice. Un cuestionario no puede ser trabajo en grupo.

Solo una persona escribe en un archivo a la vez: al resto del grupo le aparece como suyo, de solo lectura y con su nombre, mientras los demás archivos de la tarea siguen siendo editables, y un portátil cerrado libera el archivo aproximadamente un minuto después. No se guarda nada por alumno en una tarea en grupo, así que no hay copia aparte, ni nota aparte, ni constancia de quién la abrió, y una prórroga dada a un miembro es de todo el grupo.

Ponerle un tiempo límite si quieres

Cualquier tarea puede tener un tiempo límite: marca «Ponerles un límite de tiempo» en los ajustes de la tarea y escribe los minutos, hasta cuatro horas. El reloj empieza la primera vez que cada alumno abre la tarea y lo lleva la plataforma, así que recargar la página o borrar las cookies no lo reinicia, y que tú abras su trabajo para calificarlo no inicia ninguno.

Tú eliges qué significa que se acabe: que quede constancia de que se pasaron de tiempo, o que el trabajo se detenga de verdad. Si la casilla queda sin marcar, pasarse se muestra al alumno y a ti y no se rechaza nada; marca «Impedir que sigan trabajando cuando se acabe el tiempo» y los guardados y las entregas se detienen en ese momento, salvo en un cuestionario, que siempre se acepta y se califica por tarde que llegue. En ningún caso se pierde lo escrito, porque el editor guarda automáticamente un segundo después de la última pulsación de tecla.

Devolver un trabajo da al alumno un reloj nuevo. Todas las listas de tareas, la del alumno y la de tu módulo, muestran una etiqueta «Con tiempo» con los minutos antes de que nadie abra la tarea, porque abrirla es lo que pone en marcha el reloj.

Cuánto puede tardar una ejecución

Esto no es lo mismo que el tiempo límite: es lo que puede durar una pulsación de «Ejecutar», o una ejecución de las pruebas, antes de que se detenga el programa. Sin ajustes, son 10 segundos para Python, Bash, Node y SQL, y 20 para Java, Go y TypeScript en Node, que antes tienen que compilar. Una tarea de Go, Java o TypeScript que declara paquetes recibe 45, para que la primera ejecución tenga tiempo de descargarlos y compilarlos.

Para cambiarlo, ajusta «Cuánto tiempo puede ejecutarse» en los ajustes de la tarea, en segundos, hasta 60; 0 mantiene el valor por defecto de arriba. Se permite un límite más corto que el predeterminado, así que «haz que termine en dos segundos» es un ejercicio legítimo, y una cifra superior a 60 se rechaza en lugar de rebajarse en silencio. Un alumno no puede pedir ni un segundo más de lo que permite la tarea.

Una ejecución detenida por tiempo lo dice y conserva lo que ya había mostrado. La entrada estándar es un cuadro bajo el código, de hasta 16 KB, y la salida de un programa que imprime muchísimo se corta, con una nota que lo indica.

Dónde está todo lo de una tarea

Una tarea tiene cuatro pestañas. «Editor de la tarea» sirve para escribirla. «Ajustes de la tarea» reúne lo que un alumno puede ver y cambiar, cuánto puede ejecutarse, «Preguntar a la IA», el tiempo límite, la fecha de entrega y las notas. «Estado» muestra quién la tiene y cómo va, y «Personas» muestra a quién va dirigida, sus propietarios y, en un trabajo en grupo, los grupos.

Aquí nada tiene un botón «Guardar»

Cada ajuste se guarda automáticamente un momento después de cambiarlo, y aparece «Guardado» junto al campo al que corresponde. Así funciona toda la plataforma, no solo esta página: los ajustes de una tarea, los de un módulo, los datos y la tarifa de tu centro, los editores de cuestionarios y el calendario de disponibilidad de un anfitrión.

Si escribes un valor que la plataforma no acepta, se indica junto al campo al momento, y no se envía nada hasta que sea algo que se pueda guardar. Un campo con límite te indica cuánto espacio te queda a medida que te acercas, en lugar de rechazar sin avisar el siguiente carácter.

El único sitio donde todavía se pulsa un botón es donde pulsarlo llega a otra persona. Guardar un servicio invita a los clientes que se acaban de marcar en él, y eso no se puede deshacer, así que es una decisión y no una pausa al escribir.

Preguntas frecuentes

¿Pueden los alumnos ver las pruebas?
Solo si tú lo permites, con «Pruebas visibles para los alumnos» en los ajustes de la tarea. Las pruebas ocultas dan un recuento y nada más, que es lo que quieres en una evaluación, y el alumno aun así puede escribir pruebas propias en su pestaña «Pruebas»; las visibles son mejores para practicar, porque leer una prueba que falla es una habilidad.
¿Necesitan los alumnos tener Python instalado?
No. El código se ejecuta en nuestras máquinas, cada vez en un contenedor nuevo.
¿Puedo reutilizar un ejercicio con la clase del año que viene?
Sí. Una tarea pertenece a quien la escribió y no al módulo, así que puedes volver a asignarla u ofrecérsela a otro profesor.
¿Cuánto puede ejecutarse un programa?
Diez segundos por defecto, veinte para Java, Go y TypeScript en Node, y hasta un minuto si lo subes en la tarea.