def getPDFTitle(self, ref, f): """Use pdfinfo to retrieve title from a PDF. FIXME: Unix-only, I'm afraid. """ pywikibot.output(u'PDF file.') fd, infile = tempfile.mkstemp() urlobj = os.fdopen(fd, 'w+') urlobj.write(f.content) try: pdfinfo_out = subprocess.Popen([r"pdfinfo", "/dev/stdin"], stdin=urlobj, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False).communicate()[0] for aline in pdfinfo_out.splitlines(): if aline.lower().startswith('title'): ref.title = aline.split(None)[1:] ref.title = ' '.join(ref.title) if ref.title != '': pywikibot.output(u'title: %s' % ref.title) pywikibot.output(u'PDF done.') except ValueError: pywikibot.output(u'pdfinfo value error.') except OSError: pywikibot.output(u'pdfinfo OS error.') except Exception: # Ignore errors pywikibot.output(u'PDF processing error.') pywikibot.exception() finally: urlobj.close() os.unlink(infile)
def main(): local_args = pywikibot.handleArgs() cache_paths = None delete = False command = None for arg in local_args: if command == '': command = arg elif arg == '-delete': delete = True elif arg == '-password': command = 'has_password(entry)' elif arg == '-c': if command: pywikibot.error('Only one command may be executed.') exit(1) command = '' else: if not cache_paths: cache_paths = [arg] else: cache_paths.append(arg) func = None if not cache_paths: cache_paths = ['apicache', 'tests/apicache'] # Also process the base directory, if it isnt the current directory if os.path.abspath(os.getcwd()) != pywikibot.config2.base_dir: cache_paths += [ os.path.join(pywikibot.config2.base_dir, 'apicache')] # Also process the user home cache, if it isnt the config directory if os.path.expanduser('~/.pywikibot') != pywikibot.config2.base_dir: cache_paths += [ os.path.join(os.path.expanduser('~/.pywikibot'), 'apicache')] if delete: action_func = lambda entry: entry._delete() else: action_func = lambda entry: pywikibot.output(entry) if command: try: command_func = eval('lambda entry: ' + command) except: pywikibot.exception() pywikibot.error(u'Can not compile command: %s' % command) exit(1) func = lambda entry: command_func(entry) and action_func(entry) else: func = action_func for cache_path in cache_paths: if len(cache_paths) > 1: pywikibot.output(u'Processing %s' % cache_path) process_entries(cache_path, func)
def revert(self, item): history = pywikibot.Page(self.site, item['title']).fullVersionHistory( total=2, rollback=self.rollback) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate(pywikibot.Site(), 'revertbot-revert', {'revid': rev[0], 'author': rev[2], 'timestamp': rev[1]}) if self.comment: comment += ': ' + self.comment page = pywikibot.Page(self.site, item['title']) pywikibot.output(u"\n\n>>> \03{lightpurple}%s\03{default} <<<" % page.title(asLink=True, forceInterwiki=True, textlink=True)) if not self.rollback: old = page.text page.text = rev[3] pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request(action="rollback", title=page.title(), user=self.user, token=rev[4], markbot=1).submit() except pywikibot.data.api.APIError as e: if e.code == 'badtoken': pywikibot.error("There was an API token error rollbacking the edit") else: pywikibot.exception() return False return u"The edit(s) made in %s by %s was rollbacked" % (page.title(), self.user)
def revert(self, item): history = pywikibot.Page(self.site, item["title"]).fullVersionHistory(total=2, rollback=self.rollback) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate( pywikibot.Site(), "revertbot-revert", {"revid": rev[0], "author": rev[2], "timestamp": rev[1]} ) if self.comment: comment += ": " + self.comment page = pywikibot.Page(self.site, item["title"]) pywikibot.output( "\n\n>>> \03{lightpurple}%s\03{default} <<<" % page.title(asLink=True, forceInterwiki=True, textlink=True) ) if not self.rollback: old = page.text page.text = rev[3] pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request( self.site, parameters={"action": "rollback", "title": page, "user": self.user, "token": rev[4], "markbot": True}, ).submit() except pywikibot.data.api.APIError as e: if e.code == "badtoken": pywikibot.error("There was an API token error rollbacking the edit") else: pywikibot.exception() return False return "The edit(s) made in %s by %s was rollbacked" % (page.title(), self.user)
def run(self): """Process all pages in generator.""" if not hasattr(self, 'generator'): raise NotImplementedError('Variable %s.generator not set.' % self.__class__.__name__) treat_missing_item = hasattr(self, 'treat_missing_item') try: for page in self.generator: if not page.exists(): pywikibot.output('%s doesn\'t exist.' % page) try: item = pywikibot.ItemPage.fromPage(page) except pywikibot.NoPage: item = None if not item: if not treat_missing_item: pywikibot.output( '%s doesn\'t have a wikidata item.' % page) #TODO FIXME: Add an option to create the item continue self.treat(page, item) except QuitKeyboardInterrupt: pywikibot.output('\nUser quit %s bot run...' % self.__class__.__name__) except KeyboardInterrupt: if config.verbose_output: raise else: pywikibot.output('\nKeyboardInterrupt during %s bot run...' % self.__class__.__name__) except Exception as e: pywikibot.exception(msg=e, tb=True)
def main(*args): """ Process command line arguments and invoke bot. If args is an empty list, sys.argv is used. @param args: command line arguments @type args: list of unicode """ all = False new = False sysop = False for arg in pywikibot.handle_args(args): if arg in ('-all', '-update'): all = True elif arg == '-new': new = True elif arg == '-sysop': sysop = True if all: refresh_all(sysop=sysop) elif new: refresh_new(sysop=sysop) else: site = pywikibot.Site() watchlist = refresh(site, sysop=sysop) pywikibot.output(u'{0:d} pages in the watchlist.'.format(len(watchlist))) for page in watchlist: try: pywikibot.stdout(page.title()) except pywikibot.InvalidTitle: pywikibot.exception()
def main_script(page, rev=None, params=NotImplemented): # pylint: disable=unused-argument """Main thread.""" # http://opensourcehacker.com/2011/02/23/temporarily-capturing-python-logging-output-to-a-string-buffer/ # https://docs.python.org/release/2.6/library/logging.html from io import StringIO import logging # safety; default mode is safe (no writing) pywikibot.config.simulate = True pywikibot.output(u'--- ' * 20) buffer = StringIO() rootLogger = logging.getLogger() logHandler = logging.StreamHandler(buffer) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") logHandler.setFormatter(formatter) rootLogger.addHandler(logHandler) sys.stdout = buffer sys.stderr = buffer # all output to logging and stdout/stderr is catched BUT NOT lua output (!) if rev is None: code = page.get() # shell; "on demand" else: code = page.getOldVersion(rev) # crontab; scheduled try: exec(code) except: # (done according to subster in trunk and submit in rewrite/.../data/api.py) pywikibot.exception(tb=True) # secure traceback print (from api.py submit) sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ # Remove our handler rootLogger.removeHandler(logHandler) logHandler.flush() buffer.flush() pywikibot.output(u'--- ' * 20) # safety; restore settings pywikibot.config.simulate = __simulate sys.argv = __sys_argv pywikibot.output( u'environment: garbage; %s / memory; %s / members; %s' % ( gc.collect(), resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * resource.getpagesize(), len(dir()))) # 'len(dir())' is equivalent to 'len(inspect.getmembers(__main__))' # append result to output page if rev is None: wiki_logger(buffer.getvalue(), page, rev)
def run(self): """Starts the robot.""" self.templateTitles = self.getTemplateSynonyms(self.templateTitle) for page in self.generator: try: self.processPage(page) except Exception as e: pywikibot.exception(msg=e, tb=True)
def main(): local_args = pywikibot.handleArgs() cache_paths = None delete = False command = None for arg in local_args: if command == "": command = arg elif arg == "-delete": delete = True elif arg == "-password": command = "has_password(entry)" elif arg == "-c": if command: pywikibot.error("Only one command may be executed.") exit(1) command = "" else: if not cache_paths: cache_paths = [arg] else: cache_paths.append(arg) func = None if not cache_paths: cache_paths = ["apicache", "tests/apicache"] # Also process the base directory, if it isnt the current directory if os.path.abspath(os.getcwd()) != pywikibot.config2.base_dir: cache_paths += [os.path.join(pywikibot.config2.base_dir, "apicache")] # Also process the user home cache, if it isnt the config directory if os.path.expanduser("~/.pywikibot") != pywikibot.config2.base_dir: cache_paths += [os.path.join(os.path.expanduser("~/.pywikibot"), "apicache")] if delete: action_func = lambda entry: entry._delete() else: action_func = lambda entry: pywikibot.output(entry) if command: try: command_func = eval("lambda entry: " + command) except: pywikibot.exception() pywikibot.error("Can not compile command: %s" % command) exit(1) func = lambda entry: command_func(entry) and action_func(entry) else: func = action_func for cache_path in cache_paths: if len(cache_paths) > 1: pywikibot.output("Processing %s" % cache_path) process_entries(cache_path, func)
def test_exception(self): class TestException(Exception): pass try: raise TestException("Testing Exception") except TestException: pywikibot.exception("exception") self.assertEqual(newstdout.getvalue(), "") self.assertEqual(newstderr.getvalue(), "ERROR: TestException: Testing Exception\n")
def treat(self, page): pywikibot.output(u'parsing {}'.format(page)) item = pywikibot.ItemPage.fromPage(page) if not item.exists(): pywikibot.warning(u'item not found for {}'.format(page)) return text = page.text code = mwparserfromhell.parse(page.text) removed = [] for template in code.ifilter_templates(): if template.name.strip().title() != 'Autore': continue for pcode, pname in self.params.items(): if template.has(pname, False): val = template.get(pname).value.strip() if val == '' or getattr(self, 'handle_' + pcode)(val, item) is True: template.remove(pname, keep_field=False) removed.append(pname) sections = {} sbeg = None elements = code.filter() for el in code.ifilter_tags(): if el.tag == 'section' and el.self_closing is True: if el.has('begin'): sbeg = el elif sbeg and el.has('end'): sname = unicode(sbeg.get('begin').value) if unicode(el.get('end').value) == sname: start = elements.index(sbeg) + 2 + len(sbeg.attributes) * 2 sections[sname] = [sbeg] + elements[start:elements.index(el) + 1] for scode, sname in self.params.items(): if sname in sections: val = ''.join(map(unicode, sections[sname][1:-1])).strip() if val == '' or getattr(self, 'handle_' + scode)(val, item) is True: for el in sections[sname]: code.remove(el) removed.append(sname) if len(removed) == 6: remset = list(set(removed)) if len(remset) != 3: return removed = list(remset) text = unicode(code) text = re.sub('(?<=\/\>)(\n\s*)+(?=\n\<)', '', text) comment = i18n.translate(page.site, wikidata_summary[1], {'counter': len(removed), 'params': page.site.list_to_text(removed), 'id': item.getID() }) try: self.userPut(page, page.text, text, comment=comment, minor=True, botflag=True) except Exception as e: pywikibot.exception(e)
def setUpClass(cls): """ Set up the test class. Prevent tests running if the host is down. """ super(CheckHostnameMixin, cls).setUpClass() if not hasattr(cls, 'sites'): return for key, data in cls.sites.items(): if 'hostname' not in data: raise Exception('%s: hostname not defined for %s' % (cls.__name__, key)) hostname = data['hostname'] if hostname in cls._checked_hostnames: if isinstance(cls._checked_hostnames[hostname], Exception): raise unittest.SkipTest( '%s: hostname %s failed (cached): %s' % (cls.__name__, hostname, cls._checked_hostnames[hostname])) elif cls._checked_hostnames[hostname] is False: raise unittest.SkipTest('%s: hostname %s failed (cached)' % (cls.__name__, hostname)) else: continue e = None try: if '://' not in hostname: hostname = 'http://' + hostname r = http.fetch(uri=hostname, default_error_handling=False) if r.exception: e = r.exception else: if r.status not in [200, 301, 302, 303, 307, 308]: raise ServerError('HTTP status: %d' % r.status) r.content # default decode may raise exception except Exception as e2: pywikibot.error('%s: accessing %s caused exception:' % (cls.__name__, hostname)) pywikibot.exception(e2, tb=True) e = e2 pass if e: cls._checked_hostnames[hostname] = e raise unittest.SkipTest( '%s: hostname %s failed: %s' % (cls.__name__, hostname, e)) cls._checked_hostnames[hostname] = True
def test_exception(self): class TestException(Exception): """Test exception.""" try: raise TestException('Testing Exception') except TestException: pywikibot.exception('exception') self.assertEqual(newstdout.getvalue(), '') self.assertEqual(newstderr.getvalue(), 'ERROR: TestException: Testing Exception\n')
def safe_execute(self, method, text): """Execute the method and catch exceptions if enabled.""" result = None try: result = method(text) except Exception as e: if self.ignore == CANCEL_METHOD: pywikibot.warning('Unable to perform "{0}" on "{1}"!'.format(method.__name__, self.title)) pywikibot.exception(e) else: raise return text if result is None else result
def do_check(self, page_title, rev=None, params=None): # Create two threads as follows # (simple 'thread' for more sophisticated code use 'threading') try: thread.start_new_thread(main_script, (self.refs[page_title], rev, params)) except: # (done according to subster in trunk and submit in rewrite/.../data/api.py) # TODO: is this error handling here needed at all??!? pywikibot.exception(tb=True) # secure traceback print (from api.py submit) pywikibot.warning("Unable to start thread") wiki_logger(traceback.format_exc(), self.refs[page_title], rev)
def _parse_command(command, name): obj = globals().get(command) if callable(obj): return obj else: try: return eval('lambda entry: ' + command) except: pywikibot.exception() pywikibot.error( 'Cannot compile {0} command: {1}'.format(name, command)) return None
def _parse_command(command, name): """Parse command.""" obj = globals().get(command) if callable(obj): return obj else: try: return eval('lambda entry: ' + command) except Exception: pywikibot.exception() pywikibot.error( 'Cannot compile {0} command: {1}'.format(name, command)) return None
def safe_execute(self, method, text): """Execute the method and catch exceptions if enabled.""" result = None try: result = method(text) except Exception as e: if self.ignore == CANCEL_METHOD: pywikibot.warning('Unable to perform "{0}" on "{1}"!'.format( method.__name__, self.title)) pywikibot.exception(e) else: raise return text if result is None else result
def save_list(page_list: list[pywikibot.Page], page: Page) -> None: """ Write the given page_list to the given page. :param page_list: List of pages to output :param page: Page to save to """ list_text = "" for item in sorted(page_list): list_text += f"\n# {item.title(as_link=True, textlink=True)}" try: page.save_bot_start_end(list_text, summary="Updating list", force=True) except pywikibot.exceptions.Error: pywikibot.exception(tb=True)
def userIsExperienced(self, username): """ Check whether is this user is experienced. user is experienced if edits >= 50 changed to 25 // 20150309 """ try: user = pywikibot.User(self.site, username) except pywikibot.InvalidTitle: pywikibot.exception() return False return user.editCount() >= self.useredits
def do_check(self, page_title, rev=None, params=None): # Create two threads as follows # (simple 'thread' for more sophisticated code use 'threading') try: thread.start_new_thread(main_script, (self.refs[page_title], rev, params)) except: # (done according to subster in trunk and submit in rewrite/.../data/api.py) # TODO: is this error handling here needed at all??!? pywikibot.exception( tb=True) # secure traceback print (from api.py submit) pywikibot.warning(u"Unable to start thread") wiki_logger(traceback.format_exc(), self.refs[page_title], rev)
def wrapper(*args, **kwargs): try: func(*args, **kwargs) except AssertionError: tb = traceback.extract_tb(sys.exc_info()[2]) for depth, line in enumerate(tb): if re.match('^assert[A-Z]', line[2]): break tb = traceback.format_list(tb[:depth]) pywikibot.error('\n' + ''.join(tb)[:-1]) # remove \n at the end raise unittest.SkipTest('Test is allowed to fail.') except Exception: pywikibot.exception(tb=True) raise unittest.SkipTest('Test is allowed to fail.')
def process_entries(cache_dir, func): """ Check the contents of the cache. """ # This program tries to use file access times to determine # whether cache files are being used. # However file access times are not always usable. # On many modern filesystems, they have been disabled. # On unix, check the filesystem mount options. You may # need to remount with 'strictatime'. # - None = detect # - False = dont use # - True = always use use_accesstime = None if not cache_dir: cache_dir = os.path.join(pywikibot.config2.base_dir, 'apicache') for filename in os.listdir(cache_dir): filepath = os.path.join(cache_dir, filename) if use_accesstime is not False: stinfo = os.stat(filepath) entry = CacheEntry(cache_dir, filename) entry._load_cache() if use_accesstime is None: stinfo2 = os.stat(filepath) use_accesstime = stinfo.st_atime != stinfo2.st_atime if use_accesstime: # Reset access times to values before loading cache entry. os.utime(filepath, (stinfo.st_atime, stinfo.st_mtime)) entry.stinfo = stinfo try: entry.parse_key() except ParseError: pywikibot.error(u'Problems parsing %s with key %s' % (entry.filename, entry.key)) pywikibot.exception() continue try: entry._rebuild() except Exception: pywikibot.error(u'Problems loading %s with key %s, %r' % (entry.filename, entry.key, entry._parsed_key)) pywikibot.exception() continue func(entry)
def change(self, text): """Execute all clean up methods and catch errors if activated.""" try: new_text = self._change(text) except Exception as e: if self.ignore == CANCEL_PAGE: pywikibot.warning(u'Skipped "{0}", because an error occured.'.format(self.title)) pywikibot.exception(e) return False else: raise else: if self.diff: pywikibot.showDiff(text, new_text) return new_text
def checkORES(self, page): revision = page._rcinfo.get('revision') ores = str(revision.get('new')) url = 'https://ores.wmflabs.org/v3/scores/eswiki/' + ores retornar = {} r = requests.get(url=url) data = r.json() try: goodfaith = data.get('eswiki').get('scores').get(ores).get('goodfaith') damaging = data.get('eswiki').get('scores').get(ores).get('damaging') buena_fe = goodfaith.get('score').get('probability').get('true') danina = damaging.get('score').get('probability').get('true') return (ores, buena_fe, danina, True if buena_fe < self.getOption('gf') or danina > self.getOption('dm') else False) except: pywikibot.exception()
def test_exception_tb(self): class TestException(Exception): pass try: raise TestException("Testing Exception") except TestException: pywikibot.exception("exception", tb=True) self.assertEqual(newstdout.getvalue(), "") stderrlines = newstderr.getvalue().split("\n") self.assertEqual(stderrlines[0], "ERROR: TestException: Testing Exception") self.assertEqual(stderrlines[1], "Traceback (most recent call last):") self.assertEqual(stderrlines[3], """ raise TestException("Testing Exception")""") self.assertEqual(stderrlines[4], "TestException: Testing Exception") self.assertNotEqual(stderrlines[-1], "\n")
def test_exception_tb(self): try: raise TestExceptionError('Testing Exception') except TestExceptionError: pywikibot.exception('exception', tb=True) self.assertEqual(newstdout.getvalue(), '') stderrlines = newstderr.getvalue().split('\n') self.assertEqual(stderrlines[0], 'ERROR: TestExceptionError: Testing Exception') self.assertEqual(stderrlines[1], 'Traceback (most recent call last):') self.assertEqual(stderrlines[3], " raise TestExceptionError('Testing Exception')") self.assertTrue(stderrlines[4].endswith(': Testing Exception')) self.assertNotEqual(stderrlines[-1], '\n')
def revert(self, item): """Revert a single item.""" page = pywikibot.Page(self.site, item['title']) history = list(page.revisions(total=2)) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate(self.site, 'revertbot-revert', { 'revid': rev.revid, 'author': rev.user, 'timestamp': rev.timestamp }) additional_comment = self.getOption('comment') if additional_comment: comment += ': ' + additional_comment pywikibot.output( color_format( '\n\n>>> {lightpurple}{0}{default} <<<', page.title(as_link=True, force_interwiki=True, textlink=True))) if not self.getOption('rollback'): old = page.text page.text = page.getOldVersion(rev.revid) pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request(self.site, parameters={ 'action': 'rollback', 'title': page, 'user': self.user, 'token': rev.rollbacktoken, 'markbot': True }).submit() except pywikibot.data.api.APIError as e: if e.code == 'badtoken': pywikibot.error( 'There was an API token error rollbacking the edit') else: pywikibot.exception() return False return 'The edit(s) made in {0} by {1} was rollbacked'.format( page.title(), self.user)
def process_result(self, result): entity_gid, url_gid, wikipage = result wp.debug("» {wp} https://musicbrainz.org/{entitytype}/{gid}".format( entitytype=self._current_entity_type.replace("_", "-"), wp=wikipage, gid=entity_gid), layer="") try: itempage = get_wikidata_itempage_from_wikilink(wikipage) except wp.NoSuchSite: wp.warning("{page} no supported family".format(page=wikipage)) return except (wp.BadTitle, wp.InvalidTitle) as e: wp.error( "Bad or invalid title received while processing {page}".format( page=wikipage)) wp.exception(e, tb=True) return except IsDisambigPage: wp.warning("{page} is a disambiguation page".format(page=wikipage)) return except IsRedirectPage as e: wp.debug("{page} is a redirect".format(page=wikipage), layer="") self.fix_redirect(url_gid, e.old, e.new) return except ValueError as e: wp.output(e) return if itempage is None: wp.debug( u"There's no wikidata page for {mbid}".format(mbid=entity_gid), layer="") return if any((key.lower() == self.property_id.lower() and claim.target == entity_gid) for key, claims in itempage.claims.items() for claim in claims): wp.debug( u"{page} already has property {pid} with value {mbid}".format( page=wikipage, mbid=entity_gid, pid=self.property_id), layer="") self.donefunc(entity_gid) return wp.debug("{mbid} is not linked in Wikidata".format(mbid=entity_gid), layer="") self.add_mbid_claim_to_item(itempage, entity_gid)
def process_result(self, result): entity_gid, url_gid, wikipage = result wp.debug("» {wp} https://musicbrainz.org/{entitytype}/{gid}".format( entitytype=self._current_entity_type.replace("_", "-"), wp=wikipage, gid=entity_gid ), layer="") try: itempage = get_wikidata_itempage_from_wikilink(wikipage) except wp.NoSuchSite: wp.warning("{page} no supported family".format(page=wikipage)) return except (wp.BadTitle, wp.InvalidTitle) as e: wp.error("Bad or invalid title received while processing {page}".format(page=wikipage)) wp.exception(e, tb=True) return except SkipPage as e: wp.warning("{page} is being skipped because: {reason}".format(page=wikipage, reason=e)) return except IsRedirectPage as e: wp.debug("{page} is a redirect".format(page=wikipage), layer="") if self.can_edit: self.fix_redirect(url_gid, e.old, e.new) return except ValueError as e: wp.output(e) return if itempage is None: wp.debug(u"There's no wikidata page for {mbid}".format(mbid=entity_gid), layer="") return if any((key.lower() == self.property_id.lower() and claim.target == entity_gid) for key, claims in itempage.claims.items() for claim in claims): wp.debug(u"{page} already has property {pid} with value {mbid}". format(page=wikipage, mbid=entity_gid, pid=self.property_id), layer="") self.donefunc(entity_gid) return wp.debug("{mbid} is not linked in Wikidata".format( mbid=entity_gid), layer="") self.add_mbid_claim_to_item(itempage, entity_gid)
def _get_voter(username, eligibility_dict): voter = pywikibot.User(COMMONS, username) sul = COMMONS._simple_request(action='query', meta='globaluserinfo', guiprop='merged', guiuser=voter.username).submit() try: sul = sul['query']['globaluserinfo']['merged'] except KeyError: newusername = eligibility_dict['possiblerenames'][voter.username] logger.warn('Following rename "%s" -> "%s"' % (username, newusername)) return get_voter(newusername, eligibility_dict) sul = sorted(sul, key=lambda item: item['editcount'], reverse=True) eligible_register = eligible_edits = False for sulentry in sul: eligible_register = eligible_register or ( min(pywikibot.Timestamp.fromISOformat(sulentry['registration']), pywikibot.Timestamp.fromISOformat(sulentry['timestamp'])) < eligibility_dict['register']['before']) if not eligible_edits: # Being lazy if sulentry['editcount'] >= eligibility_dict['edits']['atleast']: try: sul_site = COMMONS.fromDBName(sulentry['wiki']) except pywikibot.exceptions.UnknownFamily: pywikibot.exception( 'Failed to get Site object for {}, skipping'.format( sulentry['wiki'])) continue if eligibility_dict['edits']['includedeleted']: raise NotImplementedError( 'counting deleted edits is not implemented') else: contribs = sul_site.usercontribs( voter.username, start=eligibility_dict['edits']['before'], total=eligibility_dict['edits']['atleast']) eligible_edits = (len(list(contribs)) >= eligibility_dict['edits']['atleast']) if eligible_register and eligible_edits: # logger.warn('[[User:{}]]: eligible'.format(voter.username)) return voter return None
def proposed_by(self, textvalue): prop = self.current_page if 'P3254' not in prop.claims: try: int(textvalue) except ValueError as e: pywikibot.exception(e) else: claim = pywikibot.Claim(self.repo, 'P3254') target = ('https://www.wikidata.org/wiki/' 'Wikidata:Property_proposal/Archive/{}#{}' ).format(textvalue, prop.id) claim.setTarget(target) claim.addSource(self.get_source()) return self.user_add_claim( prop, claim, summary=self.make_summary()) return False
def test_exception_tb(self): class TestException(Exception): """Test exception.""" try: raise TestException('Testing Exception') except TestException: pywikibot.exception('exception', tb=True) self.assertEqual(newstdout.getvalue(), '') stderrlines = newstderr.getvalue().split('\n') self.assertEqual(stderrlines[0], 'ERROR: TestException: Testing Exception') self.assertEqual(stderrlines[1], 'Traceback (most recent call last):') self.assertEqual(stderrlines[3], " raise TestException('Testing Exception')") self.assertTrue(stderrlines[4].endswith(': Testing Exception')) self.assertNotEqual(stderrlines[-1], '\n')
def checkORES(self, page): headers = {'User-Agent': 'SeroBOT - an ORES counter vandalism tool'} wiki = self.available_options.get('wiki') revision = page._rcinfo.get('revision') ores = str(revision.get('new')) url = 'https://ores.wikimedia.org/v3/scores/{0}/{1}'.format(wiki, ores) r = requests.get(url=url, headers=headers) data = r.json() try: goodfaith = data.get(wiki).get('scores').get(ores).get('goodfaith') damaging = data.get(wiki).get('scores').get(ores).get('damaging') buena_fe = goodfaith.get('score').get('probability').get('true') danina = damaging.get('score').get('probability').get('true') return (ores, buena_fe, danina, True if buena_fe < self.available_options.get('gf') or danina > self.available_options.get('dm') else False) except: pywikibot.exception()
def get_wiki(self): """Get wiki from base_url.""" import pywikibot print('Generating family file from ' + self.base_url) for verify in (True, False): try: w = self.Wiki(self.base_url, verify=verify) except pywikibot.FatalServerError: print('ERROR: ' + pywikibot.comms.http.SSL_CERT_VERIFY_FAILED_MSG) pywikibot.exception() if not pywikibot.bot.input_yn( 'Retry with disabled ssl certificate validation', automatic_quit=False): break else: return w, verify return None, None
def proposed_by(self, textvalue): prop = self.current_page if 'P3254' not in prop.claims: try: int(textvalue) except ValueError as e: pywikibot.exception(e) else: claim = pywikibot.Claim(self.repo, 'P3254') target = ('https://www.wikidata.org/wiki/' 'Wikidata:Property_proposal/Archive/{}#{}').format( textvalue, prop.id) claim.setTarget(target) claim.addSource(self.get_source()) return self.user_add_claim(prop, claim, summary=self.make_summary()) return False
def generator(self): """Retrieve new users.""" if globalvar.timeoffset != 0: start = self.site.server_time() - timedelta( minutes=globalvar.timeoffset) else: start = globalvar.offset for ue in self.site.logevents('newusers', total=globalvar.queryLimit, start=start): if ue.action() == 'create' or (ue.action() == 'autocreate' and globalvar.welcomeAuto): try: user = ue.page() except HiddenKeyError: pywikibot.exception() else: yield user
def parse(self) -> None: """Parse the page.""" text = removeDisabledParts(self.text, tags=EXCEPTIONS, site=self.site) wikicode = mwparserfromhell.parse(text, skip_style_tags=True) for section in wikicode.get_sections(flat=True, include_lead=False): heading = section.filter_headings()[0] section_title = str(heading.title).lower() for mode in self.MODES: if mode in section_title: self.mode = mode break else: continue try: self._parse_section(str(section)) except (ValueError, pywikibot.Error): pywikibot.exception(tb=True) self._check_run()
def revert(self, item) -> Union[str, bool]: """Revert a single item.""" page = pywikibot.Page(self.site, item['title']) history = list(page.revisions(total=2)) if len(history) <= 1: return False rev = history[1] pywikibot.output( color_format( '\n\n>>> {lightpurple}{0}{default} <<<', page.title(as_link=True, force_interwiki=True, textlink=True))) if not self.opt.rollback: comment = i18n.twtranslate(self.site, 'revertbot-revert', { 'revid': rev.revid, 'author': rev.user, 'timestamp': rev.timestamp }) if self.opt.comment: comment += ': ' + self.opt.comment old = page.text page.text = page.getOldVersion(rev.revid) pywikibot.showDiff(old, page.text) page.save(comment) return comment try: self.site.rollbackpage(page, user=self.user, markbot=True) except APIError as e: if e.code == 'badtoken': pywikibot.error( 'There was an API token error rollbacking the edit') return False except Error: pass else: return 'The edit(s) made in {} by {} was rollbacked'.format( page.title(), self.user) pywikibot.exception() return False
def generator(self): if not self.getOption('date'): self.options['date'] = pywikibot.input( 'Enter the date when the reports were created') url = '%s/%s/%s/' % (self.labs_url, self.sub_directory, self.getOption('date')) response = urlopen(url) regex = re.compile('href="([^"]+)"') not_yet = bool(self.getOption('start')) for match in regex.finditer(response.read().decode()): file_name = match.group(1) dbname = file_name.partition('-')[0] if not_yet: if dbname == self.getOption('start'): not_yet = False else: continue if dbname in self.getOption('skip'): continue try: site = pywikibot.site.APISite.fromDBName(dbname) except ValueError as e: pywikibot.exception(e) continue pywikibot.output("Working on '%s'" % dbname) resp = urlopen(url + file_name) lines = resp.readlines() if not lines: continue lines.pop(0) f = map(methodcaller('decode', 'utf-8'), lines) for row in csv.reader(f, delimiter='\t'): if len(set(row[1:3])) > 1: continue if int(row[1]) not in self.namespaces: continue if '#' in row[4]: continue yield pywikibot.Page(site, row[3], ns=int(row[1]))
def getTags(self) -> List[str]: try: try: r = self.getRevisions(self.revInfo.newRevision, self.revInfo.newRevision) except pywikibot.data.api.APIError as e: if e.code == "badid_rvstartid": self.output("getTags() rvstartid not found. Retrying... ") time.sleep(10) r = self.getRevisions(self.revInfo.newRevision, self.revInfo.newRevision) else: raise except Exception as e: pywikibot.exception(e) return [] else: try: return cast(List[str], r[0]["tags"]) except KeyError: return []
def treat_page(self) -> None: """Treat page with the cosmetic toolkit. .. versionchanged:: 7.0 skip if InvalidPageError is raised """ cc_toolkit = CosmeticChangesToolkit(self.current_page, ignore=self.opt.ignore) try: old_text = self.current_page.text except InvalidPageError: pywikibot.exception() return new_text = cc_toolkit.change(old_text) if new_text is not False: self.put_current(new_text=new_text, summary=self.opt.summary, asynchronous=self.opt['async'])
def treat_page(self): """Change all redirects from the current page to actual links.""" try: newtext = self.current_page.text except InvalidPageError: pywikibot.exception() return with ThreadPoolExecutor() as executor: futures = { executor.submit(self.get_target, p) for p in self.current_page.linkedPages() } for future in as_completed(futures): page, target = future.result() if target: newtext = self.replace_links(newtext, page, target) self.put_current(newtext)
def revert(self, item): """Revert a single item.""" page = pywikibot.Page(self.site, item["title"]) history = list(page.revisions(total=2)) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate( self.site, "revertbot-revert", {"revid": rev.revid, "author": rev.user, "timestamp": rev.timestamp} ) if self.comment: comment += ": " + self.comment pywikibot.output( color_format( "\n\n>>> {lightpurple}{0}{default} <<<", page.title(asLink=True, forceInterwiki=True, textlink=True) ) ) if not self.rollback: old = page.text page.text = rev.text pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request( self.site, parameters={ "action": "rollback", "title": page, "user": self.user, "token": rev.rollbacktoken, "markbot": True, }, ).submit() except pywikibot.data.api.APIError as e: if e.code == "badtoken": pywikibot.error("There was an API token error rollbacking the edit") else: pywikibot.exception() return False return "The edit(s) made in %s by %s was rollbacked" % (page.title(), self.user)
def revert(self, item): page = pywikibot.Page(self.site, item['title']) history = list(page.revisions(total=2)) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate(self.site, 'revertbot-revert', { 'revid': rev.revid, 'author': rev.user, 'timestamp': rev.timestamp }) if self.comment: comment += ': ' + self.comment pywikibot.output( color_format( '\n\n>>> {lightpurple}{0}{default} <<<', page.title(asLink=True, forceInterwiki=True, textlink=True))) if not self.rollback: old = page.text page.text = rev.text pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request(self.site, parameters={ 'action': 'rollback', 'title': page, 'user': self.user, 'token': rev.rollbacktoken, 'markbot': True }).submit() except pywikibot.data.api.APIError as e: if e.code == 'badtoken': pywikibot.error( "There was an API token error rollbacking the edit") else: pywikibot.exception() return False return u"The edit(s) made in %s by %s was rollbacked" % (page.title(), self.user)
def test_exception_tb(self): try: raise TestExceptionError('Testing Exception') except TestExceptionError: pywikibot.exception('exception', tb=True) self.assertEqual(newstdout.getvalue(), '') stderrlines = newstderr.getvalue().split('\n') self.assertEqual(stderrlines[0], 'ERROR: TestExceptionError: Testing Exception') self.assertEqual(stderrlines[1], 'Traceback (most recent call last):') self.assertEqual(stderrlines[3], " raise TestExceptionError('Testing Exception')") end_str = ': Testing Exception' traceback_line = stderrlines[4 + (PYTHON_VERSION >= (3, 11))] self.assertTrue( traceback_line.endswith(end_str), '\n{!r} does not end with {!r}'.format(traceback_line, end_str)) self.assertNotEqual(stderrlines[-1], '\n')
def number_of_ids(self, textvalue): prop = self.current_page if prop.type == 'external-id' and 'P4876' not in prop.claims: remove = False match = self.regexes['quantity'].search(textvalue) if match: try: num = int(match.group('value')) except ValueError as e: pywikibot.exception(e) else: target = pywikibot.WbQuantity(num, site=self.repo) claim = pywikibot.Claim(self.repo, 'P4876') claim.setTarget(target) claim.addSource(self.get_source()) remove = self.user_add_claim( prop, claim, summary=self.make_summary()) else: remove = True return remove
def test_exception_tb(self): class TestException(Exception): pass try: raise TestException("Testing Exception") except TestException: pywikibot.exception("exception", tb=True) self.assertEqual(newstdout.getvalue(), "") stderrlines = newstderr.getvalue().split("\n") self.assertEqual(stderrlines[0], "ERROR: TestException: Testing Exception") self.assertEqual(stderrlines[1], "Traceback (most recent call last):") self.assertEqual( stderrlines[3], """ raise TestException("Testing Exception")""") self.assertEqual(stderrlines[4], "TestException: Testing Exception") self.assertNotEqual(stderrlines[-1], "\n")
def number_of_ids(self, textvalue): prop = self.current_page if prop.type == 'external-id' and 'P4876' not in prop.claims: remove = False match = self.regexes['quantity'].search(textvalue) if match: try: num = int(match.group('value')) except ValueError as e: pywikibot.exception(e) else: target = pywikibot.WbQuantity(num, site=self.repo) claim = pywikibot.Claim(self.repo, 'P4876') claim.setTarget(target) claim.addSource(self.get_source()) remove = self.user_add_claim(prop, claim, summary=self.make_summary()) else: remove = True return remove
def revert(self, item): """Revert a single item.""" page = pywikibot.Page(self.site, item['title']) history = list(page.revisions(total=2)) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate( self.site, 'revertbot-revert', {'revid': rev.revid, 'author': rev.user, 'timestamp': rev.timestamp}) if self.comment: comment += ': ' + self.comment pywikibot.output(color_format( '\n\n>>> {lightpurple}{0}{default} <<<', page.title(asLink=True, forceInterwiki=True, textlink=True))) if not self.rollback: old = page.text page.text = page.getOldVersion(rev.revid) pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request( self.site, parameters={'action': 'rollback', 'title': page, 'user': self.user, 'token': rev.rollbacktoken, 'markbot': True}).submit() except pywikibot.data.api.APIError as e: if e.code == 'badtoken': pywikibot.error( 'There was an API token error rollbacking the edit') else: pywikibot.exception() return False return 'The edit(s) made in %s by %s was rollbacked' % (page.title(), self.user)
def revert(self, item): history = pywikibot.Page(self.site, item['title']).fullVersionHistory( total=2, rollback=self.rollback) if len(history) > 1: rev = history[1] else: return False comment = i18n.twtranslate(pywikibot.Site(), 'revertbot-revert', { 'revid': rev[0], 'author': rev[2], 'timestamp': rev[1] }) if self.comment: comment += ': ' + self.comment page = pywikibot.Page(self.site, item['title']) pywikibot.output( u"\n\n>>> \03{lightpurple}%s\03{default} <<<" % page.title(asLink=True, forceInterwiki=True, textlink=True)) if not self.rollback: old = page.text page.text = rev[3] pywikibot.showDiff(old, page.text) page.save(comment) return comment try: pywikibot.data.api.Request(action="rollback", title=page.title(), user=self.user, token=rev[4], markbot=1).submit() except pywikibot.data.api.APIError as e: if e.code == 'badtoken': pywikibot.error( "There was an API token error rollbacking the edit") else: pywikibot.exception() return False return u"The edit(s) made in %s by %s was rollbacked" % (page.title(), self.user)
def main(*args): """ Process command line arguments and invoke bot. If args is an empty list, sys.argv is used. @param args: command line arguments @type args: str """ opt_all = False opt_new = False opt_count = False opt_count_all = False for arg in pywikibot.handle_args(args): if arg in ('-all', '-update'): opt_all = True elif arg == '-new': opt_new = True elif arg == '-count': opt_count = True elif arg == '-count:all': opt_count_all = True if opt_all: refresh_all() elif opt_new: refresh_new() elif opt_count: count_watchlist() elif opt_count_all: count_watchlist_all() else: site = pywikibot.Site() count_watchlist(site) watchlist = list(site.watched_pages(force=True)) for page in watchlist: try: pywikibot.stdout(page.title()) except pywikibot.InvalidTitle: pywikibot.exception()
def get_target(page): """Get the target page for a given page.""" target = None if not page.exists(): with suppress(pywikibot.NoMoveTarget, pywikibot.CircularRedirect, pywikibot.InvalidTitle): target = page.moved_target() elif page.isRedirectPage(): try: target = page.getRedirectTarget() except (pywikibot.CircularRedirect, pywikibot.InvalidTitle): pass except RuntimeError: pywikibot.exception() else: section = target.section() if section and not does_text_contain_section( target.text, section): pywikibot.warning( 'Section #{} not found on page {}'.format( section, target.title(as_link=True, with_section=False))) target = None return target
def treat_page(self) -> None: """Process one page.""" self.check_disabled() try: errors = self.validate_svg() except (AssertionError, RequestException, RuntimeError): pywikibot.exception() return if errors: n_errors = len(errors) new_tpl = Template('Invalid SVG') new_tpl.add('1', n_errors) summary = 'W3C invalid SVG: {} error{}'.format( n_errors, 's' if n_errors > 1 else '') else: new_tpl = Template('Valid SVG') summary = 'W3C valid SVG' wikicode = mwparserfromhell.parse(self.current_page.text, skip_style_tags=True) for tpl in wikicode.ifilter_templates(): try: template = pywikibot.Page( self.site, removeDisabledParts(str(tpl.name), site=self.site).strip(), ns=10, ) template.title() except pywikibot.InvalidTitle: continue if template in self.templates: wikicode.replace(tpl, new_tpl) break else: wikicode.insert(0, '\n') wikicode.insert(0, new_tpl) self.put_current(str(wikicode), summary=summary, minor=not errors)
def main(*args): """ Process command line arguments and invoke bot. If args is an empty list, sys.argv is used. @param args: command line arguments @type args: list of unicode """ filename = None pagename = None namespace = None salt = None force = False calc = None sleep = 10 args = [] def if_arg_value(arg, name): if arg.startswith(name): yield arg[len(name) + 1:] for arg in pywikibot.handle_args(args): for v in if_arg_value(arg, '-file'): filename = v for v in if_arg_value(arg, '-locale'): # Required for english month names locale.setlocale(locale.LC_TIME, v.encode('utf8')) for v in if_arg_value(arg, '-timezone'): os.environ['TZ'] = v.timezone # Or use the preset value if hasattr(time, 'tzset'): time.tzset() for v in if_arg_value(arg, '-calc'): calc = v for v in if_arg_value(arg, '-salt'): salt = v for v in if_arg_value(arg, '-force'): force = True for v in if_arg_value(arg, '-filename'): filename = v for v in if_arg_value(arg, '-page'): pagename = v for v in if_arg_value(arg, '-namespace'): namespace = v for v in if_arg_value(arg, '-sleep'): sleep = int(v) if not arg.startswith('-'): args.append(arg) site = pywikibot.Site() if calc: if not salt: pywikibot.bot.suggest_help(missing_parameters=['-salt']) return False page = pywikibot.Page(site, calc) if page.exists(): calc = page.title() else: pywikibot.output(u'NOTE: the specified page "%s" does not (yet) exist.' % calc) s = md5() s.update(salt + '\n') s.update(calc + '\n') pywikibot.output(u'key = ' + s.hexdigest()) return if not salt: salt = '' if not args: pywikibot.bot.suggest_help(additional_text='No template was specified.') return False for a in args: pagelist = [] a = pywikibot.Page(site, a, ns=10).title() if not filename and not pagename: if namespace is not None: ns = [str(namespace)] else: ns = [] for pg in generate_transclusions(site, a, ns): pagelist.append(pg) if filename: for pg in open(filename, 'r').readlines(): pagelist.append(pywikibot.Page(site, pg, ns=10)) if pagename: pagelist.append(pywikibot.Page(site, pagename, ns=3)) pagelist = sorted(pagelist) for pg in iter(pagelist): pywikibot.output(u'Processing %s' % pg) # Catching exceptions, so that errors in one page do not bail out # the entire process try: archiver = PageArchiver(pg, a, salt, force) archiver.run() except ArchiveBotSiteConfigError as e: # no stack trace for errors originated by pages on-site pywikibot.error('Missing or malformed template in page %s: %s' % (pg, e)) except Exception: pywikibot.error(u'Error occurred while processing page %s' % pg) pywikibot.exception(tb=True) finally: time.sleep(sleep)
# from __future__ import absolute_import, unicode_literals import re import sys import pywikibot from pywikibot import i18n try: import pycountry except ImportError: pywikibot.error('This script requires the python-pycountry module') pywikibot.error('See: https://pypi.python.org/pypi/pycountry') pywikibot.exception() sys.exit(1) class StatesRedirectBot(pywikibot.Bot): """Bot class used for implementation of re-direction norms.""" def __init__(self, start, force): """Constructor. Parameters: @param start:xxx Specify the place in the alphabet to start searching. @param force: Don't ask whether to create pages, just create them.