Skip to content

Commit

Permalink
Merge pull request #50 from sot/cxotime-now-environment-override
Browse files Browse the repository at this point in the history
Use `CXOTIME_NOW` environment variable as current time if set
  • Loading branch information
taldcroft authored Feb 8, 2025
2 parents a724f62 + 9864220 commit 9cd4281
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 29 deletions.
6 changes: 4 additions & 2 deletions cxotime/cxotime.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
import os
import sys
import warnings
from copy import copy
Expand Down Expand Up @@ -131,8 +132,9 @@ def __init__(self, *args, **kwargs):
if kwargs.setdefault("format", "date") != "date":
raise ValueError("must use format 'date' for DateTime input")
else:
# For `CxoTime()`` return the current time in `date` format.
args = (Time.now().yday,)
# For `CxoTime()`` return the current time in `date` format or the value
# of the envionment variable CXOTIME_NOW if set.
args = (os.environ.get("CXOTIME_NOW", Time.now().yday),)

# If format is supplied and is a DateTime format then require scale='utc'.
fmt = kwargs.get("format")
Expand Down
29 changes: 26 additions & 3 deletions cxotime/tests/test_cxotime.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,27 @@ def test_convert_time_format_obj():
assert tm.date == convert_time_format(tm, "date")


def test_with_object_input():
"""Check CxoTime fails when called with an object() that is not CxoTime.NOW"""
with pytest.raises(ValueError):
CxoTime(object())


@pytest.mark.parametrize("fmt", ["date", "iso", "greta"])
def test_cxotime_now_env_var(monkeypatch, fmt):
"""Check instantiating with CxoTime.NOW results in current time."""
tm = CxoTime("2015:160:02:24:01.250")
date = tm.date
monkeypatch.setenv("CXOTIME_NOW", getattr(tm, fmt))
assert CxoTime(CxoTime.NOW).date == date
assert CxoTime(None).date == date
assert CxoTime().date == date
assert CxoTime.now().date == date

# Ensure that env var does not disrupt normal operation
assert CxoTime("2025:001:00:00:01.250").date == "2025:001:00:00:01.250"


def test_cxotime_descriptor_not_required_no_default():
@dataclass
class MyClass:
Expand Down Expand Up @@ -527,19 +548,21 @@ def test_cxotime_descriptor_with_NOW():
class MyData:
stop: CxoTime = CxoTimeDescriptor(default=CxoTime.NOW)

dt_max = 0.2 # sec. Apparently on VM Windows there can be long delays.

# Make a new object and check that the stop time is approximately the current time.
obj1 = MyData()
assert (CxoTime.now() - obj1.stop).sec < 0.1
assert abs((CxoTime.now() - obj1.stop).sec) < dt_max

# Wait for 0.5 second and make a new object and check that the stop time is 0.5
# second later. This proves the NOW sentinel is evaluated at object creation time
# not class definition time.
time.sleep(0.5)
obj2 = MyData()
dt = obj2.stop - obj1.stop
assert round(dt.sec, 1) == 0.5
assert abs(dt.sec - 0.5) < dt_max

time.sleep(0.5)
obj2.stop = CxoTime.NOW
dt = obj2.stop - obj1.stop
assert round(dt.sec, 1) == 1.0
assert abs(dt.sec - 1.0) < dt_max
77 changes: 53 additions & 24 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,36 @@ method:
'local': '2022 Sun Jan 02 07:00:00 AM EST',
'unix': 1641124800.0}

CxoTime.NOW
-----------
Handling current time
---------------------

The |CxoTime| class has a special value ``CxoTime.NOW`` which signifies the current time
For convenience and compatibility with the DateTime_ class, |CxoTime| provides several
equivalent ways to specify the current time:

>>> CxoTime.now() # Preferred method since it is explicit
>>> CxoTime()
>>> CxoTime(None)
>>> CxoTime(CxoTime.NOW)

See below for situations where you should use ``CxoTime.NOW``.

``CXOTIME_NOW`` environment variable
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``CXOTIME_NOW`` environment variable can be used to override the default current
time. This is useful for testing or for running Ska Python code that needs to be
reproducible.

For example, to set the current time to 2022-01-01 00:00:00.000:

>>> import os
>>> os.environ['CXOTIME_NOW'] = '2022-01-01 00:00:00.000'
>>> CxoTime.now().date
'2022:001:00:00:00.000'

``CxoTime.NOW`` sentinel
^^^^^^^^^^^^^^^^^^^^^^^^

The |CxoTime| class has a special attribute ``CxoTime.NOW`` which signifies the current time
when used to initialize a |CxoTime| object. This is commonly useful for example when
defining a function that has accepts a CxoTime-like argument that defaults to the
current time.
Expand All @@ -244,34 +270,37 @@ current time.

For example:

>>> from cxotime import CxoTime
>>> def my_func(stop=CxoTime.NOW):
>>> import os
>>> from cxotime import CxoTime, CxoTimeLike
>>> os.environ['CXOTIME_NOW'] = '2022-01-01 00:00:00.000'
>>> def my_func(stop: CxoTimeLike=CxoTime.NOW):
... stop = CxoTime(stop)
... print(stop)
...
>>> my_func()
2024:006:11:37:41.930
2022-01-01 00:00:00.000

This can also be used in a `dataclass
<https://docs.python.org/3/library/dataclasses.html>`_ to specify an attribute that is
optional and defaults to the current time when the object is created::

>>> import time
>>> from dataclasses import dataclass
>>> from cxotime import CxoTime, CxoTimeDescriptor
>>> @dataclass
... class MyData:
... start: CxoTime = CxoTimeDescriptor(required=True)
... stop: CxoTime = CxoTimeDescriptor(default=CxoTime.NOW)
...
>>> obj1 = MyData("2022:001")
>>> print(obj1.start)
2022:001:00:00:00.000
>>> time.sleep(2)
>>> obj2 = MyData("2022:001")
>>> dt = obj2.stop - obj1.stop
>>> round(dt.sec, 2)
2.0
optional and defaults to the current time when the object is created:

>>> import time
>>> from dataclasses import dataclass
>>> from cxotime import CxoTime, CxoTimeDescriptor
>>> @dataclass
... class MyData:
... start: CxoTime = CxoTimeDescriptor(required=True)
... stop: CxoTime = CxoTimeDescriptor(default=CxoTime.NOW)
...
>>> obj1 = MyData("2022:001")
>>> obj1.start
'2022:001:00:00:00.000'
>>> time.sleep(2)
>>> obj2 = MyData("2022:001")
>>> dt = obj2.stop - obj1.stop
>>> round(dt.sec, 1)
2.0


Compatibility with DateTime
---------------------------
Expand Down

0 comments on commit 9cd4281

Please sign in to comment.