На основе ответов здесь я написал реализацию Python, которая корректно вычисляет как многочастные, так и одночастные файлы ETags.
def calculate_s3_etag(file_path, chunk_size=8 * 1024 * 1024):
md5s = []
with open(file_path, 'rb') as fp:
while True:
data = fp.read(chunk_size)
if not data:
break
md5s.append(hashlib.md5(data))
if len(md5s) == 1:
return '"{}"'.format(md5s[0].hexdigest())
digests = b''.join(m.digest() for m in md5s)
digests_md5 = hashlib.md5(digests)
return '"{}-{}"'.format(digests_md5.hexdigest(), len(md5s))
По умолчанию chunk_size имеет 8 МБ, используемый официальным aws cli
инструмент, и он делает многостраничную загрузку для 2+ кусков. Он должен работать как на Python 2, так и на 3.