Skip to content

Commit 07bbf89

Browse files
committed
fix: address review findings for nominal frequency labels
- Fix lint: remove unused pytest import, rename ambiguous 'l' → 'label' (E741) - Fix __init__.py overloads: add Literal[True] nominal variants returning List[str] - Fix duplicate label computation: reuse getansifrequencies labels via slice - Add docstring to _nominal_freq_for_band explaining fallback behavior - Fix mypy: annotate extended list, add type: ignore for overload dispatch - Add trailing newline to __init__.py
1 parent c516d9c commit 07bbf89

3 files changed

Lines changed: 58 additions & 11 deletions

File tree

src/pyoctaveband/__init__.py

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def octavefilter(
5252
calibration_factor: float = 1.0,
5353
dbfs: bool = False,
5454
mode: str = "rms",
55-
nominal: bool = False,
55+
nominal: Literal[False] = False,
5656
) -> Tuple[np.ndarray, List[float]]: ...
5757

5858

@@ -73,10 +73,52 @@ def octavefilter(
7373
calibration_factor: float = 1.0,
7474
dbfs: bool = False,
7575
mode: str = "rms",
76-
nominal: bool = False,
76+
nominal: Literal[False] = False,
7777
) -> Tuple[np.ndarray, List[float], List[np.ndarray]]: ...
7878

7979

80+
@overload
81+
def octavefilter(
82+
x: List[float] | np.ndarray,
83+
fs: int,
84+
fraction: float = 1,
85+
order: int = 6,
86+
limits: List[float] | None = None,
87+
show: bool = False,
88+
sigbands: Literal[False] = False,
89+
plot_file: str | None = None,
90+
detrend: bool = True,
91+
filter_type: str = "butter",
92+
ripple: float = 0.1,
93+
attenuation: float = 60.0,
94+
calibration_factor: float = 1.0,
95+
dbfs: bool = False,
96+
mode: str = "rms",
97+
nominal: Literal[True] = ...,
98+
) -> Tuple[np.ndarray, List[str]]: ...
99+
100+
101+
@overload
102+
def octavefilter(
103+
x: List[float] | np.ndarray,
104+
fs: int,
105+
fraction: float = 1,
106+
order: int = 6,
107+
limits: List[float] | None = None,
108+
show: bool = False,
109+
sigbands: Literal[True] = True,
110+
plot_file: str | None = None,
111+
detrend: bool = True,
112+
filter_type: str = "butter",
113+
ripple: float = 0.1,
114+
attenuation: float = 60.0,
115+
calibration_factor: float = 1.0,
116+
dbfs: bool = False,
117+
mode: str = "rms",
118+
nominal: Literal[True] = ...,
119+
) -> Tuple[np.ndarray, List[str], List[np.ndarray]]: ...
120+
121+
80122
def octavefilter(
81123
x: List[float] | np.ndarray,
82124
fs: int,
@@ -149,6 +191,6 @@ def octavefilter(
149191
)
150192

151193
if sigbands:
152-
return filter_bank.filter(x, sigbands=True, mode=mode, detrend=detrend, nominal=nominal)
194+
return filter_bank.filter(x, sigbands=True, mode=mode, detrend=detrend, nominal=nominal) # type: ignore[call-overload,no-any-return]
153195
else:
154-
return filter_bank.filter(x, sigbands=False, mode=mode, detrend=detrend, nominal=nominal)
196+
return filter_bank.filter(x, sigbands=False, mode=mode, detrend=detrend, nominal=nominal) # type: ignore[call-overload,no-any-return]

src/pyoctaveband/frequencies.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ def _genfreqs(
121121
:param fs: Sample rate.
122122
:return: Tuple of center, lower, upper frequencies, and nominal labels.
123123
"""
124-
freq, freq_d, freq_u, _ = getansifrequencies(fraction, limits)
124+
freq, freq_d, freq_u, labels = getansifrequencies(fraction, limits)
125125
freq, freq_d, freq_u = _deleteouters(freq, freq_d, freq_u, fs)
126-
labels = [_format_nominal_freq(_nominal_freq_for_band(f, fraction)) for f in freq]
126+
# _deleteouters only removes trailing bands above Nyquist, so slice labels
127+
labels = labels[: len(freq)]
127128
return freq, freq_d, freq_u, labels
128129

129130

@@ -138,11 +139,16 @@ def _iec_e3_round(f: float) -> float:
138139

139140

140141
def _nominal_freq_for_band(exact_freq: float, fraction: float) -> float:
141-
"""Return IEC 61260-1 nominal frequency (float) for an exact mid-band frequency."""
142+
"""Return IEC 61260-1 nominal frequency (float) for an exact mid-band frequency.
143+
144+
For standard fractions (1, 3), snaps to the IEC preferred table via
145+
``normalizedfreq``. For non-standard fractions, falls back to Annex E.3
146+
significant-figure rounding (``_iec_e3_round``).
147+
"""
142148
frac = round(fraction)
143149
if frac in (1, 3):
144150
base = normalizedfreq(frac)
145-
extended = [f * (10 ** d) for d in range(-3, 4) for f in base]
151+
extended: List[float] = [f * (10 ** d) for d in range(-3, 4) for f in base]
146152
return min(extended, key=lambda f: abs(np.log(f / exact_freq)))
147153
return _iec_e3_round(exact_freq)
148154

tests/test_nominal_frequencies.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55

66
import numpy as np
7-
import pytest
87

98
from pyoctaveband.frequencies import (
109
_format_nominal_freq,
@@ -66,7 +65,7 @@ def test_format_1k_and_above():
6665
def test_getansifrequencies_returns_labels():
6766
freq, fd, fu, labels = getansifrequencies(fraction=3)
6867
assert isinstance(labels, list)
69-
assert all(isinstance(l, str) for l in labels)
68+
assert all(isinstance(label, str) for label in labels)
7069
assert len(labels) == len(freq)
7170
assert "1k" in labels
7271
assert "31.5" in labels
@@ -84,7 +83,7 @@ def test_filterbank_nominal_freq_attribute():
8483
fb = OctaveFilterBank(fs=48000, fraction=1)
8584
assert hasattr(fb, "nominal_freq")
8685
assert isinstance(fb.nominal_freq, list)
87-
assert all(isinstance(l, str) for l in fb.nominal_freq)
86+
assert all(isinstance(label, str) for label in fb.nominal_freq)
8887
assert "1k" in fb.nominal_freq
8988
assert len(fb.nominal_freq) == fb.num_bands
9089

0 commit comments

Comments
 (0)