Skip to content

Commit

Permalink
Add config option to control fast parser and test
Browse files Browse the repository at this point in the history
  • Loading branch information
taldcroft committed Sep 25, 2020
1 parent d9ddab3 commit b66d37a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 17 deletions.
20 changes: 19 additions & 1 deletion cxotime/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from .cxotime import CxoTime
import ska_helpers
from astropy import config as _config

__version__ = ska_helpers.get_version(__package__)


class Conf(_config.ConfigNamespace): # noqa
"""
Configuration parameters for `astropy.table`.
"""

use_fast_parser = _config.ConfigItem(
['True', 'False', 'force'],
"Use fast C parser for supported time strings formats, including ISO, "
"ISOT, and YearDayTime. Allowed values are the 'False' (use Python parser),"
"'True' (use C parser and fall through to Python parser if fails), and "
"'force' (use C parser and raise exception if it fails). Note that the"
"options are all strings.")

conf = Conf() # noqa

from .cxotime import CxoTime # noqa


def test(*args, **kwargs):
'''
Run py.test unit tests.
Expand Down
22 changes: 18 additions & 4 deletions cxotime/cxotime.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from astropy.utils import iers
from astropy import _erfa as erfa

from cxotime import conf

# For working in Chandra operations, possibly with no network access, we cannot
# allow auto downloads.
iers.conf.auto_download = False
Expand Down Expand Up @@ -168,14 +170,19 @@ def set_jds_fast_or_python(self, val1, val2):
# If specific input subformat is required then use the Python parser.
# Also do this if Time format class does not define `use_fast_parser`
# or if the fast parser is entirely disabled.
if self.in_subfmt != '*':
self.set_jds_python(self, val1, val2)
if (self.in_subfmt != '*'
or not self.__class__.__dict__.get('use_fast_parser')
or conf.use_fast_parser == 'False'):
self.set_jds_python(val1, val2)
else:
try:
self.set_jds_fast(val1)
except Exception:
# Fall through to the Python parser.
self.set_jds_python(self, val1, val2)
# Fall through to the Python parser unless fast is forced.
if conf.use_fast_parser == 'force':
raise
else:
self.set_jds_python(val1, val2)

def set_jds_fast(self, val1):
"""Use fast C parser to parse time strings in val1 and set jd1, jd2"""
Expand Down Expand Up @@ -283,6 +290,7 @@ class TimeDate(TimeYearDayTime, FastDateParserMixin):
name = 'date'

# Class attributes for fast C-parsing
use_fast_parser = True
delims = (0, 0, ord(':'), ord(':'), ord(':'), ord(':'), ord('.'))
starts = (0, -1, 4, 8, 11, 14, 17)
stops = (3, -1, 7, 10, 13, 16, -1)
Expand Down Expand Up @@ -348,6 +356,7 @@ class TimeGreta(TimeDate, FastDateParserMixin):
# stops: position where component ends (-1 => continue to end of string)

# Before: yr mon doy hour minute second frac
use_fast_parser = True
delims = (0, 0, 0, ord('.'), 0, 0, 0)
starts = (0, -1, 4, 7, 10, 12, 14)
stops = (3, -1, 6, 9, 11, 13, -1)
Expand Down Expand Up @@ -375,6 +384,11 @@ def set_jds(self, val1, val2):

self.set_jds_fast_or_python(val1, val2)

def set_jds_python(self, val1, val2):
# Reformat from YYYYDDD.HHMMSSsss to YYYYDDDHHMMSS.sss
val1 = np.array([x[:7] + x[8:14] + '.' + x[14:] for x in val1.flat]).reshape(val1.shape)
super().set_jds_python(val1, val2)

def to_value(self, parent=None, **kwargs):
if self.scale == 'utc':
out1 = super().value
Expand Down
37 changes: 25 additions & 12 deletions cxotime/tests/test_cxotime.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
Simple test of CxoTime. The base Time object is extremely well
tested, so this simply confirms that the add-on in CxoTime works.
"""

import pytest
import numpy as np

from .. import CxoTime
from .. import CxoTime, conf
from astropy.time import Time
from Chandra.Time import DateTime
import astropy.units as u


def test_cxotime_basic():
@pytest.fixture(scope='module', params=['True', 'False', 'force'])
def use_fast_parser(request):
conf.use_fast_parser = request.param
yield
conf.use_fast_parser = 'True'


def test_cxotime_basic(use_fast_parser):
t = CxoTime(1)
assert t.format == 'secs'
assert t.scale == 'utc'
Expand All @@ -38,8 +44,15 @@ def test_cxotime_basic():
t = CxoTime('1998:001:00:00:01.000', scale='tt')


# @pytest.mark.parmetrize('use_fast_parser', ['True', 'False', 'force'])
# @pytest.mark.parametrize('now_method', [CxoTime, CxoTime.now])
# def test_cxotime_now(use_fast_parser, now_method):
# with conf.set_temp('use_fast_parser', use_fast_parser):
# _test_cxotime_basic(now_method)


@pytest.mark.parametrize('now_method', [CxoTime, CxoTime.now])
def test_cxotime_now(now_method):
def test_cxotime_now(use_fast_parser, now_method):
ct_now = now_method()
t_now = Time.now()
assert t_now >= ct_now
Expand All @@ -50,7 +63,7 @@ def test_cxotime_now(now_method):
CxoTime(scale='utc')


def test_cxotime_from_datetime():
def test_cxotime_from_datetime(use_fast_parser):
secs = DateTime(np.array(['2000:001', '2015:181:23:59:60.500', '2015:180:01:02:03.456'])).secs
dts = DateTime(secs)
ct = CxoTime(dts)
Expand All @@ -65,7 +78,7 @@ def test_cxotime_from_datetime():
assert np.allclose(vals_out, getattr(dts, out_fmt), atol=1e-4, rtol=0)


def test_cxotime_vs_datetime():
def test_cxotime_vs_datetime(use_fast_parser):
# Note the bug (https://github.com/sot/Chandra.Time/issues/21), hence the odd first two lines
# >>> DateTime('2015:181:23:59:60.500').date
# '2015:182:00:00:00.500'
Expand All @@ -88,7 +101,7 @@ def test_cxotime_vs_datetime():
assert np.allclose(vals_out, vals[out_fmt], atol=1e-4, rtol=0)


def test_secs():
def test_secs(use_fast_parser):
"""
Test a problem fixed in https://github.com/astropy/astropy/pull/4312.
This test would pass for ``t = CxoTime(1, scale='tt')`` or if
Expand All @@ -99,7 +112,7 @@ def test_secs():
assert np.allclose(t.value, 1.0, atol=1e-10, rtol=0)


def test_date():
def test_date(use_fast_parser):
t = CxoTime('2001:002:03:04:05.678')
assert t.format == 'date'
assert t.scale == 'utc'
Expand All @@ -108,7 +121,7 @@ def test_date():
assert CxoTime('2015-06-30 23:59:60.5').date == '2015:181:23:59:60.500'


def test_arithmetic():
def test_arithmetic(use_fast_parser):
"""Very basic test of arithmetic"""
t1 = CxoTime(0.0)
t2 = CxoTime(86400.0)
Expand All @@ -120,14 +133,14 @@ def test_arithmetic():
assert isinstance(t3, CxoTime)


def test_frac_year():
def test_frac_year(use_fast_parser):
t = CxoTime(2000.5, format='frac_year')
assert t.date == '2000:184:00:00:00.000'
t = CxoTime('2000:184:00:00:00.000')
assert t.frac_year == 2000.5


def test_greta():
def test_greta(use_fast_parser):
"""Test greta format"""
t_in = [['2001002.030405678', '2002002.030405678'],
['2003002.030405678', '2004002.030405678']]
Expand All @@ -148,7 +161,7 @@ def test_greta():
assert CxoTime('2015181.235960500').date == '2015:181:23:59:60.500'


def test_scale_exception():
def test_scale_exception(use_fast_parser):
with pytest.raises(ValueError, match="must use scale 'utc' for format 'secs'"):
CxoTime(1, scale='tt')

Expand Down

0 comments on commit b66d37a

Please sign in to comment.