# Buggy code
def complete(self, body):
    decode_hex = codecs.getdecoder("hex_codec")
    total = bytearray()
    md5s = bytearray()

    last = None
    count = 0
    for pn, etag in body:
        part = self.parts.get(pn)
        part_etag = None
        if part is not None:
            part_etag = part.etag.replace('"', "")
            etag = etag.replace('"', "")
        if part is None or part_etag != etag:
            raise InvalidPart()
        if last is not None and len(last.value) < UPLOAD_PART_MIN_SIZE:
            raise EntityTooSmall()
        md5s.extend(decode_hex(part_etag)[0])
        total.extend(part.value)
        last = part
        count += 1

    etag = hashlib.md5()
    etag.update(bytes(md5s))
    return total, "{0}-{1}".format(etag.hexdigest(), count)


# Traceback (botocore.exceptions.ClientError)
Traceback (most recent call last):
File "/Users/myuser/projects/project/web/pdf_file_downloader.py", line 16, in download
self.s3.download_file(self.bucket_name, self.file_name, self.local_path())
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/boto3/s3/inject.py", line 172, in download_file
extra_args=ExtraArgs, callback=Callback)
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/boto3/s3/transfer.py", line 307, in download_file
future.result()
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/s3transfer/futures.py", line 106, in result
return self._coordinator.result()
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/s3transfer/futures.py", line 265, in result
raise self._exception
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/s3transfer/tasks.py", line 126, in __call__
return self._execute_main(kwargs)
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/s3transfer/tasks.py", line 150, in _execute_main
return_value = self._main(**kwargs)
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/s3transfer/download.py", line 512, in _main
Bucket=bucket, Key=key, **extra_args)
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/botocore/client.py", line 316, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/Users/myuser/Library/Caches/pypoetry/virtualenvs/project-X5XCMv3p-py3.6/lib/python3.6/site-packages/botocore/client.py", line 626, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (416) when calling the GetObject operation: Requested Range Not Satisfiable

# Fixed code
def complete(self, body):
    decode_hex = codecs.getdecoder("hex_codec")
    total = bytearray()
    md5s = bytearray()

    last = None
    count = 0
    for pn, etag in body:
        part = self.parts.get(pn)
        part_etag = None
        if part is not None:
            part_etag = part.etag.replace('"', "")
            etag = etag.replace('"', "")
        if part is None or part_etag != etag:
            raise InvalidPart()
        if last is not None and last.contentsize < UPLOAD_PART_MIN_SIZE:
            raise EntityTooSmall()
        md5s.extend(decode_hex(part_etag)[0])
        total.extend(part.value)
        last = part
        count += 1

    etag = hashlib.md5()
    etag.update(bytes(md5s))
    return total, "{0}-{1}".format(etag.hexdigest(), count)