Add a new datastream to an existing object.  On success,
        the return response should have a status of 201 Created;
        if there is an error, the response body includes the error message.

        :param pid: object pid
        :param dsID: id for the new datastream
        :param dslabel: label for the new datastream (optional)
        :param mimeType: mimetype for the new datastream (optional)
        :param logMessage: log message for the object history (optional)
        :param controlGroup: control group for the new datastream (optional)
        :param dsLocation: URL where the content should be ingested from
        :param altIDs: alternate ids (optional)
        :param versionable: configure datastream versioning (optional)
        :param dsState: datastream state (optional)
        :param formatURI: datastream format (optional)
        :param checksumType: checksum type (optional)
        :param checksum: checksum  (optional)
        :param content: datastream content, as a file-like object or
            characterdata (optional)
        :rtype: :class:`requests.models.Response`

def addDatastream(self, pid, dsID, dsLabel=None, mimeType=None, logMessage=None,
        controlGroup=None, dsLocation=None, altIDs=None, versionable=None,
        dsState=None, formatURI=None, checksumType=None, checksum=None, content=None):
        '''Add a new datastream to an existing object.  On success,
        the return response should have a status of 201 Created;
        if there is an error, the response body includes the error message.

        :param pid: object pid
        :param dsID: id for the new datastream
        :param dslabel: label for the new datastream (optional)
        :param mimeType: mimetype for the new datastream (optional)
        :param logMessage: log message for the object history (optional)
        :param controlGroup: control group for the new datastream (optional)
        :param dsLocation: URL where the content should be ingested from
        :param altIDs: alternate ids (optional)
        :param versionable: configure datastream versioning (optional)
        :param dsState: datastream state (optional)
        :param formatURI: datastream format (optional)
        :param checksumType: checksum type (optional)
        :param checksum: checksum  (optional)
        :param content: datastream content, as a file-like object or
            characterdata (optional)
        :rtype: :class:`requests.models.Response`
        '''

        # objects/{pid}/datastreams/NEWDS? [opts]
        # content via multipart file in request content, or dsLocation=URI
        # one of dsLocation or filename must be specified

        # if checksum is sent without checksum type, Fedora seems to
        # ignore it (does not error on invalid checksum with no checksum type)
        if checksum is not None and checksumType is None:
            warnings.warn('Fedora will ignore the checksum (%s) because no checksum type is specified' \
                          % checksum)

        http_args = {}
        if dsLabel:
            http_args['dsLabel'] = dsLabel
        if mimeType:
            http_args['mimeType'] = mimeType
        if logMessage:
            http_args['logMessage'] = logMessage
        if controlGroup:
            http_args['controlGroup'] = controlGroup
        if dsLocation:
            http_args['dsLocation'] = dsLocation
        if altIDs:
            http_args['altIDs'] = altIDs
        if versionable is not None:
            http_args['versionable'] = versionable
        if dsState:
            http_args['dsState'] = dsState
        if formatURI:
            http_args['formatURI'] = formatURI
        if checksumType:
            http_args['checksumType'] = checksumType
        if checksum:
            http_args['checksum'] = checksum

        # Added code to match how content is now handled, see modifyDatastream.
        extra_args = {}
        # could be a string or a file-like object
        if content:
            if hasattr(content, 'read'):    # if content is a file-like object, warn if no checksum
                if not checksum:
                    logger.warning("File was ingested into fedora without a passed checksum for validation, pid was: %s and dsID was: %s.",
                                   pid, dsID)
                extra_args['files'] = {'file': content}

            else:
                # fedora wants a multipart file upload;
                # this seems to work better for handling unicode than
                # simply sending content via requests data parameter
                extra_args['files'] = {'file': ('filename', content)}

        # set content-type header ?
        url = 'objects/%s/datastreams/%s' % (pid, dsID)
        return self.post(url, params=http_args, **extra_args)