code: def create_predictable_zip(path):
      
      # if path is a directory, recursively enumerate all the files under the directory
      if os.path.isdir(path): 
          paths = []
          for root, directories, filenames in os.walk(path):
              paths += [os.path.join(root, filename)[len(path)+1:] for filename in filenames]
          reader = lambda x: _read_file(os.path.join(path, x))
      # otherwise, if it's a zip file, open it up and pull out the list of names
      elif os.path.isfile(path) and os.path.splitext(path)[1] == ".zip":
          inputzip = zipfile.ZipFile(path)
          paths = inputzip.namelist()
          reader = lambda x: inputzip.read(x)
      else:
          raise Exception("The `path` must either point to a directory or to a zip file.")
  
      # create a temporary zip file path to write the output into
      zippathfd, zippath = tempfile.mkstemp(suffix=".zip")
  
      with zipfile.ZipFile(zippath, "w") as outputzip:
          # loop over the file paths in sorted order, to ensure a predictable zip
          for filepath in sorted(paths):
              write_file_to_zip_with_neutral_metadata(outputzip, filepath, reader(filepath))
          os.fdopen(zippathfd).close()
      return zippath
docs: Create a zip file with predictable sort order and metadata so that MD5 will
      stay consistent if zipping the same content twice.
      Args:
          path (str): absolute path either to a directory to zip up, or an existing zip file to convert.
      Returns: path (str) to the output zip file