jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1312241?usp=email )
Change subject: MWSite: raise the Exception if self.private_wiki value cannot be set
......................................................................
MWSite: raise the Exception if self.private_wiki value cannot be set
If _parse_site() leads to an exception, raise it if private_wiki
variable cannot be set. Otherwise raise the
RuntimeError(Unable to determine articlepath)
Change-Id: I9e2262ae5c68fc35054bb6e378ba76f2712b5217
---
M pywikibot/site_detect.py
1 file changed, 5 insertions(+), 0 deletions(-)
Approvals:
jenkins-bot: Verified
Xqt: Looks good to me, approved
diff --git a/pywikibot/site_detect.py b/pywikibot/site_detect.py
index bcbd627..0c255b5 100644
--- a/pywikibot/site_detect.py
+++ b/pywikibot/site_detect.py
@@ -61,6 +61,7 @@
self.server = wp.server
self.scriptpath = wp.scriptpath
self.articlepath = None
+ self.private_wiki = None
if self.api:
try:
@@ -69,6 +70,7 @@
raise
except Exception as e:
pywikibot.log(f'MW detection failed: {e!r}')
+ self.private_wiki = e
if not self.version:
self._fetch_old_version()
@@ -80,6 +82,9 @@
raise RuntimeError(f'Unsupported version: {self.version}')
if not self.articlepath:
+ if isinstance(self.private_wiki, Exception):
+ raise self.private_wiki
+
if not self.private_wiki:
raise RuntimeError(
f'Unable to determine articlepath: {self.fromurl}')
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1312241?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I9e2262ae5c68fc35054bb6e378ba76f2712b5217
Gerrit-Change-Number: 1312241
Gerrit-PatchSet: 4
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1162017?usp=email )
Change subject: IMPR(GeneratorsMixin.usercontribs): Add all `ucshow` parameters
......................................................................
IMPR(GeneratorsMixin.usercontribs): Add all `ucshow` parameters
MediaWiki core supports are five values (and their negations) for the
`ucshow` parameter, of which one and a half were supported so far:
- `minor` was supported
- `top` was only supported as the deprecated `uctoponly` parameter,
which generates deprecation warnings, and only works as a positive
filter (i.e. doesn’t allow filtering for non-top edits)
- `new`, `patrolled` and `autopatrolled` weren’t supported at all
Add support for all five using ternary (`bool|None`) parameters, and
deprecate the old, binary (`bool`) `top_only` parameter at a Pywikibot
level, avoiding the API deprecation warnings.
All five filters has been supported since MediaWiki 1.31 or earlier (the
newest one is `autopatrolled`, which debuted exactly in 1.31: T184791 /
If64ba8b845b122a87f20646dddf72ef257b793cb), so backward compatibility is
not an issue.
This adds support only for core filters. At least the ORES extension
adds an additional filter `oresreview`, but I’m not sure if it’s a good
idea to add an extension-specific filter to a generic query.
Due to kwargs usage the new parameters are also available with
User.contribs and User.contributions.
Add tests for `new` and `top`, but not for `patrolled` and
`autopatrolled`, as the latter two may fail with permission errors,
making the tests flaky.
All parameters are keyword-only now; older usage is deprecated.
Update documentation
Change-Id: I0b67fe74bc2a7412da11374f6968472d40b3759d
---
M pywikibot/page/_user.py
M pywikibot/site/_generators.py
M tests/site_generators_tests.py
3 files changed, 123 insertions(+), 31 deletions(-)
Approvals:
jenkins-bot: Verified
Xqt: Looks good to me, approved
diff --git a/pywikibot/page/_user.py b/pywikibot/page/_user.py
index 6f9d486..9a8e8c9 100644
--- a/pywikibot/page/_user.py
+++ b/pywikibot/page/_user.py
@@ -536,6 +536,10 @@
now accepts ``None`` to iterate both latest and non-latest
contributions. ``False`` now iterates only non-latest
contributions. Default is ``None``.
+ .. version-changed:: 11.7
+ The *new*, *patrolled*, *autopatrolled*, *prop* and
+ *formatversion* parameter were added. The ``size`` property
+ is included by default.
.. seealso::
- :meth:`contribs`
- :meth:`Site.usercontribs()
@@ -545,16 +549,31 @@
:param total: Limit result to this number of pages
:keyword start: Iterate contributions starting at this Timestamp
:keyword end: Iterate contributions ending at this Timestamp
- :keyword reverse: Iterate oldest contributions first (default: newest)
+ :keyword bool reverse: Iterate oldest contributions first
+ (default: newest)
:keyword namespaces: Only iterate pages in these namespaces
:type namespaces: Iterable of str or Namespace key,
or a single instance of those types. May be a '|' separated
list of namespace identifiers.
- :keyword minor: If True, iterate only minor edits; if False and
- not None, iterate only non-minor edits (default: iterate both)
- :param top: if ``True``, iterate only edits which are the latest
- revision; if ``False``, do not iterate last revision edits;
- ``None`` to iterate both (default: ``None``)
+ :keyword bool | None minor: If ``True``, iterate only minor
+ edits; if ``False`` and not ``None``, iterate only non-minor
+ edits (default: iterate both)
+ :keyword bool | None top: if ``True``, iterate only edits which
+ are the latest revision; if ``False``, do not iterate last
+ revision edits; ``None`` to iterate both (default: ``None``)
+ :keyword bool | None new: If ``True``, iterate only edits
+ creating new pages; if ``False``, iterate only edits to
+ existing pages; if ``None``, iterate both.
+ :keyword bool | None patrolled: If ``True``, iterate only edits
+ that have been patrolled (either manually or automatically;
+ use the *autopatrolled* parameter to control how); if
+ ``False``, iterate only edits that haven't been patrolled
+ yet; if ``None``, iterate both; both ``True`` or ``False``
+ exclude edits older than ``$wgRCMaxAge``.
+ :keyword bool | None autopatrolled: If ``True``, iterate only
+ autopatrolled edits; if ``False``, iterate only edits that
+ weren't autopatrolled; if ``None``, iterate both; both
+ ``True`` or ``False`` exclude edits older than ``$wgRCMaxAge``.
:return: Tuple of pywikibot.Page, revid, pywikibot.Timestamp, comment
"""
prop = ('comment', 'ids', 'timestamp', 'title')
@@ -598,20 +617,37 @@
<pywikibot.site._generators.GeneratorsMixin.usercontribs>`
- :api:`Usercontribs`
+ :keyword int | None total: Limit result to this number of pages
:keyword start: Iterate contributions starting at this Timestamp
:keyword end: Iterate contributions ending at this Timestamp
- :keyword reverse: Iterate oldest contributions first (default:
- newest)
+ :keyword bool reverse: Iterate oldest contributions first
+ (default: newest)
:keyword namespaces: Only iterate pages in these namespaces
- :keyword minor: If ``True``, iterate only minor edits; if ``False``
- and not ``None``, iterate only non-minor edits (default:
- iterate both)
- :keyword total: Limit result to this number of pages
- :keyword top: if ``True``, iterate only edits which are the latest
- revision; if ``False``, do not iterate last revision edits;
- ``None`` to iterate both (default: ``None``)
- :keyword prop: Include additional pieces of information. Refer
- :api:`Usercontribs` for the elements and the default setting.
+ :type namespaces: Iterable of str or Namespace key,
+ or a single instance of those types. May be a '|' separated
+ list of namespace identifiers.
+ :keyword bool | None minor: If ``True``, iterate only minor
+ edits; if ``False`` and not ``None``, iterate only non-minor
+ edits (default: iterate both)
+ :keyword bool | None top: if ``True``, iterate only edits which
+ are the latest revision; if ``False``, do not iterate last
+ revision edits; ``None`` to iterate both (default: ``None``)
+ :keyword bool | None new: If ``True``, iterate only edits
+ creating new pages; if ``False``, iterate only edits to
+ existing pages; if ``None``, iterate both.
+ :keyword bool | None patrolled: If ``True``, iterate only edits
+ that have been patrolled (either manually or automatically;
+ use the *autopatrolled* parameter to control how); if
+ ``False``, iterate only edits that haven't been patrolled
+ yet; if ``None``, iterate both; both ``True`` or ``False``
+ exclude edits older than ``$wgRCMaxAge``.
+ :keyword bool | None autopatrolled: If ``True``, iterate only
+ autopatrolled edits; if ``False``, iterate only edits that
+ weren't autopatrolled; if ``None``, iterate both; both
+ ``True`` or ``False`` exclude edits older than ``$wgRCMaxAge``.
+ :keyword Iterable[str] | str | None prop: Include additional
+ pieces of information. Refer :api:`Usercontribs` for the
+ elements and the default setting.
:return: For each entry return a tuple of Page, Revision
"""
for contrib in self.site.usercontribs(
diff --git a/pywikibot/site/_generators.py b/pywikibot/site/_generators.py
index 44e2b61..40dd40f 100644
--- a/pywikibot/site/_generators.py
+++ b/pywikibot/site/_generators.py
@@ -1638,8 +1638,10 @@
parameters=parameters)
@deprecated_args(top_only='top') # since 11.6.0
+ @deprecated_signature(since='10.7.0')
def usercontribs(
self,
+ *,
user: str | None = None,
userprefix: str | None = None,
start: pywikibot.time.Timestamp | datetime | str | None = None,
@@ -1649,7 +1651,10 @@
minor: bool | None = None,
total: int | None = None,
top: bool | None = None,
- *,
+ # old kw args below
+ new: bool | None = None,
+ patrolled: bool | None = None,
+ autopatrolled: bool | None = None,
prop: Iterable[str] | str | None = None,
formatversion: int = 1
) -> Iterable[dict[str, Any]]:
@@ -1659,32 +1664,51 @@
.. seealso::
- :api:`Usercontribs`
+ - :meth:`pywikibot.User.contribs`
- :meth:`pywikibot.User.contributions`
.. version-changed:: 3.0.20200609
The *showMinor* parameter was renamed to *minor*.
+
.. version-changed:: 11.6
- The *prop* and *formatversion* parameter were added. The
+ The *prop* and *formatversion* parameters were added. The
*top_only* was renamed to *top*. This parameter now accepts
``None`` to iterate both latest and non-latest contributions.
``False`` now iterates only non-latest contributions. Default
is ``None``. The ``size`` property is included by default.
- :param user: Iterate contributions by this user (name or IP)
+ .. version-changed:: 11.7
+ All parameters are keyword-only now. The *new*, *patrolled*,
+ and *autopatrolled* parameters were added.
+
+ :param user: Iterate contributions by this user (name or IP).
:param userprefix: Iterate contributions by all users whose
- names or IPs start with this substring
- :param start: Iterate contributions starting at this Timestamp
- :param end: Iterate contributions ending at this Timestamp
+ names or IPs start with this substring.
+ :param start: Iterate contributions starting at this Timestamp.
+ :param end: Iterate contributions ending at this Timestamp.
:param reverse: Iterate oldest contributions first (default:
- newest)
- :param namespaces: Only iterate pages in these namespaces
+ newest).
+ :param namespaces: Only iterate pages in these namespaces.
:param minor: If ``True``, iterate only minor edits; if ``False``
and not ``None``, iterate only non-minor edits (default:
- iterate both)
- :param total: Limit result to this number of pages
+ iterate both).
+ :param total: Limit result to this number of pages.
:param top: if ``True``, iterate only edits which are the latest
revision; if ``False``, do not iterate last revision edits;
- ``None`` to iterate both (default: ``None``)
+ ``None`` to iterate both (default: ``None``).
+ :param new: If ``True``, iterate only edits creating new pages;
+ if ``False``, iterate only edits to existing pages; if
+ ``None``, iterate both.
+ :param patrolled: If ``True``, iterate only edits that have been
+ patrolled (either manually or automatically; use the
+ *autopatrolled* parameter to control how); if ``False``,
+ iterate only edits that haven't been patrolled yet; if
+ ``None``, iterate both; both ``True`` or ``False`` exclude
+ edits older than ``$wgRCMaxAge``.
+ :param autopatrolled: If ``True``, iterate only autopatrolled
+ edits; if ``False``, iterate only edits that weren't
+ autopatrolled; if ``None``, iterate both; both ``True`` or
+ ``False`` exclude edits older than ``$wgRCMaxAge``.
:param prop: Include additional pieces of information. Refer
:api:`Usercontribs` for the elements and the default setting.
:param formatversion: The API format version to use for the
@@ -1718,9 +1742,15 @@
ucgen.request['ucuserprefix'] = userprefix
if reverse:
ucgen.request['ucdir'] = 'newer'
- option_set = api.OptionSet(self, 'usercontribs', 'show')
- option_set['minor'] = minor
- option_set['top'] = top
+
+ filters = {
+ 'minor': minor,
+ 'top': top,
+ 'new': new,
+ 'patrolled': patrolled,
+ 'autopatrolled': autopatrolled,
+ }
+ option_set = api.OptionSet(self, 'usercontribs', 'show', filters)
ucgen.request['ucshow'] = option_set
return ucgen
diff --git a/tests/site_generators_tests.py b/tests/site_generators_tests.py
index d01d0fa..eb5d493 100755
--- a/tests/site_generators_tests.py
+++ b/tests/site_generators_tests.py
@@ -1177,6 +1177,32 @@
self.assertIsInstance(contrib, dict)
self.assertNotIn('minor', contrib)
+ def test_show_new(self) -> None:
+ """Test the site.usercontribs() method using showMinor."""
+ mysite = self.get_site()
+ for contrib in mysite.usercontribs(user=mysite.user(),
+ new=True, total=5):
+ self.assertIsInstance(contrib, dict)
+ self.assertIn('new', contrib)
+
+ for contrib in mysite.usercontribs(user=mysite.user(),
+ new=False, total=5):
+ self.assertIsInstance(contrib, dict)
+ self.assertNotIn('new', contrib)
+
+ def test_show_top(self) -> None:
+ """Test the site.usercontribs() method using showMinor."""
+ mysite = self.get_site()
+ for contrib in mysite.usercontribs(user=mysite.user(),
+ top=True, total=5):
+ self.assertIsInstance(contrib, dict)
+ self.assertIn('top', contrib)
+
+ for contrib in mysite.usercontribs(user=mysite.user(),
+ top=False, total=5):
+ self.assertIsInstance(contrib, dict)
+ self.assertNotIn('top', contrib)
+
class TestUserContribsWithoutUser(DefaultSiteTestCase):
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1162017?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I0b67fe74bc2a7412da11374f6968472d40b3759d
Gerrit-Change-Number: 1162017
Gerrit-PatchSet: 9
Gerrit-Owner: Tacsipacsi <tacsipacsi(a)jnet.hu>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1316008?usp=email )
Change subject: doc: add :ext: Sphinx role linking to MediaWiki extensions
......................................................................
doc: add :ext: Sphinx role linking to MediaWiki extensions
Bug: T433111
Change-Id: Ie9878a9c28926733fd33b5eb1b5fd4ddba0ea649
---
M docs/conf.py
M pywikibot/family.py
M pywikibot/login.py
M pywikibot/proofreadpage.py
M pywikibot/site/_extensions.py
M scripts/coordinate_import.py
M scripts/illustrate_wikidata.py
7 files changed, 14 insertions(+), 18 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/docs/conf.py b/docs/conf.py
index e113e7c..df97871 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -496,6 +496,8 @@
extlinks = {
# MediaWiki API
'api': ('https://www.mediawiki.org/wiki/API:%s', 'API:%s'),
+ # MediaWiki Extension
+ 'ext': ('https://www.mediawiki.org/wiki/Extension:%s', 'Extension:%s'),
# Python bug tracker
'issue': ('https://github.com/python/cpython/issues/%s',
'Python issue %s'),
diff --git a/pywikibot/family.py b/pywikibot/family.py
index 516e61f..365b0d9 100644
--- a/pywikibot/family.py
+++ b/pywikibot/family.py
@@ -252,7 +252,7 @@
ldapDomain = ()
"""LDAP domain if your wiki uses LDAP authentication.
- .. seealso:: https://www.mediawiki.org/wiki/Extension:LDAPAuthentication2
+ .. seealso:: :ext:`LDAPAuthentication2`
"""
crossnamespace: CrossnamespaceType = collections.defaultdict(dict)
diff --git a/pywikibot/login.py b/pywikibot/login.py
index 9ae59f6..c79acaa 100644
--- a/pywikibot/login.py
+++ b/pywikibot/login.py
@@ -371,8 +371,8 @@
.. version-changed:: 10.2
Secondary authentication via email was enabled.
.. seealso::
- - https://www.mediawiki.org/wiki/Extension:OATHAuth
- - https://www.mediawiki.org/wiki/Extension:EmailAuth
+ - :ext:`OATHAuth`
+ - :ext:`EmailAuth`
"""
_waituntil: datetime.datetime
diff --git a/pywikibot/proofreadpage.py b/pywikibot/proofreadpage.py
index a3ebef4..c5c7b85 100644
--- a/pywikibot/proofreadpage.py
+++ b/pywikibot/proofreadpage.py
@@ -1101,9 +1101,8 @@
.. note:: This method is called by initializer and should not be used.
- .. seealso::
- `ProofreadPage Index Pagination API
- <https://www.mediawiki.org/wiki/Extension:ProofreadPage/Index_pagination_API>`_
+ .. seealso:: :ext:`ProofreadPage Index Pagination API
+ <ProofreadPage/Index_pagination_API>`
:meta public:
"""
diff --git a/pywikibot/site/_extensions.py b/pywikibot/site/_extensions.py
index e0ca075..f048be7 100644
--- a/pywikibot/site/_extensions.py
+++ b/pywikibot/site/_extensions.py
@@ -343,7 +343,7 @@
) -> Iterable[pywikibot.Page]:
"""Return a generator to pages containing linter errors.
- .. seealso:: https://www.mediawiki.org/wiki/Extension:Linter
+ .. seealso:: :ext:`Linter`
:param lint_categories: Categories of lint errors. Must be an
iterable of lint categories, or a pipe-separated string of
@@ -446,10 +446,8 @@
:return: The extract of the page.
.. seealso::
-
- - https://www.mediawiki.org/wiki/Extension:TextExtracts
-
- - :meth:`page.BasePage.extract`.
+ - :ext:`TextExtracts`
+ - :meth:`page.BasePage.extract`
"""
if not page.exists():
raise NoPageError(page)
diff --git a/scripts/coordinate_import.py b/scripts/coordinate_import.py
index ed97b48..e71c9ac 100755
--- a/scripts/coordinate_import.py
+++ b/scripts/coordinate_import.py
@@ -14,10 +14,9 @@
This will work on all pages in the category "coordinates not on Wikidata"
and will import the coordinates on these pages to Wikidata.
-The data from the "GeoData" extension
-(https://www.mediawiki.org/wiki/Extension:GeoData)
-is used so that extension has to be setup properly. You can look at the
-[[Special:Nearby]] page on your local Wiki to see if it's populated.
+The data from the :ext:`"GeoData" extension<GeoData>` is used so that
+extension has to be setup properly. You can look at the [[Special:Nearby]]
+page on your local Wiki to see if it's populated.
You can use any typical pagegenerator to provide with a list of pages:
diff --git a/scripts/illustrate_wikidata.py b/scripts/illustrate_wikidata.py
index 8bfd71a..6a36693 100755
--- a/scripts/illustrate_wikidata.py
+++ b/scripts/illustrate_wikidata.py
@@ -7,9 +7,7 @@
"""Bot to add images to Wikidata items.
The image is extracted from the page_props. For this to be available the
-PageImages extension
-(https://www.mediawiki.org/wiki/Extension:PageImages) needs to be
-installed.
+:ext:`PageImages extension<PageImages>` needs to be installed.
The following options are provided:
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1316008?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ie9878a9c28926733fd33b5eb1b5fd4ddba0ea649
Gerrit-Change-Number: 1316008
Gerrit-PatchSet: 2
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1315873?usp=email )
Change subject: docs: improve tests package documentation
......................................................................
docs: improve tests package documentation
Change-Id: I2101eaa3db8686bad54eaefd52a67d1dd696c555
---
M docs/tests_ref/aspects.rst
M docs/tests_ref/basepage.rst
M docs/tests_ref/index.rst
M docs/tests_ref/precommit.rst
M docs/tests_ref/pytest.rst
A docs/tests_ref/tests.rst
M docs/tests_ref/utils.rst
M tests/README.rst
M tests/__init__.py
9 files changed, 211 insertions(+), 49 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/docs/tests_ref/aspects.rst b/docs/tests_ref/aspects.rst
index 948faf6..7acdf29 100644
--- a/docs/tests_ref/aspects.rst
+++ b/docs/tests_ref/aspects.rst
@@ -1,8 +1,9 @@
-********************
-tests.aspects module
-********************
+***********************************************
+:mod:`tests.aspects` --- Test behaviour aspects
+***********************************************
.. automodule:: tests.aspects
+ :synopsis: Reusable test behaviour aspects for the Pywikibot test suite.
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/tests_ref/basepage.rst b/docs/tests_ref/basepage.rst
index 97e2d09..463ab40 100644
--- a/docs/tests_ref/basepage.rst
+++ b/docs/tests_ref/basepage.rst
@@ -1,8 +1,9 @@
-*********************
-tests.basepage module
-*********************
+***********************************************
+:mod:`tests.basepage` --- BasePage test helpers
+***********************************************
.. automodule:: tests.basepage
+ :synopsis: BasePage tests subclasses
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/tests_ref/index.rst b/docs/tests_ref/index.rst
index 2d4eefc..750b95f 100644
--- a/docs/tests_ref/index.rst
+++ b/docs/tests_ref/index.rst
@@ -12,6 +12,7 @@
.. toctree::
:titlesonly:
+ tests
aspects
basepage
utils
diff --git a/docs/tests_ref/precommit.rst b/docs/tests_ref/precommit.rst
index 1fb5769..8c1e820 100644
--- a/docs/tests_ref/precommit.rst
+++ b/docs/tests_ref/precommit.rst
@@ -1,8 +1,9 @@
-**********************
-precommit hooks module
-**********************
+***************************************
+:mod:`tests.hooks` --- Pre-commit hooks
+***************************************
.. automodule:: tests.hooks.copyright_fixer
+ :synopsis: Check and update copyright headers in Pywikibot source files
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/tests_ref/pytest.rst b/docs/tests_ref/pytest.rst
index 5d062af..b965fc9 100644
--- a/docs/tests_ref/pytest.rst
+++ b/docs/tests_ref/pytest.rst
@@ -1,8 +1,9 @@
-********************
-pytest plugin module
-********************
+****************************************
+:mod:`conftest` --- Pytest plugin module
+****************************************
.. automodule:: conftest
+ :synopsis: Pytest fixtures and hooks integrating the Pywikibot test suite with pytest
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/tests_ref/tests.rst b/docs/tests_ref/tests.rst
new file mode 100644
index 0000000..7057dd3
--- /dev/null
+++ b/docs/tests_ref/tests.rst
@@ -0,0 +1,9 @@
+*****************************************
+:mod:`tests` --- Core test infrastructure
+*****************************************
+
+.. automodule:: tests
+ :synopsis: Core infrastructure for running and organizing the Pywikibot test suite
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/tests_ref/utils.rst b/docs/tests_ref/utils.rst
index 72b7900..55c0e23 100644
--- a/docs/tests_ref/utils.rst
+++ b/docs/tests_ref/utils.rst
@@ -1,8 +1,9 @@
-******************
-tests.utils module
-******************
+*************************************
+:mod:`tests.utils` --- Test utilities
+*************************************
.. automodule:: tests.utils
+ :synopsis: Test utility funktions
:members:
:undoc-members:
:show-inheritance:
diff --git a/tests/README.rst b/tests/README.rst
index d5bd42a..905c1ae 100644
--- a/tests/README.rst
+++ b/tests/README.rst
@@ -5,8 +5,8 @@
The Pywikibot tests are based on the `unittest framework
<https://docs.python.org/3/library/unittest.html>`_.
-The tests package provides a function load_tests that supports the
-`load tests protocol
+The tests package provides a function :func:`tests.load_tests` that supports
+the `load tests protocol
<https://docs.python.org/3/library/unittest.html#load-tests-protocol>`_.
The default ordering begins with tests of underlying components, then tests
site and page semantics, and finishes with tests of the scripts and finally
@@ -30,7 +30,7 @@
**pytest**
-.. note:: Python 3.10 or higher is required to run pytest.
+.. note:: Running the test suite with pytest requires Python 3.10 or higher.
::
@@ -110,17 +110,17 @@
PYWIKIBOT_TEST_NO_RC=1
**PYWIKIBOT_TEST_OAUTH**
- This environment variable holds the Oauth token. It is set by
+ This environment variable holds the OAuth token. It is set by
``oauth_tests-ci.yml`` CI config file and is solely used by
:source:`tests/oauth_tests`. You can use it for your private tests. The
environment variable must contain consumer key and secret and access
key and secret delimited by ``:`` as::
- PYWIKIBOT_TEST_OAUTH=consumer_key:consumer_secret:access_key:access:secret
+ PYWIKIBOT_TEST_OAUTH=consumer_key:consumer_secret:access_key:access_secret
**PYWIKIBOT_TEST_QUIET**
- This environment variable can be set for quit mode. It prevents output by
- test package, i.e. 'max_retries reduced from x to y'. It is used be the
+ This environment variable can be set for quiet mode. It prevents output by
+ test package, i.e. 'max_retries reduced from x to y'. It is used by the
:func:`tests.utils.execute` test runner. To enable it for other tests use::
PYWIKIBOT_TEST_QUIET=1
@@ -230,33 +230,44 @@
def test_patch(self):
self.assertEqual('pong', http_ping())
+
Contributing tests
==================
-Test modules should be named according to the pywikibot that is being tested.
-e.g. the module pywikibot.page is tested by tests.page_tests.
+The test package distinguishes between framework tests, which cover Pywikibot
+framework components, and script tests, which cover individual Pywikibot
+scripts.
-New test classes should be added to the existing test modules unless it
-tests a new component of pywikibot.
+Test modules should be named according to the Pywikibot component being
+tested. For example, the module :mod:`pywikibot.page` is tested by
+:source:`tests/page_tests`.
-All test classes must be a subclass of tests.aspects.TestCase, which uses a
-metaclass to dynamically check the test can be run on a specified site, or
-run a test on multiple sites.
+New test classes should be added to the existing test modules unless they
+test a new component of Pywikibot.
+
+All test classes must be a subclass of :class:`TestCase
+<tests.aspects.TestCase>`. Its metaclass validates the declared test environment
+and dynamically creates the required site objects. Tests can declare a specific
+site, multiple sites, or other behaviour attributes as described in
+:ref:`Test behaviour attributes`.
+
Test sites
----------
-If a test depends on a specific site, add class attributes 'family' and code'.
+If a test depends on a specific site, add the class attributes ``family``
+and ``code``:
::
family = 'wikipedia'
code = 'en'
-Once declared, the Site object can be accessed at self.site.
+Once declared, the Site object is available as ``self.site``.
-If a test requires multiple specific sites, add a class attribute 'sites'.
+If a test requires multiple specific sites, define the ``sites`` class
+attribute. Each key becomes a separate test variant.
::
@@ -271,30 +282,139 @@
}
}
-To obtain the Site object, call self.get_site with the key given to the site.
+To obtain the Site object, call :meth:`get_site<tests.TestCase.get_site>`
+with the key given to the site:
::
self.get_site('itwikt')
-For tests which require network access to a website which is not an APISite,
-the class attribute 'sites' may include a hostname.
+If a test method accepts the site key as its second positional argument,
+the metaclass creates one test for each entry in ``sites`` and passes the
+corresponding key to the test method:
+
+::
+
+ def test_something(self, site_key):
+ site = self.get_site(site_key)
+
+For tests which require network access to a host which is not a MediaWiki
+API site, the class attribute 'sites' may include a hostname:
::
sites = {
- 'wdq':
+ 'wdq': {
'hostname': 'query.wikidata.org',
}
}
+If no API site is used and only hosts are require, you may define
+``hostname`` or ``hostnames``:
-Other class attributes
-----------------------
+::
-- ``net = False``: test class does not use a site
-- ``dry = True``: test class can use a fake site object
-- ``cached = True``: test class may aggressively cache API responses
-- ``login = True``: test class needs to login to site
-- ``rights = '<rights>'``: test class needs specific rights. Multiple rights must be delimited with ``,``.
-- ``write = True``: test class needs to write to a site
+ hostname = 'query.wikidata.org'
+
+or:
+
+::
+
+ hostnames = [
+ 'query.wikidata.org',
+ 'example.org',
+ ]
+
+The hosts are added to the test site's definitions and checked for network
+availability.
+
+
+Test behaviour attributes
+-------------------------
+
+The following class attributes control the behaviour of a test class.
+Attributes which enable additional functionality are normally set to
+``True``. Attributes which are not set keep their default behaviour.
+
+Some attributes implicitly enable additional behaviour or add mixins to
+the test class.
+
+
+Caching
+~~~~~~~
+
+``cached = True``
+ The test class may aggressively cache API responses. This adds
+ :class:`ForceCacheMixin<tests.aspects.ForceCacheMixin>`. ``cached``
+ is intended for read-only tests and must not be combined with
+ ``write = True``.
+
+
+Network access
+~~~~~~~~~~~~~~
+
+``net = True``
+ The test class explicitly requires network access.
+
+``net = False``
+ The test class explicitly declares that no network access is used.
+
+ Test classes which do not use a site must explicitly define ``net``.
+
+``site = False``
+ The test class does not use a Site object. This adds
+ :class:`DisableSiteMixin<tests.aspects.DisableSiteMixin>` and prevents
+ calls to :func:`pywikibot.Site`. ``site = False`` is commonly combined
+ with ``net = False`` for tests which do not access a site or the network.
+
+Disconnected site tests
+~~~~~~~~~~~~~~~~~~~~~~~
+
+``dry = True``
+ The test class uses disconnected Site objects instead of accessing real
+ sites. This adds :class:`DisconnectedSiteMixin
+ <tests.aspects.DisconnectedSiteMixin>`. ``dry`` implicitly disables
+ network access (equivalent to ``net = False``).
+
+
+Authentication
+~~~~~~~~~~~~~~
+
+``login = True``
+ The test class requires authentication on the configured site. This
+ adds :class:`RequireLoginMixin<tests.aspects.RequireLoginMixin>`.
+
+``oauth = True``
+ The test class uses OAuth authentication when authentication is required.
+
+``rights = '<rights>'``
+ The test class requires specific user rights. Multiple rights must be
+ separated by commas. Setting ``rights`` implicitly enables ``login = True``
+ and adds :class:`NeedRightsMixin<tests.aspects.NeedRightsMixin>`.
+
+
+Writing tests
+~~~~~~~~~~~~~
+
+``write = True``
+ The test class performs write operations on a site. This adds
+ :class:`SiteWriteMixin<tests.aspects.SiteWriteMixin>`. Setting ``write``
+ implicitly enables ``login = True``. Write tests require explicit enabling
+ through the test environment ``PYWIKIBOT_TEST_WRITE``.
+
+
+Script execution
+~~~~~~~~~~~~~~~~
+
+``pwb = True``
+ The test class invokes scripts through :mod:`pwb`. Test classes using
+ ``pwb`` normally require a configured site. If a ``pwb`` test does not
+ use a site, it must explicitly define ``site = False``.
+
+
+Wikibase tests
+~~~~~~~~~~~~~~
+
+``wikibase = True``
+ The test class requires sites with a Wikibase data repository. This
+ is used by :class:`WikibaseTestCase<tests.aspects.WikibaseTestCase>`.
diff --git a/tests/__init__.py b/tests/__init__.py
index 851a402..c84212e 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -3,15 +3,38 @@
#
# Distributed under the terms of the MIT license.
#
-"""Package tests."""
+"""Core infrastructure for the Pywikibot test suite.
+
+This module defines the main groups of test modules and implements the
+`unittest load tests protocol
+<https://docs.python.org/3/library/unittest.html#load-tests-protocol>`_.
+It controls the order in which test modules are loaded and provides the
+entry point used by the test runner.
+
+It also provides helpers for locating test data paths and for controlling
+API request caching during tests.
+
+The test modules are grouped into library tests, which cover Pywikibot
+library components, and script tests, which cover Pywikibot scripts. The
+corresponding module collections are available as
+:data:`library_test_modules` and :data:`script_test_modules`.
+
+Shared test infrastructure such as test case classes and reusable test
+components is implemented in :mod:`tests.aspects`, :mod:`tests.basepage`,
+and :mod:`tests.utils`.
+
+For information about running tests, writing new tests, and available test
+options, see :ref:`Pywikibot tests`.
+"""
from __future__ import annotations
__all__ = (
- 'create_path_func', 'join_cache_path', 'join_data_path',
- 'join_html_data_path', 'join_images_path', 'join_pages_path',
- 'join_root_path', 'join_xml_data_path', 'patch_request', 'unittest_print',
- 'unpatch_request',
+ 'TestRequest', 'create_path_func', 'collector', 'join_cache_path',
+ 'join_data_path', 'join_html_data_path', 'join_images_path',
+ 'join_pages_path', 'join_root_path', 'join_xml_data_path',
+ 'library_test_modules', 'load_tests', 'patch_request',
+ 'script_test_modules', 'unittest_print', 'unpatch_request',
)
import functools
@@ -65,6 +88,8 @@
# Find the root directory of the checkout
_pwb_py = join_root_path('pwb.py')
+#: Names of test modules covering Pywikibot framework components.
+#: The corresponding test files end with ``_tests.py``.
library_test_modules = {
'api',
'basesite',
@@ -143,6 +168,8 @@
'xmlreader'
}
+#: Names of test modules covering Pywikibot scripts.
+#: The corresponding test files end with ``_tests.py``.
script_test_modules = {
'add_text',
'archivebot',
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1315873?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I2101eaa3db8686bad54eaefd52a67d1dd696c555
Gerrit-Change-Number: 1315873
Gerrit-PatchSet: 4
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot