docs: def upload(self, url, filename, data=None, formname=None,
                 otherfields=()):
          """Upload a file to the url
  
          :param url:
          :param filename: The name of the file
          :param data: A file object or data to use rather than reading from
                       the file.
          :return:
          """
          if data is None:
              data = open(filename, 'rb')
          self._upbuffer = StringIO.StringIO(get_upload_form(filename, data,
                                                             formname,
                                                             otherfields))
          ulheaders = self.stdheaders.copy()
          ulheaders['Content-Type'] = 'multipart/form-data; boundary=' + BND
          ulheaders['Content-Length'] = len(uploadforms[filename])
          self.ulsize = len(uploadforms[filename])
          webclient = self.dupe()
          webclient.request('POST', url, self._upbuffer, ulheaders)
          rsp = webclient.getresponse()
          # peer updates in progress should already have pointers,
          # subsequent transactions will cause memory to needlessly double,
          # but easiest way to keep memory relatively low
          try:
              del uploadforms[filename]
          except KeyError:  # something could have already deleted it
              pass
          self.rspstatus = rsp.status
          if rsp.status != 200:
              raise Exception('Unexpected response in file upload: ' +
                              rsp.read())
          return rsp.read()