John Vandenberg has uploaded a new change for review. https://gerrit.wikimedia.org/r/175404
Change subject: Permissive Timestamp fromX methods ...................................................................... Permissive Timestamp fromX methods Several methods of site and page classes return a Timestamp where previously they returned a string which should be passed to the Timestamp class to create a Timestamp object. In order to improve compatibility with old versions of pywikibot, Timestamp should recognise it is being passed a Timestamp, and not try to parse it. Change-Id: Ifb850b3e52c0fb1b84f2da433f50cb142f854591 --- M pywikibot/__init__.py A tests/timestamp_tests.py 2 files changed, 106 insertions(+), 2 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core refs/changes/04/175404/1 diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index e20d7c4..d60e45e 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -112,6 +112,10 @@ 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. Use Site.getcurrenttime() for the current time; this is more reliable than using Timestamp.utcnow(). @@ -124,11 +128,19 @@ @classmethod def fromISOformat(cls, ts): """Convert an ISO 8601 timestamp to a Timestamp object.""" + # If inadvertantly passed a Timestamp object, use replace() + # to create a clone. + if isinstance(ts, cls): + return ts.replace(microsecond=ts.microsecond) return cls.strptime(ts, cls.ISO8601Format) @classmethod def fromtimestampformat(cls, ts): """Convert a MediaWiki internal timestamp to a Timestamp object.""" + # If inadvertantly passed a Timestamp object, use replace() + # to create a clone. + if isinstance(ts, cls): + return ts.replace(microsecond=ts.microsecond) return cls.strptime(ts, cls.mediawikiTSFormat) def toISOformat(self): @@ -144,7 +156,8 @@ return self.toISOformat() def __add__(self, other): - newdt = datetime.datetime.__add__(self, other) + """Perform addition, returning a Timestamp instead of datetime.""" + newdt = super(Timestamp, self).__add__(other) if isinstance(newdt, datetime.datetime): return Timestamp(newdt.year, newdt.month, newdt.day, newdt.hour, newdt.minute, newdt.second, newdt.microsecond, @@ -153,7 +166,8 @@ return newdt def __sub__(self, other): - newdt = datetime.datetime.__sub__(self, other) + """Perform substraction, returning a Timestamp instead of datetime.""" + newdt = super(Timestamp, self).__sub__(other) if isinstance(newdt, datetime.datetime): return Timestamp(newdt.year, newdt.month, newdt.day, newdt.hour, newdt.minute, newdt.second, newdt.microsecond, diff --git a/tests/timestamp_tests.py b/tests/timestamp_tests.py new file mode 100644 index 0000000..0018c01 --- /dev/null +++ b/tests/timestamp_tests.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +"""Tests for the Timestamp class.""" +# +# (C) Pywikibot team, 2014 +# +# Distributed under the terms of the MIT license. +# +__version__ = '$Id$' + +import datetime + +from pywikibot import Timestamp as T + +from tests.aspects import unittest, TestCase + + +class TestTimestamp(TestCase): + + """Test Timestamp class comparisons.""" + + net = False + + def test_instantiate_from_instance(self): + """Test passing instance to factory methods works.""" + t1 = T.utcnow() + self.assertIsNot(t1, T.fromISOformat(t1)) + self.assertEqual(t1, T.fromISOformat(t1)) + self.assertIsInstance(T.fromISOformat(t1), T) + self.assertIsNot(t1, T.fromtimestampformat(t1)) + self.assertEqual(t1, T.fromtimestampformat(t1)) + self.assertIsInstance(T.fromtimestampformat(t1), T) + + def test_iso_format(self): + t1 = T.utcnow() + ts1 = t1.toISOformat() + t2 = T.fromISOformat(ts1) + ts2 = t2.toISOformat() + # MediaWiki ISO format doesnt include microseconds + self.assertNotEqual(t1, t2) + t1 = t1.replace(microsecond=0) + self.assertEqual(t1, t2) + self.assertEqual(ts1, ts2) + + def test_mediawiki_format(self): + t1 = T.utcnow() + ts1 = t1.totimestampformat() + t2 = T.fromtimestampformat(ts1) + ts2 = t2.totimestampformat() + self.assertNotEqual(t1, t2) + t1 = t1.replace(microsecond=0) + self.assertEqual(t1, t2) + self.assertEqual(ts1, ts2) + + def test_add_timedelta(self): + t1 = T.utcnow() + t2 = t1 + datetime.timedelta(days=1) + self.assertEqual(t1.day + 1, t2.day) + self.assertIsInstance(t2, T) + + def test_add_timedate(self): + """Test unsupported additions raise NotImplemented.""" + t1 = datetime.datetime.utcnow() + t2 = t1 + datetime.timedelta(days=1) + t3 = t1.__add__(t2) + self.assertIs(t3, NotImplemented) + + # Now use the pywikibot class + t1 = T.utcnow() + t2 = t1 + datetime.timedelta(days=1) + t3 = t1.__add__(t2) + self.assertIs(t3, NotImplemented) + + def test_sub_timedelta(self): + t1 = T.utcnow() + t2 = t1 - datetime.timedelta(days=1) + self.assertEqual(t1.day - 1, t2.day) + self.assertIsInstance(t2, T) + + def test_sub_timedate(self): + t1 = T.utcnow() + t2 = t1 - datetime.timedelta(days=1) + td = t1 - t2 + self.assertIsInstance(td, datetime.timedelta) + self.assertEqual(t2 + td, t1) + +if __name__ == '__main__': + try: + unittest.main() + except SystemExit: + pass -- To view, visit https://gerrit.wikimedia.org/r/175404 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifb850b3e52c0fb1b84f2da433f50cb142f854591 Gerrit-PatchSet: 1 Gerrit-Project: pywikibot/core Gerrit-Branch: master Gerrit-Owner: John Vandenberg <jay...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits