wwvb 7.0.0__tar.gz → 8.0.0rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wwvb-8.0.0rc1/.forgejo/workflows/ci.yml +65 -0
- wwvb-8.0.0rc1/.forgejo/workflows/cron.yml +37 -0
- {wwvb-7.0.0/.github → wwvb-8.0.0rc1/.forgejo}/workflows/release.yml +8 -13
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/.gitignore +1 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/.pre-commit-config.yaml +8 -2
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/Makefile +1 -1
- {wwvb-7.0.0/src/wwvb.egg-info → wwvb-8.0.0rc1}/PKG-INFO +4 -8
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/README.md +1 -5
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/pyproject.toml +2 -2
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/requirements-dev.txt +3 -1
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/__init__.py +20 -5
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/__version__.py +3 -3
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/decode.py +1 -1
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/gen.py +6 -3
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.json +1 -1
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/wwvbtk.py +6 -4
- {wwvb-7.0.0 → wwvb-8.0.0rc1/src/wwvb.egg-info}/PKG-INFO +4 -8
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/SOURCES.txt +3 -4
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testcli.py +11 -3
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testls.py +0 -4
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testpm.py +0 -4
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testuwwvb.py +1 -5
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testwwvb.py +8 -8
- wwvb-7.0.0/.github/workflows/cron.yml +0 -48
- wwvb-7.0.0/.github/workflows/test.yml +0 -126
- wwvb-7.0.0/codecov.yml +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/.readthedocs.yaml +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/CC0-1.0.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/GPL-3.0-only.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/Unlicense.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/_static/.empty +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/conf.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/index.rst +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/requirements.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/setup.cfg +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/uwwvb.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/dut1table.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.json.license +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/py.typed +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/tz.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/updateiers.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/dependency_links.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/entry_points.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/requires.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/top_level.txt +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testdaylight.py +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/1998leapsecond +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/2012leapsecond +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/all-headers +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/bar +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/both +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/cradek +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/duration +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/enddst-phase +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/enddst-phase-2 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/endleapyear +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday1 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday28 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday29 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/negleapsecond +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nextdst +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nextst +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nonleapday1 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nonleapday28 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/phase +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst-phase +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst-phase-2 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startleapyear +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startst +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k-1 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k1 +0 -0
- {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k1-1 +0 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2021-2025 Jeff Epler
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: CC0-1.0
|
4
|
+
|
5
|
+
name: Test wwvbpy
|
6
|
+
|
7
|
+
on:
|
8
|
+
push:
|
9
|
+
pull_request:
|
10
|
+
release:
|
11
|
+
types:
|
12
|
+
- created # forgejo does not document the value "created"
|
13
|
+
- published
|
14
|
+
|
15
|
+
# (may not be used by forgejo, but is ignored for now)
|
16
|
+
concurrency:
|
17
|
+
group: ${{ forge.workflow }}-${{ forge.ref_name }}-${{ forge.event_name }}
|
18
|
+
cancel-in-progress: true
|
19
|
+
|
20
|
+
jobs:
|
21
|
+
build:
|
22
|
+
runs-on: codeberg-tiny
|
23
|
+
container:
|
24
|
+
image: docker.io/library/python:3-trixie
|
25
|
+
steps:
|
26
|
+
- name: Set up node
|
27
|
+
run: apt-get update && apt-get install -y --no-install-recommends nodejs
|
28
|
+
|
29
|
+
- uses: actions/checkout@v4
|
30
|
+
|
31
|
+
- name: Set up uv
|
32
|
+
run: pip install --break-system-packages uv
|
33
|
+
|
34
|
+
- name: Run main tests
|
35
|
+
run: |
|
36
|
+
for version in 3.9 3.10 3.11 3.12 3.13; do
|
37
|
+
echo "::group::Test with Python $version"
|
38
|
+
uv venv --python $version _venv_${version}
|
39
|
+
. _venv_${version}/bin/activate
|
40
|
+
uv pip install -r requirements-dev.txt
|
41
|
+
env PYTHONPATH=src python -mcoverage run -p -m unittest discover -s test
|
42
|
+
deactivate
|
43
|
+
echo "::endgroup::"
|
44
|
+
done
|
45
|
+
|
46
|
+
for version in 3.13; do
|
47
|
+
echo "::group::Aggregate coverage and run final checks"
|
48
|
+
. _venv_${version}/bin/activate
|
49
|
+
make -j $(nproc) -O mypy test_venv
|
50
|
+
python -mcoverage combine -q
|
51
|
+
python -mcoverage json --include "src/**/*.py"
|
52
|
+
python -mcoverage report --fail-under=100 --include "src/**/*.py"
|
53
|
+
prek --all-files
|
54
|
+
deactivate
|
55
|
+
echo "::endgroup::"
|
56
|
+
done
|
57
|
+
|
58
|
+
- name: Upload Coverage as artifact
|
59
|
+
if: always()
|
60
|
+
uses: actions/upload-artifact@v3
|
61
|
+
with:
|
62
|
+
path: coverage.json
|
63
|
+
|
64
|
+
- name: Check build directory size
|
65
|
+
run: du -shx
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: CC0-1.0
|
4
|
+
|
5
|
+
name: Update DUT1 data
|
6
|
+
|
7
|
+
on:
|
8
|
+
schedule:
|
9
|
+
- cron: '0 10 2 * *'
|
10
|
+
workflow_dispatch:
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
update-dut1:
|
14
|
+
permissions: write-all
|
15
|
+
runs-on: codeberg-tiny
|
16
|
+
container:
|
17
|
+
image: docker.io/library/python:3-trixie
|
18
|
+
steps:
|
19
|
+
- name: Set up node
|
20
|
+
run: apt-get update && apt-get install -y --no-install-recommends nodejs
|
21
|
+
|
22
|
+
- uses: actions/checkout@v4
|
23
|
+
|
24
|
+
- name: Install dependencies
|
25
|
+
run: pip install -e .
|
26
|
+
|
27
|
+
- name: Update DUT1 data
|
28
|
+
run: python -m wwvb.updateiers --dist
|
29
|
+
|
30
|
+
- name: Test
|
31
|
+
run: python -munittest discover -s test
|
32
|
+
|
33
|
+
- name: Commit updates
|
34
|
+
run: |
|
35
|
+
git config user.name "${FORGEJO_ACTOR} (actions cron)"
|
36
|
+
git config user.email "${FORGEJO_ACTOR}@noreply.invalid"
|
37
|
+
if git commit -m"update iersdata" src/wwvb/iersdata.json; then git push origin; fi
|
@@ -10,30 +10,25 @@ on:
|
|
10
10
|
|
11
11
|
jobs:
|
12
12
|
release:
|
13
|
-
|
14
|
-
runs-on:
|
13
|
+
permissions: write-all
|
14
|
+
runs-on: codeberg-tiny
|
15
|
+
container:
|
16
|
+
image: docker.io/library/python:3-trixie
|
15
17
|
steps:
|
16
|
-
- name:
|
17
|
-
|
18
|
-
GITHUB_CONTEXT: ${{ toJson(github) }}
|
19
|
-
run: echo "$GITHUB_CONTEXT"
|
18
|
+
- name: Set up node
|
19
|
+
run: apt-get update && apt-get install -y --no-install-recommends nodejs
|
20
20
|
|
21
21
|
- uses: actions/checkout@v4
|
22
22
|
with:
|
23
23
|
persist-credentials: false
|
24
24
|
|
25
|
-
- name: Set up Python
|
26
|
-
uses: actions/setup-python@v5
|
27
|
-
with:
|
28
|
-
python-version: 3.9
|
29
|
-
|
30
25
|
- name: Install deps
|
31
26
|
run: |
|
32
27
|
python -mpip install wheel
|
33
28
|
python -mpip install -r requirements-dev.txt
|
34
29
|
|
35
30
|
- name: Test
|
36
|
-
run: make coverage
|
31
|
+
run: make coverage mypy
|
37
32
|
|
38
33
|
- name: Build release
|
39
34
|
run: python -mbuild
|
@@ -42,4 +37,4 @@ jobs:
|
|
42
37
|
run: twine upload -u "$TWINE_USERNAME" -p "$TWINE_PASSWORD" dist/*
|
43
38
|
env:
|
44
39
|
TWINE_USERNAME: __token__
|
45
|
-
TWINE_PASSWORD: ${{ secrets.
|
40
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
@@ -21,10 +21,16 @@ repos:
|
|
21
21
|
- id: reuse
|
22
22
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
23
23
|
# Ruff version.
|
24
|
-
rev: v0.12.
|
24
|
+
rev: v0.12.11
|
25
25
|
hooks:
|
26
26
|
# Run the linter.
|
27
|
-
- id: ruff
|
27
|
+
- id: ruff-check
|
28
28
|
args: [ --fix ]
|
29
29
|
# Run the formatter.
|
30
30
|
- id: ruff-format
|
31
|
+
- repo: https://github.com/asottile/pyupgrade
|
32
|
+
rev: v3.20.0
|
33
|
+
hooks:
|
34
|
+
- id: pyupgrade
|
35
|
+
args: [ --py39-plus ]
|
36
|
+
exclude: src/uwwvb.py # CircuitPython prevailing standard!
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wwvb
|
3
|
-
Version:
|
3
|
+
Version: 8.0.0rc1
|
4
4
|
Summary: Generate WWVB timecodes for any desired time
|
5
5
|
Author-email: Jeff Epler <jepler@gmail.com>
|
6
|
-
Project-URL: Source, https://
|
7
|
-
Project-URL: Documentation, https://
|
6
|
+
Project-URL: Source, https://codeberg.org/jepler/wwvbpy
|
7
|
+
Project-URL: Documentation, https://codeberg.org/jepler/wwvbpy
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
@@ -29,11 +29,7 @@ SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
|
29
29
|
|
30
30
|
SPDX-License-Identifier: GPL-3.0-only
|
31
31
|
-->
|
32
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
|
33
|
-
[](https://codecov.io/gh/jepler/wwvbpy)
|
34
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
|
35
32
|
[](https://pypi.org/project/wwvb)
|
36
|
-
[](https://results.pre-commit.ci/latest/github/jepler/wwvbpy/main)
|
37
33
|
|
38
34
|
# Purpose
|
39
35
|
|
@@ -63,7 +59,7 @@ The package includes:
|
|
63
59
|
|
64
60
|
# Development status
|
65
61
|
|
66
|
-
The author ([@jepler](https://
|
62
|
+
The author ([@jepler](https://unpythonic.net)) occasionally develops and maintains this project, but
|
67
63
|
issues are not likely to be acted on. They would be interested in adding
|
68
64
|
co-maintainer(s).
|
69
65
|
|
@@ -3,11 +3,7 @@ SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
|
3
3
|
|
4
4
|
SPDX-License-Identifier: GPL-3.0-only
|
5
5
|
-->
|
6
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
|
7
|
-
[](https://codecov.io/gh/jepler/wwvbpy)
|
8
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
|
9
6
|
[](https://pypi.org/project/wwvb)
|
10
|
-
[](https://results.pre-commit.ci/latest/github/jepler/wwvbpy/main)
|
11
7
|
|
12
8
|
# Purpose
|
13
9
|
|
@@ -37,7 +33,7 @@ The package includes:
|
|
37
33
|
|
38
34
|
# Development status
|
39
35
|
|
40
|
-
The author ([@jepler](https://
|
36
|
+
The author ([@jepler](https://unpythonic.net)) occasionally develops and maintains this project, but
|
41
37
|
issues are not likely to be acted on. They would be interested in adding
|
42
38
|
co-maintainer(s).
|
43
39
|
|
@@ -39,8 +39,8 @@ classifiers = [
|
|
39
39
|
]
|
40
40
|
requires-python = ">=3.9"
|
41
41
|
[project.urls]
|
42
|
-
Source = "https://
|
43
|
-
Documentation = "https://
|
42
|
+
Source = "https://codeberg.org/jepler/wwvbpy"
|
43
|
+
Documentation = "https://codeberg.org/jepler/wwvbpy"
|
44
44
|
[project.scripts]
|
45
45
|
wwvbgen = "wwvb.gen:main"
|
46
46
|
wwvbdecode = "wwvb.decode:main"
|
@@ -7,10 +7,12 @@ build
|
|
7
7
|
click
|
8
8
|
coverage >= 7.10.3
|
9
9
|
mypy; implementation_name=="cpython"
|
10
|
+
pyright; implementation_name=="cpython"
|
11
|
+
pyrefly; implementation_name=="cpython"
|
10
12
|
click>=8.1.5; implementation_name=="cpython"
|
11
13
|
leapseconddata
|
12
14
|
platformdirs
|
13
|
-
|
15
|
+
prek
|
14
16
|
python-dateutil
|
15
17
|
requests; implementation_name=="cpython"
|
16
18
|
setuptools>=68; implementation_name=="cpython"
|
@@ -20,15 +20,30 @@ import enum
|
|
20
20
|
import json
|
21
21
|
import warnings
|
22
22
|
from dataclasses import dataclass
|
23
|
-
from typing import ClassVar
|
23
|
+
from typing import ClassVar, Literal
|
24
24
|
|
25
25
|
from . import iersdata
|
26
26
|
from .tz import Mountain
|
27
27
|
|
28
|
+
WWVBChannel = Literal["amplitude", "phase", "both"]
|
29
|
+
|
28
30
|
TYPE_CHECKING = False
|
29
31
|
if TYPE_CHECKING:
|
30
32
|
from collections.abc import Generator
|
31
|
-
from typing import
|
33
|
+
from typing import NotRequired, Self, TextIO, TypedDict, TypeVar
|
34
|
+
|
35
|
+
class JsonMinute(TypedDict):
|
36
|
+
"""Implementation detail
|
37
|
+
|
38
|
+
This is the Python object type that is serialized by `print_timecodes_json`
|
39
|
+
"""
|
40
|
+
|
41
|
+
year: int
|
42
|
+
days: int
|
43
|
+
hour: int
|
44
|
+
minute: int
|
45
|
+
amplitude: NotRequired[str]
|
46
|
+
phase: NotRequired[str]
|
32
47
|
|
33
48
|
T = TypeVar("T")
|
34
49
|
|
@@ -927,7 +942,7 @@ styles = {
|
|
927
942
|
def print_timecodes(
|
928
943
|
w: WWVBMinute,
|
929
944
|
minutes: int,
|
930
|
-
channel:
|
945
|
+
channel: WWVBChannel,
|
931
946
|
style: str,
|
932
947
|
file: TextIO,
|
933
948
|
*,
|
@@ -964,7 +979,7 @@ def print_timecodes(
|
|
964
979
|
def print_timecodes_json(
|
965
980
|
w: WWVBMinute,
|
966
981
|
minutes: int,
|
967
|
-
channel:
|
982
|
+
channel: WWVBChannel,
|
968
983
|
file: TextIO,
|
969
984
|
) -> None:
|
970
985
|
"""Print a range of timecodes in JSON format.
|
@@ -984,7 +999,7 @@ def print_timecodes_json(
|
|
984
999
|
"""
|
985
1000
|
result = []
|
986
1001
|
for _ in range(minutes):
|
987
|
-
data:
|
1002
|
+
data: JsonMinute = {
|
988
1003
|
"year": w.year,
|
989
1004
|
"days": w.days,
|
990
1005
|
"hour": w.hour,
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '
|
32
|
-
__version_tuple__ = version_tuple = (
|
31
|
+
__version__ = version = '8.0.0rc1'
|
32
|
+
__version_tuple__ = version_tuple = (8, 0, 0, 'rc1')
|
33
33
|
|
34
|
-
__commit_id__ = commit_id = '
|
34
|
+
__commit_id__ = commit_id = 'g5b40d06db'
|
@@ -9,15 +9,18 @@ from __future__ import annotations
|
|
9
9
|
|
10
10
|
import datetime
|
11
11
|
import sys
|
12
|
-
from typing import Any
|
13
12
|
|
14
13
|
import click
|
15
14
|
import dateutil.parser
|
16
15
|
|
17
16
|
from . import WWVBMinute, WWVBMinuteIERS, print_timecodes, print_timecodes_json, styles
|
18
17
|
|
18
|
+
TYPE_CHECKING = False
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from . import WWVBChannel
|
19
21
|
|
20
|
-
|
22
|
+
|
23
|
+
def parse_timespec(ctx: click.Context, param: click.Parameter, value: list[str]) -> datetime.datetime: # noqa: ARG001
|
21
24
|
"""Parse a time specifier from the commandline"""
|
22
25
|
try:
|
23
26
|
if len(value) == 5:
|
@@ -95,7 +98,7 @@ def main(
|
|
95
98
|
dut1: int,
|
96
99
|
minutes: int,
|
97
100
|
style: str,
|
98
|
-
channel:
|
101
|
+
channel: WWVBChannel,
|
99
102
|
all_timecodes: bool,
|
100
103
|
timespec: datetime.datetime,
|
101
104
|
) -> None:
|
@@ -1 +1 @@
|
|
1
|
-
{"START": "1972-01-01", "OFFSETS_GZ": "
|
1
|
+
{"START": "1972-01-01", "OFFSETS_GZ": "H4sIAJLBtmgC/+2aa3LDMAiEL5uHLTuxnN5/pn/aTmfSSiAWhGy+E2SWZQE58zwiH/1YivB/96vMXiIX2Io8CTyIrDSWGqlMRdrpDa6aJFnr0m4wYZkCE2UmSF0V+13vBveStK6JTfQyW3O86HLJf0RvDgy5u4FCI+WVKTsVoUdHzsrRoWRfYHIItZ5EEgu0Beu58EgEpMpO9zf4/s3iNO4y7/hqEwOZIPu3+PuO2T7Ic5E8GxsnZHvUYOtELxW1WP+0yx/caFxpyAooq6lq06UEr+UkLeXOIDPZ6EBrqb5K8Tvu6/B9CdnZqFQL05s2KauWy/IeF/tJGAisjK9MgGyDuUkRq4G1gRE+VjA30uZNPsdantkgMq58QO4fw+sqzj+A2/16mmvnyy9UzDvMktDgKYlnkFeB2rx+wNANG40aA4OgsY03AWoDCVs/XMmkyQ0+0jWaUqPdwA0m/MRuccGjCwirHToWzbcs8P7U1nZZLSYdHapWu5HqVg1YjK2fPEwvPZPzLPUF848tyid2u7dh8B7h+wVQ923Q+kqxZe3JclSSB+YTM3nnHrjgFth/vzgZzw6cbOMYa4bHFPU/DR3mp/ubKM4cgwMnHZW4GFxFprOVcevAKGva6oExn1MOmyGDJQPm0rpU8bjqdOo993O6Xz9ofToZela5vwrWoTn4l4o5CIIaKejCEgSnJv784V+z0yyz2F/zCTF9VskETgAA"}
|
@@ -8,13 +8,13 @@ from __future__ import annotations
|
|
8
8
|
|
9
9
|
import datetime
|
10
10
|
import functools
|
11
|
-
from tkinter import Canvas, TclError, Tk
|
12
|
-
from typing import TYPE_CHECKING, Any
|
11
|
+
from tkinter import Canvas, Event, TclError, Tk
|
13
12
|
|
14
13
|
import click
|
15
14
|
|
16
15
|
import wwvb
|
17
16
|
|
17
|
+
TYPE_CHECKING = False
|
18
18
|
if TYPE_CHECKING:
|
19
19
|
from collections.abc import Generator
|
20
20
|
|
@@ -25,7 +25,7 @@ def _app() -> Tk:
|
|
25
25
|
return Tk()
|
26
26
|
|
27
27
|
|
28
|
-
def validate_colors(ctx:
|
28
|
+
def validate_colors(ctx: click.Context, param: click.Parameter, value: str) -> list[str]: # noqa: ARG001
|
29
29
|
"""Check that all colors in a string are valid, splitting it to a list"""
|
30
30
|
app = _app()
|
31
31
|
colors = value.split()
|
@@ -106,7 +106,7 @@ def main(colors: list[str], size: int, min_size: int | None) -> None: # noqa: P
|
|
106
106
|
canvas.pack(fill="both", expand=True)
|
107
107
|
app.wm_deiconify()
|
108
108
|
|
109
|
-
def resize_canvas(event:
|
109
|
+
def resize_canvas(event: Event) -> None:
|
110
110
|
"""Keep the circle filling the window when it is resized"""
|
111
111
|
sz = min(event.width, event.height) - 8
|
112
112
|
if sz < 0:
|
@@ -141,10 +141,12 @@ def main(colors: list[str], size: int, min_size: int | None) -> None: # noqa: P
|
|
141
141
|
|
142
142
|
controller = controller_func().__next__
|
143
143
|
|
144
|
+
# pyrefly: ignore # bad-assignment
|
144
145
|
def after_func() -> None:
|
145
146
|
"""Repeatedly run the controller after the desired interval"""
|
146
147
|
app.after(controller(), after_func)
|
147
148
|
|
149
|
+
# pyrefly: ignore # bad-argument-type
|
148
150
|
app.after_idle(after_func)
|
149
151
|
app.mainloop()
|
150
152
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wwvb
|
3
|
-
Version:
|
3
|
+
Version: 8.0.0rc1
|
4
4
|
Summary: Generate WWVB timecodes for any desired time
|
5
5
|
Author-email: Jeff Epler <jepler@gmail.com>
|
6
|
-
Project-URL: Source, https://
|
7
|
-
Project-URL: Documentation, https://
|
6
|
+
Project-URL: Source, https://codeberg.org/jepler/wwvbpy
|
7
|
+
Project-URL: Documentation, https://codeberg.org/jepler/wwvbpy
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
@@ -29,11 +29,7 @@ SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
|
29
29
|
|
30
30
|
SPDX-License-Identifier: GPL-3.0-only
|
31
31
|
-->
|
32
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
|
33
|
-
[](https://codecov.io/gh/jepler/wwvbpy)
|
34
|
-
[](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
|
35
32
|
[](https://pypi.org/project/wwvb)
|
36
|
-
[](https://results.pre-commit.ci/latest/github/jepler/wwvbpy/main)
|
37
33
|
|
38
34
|
# Purpose
|
39
35
|
|
@@ -63,7 +59,7 @@ The package includes:
|
|
63
59
|
|
64
60
|
# Development status
|
65
61
|
|
66
|
-
The author ([@jepler](https://
|
62
|
+
The author ([@jepler](https://unpythonic.net)) occasionally develops and maintains this project, but
|
67
63
|
issues are not likely to be acted on. They would be interested in adding
|
68
64
|
co-maintainer(s).
|
69
65
|
|
@@ -3,13 +3,12 @@
|
|
3
3
|
.readthedocs.yaml
|
4
4
|
Makefile
|
5
5
|
README.md
|
6
|
-
codecov.yml
|
7
6
|
pyproject.toml
|
8
7
|
requirements-dev.txt
|
9
8
|
requirements.txt
|
10
|
-
.
|
11
|
-
.
|
12
|
-
.
|
9
|
+
.forgejo/workflows/ci.yml
|
10
|
+
.forgejo/workflows/cron.yml
|
11
|
+
.forgejo/workflows/release.yml
|
13
12
|
LICENSES/CC0-1.0.txt
|
14
13
|
LICENSES/GPL-3.0-only.txt
|
15
14
|
LICENSES/Unlicense.txt
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/python3
|
2
|
+
|
2
3
|
"""Test most wwvblib commandline programs"""
|
3
4
|
|
4
5
|
# ruff: noqa: N802 D102
|
@@ -6,13 +7,13 @@
|
|
6
7
|
#
|
7
8
|
# SPDX-License-Identifier: GPL-3.0-only
|
8
9
|
|
10
|
+
from __future__ import annotations
|
11
|
+
|
9
12
|
import json
|
10
13
|
import os
|
11
14
|
import subprocess
|
12
15
|
import sys
|
13
16
|
import unittest
|
14
|
-
from collections.abc import Sequence
|
15
|
-
from typing import Any
|
16
17
|
|
17
18
|
# These imports must remain, even though the module contents are not used directly!
|
18
19
|
import wwvb.dut1table
|
@@ -22,6 +23,12 @@ import wwvb.gen
|
|
22
23
|
assert wwvb.dut1table.__name__ == "wwvb.dut1table"
|
23
24
|
assert wwvb.gen.__name__ == "wwvb.gen"
|
24
25
|
|
26
|
+
TYPE_CHECKING = False
|
27
|
+
if TYPE_CHECKING:
|
28
|
+
from collections.abc import Sequence
|
29
|
+
|
30
|
+
from wwvb import JsonMinute
|
31
|
+
|
25
32
|
|
26
33
|
class CLITestCase(unittest.TestCase):
|
27
34
|
"""Test various CLI commands within wwvbpy"""
|
@@ -55,9 +62,10 @@ class CLITestCase(unittest.TestCase):
|
|
55
62
|
def assertStarts(self, expected: str, actual: str, *args: str) -> None:
|
56
63
|
self.assertMultiLineEqual(expected, actual[: len(expected)], f"args={args}")
|
57
64
|
|
58
|
-
def assertModuleJson(self, expected:
|
65
|
+
def assertModuleJson(self, expected: list[JsonMinute], *args: str) -> None:
|
59
66
|
"""Check the output from invoking a `python -m modulename` program matches the expected"""
|
60
67
|
actual = self.moduleOutput(*args)
|
68
|
+
# Note: in mypy, revealed type of json.loads is typing.Any!
|
61
69
|
self.assertEqual(json.loads(actual), expected)
|
62
70
|
|
63
71
|
def assertModuleOutputStarts(self, expected: str, *args: str) -> None:
|
@@ -47,7 +47,7 @@ class WWVBRoundtrip(unittest.TestCase):
|
|
47
47
|
any_leap_second = False
|
48
48
|
for _ in range(20):
|
49
49
|
timecode = minute.as_timecode()
|
50
|
-
decoded = None
|
50
|
+
decoded: uwwvb.WWVBMinute | None = None
|
51
51
|
if len(timecode.am) == 61:
|
52
52
|
any_leap_second = True
|
53
53
|
for code in timecode.am:
|
@@ -215,7 +215,3 @@ class WWVBRoundtrip(unittest.TestCase):
|
|
215
215
|
datetime.datetime(2020, 12, 31, 17, 00, tzinfo=zoneinfo.ZoneInfo("America/Denver")), # Mountain time!
|
216
216
|
uwwvb.as_datetime_local(decoded),
|
217
217
|
)
|
218
|
-
|
219
|
-
|
220
|
-
if __name__ == "__main__":
|
221
|
-
unittest.main()
|
@@ -18,7 +18,7 @@ import unittest
|
|
18
18
|
|
19
19
|
import uwwvb
|
20
20
|
import wwvb
|
21
|
-
from wwvb import decode, iersdata, tz
|
21
|
+
from wwvb import WWVBChannel, decode, iersdata, tz
|
22
22
|
|
23
23
|
|
24
24
|
class WWVBMinute2k(wwvb.WWVBMinute):
|
@@ -44,11 +44,15 @@ class WWVBTestCase(unittest.TestCase):
|
|
44
44
|
header = lines[0].split()
|
45
45
|
timestamp = " ".join(header[:10])
|
46
46
|
options = header[10:]
|
47
|
-
channel = "amplitude"
|
47
|
+
channel: WWVBChannel = "amplitude"
|
48
48
|
style = "default"
|
49
49
|
for o in options:
|
50
|
-
if o
|
51
|
-
channel =
|
50
|
+
if o == "--channel=both":
|
51
|
+
channel = "both"
|
52
|
+
elif o == "--channel=amplitude":
|
53
|
+
channel = "amplitude"
|
54
|
+
elif o == "--channel=phase":
|
55
|
+
channel = "phase"
|
52
56
|
elif o.startswith("--style="):
|
53
57
|
style = o[8:]
|
54
58
|
else:
|
@@ -430,7 +434,3 @@ class WWVBRoundtrip(unittest.TestCase):
|
|
430
434
|
minute.am[57] = wwvb.AmplitudeModulation.MARK
|
431
435
|
decoded_minute = wwvb.WWVBMinute.from_timecode_am(minute)
|
432
436
|
assert decoded_minute is None
|
433
|
-
|
434
|
-
|
435
|
-
if __name__ == "__main__":
|
436
|
-
unittest.main()
|
@@ -1,48 +0,0 @@
|
|
1
|
-
# SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: CC0-1.0
|
4
|
-
|
5
|
-
name: Update DUT1 data
|
6
|
-
|
7
|
-
on:
|
8
|
-
schedule:
|
9
|
-
- cron: '0 10 2 * *'
|
10
|
-
workflow_dispatch:
|
11
|
-
|
12
|
-
jobs:
|
13
|
-
update-dut1:
|
14
|
-
runs-on: ubuntu-24.04
|
15
|
-
if: startswith(github.repository, 'jepler/')
|
16
|
-
steps:
|
17
|
-
|
18
|
-
- name: Dump GitHub context
|
19
|
-
env:
|
20
|
-
GITHUB_CONTEXT: ${{ toJson(github) }}
|
21
|
-
run: echo "$GITHUB_CONTEXT"
|
22
|
-
|
23
|
-
- uses: actions/checkout@v4
|
24
|
-
with:
|
25
|
-
persist-credentials: false
|
26
|
-
|
27
|
-
- name: Set up Python 3.10
|
28
|
-
uses: actions/setup-python@v5
|
29
|
-
with:
|
30
|
-
python-version: "3.10"
|
31
|
-
|
32
|
-
- name: Install dependencies
|
33
|
-
run: pip install -e .
|
34
|
-
|
35
|
-
- name: Update DUT1 data
|
36
|
-
run: python -m wwvb.updateiers --dist
|
37
|
-
|
38
|
-
- name: Test
|
39
|
-
run: python -munittest
|
40
|
-
|
41
|
-
- name: Commit updates
|
42
|
-
env:
|
43
|
-
REPO: ${{ github.repository }}
|
44
|
-
run: |
|
45
|
-
git config user.name "${GITHUB_ACTOR} (github actions cron)"
|
46
|
-
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
47
|
-
git remote set-url --push origin "https://${GITHUB_ACTOR}:${{ secrets.GITHUB_TOKEN }}@github.com/$REPO"
|
48
|
-
if git commit -m"update iersdata" src/wwvb/iersdata.json; then git push origin HEAD:main; fi
|
@@ -1,126 +0,0 @@
|
|
1
|
-
# SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: CC0-1.0
|
4
|
-
|
5
|
-
name: Test wwvbgen
|
6
|
-
|
7
|
-
on:
|
8
|
-
push:
|
9
|
-
pull_request:
|
10
|
-
release:
|
11
|
-
types: [published]
|
12
|
-
check_suite:
|
13
|
-
types: [rerequested]
|
14
|
-
|
15
|
-
jobs:
|
16
|
-
docs:
|
17
|
-
runs-on: ubuntu-latest
|
18
|
-
steps:
|
19
|
-
- name: Set up Python
|
20
|
-
uses: actions/setup-python@v5
|
21
|
-
with:
|
22
|
-
python-version: '3.12'
|
23
|
-
|
24
|
-
- uses: actions/checkout@v4
|
25
|
-
with:
|
26
|
-
persist-credentials: false
|
27
|
-
|
28
|
-
- name: Install deps
|
29
|
-
run: python -mpip install -r requirements-dev.txt
|
30
|
-
|
31
|
-
- name: Build HTML docs
|
32
|
-
run: make html
|
33
|
-
|
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
|
-
- name: Check stubs
|
59
|
-
if: (! startsWith(matrix.python-version, 'pypy-'))
|
60
|
-
run: make mypy PYTHON=python
|
61
|
-
|
62
|
-
|
63
|
-
test:
|
64
|
-
strategy:
|
65
|
-
fail-fast: false
|
66
|
-
matrix:
|
67
|
-
python-version:
|
68
|
-
- '3.9'
|
69
|
-
- '3.10'
|
70
|
-
- '3.11'
|
71
|
-
- '3.12'
|
72
|
-
- '3.13'
|
73
|
-
- '3.14.0-alpha.0 - 3.14'
|
74
|
-
os-version:
|
75
|
-
- 'ubuntu-latest'
|
76
|
-
include:
|
77
|
-
- os-version: 'macos-latest'
|
78
|
-
python-version: '3.x'
|
79
|
-
- os-version: 'windows-latest'
|
80
|
-
python-version: '3.x'
|
81
|
-
- os-version: 'ubuntu-latest'
|
82
|
-
python-version: 'pypy-3.10'
|
83
|
-
|
84
|
-
runs-on: ${{ matrix.os-version }}
|
85
|
-
steps:
|
86
|
-
- uses: actions/checkout@v4
|
87
|
-
with:
|
88
|
-
persist-credentials: false
|
89
|
-
|
90
|
-
- name: Set up Python
|
91
|
-
uses: actions/setup-python@v5
|
92
|
-
with:
|
93
|
-
python-version: ${{ matrix.python-version }}
|
94
|
-
|
95
|
-
- name: Install deps
|
96
|
-
run: |
|
97
|
-
python -mpip install wheel
|
98
|
-
python -mpip install -r requirements-dev.txt
|
99
|
-
|
100
|
-
- name: Coverage
|
101
|
-
run: make coverage PYTHON=python
|
102
|
-
|
103
|
-
- name: Test installed version
|
104
|
-
run: make test_venv PYTHON=python
|
105
|
-
|
106
|
-
- name: Upload Coverage as artifact
|
107
|
-
if: always()
|
108
|
-
uses: actions/upload-artifact@v4
|
109
|
-
with:
|
110
|
-
name: coverage for ${{ matrix.python-version }} on ${{ matrix.os-version }}
|
111
|
-
path: coverage.xml
|
112
|
-
|
113
|
-
pre-commit:
|
114
|
-
runs-on: ubuntu-latest
|
115
|
-
steps:
|
116
|
-
- uses: actions/checkout@v4
|
117
|
-
with:
|
118
|
-
persist-credentials: false
|
119
|
-
|
120
|
-
- name: Set up Python
|
121
|
-
uses: actions/setup-python@v5
|
122
|
-
with:
|
123
|
-
python-version: '3.x'
|
124
|
-
|
125
|
-
- name: pre-commit
|
126
|
-
run: pip install pre-commit && pre-commit run --all
|
wwvb-7.0.0/codecov.yml
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|