Thursday, April 30, 2026

Today a bug in Lino Prima took me a few hours to hunt and fix.

Look at this code:

    class Challenge(Sequenced)::

def get_siblings(self):
    if self.exam_id:
        return self.__class__.objects.filter(exam=self.exam)
    return self.__class__.objects.filter(project_section=self.project_section)

Above code is bad. Below is the corrected code:

def get_siblings(self):
    if self.exam_id:
        return self.__class__.objects.filter(exam=self.exam)
    if self.project_section:
        return self.__class__.objects.filter(project_section=self.project_section)
    return self.__class__.objects.none()

A lino_prima.lib.ratings.Challenge row has always either exam or project_section set. But on a row having both exam and project_section None (a case that theoretically doesn’t exist, but yesterday it did), the buggy get_siblings() will return all rows with project_section being null, i.e. all rows that have have an non-null exam_id. More exactly there were 3454 such rows. How could this exceptional situation happen? We don’t know. It is not worth to try to find out.

Here is the script I ran in to order to diagnose the problem and to repair the data:

import sys
from lino.api.shell import *

qs = ratings.Challenge.objects.filter(
    project_section__isnull=True).order_by('id')
print(qs.count(), qs)
# 3454 <QuerySet [Challenge #10442 ('Ausdrucksvolles Lesen /10 in Löwen (31.07.)'), Challenge #10443 ('Sprechen /10 in Morgenkreis Experiment (31.07.)'), Challenge #10444 ('Sprechen /10 in Morgenkreis Lesen (31.07.)'), Challenge >

for obj in qs:
    print(obj.seqno, obj)

seqnos = set([obj.seqno for obj in qs])
print("There are", len(seqnos), "different seqnos")
# There are 3454 different seqnos

# sys.exit()

for obj in qs:
  obj.seqno = 0
  # do NOT call full_clean() because that would call set_seqno()
  obj.save()

qs = ratings.Challenge.objects.filter(seqno=0).order_by('id')

for obj in qs:
  obj.full_clean()
  obj.save()

Lesson to learn: Be careful when implementing Sequenced.get_siblings.