Indeed and the duration for refreshing the Neopixels is almost a known data point.
According to Adafruit’s Uber guide
NeoPixels receive data from a fixed-frequency 800 KHz data stream. Each bit of data therefore requires 1/800,000 sec — 1.25 microseconds. One pixel requires 24 bits (8 bits each for red, green blue) — 30 microseconds. After the last pixel’s worth of data is issued, the stream must stop for at least 50 microseconds for the new colors to “latch.”
So a strip of 400 pixels will require (400 * 30) + 50, or 12,050 microseconds - about 12ms.
Then there is the unpacking time taken after receiving the full payload - which would need to be timed.
Then you would need to add a few more ms to be on the safe side.
The total will be the minimum delay in between two payloads that the PC / Python script should honor.
This might still be second guessing the timing and may be a better approach would be to have a communication protocol and a two way discussion between the PC and Arduino.
The Python scripts starts and opens the Arduino’s serial port. That will reboot the arduino. Then the Python script waits for a message from the Arduino saying it’s ready to run. The PC sends the first frame and pauses. The arduino receives the frame and updates the strip and then sends a message again to the PC stating it’s ready to get the next frame. And you cycle again.
The two sides then become synchronized and you don’t have a race between the serial port and the strip’s update.
I’ve written a small tutorial on interfacing with Python. May be it can help See Two ways communication between Python3 and Arduino