Exemplo n.º 1
0
    def __init__(self,
                 source,
                 current_page=None,
                 pagination_filter=None,
                 offset=0,
                 limit=-1,
                 locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked
Exemplo n.º 2
0
 def __init__(self, source, *, current_page=None):
     self._source = source
     self._is_content_source = isinstance(source,
                                          (ContentSource, _CombinedSource))
     self._cache = None
     self._pagination_slicer = None
     self._has_sorter = False
     self._next_page = None
     self._prev_page = None
     self._locked = False
     self._load_event = Event()
     self._iter_event = Event()
     self._current_page = current_page
     self._initIterator()
Exemplo n.º 3
0
    def __init__(self, source, current_page=None, pagination_filter=None,
            offset=0, limit=-1, locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked
Exemplo n.º 4
0
class Record(object):
    def __init__(self):
        self.entries = []
        self.entry_added = Event()
        self.app_version = APP_VERSION
        self.record_version = self.__class__.RECORD_VERSION
        self.stats = {}

    def hasLatestVersion(self):
        return (self.app_version == APP_VERSION and
                self.record_version == self.__class__.RECORD_VERSION)

    def addEntry(self, entry):
        self.entries.append(entry)
        self.entry_added.fire(entry)

    def save(self, path):
        path_dir = os.path.dirname(path)
        if not os.path.isdir(path_dir):
            os.makedirs(path_dir, 0o755)

        with open(path, 'wb') as fp:
            pickle.dump(self, fp, pickle.HIGHEST_PROTOCOL)

    def __getstate__(self):
        odict = self.__dict__.copy()
        del odict['entry_added']
        return odict

    def __setstate__(self, state):
        state['entry_added'] = Event()
        self.__dict__.update(state)

    @staticmethod
    def load(path):
        logger.debug("Loading bake record from: %s" % path)
        with open(path, 'rb') as fp:
            return pickle.load(fp)
Exemplo n.º 5
0
class Record(object):
    def __init__(self):
        self.entries = []
        self.entry_added = Event()
        self.app_version = APP_VERSION
        self.record_version = self.__class__.RECORD_VERSION

    def hasLatestVersion(self):
        return (self.app_version == APP_VERSION and
                self.record_version == self.__class__.RECORD_VERSION)

    def addEntry(self, entry):
        self.entries.append(entry)
        self.entry_added.fire(entry)

    def save(self, path):
        path_dir = os.path.dirname(path)
        if not os.path.isdir(path_dir):
            os.makedirs(path_dir, 0o755)

        with open(path, 'wb') as fp:
            pickle.dump(self, fp, pickle.HIGHEST_PROTOCOL)

    def __getstate__(self):
        odict = self.__dict__.copy()
        del odict['entry_added']
        return odict

    def __setstate__(self, state):
        state['entry_added'] = Event()
        self.__dict__.update(state)

    @staticmethod
    def load(path):
        logger.debug("Loading bake record from: %s" % path)
        with open(path, 'rb') as fp:
            return pickle.load(fp)
Exemplo n.º 6
0
    def __init__(self, source, *,
                 current_page=None,
                 pagination_filter=None, sorter=None,
                 offset=0, limit=-1, locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # If we're currently baking, apply the default baker filter
        # to exclude things like draft posts.
        if (isinstance(source, PageSource) and
                source.app.config.get('baker/is_baking')):
            setting_name = source.app.config.get('baker/no_bake_setting',
                                                 'draft')
            accessor = self._getSettingAccessor()
            draft_filter = PaginationFilter(accessor)
            draft_filter.root_clause = NotClause()
            draft_filter.root_clause.addClause(
                    IsFilterClause(setting_name, True))
            self._simpleNonSortedWrap(
                    PaginationFilterIterator, draft_filter)

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if sorter is not None:
            self._simpleNonSortedWrap(GenericSortIterator, sorter)
            self._has_sorter = True

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked
Exemplo n.º 7
0
class PageIterator(object):
    debug_render = []
    debug_render_doc_dynamic = ['_debugRenderDoc']
    debug_render_not_empty = True

    def __init__(self, source, current_page=None, pagination_filter=None,
            offset=0, limit=-1, locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # If we're currently baking, apply the default baker filter
        # to exclude things like draft posts.
        if (isinstance(source, PageSource) and
                source.app.config.get('baker/is_baking')):
            setting_name = source.app.config.get('baker/no_bake_setting',
                                                 'draft')
            accessor = self._getSettingAccessor()
            draft_filter = PaginationFilter(accessor)
            draft_filter.root_clause = NotClause()
            draft_filter.root_clause.addClause(
                    IsFilterClause(setting_name, True))
            self._simpleNonSortedWrap(
                    PaginationFilterIterator, draft_filter)

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked

    @property
    def total_count(self):
        self._load()
        if self._pagination_slicer is not None:
            return self._pagination_slicer.inner_count
        return len(self._pagesData)

    @property
    def next_page(self):
        self._load()
        return self._next_page

    @property
    def prev_page(self):
        self._load()
        return self._prev_page

    def __len__(self):
        self._load()
        return len(self._pagesData)

    def __getitem__(self, key):
        self._load()
        return self._pagesData[key]

    def __iter__(self):
        self._load()
        self._iter_event.fire()
        return iter(self._pagesData)

    def __getattr__(self, name):
        if name[:3] == 'is_' or name[:3] == 'in_':
            def is_filter(value):
                conf = {'is_%s' % name[3:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return is_filter

        if name[:4] == 'has_':
            def has_filter(value):
                conf = {name: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return has_filter

        if name[:5] == 'with_':
            def has_filter(value):
                conf = {'has_%s' % name[5:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return has_filter

        return self.__getattribute__(name)

    def skip(self, count):
        return self._simpleWrap(SliceIterator, count)

    def limit(self, count):
        return self._simpleWrap(SliceIterator, 0, count)

    def slice(self, skip, limit):
        return self._simpleWrap(SliceIterator, skip, limit)

    def filter(self, filter_name):
        if self._current_page is None:
            raise Exception("Can't use `filter()` because no parent page was "
                            "set for this page iterator.")
        filter_conf = self._current_page.config.get(filter_name)
        if filter_conf is None:
            raise Exception("Couldn't find filter '%s' in the configuration "
                            "header for page: %s" %
                            (filter_name, self._current_page.path))
        accessor = self._getSettingAccessor()
        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf,
                                         accessor)

    def sort(self, setting_name=None, reverse=False):
        self._ensureUnlocked()
        self._unload()
        if setting_name is not None:
            accessor = self._getSettingAccessor()
            self._pages = SettingSortIterator(self._pages, setting_name,
                                              reverse, accessor)
        else:
            self._pages = NaturalSortIterator(self._pages, reverse)
        self._has_sorter = True
        return self

    def reset(self):
        self._ensureUnlocked()
        self._unload
        return self

    @property
    def _has_more(self):
        self._load()
        if self._pagination_slicer:
            return self._pagination_slicer.has_more
        return False

    def _simpleWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._ensureSorter()
        self._pages = it_class(self._pages, *args, **kwargs)
        if self._pagination_slicer is None and it_class is SliceIterator:
            self._pagination_slicer = self._pages
            self._pagination_slicer.current_page = self._current_page
        return self

    def _simpleNonSortedWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._pages = it_class(self._pages, *args, **kwargs)
        return self

    def _getSettingAccessor(self):
        accessor = None
        if isinstance(self._source, IPaginationSource):
            accessor = self._source.getSettingAccessor()
        return accessor

    def _ensureUnlocked(self):
        if self._locked:
            raise Exception(
                    "This page iterator has been locked, probably because "
                    "you're trying to tamper with pagination data.")

    def _ensureSorter(self):
        if self._has_sorter:
            return
        if isinstance(self._source, IPaginationSource):
            sort_it = self._source.getSorterIterator(self._pages)
            if sort_it is not None:
                self._pages = sort_it
        self._has_sorter = True

    def _unload(self):
        self._pagesData = None
        self._next_page = None
        self._prev_page = None

    def _load(self):
        if self._pagesData is not None:
            return

        if (self._current_page is not None and
                self._current_page.app.env.abort_source_use and
                isinstance(self._source, PageSource)):
            logger.debug("Aborting iteration from %s." %
                         self._current_page.ref_spec)
            raise AbortedSourceUseError()

        self._ensureSorter()

        it_chain = self._pages
        is_pgn_source = False
        if isinstance(self._source, IPaginationSource):
            is_pgn_source = True
            tail_it = self._source.getTailIterator(self._pages)
            if tail_it is not None:
                it_chain = tail_it

        self._pagesData = list(it_chain)

        if is_pgn_source and self._current_page and self._pagination_slicer:
            pn = [self._pagination_slicer.prev_page,
                    self._pagination_slicer.next_page]
            pn_it = self._source.getTailIterator(iter(pn))
            self._prev_page, self._next_page = (list(pn_it))

    def _debugRenderDoc(self):
        return "Contains %d items" % len(self)
Exemplo n.º 8
0
class PageIterator(object):
    def __init__(self,
                 source,
                 current_page=None,
                 pagination_filter=None,
                 offset=0,
                 limit=-1,
                 locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked

    @property
    def total_count(self):
        self._load()
        if self._pagination_slicer is not None:
            return self._pagination_slicer.inner_count
        return len(self._pagesData)

    @property
    def next_page(self):
        self._load()
        return self._next_page

    @property
    def prev_page(self):
        self._load()
        return self._prev_page

    def __len__(self):
        self._load()
        return len(self._pagesData)

    def __getitem__(self, key):
        self._load()
        return self._pagesData[key]

    def __iter__(self):
        self._load()
        self._iter_event.fire()
        return iter(self._pagesData)

    def __getattr__(self, name):
        if name[:3] == 'is_' or name[:3] == 'in_':

            def is_filter(value):
                conf = {'is_%s' % name[3:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)

            return is_filter

        if name[:4] == 'has_':

            def has_filter(value):
                conf = {name: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)

            return has_filter

        if name[:5] == 'with_':

            def has_filter(value):
                conf = {'has_%s' % name[5:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)

            return has_filter

        return self.__getattribute__(name)

    def skip(self, count):
        return self._simpleWrap(SliceIterator, count)

    def limit(self, count):
        return self._simpleWrap(SliceIterator, 0, count)

    def slice(self, skip, limit):
        return self._simpleWrap(SliceIterator, skip, limit)

    def filter(self, filter_name):
        if self._current_page is None:
            raise Exception("Can't use `filter()` because no parent page was "
                            "set for this page iterator.")
        filter_conf = self._current_page.config.get(filter_name)
        if filter_conf is None:
            raise Exception("Couldn't find filter '%s' in the configuration "
                            "header for page: %s" %
                            (filter_name, self._current_page.path))
        accessor = self._getSettingAccessor()
        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf,
                                         accessor)

    def sort(self, setting_name=None, reverse=False):
        self._ensureUnlocked()
        self._unload()
        if setting_name is not None:
            accessor = self._getSettingAccessor()
            self._pages = SettingSortIterator(self._pages, setting_name,
                                              reverse, accessor)
        else:
            self._pages = NaturalSortIterator(self._pages, reverse)
        self._has_sorter = True
        return self

    def reset(self):
        self._ensureUnlocked()
        self._unload
        return self

    @property
    def _has_more(self):
        self._load()
        if self._pagination_slicer:
            return self._pagination_slicer.has_more
        return False

    def _simpleWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._ensureSorter()
        self._pages = it_class(self._pages, *args, **kwargs)
        if self._pagination_slicer is None and it_class is SliceIterator:
            self._pagination_slicer = self._pages
            self._pagination_slicer.current_page = self._current_page
        return self

    def _simpleNonSortedWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._pages = it_class(self._pages, *args, **kwargs)
        return self

    def _getSettingAccessor(self):
        accessor = None
        if isinstance(self._source, IPaginationSource):
            accessor = self._source.getSettingAccessor()
        return accessor

    def _ensureUnlocked(self):
        if self._locked:
            raise Exception(
                "This page iterator has been locked, probably because "
                "you're trying to tamper with pagination data.")

    def _ensureSorter(self):
        if self._has_sorter:
            return
        if isinstance(self._source, IPaginationSource):
            sort_it = self._source.getSorterIterator(self._pages)
            if sort_it is not None:
                self._pages = sort_it
        self._has_sorter = True

    def _unload(self):
        self._pagesData = None
        self._next_page = None
        self._prev_page = None

    def _load(self):
        if self._pagesData is not None:
            return

        self._ensureSorter()

        it_chain = self._pages
        is_pgn_source = False
        if isinstance(self._source, IPaginationSource):
            is_pgn_source = True
            tail_it = self._source.getTailIterator(self._pages)
            if tail_it is not None:
                it_chain = tail_it

        self._pagesData = list(it_chain)

        if is_pgn_source and self._current_page and self._pagination_slicer:
            pn = [
                self._pagination_slicer.prev_page,
                self._pagination_slicer.next_page
            ]
            pn_it = self._source.getTailIterator(iter(pn))
            self._prev_page, self._next_page = (list(pn_it))
Exemplo n.º 9
0
class PageIterator:
    def __init__(self, source, *, current_page=None):
        self._source = source
        self._is_content_source = isinstance(source,
                                             (ContentSource, _CombinedSource))
        self._cache = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._locked = False
        self._load_event = Event()
        self._iter_event = Event()
        self._current_page = current_page
        self._initIterator()

    @property
    def total_count(self):
        self._load()
        if self._pagination_slicer is not None:
            return self._pagination_slicer.inner_count
        return len(self._cache)

    @property
    def next_page(self):
        self._load()
        return self._next_page

    @property
    def prev_page(self):
        self._load()
        return self._prev_page

    def __len__(self):
        self._load()
        return len(self._cache)

    def __getitem__(self, key):
        self._load()
        return self._cache[key]

    def __iter__(self):
        self._load()
        self._iter_event.fire(self)
        return iter(self._cache)

    def __getattr__(self, name):
        if name[:3] == 'is_' or name[:3] == 'in_':

            def is_filter(value):
                conf = {'is_%s' % name[3:]: value}
                return self._simpleNonSortedWrap(SettingFilterIterator, conf)

            return is_filter

        if name[:4] == 'has_':

            def has_filter(value):
                conf = {name: value}
                return self._simpleNonSortedWrap(SettingFilterIterator, conf)

            return has_filter

        if name[:5] == 'with_':

            def has_filter(value):
                conf = {'has_%s' % name[5:]: value}
                return self._simpleNonSortedWrap(SettingFilterIterator, conf)

            return has_filter

        return self.__getattribute__(name)

    def skip(self, count):
        return self._simpleWrap(SliceIterator, count)

    def limit(self, count):
        return self._simpleWrap(SliceIterator, 0, count)

    def slice(self, skip, limit):
        return self._simpleWrap(SliceIterator, skip, limit)

    def filter(self, filter_name):
        if self._current_page is None:
            raise Exception("Can't use `filter()` because no parent page was "
                            "set for this page iterator.")
        filter_conf = self._current_page.config.get(filter_name)
        if filter_conf is None:
            raise Exception("Couldn't find filter '%s' in the configuration "
                            "header for page: %s" %
                            (filter_name, self._current_page.path))
        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf)

    def sort(self, setting_name=None, reverse=False):
        if setting_name:
            self._wrapAsSort(SettingSortIterator, setting_name, reverse)
        else:
            self._wrapAsSort(NaturalSortIterator, reverse)
        return self

    def reset(self):
        self._ensureUnlocked()
        self._unload()
        return self

    @property
    def _is_loaded(self):
        return self._cache is not None

    @property
    def _has_more(self):
        self._load()
        if self._pagination_slicer:
            return self._pagination_slicer.has_more
        return False

    def _simpleWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._ensureUnloaded()
        self._ensureSorter()
        self._it = it_class(self._it, *args, **kwargs)
        if self._pagination_slicer is None and it_class is SliceIterator:
            self._pagination_slicer = self._it
            self._pagination_slicer.current_page = self._current_page
        return self

    def _simpleNonSortedWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._ensureUnloaded()
        self._it = it_class(self._it, *args, **kwargs)
        return self

    def _wrapAsSort(self, sort_it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._ensureUnloaded()
        self._it = sort_it_class(self._it, *args, **kwargs)
        self._has_sorter = True
        return self

    def _lockIterator(self):
        self._ensureUnlocked()
        self._locked = True

    def _ensureUnlocked(self):
        if self._locked:
            raise Exception(
                "This page iterator has been locked and can't be modified.")

    def _ensureUnloaded(self):
        if self._cache:
            raise Exception(
                "This page iterator has already been iterated upon and "
                "can't be modified anymore.")

    def _ensureSorter(self):
        if self._has_sorter:
            return
        if self._is_content_source:
            # For content sources, the default sorting is reverse
            # date/time sorting.
            self._it = DateSortIterator(self._it, reverse=True)
        self._has_sorter = True

    def _initIterator(self):
        if self._is_content_source:
            if isinstance(self._source, _CombinedSource):
                self._it = self._source
            else:
                self._it = PageContentSourceIterator(self._source)

            app = self._source.app
            if app.config.get('baker/is_baking'):
                # While baking, automatically exclude any page with
                # the `draft` setting.
                draft_setting = app.config['baker/no_bake_setting']
                self._it = NoDraftsIterator(self._it, draft_setting)
        else:
            self._it = GenericSourceIterator(self._source)

    def _unload(self):
        self._initIterator()
        self._cache = None
        self._paginationSlicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None

    def _load(self):
        if self._cache is not None:
            return

        self._ensureSorter()

        if self._is_content_source:
            self._it = PaginationDataBuilderIterator(self._it)

        self._cache = list(self._it)

        if (self._current_page is not None
                and self._pagination_slicer is not None):
            pn = [
                self._pagination_slicer.prev_page,
                self._pagination_slicer.next_page
            ]
            pn_it = PaginationDataBuilderIterator(iter(pn))
            self._prev_page, self._next_page = (list(pn_it))

        self._load_event.fire(self)

    def _debugRenderDoc(self):
        return "Contains %d items" % len(self)
Exemplo n.º 10
0
 def __setstate__(self, state):
     state['entry_added'] = Event()
     self.__dict__.update(state)
Exemplo n.º 11
0
 def __init__(self):
     self.entries = []
     self.entry_added = Event()
     self.app_version = APP_VERSION
     self.record_version = self.__class__.RECORD_VERSION
Exemplo n.º 12
0
class PageIterator(object):
    def __init__(self, source, current_page=None, pagination_filter=None,
            offset=0, limit=-1, locked=False):
        self._source = source
        self._current_page = current_page
        self._locked = False
        self._pages = source
        self._pagesData = None
        self._pagination_slicer = None
        self._has_sorter = False
        self._next_page = None
        self._prev_page = None
        self._iter_event = Event()

        if isinstance(source, IPaginationSource):
            src_it = source.getSourceIterator()
            if src_it is not None:
                self._pages = src_it

        # Apply any filter first, before we start sorting or slicing.
        if pagination_filter is not None:
            self._simpleNonSortedWrap(PaginationFilterIterator,
                                      pagination_filter)

        if offset > 0 or limit > 0:
            self.slice(offset, limit)

        self._locked = locked

    @property
    def total_count(self):
        self._load()
        if self._pagination_slicer is not None:
            return self._pagination_slicer.inner_count
        return len(self._pagesData)

    @property
    def next_page(self):
        self._load()
        return self._next_page

    @property
    def prev_page(self):
        self._load()
        return self._prev_page

    def __len__(self):
        self._load()
        return len(self._pagesData)

    def __getitem__(self, key):
        self._load()
        return self._pagesData[key]

    def __iter__(self):
        self._load()
        self._iter_event.fire()
        return iter(self._pagesData)

    def __getattr__(self, name):
        if name[:3] == 'is_' or name[:3] == 'in_':
            def is_filter(value):
                conf = {'is_%s' % name[3:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return is_filter

        if name[:4] == 'has_':
            def has_filter(value):
                conf = {name: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return has_filter

        if name[:5] == 'with_':
            def has_filter(value):
                conf = {'has_%s' % name[5:]: value}
                accessor = self._getSettingAccessor()
                return self._simpleNonSortedWrap(SettingFilterIterator, conf,
                                                 accessor)
            return has_filter

        return self.__getattribute__(name)

    def skip(self, count):
        return self._simpleWrap(SliceIterator, count)

    def limit(self, count):
        return self._simpleWrap(SliceIterator, 0, count)

    def slice(self, skip, limit):
        return self._simpleWrap(SliceIterator, skip, limit)

    def filter(self, filter_name):
        if self._current_page is None:
            raise Exception("Can't use `filter()` because no parent page was "
                            "set for this page iterator.")
        filter_conf = self._current_page.config.get(filter_name)
        if filter_conf is None:
            raise Exception("Couldn't find filter '%s' in the configuration "
                            "header for page: %s" %
                            (filter_name, self._current_page.path))
        accessor = self._getSettingAccessor()
        return self._simpleNonSortedWrap(SettingFilterIterator, filter_conf,
                                         accessor)

    def sort(self, setting_name=None, reverse=False):
        self._ensureUnlocked()
        self._unload()
        if setting_name is not None:
            accessor = self._getSettingAccessor()
            self._pages = SettingSortIterator(self._pages, setting_name,
                                              reverse, accessor)
        else:
            self._pages = NaturalSortIterator(self._pages, reverse)
        self._has_sorter = True
        return self

    def reset(self):
        self._ensureUnlocked()
        self._unload
        return self

    @property
    def _has_more(self):
        self._load()
        if self._pagination_slicer:
            return self._pagination_slicer.has_more
        return False

    def _simpleWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._ensureSorter()
        self._pages = it_class(self._pages, *args, **kwargs)
        if self._pagination_slicer is None and it_class is SliceIterator:
            self._pagination_slicer = self._pages
            self._pagination_slicer.current_page = self._current_page
        return self

    def _simpleNonSortedWrap(self, it_class, *args, **kwargs):
        self._ensureUnlocked()
        self._unload()
        self._pages = it_class(self._pages, *args, **kwargs)
        return self

    def _getSettingAccessor(self):
        accessor = None
        if isinstance(self._source, IPaginationSource):
            accessor = self._source.getSettingAccessor()
        return accessor

    def _ensureUnlocked(self):
        if self._locked:
            raise Exception(
                    "This page iterator has been locked, probably because "
                    "you're trying to tamper with pagination data.")

    def _ensureSorter(self):
        if self._has_sorter:
            return
        if isinstance(self._source, IPaginationSource):
            sort_it = self._source.getSorterIterator(self._pages)
            if sort_it is not None:
                self._pages = sort_it
        self._has_sorter = True

    def _unload(self):
        self._pagesData = None
        self._next_page = None
        self._prev_page = None

    def _load(self):
        if self._pagesData is not None:
            return

        self._ensureSorter()

        it_chain = self._pages
        is_pgn_source = False
        if isinstance(self._source, IPaginationSource):
            is_pgn_source = True
            tail_it = self._source.getTailIterator(self._pages)
            if tail_it is not None:
                it_chain = tail_it

        self._pagesData = list(it_chain)

        if is_pgn_source and self._current_page and self._pagination_slicer:
            pn = [self._pagination_slicer.prev_page,
                    self._pagination_slicer.next_page]
            pn_it = self._source.getTailIterator(iter(pn))
            self._prev_page, self._next_page = (list(pn_it))