Modify an existing datastream, similar to :meth:`addDatastraem`.
        Content can be specified by either a URI location or as
        string content or file-like object; if content is not specified,
        datastream metadata will be updated without modifying the content.

        On success, the returned response should have a status code 200;
        on failure, the response body may include an 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 dsLocation: URL where the content should be ingested from (optional)
        :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)
        :param force: force the update (default: False)
        :rtype: :class:`requests.models.Response`

def modifyDatastream(self, pid, dsID, dsLabel=None, mimeType=None, logMessage=None, dsLocation=None,
        altIDs=None, versionable=None, dsState=None, formatURI=None, checksumType=None,
        checksum=None, content=None, force=False):
        '''Modify an existing datastream, similar to :meth:`addDatastraem`.
        Content can be specified by either a URI location or as
        string content or file-like object; if content is not specified,
        datastream metadata will be updated without modifying the content.

        On success, the returned response should have a status code 200;
        on failure, the response body may include an 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 dsLocation: URL where the content should be ingested from (optional)
        :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)
        :param force: force the update (default: False)
        :rtype: :class:`requests.models.Response`
        '''
        # /objects/{pid}/datastreams/{dsID} ? [dsLocation] [altIDs] [dsLabel]
        # [versionable] [dsState] [formatURI] [checksumType] [checksum]
        # [mimeType] [logMessage] [force] [ignoreContent]
        # NOTE: not implementing ignoreContent (unneeded)

        # Unlike addDatastream, if checksum is sent without checksum
        # type, Fedora honors it (*does* error on invalid checksum
        # with no checksum type) - it seems to use the existing
        # checksum type if a new type is not specified.
        http_args = {}
        if dsLabel:
            http_args['dsLabel'] = dsLabel
        if mimeType:
            http_args['mimeType'] = mimeType
        if logMessage:
            http_args['logMessage'] = logMessage
        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
        if force:
            http_args['force'] = force

        content_args = {}
        if content:
            # content can be either a string or a file-like object
            if hasattr(content, 'read'):    # allow content to be a file
                # warn about missing checksums for files
                if not checksum:
                    logger.warning("Updating datastream %s/%s with a file, but no checksum passed",
                                   pid, dsID)

            # either way (string or file-like object), set content as request data
            # (file-like objects supported in requests as of 0.13.1)
            content_args['data'] = content

        url = 'objects/%s/datastreams/%s' % (pid, dsID)
        return self.put(url, params=http_args, **content_args)