I managed to make this work by using Python's built-in open() call instead of os.open(), which allowed me to disable buffering using the buffering=0 option. So it seems I/O buffering by Linux was the issue (and os.open() could also be used with appropriate flags). Though I am not sure why this problem does not occur with older Rigol scopes such as the DS1052.
The new code is
# for future compatibility
from __future__ import division
from __future__ import print_function
# for file access
import os
# for timed waits
import time
class Device:
"""
Simple usbmtc device
"""
def __init__(self, device="/dev/usbtmc0"):
self.FILE = open(device, 'w+', buffering=0)
def __del__(self):
self.FILE.close()
def write(self, cmd):
self.FILE.write(cmd)
def read(self):
return self.FILE.read()
def query(self, cmd, timeout=0.01):
self.write(cmd)
time.sleep(timeout)
return self.read()
def reset():
self.write("*RST")