Skip to content
Commits on Source (4)
......@@ -45,8 +45,8 @@ script:
- if [[ "${BUILD_DOCS}" == "true" ]]; then
pushd docs && make html linkcheck O=-W && popd;
else
pytest -v;
fi;
pytest;
fi
after_success:
- coveralls
......@@ -65,4 +65,4 @@ deploy:
skip_cleanup: true
on:
branch: master
condition: '${PYTHON_VERSION} == 3.7 AND ${BUILD_DOCS} == "true"'
condition: '${PYTHON_VERSION} == 3.7 && ${BUILD_DOCS} == "true"'
......@@ -3,3 +3,4 @@ include README.md
include COPYING
recursive-include cftime *.py
recursive-include cftime *.pyx
recursive-exclude cftime *.c
......@@ -5,8 +5,18 @@ Time-handling functionality from netcdf4-python
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/fl9taa9je4e6wi7n/branch/master?svg=true)](https://ci.appveyor.com/project/jswhit/cftime/branch/master)
[![PyPI package](https://badge.fury.io/py/cftime.svg)](http://python.org/pypi/cftime)
[![Coverage Status](https://coveralls.io/repos/github/Unidata/cftime/badge.svg?branch=master)](https://coveralls.io/github/Unidata/cftime?branch=master)
[![Tag Status](https://img.shields.io/github/tag/UniData/cftime.svg)](https://github.com/Unidata/cftime/tags)
[![Release Status](https://img.shields.io/github/release/UniData/cftime.svg)](https://github.com/Unidata/cftime/releases)
[![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.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
when cython not installed, regression on 32-bit platforms, workaround for pandas
compatibility).
12/01/2018: version 1.0.3 released. Test coverage with coveralls.io, improved round-tripping accuracy for non-real world calendars (like `360_day`).
10/27/2018: version 1.0.2 released. Improved accuracy (from approximately 1000 microseconds to 10 microseconds on x86
......
* create a release branch ('vX.Y.Zrel'). In the release branch...
* make sure version number in cftime/_cftime.pyx is correct.
* update README.md as needed.
* commit and push all of the above changes.
* create a pull request for the release branch.
* After release branch has been merged, tag a release
% git tag -a vX.Y.Zrel -m "version X.Y.Z release"
% git push origin --tags
Then create a release on github from that tag.
* Update the BUILD_COMMIT variable in .travis.yml and appveyor.yml
in https://github.com/MacPython/cftime-wheels.
Push those changes to trigger the binary wheel builds (for
macos x, linux and windows).
* Download the binary wheels from wheels.scipy.org, put them in a
directory called 'upload'. Create a source tarball using
% python setup.py clean
% python setup.py clean_cython
% python setup.py sdist
Add the source tarball to the 'upload' directory.
* upload the release files to pypi with twine
(twine upload upload/*). This will require creating a ~/.pypirc
file with your pypi login credentials.
......@@ -42,7 +42,7 @@ cdef int[13] _spm_366day = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 33
_rop_lookup = {Py_LT: '__gt__', Py_LE: '__ge__', Py_EQ: '__eq__',
Py_GT: '__lt__', Py_GE: '__le__', Py_NE: '__ne__'}
__version__ = '1.0.3'
__version__ = '1.0.3.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.
......@@ -65,6 +65,7 @@ class real_datetime(datetime_python):
@property
def dayofyr(self):
return self.timetuple().tm_yday
nanosecond = 0 # workaround for pandas bug (cftime issue #77)
# start of the gregorian calendar
gregorian = real_datetime(1582,10,15)
......@@ -455,7 +456,7 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=False,
# get the day (Z) and the fraction of the day (F)
# use 'round half up' rounding instead of numpy's even rounding
# so that 0.5 is rounded to 1.0, not 0 (cftime issue #49)
Z = np.int32(_round_half_up(julian))
Z = np.atleast_1d(np.int32(_round_half_up(julian)))
F = (julian + 0.5 - Z).astype(np.longdouble)
cdef Py_ssize_t i_max = len(Z)
......@@ -498,7 +499,7 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=False,
# recomputing year,month,day etc
# ms_eps is proportional to julian day,
# about 47 microseconds in 2000 for Julian base date in -4713
ms_eps = np.array(np.finfo(np.float64).eps,np.longdouble)
ms_eps = np.atleast_1d(np.array(np.finfo(np.float64).eps,np.longdouble))
ms_eps = 86400000000.*np.maximum(ms_eps*julian, ms_eps)
microsecond = np.where(microsecond < ms_eps, 0, microsecond)
indxms = microsecond > 1000000-ms_eps
......
......@@ -2,6 +2,7 @@
testpaths = test
addopts =
-ra
-v
--doctest-modules
--cov-config .coveragerc
--cov=cftime
......
......@@ -3,14 +3,20 @@ from __future__ import print_function
import os
import sys
from Cython.Build import cythonize
from setuptools import Command, Extension, setup
# https://github.com/Unidata/cftime/issues/34
try:
from Cython.Build import cythonize
except ImportError:
cythonize = False
BASEDIR = os.path.abspath(os.path.dirname(__file__))
CMDS_NOCYTHONIZE = ['clean','clean_cython','sdist']
COMPILER_DIRECTIVES = {}
DEFINE_MACROS = None
FLAG_COVERAGE = '--cython-coverage' # custom flag enabling Cython line tracing
BASEDIR = os.path.abspath(os.path.dirname(__file__))
NAME = 'cftime'
CFTIME_DIR = os.path.join(BASEDIR, NAME)
CYTHON_FNAME = os.path.join(CFTIME_DIR, '_{}.pyx'.format(NAME))
......@@ -64,7 +70,8 @@ def description():
return result
if FLAG_COVERAGE in sys.argv or os.environ.get('CYTHON_COVERAGE', None):
if ((FLAG_COVERAGE in sys.argv or os.environ.get('CYTHON_COVERAGE', None))
and cythonize):
COMPILER_DIRECTIVES = {'linetrace': True,
'warn.maybe_uninitialized': False,
'warn.unreachable': False,
......@@ -75,9 +82,18 @@ if FLAG_COVERAGE in sys.argv or os.environ.get('CYTHON_COVERAGE', None):
sys.argv.remove(FLAG_COVERAGE)
print('enable: "linetrace" Cython compiler directive')
extension = Extension('{}._{}'.format(NAME, NAME),
sources=[CYTHON_FNAME],
define_macros=DEFINE_MACROS)
# See https://github.com/Unidata/cftime/issues/91
if any([arg in CMDS_NOCYTHONIZE for arg in sys.argv]):
ext_modules = []
else:
extension = Extension('{}._{}'.format(NAME, NAME),
sources=[CYTHON_FNAME],
define_macros=DEFINE_MACROS)
ext_modules = [extension]
if cythonize:
ext_modules = cythonize(extension,
compiler_directives=COMPILER_DIRECTIVES,
language_level=2)
setup(
name=NAME,
......@@ -89,9 +105,18 @@ setup(
cmdclass={'clean_cython': CleanCython},
packages=[NAME],
version=extract_version(),
ext_modules=cythonize(extension,
compiler_directives=COMPILER_DIRECTIVES,
language_level=2),
ext_modules=ext_modules,
setup_requires=load('setup.txt'),
install_requires=load('requirements.txt'),
tests_require=load('requirements-dev.txt'))
tests_require=load('requirements-dev.txt'),
classifiers=[
'Development Status :: 5 - Production/Stable',
'Operating System :: MacOS :: MacOS X',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Scientific/Engineering',
'License :: OSI Approved'])
from cftime import num2date, date2num
import time
try:
from time import perf_counter
except ImportError:
from time import clock as perf_counter
import numpy as np
units = 'hours since 01-01-01'
calendar = 'standard'
timevals = np.arange(0,10000,1)
print('processing %s values...' % len(timevals))
t1 = time.clock()
t1 = perf_counter()
dates =\
num2date(timevals,units=units,calendar=calendar,only_use_cftime_datetimes=True)
t2 = time.clock()
t2 = perf_counter()
t = t2-t1
print('num2date took %s seconds' % t)
timevals2 = date2num(dates,units=units,calendar=calendar)
t1 = time.clock()
t1 = perf_counter()
t = t1-t2
print('date2num took %s seconds' % t)
......@@ -354,7 +354,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (microsecs) = %s eps = %s' % \
print('calendar = %s max abs err (microsecs) = %s eps = %s' % \
(calendar,maxerr,eps))
units = 'milliseconds since 1800-01-30 01:01:01'
eps = 0.1
......@@ -370,7 +370,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (millisecs) = %s eps = %s' % \
print('calendar = %s max abs err (millisecs) = %s eps = %s' % \
(calendar,maxerr,eps))
eps = 1.e-3
units = 'seconds since 0001-01-30 01:01:01'
......@@ -386,7 +386,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (secs) = %s eps = %s' % \
print('calendar = %s max abs err (secs) = %s eps = %s' % \
(calendar,maxerr,eps))
eps = 1.e-5
units = 'minutes since 0001-01-30 01:01:01'
......@@ -402,7 +402,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (mins) = %s eps = %s' % \
print('calendar = %s max abs err (mins) = %s eps = %s' % \
(calendar,maxerr,eps))
eps = 1.e-6
units = 'hours since 0001-01-30 01:01:01'
......@@ -418,7 +418,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (hours) = %s eps = %s' % \
print('calendar = %s max abs err (hours) = %s eps = %s' % \
(calendar,maxerr,eps))
eps = 1.e-8
units = 'days since 0001-01-30 01:01:01'
......@@ -434,7 +434,7 @@ class cftimeTestCase(unittest.TestCase):
assert(err < eps)
assert(date1.strftime(dateformat) == date2.strftime(dateformat))
if verbose:
print('calender = %s max abs err (days) = %s eps = %s' % \
print('calendar = %s max abs err (days) = %s eps = %s' % \
(calendar,maxerr,eps))
# issue 353
......