code: def calculate_etag(self, expected=None):
          
          md5s = []
          with open(self.filepath, 'rb') as fp:
              while True:
                  data = fp.read(CHUNK_SIZE)
                  if not data:
                      break
                  md5s.append(hashlib.md5(data))
  
          digests = b"".join(m.digest() for m in md5s)
  
          new_md5 = hashlib.md5(digests)
          new_etag = '%s-%s' % (new_md5.hexdigest(),len(md5s))
          self.etag = new_etag
  
          return new_etag
docs: calculates a multipart upload etag in the same way as amazon s3
              args:
                  source_path -- The file to calculate the etage for
                  chunk_size -- The chunk size to calculate for.
                  expected -- optional If passed a string, the string
                  will be compared to the resulting etag and raise an
                  exception if they don't match