Hello community, here is the log from the commit of package python-cftime for openSUSE:Factory checked in at 2020-01-25 13:24:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-cftime (Old) and /work/SRC/openSUSE:Factory/.python-cftime.new.26092 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-cftime" Sat Jan 25 13:24:39 2020 rev:3 rq:766930 version:1.0.4.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-cftime/python-cftime.changes 2019-03-19 09:58:16.360105847 +0100 +++ /work/SRC/openSUSE:Factory/.python-cftime.new.26092/python-cftime.changes 2020-01-25 13:24:47.320053082 +0100 @@ -1,0 +2,7 @@ +Fri Jan 24 15:13:06 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com> + +- update to 1.0.4.2 + * fix for date2num error when converting a DatetimeProlepticGregorian + object + +------------------------------------------------------------------- Old: ---- cftime-1.0.3.4.tar.gz New: ---- cftime-1.0.4.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-cftime.spec ++++++ --- /var/tmp/diff_new_pack.j2FHxg/_old 2020-01-25 13:24:47.916053344 +0100 +++ /var/tmp/diff_new_pack.j2FHxg/_new 2020-01-25 13:24:47.920053345 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-cftime # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-cftime -Version: 1.0.3.4 +Version: 1.0.4.2 Release: 0 Summary: Time-handling functionality from netcdf4-python License: MIT ++++++ cftime-1.0.3.4.tar.gz -> cftime-1.0.4.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/PKG-INFO new/cftime-1.0.4.2/PKG-INFO --- old/cftime-1.0.3.4/PKG-INFO 2018-12-05 23:09:17.000000000 +0100 +++ new/cftime-1.0.4.2/PKG-INFO 2019-10-23 20:26:42.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: cftime -Version: 1.0.3.4 +Version: 1.0.4.2 Summary: Time-handling functionality from netcdf4-python Home-page: UNKNOWN Author: Jeff Whitaker @@ -18,7 +18,11 @@ [![Commits Status](https://img.shields.io/github/commits-since/UniData/cftime/latest.svg)](https://github.com/UniData/cftime/commits/master) ## News - 12/05/2018: version 1.0.3.3 released (just to fix a problem with the source + 10/25/2019: version 1.0.4.1 released (fix for [issue #126](https://github.com/Unidata/cftime/issues/126)). + + 10/21/2019: version 1.0.4 released. + + 12/05/2018: version 1.0.3.4 released (just to fix a problem with the source tarball on pypi). 12/05/2018: version 1.0.3.1 released. Bugfix release (fixed issue with installation @@ -58,5 +62,5 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Scientific/Engineering -Classifier: License :: OSI Approved +Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Description-Content-Type: text/markdown diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/README.md new/cftime-1.0.4.2/README.md --- old/cftime-1.0.3.4/README.md 2018-12-05 22:23:35.000000000 +0100 +++ new/cftime-1.0.4.2/README.md 2019-10-23 20:26:29.000000000 +0200 @@ -10,7 +10,11 @@ [![Commits Status](https://img.shields.io/github/commits-since/UniData/cftime/latest.svg)](https://github.com/UniData/cftime/commits/master) ## News -12/05/2018: version 1.0.3.3 released (just to fix a problem with the source +10/25/2019: version 1.0.4.1 released (fix for [issue #126](https://github.com/Unidata/cftime/issues/126)). + +10/21/2019: version 1.0.4 released. + +12/05/2018: version 1.0.3.4 released (just to fix a problem with the source tarball on pypi). 12/05/2018: version 1.0.3.1 released. Bugfix release (fixed issue with installation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/cftime/_cftime.pyx new/cftime-1.0.4.2/cftime/_cftime.pyx --- old/cftime-1.0.3.4/cftime/_cftime.pyx 2018-12-05 22:57:21.000000000 +0100 +++ new/cftime-1.0.4.2/cftime/_cftime.pyx 2019-10-23 20:26:38.000000000 +0200 @@ -17,8 +17,9 @@ except ImportError: # python 3.x pass + microsec_units = ['microseconds','microsecond', 'microsec', 'microsecs'] -millisec_units = ['milliseconds', 'millisecond', 'millisec', 'millisecs'] +millisec_units = ['milliseconds', 'millisecond', 'millisec', 'millisecs', 'msec', 'msecs', 'ms'] sec_units = ['second', 'seconds', 'sec', 'secs', 's'] min_units = ['minute', 'minutes', 'min', 'mins'] hr_units = ['hour', 'hours', 'hr', 'hrs', 'h'] @@ -42,7 +43,7 @@ _rop_lookup = {Py_LT: '__gt__', Py_LE: '__ge__', Py_EQ: '__eq__', Py_GT: '__lt__', Py_GE: '__le__', Py_NE: '__ne__'} -__version__ = '1.0.3.4' +__version__ = '1.0.4.2' # Adapted from http://delete.me.uk/2005/03/iso8601.html # Note: This regex ensures that all ISO8601 timezone formats are accepted - but, due to legacy support for other timestrings, not all incorrect formats can be rejected. @@ -93,7 +94,7 @@ (units, isostring) = _datesplit(timestr) # parse the date string. - year, month, day, hour, minute, second, utc_offset =\ + year, month, day, hour, minute, second, microsecond, utc_offset =\ _parse_date( isostring.strip() ) if year >= MINYEAR: basedate = real_datetime(year, month, day, hour, minute, second) @@ -121,7 +122,7 @@ raise ValueError( "units must be one of 'seconds', 'minutes', 'hours' or 'days' (or singular version of these), got '%s'" % units) # parse the date string. - year, month, day, hour, minute, second, utc_offset = _parse_date( + year, month, day, hour, minute, second, microsecond, utc_offset = _parse_date( isostring.strip()) return units, utc_offset, datetime(year, month, day, hour, minute, second) @@ -182,6 +183,9 @@ ismasked = True times = [] for date in dates.flat: + if getattr(date, 'tzinfo',None) is not None: + date = date.replace(tzinfo=None) - date.utcoffset() + if ismasked and not date: times.append(None) else: @@ -408,6 +412,9 @@ cdef Py_ssize_t i for i in range(i_max): d = date[i] + if getattr(d, 'tzinfo', None) is not None: + d = d.replace(tzinfo=None) - d.utcoffset() + year[i] = d.year month[i] = d.month day[i] = d.day @@ -909,7 +916,12 @@ The timezone is parsed from the date string, assuming UTC by default. + Note that a seconds element with a fractional component + (e.g. 12.5) is converted into integer seconds and integer + microseconds. + Adapted from pyiso8601 (http://code.google.com/p/pyiso8601/) + """ if not isinstance(datestring, str) and not isinstance(datestring, unicode): raise ValueError("Expecting a string %r" % datestring) @@ -924,13 +936,14 @@ groups["minute"] = 0 if groups["second"] is None: groups["second"] = 0 - # if groups["fraction"] is None: - # groups["fraction"] = 0 - # else: - # groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6) + if groups["fraction"] is None: + groups["fraction"] = 0 + else: + groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6) iyear = int(groups["year"]) return iyear, int(groups["month"]), int(groups["day"]),\ int(groups["hour"]), int(groups["minute"]), int(groups["second"]),\ + int(groups["fraction"]),\ tzoffset_mins cdef _check_index(indices, times, nctime, calendar, select): @@ -1220,9 +1233,11 @@ "hour": self.hour, "minute": self.minute, "second": self.second, - "microsecond": self.microsecond, - "dayofwk": self.dayofwk, - "dayofyr": self.dayofyr} + "microsecond": self.microsecond} + + if 'dayofyr' in kwargs or 'dayofwk' in kwargs: + raise ValueError('Replacing the dayofyr or dayofwk of a datetime is ' + 'not supported.') for name, value in kwargs.items(): args[name] = value @@ -1246,13 +1261,17 @@ self.microsecond) def __repr__(self): - return "{0}.{1}{2}".format('cftime', - self.__class__.__name__, - self._getstate()) + return "{0}.{1}({2})".format('cftime', + self.__class__.__name__, + str(self)) def __str__(self): - return "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format( - self.year, self.month, self.day, self.hour, self.minute, self.second) + second = '{:02d}'.format(self.second) + if self.microsecond: + second += '.{}'.format(self.microsecond) + + return "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{}".format( + self.year, self.month, self.day, self.hour, self.minute, second) def __hash__(self): try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/cftime.egg-info/PKG-INFO new/cftime-1.0.4.2/cftime.egg-info/PKG-INFO --- old/cftime-1.0.3.4/cftime.egg-info/PKG-INFO 2018-12-05 23:09:17.000000000 +0100 +++ new/cftime-1.0.4.2/cftime.egg-info/PKG-INFO 2019-10-23 20:26:42.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: cftime -Version: 1.0.3.4 +Version: 1.0.4.2 Summary: Time-handling functionality from netcdf4-python Home-page: UNKNOWN Author: Jeff Whitaker @@ -18,7 +18,11 @@ [![Commits Status](https://img.shields.io/github/commits-since/UniData/cftime/latest.svg)](https://github.com/UniData/cftime/commits/master) ## News - 12/05/2018: version 1.0.3.3 released (just to fix a problem with the source + 10/25/2019: version 1.0.4.1 released (fix for [issue #126](https://github.com/Unidata/cftime/issues/126)). + + 10/21/2019: version 1.0.4 released. + + 12/05/2018: version 1.0.3.4 released (just to fix a problem with the source tarball on pypi). 12/05/2018: version 1.0.3.1 released. Bugfix release (fixed issue with installation @@ -58,5 +62,5 @@ Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Scientific/Engineering -Classifier: License :: OSI Approved +Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) Description-Content-Type: text/markdown diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/setup.py new/cftime-1.0.4.2/setup.py --- old/cftime-1.0.3.4/setup.py 2018-12-05 23:08:20.000000000 +0100 +++ new/cftime-1.0.4.2/setup.py 2019-10-23 20:26:38.000000000 +0200 @@ -119,4 +119,5 @@ 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Topic :: Scientific/Engineering', - 'License :: OSI Approved']) + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)'] + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cftime-1.0.3.4/test/test_cftime.py new/cftime-1.0.4.2/test/test_cftime.py --- old/cftime-1.0.3.4/test/test_cftime.py 2018-12-02 19:12:12.000000000 +0100 +++ new/cftime-1.0.4.2/test/test_cftime.py 2019-10-23 20:26:29.000000000 +0200 @@ -19,6 +19,33 @@ DatetimeProlepticGregorian, JulianDayFromDate, _parse_date, date2index, date2num, num2date, utime) +try: + from datetime import timezone +except ImportError: # python2.7 + from datetime import tzinfo + class timezone(tzinfo): + """ + Fixed offset in minutes east from UTC. adapted from + python 2.7 docs FixedOffset + """ + + def __init__(self, offset, name): + self.__offset = offset + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return timedelta(hours=0) + + +utc = timezone(timedelta(hours=0), 'UTC') +est = timezone(timedelta(hours=-5), 'UTC') + # test cftime module for netCDF time <--> python datetime conversions. dtime = namedtuple('dtime', ('values', 'units', 'calendar')) @@ -81,7 +108,20 @@ self.cdftime_noleap_capcal = utime( 'days since 1600-02-28 00:00:00', calendar='NOLEAP') - def runTest(self): + def test_tz_aware(self): + """testing with timezone""" + self.assertTrue(self.cdftime_mixed.units == 'hours') + d1 = datetime(1582, 10, 4, 23, tzinfo=utc) + t1 = self.cdftime_mixed.date2num(d1) + d2 = datetime(1582, 10, 4, 18, tzinfo=est) + t2 = self.cdftime_mixed.date2num(d2) + d3 = d2.replace(tzinfo=None) + t3 = self.cdftime_mixed.date2num(d3) + assert_almost_equal(t1, 13865687.0) + assert_almost_equal(t2, 13865687.0) + assert_almost_equal(t3, 13865682.0) + + def test_tz_naive(self): """testing cftime""" # test mixed julian/gregorian calendar # check attributes. @@ -671,7 +711,10 @@ assert(cftime.date2num(cftime.datetime(1, 12, 1, 0, 0, 0, 0, -1, 1), units='days since 01-01-01',calendar='noleap') == 334.0) assert(cftime.date2num(cftime.num2date(1.0,units='days since 01-01-01',calendar='noleap'),units='days since 01-01-01',calendar='noleap') == 1.0) assert(cftime.date2num(cftime.DatetimeNoLeap(1980, 1, 1, 0, 0, 0, 0, 6, 1),'days since 1970-01-01','noleap') == 3650.0) - + # issue #126 + d = cftime.DatetimeProlepticGregorian(1, 1, 1) + assert(cftime.date2num(d, 'days since 0001-01-01',\ + 'proleptic_gregorian') == 0.0) class TestDate2index(unittest.TestCase): @@ -734,6 +777,15 @@ values=date2num(dates, units), units=units) + def test_tz_aware(self): + """implicit test of date2num""" + dutc = datetime(1950, 2, 1, 0, tzinfo=utc) + t1 = date2index(dutc, self.standardtime) + assert_equal(t1, 31) + dest = datetime(1950, 1, 31, 19, tzinfo=est) + t2 = date2index(dest, self.standardtime) + assert_equal(t2, 31) + def test_simple(self): t = date2index(datetime(1950, 2, 1), self.standardtime) assert_equal(t, 31) @@ -1043,8 +1095,6 @@ self.assertEqual(self.date1_365_day.replace(minute=3).minute, 3) self.assertEqual(self.date1_365_day.replace(second=3).second, 3) self.assertEqual(self.date1_365_day.replace(microsecond=3).microsecond, 3) - self.assertEqual(self.date1_365_day.replace(dayofwk=3).dayofwk, 3) - self.assertEqual(self.date1_365_day.replace(dayofyr=3).dayofyr, 3) def test_pickling(self): "Test reversibility of pickling." @@ -1186,25 +1236,25 @@ "Test timezone parsing in _parse_date" # these should succeed and are ISO8601 compliant - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 60.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 60.0) for datestr in ("2017-05-01 00:00+01:00", "2017-05-01 00:00+0100", "2017-05-01 00:00+01"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # some more tests with non-zero minutes, should all be ISO compliant and work - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 85.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 85.0) for datestr in ("2017-05-01 00:00+01:25", "2017-05-01 00:00+0125"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # these are NOT ISO8601 compliant and should not even be parseable but will be parsed with timezone anyway # because, due to support of other legacy time formats, they are difficult to reject # ATTENTION: only the hours part of this will be parsed, single-digit minutes will be ignored! - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 60.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 60.0) for datestr in ("2017-05-01 00:00+01:0", "2017-05-01 00:00+01:", "2017-05-01 00:00+01:5"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # these should not even be parseable as datestrings but are parseable anyway with ignored timezone # this is because the module also supports some legacy, non-standard time strings - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 0.0) for datestr in ("2017-05-01 00:00+1",): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) @@ -1368,8 +1418,9 @@ @pytest.mark.parametrize( 'date_args', [(1, 2, 3, 4, 5, 6), (10, 2, 3, 4, 5, 6), (100, 2, 3, 4, 5, 6), - (1000, 2, 3, 4, 5, 6)], - ids=['1', '10', '100', '1000']) + (1000, 2, 3, 4, 5, 6), + (2000, 1, 1, 12, 34, 56, 123456)], + ids=['1', '10', '100', '1000', '2000']) def test_str_matches_datetime_str(date_type, date_args): assert str(date_type(*date_args)) == str(datetime(*date_args)) @@ -1419,13 +1470,28 @@ def test_repr(): - expected = 'cftime.datetime(2000, 1, 1, 0, 0, 0, 0, -1, 1)' - # dayofwk, dayofyr not set + expected = 'cftime.datetime(2000-01-01 00:00:00)' assert repr(datetimex(2000, 1, 1)) == expected - expected = 'cftime.DatetimeGregorian(2000, 1, 1, 0, 0, 0, 0, 5, 1)' - # dayofwk, dayofyr are set - assert repr(DatetimeGregorian(2000, 1, 1)) == expected + +def test_dayofyr_after_replace(date_type): + date = date_type(1, 1, 1) + assert date.dayofyr == 1 + assert date.replace(day=2).dayofyr == 2 + + +def test_dayofwk_after_replace(date_type): + date = date_type(1, 1, 1) + original_dayofwk = date.dayofwk + expected = (original_dayofwk + 1) % 7 + result = date.replace(day=2).dayofwk + assert result == expected + + +@pytest.mark.parametrize('argument', ['dayofyr', 'dayofwk']) +def test_replace_dayofyr_or_dayofwk_error(date_type, argument): + with pytest.raises(ValueError): + date_type(1, 1, 1).replace(**{argument: 3}) if __name__ == '__main__':