Skip to content
This repository was archived by the owner on Sep 8, 2025. It is now read-only.

Commit 495cb1a

Browse files
authored
Merge branch 'main' into use-upstream-type-hints
2 parents c6eae05 + 5afa43e commit 495cb1a

File tree

8 files changed

+113
-32
lines changed

8 files changed

+113
-32
lines changed

.github/workflows/test.yml

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,31 @@ jobs:
3131
- name: Build HTML docs
3232
run: make html
3333

34+
typing:
35+
strategy:
36+
fail-fast: false
37+
matrix:
38+
python-version:
39+
- '3.13'
40+
os-version:
41+
- 'ubuntu-latest'
42+
runs-on: ${{ matrix.os-version }}
43+
steps:
44+
- uses: actions/checkout@v4
45+
with:
46+
persist-credentials: false
47+
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: ${{ matrix.python-version }}
52+
53+
- name: Install deps
54+
run: |
55+
python -mpip install wheel
56+
python -mpip install -r requirements-dev.txt
57+
58+
3459
test:
3560
strategy:
3661
fail-fast: false
@@ -68,10 +93,6 @@ jobs:
6893
python -mpip install wheel
6994
python -mpip install -r requirements-dev.txt
7095
71-
- name: Check stubs
72-
if: (! startsWith(matrix.python-version, 'pypy-'))
73-
run: make mypy PYTHON=python
74-
7596
- name: Coverage
7697
run: make coverage PYTHON=python
7798

.readthedocs.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# SPDX-FileCopyrightText: 2024 Jeff Epler
2+
#
3+
# SPDX-License-Identifier: GPL-3.0-only
4+
5+
version: 2
6+
7+
build:
8+
os: ubuntu-lts-latest
9+
tools:
10+
python: "3"
11+
12+
sphinx:
13+
configuration: doc/conf.py
14+
15+
python:
16+
install:
17+
- requirements: requirements-dev.txt

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ SPDX-License-Identifier: GPL-3.0-only
77
[![codecov](https://codecov.io/gh/jepler/wwvbpy/branch/main/graph/badge.svg?token=Exx0c3Gp65)](https://codecov.io/gh/jepler/wwvbpy)
88
[![Update DUT1 data](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
99
[![PyPI](https://img.shields.io/pypi/v/wwvb)](https://pypi.org/project/wwvb)
10-
[![CodeQL](https://github.com/jepler/wwvbpy/actions/workflows/codeql.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/codeql.yml)
1110
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/jepler/wwvbpy/main.svg)](https://results.pre-commit.ci/latest/github/jepler/wwvbpy/main)
1211

1312
# Purpose
1413

15-
wwvbpy generates WWVB timecodes for any desired time. These timecodes
16-
may be useful in testing WWVB decoder software.
14+
Python package and command line programs for interacting with WWVB timecodes.
1715

1816
Where possible, wwvbpy uses existing facilities for calendar and time
1917
manipulation (datetime and dateutil).
@@ -39,7 +37,7 @@ The package includes:
3937

4038
# Development status
4139

42-
The author (@jepler) occasionally develops and maintains this project, but
40+
The author ([@jepler](https://github.com/jepler)) occasionally develops and maintains this project, but
4341
issues are not likely to be acted on. They would be interested in adding
4442
co-maintainer(s).
4543

@@ -67,7 +65,7 @@ channel.
6765
# Usage
6866

6967
~~~~
70-
Usage: python -m wwvb.gen [OPTIONS] [TIMESPEC]...
68+
Usage: wwvbgen [OPTIONS] [TIMESPEC]...
7169
7270
Generate WWVB timecodes
7371
@@ -97,7 +95,7 @@ Options:
9795

9896
For example, to display the leap second that occurred at the end of 1998,
9997
~~~~
100-
$ python wwvbgen.py -m 7 1998 365 23 56
98+
$ wwvbgen -m 7 1998 365 23 56
10199
WWVB timecode: year=98 days=365 hour=23 min=56 dst=0 ut1=-300 ly=0 ls=1
102100
'98+365 23:56 210100110200100001120011001102010100010200110100121000001002
103101
'98+365 23:57 210100111200100001120011001102010100010200110100121000001002
@@ -119,7 +117,7 @@ The letters `a` through `u` represent offsets of -1.0s through +1.0s
119117
in 0.1s increments; `k` represents 0s. (In practice, only a smaller range
120118
of values, typically -0.7s to +0.8s, is seen)
121119

122-
For 2001 through 2019, NIST has published the actual DUT1 values broadcast,
120+
For 2001 through 2024, NIST has published the actual DUT1 values broadcast,
123121
and the date of each change, though it in the format of an HTML
124122
table and not designed for machine readability:
125123

doc/conf.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
# ones.
5757
extensions = [
5858
"sphinx.ext.autodoc",
59+
"sphinx_mdinclude",
5960
]
6061

6162
# Add any paths that contain templates here, relative to this directory.
@@ -82,6 +83,10 @@
8283
autodoc_typehints = "description"
8384
autodoc_class_signature = "separated"
8485

86+
default_role = "any"
87+
88+
intersphinx_mapping = {'py': ('https://docs.python.org/3', None)}
89+
8590
# SPDX-FileCopyrightText: 2021-2024 Jeff Epler
8691
#
8792
# SPDX-License-Identifier: GPL-3.0-only

doc/index.rst

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,10 @@
22
..
33
.. SPDX-License-Identifier: GPL-3.0-only
44
5-
wwvbpy
6-
======
7-
8-
.. image:: https://github.com/jepler/wwvbpy/actions/workflows/test.yml/badge.svg
9-
:target: https://github.com/jepler/wwvbpy/actions/workflows/test.yml
10-
:alt: Test wwvbpy
11-
12-
.. image:: https://img.shields.io/pypi/v/wwvb
13-
:target: https://pypi.org/project/wwvb
14-
:alt: PyPI
5+
wwvbpy |version|
6+
================
157

8+
.. mdinclude:: ../README.md
169

1710
.. toctree::
1811
:maxdepth: 2

requirements-dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ pre-commit
1414
python-dateutil
1515
requests; implementation_name=="cpython"
1616
setuptools>=68; implementation_name=="cpython"
17-
sphinx>=7,<8
17+
sphinx
1818
sphinx-autodoc-typehints
1919
sphinx-rtd-theme
20+
sphinx-mdinclude
2021
twine; implementation_name=="cpython"
2122
types-beautifulsoup4; implementation_name=="cpython"
2223
types-python-dateutil; implementation_name=="cpython"

src/uwwvb.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
# ruff: noqa: C405 PYI024 PLR2004 FBT001 FBT002
66

7-
"""Implementation of a WWVB state machine & decoder for resource-constrained systems"""
7+
"""Implementation of a WWVB state machine & decoder for resource-constrained systems
8+
9+
This version is intended for use with MicroPython & CircuitPython.
10+
"""
811

912
from __future__ import annotations
1013

src/wwvb/__init__.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
#!/usr/bin/python3
2-
"""A library for WWVB timecodes"""
2+
"""A package and CLI for WWVB timecodes
3+
4+
This is the full featured library suitable for use on 'real computers'.
5+
For a reduced version suitable for use on MicroPython & CircuitPython,
6+
see `uwwvb`.
7+
8+
This package also includes the commandline programs listed above,
9+
perhaps most importantly ``wwvbgen`` for generating WWVB timecodes.
10+
"""
311

412
# SPDX-FileCopyrightText: 2011-2024 Jeff Epler
513
#
@@ -322,16 +330,17 @@ class DstStatus(enum.IntEnum):
322330
"""Constants that describe the DST status of a minute"""
323331

324332
DST_NOT_IN_EFFECT = 0b00
333+
"""DST not in effect today"""
325334
DST_STARTS_TODAY = 0b01
335+
"""DST starts today at 0200 local standard time"""
326336
DST_ENDS_TODAY = 0b10
337+
"""DST ends today at 0200 local standard time"""
327338
DST_IN_EFFECT = 0b11
339+
"""DST in effect all day today"""
328340

329341

330342
class _WWVBMinute(NamedTuple):
331-
"""Uniquely identifies a minute of time in the WWVB system.
332-
333-
To use ut1 and ls information from IERS, create a WWVBMinuteIERS value instead.
334-
"""
343+
"""(implementation detail)"""
335344

336345
year: int
337346
"""2-digit year within the WWVB epoch"""
@@ -361,7 +370,8 @@ class _WWVBMinute(NamedTuple):
361370
class WWVBMinute(_WWVBMinute):
362371
"""Uniquely identifies a minute of time in the WWVB system.
363372
364-
To use ut1 and ls information from IERS, create a WWVBMinuteIERS value instead.
373+
To use ``ut1`` and ``ls`` information from IERS, create a `WWVBMinuteIERS`
374+
object instead.
365375
"""
366376

367377
epoch: int = 1970
@@ -377,7 +387,19 @@ def __new__( # noqa: PYI034
377387
ls: bool | None = None,
378388
ly: bool | None = None,
379389
) -> WWVBMinute:
380-
"""Construct a WWVBMinute"""
390+
"""Construct a WWVBMinute
391+
392+
:param year: The 2- or 4-digit year. This parameter is converted by the `full_year` method.
393+
:param days: 1-based day of year
394+
395+
:param hour: UTC hour of day
396+
397+
:param minute: Minute of hour
398+
:param dst: 2-bit DST code
399+
:param ut1: UT1 offset in units of 100ms, range -900 to +900ms
400+
:param ls: Leap second warning flag
401+
:param ly: Leap year flag
402+
"""
381403
dst = cls.get_dst(year, days) if dst is None else DstStatus(dst)
382404
if ut1 is None and ls is None:
383405
ut1, ls = cls._get_dut1_info(year, days)
@@ -425,7 +447,10 @@ def __str__(self) -> str:
425447
)
426448

427449
def as_datetime_utc(self) -> datetime.datetime:
428-
"""Convert to a UTC datetime"""
450+
"""Convert to a UTC datetime
451+
452+
The returned object has ``tzinfo=datetime.timezone.utc``.
453+
"""
429454
d = datetime.datetime(self.year, 1, 1, tzinfo=datetime.timezone.utc)
430455
d += datetime.timedelta(self.days - 1, self.hour * 3600 + self.min * 60)
431456
return d
@@ -438,7 +463,18 @@ def as_datetime_local(
438463
*,
439464
dst_observed: bool = True,
440465
) -> datetime.datetime:
441-
"""Convert to a local datetime according to the DST bits"""
466+
"""Convert to a local datetime according to the DST bits
467+
468+
The returned object has ``tz=datetime.timezone(computed_offset)``.
469+
470+
:param standard_time_offset: The UTC offset of local standard time, in seconds west of UTC.
471+
The default value, ``7 * 3600``, is for Colorado, the source of the WWVB broadcast.
472+
473+
:param dst_observed: If ``True`` then the locale observes DST, and a
474+
one hour offset is applied according to WWVB rules. If ``False``, then
475+
the standard time offset is used at all times.
476+
477+
"""
442478
u = self.as_datetime_utc()
443479
offset = datetime.timedelta(seconds=-standard_time_offset)
444480
d = u - datetime.timedelta(seconds=standard_time_offset)
@@ -750,18 +786,25 @@ class AmplitudeModulation(enum.IntEnum):
750786
"""Constants that describe an Amplitude Modulation value"""
751787

752788
ZERO = 0
789+
"""A zero bit (reduced carrier during the first 200ms of the second)"""
753790
ONE = 1
791+
"""A one bit (reduced carrier during the first 500ms of the second)"""
754792
MARK = 2
793+
"""A mark bit (reduced carrier during the first 800ms of the second)"""
755794
UNSET = -1
795+
"""An unset or unknown amplitude modulation value"""
756796

757797

758798
@enum.unique
759799
class PhaseModulation(enum.IntEnum):
760800
"""Constants that describe a Phase Modulation value"""
761801

762802
ZERO = 0
803+
"""A one bit (180° phase shift during the second)"""
763804
ONE = 1
805+
"""A zero bit (No phase shift during the second)"""
764806
UNSET = -1
807+
"""An unset or unknown phase modulation value"""
765808

766809

767810
class WWVBTimecode:

0 commit comments

Comments
 (0)