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.
Files changed (75) hide show
  1. wwvb-8.0.0rc1/.forgejo/workflows/ci.yml +65 -0
  2. wwvb-8.0.0rc1/.forgejo/workflows/cron.yml +37 -0
  3. {wwvb-7.0.0/.github → wwvb-8.0.0rc1/.forgejo}/workflows/release.yml +8 -13
  4. {wwvb-7.0.0 → wwvb-8.0.0rc1}/.gitignore +1 -0
  5. {wwvb-7.0.0 → wwvb-8.0.0rc1}/.pre-commit-config.yaml +8 -2
  6. {wwvb-7.0.0 → wwvb-8.0.0rc1}/Makefile +1 -1
  7. {wwvb-7.0.0/src/wwvb.egg-info → wwvb-8.0.0rc1}/PKG-INFO +4 -8
  8. {wwvb-7.0.0 → wwvb-8.0.0rc1}/README.md +1 -5
  9. {wwvb-7.0.0 → wwvb-8.0.0rc1}/pyproject.toml +2 -2
  10. {wwvb-7.0.0 → wwvb-8.0.0rc1}/requirements-dev.txt +3 -1
  11. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/__init__.py +20 -5
  12. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/__version__.py +3 -3
  13. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/decode.py +1 -1
  14. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/gen.py +6 -3
  15. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.json +1 -1
  16. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/wwvbtk.py +6 -4
  17. {wwvb-7.0.0 → wwvb-8.0.0rc1/src/wwvb.egg-info}/PKG-INFO +4 -8
  18. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/SOURCES.txt +3 -4
  19. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testcli.py +11 -3
  20. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testls.py +0 -4
  21. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testpm.py +0 -4
  22. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testuwwvb.py +1 -5
  23. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testwwvb.py +8 -8
  24. wwvb-7.0.0/.github/workflows/cron.yml +0 -48
  25. wwvb-7.0.0/.github/workflows/test.yml +0 -126
  26. wwvb-7.0.0/codecov.yml +0 -0
  27. {wwvb-7.0.0 → wwvb-8.0.0rc1}/.readthedocs.yaml +0 -0
  28. {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/CC0-1.0.txt +0 -0
  29. {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/GPL-3.0-only.txt +0 -0
  30. {wwvb-7.0.0 → wwvb-8.0.0rc1}/LICENSES/Unlicense.txt +0 -0
  31. {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/_static/.empty +0 -0
  32. {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/conf.py +0 -0
  33. {wwvb-7.0.0 → wwvb-8.0.0rc1}/doc/index.rst +0 -0
  34. {wwvb-7.0.0 → wwvb-8.0.0rc1}/requirements.txt +0 -0
  35. {wwvb-7.0.0 → wwvb-8.0.0rc1}/setup.cfg +0 -0
  36. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/uwwvb.py +0 -0
  37. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/dut1table.py +0 -0
  38. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.json.license +0 -0
  39. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/iersdata.py +0 -0
  40. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/py.typed +0 -0
  41. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/tz.py +0 -0
  42. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb/updateiers.py +0 -0
  43. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/dependency_links.txt +0 -0
  44. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/entry_points.txt +0 -0
  45. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/requires.txt +0 -0
  46. {wwvb-7.0.0 → wwvb-8.0.0rc1}/src/wwvb.egg-info/top_level.txt +0 -0
  47. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/testdaylight.py +0 -0
  48. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/1998leapsecond +0 -0
  49. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/2012leapsecond +0 -0
  50. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/all-headers +0 -0
  51. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/bar +0 -0
  52. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/both +0 -0
  53. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/cradek +0 -0
  54. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/duration +0 -0
  55. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/enddst-phase +0 -0
  56. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/enddst-phase-2 +0 -0
  57. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/endleapyear +0 -0
  58. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday1 +0 -0
  59. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday28 +0 -0
  60. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/leapday29 +0 -0
  61. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/negleapsecond +0 -0
  62. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nextdst +0 -0
  63. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nextst +0 -0
  64. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nonleapday1 +0 -0
  65. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/nonleapday28 +0 -0
  66. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/phase +0 -0
  67. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst +0 -0
  68. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst-phase +0 -0
  69. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startdst-phase-2 +0 -0
  70. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startleapyear +0 -0
  71. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/startst +0 -0
  72. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k +0 -0
  73. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k-1 +0 -0
  74. {wwvb-7.0.0 → wwvb-8.0.0rc1}/test/wwvbgen_testcases/y2k1 +0 -0
  75. {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: ubuntu-24.04
13
+ permissions: write-all
14
+ runs-on: codeberg-tiny
15
+ container:
16
+ image: docker.io/library/python:3-trixie
15
17
  steps:
16
- - name: Dump GitHub context
17
- env:
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.pypi_token }}
40
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
@@ -9,6 +9,7 @@
9
9
  /build
10
10
  /_build
11
11
  /coverage.xml
12
+ /coverage.json
12
13
  /dist
13
14
  /finals2000A.all.csv
14
15
  /htmlcov
@@ -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.10
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!
@@ -24,7 +24,7 @@ ENVPYTHON ?= _env/bin/python3
24
24
  endif
25
25
 
26
26
  .PHONY: default
27
- default: coverage mypy
27
+ default: coverage mypy pyright pyrefly
28
28
 
29
29
  COVERAGE_INCLUDE=--include "src/**/*.py"
30
30
  .PHONY: coverage
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wwvb
3
- Version: 7.0.0
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://github.com/jepler/wwvbpy
7
- Project-URL: Documentation, https://github.com/jepler/wwvbpy
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
- [![Test wwvbgen](https://github.com/jepler/wwvbpy/actions/workflows/test.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
33
- [![codecov](https://codecov.io/gh/jepler/wwvbpy/branch/main/graph/badge.svg?token=Exx0c3Gp65)](https://codecov.io/gh/jepler/wwvbpy)
34
- [![Update DUT1 data](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
35
32
  [![PyPI](https://img.shields.io/pypi/v/wwvb)](https://pypi.org/project/wwvb)
36
- [![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)
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://github.com/jepler)) occasionally develops and maintains this project, but
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
- [![Test wwvbgen](https://github.com/jepler/wwvbpy/actions/workflows/test.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
7
- [![codecov](https://codecov.io/gh/jepler/wwvbpy/branch/main/graph/badge.svg?token=Exx0c3Gp65)](https://codecov.io/gh/jepler/wwvbpy)
8
- [![Update DUT1 data](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
9
6
  [![PyPI](https://img.shields.io/pypi/v/wwvb)](https://pypi.org/project/wwvb)
10
- [![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)
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://github.com/jepler)) occasionally develops and maintains this project, but
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://github.com/jepler/wwvbpy"
43
- Documentation = "https://github.com/jepler/wwvbpy"
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
- pre-commit
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 Any, Self, TextIO, TypeVar
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: str,
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: str,
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: dict[str, Any] = {
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 = '7.0.0'
32
- __version_tuple__ = version_tuple = (7, 0, 0)
31
+ __version__ = version = '8.0.0rc1'
32
+ __version_tuple__ = version_tuple = (8, 0, 0, 'rc1')
33
33
 
34
- __commit_id__ = commit_id = 'g14c182717'
34
+ __commit_id__ = commit_id = 'g5b40d06db'
@@ -6,10 +6,10 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  import sys
9
- from typing import TYPE_CHECKING
10
9
 
11
10
  import wwvb
12
11
 
12
+ TYPE_CHECKING = False
13
13
  if TYPE_CHECKING:
14
14
  from collections.abc import Generator
15
15
 
@@ -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
- def parse_timespec(ctx: Any, param: Any, value: list[str]) -> datetime.datetime: # noqa: ARG001
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: str,
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": "H4sIAOvijWgC/+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+zUyyvbb/gE8h8bi3oTQAA"}
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: Any, param: Any, value: str) -> list[str]: # noqa: ARG001
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: Any) -> None:
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: 7.0.0
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://github.com/jepler/wwvbpy
7
- Project-URL: Documentation, https://github.com/jepler/wwvbpy
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
- [![Test wwvbgen](https://github.com/jepler/wwvbpy/actions/workflows/test.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/test.yml)
33
- [![codecov](https://codecov.io/gh/jepler/wwvbpy/branch/main/graph/badge.svg?token=Exx0c3Gp65)](https://codecov.io/gh/jepler/wwvbpy)
34
- [![Update DUT1 data](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml/badge.svg)](https://github.com/jepler/wwvbpy/actions/workflows/cron.yml)
35
32
  [![PyPI](https://img.shields.io/pypi/v/wwvb)](https://pypi.org/project/wwvb)
36
- [![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)
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://github.com/jepler)) occasionally develops and maintains this project, but
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
- .github/workflows/cron.yml
11
- .github/workflows/release.yml
12
- .github/workflows/test.yml
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: Any, *args: str) -> None:
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:
@@ -56,7 +56,3 @@ class TestLeapSecond(unittest.TestCase):
56
56
  assert not our_is_ls
57
57
  d = datetime.datetime.combine(nm, datetime.time(), tzinfo=datetime.timezone.utc)
58
58
  self.assertEqual(leap, bench)
59
-
60
-
61
- if __name__ == "__main__":
62
- unittest.main()
@@ -27,7 +27,3 @@ class TestPhaseModulation(unittest.TestCase):
27
27
 
28
28
  self.assertEqual(ref_am, test_am)
29
29
  self.assertEqual(ref_pm, test_pm)
30
-
31
-
32
- if __name__ == "__main__":
33
- unittest.main()
@@ -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.startswith("--channel="):
51
- channel = o[10:]
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