jenkins-bot has submitted this change and it was merged.
Change subject: [IMPROV] Add docstrings ......................................................................
[IMPROV] Add docstrings
Change-Id: Idd9212a92a9fd3e2592dc1b7dcb4879d053e0987 --- M pywikibot/data/wikidataquery.py M pywikibot/flow.py M pywikibot/logentries.py M pywikibot/userinterfaces/terminal_interface_win32.py M pywikibot/userinterfaces/transliteration.py M pywikibot/userinterfaces/win32_unicode.py M tests/page_tests.py M tests/python_tests.py M tests/reflinks_tests.py M tests/timestamp_tests.py M tests/wikibase_edit_tests.py M tests/xmlreader_tests.py M tox.ini 13 files changed, 120 insertions(+), 2 deletions(-)
Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
diff --git a/pywikibot/data/wikidataquery.py b/pywikibot/data/wikidataquery.py index 2d7ee3a..8a40510 100644 --- a/pywikibot/data/wikidataquery.py +++ b/pywikibot/data/wikidataquery.py @@ -112,6 +112,7 @@ return s
def __repr__(self): + """Return a string representation.""" return u"QuerySet(%s)" % self
@@ -201,6 +202,7 @@ return True
def validateOrRaise(self, msg=None): + """Validate the contents and raise TypeError if the validation fails.""" if not self.validate(): raise TypeError(msg)
@@ -221,6 +223,7 @@ return int(item)
def convertWDTypes(self, items): + """Convert the items into integer IDs using L{Query.convertWDType}.""" return [self.convertWDType(x) for x in listify(items)]
def __str__(self): @@ -234,6 +237,7 @@ raise NotImplementedError
def __repr__(self): + """Return a string representation.""" return u"Query(%s)" % self
@@ -262,6 +266,7 @@ self.validateOrRaise()
def formatItems(self): + """Format the items when they are a list.""" res = '' if self.items: res += ":" + ",".join([self.formatItem(x) for x in self.items]) @@ -269,9 +274,11 @@ return res
def validate(self): + """Validate that the items are ints or Querys.""" return self.isOrContainsOnlyTypes(self.items, [int, Query])
def __str__(self): + """Return the query string for the API.""" if isinstance(self.items, list): return "%s[%s%s]" % (self.queryType, self.prop, self.formatItems()) elif isinstance(self.items, Query): @@ -296,6 +303,7 @@ return '"%s"' % x
def validate(self): + """Validate that the items are strings.""" return self.isOrContainsOnlyTypes(self.items, basestring)
@@ -330,11 +338,13 @@ self.validateOrRaise()
def validate(self): + """Validate that the item, forward and reverse are all ints.""" return (self.isOrContainsOnlyTypes(self.item, int) and self.isOrContainsOnlyTypes(self.forward, int) and self.isOrContainsOnlyTypes(self.reverse, int))
def __str__(self): + """Return the query string for the API.""" return "%s[%s][%s][%s]" % (self.queryType, self.formatList(self.item), self.formatList(self.forward), self.formatList(self.reverse)) @@ -354,9 +364,11 @@ self.rad = rad
def validate(self): + """Validate that the prop is an int.""" return isinstance(self.prop, int)
def __str__(self): + """Return the query string for the API.""" return "%s[%s,%s,%s,%s]" % (self.queryType, self.prop, self.lt, self.lg, self.rad)
@@ -383,9 +395,11 @@ self.end = end
def validate(self): + """Validate that a range is given and the prop is an int.""" return (self.begin or self.end) and isinstance(self.prop, int)
def __str__(self): + """Return the query string for the API.""" begin = self.begin.toTimestr() if self.begin else ''
# if you don't have an end, you don't put in the comma @@ -410,9 +424,11 @@ self.validateOrRaise()
def validate(self): + """Validate that the link is a string.""" return self.isOrContainsOnlyTypes(self.link, basestring)
def __str__(self): + """Return the query string for the API.""" return "%s[%s]" % (self.queryType, self.formatList(self.link))
@@ -470,6 +486,7 @@ "wikidataquery_cache")
def getUrl(self, queryStr): + """Get the URL given the query string.""" return "%s/api?%s" % (self.host, queryStr)
def getQueryString(self, q, labels=[], props=[]): diff --git a/pywikibot/flow.py b/pywikibot/flow.py index 1580edb..5677db9 100644 --- a/pywikibot/flow.py +++ b/pywikibot/flow.py @@ -70,6 +70,7 @@ return self._uuid
def get(self, force=False, get_redirect=False, sysop=False): + """Get the page's content.""" if get_redirect or force or sysop: raise NotImplementedError
diff --git a/pywikibot/logentries.py b/pywikibot/logentries.py index 825f166..11f1d73 100644 --- a/pywikibot/logentries.py +++ b/pywikibot/logentries.py @@ -31,6 +31,7 @@ """
def __missing__(self, key): + """Debug when the key is missing.""" pywikibot.debug(u"API log entry received:\n" + repr(self), _logger) raise KeyError("Log entry (%s) has no '%s' key" % (self._type, key)) @@ -55,6 +56,7 @@ self.data._type = self.type()
def __hash__(self): + """Return the id as the hash.""" return self.logid()
@property @@ -74,12 +76,15 @@ "for type %s." % (self.action(), self.type))
def logid(self): + """Return the id of the log entry.""" return self.data['logid']
def pageid(self): + """Return the log id of the page handled by this log entry.""" return self.data['pageid']
def ns(self): + """Return the namespace id of the page handled by this log entry.""" return self.data['ns']
@deprecated('page()') @@ -104,12 +109,15 @@ return self._page
def type(self): + """The type of thie logentry.""" return self.data['type']
def action(self): + """The action of this log entry.""" return self.data['action']
def user(self): + """Return the user name doing this action.""" # TODO use specific User class ? return self.data['user']
@@ -121,6 +129,7 @@ return self._timestamp
def comment(self): + """Return the logentry's comment.""" return self.data['comment']
diff --git a/pywikibot/userinterfaces/terminal_interface_win32.py b/pywikibot/userinterfaces/terminal_interface_win32.py index afe4841..600a713 100755 --- a/pywikibot/userinterfaces/terminal_interface_win32.py +++ b/pywikibot/userinterfaces/terminal_interface_win32.py @@ -49,6 +49,7 @@ """User interface for Win32 terminals without ctypes."""
def __init__(self): + """Constructor.""" terminal_interface_base.UI.__init__(self) self.encoding = 'ascii'
@@ -58,6 +59,7 @@ """User interface for Win32 terminals using ctypes."""
def __init__(self): + """Constructor.""" Win32BaseUI.__init__(self) from .win32_unicode import stdin, stdout, stderr, argv self.stdin = stdin @@ -67,6 +69,7 @@ self.encoding = 'utf-8'
def printColorized(self, text, targetStream): + """Print the text colorized to the target stream.""" std_out_handle = ctypes.windll.kernel32.GetStdHandle(-11) # Color tags might be cascaded, e.g. because of transliteration. # Therefore we need this stack. diff --git a/pywikibot/userinterfaces/transliteration.py b/pywikibot/userinterfaces/transliteration.py index efd4103..49e0d1f 100644 --- a/pywikibot/userinterfaces/transliteration.py +++ b/pywikibot/userinterfaces/transliteration.py @@ -10,6 +10,13 @@ """Class to transliterating text."""
def __init__(self, encoding): + """ + Initialize the transliteration mapping. + + @param encoding: the encoding available. Any transliterated character + which can't be mapped, will be removed from the mapping. + @type encoding: str + """ self.trans = {} for char in u"ÀÁÂẦẤẪẨẬÃĀĂẰẮẴẶẲȦǠẠḀȂĄǍẢ": self.trans[char] = u"A" @@ -2818,6 +2825,20 @@ self.trans[char] = value
def transliterate(self, char, default="?", prev="-", next="-"): + """ + Transliterate the character. + + @param char: The character to transliterate. + @type char: str + @param default: The character used when there is no transliteration. + @type default: str + @param prev: The previous character + @type prev: str + @param next: The next character + @type next: str + @return: The transliterated character which may be an empty string + @rtype: str + """ if char in self.trans: return self.trans[char] # Arabic diff --git a/pywikibot/userinterfaces/win32_unicode.py b/pywikibot/userinterfaces/win32_unicode.py index 4af10bc..e4b176f 100755 --- a/pywikibot/userinterfaces/win32_unicode.py +++ b/pywikibot/userinterfaces/win32_unicode.py @@ -83,12 +83,14 @@ INVALID_HANDLE_VALUE = DWORD(-1).value
def not_a_console(handle): + """Return whether the handle is not to a console.""" if handle == INVALID_HANDLE_VALUE or handle is None: return True return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR or GetConsoleMode(handle, byref(DWORD())) == 0)
def old_fileno(std_name): + """Return the fileno or None if that doesn't work.""" # some environments like IDLE don't support the fileno operation # handle those like std streams which don't have fileno at all std = getattr(sys, 'std{0}'.format(std_name)) @@ -133,6 +135,7 @@ """Unicode terminal input class."""
def __init__(self, hConsole, name, bufsize=1024): + """Initialize the input stream.""" self._hConsole = hConsole self.bufsize = bufsize self.buffer = create_unicode_buffer(bufsize) @@ -140,6 +143,7 @@ self.encoding = 'utf-8'
def readline(self): + """Read one line from the input.""" maxnum = DWORD(self.bufsize - 1) numrecv = DWORD(0) result = ReadConsoleW(self._hConsole, self.buffer, maxnum, byref(numrecv), None) @@ -163,6 +167,7 @@ """Unicode terminal output class."""
def __init__(self, hConsole, stream, fileno, name): + """Initialize the output stream.""" self._hConsole = hConsole self._stream = stream self._fileno = fileno @@ -174,16 +179,20 @@ self.flush()
def isatty(self): + """Return whether it's a tty.""" return False
def close(self): + """Set the stream to be closed.""" # don't really close the handle, that would only cause problems self.closed = True
def fileno(self): + """Return the fileno.""" return self._fileno
def flush(self): + """Flush the stream.""" if self._hConsole is None: try: self._stream.flush() @@ -193,6 +202,7 @@ raise
def write(self, text): + """Write the text to the output.""" try: if self._hConsole is None: if isinstance(text, unicode): @@ -222,6 +232,7 @@ raise
def writelines(self, lines): + """Write a list of lines by using write.""" try: for line in lines: self.write(line) diff --git a/tests/page_tests.py b/tests/page_tests.py index 087bc14..13b4ed4 100644 --- a/tests/page_tests.py +++ b/tests/page_tests.py @@ -167,6 +167,7 @@ cached = True
def testGeneral(self): + """Test general features of a page.""" site = self.get_site() mainpage = self.get_mainpage() maintalk = mainpage.toggleTalkPage() @@ -383,6 +384,7 @@ self.assertEqual(p3.isCategory(), False)
def testIsImage(self): + """Test C{Page.isImage} check.""" site = self.get_site() p1 = pywikibot.Page(site, u"First page") p2 = pywikibot.Page(site, u"File:Second page") @@ -437,6 +439,7 @@ self.assertFalse(pg.isDisambig())
def testReferences(self): + """Test references to a page.""" mainpage = self.get_mainpage() count = 0 # Ignore redirects for time considerations @@ -459,6 +462,7 @@ break
def testLinks(self): + """Test the different types of links from a page.""" if self.site.family.name == 'wpbeta': raise unittest.SkipTest('Test fails on betawiki; T69931') mainpage = self.get_mainpage() @@ -485,6 +489,7 @@ self.assertIsInstance(p, unicode)
def testPickleAbility(self): + """Test the ability to pickle the page.""" mainpage = self.get_mainpage() import pickle mainpage_str = pickle.dumps(mainpage, protocol=config.pickle_protocol) @@ -722,7 +727,13 @@
class TestPageRedirects(TestCase):
- """Test redirects.""" + """ + Test redirects. + + This is using the pages 'User:Legoktm/R1', 'User:Legoktm/R2' and + 'User:Legoktm/R3' on the English Wikipedia. 'R1' is redirecting to 'R2', + 'R2' is a normal page and 'R3' does not exist. + """
family = 'wikipedia' code = 'en' @@ -730,6 +741,7 @@ cached = True
def testIsRedirect(self): + """Test C{Page.isRedirectPage()} and C{Page.getRedirectTarget}.""" site = self.get_site() p1 = pywikibot.Page(site, u'User:Legoktm/R1') p2 = pywikibot.Page(site, u'User:Legoktm/R2') @@ -737,6 +749,7 @@ self.assertEqual(p1.getRedirectTarget(), p2)
def testPageGet(self): + """Test C{Page.get()} on different types of pages.""" site = self.get_site() p1 = pywikibot.Page(site, u'User:Legoktm/R2') p2 = pywikibot.Page(site, u'User:Legoktm/R1') @@ -755,6 +768,7 @@ user = True
def test_purge(self): + """Test purging the mainpage.""" mainpage = self.get_mainpage() self.assertIsInstance(mainpage.purge(), bool)
diff --git a/tests/python_tests.py b/tests/python_tests.py index 218cc40..1f958d9 100755 --- a/tests/python_tests.py +++ b/tests/python_tests.py @@ -59,6 +59,7 @@
@unittest.skipIf(not unicodedata2, 'unicodedata2 not found') def test_issue_10254_unicodedata2(self): + """Test Python issue #10254 is avoided with unicodedata2 package.""" text = 'Li̍t-sṳ́' self.assertEqual(text, unicodedata2.normalize('NFC', text))
diff --git a/tests/reflinks_tests.py b/tests/reflinks_tests.py index fec7c44..6834223 100644 --- a/tests/reflinks_tests.py +++ b/tests/reflinks_tests.py @@ -145,6 +145,7 @@ code = 'en'
def setUp(self): + """Set up the script by patching the bot class.""" super(TestReferencesBotConstructor, self).setUp() self._original_constructor = ReferencesRobot.__init__ self._original_run = ReferencesRobot.run @@ -152,17 +153,20 @@ ReferencesRobot.run = lambda self: None
def tearDown(self): + """Tear down the test by undoing the bot class patch.""" ReferencesRobot.__init__ = self._original_constructor ReferencesRobot.run = self._original_run super(TestReferencesBotConstructor, self).tearDown()
def test_xml_simple(self): + """Test the generator without any narrowing.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml')) gen = self.constructor_args[0] self.assertPageTitlesCountEqual(gen, [u'Fake page', u'Talk:Fake page'], site=self.get_site())
def test_xml_one_namespace(self): + """Test the generator using one namespace id.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:1') gen = self.constructor_args[0] @@ -171,6 +175,7 @@ site=self.get_site())
def test_xml_multiple_namespace_ids(self): + """Test the generator using multiple separate namespaces parameters.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:0', '-namespace:1', '-xmlstart:Fake page') gen = self.constructor_args[0] @@ -179,6 +184,7 @@
@unittest.expectedFailure def test_xml_multiple_namespace_ids_2(self): + """Test the generator using multiple namespaces in one parameter.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:0,1', '-xmlstart:Fake page') gen = self.constructor_args[0] @@ -187,6 +193,7 @@
@unittest.expectedFailure def test_xml_start_prefix(self): + """Test the generator using a start partial page.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:1', '-xmlstart:Fake') gen = self.constructor_args[0] @@ -196,6 +203,7 @@
@unittest.expectedFailure def test_xml_start_underscore(self): + """Test the generator using a start page with an underscore.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:1', '-xmlstart:Fake_page') gen = self.constructor_args[0] @@ -204,6 +212,7 @@ site=self.get_site())
def test_xml_namespace_name(self): + """Test the generator using a namespace name.""" main('-xml:' + os.path.join(_xml_data_dir, 'dummy-reflinks.xml'), '-namespace:Talk', '-xmlstart:Fake page') gen = self.constructor_args[0] @@ -213,6 +222,7 @@
def dummy_constructor(self, *args, **kwargs): + """A constructor faking the actual constructor.""" TestReferencesBotConstructor.constructor_args = args TestReferencesBotConstructor.constructor_kwargs = kwargs
diff --git a/tests/timestamp_tests.py b/tests/timestamp_tests.py index 1b449d4..82ad48a 100644 --- a/tests/timestamp_tests.py +++ b/tests/timestamp_tests.py @@ -24,6 +24,7 @@ net = False
def test_clone(self): + """Test cloning a Timestamp instance.""" t1 = T.utcnow() t2 = t1.clone() self.assertEqual(t1, t2) @@ -40,6 +41,7 @@ self.assertIsInstance(T.fromtimestampformat(t1), T)
def test_iso_format(self): + """Test conversion from and to ISO format.""" t1 = T.utcnow() ts1 = t1.toISOformat() t2 = T.fromISOformat(ts1) @@ -51,6 +53,7 @@ self.assertEqual(ts1, ts2)
def test_mediawiki_format(self): + """Test conversion from and to timestamp format.""" t1 = T.utcnow() ts1 = t1.totimestampformat() t2 = T.fromtimestampformat(ts1) @@ -62,6 +65,7 @@ self.assertEqual(ts1, ts2)
def test_add_timedelta(self): + """Test addin a timedelta to a Timestamp.""" t1 = T.utcnow() t2 = t1 + datetime.timedelta(days=1) if t1.month != t2.month: @@ -84,6 +88,7 @@ self.assertIs(t3, NotImplemented)
def test_sub_timedelta(self): + """Test substracting a timedelta from a Timestamp.""" t1 = T.utcnow() t2 = t1 - datetime.timedelta(days=1) if t1.month != t2.month: @@ -93,6 +98,7 @@ self.assertIsInstance(t2, T)
def test_sub_timedate(self): + """Test subtracting two timestamps.""" t1 = T.utcnow() t2 = t1 - datetime.timedelta(days=1) td = t1 - t2 diff --git a/tests/wikibase_edit_tests.py b/tests/wikibase_edit_tests.py index 9367e32..27c22b6 100644 --- a/tests/wikibase_edit_tests.py +++ b/tests/wikibase_edit_tests.py @@ -27,6 +27,7 @@ write = True
def test_label_set(self): + """Test setting an English label.""" testsite = self.get_repo() item = pywikibot.ItemPage(testsite, 'Q68') self.assertIsInstance(item, pywikibot.ItemPage) @@ -36,6 +37,7 @@ self.assertEqual(item.labels['en'], 'Test123')
def test_label_remove(self): + """Test adding a Farsi and English label and removing the Farsi one.""" testsite = self.get_repo() item = pywikibot.ItemPage(testsite, 'Q68') # These two should be additive @@ -54,12 +56,14 @@ self.assertNotIn('fa', item.labels.keys())
def test_alias_set(self): + """Test setting an English alias.""" testsite = self.get_repo() ts = str(time.time()) item = pywikibot.ItemPage(testsite, 'Q68') item.editAliases({'en': [ts]})
def test_add_claim_with_qualifier(self): + """Test adding a claim with a qualifier to an item and a property.""" testsite = self.get_repo() item = pywikibot.ItemPage(testsite, 'Q68') item.get() @@ -99,6 +103,7 @@ item.claims['P115'][0].addQualifier(end_date)
def test_edit_entity_new_item(self): + """Test creating a new item using C{ItemPage.editEntity}.""" testsite = self.get_repo() ts = str(time.time()) data = { @@ -119,6 +124,7 @@ item.editEntity(data)
def test_edit_entity_new_linked_item(self): + """Test linking a page using a new item.""" ts = str(time.time())
# Create a new page, which is unlinked diff --git a/tests/xmlreader_tests.py b/tests/xmlreader_tests.py index de2e86c..8534076 100644 --- a/tests/xmlreader_tests.py +++ b/tests/xmlreader_tests.py @@ -26,6 +26,7 @@ net = False
def _get_entries(self, filename, **kwargs): + """Get all entries via XmlDump.""" entries = [r for r in xmlreader.XmlDump(os.path.join(_xml_data_dir, filename), **kwargs).parse()] @@ -37,6 +38,7 @@ """XML export version 0.3 tests."""
def test_XmlDumpAllRevs(self): + """Test loading all revisions.""" pages = self._get_entries('article-pear.xml', allrevisions=True) self.assertEqual(4, len(pages)) self.assertEqual(u"Automated conversion", pages[0].comment) @@ -47,6 +49,7 @@ self.assertEqual(u"Pear", pages[0].title)
def test_XmlDumpFirstRev(self): + """Test loading the first revision.""" pages = self._get_entries("article-pear.xml", allrevisions=False) self.assertEqual(1, len(pages)) self.assertEqual(u"Automated conversion", pages[0].comment) @@ -56,6 +59,7 @@ self.assertTrue(not pages[0].isredirect)
def test_XmlDumpRedirect(self): + """Test XmlDump correctly parsing whether a page is a redirect.""" pages = self._get_entries('article-pyrus.xml', allrevisions=True) pages = [r for r in xmlreader.XmlDump(os.path.join(_xml_data_dir, @@ -63,6 +67,7 @@ self.assertTrue(pages[0].isredirect)
def _compare(self, previous, variant, all_revisions): + """Compare the tested variant with the previous (if not None).""" entries = self._get_entries('article-pyrus' + variant, allrevisions=all_revisions) result = [entry.__dict__ for entry in entries] @@ -71,6 +76,7 @@ return result
def _compare_variants(self, all_revisions): + """Compare the different XML file variants.""" previous = None previous = self._compare(previous, '.xml', all_revisions) previous = self._compare(previous, '-utf16.xml', all_revisions) @@ -78,9 +84,11 @@ previous = self._compare(previous, '-utf16.xml.bz2', all_revisions)
def test_XmlDump_compare_all(self): + """Compare the different XML files using all revisions.""" self._compare_variants(True)
def test_XmlDump_compare_single(self): + """Compare the different XML files using only a single revision.""" self._compare_variants(False)
@@ -89,6 +97,7 @@ """XML export version 0.10 tests."""
def test_pair(self): + """Test reading the main page/user talk page pair file.""" entries = self._get_entries('pair-0.10.xml', allrevisions=True) self.assertEqual(4, len(entries)) self.assertTrue(all(entry.username == 'Carlossuarez46' diff --git a/tox.ini b/tox.ini index 7877956..67b30f7 100644 --- a/tox.ini +++ b/tox.ini @@ -53,6 +53,7 @@ pywikibot/families/ \ pywikibot/fixes.py \ pywikibot/i18n.py \ + pywikibot/logentries.py \ pywikibot/login.py \ pywikibot/page.py \ pywikibot/pagegenerators.py \ @@ -66,6 +67,9 @@ pywikibot/userinterfaces/terminal_interface.py \ pywikibot/userinterfaces/terminal_interface_base.py \ pywikibot/userinterfaces/terminal_interface_unix.py \ + pywikibot/userinterfaces/terminal_interface_win32.py \ + pywikibot/userinterfaces/transliteration.py \ + pywikibot/userinterfaces/win32_unicode.py \ pywikibot/version.py \ pywikibot/weblib.py \ pywikibot/xmlreader.py \ @@ -151,14 +155,18 @@ tests/mediawikiversion_tests.py \ tests/namespace_tests.py \ tests/oauth_tests.py \ + tests/page_tests.py \ tests/proofreadpage_tests.py \ tests/protectbot_tests.py \ tests/pwb/ \ tests/pwb_tests.py \ + tests/python_tests.py \ + tests/reflinks_tests.py \ tests/replacebot_tests.py \ tests/script_tests.py \ tests/site_detect_tests.py \ tests/tests_tests.py \ + tests/timestamp_tests.py \ tests/timestripper_tests.py \ tests/thread_tests.py \ tests/tk_tests.py \ @@ -170,8 +178,10 @@ tests/uploadbot_tests.py \ tests/weblib_tests.py \ tests/weblinkchecker_tests.py \ + tests/wikibase_edit_tests.py \ tests/wikidataquery_tests.py \ - tests/wikistats_tests.py + tests/wikistats_tests.py \ + tests/xmlreader_tests.py
deps = flake8>=2.2.5 flake8-docstrings