def cull(self, file_filter=None, attrs=None):
        """ Delete ALL data files and remove torrent from client.

            @param file_filter: Optional callable for selecting a subset of all files.
                The callable gets a file item as described for RtorrentItem._get_files
                and must return True for items eligible for deletion.
            @param attrs: Optional list of additional attributes to fetch for a filter.
        """
        dry_run = 0 # set to 1 for testing

        def remove_with_links(path):
            "Remove a path including any symlink chains leading to it."
            rm_paths = []
            while os.path.islink(path):
                target = os.readlink(path)
                rm_paths.append(path)
                path = target

            if os.path.exists(path):
                rm_paths.append(path)
            else:
                self._engine.LOG.debug("Real path '%s' doesn't exist,"
                    " but %d symlink(s) leading to it will be deleted..." % (path, len(rm_paths)))

            # Remove the link chain, starting at the real path
            # (this prevents losing the chain when there's permission problems)
            for rm_path in reversed(rm_paths):
                is_dir = os.path.isdir(rm_path) and not os.path.islink(rm_path)
                self._engine.LOG.debug("Deleting '%s%s'" % (rm_path, '/' if is_dir else ''))
                if not dry_run:
                    try:
                        (os.rmdir if is_dir else os.remove)(rm_path)
                    except OSError as exc:
                        if exc.errno == errno.ENOENT:
                            # Seems this disappeared somehow inbetween (race condition)
                            self._engine.LOG.info("Path '%s%s' disappeared before it could be deleted"
                                                  % (rm_path, '/' if is_dir else ''))
                        else:
                            raise

            return rm_paths

        # Assemble doomed files and directories
        files, dirs = set(), set()
        base_path = os.path.expanduser(self.directory)
        item_files = list(self._get_files(attrs=attrs))

        if not self.directory:
            raise error.EngineError("Directory for item #%s is empty,"
                " you might want to add a filter 'directory=!'" % (self._fields["hash"],))
        if not os.path.isabs(base_path):
            raise error.EngineError("Directory '%s' for item #%s is not absolute, which is a bad idea;"
                " fix your .rtorrent.rc, and use 'directory.default.set = /...'"
                % (self.directory, self._fields["hash"],))
        if self.fetch("=is_multi_file") and os.path.isdir(self.directory):
            dirs.add(self.directory)

        for item_file in item_files:
            if file_filter and not file_filter(item_file):
                continue
            #print repr(item_file)
            path = os.path.join(base_path, item_file.path)
            files.add(path)
            if '/' in item_file.path:
                dirs.add(os.path.dirname(path))

        # Delete selected files
        if not dry_run:
            self.stop()
        for path in sorted(files):
            ##self._engine.LOG.debug("Deleting file '%s'" % (path,))
            remove_with_links(path)

        # Prune empty directories (longer paths first)
        doomed = files | dirs
        for path in sorted(dirs, reverse=True):
            residue = set(os.listdir(path) if os.path.exists(path) else [])
            ignorable = set(i for i in residue
                if any(fnmatch.fnmatch(i, pat) for pat in config.waif_pattern_list)
                #or os.path.join(path, i) in doomed
            )
            ##print "---", residue - ignorable
            if residue and residue != ignorable:
                self._engine.LOG.info("Keeping non-empty directory '%s' with %d %s%s!" % (
                    path, len(residue),
                    "entry" if len(residue) == 1 else "entries",
                    (" (%d ignorable)" % len(ignorable)) if ignorable else "",
                ))
            else:
                ##print "---", ignorable
                for waif in ignorable:# - doomed:
                    waif = os.path.join(path, waif)
                    self._engine.LOG.debug("Deleting waif '%s'" % (waif,))
                    if not dry_run:
                        try:
                            os.remove(waif)
                        except EnvironmentError as exc:
                            self._engine.LOG.warn("Problem deleting waif '%s' (%s)" % (waif, exc))

                ##self._engine.LOG.debug("Deleting empty directory '%s'" % (path,))
                doomed.update(remove_with_links(path))

        # Delete item from engine
        if not dry_run:
            self.delete()
Delete ALL data files and remove torrent from client.

            @param file_filter: Optional callable for selecting a subset of all files.
                The callable gets a file item as described for RtorrentItem._get_files
                and must return True for items eligible for deletion.
            @param attrs: Optional list of additional attributes to fetch for a filter.