jenkins-bot has submitted this change and it was merged.
Change subject: i18n.input prompt fallback
......................................................................
i18n.input prompt fallback
pywikibot depends on four i18n messages that are only included
in git sub-module scripts/i18n, which is not packaged with pywikibot
in setup.py. Three uses of i18n messages are in pagegenerators.py, and
one is in Page for cosmetic_changes, however the code where the
cosmetic_changes i18n message occurs is already disabled when packaged
without scripts. The pagegenerators uses are all via i18n.input.
Instead of raising exception ImportError when the i18n git submodule
is not available, or packaging scripts and scripts.i18n for the sake
of the three pagegenerators i18n messages:
- detect missing message package and raise custom exception
TranslationError
- add a fallback prompt to i18n.input, used by pagegenerators
Bug: 66897
Change-Id: I12518189126d8f929d30ab18bf8597a288d28891
---
M pywikibot/config2.py
M pywikibot/exceptions.py
M pywikibot/i18n.py
M pywikibot/pagegenerators.py
M tests/aspects.py
A tests/i18n/pywikibot.py
M tests/i18n_tests.py
M tests/utils.py
8 files changed, 270 insertions(+), 32 deletions(-)
Approvals:
XZise: Looks good to me, but someone else must approve
Ladsgroup: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/config2.py b/pywikibot/config2.py
index 0343338..5169b0c 100644
--- a/pywikibot/config2.py
+++ b/pywikibot/config2.py
@@ -350,7 +350,7 @@
userinterface_init_kwargs = {}
# i18n setting for user interface language
-# default is config.mylang or 'en'
+# default is obtained from L{locale.getdefaultlocale}
userinterface_lang = None
# Should we transliterate characters that do not exist in the console
diff --git a/pywikibot/exceptions.py b/pywikibot/exceptions.py
index 2a8105f..df3ffbd 100644
--- a/pywikibot/exceptions.py
+++ b/pywikibot/exceptions.py
@@ -12,6 +12,7 @@
- CaptchaError: Captcha is asked and config.solve_captcha == False
- Server504Error: Server timed out with HTTP 504 code
- PageNotFound: Page not found (deprecated)
+ - i18n.TranslationError: i18n/l10n message not available
SiteDefinitionError: Site loading problem
- UnknownSite: Site does not exist in Family
diff --git a/pywikibot/i18n.py b/pywikibot/i18n.py
index 85a1055..1be4248 100644
--- a/pywikibot/i18n.py
+++ b/pywikibot/i18n.py
@@ -4,6 +4,17 @@
Helper functions for both the internal translation system
and for TranslateWiki-based translations.
+
+By default messages are assumed to reside in a package called
+'scripts.i18n'. In pywikibot 2.0, that package is not packaged
+with pywikibot, and pywikibot 2.0 does not have a hard dependency
+on any i18n messages. However, there are three user input questions
+in pagegenerators which will use i18 messages if they can be loaded.
+
+The default message location may be changed by calling
+L{set_message_package} with a package name. The package must contain
+an __init__.py, and a message bundle called 'pywikibot' containing
+messages. See L{twntranslate} for more information on the messages.
"""
#
# (C) Pywikibot team, 2004-2015
@@ -31,7 +42,50 @@
PLURAL_PATTERN = r'{{PLURAL:(?:%\()?([^\)]*?)(?:\)d)?\|(.*?)}}'
# Package name for the translation messages
-messages_package_name = 'scripts.i18n'
+_messages_package_name = 'scripts.i18n'
+# Flag to indicate whether translation messages are available
+_messages_available = None
+
+
+def set_messages_package(package_name):
+ """Set the package name where i18n messages are located."""
+ global _messages_package_name
+ global _messages_available
+ _messages_package_name = package_name
+ _messages_available = None
+
+
+def messages_available():
+ """
+ Return False if there are no i18n messages available.
+
+ To determine if messages are available, it looks for the package name
+ set using L{set_messages_package} for a message bundle called 'pywikibot'
+ containing messages.
+
+ @rtype: bool
+ """
+ global _messages_available
+ if _messages_available is not None:
+ return _messages_available
+ with warnings.catch_warnings():
+ # Ignore 'missing __init__.py' as import looks at the JSON
+ # directories before loading the python file.
+ try:
+ warnings.simplefilter("ignore", ImportWarning)
+ module = __import__(_messages_package_name, fromlist=['pywikibot'])
+ except ImportError:
+ _messages_available = False
+ return False
+
+ try:
+ getattr(module, 'pywikibot').msg
+ except AttributeError:
+ _messages_available = False
+ return False
+
+ _messages_available = True
+ return True
def _altlang(code):
@@ -233,22 +287,37 @@
return []
-class TranslationError(Error):
+class TranslationError(Error, ImportError):
"""Raised when no correct translation could be found."""
+
+ # Inherits from ImportError, as this exception is now used
+ # where previously an ImportError would have been raised,
+ # and may have been caught by scripts as such.
pass
def _get_messages_bundle(name):
"""Load all translation messages for a bundle name."""
+ exception_message = 'Unknown problem'
+
with warnings.catch_warnings():
# Ignore 'missing __init__.py' as import looks at the JSON
# directories before loading the python file.
warnings.simplefilter("ignore", ImportWarning)
- transdict = getattr(__import__(messages_package_name,
- fromlist=[name]),
- name).msg
+ try:
+ transdict = getattr(__import__(_messages_package_name,
+ fromlist=[name]),
+ name).msg
+ except ImportError as e:
+ exception_message = str(e)
+
+ if not transdict:
+ raise TranslationError(
+ 'Could not load bundle %s from message package %s: %s'
+ % (name, _messages_package_name, exception_message))
+
return transdict
@@ -379,6 +448,11 @@
@param fallback: Try an alternate language code
@type fallback: boolean
"""
+ if not messages_available():
+ raise TranslationError(
+ 'Unable to load messages package %s for bundle %s'
+ % (_messages_package_name, twtitle))
+
package = twtitle.split("-")[0]
transdict = _get_messages_bundle(package)
code_needed = False
@@ -453,7 +527,7 @@
}
>>> from pywikibot import i18n
- >>> i18n.messages_package_name = 'tests.i18n'
+ >>> i18n.set_messages_package('tests.i18n')
>>> # use a number
>>> str(i18n.twntranslate('en', 'test-plural', 0) % {'num': 'no'})
'Bot: Changing no pages.'
@@ -469,7 +543,6 @@
>>> # use format strings also outside
>>> str(i18n.twntranslate('fr', 'test-plural', 10) % {'descr': 'seulement'})
'Robot: Changer seulement quelques pages.'
- >>> i18n.messages_package_name = 'scripts.i18n'
The translations are retrieved from i18n.<package>, based on the callers
import table.
@@ -513,6 +586,11 @@
"""
package = twtitle.split("-")[0]
transdict = _get_messages_bundle(package)
+ if not transdict:
+ pywikibot.warning('twhas_key: Could not load message bundle %s.%s'
+ % (_messages_package_name, package))
+ return False
+
# If a site is given instead of a code, use its language
if hasattr(code, 'code'):
code = code.code
@@ -530,7 +608,7 @@
return (lang for lang in sorted(transdict.keys()) if lang != 'qqq')
-def input(twtitle, parameters=None, password=False):
+def input(twtitle, parameters=None, password=False, fallback_prompt=None):
"""
Ask the user a question, return the user's answer.
@@ -541,9 +619,19 @@
@param twtitle: The TranslateWiki string title, in <package>-<key> format
@param parameters: The values which will be applied to the translated text
@param password: Hides the user's input (for password entry)
+ @param fallback_prompt: The English prompt if i18n is not available.
@rtype: unicode string
"""
- code = config.userinterface_lang or \
- locale.getdefaultlocale()[0].split('_')[0]
- trans = twtranslate(code, twtitle, parameters)
- return pywikibot.input(trans, password)
+ if not messages_available():
+ if not fallback_prompt:
+ raise TranslationError(
+ 'Unable to load messages package %s for bundle %s'
+ % (_messages_package_name, twtitle))
+ else:
+ prompt = fallback_prompt
+ else:
+ code = config.userinterface_lang or \
+ locale.getdefaultlocale()[0].split('_')[0]
+
+ prompt = twtranslate(code, twtitle, parameters)
+ return pywikibot.input(prompt, password)
diff --git a/pywikibot/pagegenerators.py b/pywikibot/pagegenerators.py
index 008d383..b01ae3f 100644
--- a/pywikibot/pagegenerators.py
+++ b/pywikibot/pagegenerators.py
@@ -402,7 +402,9 @@
"""Return generator based on Category defined by arg and gen_func."""
categoryname = arg.partition(':')[2]
if not categoryname:
- categoryname = i18n.input('pywikibot-enter-category-name')
+ categoryname = i18n.input(
+ 'pywikibot-enter-category-name',
+ fallback_prompt='Please enter the category name:')
categoryname = categoryname.replace('#', '|')
categoryname, sep, startfrom = categoryname.partition('|')
@@ -468,7 +470,9 @@
fileLinksPageTitle = arg[11:]
if not fileLinksPageTitle:
fileLinksPageTitle = i18n.input(
- 'pywikibot-enter-file-links-processing')
+ 'pywikibot-enter-file-links-processing',
+ fallback_prompt='Links to which file page should be '
+ 'processed?')
if fileLinksPageTitle.startswith(self.site.namespace(6) + ':'):
fileLinksPage = pywikibot.FilePage(self.site,
fileLinksPageTitle)
@@ -505,7 +509,9 @@
elif arg.startswith('-interwiki'):
title = arg[11:]
if not title:
- title = i18n.input('pywikibot-enter-page-processing')
+ title = i18n.input(
+ 'pywikibot-enter-page-processing',
+ fallback_prompt='Which page should be processed?')
page = pywikibot.Page(pywikibot.Link(title,
self.site))
gen = InterwikiPageGenerator(page)
diff --git a/tests/aspects.py b/tests/aspects.py
index 250ffb2..7615736 100644
--- a/tests/aspects.py
+++ b/tests/aspects.py
@@ -1162,6 +1162,16 @@
if self.orig_pywikibot_dir:
os.environ['PYWIKIBOT2_DIR'] = self.orig_pywikibot_dir
+ def _execute(self, args, data_in=None, timeout=0, error=None):
+ from tests.utils import execute_pwb
+
+ site = self.get_site()
+
+ args = args + ['-family:' + site.family.name,
+ '-code:' + site.code]
+
+ return execute_pwb(args, data_in, timeout, error)
+
class DebugOnlyTestCase(TestCase):
diff --git a/tests/i18n/pywikibot.py b/tests/i18n/pywikibot.py
new file mode 100644
index 0000000..a8650f3
--- /dev/null
+++ b/tests/i18n/pywikibot.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+"""i18n message bundle called 'pywikibot' to fool the i18n loader."""
+msg = {}
diff --git a/tests/i18n_tests.py b/tests/i18n_tests.py
index f5dc65f..5c05011 100644
--- a/tests/i18n_tests.py
+++ b/tests/i18n_tests.py
@@ -7,9 +7,16 @@
#
__version__ = '$Id$'
-from pywikibot import i18n
+import sys
-from tests.aspects import unittest, TestCase
+import pywikibot
+
+from pywikibot import i18n, bot
+
+from tests.aspects import unittest, TestCase, DefaultSiteTestCase, PwbTestCase
+
+if sys.version_info[0] == 3:
+ basestring = (str, )
class TestTranslate(TestCase):
@@ -76,25 +83,64 @@
u'test-no-english JA')
-class TestTWN(TestCase):
+class UserInterfaceLangTestCase(TestCase):
+
+ """Base class for tests using config.userinterface_lang."""
+
+ def setUp(self):
+ super(UserInterfaceLangTestCase, self).setUp()
+ self.orig_userinterface_lang = pywikibot.config.userinterface_lang
+ pywikibot.config.userinterface_lang = self.get_site().code
+
+ def tearDown(self):
+ pywikibot.config.userinterface_lang = self.orig_userinterface_lang
+ super(UserInterfaceLangTestCase, self).tearDown()
+
+
+class TWNSetMessagePackageBase(TestCase):
+
+ """Partial base class for TranslateWiki tests."""
+
+ message_package = None
+
+ def setUp(self):
+ self.orig_messages_package_name = i18n._messages_package_name
+ i18n.set_messages_package(self.message_package)
+ super(TWNSetMessagePackageBase, self).setUp()
+
+ def tearDown(self):
+ super(TWNSetMessagePackageBase, self).tearDown()
+ i18n.set_messages_package(self.orig_messages_package_name)
+
+
+class TWNTestCaseBase(TWNSetMessagePackageBase):
"""Base class for TranslateWiki tests."""
- net = False
-
- def setUp(self):
- self.orig_messages_package_name = i18n.messages_package_name
- i18n.messages_package_name = 'tests.i18n'
- super(TestTWN, self).setUp()
-
- def tearDown(self):
- super(TestTWN, self).tearDown()
- i18n.messages_package_name = self.orig_messages_package_name
+ @classmethod
+ def setUpClass(cls):
+ if not isinstance(cls.message_package, basestring):
+ raise TypeError('%s.message_package must be a package name'
+ % cls.__name__)
+ # Th call to set_messages_package below exists only to confirm
+ # that the package exists and messages are available, so
+ # that tests can be skipped if the i18n data doesnt exist.
+ cls.orig_messages_package_name = i18n._messages_package_name
+ i18n.set_messages_package(cls.message_package)
+ has_messages = i18n.messages_available()
+ i18n._messages_package_name = cls.orig_messages_package_name
+ if not has_messages:
+ raise unittest.SkipTest("i18n messages package '%s' not available."
+ % cls.message_package)
+ super(TWNTestCaseBase, cls).setUpClass()
-class TestTWTranslate(TestTWN):
+class TestTWTranslate(TWNTestCaseBase):
"""Test twtranslate method."""
+
+ net = False
+ message_package = 'tests.i18n'
def testLocalized(self):
self.assertEqual(i18n.twtranslate('en', 'test-localized'),
@@ -123,12 +169,16 @@
u'test-non-localized EN')
def testNoEnglish(self):
- self.assertRaises(i18n.TranslationError, i18n.twtranslate, 'en', 'test-no-english')
+ self.assertRaises(i18n.TranslationError, i18n.twtranslate,
+ 'en', 'test-no-english')
-class TestTWNTranslate(TestTWN):
+class TestTWNTranslate(TWNTestCaseBase):
"""Test {{PLURAL:}} support."""
+
+ net = False
+ message_package = 'tests.i18n'
def testNumber(self):
"""Use a number."""
@@ -260,6 +310,83 @@
u'Bot: Ă„ndere 1 Zeile von einer Seite.')
+class ScriptMessagesTestCase(TWNTestCaseBase):
+
+ """Real messages test."""
+
+ net = False
+ message_package = 'scripts.i18n'
+
+ def test_basic(self):
+ """Verify that real messages are able to be loaded."""
+ self.assertEqual(i18n.twntranslate('en', 'pywikibot-enter-new-text'),
+ 'Please enter the new text:')
+
+ def test_missing(self):
+ """Test a missing message from a real message bundle."""
+ self.assertRaises(i18n.TranslationError,
+ i18n.twntranslate, 'en', 'pywikibot-missing-key')
+
+
+class InputTestCase(TWNTestCaseBase, UserInterfaceLangTestCase, PwbTestCase):
+
+ """Test i18n.input."""
+
+ family = 'wikipedia'
+ code = 'arz'
+
+ message_package = 'scripts.i18n'
+
+ @classmethod
+ def setUpClass(cls):
+ if cls.code in i18n.twget_keys('pywikibot-enter-category-name'):
+ raise unittest.SkipTest(
+ '%s has a translation for %s'
+ % (cls.code, 'pywikibot-enter-category-name'))
+
+ super(InputTestCase, cls).setUpClass()
+
+ def test_pagegen_i18n_input(self):
+ """Test i18n.input via ."""
+ result = self._execute(args=['listpages', '-cat'],
+ data_in='non-existant-category\n',
+ timeout=5)
+
+ self.assertIn('Please enter the category name:', result['stderr'])
+
+
+class MissingPackageTestCase(TWNSetMessagePackageBase,
+ UserInterfaceLangTestCase,
+ DefaultSiteTestCase):
+
+ """Test misssing messages package."""
+
+ message_package = 'scripts.foobar.i18n'
+
+ def _capture_output(self, text, *args, **kwargs):
+ self.output_text = text
+
+ def setUp(self):
+ super(MissingPackageTestCase, self).setUp()
+ self.output_text = ''
+ self.orig_raw_input = bot.ui._raw_input
+ self.orig_output = bot.ui.output
+ bot.ui._raw_input = lambda *args, **kwargs: 'dummy input'
+ bot.ui.output = self._capture_output
+
+ def tearDown(self):
+ bot.ui._raw_input = self.orig_raw_input
+ bot.ui.output = self.orig_output
+ super(MissingPackageTestCase, self).tearDown()
+
+ def test_pagegen_i18n_input(self):
+ """Test i18n.input falls back with missing message package."""
+ rv = i18n.input('pywikibot-enter-category-name',
+ fallback_prompt='dummy output')
+ self.assertEqual(rv, 'dummy input')
+ self.assertIn('dummy output ', self.output_text)
+
+
if __name__ == '__main__':
try:
unittest.main()
diff --git a/tests/utils.py b/tests/utils.py
index e9ff62b..ae80633 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -266,6 +266,9 @@
env = os.environ.copy()
# sys.path may have been modified by the test runner to load dependencies.
env['PYTHONPATH'] = ":".join(sys.path)
+ # LC_ALL is used by i18n.input as an alternative for userinterface_lang
+ if pywikibot.config.userinterface_lang:
+ env['LC_ALL'] = pywikibot.config.userinterface_lang
# Set EDITOR to an executable that ignores all arguments and does nothing.
if sys.platform == 'win32':
env['EDITOR'] = 'call'
--
To view, visit https://gerrit.wikimedia.org/r/166421
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I12518189126d8f929d30ab18bf8597a288d28891
Gerrit-PatchSet: 11
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot <>
jenkins-bot has submitted this change and it was merged.
Change subject: archivebot: make capitalized templates discoverable
......................................................................
archivebot: make capitalized templates discoverable
Follows up ee42bfd6, which made templates like
https://en.wikivoyage.org/wiki/Template:Auto_archiving
not discoverable when used with the syntax {{auto archiving}}.
Change-Id: I89a7248967c133fc56133c957ea4c32534b3f25a
---
M scripts/archivebot.py
1 file changed, 25 insertions(+), 4 deletions(-)
Approvals:
XZise: Looks good to me, but someone else must approve
Ladsgroup: Looks good to me, approved
jenkins-bot: Verified
Whym: Looks good to me, but someone else must approve
diff --git a/scripts/archivebot.py b/scripts/archivebot.py
index 6563a83..a8fe3b7 100644
--- a/scripts/archivebot.py
+++ b/scripts/archivebot.py
@@ -206,6 +206,29 @@
namespaces=namespaces)
+def template_title_regex(tpl_page):
+ """
+ Return a regex that matches to variations of the template title.
+
+ It supports the transcluding variant as well as localized namespaces and
+ case-insensitivity depending on the namspace.
+
+ @param tpl_page: The template page
+ @type tpl_page: Page
+ """
+ ns = tpl_page.site.namespaces[tpl_page.namespace()]
+ marker = '?' if ns.id == 10 else ''
+ title = tpl_page.title(withNamespace=False)
+ if ns.case != 'case-sensitive':
+ title = '[%s%s]%s' % (re.escape(title[0].upper()),
+ re.escape(title[0].lower()),
+ re.escape(title[1:]))
+ else:
+ title = re.escape(title)
+
+ return re.compile(r'(?:(?:{0}):){1}{2}'.format(u'|'.join(ns), marker, title))
+
+
class TZoneUTC(datetime.tzinfo):
"""Class building a UTC tzinfo object."""
@@ -535,10 +558,8 @@
self.archives[a].update(comment)
# Save the page itself
- marker = '?' if self.tpl.namespace() == 10 else ''
- rx = re.compile(r"\{\{(?:(?:%s):)%s%s\s*?\n.*?\n\}\}" % (u'|'.join(
- set(self.site.namespaces[self.tpl.namespace()])), marker,
- re.escape(self.tpl.title(withNamespace=False))), re.DOTALL)
+ rx = re.compile(r'\{\{%s\s*?\n.*?\n\}\}'
+ % (template_title_regex(self.tpl).pattern), re.DOTALL)
if not rx.search(self.page.header):
pywikibot.error("Couldn't find the template in the header")
return
--
To view, visit https://gerrit.wikimedia.org/r/193351
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I89a7248967c133fc56133c957ea4c32534b3f25a
Gerrit-PatchSet: 8
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Whym <whym(a)whym.org>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: Ricordisamoa <ricordisamoa(a)openmailbox.org>
Gerrit-Reviewer: Whym <whym(a)whym.org>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>
jenkins-bot has submitted this change and it was merged.
Change subject: Add compare method using mediawiki's action=compare.
......................................................................
Add compare method using mediawiki's action=compare.
This method queries the server to get the difference between any two
revisions and returns a HTML string. The html_comparator function in the
diff module then parses this result.
Change-Id: If776435e96a88bd4bee56a6af1f74e759370b7f5
---
M pywikibot/diff.py
M pywikibot/site.py
M requirements.txt
3 files changed, 74 insertions(+), 0 deletions(-)
Approvals:
XZise: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/diff.py b/pywikibot/diff.py
index 09fdfdf..9bde69f 100644
--- a/pywikibot/diff.py
+++ b/pywikibot/diff.py
@@ -14,6 +14,10 @@
from itertools import zip_longest
else:
from itertools import izip_longest as zip_longest
+try:
+ from bs4 import BeautifulSoup
+except ImportError as bserror:
+ BeautifulSoup = False
import pywikibot
from pywikibot.backports import format_range_unified # introduced in 2.7.2
@@ -347,3 +351,29 @@
text = ''.join(text_list)
return text
+
+
+def html_comparator(compare_string):
+ """List of added and deleted contexts from 'action=compare' html string.
+
+ This function is useful when combineds with site.py's "compare" method.
+ Site.compare() returns HTML that is useful for displaying on a page.
+ Here we use BeautifulSoup to get the un-HTML-ify the context of changes.
+ Finally we present the added and deleted contexts.
+ @param compare_string: HTML string from mediawiki API
+ @type compare_string: str
+ @return: deleted and added list of contexts
+ @rtype: dict
+ """
+ # check if BeautifulSoup imported
+ if not BeautifulSoup:
+ raise bserror # should have been raised and stored earlier.
+
+ comparands = {'deleted-context': [], 'added-context': []}
+ soup = BeautifulSoup(compare_string)
+ for change_type, css_class in (('deleted-context', 'diff-deletedline'), ('added-context', 'diff-addedline')):
+ crutons = soup.find_all('td', class_=css_class)
+ for cruton in crutons:
+ cruton_string = ''.join(cruton.strings)
+ comparands[change_type].append(cruton_string)
+ return comparands
diff --git a/pywikibot/site.py b/pywikibot/site.py
index a6ed308..222145d 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -5372,6 +5372,47 @@
return self.allpages(namespace=namespaces[0], protect_level=level,
protect_type=type, total=total)
+ @need_version("1.18")
+ def compare(self, old, diff):
+ """Corresponding method to the 'action=compare' API action.
+
+ See: https://en.wikipedia.org/w/api.php?action=help&modules=compare
+ Use pywikibot.diff's html_comparator() method to parse result.
+ @param old: starting revision ID, title, Page, or Revision
+ @type old: int, str, pywikibot.Page, or pywikibot.Page.Revision
+ @param diff: ending revision ID, title, Page, or Revision
+ @type diff: int, str, pywikibot.Page, or pywikibot.Page.Revision
+ @return: Returns an HTML string of a diff between two revisions.
+ @rtype: str
+ """
+ # check old and diff types
+ def get_param(item):
+ if isinstance(item, basestring):
+ return 'title', item
+ elif isinstance(item, pywikibot.Page):
+ return 'title', item.title()
+ elif isinstance(item, int):
+ return 'rev', item
+ elif isinstance(item, pywikibot.page.Revision):
+ return 'rev', item.revid
+ else:
+ return None
+
+ old = get_param(old)
+ if not old:
+ raise TypeError('old parameter is of invalid type')
+ diff = get_param(diff)
+ if not diff:
+ raise TypeError('diff parameter is of invalid type')
+
+ params = {'from{0}'.format(old[0]): old[1],
+ 'to{0}'.format(diff[0]): diff[1]}
+
+ req = api.Request(site=self, action='compare', **params)
+ data = req.submit()
+ comparison = data['compare']['*']
+ return comparison
+
class DataSite(APISite):
diff --git a/requirements.txt b/requirements.txt
index f537b59..e0f5680 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -59,3 +59,6 @@
# scripts/script_wui.py depends on Lua, which is not available using pip
# but can be obtained from: https://github.com/bastibe/lunatic-python
+
+# core HTML comparison parser in diff module
+beautifulsoup4
--
To view, visit https://gerrit.wikimedia.org/r/182561
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: If776435e96a88bd4bee56a6af1f74e759370b7f5
Gerrit-PatchSet: 12
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Legoktm <legoktm.wikipedia(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Legoktm <legoktm.wikipedia(a)gmail.com>
Gerrit-Reviewer: Maximilianklein <isalix(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>
jenkins-bot has submitted this change and it was merged.
Change subject: A BaseSite subclass for non MW sites.
......................................................................
A BaseSite subclass for non MW sites.
Currently the class only contains a constructor and __getattribute__.
__getattribute__ method returns an attribute if present. This is done
using a whitelist and not hasattr as hasattr uses getattribute of the
super which goes into an infinite recursion. No attributes have been
implemented yet and NotImplementedError is raised if the attribute is
not present in the whitelist. A corresponsding unittest has been
written for this class.
Change-Id: I5d182c6dc4b96b6f06b87ef320bdaec44c8945b8
---
M pywikibot/site.py
M tests/site_tests.py
2 files changed, 41 insertions(+), 1 deletion(-)
Approvals:
XZise: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/site.py b/pywikibot/site.py
index 4edb41d..a6ed308 100644
--- a/pywikibot/site.py
+++ b/pywikibot/site.py
@@ -64,12 +64,13 @@
from pywikibot.echo import Notification
if sys.version_info[0] > 2:
- from urllib.parse import urlencode
+ from urllib.parse import urlencode, urlparse
basestring = (str,)
unicode = str
from itertools import zip_longest
else:
from urllib import urlencode
+ from urlparse import urlparse
from itertools import izip_longest as zip_longest
@@ -1445,6 +1446,25 @@
return self._tokens.__repr__()
+class NonMWAPISite(BaseSite):
+
+ """API interface to non MediaWiki sites."""
+
+ def __init__(self, url):
+ """Constructor."""
+ self.netloc = urlparse(url).netloc
+
+ def __getattribute__(self, attr):
+ """Return attribute if present else raise NotImplementedError."""
+ whitelist = ['__getattribute__', 'netloc']
+ if attr in whitelist:
+ return super(NonMWAPISite, self).__getattribute__(attr)
+ else:
+ raise NotImplementedError('The attribute %s has not been on '
+ 'site %s implemented yet.'
+ % (attr, self.netloc))
+
+
class APISite(BaseSite):
"""API interface to MediaWiki site.
diff --git a/tests/site_tests.py b/tests/site_tests.py
index db78da7..3d116e7 100644
--- a/tests/site_tests.py
+++ b/tests/site_tests.py
@@ -2455,6 +2455,26 @@
pywikibot.Site, 'en', 'wikidata')
+class TestNonMWAPISite(TestCase):
+
+ """Test the BaseSite subclass, site.NonMWAPISite."""
+
+ net = False
+
+ def testNonMWsites(self):
+ """Test NonMWAPISite for sites not using MediaWiki."""
+ self._run_test("http://moinmo.in/$1")
+ self._run_test("http://twiki.org/cgi-bin/view/$1")
+ self._run_test("http://www.usemod.com/cgi-bin/wiki.pl?$1")
+ self._run_test("https://developer.mozilla.org/en/docs/$1")
+ self._run_test("http://www.tvtropes.org/pmwiki/pmwiki.php/Main/$1")
+
+ def _run_test(self, url):
+ site = pywikibot.site.NonMWAPISite(url)
+ with self.assertRaises(NotImplementedError):
+ site.attr
+
+
if __name__ == '__main__':
try:
unittest.main()
--
To view, visit https://gerrit.wikimedia.org/r/196141
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5d182c6dc4b96b6f06b87ef320bdaec44c8945b8
Gerrit-PatchSet: 2
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Maverick <manpreetkaur9411(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>
jenkins-bot has submitted this change and it was merged.
Change subject: Fixing a compat to core migration error in flickrripper.py.
......................................................................
Fixing a compat to core migration error in flickrripper.py.
Correcting error due to mistakenly calling undeclared function 'run' by
Tkdialog in the script which is renamed as show_dialog in present
implementation in core.
Change-Id: I2741b092a003390989aac725c3b7c313234fa04f
---
M scripts/flickrripper.py
1 file changed, 1 insertion(+), 1 deletion(-)
Approvals:
XZise: Looks good to me, approved
jenkins-bot: Verified
diff --git a/scripts/flickrripper.py b/scripts/flickrripper.py
index e7cd008..433ee2a 100644
--- a/scripts/flickrripper.py
+++ b/scripts/flickrripper.py
@@ -297,7 +297,7 @@
if Tkdialog is not None and not autonomous:
try:
(newPhotoDescription, newFilename, skip) = Tkdialog(
- photoDescription, photo, filename).run()
+ photoDescription, photo, filename).show_dialog()
except ImportError as e:
pywikibot.warning(e)
pywikibot.warning('Switching to autonomous mode.')
--
To view, visit https://gerrit.wikimedia.org/r/196632
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I2741b092a003390989aac725c3b7c313234fa04f
Gerrit-PatchSet: 2
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Prianka <priyankajayaswal025(a)gmail.com>
Gerrit-Reviewer: John Vandenberg <jayvdb(a)gmail.com>
Gerrit-Reviewer: Ladsgroup <ladsgroup(a)gmail.com>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: XZise <CommodoreFabianus(a)gmx.de>
Gerrit-Reviewer: jenkins-bot <>