Xqt has submitted this change. ( 
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/811261 )

Change subject: [IMPR] Move time parts from archivebot to time module
......................................................................

[IMPR] Move time parts from archivebot to time module

Change-Id: I612e7c39a8bd03cd7cffe788137e5aae213fa9aa
---
M pywikibot/time_.py
2 files changed, 263 insertions(+), 266 deletions(-)

Approvals:
  Xqt: Verified; Looks good to me, approved



diff --git a/pywikibot/time_.py b/pywikibot/time_.py
index c57c2d2..4a495ff 100644
--- a/pywikibot/time_.py
+++ b/pywikibot/time_.py
@@ -1,4 +1,266 @@
-<<<<<<< HEAD   (4a0216 [IMPR] move archivebot time parts to time module (part 
1))
+"""Time handling module."""
+#
+# (C) Pywikibot team, 2009-2022
+#
+# Distributed under the terms of the MIT license.
+#
+import datetime
+import re
+from typing import Type, Union
+
+from pywikibot.tools import classproperty
+
+__all__ = ['Timestamp']
+
+
+class Timestamp(datetime.datetime):
+
+    """Class for handling MediaWiki timestamps.
+
+    This inherits from datetime.datetime, so it can use all of the methods
+    and operations of a datetime object. To ensure that the results of any
+    operation are also a Timestamp object, be sure to use only Timestamp
+    objects (and datetime.timedeltas) in any operation.
+
+    Use Timestamp.fromISOformat() and Timestamp.fromtimestampformat() to
+    create Timestamp objects from MediaWiki string formats.
+    As these constructors are typically used to create objects using data
+    passed provided by site and page methods, some of which return a Timestamp
+    when previously they returned a MediaWiki string representation, these
+    methods also accept a Timestamp object, in which case they return a clone.
+
+    Alternatively, Timestamp.set_timestamp() can create Timestamp objects from
+    Timestamp, datetime.datetime object, or strings compliant with ISO8601,
+    MW, or POSIX formats.
+
+    Use Site.server_time() for the current time; this is more reliable
+    than using Timestamp.utcnow().
+    """
+
+    mediawikiTSFormat = '%Y%m%d%H%M%S'  # noqa: N815
+    _ISO8601Format_new = '{0:+05d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}Z'
+
+    @classmethod
+    def set_timestamp(cls: Type['Timestamp'],
+                      ts: Union[str, datetime.datetime, 'Timestamp']
+                      ) -> 'Timestamp':
+        """Set Timestamp from input object.
+
+        ts is converted to a datetime naive object representing UTC time.
+        String shall be compliant with:
+        - Mediwiki timestamp format: YYYYMMDDHHMMSS
+        - ISO8601 format: YYYY-MM-DD[T ]HH:MM:SS[Z|±HH[MM[SS[.ffffff]]]]
+        - POSIX format: seconds from Unix epoch S{1,13}[.ffffff]]
+
+        :param ts: Timestamp, datetime.datetime or str
+        :return: Timestamp object
+        :raises ValuError: conversion failed
+        """
+        if isinstance(ts, cls):
+            return ts
+        if isinstance(ts, datetime.datetime):
+            return cls._from_datetime(ts)
+        if isinstance(ts, str):
+            return cls._from_string(ts)
+
+    @staticmethod
+    def _from_datetime(dt: datetime.datetime) -> 'Timestamp':
+        """Convert a datetime.datetime timestamp to a Timestamp object."""
+        return Timestamp(dt.year, dt.month, dt.day, dt.hour,
+                         dt.minute, dt.second, dt.microsecond,
+                         dt.tzinfo)
+
+    @classmethod
+    def _from_mw(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
+        """Convert a string in MW format to a Timestamp object.
+
+        Mediwiki timestamp format: YYYYMMDDHHMMSS
+        """
+        RE_MW = r'\d{14}$'  # noqa: N806
+        m = re.match(RE_MW, timestr)
+
+        if not m:
+            msg = "time data '{timestr}' does not match MW format."
+            raise ValueError(msg.format(timestr=timestr))
+
+        return cls.strptime(timestr, cls.mediawikiTSFormat)
+
+    @classmethod
+    def _from_iso8601(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
+        """Convert a string in ISO8601 format to a Timestamp object.
+
+        ISO8601 format:
+        - YYYY-MM-DD[T ]HH:MM:SS[[.,]ffffff][Z|±HH[MM[SS[.ffffff]]]]
+        """
+        RE_ISO8601 = (r'(?:\d{4}-\d{2}-\d{2})(?P<sep>[T ])'  # noqa: N806
+                      r'(?:\d{2}:\d{2}:\d{2})(?P<u>[.,]\d{1,6})?'
+                      r'(?P<tz>Z|[+\-]\d{2}:?\d{,2})?$'
+                      )
+        m = re.match(RE_ISO8601, timestr)
+
+        if not m:
+            msg = "time data '{timestr}' does not match ISO8601 format."
+            raise ValueError(msg.format(timestr=timestr))
+
+        strpfmt = '%Y-%m-%d{sep}%H:%M:%S'.format(sep=m.group('sep'))
+        strpstr = timestr[:19]
+
+        if m.group('u'):
+            strpfmt += '.%f'
+            strpstr += m.group('u').replace(',', '.')  # .ljust(7, '0')
+
+        if m.group('tz'):
+            if m.group('tz') == 'Z':
+                strpfmt += 'Z'
+                strpstr += 'Z'
+            else:
+                strpfmt += '%z'
+                # strptime wants HHMM, without ':'
+                strpstr += (m.group('tz').replace(':', '')).ljust(5, '0')
+
+        ts = cls.strptime(strpstr, strpfmt)
+        if ts.tzinfo is not None:
+            ts = ts.astimezone(datetime.timezone.utc).replace(tzinfo=None)
+            # why pytest in py35/py37 fails without this?
+            ts = cls._from_datetime(ts)
+
+        return ts
+
+    @classmethod
+    def _from_posix(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
+        """Convert a string in POSIX format to a Timestamp object.
+
+        POSIX format: SECONDS[.ffffff]]
+        """
+        RE_POSIX = r'(?P<S>-?\d{1,13})(?:\.(?P<u>\d{1,6}))?$'  # noqa: N806
+        m = re.match(RE_POSIX, timestr)
+
+        if not m:
+            msg = "time data '{timestr}' does not match POSIX format."
+            raise ValueError(msg.format(timestr=timestr))
+
+        sec = int(m.group('S'))
+        usec = m.group('u')
+        usec = int(usec.ljust(6, '0')) if usec else 0
+        if sec < 0 and usec > 0:
+            sec = sec - 1
+            usec = 1000000 - usec
+
+        ts = (cls(1970, 1, 1)
+              + datetime.timedelta(seconds=sec, microseconds=usec))
+        return ts
+
+    @classmethod
+    def _from_string(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
+        """Convert a string to a Timestamp object."""
+        handlers = [
+            cls._from_mw,
+            cls._from_iso8601,
+            cls._from_posix,
+        ]
+
+        for handler in handlers:
+            try:
+                return handler(timestr)
+            except ValueError:
+                continue
+
+        msg = "time data '{timestr}' does not match any format."
+        raise ValueError(msg.format(timestr=timestr))
+
+    def clone(self) -> datetime.datetime:
+        """Clone this instance."""
+        return self.replace(microsecond=self.microsecond)
+
+    @classproperty
+    def ISO8601Format(cls: Type['Timestamp']) -> str:  # noqa: N802
+        """ISO8601 format string class property for compatibility purpose."""
+        return cls._ISO8601Format()
+
+    @classmethod
+    def _ISO8601Format(cls: Type['Timestamp'],  # noqa: N802
+                       sep: str = 'T') -> str:
+        """ISO8601 format string.
+
+        :param sep: one-character separator, placed between the date and time
+        :return: ISO8601 format string
+        """
+        assert len(sep) == 1
+        return '%Y-%m-%d{}%H:%M:%SZ'.format(sep)
+
+    @classmethod
+    def fromISOformat(cls: Type['Timestamp'],  # noqa: N802
+                      ts: Union[str, 'Timestamp'],
+                      sep: str = 'T') -> 'Timestamp':
+        """Convert an ISO 8601 timestamp to a Timestamp object.
+
+        :param ts: ISO 8601 timestamp or a Timestamp object already
+        :param sep: one-character separator, placed between the date and time
+        :return: Timestamp object
+        """
+        # If inadvertently passed a Timestamp object, use replace()
+        # to create a clone.
+        if isinstance(ts, cls):
+            return ts.clone()
+        _ts = '{pre}{sep}{post}'.format(pre=ts[:10], sep=sep, post=ts[11:])
+        return cls._from_iso8601(_ts)
+
+    @classmethod
+    def fromtimestampformat(cls: Type['Timestamp'], ts: Union[str, 'Timestamp']
+                            ) -> 'Timestamp':
+        """Convert a MediaWiki internal timestamp to a Timestamp object."""
+        # If inadvertently passed a Timestamp object, use replace()
+        # to create a clone.
+        if isinstance(ts, cls):
+            return ts.clone()
+        if len(ts) == 8:  # year, month and day are given only
+            ts += '000000'
+        return cls._from_mw(ts)
+
+    def isoformat(self, sep: str = 'T') -> str:  # type: ignore[override]
+        """
+        Convert object to an ISO 8601 timestamp accepted by MediaWiki.
+
+        datetime.datetime.isoformat does not postfix the ISO formatted date
+        with a 'Z' unless a timezone is included, which causes MediaWiki
+        ~1.19 and earlier to fail.
+        """
+        return self.strftime(self._ISO8601Format(sep))
+
+    def totimestampformat(self) -> str:
+        """Convert object to a MediaWiki internal timestamp."""
+        return self.strftime(self.mediawikiTSFormat)
+
+    def posix_timestamp(self) -> float:
+        """
+        Convert object to a POSIX timestamp.
+
+        See Note in datetime.timestamp().
+        """
+        return self.replace(tzinfo=datetime.timezone.utc).timestamp()
+
+    def posix_timestamp_format(self) -> str:
+        """Convert object to a POSIX timestamp format."""
+        return '{ts:.6f}'.format(ts=self.posix_timestamp())
+
+    def __str__(self) -> str:
+        """Return a string format recognized by the API."""
+        return self.isoformat()
+
+    def __add__(self, other: datetime.timedelta) -> 'Timestamp':
+        """Perform addition, returning a Timestamp instead of datetime."""
+        newdt = super().__add__(other)
+        if isinstance(newdt, datetime.datetime):
+            return self._from_datetime(newdt)
+        return newdt
+
+    def __sub__(self, other: datetime.timedelta  # type: ignore[override]
+                ) -> 'Timestamp':
+        """Perform subtraction, returning a Timestamp instead of datetime."""
+        newdt = super().__sub__(other)
+        if isinstance(newdt, datetime.datetime):
+            return self._from_datetime(newdt)
+        return newdt
 #!/usr/bin/python3
 """
 archivebot.py - discussion page archiving bot.
@@ -913,268 +1175,3 @@

 if __name__ == '__main__':
     main()
-=======
-"""Time handling module."""
-#
-# (C) Pywikibot team, 2009-2022
-#
-# Distributed under the terms of the MIT license.
-#
-import datetime
-import re
-from typing import Type, Union
-
-from pywikibot.tools import classproperty
-
-__all__ = ['Timestamp']
-
-
-class Timestamp(datetime.datetime):
-
-    """Class for handling MediaWiki timestamps.
-
-    This inherits from datetime.datetime, so it can use all of the methods
-    and operations of a datetime object. To ensure that the results of any
-    operation are also a Timestamp object, be sure to use only Timestamp
-    objects (and datetime.timedeltas) in any operation.
-
-    Use Timestamp.fromISOformat() and Timestamp.fromtimestampformat() to
-    create Timestamp objects from MediaWiki string formats.
-    As these constructors are typically used to create objects using data
-    passed provided by site and page methods, some of which return a Timestamp
-    when previously they returned a MediaWiki string representation, these
-    methods also accept a Timestamp object, in which case they return a clone.
-
-    Alternatively, Timestamp.set_timestamp() can create Timestamp objects from
-    Timestamp, datetime.datetime object, or strings compliant with ISO8601,
-    MW, or POSIX formats.
-
-    Use Site.server_time() for the current time; this is more reliable
-    than using Timestamp.utcnow().
-    """
-
-    mediawikiTSFormat = '%Y%m%d%H%M%S'  # noqa: N815
-    _ISO8601Format_new = '{0:+05d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}Z'
-
-    @classmethod
-    def set_timestamp(cls: Type['Timestamp'],
-                      ts: Union[str, datetime.datetime, 'Timestamp']
-                      ) -> 'Timestamp':
-        """Set Timestamp from input object.
-
-        ts is converted to a datetime naive object representing UTC time.
-        String shall be compliant with:
-        - Mediwiki timestamp format: YYYYMMDDHHMMSS
-        - ISO8601 format: YYYY-MM-DD[T ]HH:MM:SS[Z|±HH[MM[SS[.ffffff]]]]
-        - POSIX format: seconds from Unix epoch S{1,13}[.ffffff]]
-
-        :param ts: Timestamp, datetime.datetime or str
-        :return: Timestamp object
-        :raises ValuError: conversion failed
-        """
-        if isinstance(ts, cls):
-            return ts
-        if isinstance(ts, datetime.datetime):
-            return cls._from_datetime(ts)
-        if isinstance(ts, str):
-            return cls._from_string(ts)
-
-    @staticmethod
-    def _from_datetime(dt: datetime.datetime) -> 'Timestamp':
-        """Convert a datetime.datetime timestamp to a Timestamp object."""
-        return Timestamp(dt.year, dt.month, dt.day, dt.hour,
-                         dt.minute, dt.second, dt.microsecond,
-                         dt.tzinfo)
-
-    @classmethod
-    def _from_mw(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
-        """Convert a string in MW format to a Timestamp object.
-
-        Mediwiki timestamp format: YYYYMMDDHHMMSS
-        """
-        RE_MW = r'\d{14}$'  # noqa: N806
-        m = re.match(RE_MW, timestr)
-
-        if not m:
-            msg = "time data '{timestr}' does not match MW format."
-            raise ValueError(msg.format(timestr=timestr))
-
-        return cls.strptime(timestr, cls.mediawikiTSFormat)
-
-    @classmethod
-    def _from_iso8601(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
-        """Convert a string in ISO8601 format to a Timestamp object.
-
-        ISO8601 format:
-        - YYYY-MM-DD[T ]HH:MM:SS[[.,]ffffff][Z|±HH[MM[SS[.ffffff]]]]
-        """
-        RE_ISO8601 = (r'(?:\d{4}-\d{2}-\d{2})(?P<sep>[T ])'  # noqa: N806
-                      r'(?:\d{2}:\d{2}:\d{2})(?P<u>[.,]\d{1,6})?'
-                      r'(?P<tz>Z|[+\-]\d{2}:?\d{,2})?$'
-                      )
-        m = re.match(RE_ISO8601, timestr)
-
-        if not m:
-            msg = "time data '{timestr}' does not match ISO8601 format."
-            raise ValueError(msg.format(timestr=timestr))
-
-        strpfmt = '%Y-%m-%d{sep}%H:%M:%S'.format(sep=m.group('sep'))
-        strpstr = timestr[:19]
-
-        if m.group('u'):
-            strpfmt += '.%f'
-            strpstr += m.group('u').replace(',', '.')  # .ljust(7, '0')
-
-        if m.group('tz'):
-            if m.group('tz') == 'Z':
-                strpfmt += 'Z'
-                strpstr += 'Z'
-            else:
-                strpfmt += '%z'
-                # strptime wants HHMM, without ':'
-                strpstr += (m.group('tz').replace(':', '')).ljust(5, '0')
-
-        ts = cls.strptime(strpstr, strpfmt)
-        if ts.tzinfo is not None:
-            ts = ts.astimezone(datetime.timezone.utc).replace(tzinfo=None)
-            # why pytest in py35/py37 fails without this?
-            ts = cls._from_datetime(ts)
-
-        return ts
-
-    @classmethod
-    def _from_posix(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
-        """Convert a string in POSIX format to a Timestamp object.
-
-        POSIX format: SECONDS[.ffffff]]
-        """
-        RE_POSIX = r'(?P<S>-?\d{1,13})(?:\.(?P<u>\d{1,6}))?$'  # noqa: N806
-        m = re.match(RE_POSIX, timestr)
-
-        if not m:
-            msg = "time data '{timestr}' does not match POSIX format."
-            raise ValueError(msg.format(timestr=timestr))
-
-        sec = int(m.group('S'))
-        usec = m.group('u')
-        usec = int(usec.ljust(6, '0')) if usec else 0
-        if sec < 0 and usec > 0:
-            sec = sec - 1
-            usec = 1000000 - usec
-
-        ts = (cls(1970, 1, 1)
-              + datetime.timedelta(seconds=sec, microseconds=usec))
-        return ts
-
-    @classmethod
-    def _from_string(cls: Type['Timestamp'], timestr: str) -> 'Timestamp':
-        """Convert a string to a Timestamp object."""
-        handlers = [
-            cls._from_mw,
-            cls._from_iso8601,
-            cls._from_posix,
-        ]
-
-        for handler in handlers:
-            try:
-                return handler(timestr)
-            except ValueError:
-                continue
-
-        msg = "time data '{timestr}' does not match any format."
-        raise ValueError(msg.format(timestr=timestr))
-
-    def clone(self) -> datetime.datetime:
-        """Clone this instance."""
-        return self.replace(microsecond=self.microsecond)
-
-    @classproperty
-    def ISO8601Format(cls: Type['Timestamp']) -> str:  # noqa: N802
-        """ISO8601 format string class property for compatibility purpose."""
-        return cls._ISO8601Format()
-
-    @classmethod
-    def _ISO8601Format(cls: Type['Timestamp'],  # noqa: N802
-                       sep: str = 'T') -> str:
-        """ISO8601 format string.
-
-        :param sep: one-character separator, placed between the date and time
-        :return: ISO8601 format string
-        """
-        assert len(sep) == 1
-        return '%Y-%m-%d{}%H:%M:%SZ'.format(sep)
-
-    @classmethod
-    def fromISOformat(cls: Type['Timestamp'],  # noqa: N802
-                      ts: Union[str, 'Timestamp'],
-                      sep: str = 'T') -> 'Timestamp':
-        """Convert an ISO 8601 timestamp to a Timestamp object.
-
-        :param ts: ISO 8601 timestamp or a Timestamp object already
-        :param sep: one-character separator, placed between the date and time
-        :return: Timestamp object
-        """
-        # If inadvertently passed a Timestamp object, use replace()
-        # to create a clone.
-        if isinstance(ts, cls):
-            return ts.clone()
-        _ts = '{pre}{sep}{post}'.format(pre=ts[:10], sep=sep, post=ts[11:])
-        return cls._from_iso8601(_ts)
-
-    @classmethod
-    def fromtimestampformat(cls: Type['Timestamp'], ts: Union[str, 'Timestamp']
-                            ) -> 'Timestamp':
-        """Convert a MediaWiki internal timestamp to a Timestamp object."""
-        # If inadvertently passed a Timestamp object, use replace()
-        # to create a clone.
-        if isinstance(ts, cls):
-            return ts.clone()
-        if len(ts) == 8:  # year, month and day are given only
-            ts += '000000'
-        return cls._from_mw(ts)
-
-    def isoformat(self, sep: str = 'T') -> str:  # type: ignore[override]
-        """
-        Convert object to an ISO 8601 timestamp accepted by MediaWiki.
-
-        datetime.datetime.isoformat does not postfix the ISO formatted date
-        with a 'Z' unless a timezone is included, which causes MediaWiki
-        ~1.19 and earlier to fail.
-        """
-        return self.strftime(self._ISO8601Format(sep))
-
-    def totimestampformat(self) -> str:
-        """Convert object to a MediaWiki internal timestamp."""
-        return self.strftime(self.mediawikiTSFormat)
-
-    def posix_timestamp(self) -> float:
-        """
-        Convert object to a POSIX timestamp.
-
-        See Note in datetime.timestamp().
-        """
-        return self.replace(tzinfo=datetime.timezone.utc).timestamp()
-
-    def posix_timestamp_format(self) -> str:
-        """Convert object to a POSIX timestamp format."""
-        return '{ts:.6f}'.format(ts=self.posix_timestamp())
-
-    def __str__(self) -> str:
-        """Return a string format recognized by the API."""
-        return self.isoformat()
-
-    def __add__(self, other: datetime.timedelta) -> 'Timestamp':
-        """Perform addition, returning a Timestamp instead of datetime."""
-        newdt = super().__add__(other)
-        if isinstance(newdt, datetime.datetime):
-            return self._from_datetime(newdt)
-        return newdt
-
-    def __sub__(self, other: datetime.timedelta  # type: ignore[override]
-                ) -> 'Timestamp':
-        """Perform subtraction, returning a Timestamp instead of datetime."""
-        newdt = super().__sub__(other)
-        if isinstance(newdt, datetime.datetime):
-            return self._from_datetime(newdt)
-        return newdt
->>>>>>> BRANCH (1bd999 [IMPR] move archivebot time parts to time module (part 
1))

--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/811261
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.wikimedia.org/r/settings

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I612e7c39a8bd03cd7cffe788137e5aae213fa9aa
Gerrit-Change-Number: 811261
Gerrit-PatchSet: 1
Gerrit-Owner: Xqt <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to