wwvb 3.0.6__tar.gz → 3.0.8__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 (74) hide show
  1. {wwvb-3.0.6 → wwvb-3.0.8}/.github/workflows/test.yml +9 -2
  2. {wwvb-3.0.6 → wwvb-3.0.8}/.pre-commit-config.yaml +9 -15
  3. {wwvb-3.0.6 → wwvb-3.0.8}/Makefile +2 -0
  4. {wwvb-3.0.6/src/wwvb.egg-info → wwvb-3.0.8}/PKG-INFO +1 -1
  5. {wwvb-3.0.6 → wwvb-3.0.8}/adafruit_datetime.pyi +18 -34
  6. {wwvb-3.0.6 → wwvb-3.0.8}/conf.py +0 -1
  7. {wwvb-3.0.6 → wwvb-3.0.8}/pyproject.toml +5 -0
  8. {wwvb-3.0.6 → wwvb-3.0.8}/src/uwwvb.py +5 -5
  9. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/__init__.py +35 -49
  10. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/__version__.py +2 -2
  11. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/decode.py +2 -7
  12. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/dut1table.py +1 -0
  13. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/gen.py +4 -13
  14. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/iersdata.py +2 -4
  15. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/iersdata_dist.py +2 -3
  16. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testcli.py +87 -41
  17. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testdaylight.py +4 -12
  18. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testls.py +1 -3
  19. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testpm.py +3 -17
  20. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testuwwvb.py +11 -25
  21. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/testwwvb.py +17 -52
  22. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/updateiers.py +8 -20
  23. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/wwvbtk.py +3 -7
  24. {wwvb-3.0.6 → wwvb-3.0.8/src/wwvb.egg-info}/PKG-INFO +1 -1
  25. {wwvb-3.0.6 → wwvb-3.0.8}/.coveragerc +0 -0
  26. {wwvb-3.0.6 → wwvb-3.0.8}/.github/workflows/codeql.yml +0 -0
  27. {wwvb-3.0.6 → wwvb-3.0.8}/.github/workflows/cron.yml +0 -0
  28. {wwvb-3.0.6 → wwvb-3.0.8}/.github/workflows/release.yml +0 -0
  29. {wwvb-3.0.6 → wwvb-3.0.8}/.gitignore +0 -0
  30. {wwvb-3.0.6 → wwvb-3.0.8}/.pylintrc +0 -0
  31. {wwvb-3.0.6 → wwvb-3.0.8}/LICENSES/Apache-2.0.txt +0 -0
  32. {wwvb-3.0.6 → wwvb-3.0.8}/LICENSES/CC0-1.0.txt +0 -0
  33. {wwvb-3.0.6 → wwvb-3.0.8}/LICENSES/GPL-3.0-only.txt +0 -0
  34. {wwvb-3.0.6 → wwvb-3.0.8}/LICENSES/Unlicense.txt +0 -0
  35. {wwvb-3.0.6 → wwvb-3.0.8}/README.md +0 -0
  36. {wwvb-3.0.6 → wwvb-3.0.8}/_static/.empty +0 -0
  37. {wwvb-3.0.6 → wwvb-3.0.8}/codecov.yml +0 -0
  38. {wwvb-3.0.6 → wwvb-3.0.8}/requirements-dev.txt +0 -0
  39. {wwvb-3.0.6 → wwvb-3.0.8}/setup.cfg +0 -0
  40. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/py.typed +0 -0
  41. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb/tz.py +0 -0
  42. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb.egg-info/SOURCES.txt +0 -0
  43. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb.egg-info/dependency_links.txt +0 -0
  44. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb.egg-info/entry_points.txt +0 -0
  45. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb.egg-info/requires.txt +0 -0
  46. {wwvb-3.0.6 → wwvb-3.0.8}/src/wwvb.egg-info/top_level.txt +0 -0
  47. {wwvb-3.0.6 → wwvb-3.0.8}/tests/1998leapsecond +0 -0
  48. {wwvb-3.0.6 → wwvb-3.0.8}/tests/2012leapsecond +0 -0
  49. {wwvb-3.0.6 → wwvb-3.0.8}/tests/all-headers +0 -0
  50. {wwvb-3.0.6 → wwvb-3.0.8}/tests/bar +0 -0
  51. {wwvb-3.0.6 → wwvb-3.0.8}/tests/both +0 -0
  52. {wwvb-3.0.6 → wwvb-3.0.8}/tests/cradek +0 -0
  53. {wwvb-3.0.6 → wwvb-3.0.8}/tests/duration +0 -0
  54. {wwvb-3.0.6 → wwvb-3.0.8}/tests/enddst-phase +0 -0
  55. {wwvb-3.0.6 → wwvb-3.0.8}/tests/enddst-phase-2 +0 -0
  56. {wwvb-3.0.6 → wwvb-3.0.8}/tests/endleapyear +0 -0
  57. {wwvb-3.0.6 → wwvb-3.0.8}/tests/leapday1 +0 -0
  58. {wwvb-3.0.6 → wwvb-3.0.8}/tests/leapday28 +0 -0
  59. {wwvb-3.0.6 → wwvb-3.0.8}/tests/leapday29 +0 -0
  60. {wwvb-3.0.6 → wwvb-3.0.8}/tests/negleapsecond +0 -0
  61. {wwvb-3.0.6 → wwvb-3.0.8}/tests/nextdst +0 -0
  62. {wwvb-3.0.6 → wwvb-3.0.8}/tests/nextst +0 -0
  63. {wwvb-3.0.6 → wwvb-3.0.8}/tests/nonleapday1 +0 -0
  64. {wwvb-3.0.6 → wwvb-3.0.8}/tests/nonleapday28 +0 -0
  65. {wwvb-3.0.6 → wwvb-3.0.8}/tests/phase +0 -0
  66. {wwvb-3.0.6 → wwvb-3.0.8}/tests/startdst +0 -0
  67. {wwvb-3.0.6 → wwvb-3.0.8}/tests/startdst-phase +0 -0
  68. {wwvb-3.0.6 → wwvb-3.0.8}/tests/startdst-phase-2 +0 -0
  69. {wwvb-3.0.6 → wwvb-3.0.8}/tests/startleapyear +0 -0
  70. {wwvb-3.0.6 → wwvb-3.0.8}/tests/startst +0 -0
  71. {wwvb-3.0.6 → wwvb-3.0.8}/tests/y2k +0 -0
  72. {wwvb-3.0.6 → wwvb-3.0.8}/tests/y2k-1 +0 -0
  73. {wwvb-3.0.6 → wwvb-3.0.8}/tests/y2k1 +0 -0
  74. {wwvb-3.0.6 → wwvb-3.0.8}/tests/y2k1-1 +0 -0
@@ -23,14 +23,21 @@ jobs:
23
23
  - '3.11'
24
24
  - '3.12'
25
25
  - '3.13.0-alpha.0 - 3.13'
26
- - 'pypy-3.9'
27
26
  os-version:
28
27
  - 'ubuntu-latest'
28
+ coverage-core:
29
+ - 'ctrace'
29
30
  include:
30
31
  - os-version: 'macos-latest'
31
32
  python-version: '3.x'
32
33
  - os-version: 'windows-latest'
33
34
  python-version: '3.x'
35
+ - os-version: 'ubuntu-latest'
36
+ python-version: '3.12'
37
+ coverage-core: 'sysmon'
38
+ - os-version: 'ubuntu-latest'
39
+ python-version: 'pypy-3.10'
40
+ coverage-core: 'pytrace'
34
41
 
35
42
  runs-on: ${{ matrix.os-version }}
36
43
  steps:
@@ -51,7 +58,7 @@ jobs:
51
58
  run: make mypy PYTHON=python
52
59
 
53
60
  - name: Test
54
- run: make coverage PYTHON=python
61
+ run: make coverage PYTHON=python COVERAGE_CORE=${{ matrix.coverage-core }}
55
62
 
56
63
  - name: Upload Coverage as artifact
57
64
  if: always()
@@ -6,10 +6,6 @@ default_language_version:
6
6
  python: python3
7
7
 
8
8
  repos:
9
- - repo: https://github.com/psf/black
10
- rev: 23.11.0
11
- hooks:
12
- - id: black
13
9
  - repo: https://github.com/pre-commit/pre-commit-hooks
14
10
  rev: v4.5.0
15
11
  hooks:
@@ -19,17 +15,15 @@ repos:
19
15
  - id: trailing-whitespace
20
16
  exclude: tests
21
17
  - repo: https://github.com/fsfe/reuse-tool
22
- rev: v2.1.0
23
- hooks:
24
- - id: reuse
25
- - repo: https://github.com/pycqa/pylint
26
18
  rev: v3.0.1
27
19
  hooks:
28
- - id: pylint
29
- additional_dependencies: ["setuptools>=68", beautifulsoup4, requests, adafruit-circuitpython-datetime, click, python-dateutil, leapseconddata]
30
- - repo: https://github.com/pycqa/isort
31
- rev: 5.12.0
20
+ - id: reuse
21
+ - repo: https://github.com/astral-sh/ruff-pre-commit
22
+ # Ruff version.
23
+ rev: v0.3.5
32
24
  hooks:
33
- - id: isort
34
- name: isort (python)
35
- args: ['--profile', 'black']
25
+ # Run the linter.
26
+ - id: ruff
27
+ args: [ --fix ]
28
+ # Run the formatter.
29
+ - id: ruff-format
@@ -55,6 +55,8 @@ BUILDDIR = _build
55
55
  html:
56
56
  @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
57
57
 
58
+ # Pass the desired coverage tracer name to subprocesses
59
+ export COVERAGE_CORE
58
60
 
59
61
  # Copyright (C) 2021 Jeff Epler <jepler@gmail.com>
60
62
  # SPDX-FileCopyrightText: 2021 Jeff Epler
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wwvb
3
- Version: 3.0.6
3
+ Version: 3.0.8
4
4
  Summary: Generate WWVB timecodes for any desired time
5
5
  Home-page: https://github.com/jepler/wwvbpy
6
6
  Author: Jeff Epler
@@ -13,17 +13,11 @@ from typing import (
13
13
  Tuple,
14
14
  Type,
15
15
  TypeVar,
16
- Union,
17
16
  overload,
18
17
  )
19
18
 
20
19
  _S = TypeVar("_S")
21
20
 
22
- if sys.version_info >= (3,):
23
- _Text = str
24
- else:
25
- _Text = Union[str, unicode]
26
-
27
21
  MINYEAR: int
28
22
  MAXYEAR: int
29
23
 
@@ -33,19 +27,17 @@ class tzinfo:
33
27
  def dst(self, dt: Optional[datetime]) -> Optional[timedelta]: ...
34
28
  def fromutc(self, dt: datetime) -> datetime: ...
35
29
 
36
- if sys.version_info >= (3, 2):
37
- class timezone(tzinfo):
38
- utc: ClassVar[timezone]
39
- min: ClassVar[timezone]
40
- max: ClassVar[timezone]
41
- def __init__(self, offset: timedelta, name: str = ...) -> None: ...
42
- def __hash__(self) -> int: ...
30
+ class timezone(tzinfo):
31
+ utc: ClassVar[timezone]
32
+ min: ClassVar[timezone]
33
+ max: ClassVar[timezone]
34
+ def __init__(self, offset: timedelta, name: str = ...) -> None: ...
35
+ def __hash__(self) -> int: ...
43
36
 
44
- if sys.version_info >= (3, 9):
45
- class _IsoCalendarDate(NamedTuple):
46
- year: int
47
- week: int
48
- weekday: int
37
+ class _IsoCalendarDate(NamedTuple):
38
+ year: int
39
+ week: int
40
+ weekday: int
49
41
 
50
42
  _tzinfo = tzinfo
51
43
 
@@ -74,7 +66,7 @@ class date:
74
66
  @property
75
67
  def day(self) -> int: ...
76
68
  def ctime(self) -> str: ...
77
- def strftime(self, fmt: _Text) -> str: ...
69
+ def strftime(self, fmt: str) -> str: ...
78
70
  if sys.version_info >= (3,):
79
71
  def __format__(self, fmt: str) -> str: ...
80
72
  else:
@@ -102,10 +94,7 @@ class date:
102
94
  def __hash__(self) -> int: ...
103
95
  def weekday(self) -> int: ...
104
96
  def isoweekday(self) -> int: ...
105
- if sys.version_info >= (3, 9):
106
- def isocalendar(self) -> _IsoCalendarDate: ...
107
- else:
108
- def isocalendar(self) -> Tuple[int, int, int]: ...
97
+ def isocalendar(self) -> _IsoCalendarDate: ...
109
98
 
110
99
  class time:
111
100
  min: ClassVar[time]
@@ -160,7 +149,7 @@ class time:
160
149
  @classmethod
161
150
  def fromisoformat(cls: Type[_S], time_string: str) -> _S: ...
162
151
 
163
- def strftime(self, fmt: _Text) -> str: ...
152
+ def strftime(self, fmt: str) -> str: ...
164
153
  if sys.version_info >= (3,):
165
154
  def __format__(self, fmt: str) -> str: ...
166
155
  else:
@@ -193,7 +182,7 @@ class time:
193
182
  _date = date
194
183
  _time = time
195
184
 
196
- class timedelta(SupportsAbs[timedelta]):
185
+ class timedelta(SupportsAbs["timedelta"]):
197
186
  min: ClassVar[timedelta]
198
187
  max: ClassVar[timedelta]
199
188
  resolution: ClassVar[timedelta]
@@ -337,9 +326,7 @@ class datetime(date):
337
326
  def utcnow(cls: Type[_S]) -> _S: ...
338
327
  if sys.version_info >= (3, 6):
339
328
  @classmethod
340
- def combine(
341
- cls, date: _date, time: _time, tzinfo: Optional[_tzinfo] = ...
342
- ) -> datetime: ...
329
+ def combine(cls, date: _date, time: _time, tzinfo: Optional[_tzinfo] = ...) -> datetime: ...
343
330
  else:
344
331
  @classmethod
345
332
  def combine(cls, date: _date, time: _time) -> datetime: ...
@@ -347,7 +334,7 @@ class datetime(date):
347
334
  @classmethod
348
335
  def fromisoformat(cls: Type[_S], date_string: str) -> _S: ...
349
336
 
350
- def strftime(self, fmt: _Text) -> str: ...
337
+ def strftime(self, fmt: str) -> str: ...
351
338
  if sys.version_info >= (3,):
352
339
  def __format__(self, fmt: str) -> str: ...
353
340
  else:
@@ -402,7 +389,7 @@ class datetime(date):
402
389
  def isoformat(self, sep: str = ...) -> str: ...
403
390
 
404
391
  @classmethod
405
- def strptime(cls, date_string: _Text, format: _Text) -> datetime: ...
392
+ def strptime(cls, date_string: str, format: str) -> datetime: ...
406
393
  def utcoffset(self) -> Optional[timedelta]: ...
407
394
  def tzname(self) -> Optional[str]: ...
408
395
  def dst(self) -> Optional[timedelta]: ...
@@ -424,7 +411,4 @@ class datetime(date):
424
411
  def __hash__(self) -> int: ...
425
412
  def weekday(self) -> int: ...
426
413
  def isoweekday(self) -> int: ...
427
- if sys.version_info >= (3, 9):
428
- def isocalendar(self) -> _IsoCalendarDate: ...
429
- else:
430
- def isocalendar(self) -> Tuple[int, int, int]: ...
414
+ def isocalendar(self) -> _IsoCalendarDate: ...
@@ -1,4 +1,3 @@
1
- # pylint: disable=all
2
1
  # fmt: off
3
2
  # Configuration file for the Sphinx documentation builder.
4
3
  #
@@ -18,3 +18,8 @@ requires = [
18
18
  build-backend = "setuptools.build_meta"
19
19
  [tool.setuptools_scm]
20
20
  write_to = "src/wwvb/__version__.py"
21
+ [tool.ruff.lint]
22
+ select = ["E", "F"]
23
+ ignore = ["E741"]
24
+ [tool.ruff]
25
+ line-length = 120
@@ -16,9 +16,7 @@ always_mark = set((0, 9, 19, 29, 39, 49, 59))
16
16
  always_zero = set((4, 10, 11, 14, 20, 21, 34, 35, 44, 54))
17
17
  bcd_weights = (1, 2, 4, 8, 10, 20, 40, 80, 100, 200, 400, 800)
18
18
 
19
- WWVBMinute = namedtuple(
20
- "WWVBMinute", ["year", "days", "hour", "minute", "dst", "ut1", "ls", "ly"]
21
- )
19
+ WWVBMinute = namedtuple("WWVBMinute", ["year", "days", "hour", "minute", "dst", "ut1", "ls", "ly"])
22
20
 
23
21
 
24
22
  class WWVBDecoder:
@@ -30,7 +28,9 @@ class WWVBDecoder:
30
28
  self.state = 1
31
29
 
32
30
  def update(self, value: int) -> list[int] | None:
33
- """Update the _state machine when a new symbol is received. If a possible complete _minute is received, return it; otherwise, return None"""
31
+ """Update the _state machine when a new symbol is received.
32
+
33
+ If a possible complete _minute is received, return it; otherwise, return None"""
34
34
  result = None
35
35
  if self.state == 1:
36
36
  self.minute = []
@@ -87,7 +87,7 @@ def get_am_bcd(seq: list[int], *poslist: int) -> int | None:
87
87
  return result
88
88
 
89
89
 
90
- def decode_wwvb( # pylint: disable=too-many-return-statements
90
+ def decode_wwvb(
91
91
  t: list[int] | None,
92
92
  ) -> WWVBMinute | None:
93
93
  """Convert a received minute of wwvb symbols to a WWVBMinute. Returns None if any error is detected."""
@@ -19,7 +19,7 @@ from .tz import Mountain
19
19
  HOUR = datetime.timedelta(seconds=3600)
20
20
  SECOND = datetime.timedelta(seconds=1)
21
21
  DateOrDatetime = TypeVar("DateOrDatetime", datetime.date, datetime.datetime)
22
- T = TypeVar("T") # pylint: disable=invalid-name
22
+ T = TypeVar("T")
23
23
 
24
24
 
25
25
  def require(x: Optional[T]) -> T:
@@ -49,9 +49,7 @@ def _maybe_warn_update(dt: datetime.date) -> None:
49
49
  # prospective available now.
50
50
  today = datetime.date.today()
51
51
  if _date(dt) < today + datetime.timedelta(days=330):
52
- warnings.warn(
53
- "Note: Running `updateiers` may provide better DUT1 and LS information"
54
- )
52
+ warnings.warn("Note: Running `updateiers` may provide better DUT1 and LS information")
55
53
 
56
54
 
57
55
  def get_dut1(dt: DateOrDatetime, *, warn_outdated: bool = True) -> float:
@@ -110,9 +108,7 @@ def is_dst_change_day(t: datetime.date, tz: datetime.tzinfo = Mountain) -> bool:
110
108
  return isdst(t, tz) != isdst(t + datetime.timedelta(1), tz)
111
109
 
112
110
 
113
- def get_dst_change_hour(
114
- t: DateOrDatetime, tz: datetime.tzinfo = Mountain
115
- ) -> Optional[int]:
111
+ def get_dst_change_hour(t: DateOrDatetime, tz: datetime.tzinfo = Mountain) -> Optional[int]:
116
112
  """Return the hour when DST changes"""
117
113
  lt0 = datetime.datetime(t.year, t.month, t.day, hour=0, tzinfo=tz)
118
114
  dst0 = lt0.dst()
@@ -291,7 +287,9 @@ def extract_bit(v: int, p: int) -> bool:
291
287
 
292
288
 
293
289
  def hamming_parity(value: int) -> int:
294
- """Compute the "hamming parity" of a 26-bit number, such as the minute-of-century [See Enhanced WWVB Broadcast Format 4.3]"""
290
+ """Compute the "hamming parity" of a 26-bit number, such as the minute-of-century
291
+
292
+ For more details, see Enhanced WWVB Broadcast Format 4.3"""
295
293
  parity = 0
296
294
  for i in range(4, -1, -1):
297
295
  bit = 0
@@ -324,7 +322,9 @@ _WWVBMinute = collections.namedtuple("_WWVBMinute", "year days hour min dst ut1
324
322
 
325
323
 
326
324
  class WWVBMinute(_WWVBMinute):
327
- """Uniquely identifies a minute of time in the WWVB system. To use ut1 and ls information from IERS, create a WWVBMinuteIERS value instead."""
325
+ """Uniquely identifies a minute of time in the WWVB system.
326
+
327
+ To use ut1 and ls information from IERS, create a WWVBMinuteIERS value instead."""
328
328
 
329
329
  year: int
330
330
  hour: int
@@ -336,7 +336,7 @@ class WWVBMinute(_WWVBMinute):
336
336
 
337
337
  epoch: int = 1970
338
338
 
339
- def __new__( # pylint: disable=too-many-arguments
339
+ def __new__(
340
340
  cls,
341
341
  year: int,
342
342
  days: int,
@@ -391,7 +391,11 @@ class WWVBMinute(_WWVBMinute):
391
391
 
392
392
  def __str__(self) -> str:
393
393
  """Implement str()"""
394
- return f"year={self.year:4d} days={self.days:03d} hour={self.hour:02d} min={self.min:02d} dst={self.dst} ut1={self.ut1} ly={int(self.ly)} ls={int(self.ls)}"
394
+ return (
395
+ f"year={self.year:4d} days={self.days:03d} hour={self.hour:02d} "
396
+ f"min={self.min:02d} dst={self.dst} ut1={self.ut1} ly={int(self.ly)} "
397
+ f"ls={int(self.ls)}"
398
+ )
395
399
 
396
400
  def as_datetime_utc(self) -> datetime.datetime:
397
401
  """Convert to a UTC datetime"""
@@ -401,9 +405,7 @@ class WWVBMinute(_WWVBMinute):
401
405
 
402
406
  as_datetime = as_datetime_utc
403
407
 
404
- def as_datetime_local(
405
- self, standard_time_offset: int = 7 * 3600, dst_observed: bool = True
406
- ) -> datetime.datetime:
408
+ def as_datetime_local(self, standard_time_offset: int = 7 * 3600, dst_observed: bool = True) -> datetime.datetime:
407
409
  """Convert to a local datetime according to the DST bits"""
408
410
  u = self.as_datetime_utc()
409
411
  offset = datetime.timedelta(seconds=-standard_time_offset)
@@ -471,12 +473,7 @@ class WWVBMinute(_WWVBMinute):
471
473
  century = (self.year // 100) * 100
472
474
  # note: This relies on timedelta seconds never including leapseconds!
473
475
  return (
474
- int(
475
- (
476
- self.as_datetime()
477
- - datetime.datetime(century, 1, 1, tzinfo=datetime.timezone.utc)
478
- ).total_seconds()
479
- )
476
+ int((self.as_datetime() - datetime.datetime(century, 1, 1, tzinfo=datetime.timezone.utc)).total_seconds())
480
477
  // 60
481
478
  )
482
479
 
@@ -497,9 +494,7 @@ class WWVBMinute(_WWVBMinute):
497
494
  t.am[36] = t.am[38] = AmplitudeModulation(ut1_sign)
498
495
  t.am[37] = AmplitudeModulation(not ut1_sign)
499
496
  t._put_am_bcd(abs(self.ut1) // 100, 40, 41, 42, 43)
500
- t._put_am_bcd(
501
- self.year, 45, 46, 47, 48, 50, 51, 52, 53
502
- ) # Implicitly discards all but lowest 2 digits of year
497
+ t._put_am_bcd(self.year, 45, 46, 47, 48, 50, 51, 52, 53) # Implicitly discards all but lowest 2 digits of year
503
498
  t.am[55] = AmplitudeModulation(self.ly)
504
499
  t.am[56] = AmplitudeModulation(self.ls)
505
500
  t._put_am_bcd(self.dst, 57, 58)
@@ -539,9 +534,7 @@ class WWVBMinute(_WWVBMinute):
539
534
  for i in range(60):
540
535
  t._put_pm_bit(i, full_seq[i + offset])
541
536
 
542
- def fill_pm_timecode_regular( # pylint: disable=too-many-statements
543
- self, t: "WWVBTimecode"
544
- ) -> None:
537
+ def fill_pm_timecode_regular(self, t: "WWVBTimecode") -> None:
545
538
  """Except during minutes 10..15 and 40..45, the amplitude signal holds 'regular information'"""
546
539
  t._put_pm_bin(0, 13, SYNC_T)
547
540
 
@@ -604,24 +597,18 @@ class WWVBMinute(_WWVBMinute):
604
597
  else:
605
598
  self.fill_pm_timecode_regular(t)
606
599
 
607
- def next_minute(
608
- self, newut1: Optional[int] = None, newls: Optional[bool] = None
609
- ) -> "WWVBMinute":
600
+ def next_minute(self, newut1: Optional[int] = None, newls: Optional[bool] = None) -> "WWVBMinute":
610
601
  """Return an object representing the next minute"""
611
602
  d = self.as_datetime() + datetime.timedelta(minutes=1)
612
603
  return self.from_datetime(d, newut1, newls, self)
613
604
 
614
- def previous_minute(
615
- self, newut1: Optional[int] = None, newls: Optional[bool] = None
616
- ) -> "WWVBMinute":
605
+ def previous_minute(self, newut1: Optional[int] = None, newls: Optional[bool] = None) -> "WWVBMinute":
617
606
  """Return an object representing the previous minute"""
618
607
  d = self.as_datetime() - datetime.timedelta(minutes=1)
619
608
  return self.from_datetime(d, newut1, newls, self)
620
609
 
621
610
  @classmethod
622
- def _get_dut1_info( # pylint: disable=unused-argument
623
- cls: type, year: int, days: int, old_time: "Optional[WWVBMinute]" = None
624
- ) -> Tuple[int, bool]:
611
+ def _get_dut1_info(cls: type, year: int, days: int, old_time: "Optional[WWVBMinute]" = None) -> Tuple[int, bool]:
625
612
  """Return the DUT1 information for a given day, possibly propagating information from a previous timestamp"""
626
613
  if old_time is not None:
627
614
  if old_time.minute_length() != 60:
@@ -673,9 +660,7 @@ class WWVBMinute(_WWVBMinute):
673
660
  return cls(u.tm_year, u.tm_yday, u.tm_hour, u.tm_min, ut1=newut1, ls=newls)
674
661
 
675
662
  @classmethod
676
- def from_timecode_am( # pylint: disable=too-many-return-statements
677
- cls, t: "WWVBTimecode"
678
- ) -> Optional["WWVBMinute"]:
663
+ def from_timecode_am(cls, t: "WWVBTimecode") -> Optional["WWVBMinute"]:
679
664
  """Construct a WWVBMinute from a WWVBTimecode"""
680
665
  for i in (0, 9, 19, 29, 39, 49, 59):
681
666
  if t.am[i] != AmplitudeModulation.MARK:
@@ -717,9 +702,7 @@ class WWVBMinuteIERS(WWVBMinute):
717
702
  """A WWVBMinute that uses a database of DUT1 information"""
718
703
 
719
704
  @classmethod
720
- def _get_dut1_info(
721
- cls, year: int, days: int, old_time: Optional[WWVBMinute] = None
722
- ) -> Tuple[int, bool]:
705
+ def _get_dut1_info(cls, year: int, days: int, old_time: Optional[WWVBMinute] = None) -> Tuple[int, bool]:
723
706
  d = datetime.datetime(year, 1, 1) + datetime.timedelta(days - 1)
724
707
  return int(round(get_dut1(d) * 10)) * 100, isls(d)
725
708
 
@@ -759,11 +742,14 @@ class WWVBTimecode:
759
742
  phase: List[PhaseModulation]
760
743
 
761
744
  def __init__(self, sz: int) -> None:
762
- self.am = [AmplitudeModulation.UNSET] * sz # pylint: disable=invalid-name
745
+ self.am = [AmplitudeModulation.UNSET] * sz
763
746
  self.phase = [PhaseModulation.UNSET] * sz
764
747
 
765
748
  def _get_am_bcd(self, *poslist: int) -> Optional[int]:
766
- """Convert the bits seq[positions[0]], ... seq[positions[len(positions-1)]] [in MSB order] from BCD to decimal"""
749
+ """Convert AM data to BCD
750
+
751
+ The the bits ``self.am[poslist[i]]`` in MSB order are converted from
752
+ BCD to integer"""
767
753
  pos = reversed(poslist)
768
754
  val = [bool(self.am[p]) for p in pos]
769
755
  result = 0
@@ -779,7 +765,11 @@ class WWVBTimecode:
779
765
  return result
780
766
 
781
767
  def _put_am_bcd(self, v: int, *poslist: int) -> None:
782
- """Treating 'poslist' as a sequence of indices, update the AM signal with the value as a BCD number"""
768
+ """Insert BCD coded data into the AM signal
769
+
770
+ The bits at ``self.am[poslist[i]]`` in MSB order are filled with
771
+ the conversion of `v` to BCD
772
+ Treating 'poslist' as a sequence of indices, update the AM signal with the value as a BCD number"""
783
773
  pos = list(poslist)[::-1]
784
774
  for p, b in zip(pos, bcd_bits(v)):
785
775
  if b:
@@ -798,9 +788,7 @@ class WWVBTimecode:
798
788
 
799
789
  def __str__(self) -> str:
800
790
  """implement str()"""
801
- undefined = [
802
- i for i in range(len(self.am)) if self.am[i] == AmplitudeModulation.UNSET
803
- ]
791
+ undefined = [i for i in range(len(self.am)) if self.am[i] == AmplitudeModulation.UNSET]
804
792
  if undefined:
805
793
  warnings.warn(f"am{undefined} is unset")
806
794
 
@@ -841,7 +829,6 @@ styles = {
841
829
  }
842
830
 
843
831
 
844
- # pylint: disable=too-many-arguments
845
832
  def print_timecodes(
846
833
  w: WWVBMinute,
847
834
  minutes: int,
@@ -879,7 +866,6 @@ def print_timecodes(
879
866
  w = w.next_minute()
880
867
 
881
868
 
882
- # pylint: disable=too-many-arguments
883
869
  def print_timecodes_json(
884
870
  w: WWVBMinute,
885
871
  minutes: int,
@@ -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.6'
16
- __version_tuple__ = version_tuple = (3, 0, 6)
15
+ __version__ = version = '3.0.8'
16
+ __version_tuple__ = version_tuple = (3, 0, 8)
@@ -23,9 +23,7 @@ import wwvb
23
23
  always_zero = set((4, 10, 11, 14, 20, 21, 34, 35, 44, 54))
24
24
 
25
25
 
26
- def wwvbreceive() -> (
27
- Generator[Optional[wwvb.WWVBTimecode], wwvb.AmplitudeModulation, None]
28
- ): # pylint: disable=too-many-branches
26
+ def wwvbreceive() -> Generator[Optional[wwvb.WWVBTimecode], wwvb.AmplitudeModulation, None]:
29
27
  """A stateful decoder of WWVB signals"""
30
28
  minute: List[wwvb.AmplitudeModulation] = []
31
29
  state = 1
@@ -60,10 +58,7 @@ def wwvbreceive() -> (
60
58
  elif len(minute) % 10 and value == wwvb.AmplitudeModulation.MARK:
61
59
  # print("UNEXPECTED MARK")
62
60
  state = 1
63
- elif (
64
- len(minute) - 1 in always_zero
65
- and value != wwvb.AmplitudeModulation.ZERO
66
- ):
61
+ elif len(minute) - 1 in always_zero and value != wwvb.AmplitudeModulation.ZERO:
67
62
  # print("UNEXPECTED NONZERO")
68
63
  state = 1
69
64
  elif len(minute) == 60:
@@ -5,6 +5,7 @@
5
5
  # SPDX-License-Identifier: GPL-3.0-only
6
6
 
7
7
  """Print the table of historical DUT1 values"""
8
+
8
9
  from datetime import timedelta
9
10
  from itertools import groupby
10
11
 
@@ -16,9 +16,7 @@ import dateutil.parser
16
16
  from . import WWVBMinute, WWVBMinuteIERS, print_timecodes, print_timecodes_json, styles
17
17
 
18
18
 
19
- def parse_timespec( # pylint: disable=unused-argument
20
- ctx: Any, param: Any, value: List[str]
21
- ) -> datetime.datetime:
19
+ def parse_timespec(ctx: Any, param: Any, value: List[str]) -> datetime.datetime:
22
20
  """Parse a time specifier from the commandline"""
23
21
  try:
24
22
  if len(value) == 5:
@@ -26,9 +24,7 @@ def parse_timespec( # pylint: disable=unused-argument
26
24
  return datetime.datetime(year, month, day, hour, minute)
27
25
  if len(value) == 4:
28
26
  year, yday, hour, minute = map(int, value)
29
- return datetime.datetime(year, 1, 1, hour, minute) + datetime.timedelta(
30
- days=yday - 1
31
- )
27
+ return datetime.datetime(year, 1, 1, hour, minute) + datetime.timedelta(days=yday - 1)
32
28
  if len(value) == 1:
33
29
  return dateutil.parser.parse(value[0])
34
30
  if len(value) == 0:
@@ -68,9 +64,7 @@ def parse_timespec( # pylint: disable=unused-argument
68
64
  help="Force no leap second at the end of the month (Implies --no-iers)",
69
65
  )
70
66
  @click.option("--dut1", "-d", type=int, help="Force the DUT1 value (Implies --no-iers)")
71
- @click.option(
72
- "--minutes", "-m", default=10, help="Number of minutes to show (default: 10)"
73
- )
67
+ @click.option("--minutes", "-m", default=10, help="Number of minutes to show (default: 10)")
74
68
  @click.option(
75
69
  "--style",
76
70
  default="default",
@@ -91,7 +85,6 @@ def parse_timespec( # pylint: disable=unused-argument
91
85
  help="Modulation to show (default: amplitude)",
92
86
  )
93
87
  @click.argument("timespec", type=str, nargs=-1, callback=parse_timespec)
94
- # pylint: disable=too-many-arguments, too-many-locals
95
88
  def main(
96
89
  iers: bool,
97
90
  leap_second: bool,
@@ -127,9 +120,7 @@ def main(
127
120
  if style == "json":
128
121
  print_timecodes_json(w, minutes, channel, file=sys.stdout)
129
122
  else:
130
- print_timecodes(
131
- w, minutes, channel, style, all_timecodes=all_timecodes, file=sys.stdout
132
- )
123
+ print_timecodes(w, minutes, channel, style, all_timecodes=all_timecodes, file=sys.stdout)
133
124
 
134
125
 
135
126
  if __name__ == "__main__": # pragma no branch
@@ -21,11 +21,9 @@ for location in [
21
21
  filename = os.path.join(location, "wwvbpy_iersdata.py")
22
22
  if os.path.exists(filename):
23
23
  with open(filename, encoding="utf-8") as f:
24
- exec(f.read(), globals(), globals()) # pylint: disable=exec-used
24
+ exec(f.read(), globals(), globals())
25
25
  break
26
26
 
27
- start = datetime.datetime.combine(DUT1_DATA_START, datetime.time()).replace(
28
- tzinfo=datetime.timezone.utc
29
- )
27
+ start = datetime.datetime.combine(DUT1_DATA_START, datetime.time()).replace(tzinfo=datetime.timezone.utc)
30
28
  span = datetime.timedelta(days=len(DUT1_OFFSETS))
31
29
  end = start + span
@@ -1,10 +1,9 @@
1
1
  # -*- python3 -*-
2
+ # fmt: off
2
3
  """File generated from public data - not subject to copyright"""
3
4
  # SPDX-FileCopyrightText: Public domain
4
5
  # SPDX-License-Identifier: CC0-1.0
5
- # fmt: off
6
6
  # isort: skip_file
7
- # pylint: disable=invalid-name
8
7
  import datetime
9
8
  __all__ = ['DUT1_DATA_START', 'DUT1_OFFSETS']
10
9
  DUT1_DATA_START = datetime.date(1972, 1, 1)
@@ -35,5 +34,5 @@ DUT1_OFFSETS = str( # 19720101
35
34
  +i*126+h*176+g*97+f*91+e*52+o*116+n*98+m*70+l*133+k*91+j*91 # 20140507
36
35
  +i*77+h*140+g*91+f*84+e*70+d*34+n*72+m*76+l*66+k*53+j*56 # 20160831
37
36
  +i*105+h*77+g*45+q*25+p*63+o*91+n*154+m*105+l*190+k*118 # 20190501
38
- +j*105+i*807+j*376+k*792+l*19+k*18 # 20241102
37
+ +j*105+i*807+j*376+k*775+l*67+k*2+l*6+k*133 # 20250405
39
38
  )