Discrete-time, second-order section, direct-form II filter
This is Direct Form 1 but it's still cascaded SOS.  it's in C, but you should be able to translate it to Python easily.  the register keyword is not important.
typedef struct
{
float filterCoefficients[5];    /* b0, b1, b2, a1, a2   (a0 is normalized to 1) */
} sectionData;

void filterBuffer(int32 Nsamples, int Nsections, float* y, float* x, float* filterStates, sectionData** sections)
{
sectionData** section_ptr;
float sampleValue, state1, state2, *state_ptr, *coef_ptr;

for (int n=0; n&lt;Nsamples; n++)
    {
    section_ptr = sections;                     // reset section pointer
    state_ptr = filterStates;                   // reset state pointer
    
    sampleValue = x[n];                         // get input sample
    
    state2 = *state_ptr++;                      //   x[n-2]           
    state1 = *state_ptr--;                      //   x[n-1]           
    *state_ptr++ = state1;                      //   x[n-1] -&gt; x[n-2] 
    *state_ptr++ = sampleValue;                 //   x[n]   -&gt; x[n-1] 
    
    int i = Nsections;
    while (--i &gt;= 0)
        {
        coef_ptr = &amp;((*section_ptr++)-&gt;filterCoefficients[0]);  // point to section filter coefficients
        
        sampleValue =  *coef_ptr++ * sampleValue;   //   b0*x[n]          
        sampleValue += *coef_ptr++ * state1;        //   b1*x[n-1]        
        sampleValue += *coef_ptr++ * state2;        //   b2*x[n-2]        
        
        state2 = *state_ptr++;                      //   y[n-2]           
        state1 = *state_ptr--;                      //   y[n-1]           
        *state_ptr++ = state1;                      //   y[n-1] -&gt; y[n-2] 
        
        sampleValue += *coef_ptr++ * state1;        //  -a1*y[n-1]        
        sampleValue += *coef_ptr++ * state2;        //  -a2*y[n-2]        
        
        *state_ptr++ = sampleValue;                 //   y[n]   -&gt; y[n-1] 

        //     at this point sampleValue is the output of the section just completed
        //     and will be the input to the section about to be computed unless this
        //     is the last section, in which case sampleValue is the output.
        //     state1 and state2 are the output states of the section just completed
        //     and will be the input states of of the section about to be computed.
        }
    
    y[n] = sampleValue;                             // store output sample
    }
}