diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py index 5fac2645bf..01137a8ee7 100644 --- a/pywikibot/data/api.py +++ b/pywikibot/data/api.py @@ -3268,3 +3268,9 @@ def update_page(page, pagedict, props=[]): if "flowinfo" in pagedict: page._flowinfo = pagedict['flowinfo']['flow'] + + if 'lintId' in pagedict: + page._lintinfo = pagedict + page._lintinfo.pop('pageid') + page._lintinfo.pop('title') + page._lintinfo.pop('ns') diff --git a/pywikibot/page.py b/pywikibot/page.py index 12d847b661..e44f393342 100644 --- a/pywikibot/page.py +++ b/pywikibot/page.py @@ -160,7 +160,7 @@ class BasePage(UnicodeMixin, ComparableMixin): '_contentmodel', '_langlinks', '_isredir', '_coords', '_preloadedtext', '_timestamp', '_applicable_protections', '_flowinfo', '_quality', '_pageprops', '_revid', '_quality_text', - '_pageimage', '_item' + '_pageimage', '_item', '_lintinfo', ) def __init__(self, source, title=u"", ns=0): diff --git a/pywikibot/pagegenerators.py b/pywikibot/pagegenerators.py index e67b64ea14..ab4ed51e88 100644 --- a/pywikibot/pagegenerators.py +++ b/pywikibot/pagegenerators.py @@ -276,6 +276,19 @@ "-pageid:pageid1,pageid2,." or "-pageid:'pageid1|pageid2|..'" and supplied multiple times for multiple pages. +-linter Work on pages that contains lint errors. Extension Linter + must be available on the site. + -linter select all categories. + -linter:high, -linter:medium or -linter:low select all + categories for that prio. + Single categories can be selected with commas as in + -linter:cat1,cat2,cat3 + + Adding '/int' indentifies Lint ID to start querying from: + e.g. -linter:high/10000 + + -linter:show just shows available categories. + FILTER OPTIONS ============== @@ -312,9 +325,9 @@ -ns:not:2,3 -ns:not:Help,File - If used with -newpages/-random/-randomredirect generators, - -namespace/ns must be provided before - -newpages/-random/-randomredirect. + If used with -newpages/-random/-randomredirect/linter + generators, -namespace/ns must be provided before + -newpages/-random/-randomredirect/linter. If used with -recentchanges generator, efficiency is improved if -namespace is provided before -recentchanges. @@ -699,6 +712,41 @@ def intNone(v): value = 'Image:' + value page = pywikibot.FilePage(self.site, value) gen = FileLinksGenerator(page) + elif arg == '-linter': + if not self.site.has_extension('Linter'): + raise UnknownExtension( + '-linter needs a site with Linter extension.') + cats = self.site.siteinfo.get('linter') # Get linter categories. + valid_cats = [c for _list in cats.values() for c in _list] + + cat, sep, lint_from = value.partition('/') + if not lint_from: + lint_from = None + + if cat == 'show': # Display categories of lint errors. + _i = ' ' * 4 + txt = 'Available categories of lint errors:\n' + for prio, _list in cats.items(): + txt += '{indent}{prio}\n'.format(indent=_i, prio=prio) + for c in _list: + txt += '{indent}{cat}\n'.format(indent=2 * _i, cat=c) + pywikibot.output('%s' % txt) + return True + + if not cat: + lint_cats = valid_cats + elif cat in ['low', 'medium', 'high']: + lint_cats = cats[cat] + else: + lint_cats = cat.split(',') + for lint_cat in lint_cats: + if lint_cat not in valid_cats: + raise ValueError('Invalid category of lint errors: %s' + % cat) + + gen = self.site.linter_pages(lint_categories='|'.join(lint_cats), + namespaces=self.namespaces, + lint_from=lint_from) elif arg == '-unusedfiles': gen = UnusedFilesGenerator(total=intNone(value), site=self.site) elif arg == '-lonelypages': diff --git a/pywikibot/site.py b/pywikibot/site.py index c174f1db83..1eff176934 100644 --- a/pywikibot/site.py +++ b/pywikibot/site.py @@ -6883,6 +6883,61 @@ def get_param(item): comparison = data['compare']['*'] return comparison + @need_extension('Linter') + def linter_pages(self, lint_categories=None, total=None, + namespaces=None, pageids=None, lint_from=None): + """Return a generator to pages containing linter errors. + + @param lint_categories: categories of lint errors + @type lntcategories: an iterable that returns values (str), + or a pipe-separated string of values. + + @param total: if not None, yielding this many items in total + @type total: int + + @param namespaces: only iterate pages in these namespaces + @type namespaces: iterable of basestring or Namespace key, + or a single instance of those types. May be a '|' separated + list of namespace identifiers. + + @param pageids: only include lint errors from the specified pageids + @type pageids: an iterable that returns pageids (str or int), + or a comma- or pipe-separated string of pageids + (e.g. '945097,1483753, 956608' or '945097|483753|956608') + + @param lint_from: Lint ID to start querying from + @type lint_from: str representing digit or integer + + @return: pages with Linter errors. + @rtype: generator of Page + + """ + query = self._generator(api.ListGenerator, type_arg='linterrors', + total=total, # Will set lntlimit + namespaces=namespaces) + + if lint_categories: + if isinstance(lint_categories, basestring): + lint_categories = lint_categories.split('|') + lint_categories = [p.strip() for p in lint_categories] + query.request['lntcategories'] = '|'.join(lint_categories) + + if pageids: + if isinstance(pageids, basestring): + pageids = pageids.split('|') + pageids = [p.strip() for p in pageids] + # Validate pageids. + pageids = (str(int(p)) for p in pageids if int(p) > 0) + query.request['lntpageid'] = '|'.join(pageids) + + if lint_from: + query.request['lntfrom'] = int(lint_from) + + for pageitem in query: + page = pywikibot.Page(self, pageitem['title']) + api.update_page(page, pageitem) + yield page + # Thanks API calls @need_extension('Thanks') def thank_revision(self, revid, source=None): diff --git a/tests/pagegenerators_tests.py b/tests/pagegenerators_tests.py index 11e4d6b356..4ebfefa556 100755 --- a/tests/pagegenerators_tests.py +++ b/tests/pagegenerators_tests.py @@ -1177,6 +1177,18 @@ def test_positionalargument_with_colon(self): self.assertIsNotNone(gen2) self.assertEqual(list(gen1), list(gen2)) + def test_linter_generator_ns_multi(self): + """Test random generator with multiple namespaces.""" + gf = pagegenerators.GeneratorFactory(site=self.site) + gf.handleArg('-ns:1') + gf.handleArg('-limit:3') + gf.handleArg('-linter:obsolete-tag') + gen = gf.getCombinedGenerator() + self.assertIsNotNone(gen) + pages = list(gen) + self.assertPagesInNamespaces(pages, set([1, ])) + self.assertEqual(len(pages), 3) + class TestFactoryGeneratorWikibase(WikidataTestCase): diff --git a/tests/site_tests.py b/tests/site_tests.py index 0acfa44256..bd5ec920dc 100644 --- a/tests/site_tests.py +++ b/tests/site_tests.py @@ -1065,6 +1065,21 @@ def test_unconnected(self): self.assertLessEqual(len(tuple(upgen)), 3) +class TestLinterPages(DefaultSiteTestCase): + + """Test linter_pages methods.""" + + def test_linter_pages(self): + """Test the deprecated site.logpages() method.""" + le = list(self.site.linter_pages( + lint_categories='obsolete-tag|missing-end-tag', total=5)) + self.assertLessEqual(len(le), 5) + for entry in le: + self.assertIsInstance(entry, pywikibot.Page) + self.assertIn(entry._lintinfo['category'], + ['obsolete-tag', 'missing-end-tag']) + + class TestImageUsage(DefaultSiteTestCase): """Test cases for Site.imageusage method."""