[Git][debian-gis-team/cftime][master] 4 commits: New upstream version 1.6.4
Bas Couwenberg (@sebastic)
gitlab at salsa.debian.org
Fri Jun 7 05:28:39 BST 2024
Bas Couwenberg pushed to branch master at Debian GIS Project / cftime
Commits:
67cdd86b by Bas Couwenberg at 2024-06-07T06:21:44+02:00
New upstream version 1.6.4
- - - - -
66798918 by Bas Couwenberg at 2024-06-07T06:21:44+02:00
Update upstream source from tag 'upstream/1.6.4'
Update to upstream version '1.6.4'
with Debian dir f90eaa59c313b7992d69ccdcac6394ab28cba501
- - - - -
e0698797 by Bas Couwenberg at 2024-06-07T06:22:04+02:00
New upstream release.
- - - - -
01e1d54f by Bas Couwenberg at 2024-06-07T06:23:05+02:00
Set distribution to unstable.
- - - - -
12 changed files:
- + .github/dependabot.yml
- .github/workflows/cibuildwheel.yml
- .github/workflows/deploy-docs.yml
- .github/workflows/publish.yml
- .github/workflows/tests_conda.yml
- .github/workflows/tests_latest.yml
- Changelog
- README.md
- debian/changelog
- pyproject.toml
- src/cftime/_cftime.pyx
- test/test_cftime.py
Changes:
=====================================
.github/dependabot.yml
=====================================
@@ -0,0 +1,13 @@
+# Keep GitHub Actions up to date with GitHub's Dependabot...
+# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ groups:
+ github-actions:
+ patterns:
+ - "*" # Group all Actions updates into a single larger pull request
+ schedule:
+ interval: weekly
=====================================
.github/workflows/cibuildwheel.yml
=====================================
@@ -2,7 +2,8 @@ name: Wheels
on:
pull_request:
-
+ branches:
+ - master
push:
tags:
- "v*"
@@ -11,58 +12,97 @@ jobs:
build_bdist:
name: "Build ${{ matrix.os }} (${{ matrix.arch }}) wheels"
runs-on: ${{ matrix.os }}
+ timeout-minutes: 60 # should be long enough even on tags, but let's prevent hangs
strategy:
fail-fast: false
matrix:
- os: ["ubuntu-latest", "windows-latest", "macos-latest"]
- arch: ["x86_64", "arm64", "AMD64"]
- exclude:
- - os: ubuntu-latest
- arch: arm64
- - os: ubuntu-latest
- arch: AMD64
- - os: windows-latest
- arch: arm64
- - os: windows-latest
- arch: x86_64
- - os: macos-latest
- arch: AMD64
+ include:
+ - os: ubuntu-22.04
+ arch: x86_64
+ - os: ubuntu-22.04
+ arch: aarch64
+ - os: windows-2022
+ arch: AMD64
+ - os: macos-14
+ arch: arm64
+ - os: macos-13
+ arch: x86_64
steps:
- uses: actions/checkout at v4
with:
fetch-depth: 0
+ # For aarch64 support
+ # https://cibuildwheel.pypa.io/en/stable/faq/#emulation
+ - uses: docker/setup-qemu-action at v3
+ with:
+ platforms: all
+ if: runner.os == 'Linux' && matrix.arch == 'aarch64'
+
+ - name: Build just oldest and newest on PRs, all on tags
+ shell: bash
+ # - Always omit musl 3.8 b/c NumPy does not provide wheels for it
+ # - Always omit musllinux_aarch64 because it's slow and niche
+ # - On PPs, omit musllinux for speed
+ # - On PRs, run just oldest and newest Python versions (and omit 3.8 aarch64)
+ run: |
+ if [[ "${{ github.event_name }}" == "pull_request" ]]; then
+ CIBW_SKIP="pp* cp36-* cp37-* cp38-musllinux* cp39-* cp310-* cp311-* cp38-*_aarch64 *musllinux*"
+ else
+ CIBW_SKIP="pp* cp36-* cp37-* cp38-musllinux* *musllinux_aarch64"
+ fi
+ echo "CIBW_SKIP=$CIBW_SKIP" >> $GITHUB_ENV
+ echo "Setting CIBW_SKIP=$CIBW_SKIP"
+
- name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels"
- uses: pypa/cibuildwheel at v2.15.0
+ uses: pypa/cibuildwheel at v2.18.1
env:
- # Skips pypy and musllinux for now.
- CIBW_SKIP: "pp* cp36-* cp37-* *-musllinux*"
+ # Skips pypy py36,37
+ CIBW_SKIP: ${{ env.CIBW_SKIP }}
CIBW_ARCHS: ${{ matrix.arch }}
- CIBW_BUILD_FRONTEND: build
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
- CIBW_TEST_SKIP: "*_arm64"
+ CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014
+ # Emulated testing is slow, so trust that the Python 3.12 test is good enough on aarch64
+ # (takes about 5 minutes per wheel to build, and 5 minutes to test)
+ CIBW_TEST_SKIP: "cp38-*_aarch64 cp39-*_aarch64 cp310-*_aarch64 cp311-*_aarch64"
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: >
python -c "import cftime; print(f'cftime v{cftime.__version__}')" &&
- python -m pip install -r {package}/requirements-dev.txt &&
+ python -m pip install check-manifest cython pytest pytest-cov &&
python -m pytest -vv {package}/test
- - uses: actions/upload-artifact at v3
+ - uses: actions/upload-artifact at v4
with:
- name: pypi-artifacts
+ name: pypi-artifacts-${{ matrix.os }}-${{ matrix.arch }}
path: ${{ github.workspace }}/wheelhouse/*.whl
+ build_sdist:
+ name: Build source distribution
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout at v4
+
+ - name: Build sdist
+ run: >
+ pip install build
+ && python -m build --sdist . --outdir dist
+
+ - uses: actions/upload-artifact at v4
+ with:
+ path: dist/*.tar.gz
+
show-artifacts:
- needs: [build_bdist]
+ needs: [build_bdist, build_sdist]
name: "Show artifacts"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
steps:
- - uses: actions/download-artifact at v3
+ - uses: actions/download-artifact at v4
with:
- name: pypi-artifacts
+ pattern: pypi-artifacts*
path: ${{ github.workspace }}/dist
+ merge-multiple: true
- shell: bash
run: |
@@ -70,16 +110,17 @@ jobs:
publish-artifacts-pypi:
- needs: [build_bdist]
+ needs: [build_bdist, build_sdist]
name: "Publish to PyPI"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
# upload to PyPI for every tag starting with 'v'
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
steps:
- - uses: actions/download-artifact at v3
+ - uses: actions/download-artifact at v4
with:
- name: pypi-artifacts
+ pattern: pypi-artifacts*
path: ${{ github.workspace }}/dist
+ merge-multiple: true
- uses: pypa/gh-action-pypi-publish at release/v1
with:
=====================================
.github/workflows/deploy-docs.yml
=====================================
@@ -43,7 +43,7 @@ jobs:
popd
- name: Deploy
- uses: peaceiris/actions-gh-pages at v3
+ uses: peaceiris/actions-gh-pages at v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/_build/html
=====================================
.github/workflows/publish.yml
=====================================
@@ -9,7 +9,7 @@ jobs:
- uses: actions/checkout at v4
- name: Set up Python
- uses: actions/setup-python at v4
+ uses: actions/setup-python at v5
with:
python-version: 3.x
=====================================
.github/workflows/tests_conda.yml
=====================================
@@ -8,15 +8,21 @@ on:
jobs:
run:
runs-on: ${{ matrix.os }}
+ continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
os: [windows-latest, ubuntu-latest, macos-latest]
platform: [x64, x32]
+ experimental: [false]
exclude:
- os: macos-latest
platform: x32
+ include:
+ - python-version: "3.12"
+ os: "ubuntu-latest"
+ experimental: true
steps:
- uses: actions/checkout at v4
@@ -31,11 +37,22 @@ jobs:
cython>=0.29.20
pytest
pytest-cov
+ - name: Install unstable dependencies
+ if: matrix.experimental == true
+ shell: bash -l {0}
+ run: |
+ python -m pip install \
+ --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ \
+ --trusted-host pypi.anaconda.org \
+ --no-deps --pre --upgrade \
+ numpy;
+ python -m pip install -v -e . --no-deps --no-build-isolation --force-reinstall
- name: Install cftime
+ if: matrix.experimental != true
shell: bash -l {0}
run: |
- pip install -v -e . --no-deps --force-reinstall
+ python -m pip install -v -e . --no-deps --force-reinstall
- name: Run Tests
shell: bash -l {0}
=====================================
.github/workflows/tests_latest.yml
=====================================
@@ -6,13 +6,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: ["3.12-dev"]
+ python-version: ["3.13.0-alpha.1"]
steps:
- uses: actions/checkout at v4
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python at v4
+ uses: actions/setup-python at v5
with:
python-version: ${{ matrix.python-version }}
@@ -20,9 +20,15 @@ jobs:
run: |
python -m pip install --upgrade pip
- - name: Install cftime dependencies via pip
+ - name: Install unstable cftime dependencies via pip
run: |
- python -m pip install -r requirements-dev.txt
+ python -m pip install --pre -r requirements-dev.txt
+ # get nightly wheels for numpy
+ python -m pip install \
+ --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ \
+ --trusted-host pypi.anaconda.org \
+ --no-deps --pre --upgrade \
+ numpy
- name: Install cftime
run: |
=====================================
Changelog
=====================================
@@ -1,3 +1,11 @@
+version 1.6.4 (release tag v1.6.4rel)
+=====================================
+ * build aarch64 linux wheels (issue #333).
+ * build musllinux wheels (issue #307).
+ * return empty array if one provided to date2num (issue #315).
+ * numpy 2.0 compatibility (issue #325).
+ * handle nan/inf in num2date (issue #328).
+
version 1.6.3 (release tag v1.6.3rel)
=====================================
* add support for formats without separators in strptime (e.g. '20200229', issue #301).
=====================================
README.md
=====================================
@@ -12,6 +12,8 @@ Time-handling functionality from netcdf4-python
## News
For details on the latest updates, see the [Changelog](https://github.com/Unidata/cftime/blob/master/Changelog).
+6/7/2024: Version 1.6.4 release. Wheels for muslinux and aarch64, numpy 2.0 compatibility.
+
10/20/2023: Version 1.6.3 released. Support for python 3.12, cython 3.0, strptime formats without separators.
9/18/2022: Version 1.6.2 released. strptime method added, fix for num2date failure on
=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+cftime (1.6.4-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Bas Couwenberg <sebastic at debian.org> Fri, 07 Jun 2024 06:22:55 +0200
+
cftime (1.6.3-1) unstable; urgency=medium
* New upstream release.
=====================================
pyproject.toml
=====================================
@@ -1,3 +1,9 @@
[build-system]
-requires = ["setuptools>=41.2", "cython>=0.29.20", "wheel", "oldest-supported-numpy; python_version<'3.12.0.rc1'", "numpy>=1.26.0b1; python_version>='3.12.0.rc1'"]
+requires = [
+ "setuptools>=41.2",
+ "cython>=0.29.20",
+ "wheel",
+ "oldest-supported-numpy ; python_version < '3.9'",
+ "numpy>=2.0.0rc1,<3 ; python_version >= '3.9'",
+]
build-backend = "setuptools.build_meta"
=====================================
src/cftime/_cftime.pyx
=====================================
@@ -7,6 +7,7 @@ from cpython.object cimport (PyObject_RichCompare, Py_LT, Py_LE, Py_EQ,
from numpy cimport int64_t, int32_t
import cython
import numpy as np
+cimport numpy as np
import re
import time
from datetime import datetime as datetime_python
@@ -14,6 +15,8 @@ from datetime import timedelta, MINYEAR, MAXYEAR
import warnings
from ._strptime import _strptime
+np.import_array()
+
microsec_units = ['microseconds','microsecond', 'microsec', 'microsecs']
millisec_units = ['milliseconds', 'millisecond', 'millisec', 'millisecs', 'msec', 'msecs', 'ms']
sec_units = ['second', 'seconds', 'sec', 'secs', 's']
@@ -37,7 +40,7 @@ cdef int[12] _dayspermonth_leap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 3
cdef int[13] _cumdayspermonth = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]
cdef int[13] _cumdayspermonth_leap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
-__version__ = '1.6.3'
+__version__ = '1.6.4'
# 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.
@@ -193,7 +196,11 @@ def date2num(dates, units, calendar=None, has_year_zero=None, longdouble=False):
try:
dates[0]
except:
- isscalar = True
+ if not dates:
+ # if empty list or array input, return empty array (issue #315)
+ return np.array([],dtype=float)
+ else:
+ isscalar = True
# masked array input?
ismasked = False
@@ -613,6 +620,9 @@ def num2date(
factor = UNIT_CONVERSION_FACTORS[unit]
times = np.asanyarray(times) # Allow list as input
times = upcast_times(times)
+ # convert to masked array if any nan or inf values present
+ if not np.isfinite(times).all():
+ times = np.ma.masked_invalid(times)
scaled_times = scale_times(times, factor)
scaled_times = cast_to_int(scaled_times,units=unit)
=====================================
test/test_cftime.py
=====================================
@@ -6,8 +6,6 @@ from cftime import (Datetime360Day, DatetimeAllLeap,
DatetimeProlepticGregorian, _parse_date,
date2index, date2num, num2date, UNIT_CONVERSION_FACTORS)
import copy
-import operator
-import sys
import unittest
import warnings
from collections import namedtuple
@@ -330,17 +328,17 @@ class cftimeTestCase(unittest.TestCase):
for t in (733498.999, 733498.9999, 733498.99999, 733498.999999, 733498.9999999):
d = num2date(t, units='days since 0001-01-01 00:00:00')
t2 = date2num(d, units='days since 0001-01-01 00:00:00')
- assert(abs(t2 - t) < 1e-5) # values should be less than second
+ assert abs(t2 - t) < 1e-5 # values should be less than second
# Check equality testing
d1 = datetimex(1979, 6, 21, 9, 23, 12, calendar='standard')
d2 = datetime(1979, 6, 21, 9, 23, 12)
- assert(d1 == d2)
+ assert d1 == d2
# check timezone offset
d = datetime(2012, 2, 29, 15)
# mixed_tz is -6 hours from UTC, mixed is UTC so
# difference in elapsed time is -6 hours.
- assert(self.cdftime_mixed_tz.date2num(
- d) - self.cdftime_mixed.date2num(d) == -6)
+ assert self.cdftime_mixed_tz.date2num(
+ d) - self.cdftime_mixed.date2num(d) == -6
# Check comparisons with Python datetime types
@@ -402,7 +400,7 @@ class cftimeTestCase(unittest.TestCase):
#issue 344
units = 'hours since 2013-12-12T12:00:00'
- assert(1.0 == date2num(num2date(1.0, units), units))
+ assert 1.0 == date2num(num2date(1.0, units), units)
# test roundtrip accuracy
# also tests error found in issue #349
@@ -416,43 +414,49 @@ class cftimeTestCase(unittest.TestCase):
times2 = date2num(dates1,units,calendar=calendar)
dates2 = num2date(times2,units,calendar=calendar)
err = np.abs(times1 - times2)
- assert(np.all(err<eps))
+ assert np.all(err<eps)
dates1 = [date.strftime(dateformat) for date in dates1]
dates2 = [date.strftime(dateformat) for date in dates2]
- assert(dates1==dates2)
+ assert dates1==dates2
return err.max()
for calendar in calendars:
- eps = 1.; delta = 1.
+ eps = 1.
+ delta = 1.
units = 'microseconds since 2000-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
print('calendar = %s max abs err (microsecs) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 0.001; delta = 0.001
+ eps = 0.001
+ delta = 0.001
units = 'milliseconds since 2000-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
print('calendar = %s max abs err (millisecs) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-5; delta = 0.1
+ eps = 1.e-5
+ delta = 0.1
units = 'seconds since 0001-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
print('calendar = %s max abs err (secs) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-6; delta = 0.01
+ eps = 1.e-6
+ delta = 0.01
units = 'minutes since 0001-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
print('calendar = %s max abs err (mins) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-8; delta = 0.001
+ eps = 1.e-8
+ delta = 0.001
units = 'hours since 0001-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
print('calendar = %s max abs err (hours) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-9; delta = 0.00001
+ eps = 1.e-9
+ delta = 0.00001
units = 'days since 0001-01-30 01:01:01'
maxerr = roundtrip(eps,delta,units)
if verbose:
@@ -460,20 +464,19 @@ class cftimeTestCase(unittest.TestCase):
(calendar,maxerr,eps))
# issue 353
- assert (num2date(0, 'hours since 2000-01-01 0') ==
- datetime(2000,1,1,0))
+ assert num2date(0, 'hours since 2000-01-01 0') == datetime(2000,1,1,0)
# issue 354
num1 = np.array([[0, 1], [2, 3]])
num2 = np.array([[0, 1], [2, 3]])
dates1 = num2date(num1, 'days since 0001-01-01')
dates2 = num2date(num2, 'days since 2001-01-01')
- assert( dates1.shape == (2,2) )
- assert( dates2.shape == (2,2) )
+ assert dates1.shape == (2,2)
+ assert dates2.shape == (2,2)
num1b = date2num(dates1, 'days since 0001-01-01')
num2b = date2num(dates2, 'days since 2001-01-01')
- assert( num1b.shape == (2,2) )
- assert( num2b.shape == (2,2) )
+ assert num1b.shape == (2,2)
+ assert num2b.shape == (2,2)
assert_almost_equal(num1,num1b)
assert_almost_equal(num2,num2b)
@@ -484,8 +487,8 @@ class cftimeTestCase(unittest.TestCase):
date = datetime(1682,10,15) # assumed UTC
num = date2num(date,units)
# UTC is 7 hours ahead of units, so num should be -7
- assert (num == -7)
- assert (num2date(num, units) == date)
+ assert num == -7
+ assert num2date(num, units) == date
units = 'hours since 1482-10-15 -07:00 UTC'
# date before gregorian switch, cftime datetime used
date = datetime(1482,10,15)
@@ -541,7 +544,7 @@ class cftimeTestCase(unittest.TestCase):
d = num2date(0, units, calendar="standard")
#self.assertEqual(d, utc_date)
# tolerance of 1.e-3 secs
- assert(np.abs((d-utc_date).total_seconds()) < 1.e-3)
+ assert np.abs((d-utc_date).total_seconds()) < 1.e-3
# also test with negative values to cover 2nd code path
d = num2date(-1, units, calendar="standard")
self.assertEqual(d, utc_date - timedelta(hours=1))
@@ -608,7 +611,7 @@ class cftimeTestCase(unittest.TestCase):
# cftime issue #134
d = num2date(-657071, units, calendar='proleptic_gregorian',
only_use_cftime_datetimes=False,only_use_python_datetimes=True)
- assert(d==datetime(1,1,1,0))
+ assert d==datetime(1,1,1,0)
self.assertRaises(ValueError, num2date, \
-657072, units, calendar='proleptic_gregorian',
only_use_cftime_datetimes=False,only_use_python_datetimes=True)
@@ -619,11 +622,11 @@ class cftimeTestCase(unittest.TestCase):
utc_date = datetime(2000,1,1,18,30)
for units in ("hours since 2000-01-01 22:30+04:00", "hours since 2000-01-01 11:30-07:00", "hours since 2000-01-01 15:00-03:30"):
d = num2date(0, units, calendar="standard")
- assert(np.abs((d-utc_date).total_seconds()) < 1.e-3)
+ assert np.abs((d-utc_date).total_seconds()) < 1.e-3
# also test with negative values to cover 2nd code path
d = num2date(-1, units, calendar="standard")
- assert(np.abs((d - \
- (utc_date-timedelta(hours=1))).total_seconds()) < 1.e-3)
+ assert np.abs((d - \
+ (utc_date-timedelta(hours=1))).total_seconds()) < 1.e-3
n = date2num(utc_date, units, calendar="standard")
# n should always be 0 as all units refer to the same point in time
@@ -698,7 +701,7 @@ class cftimeTestCase(unittest.TestCase):
d1 = datetimex(2020, 5, 20, dayofwk=8, dayofyr=9, calendar='')
assert (d1.dayofwk == 8)
assert (d1.dayofyr == 9)
-
+
# issue 71: negative reference years
# https://coastwatch.pfeg.noaa.gov/erddap/convert/time.html
# gives 2446433 (365 days more - is it counting year 0?)
@@ -722,17 +725,17 @@ class cftimeTestCase(unittest.TestCase):
self.assertRaises(ValueError, utime, \
'months since 01-01-01', calendar='standard')
# issue #78 - extra digits due to roundoff
- 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)
+ 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)
+ assert cftime.date2num(d, 'days since 0001-01-01',\
+ 'proleptic_gregorian') == 0.0
# issue #140 (fractional seconds in reference date)
d = datetime.strptime('2018-01-23 09:27:10.950000',"%Y-%m-%d %H:%M:%S.%f")
units = 'seconds since 2018-01-23 09:31:42.94'
- assert(float(cftime.date2num(d, units)) == -271.99)
+ assert float(cftime.date2num(d, units)) == -271.99
# issue 143 - same answer for arrays vs scalars.
units = 'seconds since 1970-01-01 00:00:00'
times_in = [1261440000.0, 1261440001.0, 1261440002.0, 1261440003.0,
@@ -743,34 +746,34 @@ class cftimeTestCase(unittest.TestCase):
times_out2.append(cftime.num2date(time_in, units))
dates1 = [str(d) for d in times_out1]
dates2 = [str(d) for d in times_out2]
- assert(dates1 == dates2)
+ assert dates1 == dates2
# issue #143 formatting of microseconds
d = cftime.num2date(1261440000.015625,units)
# on windows only 100 ms precision
- assert(str(d)[0:24] == '2009-12-22 00:00:00.0156')
+ assert str(d)[0:24] == '2009-12-22 00:00:00.0156'
# issue #152 add isoformat()
- assert(d.isoformat()[0:24] == '2009-12-22T00:00:00.0156')
- assert(d.isoformat(sep=' ')[0:24] == '2009-12-22 00:00:00.0156')
- assert(d.isoformat(sep=' ',timespec='milliseconds') == '2009-12-22 00:00:00.016')
- assert(d.isoformat(sep=' ',timespec='seconds') == '2009-12-22 00:00:00')
- assert(d.isoformat(sep=' ',timespec='minutes') == '2009-12-22 00:00')
- assert(d.isoformat(sep=' ',timespec='hours') == '2009-12-22 00')
+ assert d.isoformat()[0:24] == '2009-12-22T00:00:00.0156'
+ assert d.isoformat(sep=' ')[0:24] == '2009-12-22 00:00:00.0156'
+ assert d.isoformat(sep=' ',timespec='milliseconds') == '2009-12-22 00:00:00.016'
+ assert d.isoformat(sep=' ',timespec='seconds') == '2009-12-22 00:00:00'
+ assert d.isoformat(sep=' ',timespec='minutes') == '2009-12-22 00:00'
+ assert d.isoformat(sep=' ',timespec='hours') == '2009-12-22 00'
# issue #165: make sure python datetime returned
d=num2date(0,units="seconds since 2000-01-01 00:00:00",only_use_cftime_datetimes=False)
assert isinstance(d, datetime)
# issue #169: cftime.datetime has no calendar attribute, causing dayofwk,dayofyr methods
# to fail.
c = cftime.datetime(*cftime._parse_date('7480-01-01 00:00:00'),calendar='standard')
- assert(c.strftime() == '7480-01-01 00:00:00')
+ assert c.strftime() == '7480-01-01 00:00:00'
# issue #175: masked values not treated properly in num2date
times = np.ma.masked_array([-3956.7499999995343,-999999999999],mask=[False,True])
units='days since 1858-11-17 00:00:00'
dates = num2date(times, units=units, calendar='standard',\
only_use_cftime_datetimes=False, only_use_python_datetimes=True)
test = dates == np.ma.masked_array([datetime(1848, 1, 17, 6, 0, 0, 40), None],mask=[0,1])
- assert(test.all())
+ assert test.all()
dates = num2date(times, units=units, calendar='standard')
- assert(str(dates)=="[cftime.DatetimeGregorian(1848, 1, 17, 6, 0, 0, 40, has_year_zero=False)\n --]")
+ assert str(dates)=="[cftime.DatetimeGregorian(1848, 1, 17, 6, 0, 0, 40, has_year_zero=False)\n --]"
# check that time range of 200,000 + years can be represented accurately
calendar='standard'
_MAX_INT64 = np.iinfo("int64").max
@@ -779,13 +782,13 @@ class cftimeTestCase(unittest.TestCase):
units = '%s since 01-01-01' % unit
time = 292471*365*86400*(1000000//int(UNIT_CONVERSION_FACTORS[unit])) + 1000000//int(UNIT_CONVERSION_FACTORS[unit])
date = num2date(time,units,calendar=calendar)
- assert(date == refdate)
+ assert date == refdate
# check round-trip
time2 = date2num(date,units,calendar=calendar)
date2 = num2date(time2,units,calendar=calendar)
# windows doesn't have a longdouble type (it defaults to float64)
if np.finfo(np.longdouble).precision == 18:
- assert(date2 == refdate)
+ assert date2 == refdate
# microsecond roundtrip accuracy preserved over time ranges of 286 years
# (float64 can only represent integers exactly up to 2**53-1)
refdate=DatetimeGregorian(286,6,3,23,47,34,740992)
@@ -793,11 +796,11 @@ class cftimeTestCase(unittest.TestCase):
units = '%s since 01-01-01' % unit
time = (2**53 - 1)*(1/UNIT_CONVERSION_FACTORS[unit]) + 1/UNIT_CONVERSION_FACTORS[unit]
date = num2date(time,units,calendar=calendar)
- assert(date == refdate)
+ assert date == refdate
# check round-trip
time2 = date2num(date,units,calendar=calendar)
date2 = num2date(time2,units,calendar=calendar)
- assert(date2 == refdate)
+ assert date2 == refdate
# issue #185: date2num should work the numpy scalar array of dates (1.2.0 regression)
dates = np.array(datetime(2010, 2, 2, 0, 0))
assert (date2num(dates, units="hours since 2010-02-01 00:00:00") == 24.)
@@ -808,7 +811,7 @@ class cftimeTestCase(unittest.TestCase):
units = 'days since -4713-01-01 12:00'
dt2 = num2date(date2num(dt1, units), units, calendar='proleptic_gregorian')
dt2 = num2date(date2num(dt1, units, calendar='standard'), units)
- assert(dt1 == dt2)
+ assert dt1 == dt2
# issue #189 - leap years calculated incorrectly for negative years in proleptic_gregorian calendar
dt1 = datetime(2020, 4, 24, 16, 15, 10) # python datetime
units = 'days since -4713-01-01 12:00'
@@ -817,32 +820,32 @@ class cftimeTestCase(unittest.TestCase):
warnings.simplefilter("ignore",category=cftime.CFWarning)
dt2 = num2date(date2num(dt1, units, cal, has_year_zero=False), units,
cal, has_year_zero=False)
- assert(dt1 == dt2)
+ assert dt1 == dt2
# issue #198 - cftime.datetime creates calendar specific datetimes that
# support addition/subtraction of timedeltas.
for cal in calendars:
dt = cftime.datetime(2020, 1, 1, calendar=cal)
dt += timedelta(hours=1)
- assert(str(dt) == '2020-01-01 01:00:00')
+ assert str(dt) == '2020-01-01 01:00:00'
# issue #193 - years with more than four digits in reference date
- assert(cftime.date2num(cftime.datetime(18000, 12, 1, 0, 0), 'days since 18000-1-1', '360_day') == 330.0)
+ assert cftime.date2num(cftime.datetime(18000, 12, 1, 0, 0), 'days since 18000-1-1', '360_day') == 330.0
# julian day not including year zero
d = cftime.datetime(2020, 12, 1, 12, calendar='julian')
with warnings.catch_warnings():
warnings.simplefilter("ignore",category=cftime.CFWarning)
units = 'days since -4713-1-1 12:00'
jd = cftime.date2num(d,units,calendar='julian')
- assert(jd == 2459198.0)
+ assert jd == 2459198.0
# if calendar=None, use input date to determine calendar
jd = cftime.date2num(d,units,calendar=None)
- assert(jd == 2459198.0)
+ assert jd == 2459198.0
# if no calendar specified, use calendar associated with datetime
# instance.
jd = cftime.date2num(d,units)
- assert(jd == 2459198.0)
+ assert jd == 2459198.0
# use 'standard' calendar
jd = cftime.date2num(d,units,calendar='standard')
- assert(jd == 2459185.0)
+ assert jd == 2459185.0
# issue #211
# (masked array handling in date2num - AttributeError:
@@ -850,7 +853,7 @@ class cftimeTestCase(unittest.TestCase):
m = np.ma.asarray(
[cftime.DatetimeGregorian(2014, 8, 1, 12, 0, 0, 0)]
)
- assert(
+ assert (
cftime.date2num(m, units="seconds since 2000-1-1")==[4.602096e+08]
)
@@ -869,11 +872,11 @@ class cftimeTestCase(unittest.TestCase):
else:
raise AssertionError # fail if ValueError not raised
d2 = cftime.datetime(1,1,1,0,has_year_zero=has_year_zero,calendar=calendar)
- assert((d2-d).days==366) # 1-1-1 is 366 days after -1-1-1 if no year zero.
+ assert (d2-d).days==366 # 1-1-1 is 366 days after -1-1-1 if no year zero.
has_year_zero=True
d = cftime.datetime(0,1,1,0,has_year_zero=has_year_zero,calendar=calendar)
d2 = cftime.datetime(1,1,1,0,has_year_zero=has_year_zero,calendar=calendar)
- assert((d2-d).days==366) # 1-1-1 is 366 days after 0-1-1 if year zero allowed.
+ assert (d2-d).days==366 # 1-1-1 is 366 days after 0-1-1 if year zero allowed.
for has_year_zero in [True,False]:
if calendar == 'julian':
d = cftime.datetime(1858,11, 4,12,has_year_zero=has_year_zero,calendar=calendar)
@@ -890,40 +893,56 @@ class cftimeTestCase(unittest.TestCase):
else:
d0 = cftime.datetime(-4713, 1, 1,12,has_year_zero=has_year_zero,calendar=calendar)
jd = d.toordinal()
- assert((d-d0).days == jdref)
- assert(jd == jdref)
- assert(d.toordinal() == jdref)
+ assert (d-d0).days == jdref
+ assert jd == jdref
+ assert d.toordinal() == jdref
d2 = cftime.datetime.fromordinal(jd,calendar=calendar,has_year_zero=has_year_zero)
- assert(d2 == d)
+ assert d2 == d
# issue #248. Set has_year_zero=True if year zero requested
# on instance creation, or by using replace method.
d=cftime.datetime(0, 0, 0, calendar=None)
- assert(d.has_year_zero==True)
+ assert d.has_year_zero is True
d=cftime.datetime(1, 0, 0, calendar=None)
- assert(d.has_year_zero==False)
+ assert d.has_year_zero is False
d = d.replace(year=0)
- assert(d.has_year_zero==True)
+ assert d.has_year_zero is True
# this should raise a warning, since the default has_year_zero
# is changed if year specified as zero. (issue #248, PR #249)
self.assertWarns(UserWarning, cftime.datetime, 0, 1, 1,\
calendar='standard')
# check that for idealized calendars has_year_zero is always True
d=cftime.datetime(0, 1, 1, calendar='360_day')
- assert(d.has_year_zero==True)
+ assert d.has_year_zero is True
d=cftime.datetime(1, 1, 1, calendar='360_day')
- assert(d.has_year_zero==True)
+ assert d.has_year_zero is True
d = d.replace(year=0)
- assert(d.has_year_zero==True)
+ assert d.has_year_zero is True
# test leap year function
- assert(cftime.is_leap_year(2000,calendar='standard'))
- assert(cftime.is_leap_year(-1,calendar='standard'))
- assert(cftime.is_leap_year(0,calendar='standard',has_year_zero=True))
- assert(not cftime.is_leap_year(1,calendar='standard',has_year_zero=True))
- assert(not cftime.is_leap_year(1,calendar='365_day'))
- assert(cftime.is_leap_year(1,calendar='366_day'))
+ assert cftime.is_leap_year(2000,calendar='standard')
+ assert cftime.is_leap_year(-1,calendar='standard')
+ assert cftime.is_leap_year(0,calendar='standard',has_year_zero=True)
+ assert not cftime.is_leap_year(1,calendar='standard',has_year_zero=True)
+ assert not cftime.is_leap_year(1,calendar='365_day')
+ assert cftime.is_leap_year(1,calendar='366_day')
# num2date should not fail on an empty int array (issue #287)
d = cftime.num2date(np.array([], dtype="int64"), "days since 1970-01-01",\
calendar="proleptic_gregorian", only_use_cftime_datetimes=True)
+ # date2num should return an empty array if given one (issue #315)
+ d = cftime.date2num([], 'seconds since 2000-01-01 12:00:00')
+ assert d.size==0
+ # issue #328: handle nan/inf in num2date.
+ times = np.array([1,2,3,np.nan],dtype=np.float64)
+ expected = np.array([DatetimeGregorian(2000, 1, 2, 0, 0, 0, 0),
+ DatetimeGregorian(2000, 1, 3, 0, 0, 0, 0),
+ DatetimeGregorian(2000, 1, 4, 0, 0, 0, 0),
+ DatetimeGregorian(2000, 1, 5, 0, 0, 0, 0)])
+ mask = [False, False, False, True]
+ expected = np.ma.masked_array(expected, mask=mask)
+ result = cftime.num2date(times, 'days since 2000-01-01', 'standard')
+ np.testing.assert_equal(result, expected)
+ times = np.array([1,2,3,np.inf],dtype=np.float64)
+ result = cftime.num2date(times, 'days since 2000-01-01', 'standard')
+ np.testing.assert_equal(result, expected)
class TestDate2index(unittest.TestCase):
@@ -1034,7 +1053,7 @@ class TestDate2index(unittest.TestCase):
nutime = self.TestTime(datetime(1950, 1, 1), 366, 24,
'hours since 1900-01-01', 'standard')
try:
- t = date2index(datetime(1949, 2, 1), nutime)
+ _t = date2index(datetime(1949, 2, 1), nutime)
except ValueError:
pass
else:
@@ -1113,7 +1132,7 @@ class TestDate2index(unittest.TestCase):
dates2 = num2date(times2, units)
datediff = abs(dates-dates2)
for diff in datediff:
- assert(diff.microseconds < 100) # tolerance of 100 ms
+ assert diff.microseconds < 100 # tolerance of 100 ms
def test_issue444(self):
# make sure integer overflow not causing error in
@@ -1122,19 +1141,19 @@ class TestDate2index(unittest.TestCase):
query_time = datetime(2037, 1, 3, 21, 12)
index = date2index(query_time, self.time_vars['time3'],
select='nearest')
- assert(index == 11)
+ assert index == 11
def test_issue272(self):
timeArray = self.issue272time
date = datetime(2020, 2, 22, 13)
- assert(date2index(date, timeArray, calendar="gregorian",
- select="exact")==3)
- assert(date2index(date, timeArray, calendar="gregorian",
- select="before")==2)
- assert(date2index(date, timeArray, calendar="gregorian",
- select="after")==4)
- assert(date2index(date, timeArray, calendar="gregorian",
- select="nearest")==3)
+ assert date2index(date, timeArray, calendar="gregorian",
+ select="exact")==3
+ assert date2index(date, timeArray, calendar="gregorian",
+ select="before")==2
+ assert date2index(date, timeArray, calendar="gregorian",
+ select="after")==4
+ assert date2index(date, timeArray, calendar="gregorian",
+ select="nearest")==3
class issue584TestCase(unittest.TestCase):
@@ -1353,7 +1372,7 @@ class DateTime(unittest.TestCase):
deserialized = pickle.loads(pickle.dumps(date))
self.assertEqual(date, deserialized)
self.assertEqual(type(date), type(deserialized))
-
+
def test_misc(self):
"Miscellaneous tests."
# make sure repr succeeds
@@ -1511,7 +1530,7 @@ def days_per_month_leap_year(date_type, month):
def test_zero_year(date_type):
- # Year 0 is valid in the 360,365 and 366 day and
+ # Year 0 is valid in the 360,365 and 366 day and
# Proleptic Gregorian calendars by default.
with warnings.catch_warnings():
warnings.simplefilter("ignore",category=cftime.CFWarning)
@@ -1520,7 +1539,7 @@ def test_zero_year(date_type):
date_type(0, 1, 1)
else:
d=date_type(0,1,1) # has_year_zero=True set if year 0 specified
- assert(d.has_year_zero) # (issue #248)
+ assert d.has_year_zero # (issue #248)
with pytest.raises(ValueError):
date_type(0, 1, 1, has_year_zero=False)
@@ -1707,21 +1726,21 @@ def test_string_format2():
def test_strptime():
d = cftime.datetime.strptime('24/Aug/2004:17:57:26 +0200', '%d/%b/%Y:%H:%M:%S %z',calendar='julian',has_year_zero=True)
- assert(repr(d) == "cftime.datetime(2004, 8, 24, 15, 57, 26, 0, calendar='julian', has_year_zero=True)")
+ assert repr(d) == "cftime.datetime(2004, 8, 24, 15, 57, 26, 0, calendar='julian', has_year_zero=True)"
d = cftime.datetime.strptime("0000-02-30",\
"%Y-%m-%d",calendar='360_day',has_year_zero=True)
- assert(repr(d) == "cftime.datetime(0, 2, 30, 0, 0, 0, 0, calendar='360_day', has_year_zero=True)")
+ assert repr(d) == "cftime.datetime(0, 2, 30, 0, 0, 0, 0, calendar='360_day', has_year_zero=True)"
d = cftime.datetime.strptime('-9999-02-29 10:18:32.926',\
'%Y-%m-%d %H:%M:%S.%f',calendar='366_day')
- assert(repr(d) == "cftime.datetime(-9999, 2, 29, 10, 18, 32, 926000, calendar='all_leap', has_year_zero=True)")
+ assert repr(d) == "cftime.datetime(-9999, 2, 29, 10, 18, 32, 926000, calendar='all_leap', has_year_zero=True)"
d = cftime.datetime.strptime("20200230", "%Y%m%d", "360_day") # no separator, issue #301
- assert(repr(d) == "cftime.datetime(2020, 2, 30, 0, 0, 0, 0, calendar='360_day', has_year_zero=True)")
+ assert repr(d) == "cftime.datetime(2020, 2, 30, 0, 0, 0, 0, calendar='360_day', has_year_zero=True)"
d = cftime.datetime.strptime('24/Aug/-4712:17:57:26', '%d/%b/%Y:%H:%M:%S',calendar='julian')
- assert(repr(d) == "cftime.datetime(-4712, 8, 24, 17, 57, 26, 0, calendar='julian', has_year_zero=False)")
+ assert repr(d) == "cftime.datetime(-4712, 8, 24, 17, 57, 26, 0, calendar='julian', has_year_zero=False)"
d = cftime.datetime.strptime('24/August/-4712:17:57:26', '%d/%B/%Y:%H:%M:%S',calendar='julian')
- assert(repr(d) == "cftime.datetime(-4712, 8, 24, 17, 57, 26, 0, calendar='julian', has_year_zero=False)")
+ assert repr(d) == "cftime.datetime(-4712, 8, 24, 17, 57, 26, 0, calendar='julian', has_year_zero=False)"
d = cftime.datetime.strptime("-4712", "%Y", calendar="julian")
- assert(repr(d) == "cftime.datetime(-4712, 1, 1, 0, 0, 0, 0, calendar='julian', has_year_zero=False)")
+ assert repr(d) == "cftime.datetime(-4712, 1, 1, 0, 0, 0, 0, calendar='julian', has_year_zero=False)"
# should fail with KeyError
try:
d=cftime.datetime.strptime("2000-45-3", "%G-%V-%u", calendar="noleap")
@@ -2072,19 +2091,19 @@ def test_num2date_integer_upcast_required():
@pytest.mark.parametrize(
- "encoding_units",
+ "encoding_units",
["microseconds", "milliseconds", "seconds", "minutes", "hours", "days"]
)
@pytest.mark.parametrize(
"freq",
[
timedelta(microseconds=1),
- timedelta(microseconds=1000),
- timedelta(seconds=1),
- timedelta(minutes=1),
- timedelta(hours=1),
+ timedelta(microseconds=1000),
+ timedelta(seconds=1),
+ timedelta(minutes=1),
+ timedelta(hours=1),
timedelta(days=1)
- ],
+ ],
ids=lambda x: f"{x!r}"
)
def test_date2num_num2date_roundtrip(encoding_units, freq, calendar):
@@ -2092,8 +2111,8 @@ def test_date2num_num2date_roundtrip(encoding_units, freq, calendar):
lengthy_timedelta = timedelta(days=291000 * 360)
times = np.array(
[
- date_type(1, 1, 1),
- date_type(1, 1, 1) + lengthy_timedelta,
+ date_type(1, 1, 1),
+ date_type(1, 1, 1) + lengthy_timedelta,
date_type(1, 1, 1) + lengthy_timedelta + freq
]
)
@@ -2140,7 +2159,7 @@ def test_date2num_missing_data():
def test_num2date_preserves_shape():
# The optimized num2date algorithm operates on a flattened array. This
- # check ensures that the original shape of the times is restored in the
+ # check ensures that the original shape of the times is restored in the
# result.
a = np.array([[0, 1, 2], [3, 4, 5]])
result = num2date(a, units="days since 2000-01-01", calendar="standard")
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/-/compare/6b43c18db17058cb374a495d808f6a048ea243de...01e1d54f3e2ddec92acf278907af334abf4f7be1
--
This project does not include diff previews in email notifications.
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/-/compare/6b43c18db17058cb374a495d808f6a048ea243de...01e1d54f3e2ddec92acf278907af334abf4f7be1
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20240607/5fcd6c08/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list