wwvb 7.0.0__py3-none-any.whl → 8.0.0rc2__py3-none-any.whl
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/__init__.py +29 -9
- wwvb/__version__.py +2 -2
- wwvb/decode.py +1 -1
- wwvb/gen.py +6 -3
- wwvb/iersdata.json +1 -1
- wwvb/updateiers.py +4 -1
- wwvb/wwvbtk.py +6 -4
- {wwvb-7.0.0.dist-info → wwvb-8.0.0rc2.dist-info}/METADATA +5 -12
- wwvb-8.0.0rc2.dist-info/RECORD +18 -0
- wwvb-7.0.0.dist-info/RECORD +0 -18
- {wwvb-7.0.0.dist-info → wwvb-8.0.0rc2.dist-info}/WHEEL +0 -0
- {wwvb-7.0.0.dist-info → wwvb-8.0.0rc2.dist-info}/entry_points.txt +0 -0
- {wwvb-7.0.0.dist-info → wwvb-8.0.0rc2.dist-info}/top_level.txt +0 -0
wwvb/__init__.py
CHANGED
@@ -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
|
|
@@ -787,7 +802,12 @@ class WWVBMinuteIERS(WWVBMinute):
|
|
787
802
|
|
788
803
|
|
789
804
|
def _bcd_bits(n: int) -> Generator[bool]:
|
790
|
-
"""Return the bcd representation of n, starting with the least significant bit
|
805
|
+
"""Return the (infinite) bcd representation of n, starting with the least significant bit
|
806
|
+
|
807
|
+
This continues to yield `False` forever after the nonzero bcd digits have been genrated.
|
808
|
+
This allows to `zip(strict=False)` the resulting bits together with a sequence of indices
|
809
|
+
and ensure all the upper bits are set to zero.
|
810
|
+
"""
|
791
811
|
while True:
|
792
812
|
d = n % 10
|
793
813
|
n = n // 10
|
@@ -866,7 +886,7 @@ class WWVBTimecode:
|
|
866
886
|
Treating 'poslist' as a sequence of indices, update the AM signal with the value as a BCD number
|
867
887
|
"""
|
868
888
|
pos = list(poslist)[::-1]
|
869
|
-
for p, b in zip(pos, _bcd_bits(v)):
|
889
|
+
for p, b in zip(pos, _bcd_bits(v), strict=False):
|
870
890
|
if b:
|
871
891
|
self.am[p] = AmplitudeModulation.ONE
|
872
892
|
else:
|
@@ -894,7 +914,7 @@ class WWVBTimecode:
|
|
894
914
|
return ("⁰", "¹", "²", "¿")[am]
|
895
915
|
return ("₀", "₁", "₂", "⸮")[am]
|
896
916
|
|
897
|
-
return "".join(convert_one(i, j) for i, j in zip(self.am, self.phase))
|
917
|
+
return "".join(convert_one(i, j) for i, j in zip(self.am, self.phase, strict=True))
|
898
918
|
|
899
919
|
def __repr__(self) -> str:
|
900
920
|
"""Implement repr()"""
|
@@ -912,7 +932,7 @@ class WWVBTimecode:
|
|
912
932
|
|
913
933
|
def to_both_string(self, charset: list[str]) -> str:
|
914
934
|
"""Convert both channels to a string"""
|
915
|
-
return "".join(charset[i + j * 3] for i, j in zip(self.am, self.phase))
|
935
|
+
return "".join(charset[i + j * 3] for i, j in zip(self.am, self.phase, strict=True))
|
916
936
|
|
917
937
|
|
918
938
|
styles = {
|
@@ -927,7 +947,7 @@ styles = {
|
|
927
947
|
def print_timecodes(
|
928
948
|
w: WWVBMinute,
|
929
949
|
minutes: int,
|
930
|
-
channel:
|
950
|
+
channel: WWVBChannel,
|
931
951
|
style: str,
|
932
952
|
file: TextIO,
|
933
953
|
*,
|
@@ -964,7 +984,7 @@ def print_timecodes(
|
|
964
984
|
def print_timecodes_json(
|
965
985
|
w: WWVBMinute,
|
966
986
|
minutes: int,
|
967
|
-
channel:
|
987
|
+
channel: WWVBChannel,
|
968
988
|
file: TextIO,
|
969
989
|
) -> None:
|
970
990
|
"""Print a range of timecodes in JSON format.
|
@@ -984,7 +1004,7 @@ def print_timecodes_json(
|
|
984
1004
|
"""
|
985
1005
|
result = []
|
986
1006
|
for _ in range(minutes):
|
987
|
-
data:
|
1007
|
+
data: JsonMinute = {
|
988
1008
|
"year": w.year,
|
989
1009
|
"days": w.days,
|
990
1010
|
"hour": w.hour,
|
wwvb/__version__.py
CHANGED
@@ -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.0rc2'
|
32
|
+
__version_tuple__ = version_tuple = (8, 0, 0, 'rc2')
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
wwvb/decode.py
CHANGED
wwvb/gen.py
CHANGED
@@ -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:
|
wwvb/iersdata.json
CHANGED
@@ -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"}
|
wwvb/updateiers.py
CHANGED
@@ -15,13 +15,16 @@ import gzip
|
|
15
15
|
import io
|
16
16
|
import json
|
17
17
|
import pathlib
|
18
|
-
from typing import
|
18
|
+
from typing import TYPE_CHECKING
|
19
19
|
|
20
20
|
import bs4
|
21
21
|
import click
|
22
22
|
import platformdirs
|
23
23
|
import requests
|
24
24
|
|
25
|
+
if TYPE_CHECKING:
|
26
|
+
from collections.abc import Callable
|
27
|
+
|
25
28
|
DIST_PATH = pathlib.Path(__file__).parent / "iersdata.json"
|
26
29
|
|
27
30
|
IERS_URL = "https://datacenter.iers.org/data/csv/finals2000A.all.csv"
|
wwvb/wwvbtk.py
CHANGED
@@ -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,19 +1,16 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: wwvb
|
3
|
-
Version:
|
3
|
+
Version: 8.0.0rc2
|
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://wwvbpy.readthedocs.io/en/latest/
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
|
-
Classifier: Programming Language :: Python :: 3.9
|
10
|
-
Classifier: Programming Language :: Python :: 3.10
|
11
|
-
Classifier: Programming Language :: Python :: 3.11
|
12
9
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
13
10
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
14
11
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
15
12
|
Classifier: Operating System :: OS Independent
|
16
|
-
Requires-Python: >=3.
|
13
|
+
Requires-Python: >=3.10
|
17
14
|
Description-Content-Type: text/markdown
|
18
15
|
Requires-Dist: adafruit-circuitpython-datetime
|
19
16
|
Requires-Dist: beautifulsoup4
|
@@ -29,11 +26,7 @@ SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
|
29
26
|
|
30
27
|
SPDX-License-Identifier: GPL-3.0-only
|
31
28
|
-->
|
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
29
|
[](https://pypi.org/project/wwvb)
|
36
|
-
[](https://results.pre-commit.ci/latest/github/jepler/wwvbpy/main)
|
37
30
|
|
38
31
|
# Purpose
|
39
32
|
|
@@ -63,7 +56,7 @@ The package includes:
|
|
63
56
|
|
64
57
|
# Development status
|
65
58
|
|
66
|
-
The author ([@jepler](https://
|
59
|
+
The author ([@jepler](https://unpythonic.net)) occasionally develops and maintains this project, but
|
67
60
|
issues are not likely to be acted on. They would be interested in adding
|
68
61
|
co-maintainer(s).
|
69
62
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
uwwvb.py,sha256=Ybf8DeOZ5VjfqRGtO90_oEEW6HhGaztIVlh4L423MdQ,5801
|
2
|
+
wwvb/__init__.py,sha256=aFz_HXvOD5D4k_pWDgHA_kTWkBz-s3Ed5qY6W6MmuKE,34127
|
3
|
+
wwvb/__version__.py,sha256=BQnZGkrpqxv2i40P0cKXrysqXuu3x1wKpbxl8fOcQu8,714
|
4
|
+
wwvb/decode.py,sha256=JQw8XT9AoXlJAl16JRZzjECUPfA7jLhDxI-_XSibzbc,2748
|
5
|
+
wwvb/dut1table.py,sha256=HVX1338RlQzAQ-bsMPEdmCqoyIxSWoJSoRu1YGyaJO4,875
|
6
|
+
wwvb/gen.py,sha256=iMTYLtyy3ItC4AplTakkOhHNHzDFVmApjlVwYIK72nI,3798
|
7
|
+
wwvb/iersdata.json,sha256=lUMrygiih4_ItKX_t8Hqnx5bt9_1D1jocPycbtzOfhE,769
|
8
|
+
wwvb/iersdata.json.license,sha256=1k5fhRCuOn0yXbwHtB21G0Nntnf0qMxstflMHuK3-Js,71
|
9
|
+
wwvb/iersdata.py,sha256=nMqA1xcE-iPtmi9m5qcTIJwfsCxZwoNsxHfM-wvooMQ,1210
|
10
|
+
wwvb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
wwvb/tz.py,sha256=nlxKnzFPmqLLtC-cEDhWaJ3v3GCSPfqzVtUMf8EEdZ0,248
|
12
|
+
wwvb/updateiers.py,sha256=WsyFqkoxlvJS70dwW8vQhMseVACX0VwQRWWm2NyfV4Y,5846
|
13
|
+
wwvb/wwvbtk.py,sha256=cFBUduN8rQEdrpB0NtHK5r8HNDYfg_3XD7mbhYrVSrk,5284
|
14
|
+
wwvb-8.0.0rc2.dist-info/METADATA,sha256=sgVxOqNBSjlsAdw02aZJMSxkACg7GCBmXs8O5Fc7kww,9467
|
15
|
+
wwvb-8.0.0rc2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
wwvb-8.0.0rc2.dist-info/entry_points.txt,sha256=KSevvHWLEKxOxUQ-L-OQidD4Sj2BPEfhZ2TQhOgyys4,179
|
17
|
+
wwvb-8.0.0rc2.dist-info/top_level.txt,sha256=0IYdkhEAMgurpv_F-76rlyn4GdxepGFzG99tivVdQVU,11
|
18
|
+
wwvb-8.0.0rc2.dist-info/RECORD,,
|
wwvb-7.0.0.dist-info/RECORD
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
uwwvb.py,sha256=Ybf8DeOZ5VjfqRGtO90_oEEW6HhGaztIVlh4L423MdQ,5801
|
2
|
-
wwvb/__init__.py,sha256=tSEjmfqKR0KYdN7tUySGcXpK_W8rzQTtEXG7P_0WPMA,33432
|
3
|
-
wwvb/__version__.py,sha256=lB_6pZBic6H_5wY9p7_cc7miE65gtXFl65pORFxuiX0,704
|
4
|
-
wwvb/decode.py,sha256=llTLKBW49nl6COheM90NsyMnTNeVApl2oeCHtl6Tf3w,2759
|
5
|
-
wwvb/dut1table.py,sha256=HVX1338RlQzAQ-bsMPEdmCqoyIxSWoJSoRu1YGyaJO4,875
|
6
|
-
wwvb/gen.py,sha256=_fpUypu_2nZfG5Vjnya0B8C26nk1WOhnLMTCXwskAHs,3720
|
7
|
-
wwvb/iersdata.json,sha256=fEElNoF4UJMySnUvNXFlI9TT9k67jdrrGKzO6A1F2rQ,769
|
8
|
-
wwvb/iersdata.json.license,sha256=1k5fhRCuOn0yXbwHtB21G0Nntnf0qMxstflMHuK3-Js,71
|
9
|
-
wwvb/iersdata.py,sha256=nMqA1xcE-iPtmi9m5qcTIJwfsCxZwoNsxHfM-wvooMQ,1210
|
10
|
-
wwvb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
-
wwvb/tz.py,sha256=nlxKnzFPmqLLtC-cEDhWaJ3v3GCSPfqzVtUMf8EEdZ0,248
|
12
|
-
wwvb/updateiers.py,sha256=q3QY--fj06HJ9wCRCmVQK7pCpdXhCudP8BdUPG5WWOA,5781
|
13
|
-
wwvb/wwvbtk.py,sha256=cdLwWfulywHmGhaiK6L-m_QQAdpfDfyDFagbe_Y8Rgk,5186
|
14
|
-
wwvb-7.0.0.dist-info/METADATA,sha256=6oqjB6nkDQAYeoe8hGbSq5jk9Cj7q9swibX6jubJ-b4,10201
|
15
|
-
wwvb-7.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
-
wwvb-7.0.0.dist-info/entry_points.txt,sha256=KSevvHWLEKxOxUQ-L-OQidD4Sj2BPEfhZ2TQhOgyys4,179
|
17
|
-
wwvb-7.0.0.dist-info/top_level.txt,sha256=0IYdkhEAMgurpv_F-76rlyn4GdxepGFzG99tivVdQVU,11
|
18
|
-
wwvb-7.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|