docs: def addinputfile(self, project, inputtemplate, sourcefile, **kwargs):
          """Add/upload an input file to the CLAM service. Supports proper file upload streaming.
  
          project - the ID of the project you want to add the file to.
          inputtemplate - The input template you want to use to add this file (InputTemplate instance)
          sourcefile - The file you want to add: string containing a filename (or instance of ``file``)
  
          Keyword arguments (optional but recommended!):
              * ``filename`` - the filename on the server (will be same as sourcefile if not specified)
              * ``metadata`` - A metadata object.
              * ``metafile`` - A metadata file (filename)
  
          Any other keyword arguments will be passed as metadata and matched with the input template's parameters.
  
          Example::
  
              client.addinputfile("myproject", "someinputtemplate", "/path/to/local/file")
  
          With metadata, assuming such metadata parameters are defined::
  
              client.addinputfile("myproject", "someinputtemplate", "/path/to/local/file", parameter1="blah", parameterX=3.5)
  
          """
          if isinstance( inputtemplate, str) or (sys.version < '3' and isinstance( inputtemplate, unicode)): #pylint: disable=undefined-variable
              data = self.get(project) #causes an extra query to server
              inputtemplate = data.inputtemplate(inputtemplate)
          elif not isinstance(inputtemplate, clam.common.data.InputTemplate):
              raise Exception("inputtemplate must be instance of InputTemplate. Get from CLAMData.inputtemplate(id)")
  
          if not isinstance(sourcefile, IOBase):
              sourcefile = open(sourcefile,'rb')
              if 'filename' in kwargs:
                  filename = self.getinputfilename(inputtemplate, kwargs['filename'])
              else:
                  filename = self.getinputfilename(inputtemplate, os.path.basename(sourcefile.name) )
  
          data = {"file": (filename,sourcefile,inputtemplate.formatclass.mimetype), 'inputtemplate': inputtemplate.id}
          for key, value in kwargs.items():
              if key == 'filename':
                  pass #nothing to do
              elif key == 'metadata':
                  assert isinstance(value, clam.common.data.CLAMMetaData)
                  data['metadata'] =  value.xml()
              elif key == 'metafile':
                  data['metafile'] = open(value,'rb')
              else:
                  data[key] = value
  
  
          requestparams = self.initrequest(data)
          if 'auth'in requestparams:
              #TODO: streaming support doesn't work with authentication unfortunately, disabling streaming for now:
              del data['file']
              requestparams['data'] = data
              requestparams['files'] = [('file', (filename,sourcefile, inputtemplate.formatclass.mimetype))]
              if 'metafile' in kwargs:
                  del data['metafile']
                  requestparams['files'].append(('metafile',('.'+ filename + '.METADATA', open(kwargs['metafile'],'rb'), 'text/xml')))
          else:
              #streaming support
              encodeddata = MultipartEncoder(fields=requestparams['data']) #from requests-toolbelt, necessary for streaming support
              requestparams['data'] = encodeddata
              requestparams['headers']['Content-Type'] = encodeddata.content_type
          r = requests.post(self.url + project + '/input/' + filename,**requestparams)
          sourcefile.close()
  
          if r.status_code == 400:
              raise clam.common.data.BadRequest()
          elif r.status_code == 401:
              raise clam.common.data.AuthRequired()
          elif r.status_code == 403:
              if r.text[0] == '<':
                  #XML response
                  return self._parseupload(r.text)
              else:
                  raise clam.common.data.PermissionDenied(r.text)
          elif r.status_code == 404:
              raise clam.common.data.NotFound(r.text)
          elif r.status_code == 500:
              raise clam.common.data.ServerError(r.text)
          elif r.status_code == 405:
              raise clam.common.data.ServerError("Server returned 405: Method not allowed for POST on " + self.url + project + '/input/' + filename)
          elif r.status_code == 408:
              raise clam.common.data.TimeOut()
          elif not (r.status_code >= 200 and r.status_code <= 299):
              raise Exception("An error occured, return code " + str(r.status_code))
  
          return self._parseupload(r.text)