def _read_from_hdx(self, object_type, value, fieldname='id',
                       action=None, **kwargs):
        # type: (str, str, str, Optional[str], Any) -> Tuple[bool, Union[dict, str]]
        """Makes a read call to HDX passing in given parameter.

        Args:
            object_type (str): Description of HDX object type (for messages)
            value (str): Value of HDX field
            fieldname (str): HDX field name. Defaults to id.
            action (Optional[str]): Replacement CKAN action url to use. Defaults to None.
            **kwargs: Other fields to pass to CKAN.

        Returns:
            Tuple[bool, Union[dict, str]]: (True/False, HDX object metadata/Error)
        """
        if not fieldname:
            raise HDXError("Empty %s field name!" % object_type)
        if action is None:
            action = self.actions()['show']
        data = {fieldname: value}
        data.update(kwargs)
        try:
            result = Configuration.remoteckan().call_action(action, data,
                                                            requests_kwargs={
                                                                'auth': Configuration.read()._get_credentials()})
            return True, result
        except NotFound:
            return False, "%s=%s: not found!" % (fieldname, value)
        except Exception as e:
            six.raise_from(HDXError('Failed when trying to read: %s=%s! (POST)' % (fieldname, value)), e)
    def _write_to_hdx(self, action, data, id_field_name, file_to_upload=None):
        # type: (str, dict, str, Optional[str]) -> dict
        """Creates or updates an HDX object in HDX and return HDX object metadata dict

        Args:
            action (str): Action to perform eg. 'create', 'update'
            data (dict): Data to write to HDX
            id_field_name (str): Name of field containing HDX object identifier or None
            file_to_upload (Optional[str]): File to upload to HDX

        Returns:
            dict: HDX object metadata
        """
        file = None
        try:
            if file_to_upload:
                file = open(file_to_upload, 'rb')
                files = [('upload', file)]
            else:
                files = None
            return Configuration.remoteckan().call_action(self.actions()[action], data, files=files,
                                                          requests_kwargs={
                                                              'auth': Configuration.read()._get_credentials()})
        except Exception as e:
            six.raise_from(HDXError('Failed when trying to %s %s! (POST)' % (action, self.data[id_field_name])), e)
        finally:
            if file_to_upload and file:
                file.close()