Merge pull request #21 from jepler/document-data-sources
Update & document data sources
This commit is contained in:
commit
9817b72ffd
6 changed files with 76 additions and 14 deletions
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
|
@ -67,7 +67,7 @@ jobs:
|
|||
run: make mypy
|
||||
|
||||
- name: Test
|
||||
run: python -mcoverage run --branch -m unittest testleapseconddata.py && python -mcoverage report --fail-under=100 && python -mcoverage xml
|
||||
run: python -X tracemalloc=3 -mcoverage run --branch -m unittest testleapseconddata.py && python -mcoverage report --fail-under=100 && python -mcoverage xml
|
||||
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ templates_path = ['_templates']
|
|||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '_env']
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import pathlib
|
|||
import re
|
||||
import urllib.request
|
||||
from dataclasses import dataclass, field
|
||||
from typing import BinaryIO
|
||||
from typing import BinaryIO, ClassVar
|
||||
|
||||
tai = datetime.timezone(datetime.timedelta(0), "TAI")
|
||||
|
||||
|
|
@ -76,6 +76,49 @@ class LeapSecondData:
|
|||
:param Optional[datetime.datetime] updated: The last update time of the data
|
||||
"""
|
||||
|
||||
standard_file_sources: ClassVar[list[str]] = [
|
||||
"file:///usr/share/zoneinfo/leap-seconds.list", # Debian Linux
|
||||
"file:///var/db/ntpd.leap-seconds.list", # FreeBSD
|
||||
]
|
||||
"""When using `LeapSecondData.from_standard_source`, these local sources are checked first.
|
||||
|
||||
Locations for Debian Linux & FreeBSD are supported."""
|
||||
|
||||
standard_network_sources: ClassVar[list[str]] = [
|
||||
"https://hpiers.obspm.fr/iers/bul/bulc/ntp/leap-seconds.list",
|
||||
"https://data.iana.org/time-zones/tzdb/leap-seconds.list",
|
||||
"https://raw.githubusercontent.com/eggert/tz/main/leap-seconds.list",
|
||||
"ftp://ftp.boulder.nist.gov/pub/time/leap-seconds.list",
|
||||
"https://www.meinberg.de/download/ntp/leap-seconds.list",
|
||||
]
|
||||
"""When using `LeapSecondData.from_standard_source`, these network sources are checked second.
|
||||
|
||||
Remote sources are checked in the following order until a suitable file is found:
|
||||
|
||||
* The `International Earth Rotation Service (IERS)
|
||||
<https://www.iers.org/IERS/EN/Home/home_node.html>`_ is the international
|
||||
body charged with various duties including scheduling leap seconds.
|
||||
* The `Internet Assigned Numbers Authority (IANA)
|
||||
<https://www.iana.org/>`_ publishes the IANA timezone database, used by
|
||||
many major operating sytsems for handling the world's time zones. As part
|
||||
of this activity they publish a version of the leap second list.
|
||||
* `eggert/tz <https://github.com/eggert/tz>`_ is the canonical github home
|
||||
of the IANA timezone database, and updated versions of the leap second
|
||||
list can appear here before they are part of an official IANA timezone
|
||||
database release.
|
||||
* `The National Institute of Standards and Technology (NIST)'s Time
|
||||
Realization and Distribution Group
|
||||
<https://www.nist.gov/pml/time-and-frequency-division/time-distribution/internet-time-service-its>`_
|
||||
is a US federal organization that publishes a version of the leap second
|
||||
database.
|
||||
* `Meinberg Funkuhren GmbH & Co. KG
|
||||
<https://www.meinbergglobal.com/english/company/>`_ is a Germany-based
|
||||
company that published a `helpful article in its knowledge base
|
||||
<https://kb.meinbergglobal.com/kb/time_sync/ntp/configuration/ntp_leap_second_file>`_
|
||||
including URLs of sites that disseminate the leap second list. They state
|
||||
that the version they distribute is frequently more up to date than other
|
||||
sources, including IANA, NIST, and tzdb."""
|
||||
|
||||
leap_seconds: list[LeapSecondInfo]
|
||||
"""All known and scheduled leap seconds"""
|
||||
|
||||
|
|
@ -204,12 +247,7 @@ class LeapSecondData:
|
|||
leap-second.list data valid for the given timestamp, or the current
|
||||
time (if unspecified)
|
||||
"""
|
||||
for location in [ # pragma no branch
|
||||
"file:///usr/share/zoneinfo/leap-seconds.list", # Debian Linux
|
||||
"file:///var/db/ntpd.leap-seconds.list", # FreeBSD
|
||||
"https://raw.githubusercontent.com/eggert/tz/main/leap-seconds.list",
|
||||
"https://www.meinberg.de/download/ntp/leap-seconds.list",
|
||||
]:
|
||||
for location in cls.standard_file_sources + cls.standard_network_sources:
|
||||
logging.debug("Trying leap second data from %s", location)
|
||||
try:
|
||||
candidate = cls.from_url(location, check_hash=check_hash)
|
||||
|
|
@ -244,14 +282,13 @@ class LeapSecondData:
|
|||
@classmethod
|
||||
def from_url(
|
||||
cls,
|
||||
url: str = "https://raw.githubusercontent.com/eggert/tz/main/leap-seconds.list",
|
||||
url: str,
|
||||
*,
|
||||
check_hash: bool = True,
|
||||
) -> LeapSecondData | None:
|
||||
"""Retrieve the leap second list from a local file
|
||||
|
||||
:param filename: URL to read leap second data from. The
|
||||
default is maintained by the tzdata authors
|
||||
:param filename: URL to read leap second data from
|
||||
:param check_hash: Whether to check the embedded hash
|
||||
"""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from dataclasses import dataclass
|
|||
|
||||
import click
|
||||
|
||||
from . import LeapSecondData, tai
|
||||
from . import InvalidHashError, LeapSecondData, tai
|
||||
|
||||
utc = datetime.timezone.utc
|
||||
|
||||
|
|
@ -165,5 +165,29 @@ def table(ctx: click.Context, *, start: datetime.datetime, end: datetime.datetim
|
|||
print(f"{leap_second.start:%Y-%m-%d}: {leap_second.tai_offset.total_seconds():.0f}")
|
||||
|
||||
|
||||
@cli.command
|
||||
def sources() -> None:
|
||||
"""Print information about leap-second.list data sources"""
|
||||
first = True
|
||||
for location in LeapSecondData.standard_file_sources + LeapSecondData.standard_network_sources:
|
||||
if not first:
|
||||
print()
|
||||
first = False
|
||||
try:
|
||||
leap_second_data = LeapSecondData.from_url(location, check_hash=True)
|
||||
except InvalidHashError: # pragma no coverage
|
||||
print(f"{location}: Invalid hash")
|
||||
leap_second_data = LeapSecondData.from_url(location, check_hash=False)
|
||||
except Exception as e: # pragma no coverage # noqa: BLE001
|
||||
print(f"{location}: {e}")
|
||||
leap_second_data = None
|
||||
|
||||
if leap_second_data is not None:
|
||||
print(f"{location}: Last updated {leap_second_data.last_updated}")
|
||||
print(f"{location}: Valid until {leap_second_data.valid_until}")
|
||||
else:
|
||||
print(f"{location}: Could not be read")
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma no cover
|
||||
cli()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ write_to = "leapseconddata/__version__.py"
|
|||
line-length=120
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "D", "I", "N", "UP", "YTT", "BLE", "B", "FBT", "A", "COM", "C4", "DTZ", "FA", "ISC", "ICN", "PIE", "PYI", "Q", "RET", "SIM", "TID", "TCH", "ARG", "PTH", "C", "R", "W", "FLY", "RUF", "PL"]
|
||||
ignore = ["D203", "D213", "D400", "D415", "ISC001"]
|
||||
ignore = ["D203", "D213", "D400", "D415", "ISC001", "COM812"]
|
||||
[project]
|
||||
name = "leapseconddata"
|
||||
authors = [{name = "Jeff Epler", email = "jepler@gmail.com"}]
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class LeapSecondDataTest(unittest.TestCase):
|
|||
self.run_main("next-leapsecond", "2100-2-2")
|
||||
self.run_main("previous-leapsecond", "2009-2-2")
|
||||
self.run_main("previous-leapsecond", "1960-2-2")
|
||||
self.run_main("sources")
|
||||
|
||||
def test_corrupt(self) -> None:
|
||||
self.assertRaises(
|
||||
|
|
|
|||
Loading…
Reference in a new issue