wwvb 4.0.0a0__py3-none-any.whl → 4.1.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.
wwvb/testls.py DELETED
@@ -1,63 +0,0 @@
1
- #!/usr/bin/python3
2
- """Leap seconds tests"""
3
-
4
- # SPDX-FileCopyrightText: 2021 Jeff Epler
5
- #
6
- # SPDX-License-Identifier: GPL-3.0-only
7
-
8
- import datetime
9
- import unittest
10
-
11
- import leapseconddata
12
-
13
- import wwvb
14
-
15
- from . import iersdata
16
-
17
- ONE_DAY = datetime.timedelta(days=1)
18
-
19
-
20
- def next_month(d: datetime.date) -> datetime.date:
21
- """Return the start of the next month after the day 'd'"""
22
- d = d.replace(day=28)
23
- while True:
24
- d0 = d
25
- d = d + ONE_DAY
26
- if d.month != d0.month:
27
- return d
28
-
29
-
30
- class TestLeapSecond(unittest.TestCase):
31
- """Leap second tests"""
32
-
33
- maxDiff = 9999
34
-
35
- def test_leap(self) -> None:
36
- """Tests that the expected leap seconds all occur."""
37
- ls = leapseconddata.LeapSecondData.from_standard_source()
38
- assert ls.valid_until is not None
39
-
40
- d = iersdata.start
41
- e = min(iersdata.end, ls.valid_until)
42
- bench = [ts.start for ts in ls.leap_seconds[1:]]
43
- bench = [ts for ts in bench if d <= ts < e]
44
- leap = []
45
- while d < e:
46
- nm = next_month(d)
47
- eom = nm - ONE_DAY
48
- month_ends_dut1 = wwvb.get_dut1(eom)
49
- month_starts_dut1 = wwvb.get_dut1(nm)
50
- our_is_ls = month_ends_dut1 * month_starts_dut1 < 0
51
- if wwvb.isls(eom):
52
- assert our_is_ls
53
- self.assertLess(month_ends_dut1, 0)
54
- self.assertGreater(month_starts_dut1, 0)
55
- leap.append(nm)
56
- else:
57
- assert not our_is_ls
58
- d = datetime.datetime.combine(nm, datetime.time()).replace(tzinfo=datetime.timezone.utc)
59
- self.assertEqual(leap, bench)
60
-
61
-
62
- if __name__ == "__main__": # pragma: no cover
63
- unittest.main()
wwvb/testpm.py DELETED
@@ -1,33 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test Phase Modulation Signal"""
3
-
4
- # SPDX-FileCopyrightText: 2021 Jeff Epler
5
- #
6
- # SPDX-License-Identifier: GPL-3.0-only
7
-
8
- import unittest
9
-
10
- import wwvb
11
-
12
-
13
- class TestPhaseModulation(unittest.TestCase):
14
- """Test Phase Modulation Signal"""
15
-
16
- def test_pm(self) -> None:
17
- """Compare the generated signal from a reference minute in NIST docs"""
18
- ref_am = "201100000200010011120001010002011000101201000000120010010112"
19
-
20
- ref_pm = "001110110100010010000011001000011000110100110100010110110110"
21
-
22
- ref_minute = wwvb.WWVBMinuteIERS(2012, 186, 17, 30, dst=3)
23
- ref_time = ref_minute.as_timecode()
24
-
25
- test_am = ref_time.to_am_string(["0", "1", "2"])
26
- test_pm = ref_time.to_pm_string(["0", "1"])
27
-
28
- self.assertEqual(ref_am, test_am)
29
- self.assertEqual(ref_pm, test_pm)
30
-
31
-
32
- if __name__ == "__main__": # pragma: no cover
33
- unittest.main()
wwvb/testuwwvb.py DELETED
@@ -1,221 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test of uwwvb.py"""
3
- # SPDX-FileCopyrightText: 2021 Jeff Epler
4
- #
5
- # SPDX-License-Identifier: GPL-3.0-only
6
-
7
- # ruff: noqa: N802 D102
8
- import datetime
9
- import random
10
- import sys
11
- import unittest
12
- from typing import Union
13
-
14
- import adafruit_datetime
15
- import uwwvb
16
- import zoneinfo
17
-
18
- import wwvb
19
-
20
- EitherDatetimeOrNone = Union[None, datetime.datetime, adafruit_datetime.datetime]
21
-
22
-
23
- class WWVBRoundtrip(unittest.TestCase):
24
- """tests of uwwvb.py"""
25
-
26
- def assertDateTimeEqualExceptTzInfo(self, a: EitherDatetimeOrNone, b: EitherDatetimeOrNone) -> None:
27
- """Test two datetime objects for equality
28
-
29
- This equality test excludes tzinfo, and allows adafruit_datetime and core datetime modules to compare equal
30
- """
31
- assert a
32
- assert b
33
- self.assertEqual(
34
- (a.year, a.month, a.day, a.hour, a.minute, a.second, a.microsecond),
35
- (b.year, b.month, b.day, b.hour, b.minute, b.second, b.microsecond),
36
- )
37
-
38
- def test_decode(self) -> None:
39
- """Test decoding of some minutes including a leap second.
40
-
41
- Each minute must decode and match the primary decoder.
42
- """
43
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
44
- assert minute
45
- decoder = uwwvb.WWVBDecoder()
46
- decoder.update(uwwvb.MARK)
47
- any_leap_second = False
48
- for _ in range(20):
49
- timecode = minute.as_timecode()
50
- decoded = None
51
- if len(timecode.am) == 61:
52
- any_leap_second = True
53
- for code in timecode.am:
54
- decoded = uwwvb.decode_wwvb(decoder.update(int(code))) or decoded
55
- assert decoded
56
- self.assertDateTimeEqualExceptTzInfo(
57
- minute.as_datetime_utc(),
58
- uwwvb.as_datetime_utc(decoded),
59
- )
60
- minute = minute.next_minute()
61
- self.assertTrue(any_leap_second)
62
-
63
- def test_roundtrip(self) -> None:
64
- """Test that some big range of times all decode the same as the primary decoder"""
65
- dt = datetime.datetime(2002, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
66
- delta = datetime.timedelta(minutes=7182 if sys.implementation.name == "cpython" else 86400 - 7182)
67
- while dt.year < 2013:
68
- minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
69
- assert minute
70
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
71
- assert decoded
72
- self.assertDateTimeEqualExceptTzInfo(minute.as_datetime_utc(), uwwvb.as_datetime_utc(decoded))
73
- dt = dt + delta
74
-
75
- def test_dst(self) -> None:
76
- """Test of DST as handled by the small decoder"""
77
- for dt in (
78
- datetime.datetime(2021, 3, 14, 8, 59, tzinfo=datetime.timezone.utc),
79
- datetime.datetime(2021, 3, 14, 9, 00, tzinfo=datetime.timezone.utc),
80
- datetime.datetime(2021, 3, 14, 9, 1, tzinfo=datetime.timezone.utc),
81
- datetime.datetime(2021, 3, 15, 8, 59, tzinfo=datetime.timezone.utc),
82
- datetime.datetime(2021, 3, 15, 9, 00, tzinfo=datetime.timezone.utc),
83
- datetime.datetime(2021, 3, 15, 9, 1, tzinfo=datetime.timezone.utc),
84
- datetime.datetime(2021, 11, 7, 8, 59, tzinfo=datetime.timezone.utc),
85
- datetime.datetime(2021, 11, 7, 9, 00, tzinfo=datetime.timezone.utc),
86
- datetime.datetime(2021, 11, 7, 9, 1, tzinfo=datetime.timezone.utc),
87
- datetime.datetime(2021, 11, 8, 8, 59, tzinfo=datetime.timezone.utc),
88
- datetime.datetime(2021, 11, 8, 9, 00, tzinfo=datetime.timezone.utc),
89
- datetime.datetime(2021, 11, 8, 9, 1, tzinfo=datetime.timezone.utc),
90
- datetime.datetime(2021, 7, 7, 9, 1, tzinfo=datetime.timezone.utc),
91
- ):
92
- minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
93
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
94
- assert decoded
95
- self.assertDateTimeEqualExceptTzInfo(minute.as_datetime_local(), uwwvb.as_datetime_local(decoded))
96
-
97
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
98
- assert decoded
99
- self.assertDateTimeEqualExceptTzInfo(
100
- minute.as_datetime_local(dst_observed=False),
101
- uwwvb.as_datetime_local(decoded, dst_observed=False),
102
- )
103
-
104
- def test_noise(self) -> None:
105
- """Test of the state-machine decoder when faced with pseudorandom noise"""
106
- minute = wwvb.WWVBMinuteIERS.from_datetime(
107
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
108
- )
109
- r = random.Random(408)
110
- junk = [
111
- r.choice(
112
- [
113
- wwvb.AmplitudeModulation.MARK,
114
- wwvb.AmplitudeModulation.ONE,
115
- wwvb.AmplitudeModulation.ZERO,
116
- ],
117
- )
118
- for _ in range(480)
119
- ]
120
- timecode = minute.as_timecode()
121
- test_input = [*junk, wwvb.AmplitudeModulation.MARK, *timecode.am]
122
- decoder = uwwvb.WWVBDecoder()
123
- for code in test_input[:-1]:
124
- decoded = decoder.update(code)
125
- self.assertIsNone(decoded)
126
- minute_maybe = decoder.update(wwvb.AmplitudeModulation.MARK)
127
- assert minute_maybe
128
- decoded_minute = uwwvb.decode_wwvb(minute_maybe)
129
- assert decoded_minute
130
- self.assertDateTimeEqualExceptTzInfo(
131
- minute.as_datetime_utc(),
132
- uwwvb.as_datetime_utc(decoded_minute),
133
- )
134
- self.assertDateTimeEqualExceptTzInfo(
135
- minute.as_datetime_local(),
136
- uwwvb.as_datetime_local(decoded_minute),
137
- )
138
-
139
- def test_noise2(self) -> None:
140
- """Test of the full minute decoder with targeted errors to get full coverage"""
141
- minute = wwvb.WWVBMinuteIERS.from_datetime(
142
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
143
- )
144
- timecode = minute.as_timecode()
145
- decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
146
- self.assertIsNotNone(decoded)
147
- for position in uwwvb.always_mark:
148
- test_input = [int(i) for i in timecode.am]
149
- for noise in (0, 1):
150
- test_input[position] = noise
151
- decoded = uwwvb.decode_wwvb(test_input)
152
- self.assertIsNone(decoded)
153
- for position in uwwvb.always_zero:
154
- test_input = [int(i) for i in timecode.am]
155
- for noise in (1, 2):
156
- test_input[position] = noise
157
- decoded = uwwvb.decode_wwvb(test_input)
158
- self.assertIsNone(decoded)
159
- for i in range(8):
160
- if i in (0b101, 0b010): # Test the 6 impossible bit-combos
161
- continue
162
- test_input = [int(i) for i in timecode.am]
163
- test_input[36] = i & 1
164
- test_input[37] = (i >> 1) & 1
165
- test_input[38] = (i >> 2) & 1
166
- decoded = uwwvb.decode_wwvb(test_input)
167
- self.assertIsNone(decoded)
168
- # Invalid year-day
169
- test_input = [int(i) for i in timecode.am]
170
- test_input[22] = 1
171
- test_input[23] = 1
172
- test_input[25] = 1
173
- decoded = uwwvb.decode_wwvb(test_input)
174
- self.assertIsNone(decoded)
175
-
176
- def test_noise3(self) -> None:
177
- """Test impossible BCD values"""
178
- minute = wwvb.WWVBMinuteIERS.from_datetime(
179
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
180
- )
181
- timecode = minute.as_timecode()
182
-
183
- for poslist in [
184
- [1, 2, 3, 4], # tens minutes
185
- [5, 6, 7, 8], # ones minutes
186
- [15, 16, 17, 18], # tens hours
187
- [25, 26, 27, 28], # tens days
188
- [30, 31, 32, 33], # ones days
189
- [40, 41, 42, 43], # tens years
190
- [45, 46, 47, 48], # ones years
191
- [50, 51, 52, 53], # ones dut1
192
- ]:
193
- with self.subTest(test=poslist):
194
- test_input = [int(i) for i in timecode.am]
195
- for pi in poslist:
196
- test_input[pi] = 1
197
- decoded = uwwvb.decode_wwvb(test_input)
198
- self.assertIsNone(decoded)
199
-
200
- def test_str(self) -> None:
201
- """Test the str() of a WWVBDecoder"""
202
- self.assertEqual(str(uwwvb.WWVBDecoder()), "<WWVBDecoder 1 []>")
203
-
204
- def test_near_year_bug(self) -> None:
205
- """Test for a bug seen in another WWVB implementaiton
206
-
207
- .. in which the hours after UTC midnight on 12-31 of a leap year would
208
- be shown incorrectly. Check that we don't have that bug.
209
- """
210
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2021, 1, 1, 0, 0, tzinfo=datetime.timezone.utc))
211
- timecode = minute.as_timecode()
212
- decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
213
- assert decoded
214
- self.assertDateTimeEqualExceptTzInfo(
215
- datetime.datetime(2020, 12, 31, 17, 00, tzinfo=zoneinfo.ZoneInfo("America/Denver")), # Mountain time!
216
- uwwvb.as_datetime_local(decoded),
217
- )
218
-
219
-
220
- if __name__ == "__main__": # pragma no cover
221
- unittest.main()