Skip to content

Commit

Permalink
Merge pull request #4 from jepler/py.types
Browse files Browse the repository at this point in the history
Add PEP0561 py.typed, convert to package
  • Loading branch information
jepler authored Mar 23, 2022
2 parents 15135d0 + dd95841 commit a83d6a4
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 43 deletions.
48 changes: 7 additions & 41 deletions leapseconddata.py → leapseconddata/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"""

from __future__ import annotations
import datetime
import hashlib
import io
Expand Down Expand Up @@ -97,7 +98,7 @@ def __new__(
leap_seconds: List[LeapSecondInfo],
valid_until: Optional[datetime.datetime] = None,
last_updated: Optional[datetime.datetime] = None,
) -> "LeapSecondData":
) -> LeapSecondData:
return super().__new__(cls, leap_seconds, valid_until, last_updated)

def _check_validity(self, when: Optional[datetime.datetime]) -> Optional[str]:
Expand Down Expand Up @@ -211,7 +212,7 @@ def from_standard_source(
cls,
when: Optional[datetime.datetime] = None,
check_hash: bool = True,
) -> "LeapSecondData":
) -> LeapSecondData:
"""Get the list of leap seconds from a standard source.
:param when: Check that the data is valid for this moment
Expand Down Expand Up @@ -248,7 +249,7 @@ def from_file(
cls,
filename: str = "/usr/share/zoneinfo/leap-seconds.list",
check_hash: bool = True,
) -> "LeapSecondData":
) -> LeapSecondData:
"""Retrieve the leap second list from a local file.
:param filename: Local filename to read leap second data from. The
Expand All @@ -263,7 +264,7 @@ def from_url(
cls,
url: str = "https://www.ietf.org/timezones/data/leap-seconds.list",
check_hash: bool = True,
) -> "Optional[LeapSecondData]":
) -> Optional[LeapSecondData]:
"""Retrieve the leap second list from a local file
:param filename: URL to read leap second data from. The
Expand All @@ -281,7 +282,7 @@ def from_data(
cls,
data: Union[bytes, str],
check_hash: bool = True,
) -> "LeapSecondData":
) -> LeapSecondData:
"""Retrieve the leap second list from local data
:param data: Data to parse as a leap second list
Expand All @@ -303,7 +304,7 @@ def _parse_content_hash(row: bytes) -> str:
@classmethod
def from_open_file(
cls, open_file: BinaryIO, check_hash: bool = True
) -> "LeapSecondData":
) -> LeapSecondData:
"""Retrieve the leap second list from an open file-like object
:param open_file: Binary IO object containing the leap second list
Expand Down Expand Up @@ -358,38 +359,3 @@ def from_open_file(
)

return LeapSecondData(leap_seconds, valid_until, last_updated)


def main() -> None:
"""When run as a main program, print some information about leap seconds"""
logging.getLogger().setLevel(logging.INFO)
lsd = LeapSecondData.from_standard_source()
print(f"Last updated: {lsd.last_updated:%Y-%m-%d}")
print(f"Valid until: {lsd.valid_until:%Y-%m-%d}")
for when, offset in lsd.leap_seconds[-10:]:
print(f"{when:%Y-%m-%d}: {offset.total_seconds()}")
when = datetime.datetime(2011, 1, 1, tzinfo=datetime.timezone.utc)
print(f"TAI-UTC on {when:%Y-%m-%d} was {lsd.tai_offset(when).total_seconds()}")

when_tai = lsd.to_tai(when)
when_rt = lsd.tai_to_utc(when_tai)
print(f"{when:%Y-%m-%d %H:%M:%S} UTC -> {when_tai:%Y-%m-%d %H:%M:%S} TAI")
print(f"{when_tai:%Y-%m-%d %H:%M:%S} TAI -> {when_rt:%Y-%m-%d %H:%M:%S} UTC")
print(f"is leap second? {lsd.is_leap_second(when)}")

u = datetime.datetime(
1999, 1, 1, tzinfo=datetime.timezone.utc
) - datetime.timedelta(seconds=2)
t = lsd.to_tai(u)

print("replaying leapsecond at end of 1998")
for _ in range(5):
print(
f"{u:%Y-%m-%d %H:%M:%S} UTC {'LS' if lsd.is_leap_second(u) else ' '} = {t:%Y-%m-%d %H:%M:%S} TAI {'LS' if lsd.is_leap_second(t) else ' '}"
)
t += datetime.timedelta(seconds=1)
u = lsd.tai_to_utc(t)


if __name__ == "__main__": # pragma no cover
main()
48 changes: 48 additions & 0 deletions leapseconddata/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# SPDX-FileCopyrightText: 2022 Jeff Epler
#
# SPDX-License-Identifier: GPL-3.0-only

"""
Smoke test program for leapseconddata
If this was a useful program, it would be exposed as an entry point in setup.cfg.
"""

import datetime
import logging
from . import LeapSecondData


def main() -> None:
"""When run as a main program, print some information about leap seconds"""
logging.getLogger().setLevel(logging.INFO)
lsd = LeapSecondData.from_standard_source()
print(f"Last updated: {lsd.last_updated:%Y-%m-%d}")
print(f"Valid until: {lsd.valid_until:%Y-%m-%d}")
for when, offset in lsd.leap_seconds[-10:]:
print(f"{when:%Y-%m-%d}: {offset.total_seconds()}")
when = datetime.datetime(2011, 1, 1, tzinfo=datetime.timezone.utc)
print(f"TAI-UTC on {when:%Y-%m-%d} was {lsd.tai_offset(when).total_seconds()}")

when_tai = lsd.to_tai(when)
when_rt = lsd.tai_to_utc(when_tai)
print(f"{when:%Y-%m-%d %H:%M:%S} UTC -> {when_tai:%Y-%m-%d %H:%M:%S} TAI")
print(f"{when_tai:%Y-%m-%d %H:%M:%S} TAI -> {when_rt:%Y-%m-%d %H:%M:%S} UTC")
print(f"is leap second? {lsd.is_leap_second(when)}")

u = datetime.datetime(
1999, 1, 1, tzinfo=datetime.timezone.utc
) - datetime.timedelta(seconds=2)
t = lsd.to_tai(u)

print("replaying leapsecond at end of 1998")
for _ in range(5):
print(
f"{u:%Y-%m-%d %H:%M:%S} UTC {'LS' if lsd.is_leap_second(u) else ' '} = {t:%Y-%m-%d %H:%M:%S} TAI {'LS' if lsd.is_leap_second(t) else ' '}"
)
t += datetime.timedelta(seconds=1)
u = lsd.tai_to_utc(t)


if __name__ == "__main__": # pragma no cover
main()
Empty file added leapseconddata/py.typed
Empty file.
7 changes: 6 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ classifiers =
Operating System :: OS Independent

[options]
package_dir =
=.
python_requires = >=3.7
py_modules = leapseconddata
packages = leapseconddata

[options.package_data]
leapseconddata = py.typed
3 changes: 2 additions & 1 deletion testleapseconddata.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import datetime
import unittest
import leapseconddata
import leapseconddata.__main__

db = leapseconddata.LeapSecondData.from_standard_source()

Expand All @@ -17,7 +18,7 @@

class LeapSecondDataTest(unittest.TestCase):
def test_main(self) -> None: # pylint: disable=no-self-use
leapseconddata.main()
leapseconddata.__main__.main()

def test_corrupt(self) -> None:
self.assertRaises(
Expand Down

0 comments on commit a83d6a4

Please sign in to comment.