def get(self, location, etag=None):
        """
        Get a single object from the G-Node REST API. If an etag is provided it will be included in
        the request with 'If-none-match'. If the response is 304 the return value of this method will
        be None.

        :param location: The location of the object or the whole URL.
        :type location: str
        :param etag: The etag of the cached object.
        :type etag: str

        :returns: The found object or None if it was not updated.
        :rtype: Model

        :raises: HTTPError if the entity was not found on the server (404).
        """
        if location.startswith("http://"):
            url = location
        else:
            url = urlparse.urljoin(self.location, location)

        headers = {}
        if etag is not None:
            headers['If-none-match'] = etag
        future = self.__session.get(url, headers=headers)
        response = future.result()

        if response.status_code in (304, 404):
            result = None
        else:
            self.raise_for_status(response)
            result = convert.collections_to_model(convert.json_to_collections(response.content))

        return result
    def get_list(self, locations):
        """
        Get a list of objects that are referenced by their locations or complete URLs
        from the G-Node REST API. In order to get a better performance this method uses
        the features of the requests_futures package.

        :param locations: List with locations or URLs.
        :type locations: list

        :returns: A list of objects matching the list of locations.
        :rtype: list
        """
        futures = []
        results = []

        for location in locations:
            if location.startswith("http://"):
                url = location
            else:
                url = urlparse.urljoin(self.location, location)

            future = self.__session.get(url)
            futures.append(future)

        for future in futures:
            response = future.result()
            self.raise_for_status(response)

            result = convert.collections_to_model(convert.json_to_collections(response.content))
            results.append(result)

        return results
    def select(self, model_name, raw_filters=None):
        """
        Select data from a certain type e.g. blocks or spiketrains from the G-Node REST API
        and convert the results to a list of model objects.

        :param model_name: The name of the model as string.
        :type model_name: str
        :param raw_filters: Filters as defined by the G-Node REST API.
        :type raw_filters: dict

        :returns: A list of (filtered) results.
        :rtype: list
        """
        results = []

        raw_filters = {} if raw_filters is None else raw_filters

        location = Model.get_location(model_name)
        url = urlparse.urljoin(self.location, location)

        headers = {}
        future = self.__session.get(url, headers=headers, params=raw_filters)
        response = future.result()
        self.raise_for_status(response)

        raw_results = convert.json_to_collections(response.content, as_list=True)
        for obj in raw_results:
            results.append(convert.collections_to_model(obj))

        return results
    def set_delta(self, path):
        """
        Submits a given Delta file with changes to the Remote.

        :param path:    a path to the Delta file with changes to be submitted
        """
        url = urlparse.urljoin(self.location, "/api/v1/in_bulk/")

        with open(path, 'rb') as f:
            files = {'raw_file': f.read()}
            future = self.__session.post(url, files=files)
            response = future.result()

        self.raise_for_status(response)
        return convert.collections_to_model(convert.json_to_collections(response.content))
    def set(self, entity, avoid_collisions=False):
        """
        Update or create an entity on the G-Node REST API. If an etag/guid is provided by the entity it
        will be included in the header with 'If-match' if avoid_collisions is True.

        :param entity: The entity to persist.
        :type entity: Model
        :param avoid_collisions: Try to avoid collisions (lost update problem)
        :type avoid_collisions: bool

        :returns: The updated entity.
        :rtype: Model

        :raises: RuntimeError If the changes collide with remote changes of the entity.
        """
        if hasattr(entity, "location") and entity.location is not None:
            method = 'put'
            url = urlparse.urljoin(self.location, entity.location)
        else:
            method = 'post'
            url = urlparse.urljoin(self.location, Model.get_location(entity.model))

        data = convert.model_to_json_response(entity)
        headers = {'Content-Type': 'application/json'}
        if avoid_collisions and entity.guid is not None:
            headers['If-match'] = entity.guid

        future = getattr(self.__session, method)(url, data=data, headers=headers)
        response = future.result()

        if response.status_code == 304:
            result = entity
        else:
            self.raise_for_status(response)
            result = convert.collections_to_model(convert.json_to_collections(response.content))

        return result