code: def prepare_payload(op, method, uri, data):
      
      query = [] if op is None else [("op", op)]
  
      def slurp(opener):
          with opener() as fd:
              return fd.read()
  
      if method == "GET":
          headers, body = [], None
          query.extend(
              (name, slurp(value) if callable(value) else value)
              for name, value in data)
      else:
          # Even if data is empty, construct a multipart request body. Piston
          # (server-side) sets `request.data` to `None` if there's no payload.
          message = build_multipart_message(data)
          headers, body = encode_multipart_message(message)
  
      uri = urlparse(uri)._replace(query=urlencode(query)).geturl()
      return uri, body, headers
docs: Return the URI (modified perhaps) and body and headers.
  
      - For GET requests, encode parameters in the query string.
  
      - Otherwise always encode parameters in the request body.
  
      - Except op; this can always go in the query string.
  
      :param method: The HTTP method.
      :param uri: The URI of the action.
      :param data: An iterable of ``name, value`` or ``name, opener``
          tuples (see `name_value_pair`) to pack into the body or
          query, depending on the type of request.