wwvb 3.0.7__py3-none-any.whl → 4.0.0__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/__version__.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '3.0.7'
16
- __version_tuple__ = version_tuple = (3, 0, 7)
15
+ __version__ = version = '4.0.0'
16
+ __version_tuple__ = version_tuple = (4, 0, 0)
wwvb/decode.py CHANGED
@@ -3,8 +3,10 @@
3
3
  # SPDX-License-Identifier: GPL-3.0-only
4
4
  """A stateful decoder of WWVB signals"""
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import sys
7
- from typing import Generator, List, Optional
9
+ from typing import Generator
8
10
 
9
11
  import wwvb
10
12
 
@@ -20,12 +22,12 @@ import wwvb
20
22
  # State 4: Decoding a minute, starting in second 1
21
23
  # Second
22
24
 
23
- always_zero = set((4, 10, 11, 14, 20, 21, 34, 35, 44, 54))
25
+ always_zero = {4, 10, 11, 14, 20, 21, 34, 35, 44, 54}
24
26
 
25
27
 
26
- def wwvbreceive() -> Generator[Optional[wwvb.WWVBTimecode], wwvb.AmplitudeModulation, None]: # pylint: disable=too-many-branches
27
- """A stateful decoder of WWVB signals"""
28
- minute: List[wwvb.AmplitudeModulation] = []
28
+ def wwvbreceive() -> Generator[wwvb.WWVBTimecode | None, wwvb.AmplitudeModulation, None]:
29
+ """Decode WWVB signals statefully."""
30
+ minute: list[wwvb.AmplitudeModulation] = []
29
31
  state = 1
30
32
 
31
33
  value = yield None
@@ -38,10 +40,7 @@ def wwvbreceive() -> Generator[Optional[wwvb.WWVBTimecode], wwvb.AmplitudeModula
38
40
  value = yield None
39
41
 
40
42
  elif state == 2:
41
- if value == wwvb.AmplitudeModulation.MARK:
42
- state = 3
43
- else:
44
- state = 1
43
+ state = 3 if value == wwvb.AmplitudeModulation.MARK else 1
45
44
  value = yield None
46
45
 
47
46
  elif state == 3:
wwvb/gen.py CHANGED
@@ -6,9 +6,11 @@
6
6
  #
7
7
  # SPDX-License-Identifier: GPL-3.0-only
8
8
 
9
+ from __future__ import annotations
10
+
9
11
  import datetime
10
12
  import sys
11
- from typing import Any, List, Type
13
+ from typing import Any
12
14
 
13
15
  import click
14
16
  import dateutil.parser
@@ -16,17 +18,17 @@ import dateutil.parser
16
18
  from . import WWVBMinute, WWVBMinuteIERS, print_timecodes, print_timecodes_json, styles
17
19
 
18
20
 
19
- def parse_timespec( # pylint: disable=unused-argument
20
- ctx: Any, param: Any, value: List[str]
21
- ) -> datetime.datetime:
21
+ def parse_timespec(ctx: Any, param: Any, value: list[str]) -> datetime.datetime: # noqa: ARG001
22
22
  """Parse a time specifier from the commandline"""
23
23
  try:
24
24
  if len(value) == 5:
25
25
  year, month, day, hour, minute = map(int, value)
26
- return datetime.datetime(year, month, day, hour, minute)
26
+ return datetime.datetime(year, month, day, hour, minute, tzinfo=datetime.timezone.utc)
27
27
  if len(value) == 4:
28
28
  year, yday, hour, minute = map(int, value)
29
- return datetime.datetime(year, 1, 1, hour, minute) + datetime.timedelta(days=yday - 1)
29
+ return datetime.datetime(year, 1, 1, hour, minute, tzinfo=datetime.timezone.utc) + datetime.timedelta(
30
+ days=yday - 1,
31
+ )
30
32
  if len(value) == 1:
31
33
  return dateutil.parser.parse(value[0])
32
34
  if len(value) == 0:
@@ -70,7 +72,7 @@ def parse_timespec( # pylint: disable=unused-argument
70
72
  @click.option(
71
73
  "--style",
72
74
  default="default",
73
- type=click.Choice(sorted(["json"] + list(styles.keys()))),
75
+ type=click.Choice(sorted(["json", *list(styles.keys())])),
74
76
  help="Style of output",
75
77
  )
76
78
  @click.option(
@@ -87,8 +89,8 @@ def parse_timespec( # pylint: disable=unused-argument
87
89
  help="Modulation to show (default: amplitude)",
88
90
  )
89
91
  @click.argument("timespec", type=str, nargs=-1, callback=parse_timespec)
90
- # pylint: disable=too-many-arguments, too-many-locals
91
92
  def main(
93
+ *,
92
94
  iers: bool,
93
95
  leap_second: bool,
94
96
  dut1: int,
@@ -102,7 +104,6 @@ def main(
102
104
 
103
105
  TIMESPEC: one of "year yday hour minute" or "year month day hour minute", or else the current minute
104
106
  """
105
-
106
107
  if (leap_second is not None) or (dut1 is not None):
107
108
  iers = False
108
109
 
@@ -110,16 +111,13 @@ def main(
110
111
  newls = None
111
112
 
112
113
  if iers:
113
- Constructor: Type[WWVBMinute] = WWVBMinuteIERS
114
+ constructor: type[WWVBMinute] = WWVBMinuteIERS
114
115
  else:
115
- Constructor = WWVBMinute
116
- if dut1 is None:
117
- newut1 = -500 * (leap_second or 0)
118
- else:
119
- newut1 = dut1
116
+ constructor = WWVBMinute
117
+ newut1 = -500 * (leap_second or 0) if dut1 is None else dut1
120
118
  newls = bool(leap_second)
121
119
 
122
- w = Constructor.from_datetime(timespec, newls=newls, newut1=newut1)
120
+ w = constructor.from_datetime(timespec, newls=newls, newut1=newut1)
123
121
  if style == "json":
124
122
  print_timecodes_json(w, minutes, channel, file=sys.stdout)
125
123
  else:
wwvb/iersdata.py CHANGED
@@ -7,7 +7,7 @@
7
7
  # SPDX-License-Identifier: GPL-3.0-only
8
8
 
9
9
  import datetime
10
- import os
10
+ import pathlib
11
11
 
12
12
  import platformdirs
13
13
 
@@ -18,10 +18,9 @@ for location in [
18
18
  platformdirs.user_data_dir("wwvbpy", "unpythonic.net"),
19
19
  platformdirs.site_data_dir("wwvbpy", "unpythonic.net"),
20
20
  ]: # pragma no cover
21
- filename = os.path.join(location, "wwvbpy_iersdata.py")
22
- if os.path.exists(filename):
23
- with open(filename, encoding="utf-8") as f:
24
- exec(f.read(), globals(), globals()) # pylint: disable=exec-used
21
+ path = pathlib.Path(location) / "wwvbpy_iersdata.py"
22
+ if path.exists():
23
+ exec(path.read_text(encoding="utf-8"), globals(), globals())
25
24
  break
26
25
 
27
26
  start = datetime.datetime.combine(DUT1_DATA_START, datetime.time()).replace(tzinfo=datetime.timezone.utc)
wwvb/iersdata_dist.py CHANGED
@@ -1,15 +1,13 @@
1
1
  # -*- python3 -*-
2
+ # fmt: off
2
3
  """File generated from public data - not subject to copyright"""
3
-
4
4
  # SPDX-FileCopyrightText: Public domain
5
5
  # SPDX-License-Identifier: CC0-1.0
6
- # fmt: off
7
6
  # isort: skip_file
8
- # pylint: disable=invalid-name
9
7
  import datetime
10
- __all__ = ['DUT1_DATA_START', 'DUT1_OFFSETS']
8
+ __all__ = ["DUT1_DATA_START", "DUT1_OFFSETS"]
11
9
  DUT1_DATA_START = datetime.date(1972, 1, 1)
12
- d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s = tuple('defghijklmnopqrs')
10
+ d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s = tuple("defghijklmnopqrs")
13
11
  DUT1_OFFSETS = str( # 19720101
14
12
  i*182+s*123+k*30+i*31+s*19+r*31+q*29+p*28+o*30+n*36+m*40 # 19730909
15
13
  +l*39+k*33+j*31+i*31+h*18+r*19+q*38+p*32+o*31+n*33+m*48+l*45 # 19741010
@@ -36,5 +34,5 @@ DUT1_OFFSETS = str( # 19720101
36
34
  +i*126+h*176+g*97+f*91+e*52+o*116+n*98+m*70+l*133+k*91+j*91 # 20140507
37
35
  +i*77+h*140+g*91+f*84+e*70+d*34+n*72+m*76+l*66+k*53+j*56 # 20160831
38
36
  +i*105+h*77+g*45+q*25+p*63+o*91+n*154+m*105+l*190+k*118 # 20190501
39
- +j*105+i*807+j*376+k*771+l*42+k*142 # 20250308
37
+ +j*105+i*807+j*376+k*768+l*47+k*3+l*4+k*252, # 20250705
40
38
  )
wwvb/testcli.py CHANGED
@@ -1,13 +1,12 @@
1
1
  #!/usr/bin/python3
2
2
  """Test most wwvblib commandline programs"""
3
3
 
4
+ # ruff: noqa: N802 D102
4
5
  # Copyright (C) 2011-2020 Jeff Epler <jepler@gmail.com>
5
6
  # SPDX-FileCopyrightText: 2021 Jeff Epler
6
7
  #
7
8
  # SPDX-License-Identifier: GPL-3.0-only
8
9
 
9
- # pylint: disable=invalid-name
10
-
11
10
  import json
12
11
  import os
13
12
  import subprocess
@@ -27,7 +26,7 @@ class CLITestCase(unittest.TestCase):
27
26
  return subprocess.check_output(args, stdin=subprocess.DEVNULL, encoding="utf-8", env=env)
28
27
 
29
28
  def moduleArgs(self, *args: str) -> Sequence[str]:
30
- return tuple((sys.executable, *coverage_add, "-m", *args))
29
+ return (sys.executable, *coverage_add, "-m", *args)
31
30
 
32
31
  def moduleOutput(self, *args: str) -> str:
33
32
  return self.programOutput(sys.executable, *coverage_add, "-m", *args)
@@ -66,7 +65,11 @@ class CLITestCase(unittest.TestCase):
66
65
  env["PYTHONIOENCODING"] = "utf-8"
67
66
  with self.assertRaises(subprocess.SubprocessError):
68
67
  subprocess.check_output(
69
- args, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, encoding="utf-8", env=env
68
+ args,
69
+ stdin=subprocess.DEVNULL,
70
+ stderr=subprocess.DEVNULL,
71
+ encoding="utf-8",
72
+ env=env,
70
73
  )
71
74
 
72
75
  def assertModuleError(self, *args: str) -> None:
@@ -74,7 +77,7 @@ class CLITestCase(unittest.TestCase):
74
77
  self.assertProgramError(*self.moduleArgs(*args))
75
78
 
76
79
  def test_gen(self) -> None:
77
- """test wwvb.gen"""
80
+ """Test wwvb.gen"""
78
81
  self.assertModuleOutput(
79
82
  """\
80
83
  WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
wwvb/testpm.py CHANGED
@@ -15,9 +15,9 @@ class TestPhaseModulation(unittest.TestCase):
15
15
 
16
16
  def test_pm(self) -> None:
17
17
  """Compare the generated signal from a reference minute in NIST docs"""
18
- ref_am = "2011000002" "0001001112" "0001010002" "0110001012" "0100000012" "0010010112"
18
+ ref_am = "201100000200010011120001010002011000101201000000120010010112"
19
19
 
20
- ref_pm = "0011101101" "0001001000" "0011001000" "0110001101" "0011010001" "0110110110"
20
+ ref_pm = "001110110100010010000011001000011000110100110100010110110110"
21
21
 
22
22
  ref_minute = wwvb.WWVBMinuteIERS(2012, 186, 17, 30, dst=3)
23
23
  ref_time = ref_minute.as_timecode()
wwvb/testuwwvb.py CHANGED
@@ -4,6 +4,7 @@
4
4
  #
5
5
  # SPDX-License-Identifier: GPL-3.0-only
6
6
 
7
+ # ruff: noqa: N802 D102
7
8
  import datetime
8
9
  import random
9
10
  import sys
@@ -11,8 +12,9 @@ import unittest
11
12
  from typing import Union
12
13
 
13
14
  import adafruit_datetime
14
-
15
15
  import uwwvb
16
+ import zoneinfo
17
+
16
18
  import wwvb
17
19
 
18
20
  EitherDatetimeOrNone = Union[None, datetime.datetime, adafruit_datetime.datetime]
@@ -21,12 +23,11 @@ EitherDatetimeOrNone = Union[None, datetime.datetime, adafruit_datetime.datetime
21
23
  class WWVBRoundtrip(unittest.TestCase):
22
24
  """tests of uwwvb.py"""
23
25
 
24
- def assertDateTimeEqualExceptTzInfo( # pylint: disable=invalid-name
25
- self, a: EitherDatetimeOrNone, b: EitherDatetimeOrNone
26
- ) -> None:
26
+ def assertDateTimeEqualExceptTzInfo(self, a: EitherDatetimeOrNone, b: EitherDatetimeOrNone) -> None:
27
27
  """Test two datetime objects for equality
28
28
 
29
- This equality test excludes tzinfo, and allows adafruit_datetime and core datetime modules to compare equal"""
29
+ This equality test excludes tzinfo, and allows adafruit_datetime and core datetime modules to compare equal
30
+ """
30
31
  assert a
31
32
  assert b
32
33
  self.assertEqual(
@@ -36,8 +37,10 @@ class WWVBRoundtrip(unittest.TestCase):
36
37
 
37
38
  def test_decode(self) -> None:
38
39
  """Test decoding of some minutes including a leap second.
39
- Each minute must decode and match the primary decoder."""
40
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
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))
41
44
  assert minute
42
45
  decoder = uwwvb.WWVBDecoder()
43
46
  decoder.update(uwwvb.MARK)
@@ -59,7 +62,7 @@ class WWVBRoundtrip(unittest.TestCase):
59
62
 
60
63
  def test_roundtrip(self) -> None:
61
64
  """Test that some big range of times all decode the same as the primary decoder"""
62
- dt = datetime.datetime(2002, 1, 1, 0, 0)
65
+ dt = datetime.datetime(2002, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
63
66
  delta = datetime.timedelta(minutes=7182 if sys.implementation.name == "cpython" else 86400 - 7182)
64
67
  while dt.year < 2013:
65
68
  minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
@@ -72,19 +75,19 @@ class WWVBRoundtrip(unittest.TestCase):
72
75
  def test_dst(self) -> None:
73
76
  """Test of DST as handled by the small decoder"""
74
77
  for dt in (
75
- datetime.datetime(2021, 3, 14, 8, 59),
76
- datetime.datetime(2021, 3, 14, 9, 00),
77
- datetime.datetime(2021, 3, 14, 9, 1),
78
- datetime.datetime(2021, 3, 15, 8, 59),
79
- datetime.datetime(2021, 3, 15, 9, 00),
80
- datetime.datetime(2021, 3, 15, 9, 1),
81
- datetime.datetime(2021, 11, 7, 8, 59),
82
- datetime.datetime(2021, 11, 7, 9, 00),
83
- datetime.datetime(2021, 11, 7, 9, 1),
84
- datetime.datetime(2021, 11, 8, 8, 59),
85
- datetime.datetime(2021, 11, 8, 9, 00),
86
- datetime.datetime(2021, 11, 8, 9, 1),
87
- datetime.datetime(2021, 7, 7, 9, 1),
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),
88
91
  ):
89
92
  minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
90
93
  decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
@@ -100,7 +103,9 @@ class WWVBRoundtrip(unittest.TestCase):
100
103
 
101
104
  def test_noise(self) -> None:
102
105
  """Test of the state-machine decoder when faced with pseudorandom noise"""
103
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
106
+ minute = wwvb.WWVBMinuteIERS.from_datetime(
107
+ datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
108
+ )
104
109
  r = random.Random(408)
105
110
  junk = [
106
111
  r.choice(
@@ -108,12 +113,12 @@ class WWVBRoundtrip(unittest.TestCase):
108
113
  wwvb.AmplitudeModulation.MARK,
109
114
  wwvb.AmplitudeModulation.ONE,
110
115
  wwvb.AmplitudeModulation.ZERO,
111
- ]
116
+ ],
112
117
  )
113
118
  for _ in range(480)
114
119
  ]
115
120
  timecode = minute.as_timecode()
116
- test_input = junk + [wwvb.AmplitudeModulation.MARK] + timecode.am
121
+ test_input = [*junk, wwvb.AmplitudeModulation.MARK, *timecode.am]
117
122
  decoder = uwwvb.WWVBDecoder()
118
123
  for code in test_input[:-1]:
119
124
  decoded = decoder.update(code)
@@ -133,7 +138,9 @@ class WWVBRoundtrip(unittest.TestCase):
133
138
 
134
139
  def test_noise2(self) -> None:
135
140
  """Test of the full minute decoder with targeted errors to get full coverage"""
136
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
141
+ minute = wwvb.WWVBMinuteIERS.from_datetime(
142
+ datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
143
+ )
137
144
  timecode = minute.as_timecode()
138
145
  decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
139
146
  self.assertIsNotNone(decoded)
@@ -168,7 +175,9 @@ class WWVBRoundtrip(unittest.TestCase):
168
175
 
169
176
  def test_noise3(self) -> None:
170
177
  """Test impossible BCD values"""
171
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
178
+ minute = wwvb.WWVBMinuteIERS.from_datetime(
179
+ datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
180
+ )
172
181
  timecode = minute.as_timecode()
173
182
 
174
183
  for poslist in [
@@ -193,15 +202,17 @@ class WWVBRoundtrip(unittest.TestCase):
193
202
  self.assertEqual(str(uwwvb.WWVBDecoder()), "<WWVBDecoder 1 []>")
194
203
 
195
204
  def test_near_year_bug(self) -> None:
196
- """Chris's WWVB software had a bug where the hours after UTC
197
- midnight on 12-31 of a leap year would be shown incorrectly. Check that we
198
- don't have that bug."""
199
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2021, 1, 1, 0, 0))
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))
200
211
  timecode = minute.as_timecode()
201
212
  decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
202
213
  assert decoded
203
214
  self.assertDateTimeEqualExceptTzInfo(
204
- datetime.datetime(2020, 12, 31, 17, 00), # Mountain time!
215
+ datetime.datetime(2020, 12, 31, 17, 00, tzinfo=zoneinfo.ZoneInfo("America/Denver")), # Mountain time!
205
216
  uwwvb.as_datetime_local(decoded),
206
217
  )
207
218
 
wwvb/testwwvb.py CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/python3
2
+ # ruff: noqa: E501
3
+
2
4
  """Test most wwvblib functionality"""
3
5
 
4
6
  # Copyright (C) 2011-2020 Jeff Epler <jepler@gmail.com>
@@ -6,16 +8,18 @@
6
8
  #
7
9
  # SPDX-License-Identifier: GPL-3.0-only
8
10
 
11
+ from __future__ import annotations
12
+
9
13
  import copy
10
14
  import datetime
11
- import glob
12
15
  import io
16
+ import pathlib
13
17
  import random
14
18
  import sys
15
19
  import unittest
16
- from typing import Optional
17
20
 
18
21
  import uwwvb
22
+
19
23
  import wwvb
20
24
 
21
25
  from . import decode, iersdata, tz
@@ -27,7 +31,6 @@ class WWVBMinute2k(wwvb.WWVBMinute):
27
31
  epoch = 2000
28
32
 
29
33
 
30
- # pylint: disable=too-many-locals
31
34
  class WWVBTestCase(unittest.TestCase):
32
35
  """Test each expected output in tests/. Some outputs are from another program, some are from us"""
33
36
 
@@ -35,10 +38,9 @@ class WWVBTestCase(unittest.TestCase):
35
38
 
36
39
  def test_cases(self) -> None:
37
40
  """Generate a test case for each expected output in tests/"""
38
- for test in glob.glob("tests/*"):
41
+ for test in pathlib.Path("tests").glob("*"):
39
42
  with self.subTest(test=test):
40
- with open(test, "rt", encoding="utf-8") as f:
41
- text = f.read()
43
+ text = test.read_text(encoding="utf-8")
42
44
  lines = [line for line in text.split("\n") if not line.startswith("#")]
43
45
  while not lines[0]:
44
46
  del lines[0]
@@ -54,7 +56,7 @@ class WWVBTestCase(unittest.TestCase):
54
56
  elif o.startswith("--style="):
55
57
  style = o[8:]
56
58
  else:
57
- raise ValueError(f"Unknown option {repr(o)}")
59
+ raise ValueError(f"Unknown option {o!r}")
58
60
  num_minutes = len(lines) - 2
59
61
  if channel == "both":
60
62
  num_minutes = len(lines) // 3
@@ -85,14 +87,14 @@ class WWVBRoundtrip(unittest.TestCase):
85
87
 
86
88
  def test_decode(self) -> None:
87
89
  """Test that a range of minutes including a leap second are correctly decoded by the state-based decoder"""
88
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50))
90
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
89
91
  decoder = decode.wwvbreceive()
90
92
  next(decoder)
91
93
  decoder.send(wwvb.AmplitudeModulation.MARK)
92
94
  any_leap_second = False
93
95
  for _ in range(20):
94
96
  timecode = minute.as_timecode()
95
- decoded: Optional[wwvb.WWVBTimecode] = None
97
+ decoded: wwvb.WWVBTimecode | None = None
96
98
  if len(timecode.am) == 61:
97
99
  any_leap_second = True
98
100
  for code in timecode.am:
@@ -109,28 +111,28 @@ class WWVBRoundtrip(unittest.TestCase):
109
111
  def test_cover_fill_pm_timecode_extended(self) -> None:
110
112
  """Get full coverage of the function pm_timecode_extended"""
111
113
  for dt in (
112
- datetime.datetime(1992, 1, 1),
113
- datetime.datetime(1992, 4, 5),
114
- datetime.datetime(1992, 6, 1),
115
- datetime.datetime(1992, 10, 25),
114
+ datetime.datetime(1992, 1, 1, tzinfo=datetime.timezone.utc),
115
+ datetime.datetime(1992, 4, 5, tzinfo=datetime.timezone.utc),
116
+ datetime.datetime(1992, 6, 1, tzinfo=datetime.timezone.utc),
117
+ datetime.datetime(1992, 10, 25, tzinfo=datetime.timezone.utc),
116
118
  ):
117
119
  for hour in (0, 4, 11):
118
- dt = dt.replace(hour=hour, minute=10)
119
- minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
120
+ dt1 = dt.replace(hour=hour, minute=10)
121
+ minute = wwvb.WWVBMinuteIERS.from_datetime(dt1)
120
122
  assert minute is not None
121
123
  timecode = minute.as_timecode().am
122
124
  assert timecode
123
125
 
124
126
  def test_roundtrip(self) -> None:
125
127
  """Test that a wide of minutes are correctly decoded by the state-based decoder"""
126
- dt = datetime.datetime(1992, 1, 1, 0, 0)
128
+ dt = datetime.datetime(1992, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
127
129
  delta = datetime.timedelta(minutes=915 if sys.implementation.name == "cpython" else 86400 - 915)
128
130
  while dt.year < 1993:
129
131
  minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
130
132
  assert minute is not None
131
133
  timecode = minute.as_timecode().am
132
134
  assert timecode
133
- decoded_minute: Optional[wwvb.WWVBMinute] = wwvb.WWVBMinuteIERS.from_timecode_am(minute.as_timecode())
135
+ decoded_minute: wwvb.WWVBMinute | None = wwvb.WWVBMinuteIERS.from_timecode_am(minute.as_timecode())
134
136
  assert decoded_minute
135
137
  decoded = decoded_minute.as_timecode().am
136
138
  self.assertEqual(
@@ -142,7 +144,7 @@ class WWVBRoundtrip(unittest.TestCase):
142
144
 
143
145
  def test_noise(self) -> None:
144
146
  """Test against pseudorandom noise"""
145
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50))
147
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
146
148
  r = random.Random(408)
147
149
  junk = [
148
150
  r.choice(
@@ -150,12 +152,12 @@ class WWVBRoundtrip(unittest.TestCase):
150
152
  wwvb.AmplitudeModulation.MARK,
151
153
  wwvb.AmplitudeModulation.ONE,
152
154
  wwvb.AmplitudeModulation.ZERO,
153
- ]
155
+ ],
154
156
  )
155
157
  for _ in range(480)
156
158
  ]
157
159
  timecode = minute.as_timecode()
158
- test_input = junk + [wwvb.AmplitudeModulation.MARK] + timecode.am
160
+ test_input = [*junk, wwvb.AmplitudeModulation.MARK, *timecode.am]
159
161
  decoder = decode.wwvbreceive()
160
162
  next(decoder)
161
163
  for code in test_input[:-1]:
@@ -172,7 +174,7 @@ class WWVBRoundtrip(unittest.TestCase):
172
174
 
173
175
  def test_noise2(self) -> None:
174
176
  """Test of the full minute decoder with targeted errors to get full coverage"""
175
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
177
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
176
178
  timecode = minute.as_timecode()
177
179
  decoded = wwvb.WWVBMinute.from_timecode_am(timecode)
178
180
  self.assertIsNotNone(decoded)
@@ -207,7 +209,7 @@ class WWVBRoundtrip(unittest.TestCase):
207
209
 
208
210
  def test_noise3(self) -> None:
209
211
  """Test impossible BCD values"""
210
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50))
212
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
211
213
  timecode = minute.as_timecode()
212
214
 
213
215
  for poslist in [
@@ -229,12 +231,12 @@ class WWVBRoundtrip(unittest.TestCase):
229
231
 
230
232
  def test_previous_next_minute(self) -> None:
231
233
  """Test that previous minute and next minute are inverses"""
232
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50))
234
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
233
235
  self.assertEqual(minute, minute.next_minute().previous_minute())
234
236
 
235
237
  def test_timecode_str(self) -> None:
236
238
  """Test the str() and repr() methods"""
237
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50))
239
+ minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(1992, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
238
240
  timecode = minute.as_timecode()
239
241
  self.assertEqual(
240
242
  str(timecode),
@@ -257,6 +259,9 @@ class WWVBRoundtrip(unittest.TestCase):
257
259
 
258
260
  self.assertEqual(wwvb.get_dut1(e), wwvb.get_dut1(ep1))
259
261
 
262
+ ep2 = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=340)
263
+ wwvb.get_dut1(ep2)
264
+
260
265
  def test_epoch(self) -> None:
261
266
  """Test the 1970-to-2069 epoch"""
262
267
  m = wwvb.WWVBMinute(69, 1, 1, 0, 0)
@@ -269,7 +274,6 @@ class WWVBRoundtrip(unittest.TestCase):
269
274
 
270
275
  def test_fromstring(self) -> None:
271
276
  """Test the fromstring() classmethod"""
272
-
273
277
  s = "WWVB timecode: year=1998 days=365 hour=23 min=56 dst=0 ut1=-300 ly=0 ls=1"
274
278
  t = "year=1998 days=365 hour=23 min=56 dst=0 ut1=-300 ly=0 ls=1"
275
279
  self.assertEqual(wwvb.WWVBMinuteIERS.fromstring(s), wwvb.WWVBMinuteIERS.fromstring(t))
@@ -280,7 +284,7 @@ class WWVBRoundtrip(unittest.TestCase):
280
284
 
281
285
  def test_from_datetime(self) -> None:
282
286
  """Test the from_datetime() classmethod"""
283
- d = datetime.datetime(1998, 12, 31, 23, 56, 0)
287
+ d = datetime.datetime(1998, 12, 31, 23, 56, 0, tzinfo=datetime.timezone.utc)
284
288
  self.assertEqual(
285
289
  wwvb.WWVBMinuteIERS.from_datetime(d),
286
290
  wwvb.WWVBMinuteIERS.from_datetime(d, newls=True, newut1=-300),
@@ -300,16 +304,11 @@ class WWVBRoundtrip(unittest.TestCase):
300
304
  with self.assertRaises(ValueError):
301
305
  wwvb.WWVBMinute.fromstring("year=1998 days=365 hour=23 min=56 dst=0 ut1=-300 ly=0 ls=1 boo=1")
302
306
 
303
- def test_deprecated(self) -> None:
304
- """Ensure that the 'maybe_warn_update' function is covered"""
305
- with self.assertWarnsRegex(DeprecationWarning, "use ly"):
306
- wwvb.WWVBMinute(2020, 1, 1, 1).is_ly()
307
-
308
307
  def test_update(self) -> None:
309
308
  """Ensure that the 'maybe_warn_update' function is covered"""
310
309
  with self.assertWarnsRegex(Warning, "updateiers"):
311
310
  wwvb._maybe_warn_update(datetime.date(1970, 1, 1))
312
- wwvb._maybe_warn_update(datetime.datetime(1970, 1, 1, 0, 0))
311
+ wwvb._maybe_warn_update(datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc))
313
312
 
314
313
  def test_undefined(self) -> None:
315
314
  """Ensure that the check for unset elements in am works"""
@@ -318,32 +317,41 @@ class WWVBRoundtrip(unittest.TestCase):
318
317
 
319
318
  def test_tz(self) -> None:
320
319
  """Get a little more coverage in the dst change functions"""
321
- date, row = wwvb.get_dst_change_date_and_row(datetime.datetime(1960, 1, 1))
320
+ date, row = wwvb._get_dst_change_date_and_row(datetime.datetime(1960, 1, 1, tzinfo=datetime.timezone.utc))
322
321
  self.assertIsNone(date)
323
322
  self.assertIsNone(row)
324
323
 
325
- self.assertIsNone(wwvb.get_dst_change_hour(datetime.datetime(1960, 1, 1)))
324
+ self.assertIsNone(wwvb._get_dst_change_hour(datetime.datetime(1960, 1, 1, tzinfo=datetime.timezone.utc)))
326
325
 
327
- self.assertEqual(wwvb.get_dst_next(datetime.datetime(1960, 1, 1)), 0b000111)
326
+ self.assertEqual(wwvb._get_dst_next(datetime.datetime(1960, 1, 1, tzinfo=datetime.timezone.utc)), 0b000111)
328
327
 
329
328
  # Cuba followed year-round DST for several years
330
329
  self.assertEqual(
331
- wwvb.get_dst_next(datetime.datetime(2005, 1, 1), tz=tz.ZoneInfo("Cuba")),
330
+ wwvb._get_dst_next(datetime.datetime(2005, 1, 1, tzinfo=datetime.timezone.utc), tz=tz.ZoneInfo("Cuba")),
332
331
  0b101111,
333
332
  )
334
- date, row = wwvb.get_dst_change_date_and_row(datetime.datetime(2005, 1, 1), tz=tz.ZoneInfo("Cuba"))
333
+ date, row = wwvb._get_dst_change_date_and_row(
334
+ datetime.datetime(2005, 1, 1, tzinfo=datetime.timezone.utc),
335
+ tz=tz.ZoneInfo("Cuba"),
336
+ )
335
337
  self.assertIsNone(date)
336
338
  self.assertIsNone(row)
337
339
 
338
340
  # California was weird in 1948
339
341
  self.assertEqual(
340
- wwvb.get_dst_next(datetime.datetime(1948, 1, 1), tz=tz.ZoneInfo("America/Los_Angeles")),
342
+ wwvb._get_dst_next(
343
+ datetime.datetime(1948, 1, 1, tzinfo=datetime.timezone.utc),
344
+ tz=tz.ZoneInfo("America/Los_Angeles"),
345
+ ),
341
346
  0b100011,
342
347
  )
343
348
 
344
349
  # Berlin had DST changes on Monday in 1917
345
350
  self.assertEqual(
346
- wwvb.get_dst_next(datetime.datetime(1917, 1, 1), tz=tz.ZoneInfo("Europe/Berlin")),
351
+ wwvb._get_dst_next(
352
+ datetime.datetime(1917, 1, 1, tzinfo=datetime.timezone.utc),
353
+ tz=tz.ZoneInfo("Europe/Berlin"),
354
+ ),
347
355
  0b100011,
348
356
  )
349
357
 
@@ -351,7 +359,10 @@ class WWVBRoundtrip(unittest.TestCase):
351
359
  # Australia observes DST in the other half of the year compared to the
352
360
  # Northern hemisphere
353
361
  self.assertEqual(
354
- wwvb.get_dst_next(datetime.datetime(2005, 1, 1), tz=tz.ZoneInfo("Australia/Melbourne")),
362
+ wwvb._get_dst_next(
363
+ datetime.datetime(2005, 1, 1, tzinfo=datetime.timezone.utc),
364
+ tz=tz.ZoneInfo("Australia/Melbourne"),
365
+ ),
355
366
  0b100011,
356
367
  )
357
368