It looks like i goes from 0 to
(self.N // self.batch_size) * epochs
You did not set epochs to zero so it is probably self.N that is zero, which is
self.N, self.p = trainX.shape
as in N is the number of training samples, so I would specify which samples should be train vs test, and make sure that table actually contains them and they were not filtered out unexpectedly.