jenkins-bot has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1166510?usp=email )

Change subject: [bugfix] use self.event_id instead of self.id for mark_as_read
......................................................................

[bugfix] use self.event_id instead of self.id for mark_as_read

- id was renamed to event_id in 203a05c and removed in release 7.0.0
  but the mark_as_read method wasn't updated accordingly. Use event_id
  now.
- use dataclass for the Notification to enable repr/str method
- update documentation
- update typing hints
- update mypy config

Bug: T398770
Change-Id: If5dca1d2d468068ea4f6a962dfa18afa84cb74e3
---
M .pre-commit-config.yaml
M conftest.py
M pywikibot/echo.py
M pywikibot/site/_extensions.py
4 files changed, 90 insertions(+), 24 deletions(-)

Approvals:
  Xqt: Looks good to me, approved
  jenkins-bot: Verified




diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2292fe2..02695fd 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -122,11 +122,11 @@
         # Test for files which already passed in past.
         # They should be also used in conftest.py to exclude them from 
non-voting mypy test.
         files: >
-          ^pywikibot/(__metadata__|exceptions|fixes|time)\.py$|
+          ^pywikibot/(__metadata__|echo|exceptions|fixes|time)\.py$|
           ^pywikibot/(comms|data|families|specialbots)/__init__\.py$|
           ^pywikibot/families/[a-z][a-z\d]+_family\.py$|
           ^pywikibot/page/(__init__|_decorators|_revision)\.py$|
           ^pywikibot/scripts/(?:i18n/)?__init__\.py$|
-          
^pywikibot/site/(__init__|_basesite|_decorators|_interwikimap|_upload)\.py$|
+          
^pywikibot/site/(__init__|_basesite|_decorators|_extensions|_interwikimap|_upload)\.py$|
           ^pywikibot/tools/(_logging|_unidata|formatter)\.py$|
           
^pywikibot/userinterfaces/(__init__|_interface_base|terminal_interface)\.py$
diff --git a/conftest.py b/conftest.py
index 3b00f67..830c04c 100644
--- a/conftest.py
+++ b/conftest.py
@@ -16,12 +16,12 @@

 EXCLUDE_PATTERN = re.compile(
     r'(?:'
-    r'(__metadata__|exceptions|fixes|time)|'
+    r'(__metadata__|echo|exceptions|fixes|time)|'
     r'(comms|data|families|specialbots)/__init__|'
     r'families/[a-z][a-z\d]+_family|'
     r'page/(__init__|_decorators|_revision)|'
     r'scripts/(i18n/)?__init__|'
-    r'site/(__init__|_basesite|_decorators|_interwikimap|_upload)|'
+    r'site/(__init__|_basesite|_decorators|_extensions|_interwikimap|_upload)|'
     r'tools/(_logging|_unidata|formatter)|'
     r'userinterfaces/(__init__|_interface_base|terminal_interface)'
     r')\.py'
diff --git a/pywikibot/echo.py b/pywikibot/echo.py
index bd135ed..2dcd683 100644
--- a/pywikibot/echo.py
+++ b/pywikibot/echo.py
@@ -1,31 +1,52 @@
 """Classes and functions for working with the Echo extension."""
 #
-# (C) Pywikibot team, 2014-2022
+# (C) Pywikibot team, 2014-2025
 #
 # Distributed under the terms of the MIT license.
 #
 from __future__ import annotations

+from dataclasses import dataclass
 from typing import Any

 import pywikibot


+@dataclass(eq=False)
 class Notification:

-    """A notification issued by the Echo extension."""
+    """A notification issued by the Echo extension.

-    def __init__(self, site: pywikibot.site.BaseSite) -> None:
-        """Initialize an empty Notification object."""
-        self.site = site
+    .. versionchanged:: 3.0.20190204
+       The ``id`` attribute was renamed to ``event_id``, and its type
+       changed from ``str`` to ``int``.

+    .. deprecated:: 3.0.20190204
+       The ``id`` attribute was retained temporarily for backward
+       compatibility, but is deprecated and scheduled for removal.
+
+    .. versionremoved:: 7.0
+       The ``id`` attribute was removed.
+
+    .. versionchanged:: 10.3
+       The class is now defined using the ``@dataclass`` decorator to
+       simplify internal initialization and improve maintainability.
+    """
+
+    site: pywikibot.site.BaseSite
+
+    def __post_init__(self) -> None:
+        """Initialize attributes for an empty Notification object.
+
+        .. versionadded: 10.3
+        """
         self.event_id: int | None = None
         self.type = None
         self.category = None
-        self.timestamp = None
-        self.page = None
-        self.agent = None
-        self.read: bool | None = None
+        self.timestamp: pywikibot.Timestamp | None = None
+        self.page: pywikibot.Page | None = None
+        self.agent: pywikibot.User | None = None
+        self.read: pywikibot.Timestamp | bool | None = None
         self.content = None
         self.revid = None

@@ -33,12 +54,19 @@
     def fromJSON(cls,  # noqa: N802
                  site: pywikibot.site.BaseSite,
                  data: dict[str, Any]) -> Notification:
-        """Construct a Notification object from our API's JSON data."""
+        """Construct a Notification object from API JSON data.
+
+        :param site: The pywikibot site object.
+        :param data: The JSON data dictionary representing a
+            notification.
+        :return: An instance of Notification.
+        """
         notif = cls(site)

         notif.event_id = int(data['id'])
         notif.type = data['type']
         notif.category = data['category']
+
         notif.timestamp = pywikibot.Timestamp.fromtimestampformat(
             data['timestamp']['mw'])

@@ -59,8 +87,16 @@

         notif.content = data.get('*')
         notif.revid = data.get('revid')
+
         return notif

     def mark_as_read(self) -> bool:
-        """Mark the notification as read."""
-        return self.site.notifications_mark_read(list=self.id)
+        """Mark the notification as read.
+
+        :return: True if the notification was successfully marked as
+            read, else False.
+        """
+        if self.event_id is None:
+            return False
+
+        return self.site.notifications_mark_read(**{'list': self.event_id})
diff --git a/pywikibot/site/_extensions.py b/pywikibot/site/_extensions.py
index 66ea1ff..e30f130 100644
--- a/pywikibot/site/_extensions.py
+++ b/pywikibot/site/_extensions.py
@@ -6,6 +6,8 @@
 #
 from __future__ import annotations

+from typing import TYPE_CHECKING, Protocol
+
 import pywikibot
 from pywikibot.data import api
 from pywikibot.echo import Notification
@@ -20,6 +22,34 @@
 from pywikibot.tools import merge_unique_dicts


+if TYPE_CHECKING:
+    from pywikibot.site import NamespacesDict
+
+
+class BaseSiteProtocol(Protocol):
+    _proofread_levels: dict[int, str]
+    tokens: dict[str, str]
+
+    def _generator(self, *args, **kwargs) -> api.Request:
+        ...
+
+    def _request(self, **kwargs) -> api.Request:
+        ...
+
+    def _update_page(self, *args, **kwargs) -> None:
+        ...
+
+    def encoding(self) -> str:
+        ...
+
+    @property
+    def namespaces(self, **kwargs) -> NamespacesDict:
+        ...
+
+    def simple_request(self, **kwargs) -> api.Request:
+        ...
+
+
 class EchoMixin:

     """APISite mixin for Echo extension."""
@@ -50,15 +80,13 @@
                 for notification in notifications)

     @need_extension('Echo')
-    def notifications_mark_read(self, **kwargs) -> bool:
+    def notifications_mark_read(self: BaseSiteProtocol, **kwargs) -> bool:
         """Mark selected notifications as read.

         .. seealso:: :api:`echomarkread`

         :return: whether the action was successful
         """
-        # TODO: ensure that the 'echomarkread' action
-        # is supported by the site
         kwargs = merge_unique_dicts(kwargs, action='echomarkread',
                                     token=self.tokens['csrf'])
         req = self.simple_request(**kwargs)
@@ -74,7 +102,7 @@
     """APISite mixin for ProofreadPage extension."""

     @need_extension('ProofreadPage')
-    def _cache_proofreadinfo(self, expiry=False) -> None:
+    def _cache_proofreadinfo(self: BaseSiteProtocol, expiry=False) -> None:
         """Retrieve proofreadinfo from site and cache response.

         Applicable only to sites with ProofreadPage extension installed.
@@ -142,7 +170,8 @@
         return self._proofread_levels

     @need_extension('ProofreadPage')
-    def loadpageurls(self, page: pywikibot.page.BasePage) -> None:
+    def loadpageurls(self: BaseSiteProtocol,
+                     page: pywikibot.page.BasePage) -> None:
         """Load URLs from api and store in page attributes.

         Load URLs to images for a given page in the "Page:" namespace.
@@ -169,7 +198,7 @@
     """APISite mixin for GeoData extension."""

     @need_extension('GeoData')
-    def loadcoordinfo(self, page) -> None:
+    def loadcoordinfo(self: BaseSiteProtocol, page) -> None:
         """Load [[mw:Extension:GeoData]] info."""
         title = page.title(with_section=False)
         query = self._generator(api.PropertyGenerator,
@@ -187,7 +216,7 @@
     """APISite mixin for PageImages extension."""

     @need_extension('PageImages')
-    def loadpageimage(self, page) -> None:
+    def loadpageimage(self: BaseSiteProtocol, page) -> None:
         """Load [[mw:Extension:PageImages]] info.

         :param page: The page for which to obtain the image
@@ -374,7 +403,8 @@
     """

     @need_extension('TextExtracts')
-    def extract(self, page: pywikibot.Page, *,
+    def extract(self: BaseSiteProtocol,
+                page: pywikibot.Page, *,
                 chars: int | None = None,
                 sentences: int | None = None,
                 intro: bool = True,

--
To view, visit 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1166510?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: If5dca1d2d468068ea4f6a962dfa18afa84cb74e3
Gerrit-Change-Number: 1166510
Gerrit-PatchSet: 12
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to