wwvb 3.0.8__py3-none-any.whl → 4.0.0a0__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.
- uwwvb.py +4 -1
- wwvb/__init__.py +210 -169
- wwvb/__version__.py +2 -2
- wwvb/decode.py +8 -9
- wwvb/gen.py +14 -13
- wwvb/iersdata.py +4 -5
- wwvb/iersdata_dist.py +3 -3
- wwvb/testcli.py +8 -3
- wwvb/testpm.py +2 -2
- wwvb/testuwwvb.py +41 -28
- wwvb/testwwvb.py +51 -39
- wwvb/updateiers.py +34 -31
- wwvb/wwvbtk.py +12 -10
- {wwvb-3.0.8.dist-info → wwvb-4.0.0a0.dist-info}/METADATA +1 -1
- wwvb-4.0.0a0.dist-info/RECORD +23 -0
- {wwvb-3.0.8.dist-info → wwvb-4.0.0a0.dist-info}/WHEEL +1 -1
- wwvb-3.0.8.dist-info/RECORD +0 -23
- {wwvb-3.0.8.dist-info → wwvb-4.0.0a0.dist-info}/entry_points.txt +0 -0
- {wwvb-3.0.8.dist-info → wwvb-4.0.0a0.dist-info}/top_level.txt +0 -0
wwvb/updateiers.py
CHANGED
@@ -6,32 +6,34 @@
|
|
6
6
|
|
7
7
|
"""Update the DUT1 and LS data based on online sources"""
|
8
8
|
|
9
|
+
from __future__ import annotations
|
10
|
+
|
9
11
|
import csv
|
10
12
|
import datetime
|
11
13
|
import io
|
12
14
|
import itertools
|
13
|
-
import os
|
14
15
|
import pathlib
|
15
|
-
from typing import Callable
|
16
|
+
from typing import Callable
|
16
17
|
|
17
18
|
import bs4
|
18
19
|
import click
|
19
20
|
import platformdirs
|
20
21
|
import requests
|
21
22
|
|
22
|
-
DIST_PATH =
|
23
|
+
DIST_PATH = pathlib.Path(__file__).parent / "iersdata_dist.py"
|
23
24
|
|
24
|
-
OLD_TABLE_START:
|
25
|
-
OLD_TABLE_END:
|
26
|
-
if
|
25
|
+
OLD_TABLE_START: datetime.date | None = None
|
26
|
+
OLD_TABLE_END: datetime.date | None = None
|
27
|
+
if DIST_PATH.exists():
|
27
28
|
import wwvb.iersdata_dist
|
28
29
|
|
29
30
|
OLD_TABLE_START = wwvb.iersdata_dist.DUT1_DATA_START
|
30
31
|
OLD_TABLE_END = OLD_TABLE_START + datetime.timedelta(days=len(wwvb.iersdata_dist.DUT1_OFFSETS) - 1)
|
31
32
|
|
32
33
|
IERS_URL = "https://datacenter.iers.org/data/csv/finals2000A.all.csv"
|
33
|
-
|
34
|
-
|
34
|
+
IERS_PATH = pathlib.Path("finals2000A.all.csv")
|
35
|
+
if IERS_PATH.exists():
|
36
|
+
IERS_URL = str(IERS_PATH)
|
35
37
|
print("using local", IERS_URL)
|
36
38
|
NIST_URL = "https://www.nist.gov/pml/time-and-frequency-division/atomic-standards/leap-second-and-ut1-utc-information"
|
37
39
|
|
@@ -42,15 +44,14 @@ def _get_text(url: str) -> str:
|
|
42
44
|
with requests.get(url, timeout=30) as response:
|
43
45
|
return response.text
|
44
46
|
else:
|
45
|
-
return
|
47
|
+
return pathlib.Path(url).read_text(encoding="utf-8")
|
46
48
|
|
47
49
|
|
48
|
-
def update_iersdata(
|
49
|
-
|
50
|
+
def update_iersdata( # noqa: PLR0915, PLR0912
|
51
|
+
target_path: pathlib.Path,
|
50
52
|
) -> None:
|
51
53
|
"""Update iersdata.py"""
|
52
|
-
|
53
|
-
offsets: List[int] = []
|
54
|
+
offsets: list[int] = []
|
54
55
|
iersdata_text = _get_text(IERS_URL)
|
55
56
|
for r in csv.DictReader(io.StringIO(iersdata_text), delimiter=";"):
|
56
57
|
jd = float(r["MJD"])
|
@@ -97,11 +98,11 @@ def update_iersdata(
|
|
97
98
|
off_end = (patch_end - table_start).days
|
98
99
|
offsets[off_start:off_end] = [val] * (off_end - off_start)
|
99
100
|
|
100
|
-
wwvb_dut1:
|
101
|
-
wwvb_start:
|
101
|
+
wwvb_dut1: int | None = None
|
102
|
+
wwvb_start: datetime.date | None = None
|
102
103
|
for row in wwvb_dut1_table.findAll("tr")[1:][::-1]:
|
103
104
|
cells = row.findAll("td")
|
104
|
-
when = datetime.datetime.strptime(cells[0].text, "%Y-%m-%d").date()
|
105
|
+
when = datetime.datetime.strptime(cells[0].text + "+0000", "%Y-%m-%d%z").date()
|
105
106
|
dut1 = cells[2].text.replace("s", "").replace(" ", "")
|
106
107
|
dut1 = int(round(float(dut1) * 10))
|
107
108
|
if wwvb_dut1 is not None:
|
@@ -123,7 +124,7 @@ def update_iersdata(
|
|
123
124
|
assert wwvb_start is not None
|
124
125
|
patch(wwvb_start, wwvb_data_stamp + datetime.timedelta(days=1), wwvb_dut1)
|
125
126
|
|
126
|
-
with open(
|
127
|
+
with target_path.open("w", encoding="utf-8") as output:
|
127
128
|
|
128
129
|
def code(*args: str) -> None:
|
129
130
|
"""Print to the output file"""
|
@@ -138,9 +139,9 @@ def update_iersdata(
|
|
138
139
|
code("import datetime")
|
139
140
|
|
140
141
|
code("__all__ = ['DUT1_DATA_START', 'DUT1_OFFSETS']")
|
141
|
-
code(f"DUT1_DATA_START = {
|
142
|
+
code(f"DUT1_DATA_START = {table_start!r}")
|
142
143
|
c = sorted(chr(ord("a") + ch + 10) for ch in set(offsets))
|
143
|
-
code(f"{','.join(c)} = tuple({
|
144
|
+
code(f"{','.join(c)} = tuple({''.join(c)!r})")
|
144
145
|
code(f"DUT1_OFFSETS = str( # {table_start.year:04d}{table_start.month:02d}{table_start.day:02d}")
|
145
146
|
line = ""
|
146
147
|
j = 0
|
@@ -151,10 +152,7 @@ def update_iersdata(
|
|
151
152
|
sz = len(list(it))
|
152
153
|
if j:
|
153
154
|
part = part + "+"
|
154
|
-
if sz < 2
|
155
|
-
part = part + ch
|
156
|
-
else:
|
157
|
-
part = part + f"{ch}*{sz}"
|
155
|
+
part = part + ch if sz < 2 else part + f"{ch}*{sz}"
|
158
156
|
j += sz
|
159
157
|
if len(line + part) > 60:
|
160
158
|
d = table_start + datetime.timedelta(j - 1)
|
@@ -171,25 +169,30 @@ def update_iersdata(
|
|
171
169
|
print(f"iersdata covers {table_start} .. {table_end}")
|
172
170
|
|
173
171
|
|
174
|
-
def iersdata_path(callback: Callable[[str, str],
|
172
|
+
def iersdata_path(callback: Callable[[str, str], pathlib.Path]) -> pathlib.Path:
|
175
173
|
"""Find out the path for this directory"""
|
176
|
-
|
174
|
+
print("iersdata_path", callback)
|
175
|
+
r = callback("wwvbpy", "unpythonic.net") / "wwvb_iersdata.py"
|
176
|
+
print(f"iersdata_path {r=!r}")
|
177
|
+
return r
|
177
178
|
|
178
179
|
|
179
180
|
@click.command()
|
180
181
|
@click.option(
|
181
182
|
"--user",
|
182
183
|
"location",
|
183
|
-
flag_value=iersdata_path(platformdirs.
|
184
|
-
default=iersdata_path(platformdirs.
|
184
|
+
flag_value=iersdata_path(platformdirs.user_data_path),
|
185
|
+
default=iersdata_path(platformdirs.user_data_path),
|
186
|
+
type=pathlib.Path,
|
185
187
|
)
|
186
188
|
@click.option("--dist", "location", flag_value=DIST_PATH)
|
187
|
-
@click.option("--site", "location", flag_value=iersdata_path(platformdirs.
|
189
|
+
@click.option("--site", "location", flag_value=iersdata_path(platformdirs.site_data_path))
|
188
190
|
def main(location: str) -> None:
|
189
191
|
"""Update DUT1 data"""
|
190
|
-
|
191
|
-
|
192
|
-
|
192
|
+
path = pathlib.Path(location)
|
193
|
+
print(f"will write to {location!r}")
|
194
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
195
|
+
update_iersdata(path)
|
193
196
|
|
194
197
|
|
195
198
|
if __name__ == "__main__":
|
wwvb/wwvbtk.py
CHANGED
@@ -5,12 +5,13 @@
|
|
5
5
|
# SPDX-FileCopyrightText: 2021 Jeff Epler
|
6
6
|
#
|
7
7
|
# SPDX-License-Identifier: GPL-3.0-only
|
8
|
+
from __future__ import annotations
|
8
9
|
|
9
10
|
import functools
|
10
11
|
import threading
|
11
12
|
import time
|
12
13
|
from tkinter import Canvas, TclError, Tk
|
13
|
-
from typing import Any, Generator
|
14
|
+
from typing import Any, Generator
|
14
15
|
|
15
16
|
import click
|
16
17
|
|
@@ -23,7 +24,7 @@ def _app() -> Tk:
|
|
23
24
|
return Tk()
|
24
25
|
|
25
26
|
|
26
|
-
def validate_colors(ctx: Any, param: Any, value: str) -> list[str]:
|
27
|
+
def validate_colors(ctx: Any, param: Any, value: str) -> list[str]: # noqa: ARG001
|
27
28
|
"""Check that all colors in a string are valid, splitting it to a list"""
|
28
29
|
app = _app()
|
29
30
|
colors = value.split()
|
@@ -53,9 +54,8 @@ DEFAULT_COLORS = "#3c3c3c #3c3c3c #3c3c3c #cc3c3c #88883c #3ccc3c"
|
|
53
54
|
@click.option("--colors", callback=validate_colors, default=DEFAULT_COLORS)
|
54
55
|
@click.option("--size", default=48)
|
55
56
|
@click.option("--min-size", default=None)
|
56
|
-
def main(colors: list[str], size: int, min_size:
|
57
|
+
def main(colors: list[str], size: int, min_size: int | None) -> None: # noqa: PLR0915
|
57
58
|
"""Visualize the WWVB signal in realtime"""
|
58
|
-
|
59
59
|
if min_size is None:
|
60
60
|
min_size = size
|
61
61
|
|
@@ -65,7 +65,7 @@ def main(colors: list[str], size: int, min_size: Optional[int]) -> None:
|
|
65
65
|
if deadline > now:
|
66
66
|
time.sleep(deadline - now)
|
67
67
|
|
68
|
-
def wwvbtick() -> Generator[
|
68
|
+
def wwvbtick() -> Generator[tuple[float, wwvb.AmplitudeModulation], None, None]:
|
69
69
|
"""Yield consecutive values of the WWVB amplitude signal, going from minute to minute"""
|
70
70
|
timestamp = time.time() // 60 * 60
|
71
71
|
|
@@ -77,13 +77,15 @@ def main(colors: list[str], size: int, min_size: Optional[int]) -> None:
|
|
77
77
|
yield timestamp + i, code
|
78
78
|
timestamp = timestamp + 60
|
79
79
|
|
80
|
-
def wwvbsmarttick() -> Generator[
|
81
|
-
"""Yield consecutive values of the WWVB amplitude signal
|
82
|
-
|
83
|
-
|
80
|
+
def wwvbsmarttick() -> Generator[tuple[float, wwvb.AmplitudeModulation], None, None]:
|
81
|
+
"""Yield consecutive values of the WWVB amplitude signal
|
82
|
+
|
83
|
+
.. but deal with time progressing unexpectedly, such as when the
|
84
|
+
computer is suspended or NTP steps the clock backwards
|
84
85
|
|
85
86
|
When time goes backwards or advances by more than a minute, get a fresh
|
86
|
-
wwvbtick object; otherwise, discard time signals more than 1s in the past.
|
87
|
+
wwvbtick object; otherwise, discard time signals more than 1s in the past.
|
88
|
+
"""
|
87
89
|
while True:
|
88
90
|
for stamp, code in wwvbtick():
|
89
91
|
now = time.time()
|
@@ -0,0 +1,23 @@
|
|
1
|
+
uwwvb.py,sha256=Ocys0AK10NocugDxNjIjUkL3_uVqD2Q6c2WLfqXmx1s,5732
|
2
|
+
wwvb/__init__.py,sha256=gSeXqukkcHnYCJAkbXk4eWBMqBu7n3GJ7CJM32XMiaU,30770
|
3
|
+
wwvb/__version__.py,sha256=vsEaiHcm9DvHyRWD600KxOTf-j-TilwuyCMsi2Ba3dE,413
|
4
|
+
wwvb/decode.py,sha256=d7bAG2pVsFMX0uxY6pMaz-psdbLXauSHh55JDaUT6W4,2713
|
5
|
+
wwvb/dut1table.py,sha256=uqaCnCOWr7ytx-nt3mmyhFb9jJVNP5N-WJX-glunKAk,890
|
6
|
+
wwvb/gen.py,sha256=0hgicarLgCtOgBgIpb9sU08yzKgCGuwIYOqblR34H5I,3791
|
7
|
+
wwvb/iersdata.py,sha256=NOItawXnXwd3Gq3K_cx85NVQ_iogLw3MDgzOI8q_75Y,924
|
8
|
+
wwvb/iersdata_dist.py,sha256=zQVO2AjiBTrhpSs21HUG9fL4S11K3WzTk0kP_eyMXz4,2364
|
9
|
+
wwvb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
wwvb/testcli.py,sha256=wa1E9iRaE62OBHshR4K_hxhIzSNxwpWy8rgoEKuhrqs,10168
|
11
|
+
wwvb/testdaylight.py,sha256=JW8UJK-FeAg9Kjy5F_aBYbUVj44DKpJOXQ-u9ooyprA,2485
|
12
|
+
wwvb/testls.py,sha256=Kz4-MWLaUKABwyql8sWdzvtg8gipxhHv4r-6fn3fptg,1720
|
13
|
+
wwvb/testpm.py,sha256=JR3V_EIm0Su3c4m5CcKpMANL3aZnpzEzDL3KhgKX3rM,905
|
14
|
+
wwvb/testuwwvb.py,sha256=SMvq85tJgjGMYHKsreCtlM4Wrb3MYOOjf5rKf9wuHYc,9176
|
15
|
+
wwvb/testwwvb.py,sha256=t0TUJhHOh-mRFD-GUvePzHs7D3DkNb_paRAI1uYH8l8,16807
|
16
|
+
wwvb/tz.py,sha256=XVYh0btrnyP_nUiZUwBjufkYbb26_DTiZVl-R_1BA2A,299
|
17
|
+
wwvb/updateiers.py,sha256=3Bg0cpQnTDrGWcHbi0rwZ4rSURJcO64Bds9FDTYLSK8,7382
|
18
|
+
wwvb/wwvbtk.py,sha256=WumGtKsAxMw1HMTfm5x4dOKmHikCaDBRZfh_WbF4iu0,4585
|
19
|
+
wwvb-4.0.0a0.dist-info/METADATA,sha256=lLqzL4USvZY6Md_rAg-k7OhzY2ySNPHjSWgTKwF8qG4,10292
|
20
|
+
wwvb-4.0.0a0.dist-info/WHEEL,sha256=Z4pYXqR_rTB7OWNDYFOm1qRk0RX6GFP2o8LgvP453Hk,91
|
21
|
+
wwvb-4.0.0a0.dist-info/entry_points.txt,sha256=KSevvHWLEKxOxUQ-L-OQidD4Sj2BPEfhZ2TQhOgyys4,179
|
22
|
+
wwvb-4.0.0a0.dist-info/top_level.txt,sha256=0IYdkhEAMgurpv_F-76rlyn4GdxepGFzG99tivVdQVU,11
|
23
|
+
wwvb-4.0.0a0.dist-info/RECORD,,
|
wwvb-3.0.8.dist-info/RECORD
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
uwwvb.py,sha256=UX5oSMs4KZPt1hg1urZXhN0pMU3BvQWYOKExZT8FiIo,5674
|
2
|
-
wwvb/__init__.py,sha256=oUUcweJnrFDVw5_-smJopfVAk5yNFlEnOkYMixNxZzc,29762
|
3
|
-
wwvb/__version__.py,sha256=UsWpfolO3V5lhkRSzLYHaglRPoxe1Nfcc4kMi3j-8W8,411
|
4
|
-
wwvb/decode.py,sha256=PBfBzYJJkIh8VD-d_SHvBl3gX4FpXhqG1lH2fP8lUaI,2758
|
5
|
-
wwvb/dut1table.py,sha256=uqaCnCOWr7ytx-nt3mmyhFb9jJVNP5N-WJX-glunKAk,890
|
6
|
-
wwvb/gen.py,sha256=pOSgkJTh_TDKN1FulzbAW8aN77bJXtJjo1KGoBEU3Dk,3697
|
7
|
-
wwvb/iersdata.py,sha256=hJFj-ZL3RP13dcdFGWoT6WOgoV-6CAy-sWSYfi_EXwg,965
|
8
|
-
wwvb/iersdata_dist.py,sha256=dmd6ShKPG5AHBm0dfRAKFpFpt8WDiW1NqNF8DLeMgrI,2363
|
9
|
-
wwvb/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
wwvb/testcli.py,sha256=06uIEdg-ZH0UOISr0X7oy4iAQ5eb4-MejQC7TeqIJz8,10086
|
11
|
-
wwvb/testdaylight.py,sha256=JW8UJK-FeAg9Kjy5F_aBYbUVj44DKpJOXQ-u9ooyprA,2485
|
12
|
-
wwvb/testls.py,sha256=Kz4-MWLaUKABwyql8sWdzvtg8gipxhHv4r-6fn3fptg,1720
|
13
|
-
wwvb/testpm.py,sha256=I5ajzZjUypyKszSe4sTnMZbS43nPmee4H1G3uZlHC_w,935
|
14
|
-
wwvb/testuwwvb.py,sha256=oj68-Vv1EFBG9MOWB8zW2sTN1Yg22nVYOL_Aor3IJTI,8398
|
15
|
-
wwvb/testwwvb.py,sha256=bWMI0-Qbaye9Afil4qyPKsNYtY-B6d1wBJZUn-MS99w,16109
|
16
|
-
wwvb/tz.py,sha256=XVYh0btrnyP_nUiZUwBjufkYbb26_DTiZVl-R_1BA2A,299
|
17
|
-
wwvb/updateiers.py,sha256=zpMvIzuPvKdA-XvBcOwQiFx7e9yH-V-VypL95bG5rWk,7240
|
18
|
-
wwvb/wwvbtk.py,sha256=fFXoyReyGZIEpddz74KY0vKfLm1ZP1jwDHTTAbVd8XY,4525
|
19
|
-
wwvb-3.0.8.dist-info/METADATA,sha256=99ps6bN93tu3nAzKIVWepexqDDaPtfeg_SR4a0c2fRI,10290
|
20
|
-
wwvb-3.0.8.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
21
|
-
wwvb-3.0.8.dist-info/entry_points.txt,sha256=KSevvHWLEKxOxUQ-L-OQidD4Sj2BPEfhZ2TQhOgyys4,179
|
22
|
-
wwvb-3.0.8.dist-info/top_level.txt,sha256=0IYdkhEAMgurpv_F-76rlyn4GdxepGFzG99tivVdQVU,11
|
23
|
-
wwvb-3.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|