diff --git a/CHANGELOG.md b/CHANGELOG.md index 31d1a1ff5..408bb055e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1864,6 +1864,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/). Changed). Both warn on use and are removed in 5.0, one release after the 3.x aliases. +### Removed + +- The flat pre-3.2 module paths, as 3.2 announced when it deprecated them: + `phonometry.levels`, `phonometry.insulation`, `phonometry.room_ir` and the + eighty-odd siblings that the modularization grouped into domain subpackages + raise `ModuleNotFoundError` now, as does `phonometry.loudness`, deprecated + since 3.1. Only the module paths went. The names they held are still + exported flat, so `from phonometry import leq` reads as it always has, and + so does every other name in `phonometry.__all__`. The 4.0 taxonomy aliases + are untouched and stay until 5.0. + + A pickle written by a 3.x release carries a flat path in the `__module__` of + its classes, and those no longer resolve; one written by 3.2 or later + through a subpackage path still does, until 5.0. + + With one generation left, `_compat.py` keeps one table, and the alias + machinery no longer carries the per-entry wording overrides that the 3.1 + deprecations needed. + ### Fixed - The committed example `.report()` fiches were not checked against the code diff --git a/docs/api-reference.md b/docs/api-reference.md index 32559be1c..2a9149a1d 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -44,15 +44,14 @@ contour = aircraft.noise_contour(path, powers, distances, sel, lmax, x=gx, y=gy) | `phonometry.simulation` | 2D acoustic FDTD wave simulation (staggered grid, sources, probes, impedance boundaries, obstacles) | Every name in the table below is also re-exported at the top level, so -`from phonometry import ` works for every row. Two generations of module -paths are still importable and warn on use. The pre-3.2 flat ones, written -without a subpackage, are removed in 4.0; the pre-4.0 ones that the taxonomy -moved are removed in 5.0. Reading a moved name from the namespace it left -warns and delegates as well. +`from phonometry import ` works for every row. The pre-4.0 module paths +that the taxonomy moved are still importable and warn on use; they are removed +in 5.0. Reading a moved name from the namespace it left warns and delegates as +well. The pre-3.2 flat paths, written without a subpackage, were removed in +4.0 as announced. | Deprecated path | Resolves to | Removed in | | :--- | :--- | :--- | -| `phonometry.insulation` | `phonometry.building.measurement.insulation` | 4.0 | | `phonometry.metrology.levels` | `phonometry.signals.levels` | 5.0 | | `phonometry.hearing.sti` | `phonometry.speech.sti` | 5.0 | | `phonometry.vibration.human_vibration` | `phonometry.vibration.human.exposure` | 5.0 | diff --git a/llms-full.txt b/llms-full.txt index eecb24982..d7b08f935 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -2257,15 +2257,14 @@ contour = aircraft.noise_contour(path, powers, distances, sel, lmax, x=gx, y=gy) | `phonometry.simulation` | 2D acoustic FDTD wave simulation (staggered grid, sources, probes, impedance boundaries, obstacles) | Every name in the table below is also re-exported at the top level, so -`from phonometry import ` works for every row. Two generations of module -paths are still importable and warn on use. The pre-3.2 flat ones, written -without a subpackage, are removed in 4.0; the pre-4.0 ones that the taxonomy -moved are removed in 5.0. Reading a moved name from the namespace it left -warns and delegates as well. +`from phonometry import ` works for every row. The pre-4.0 module paths +that the taxonomy moved are still importable and warn on use; they are removed +in 5.0. Reading a moved name from the namespace it left warns and delegates as +well. The pre-3.2 flat paths, written without a subpackage, were removed in +4.0 as announced. | Deprecated path | Resolves to | Removed in | | :--- | :--- | :--- | -| `phonometry.insulation` | `phonometry.building.measurement.insulation` | 4.0 | | `phonometry.metrology.levels` | `phonometry.signals.levels` | 5.0 | | `phonometry.hearing.sti` | `phonometry.speech.sti` | 5.0 | | `phonometry.vibration.human_vibration` | `phonometry.vibration.human.exposure` | 5.0 | diff --git a/scripts/generate_api_docs.py b/scripts/generate_api_docs.py index 145999e76..b507ef76d 100644 --- a/scripts/generate_api_docs.py +++ b/scripts/generate_api_docs.py @@ -774,38 +774,9 @@ def build_model() -> tuple[list[ModuleDoc], dict[str, str], list[str]]: if len(slugs) != len(pages): raise ValueError("slug collision between module pages") - # Docstrings still reference the flat pre-modularization module names - # (":mod:`phonometry.insulation`"); alias them to the current pages. - labels: dict[str, list[str]] = {} - for page in pages: - if page.module != "phonometry": - labels.setdefault(page.label, []).append(page.url) - for label, urls in labels.items(): - alias = f"phonometry.{label}" - if alias not in xref and len(urls) == 1: - xref[alias] = urls[0] - for old, new in _LEGACY_MODULE_ALIASES.items(): - if old not in xref and new in xref: - xref[old] = xref[new] return pages, xref, issues -#: Flat pre-modularization module names whose basename also changed; the -#: unchanged ones are aliased automatically from the page basenames above. -_LEGACY_MODULE_ALIASES = { - "phonometry.aircraft_atmospheric_absorption": ( - "phonometry.aircraft.atmospheric_absorption" - ), - "phonometry.environmental_measurement": ( - "phonometry.environment.assessment.measurement" - ), - "phonometry.underwater_acoustics": "phonometry.underwater.acoustics", - "phonometry.underwater_propagation": - "phonometry.underwater.propagation.closed_form", - "phonometry.underwater_sound_speed": "phonometry.underwater.propagation.sound_speed", -} - - _TOP_LEVEL_INTRO = ( "Package-level names defined in `phonometry/__init__.py` itself. " "Every public name in the library can also be imported directly from " diff --git a/site/src/content/docs/reference/api/aeroacoustics/atmospheric-absorption.md b/site/src/content/docs/reference/api/aeroacoustics/atmospheric-absorption.md index 6b818185b..2ddff3c3f 100644 --- a/site/src/content/docs/reference/api/aeroacoustics/atmospheric-absorption.md +++ b/site/src/content/docs/reference/api/aeroacoustics/atmospheric-absorption.md @@ -11,7 +11,7 @@ Aircraft noise certification (14 CFR Part 36, ICAO Annex 16 Vol. I) works with one-third-octave-band spectra, and correcting a measured flyover to reference atmospheric conditions requires the band attenuation over the propagation path. The pure-tone attenuation coefficient is the ISO 9613-1 one (identical, per ARP -5534 §3.1) already provided by [`phonometry.air_absorption.air_attenuation`](/phonometry/reference/api/environment/air-absorption/#air_attenuation); +5534 §3.1) already provided by [`air_attenuation`](/phonometry/reference/api/environment/air-absorption/#air_attenuation); this module adds the **SAE Method** (ARP 5534 §3.2.2), a regression that turns the pure-tone mid-band path-length attenuation into the one-third-octave-band attenuation and stays consistent with the ISO/ANSI Exact Method well beyond the diff --git a/site/src/content/docs/reference/api/electroacoustics/swept-sine.md b/site/src/content/docs/reference/api/electroacoustics/swept-sine.md index 59a0d3c10..079ce9c04 100644 --- a/site/src/content/docs/reference/api/electroacoustics/swept-sine.md +++ b/site/src/content/docs/reference/api/electroacoustics/swept-sine.md @@ -42,7 +42,7 @@ Two excitation/deconvolution pairs are implemented: * **Exponential sweep with the Farina inverse filter** -- the classical ESS of [`phonometry.sweep_signal`](/phonometry/reference/api/rooms/impulse-response/#sweep_signal) deconvolved by the time-reversed, amplitude-compensated sweep (Farina 2000; ISO 18233:2006 Figure B.2, - the machinery of [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/)). The harmonic + the machinery of [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/#impulse_response)). The harmonic *magnitudes* are correct, but the sweep is not synchronized: its `-1` phase term breaks the time-shift/harmonic equivalence, so the phases of `H_n` for $n \ge 2$ depend on the excitation and are not diff --git a/site/src/content/docs/reference/api/environment/air-absorption.md b/site/src/content/docs/reference/api/environment/air-absorption.md index 37d7ca75c..4631de373 100644 --- a/site/src/content/docs/reference/api/environment/air-absorption.md +++ b/site/src/content/docs/reference/api/environment/air-absorption.md @@ -55,7 +55,7 @@ $f_m = 1000 \cdot 10^{k/10}$, `k` integer. Pass `exact_midband=True` to snap the requested frequencies onto that grid and reproduce Table 1 exactly. -This module closes the loop with [`phonometry.materials.absorbers.sound_absorption`](/phonometry/reference/api/materials/sound-absorption/) (ISO 354), +This module closes the loop with [`sound_absorption`](/phonometry/reference/api/materials/sound-absorption/) (ISO 354), whose air power-attenuation coefficient `m` (1/m) is defined only through the ISO 9613-1 `alpha` via $m = \alpha / (10 \log_{10} e)$. [`air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m) returns that `m` directly. @@ -99,7 +99,7 @@ scalars. ISO 354:2003 defers its air power-attenuation coefficient `m` (1/m) entirely to this `alpha` via $m = \alpha / (10 \log_{10} e)$. Use [`air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m) to obtain that `m` for -[`phonometry.sound_absorption.absorption_area`](/phonometry/reference/api/materials/sound-absorption/#absorption_area) / +[`absorption_area`](/phonometry/reference/api/materials/sound-absorption/#absorption_area) / [`absorption_coefficient`](/phonometry/reference/api/materials/sound-absorption/#absorption_coefficient). ::: @@ -121,7 +121,7 @@ ISO 354 air power-attenuation coefficient `m` (1/m) from conditions. Convenience composition of [`air_attenuation`](/phonometry/reference/api/environment/air-absorption/#air_attenuation) (ISO 9613-1 `alpha` in dB/m) with the ISO 354:2003 (8.1.2.1) conversion $m = \alpha / (10 \log_{10} e)$ -(via [`phonometry.sound_absorption.attenuation_from_alpha`](/phonometry/reference/api/materials/sound-absorption/#attenuation_from_alpha)). It lets an +(via [`attenuation_from_alpha`](/phonometry/reference/api/materials/sound-absorption/#attenuation_from_alpha)). It lets an ISO 354 caller feed real atmospheric conditions into [`absorption_area`](/phonometry/reference/api/materials/sound-absorption/#absorption_area) / [`absorption_coefficient`](/phonometry/reference/api/materials/sound-absorption/#absorption_coefficient) instead of diff --git a/site/src/content/docs/reference/api/environment/outdoor-propagation.md b/site/src/content/docs/reference/api/environment/outdoor-propagation.md index 5373b07c9..b6d5f8491 100644 --- a/site/src/content/docs/reference/api/environment/outdoor-propagation.md +++ b/site/src/content/docs/reference/api/environment/outdoor-propagation.md @@ -30,7 +30,7 @@ Implemented here are the four general terms of clause 7: * `Adiv` geometrical divergence, $20 \log_{10}(d/d_0) + 11$ (Eq. (7)); * `Aatm` atmospheric absorption, $\alpha d$ (Eq. (8)) with `alpha` - the ISO 9613-1 coefficient supplied by [`phonometry.environment.propagation.air_absorption`](/phonometry/reference/api/environment/air-absorption/); + the ISO 9613-1 coefficient supplied by [`air_absorption`](/phonometry/reference/api/environment/air-absorption/); * `Agr` ground effect, both the general per-region method of 7.3.1 with the Table 3 functions `a'/b'/c'/d'` (Eq. (9)) and the alternative simplified method of 7.3.2 (Eq. (10)); @@ -66,7 +66,7 @@ Attenuation due to atmospheric absorption (ISO 9613-2:1996, Eq. (8)). $A_{atm} = \alpha d$ with `alpha` the ISO 9613-1 atmospheric attenuation -coefficient (here in dB/m, from [`phonometry.air_absorption.air_attenuation`](/phonometry/reference/api/environment/air-absorption/#air_attenuation)) +coefficient (here in dB/m, from [`air_attenuation`](/phonometry/reference/api/environment/air-absorption/#air_attenuation)) at each octave-band midband frequency. Eq. (8) writes `alpha` in dB/km with $A_{atm} = \alpha_{\text{dB/km}} \, d / 1000$; the two forms are identical. diff --git a/site/src/content/docs/reference/api/environment/wind-turbine.md b/site/src/content/docs/reference/api/environment/wind-turbine.md index 094f76ffc..fc4407972 100644 --- a/site/src/content/docs/reference/api/environment/wind-turbine.md +++ b/site/src/content/docs/reference/api/environment/wind-turbine.md @@ -20,7 +20,7 @@ Two closed-form quantities of the standard: `ΔL_a` that decides whether a tone is audible. The tonal-audibility formula itself is the ISO 1996-2 Annex C one already in -[`phonometry.environment.assessment.measurement`](/phonometry/reference/api/environment/measurement/); what is specific to IEC 61400-11 is +[`measurement`](/phonometry/reference/api/environment/measurement/); what is specific to IEC 61400-11 is how the tone and masking-noise levels and the (Zwicker) critical band are determined from the narrowband spectrum. The rating adjustment `K_T` is the ISO 1996-2 [`tonal_adjustment`](/phonometry/reference/api/environment/measurement/#tonal_adjustment). The @@ -49,7 +49,7 @@ pressure doubling; $S_0 = 1$ m². | Name | Description | | :--- | :--- | -| `band_levels` | Background-corrected A-weighted band sound pressure levels `L_p,i`, in dB (scalar or per band). The 61400-11-specific background correction (Formula 23 subtraction with the 3-6 dB asterisk marking and the \<= 3 dB not-reported rule, subclause 9.3) is out of scope here and must be applied beforehand; note its rule set differs from the ISO 1996-2 correction in [`phonometry.environment.assessment.measurement.residual_sound_correction`](/phonometry/reference/api/environment/measurement/#residual_sound_correction). | +| `band_levels` | Background-corrected A-weighted band sound pressure levels `L_p,i`, in dB (scalar or per band). The 61400-11-specific background correction (Formula 23 subtraction with the 3-6 dB asterisk marking and the \<= 3 dB not-reported rule, subclause 9.3) is out of scope here and must be applied beforehand; note its rule set differs from the ISO 1996-2 correction in [`residual_sound_correction`](/phonometry/reference/api/environment/measurement/#residual_sound_correction). | | `r1` | Slant distance `R1` to the rotor centre, in m. | **Returns:** The apparent sound power level `L_WA`, in dB re 1 pW. diff --git a/site/src/content/docs/reference/api/materials/road-absorption.md b/site/src/content/docs/reference/api/materials/road-absorption.md index 25fc3f7f9..adc4f76d6 100644 --- a/site/src/content/docs/reference/api/materials/road-absorption.md +++ b/site/src/content/docs/reference/api/materials/road-absorption.md @@ -37,7 +37,7 @@ opposite ends of the absorption scale and are **not** interchangeable: (measured `alpha` below ~0.15). Part 2 does not restate the transfer-function / reflection-factor / absorption mathematics; Clauses 4, 5.7 and 6.6 defer it to ISO 10534-2. The core computation therefore lives in - [`phonometry.impedance_tube.two_microphone_impedance`](/phonometry/reference/api/materials/impedance-tube/#two_microphone_impedance) and is **not** + [`two_microphone_impedance`](/phonometry/reference/api/materials/impedance-tube/#two_microphone_impedance) and is **not** reimplemented here. This module contributes only the Part-2 tube geometry/validity helpers (upper usable frequency, microphone-spacing bounds, the 250-1600 Hz one-third-octave working range) and the Annex A internal-loss diff --git a/site/src/content/docs/reference/api/rooms/acoustics.md b/site/src/content/docs/reference/api/rooms/acoustics.md index ff60ab78c..1a045f9dd 100644 --- a/site/src/content/docs/reference/api/rooms/acoustics.md +++ b/site/src/content/docs/reference/api/rooms/acoustics.md @@ -69,7 +69,7 @@ integrated impulse response, Clause 6). | Name | Description | | :--- | :--- | -| `ir` | Measured impulse response (1D), e.g. from [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/) (ISO 18233). | +| `ir` | Measured impulse response (1D), e.g. from [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/#impulse_response) (ISO 18233). | | `fs` | Sample rate in Hz. | | `band` | Optional band centre frequency in Hz. When given, the impulse response is first filtered with the matching IEC 61260 fractional-octave filter; when None the broadband response is integrated directly. | | `fraction` | Bandwidth fraction of the band filter (1 = octave, 3 = one-third octave). Only used when `band` is not None. | diff --git a/site/src/content/docs/reference/api/rooms/image-source.md b/site/src/content/docs/reference/api/rooms/image-source.md index 51caa02b2..546fb0971 100644 --- a/site/src/content/docs/reference/api/rooms/image-source.md +++ b/site/src/content/docs/reference/api/rooms/image-source.md @@ -144,7 +144,7 @@ reproduces the Eyring reverberation time of the room (Kuttruff Equation | `fs` | Sample rate, Hz. | | `max_order` | Reflection-order cut-off (total wall reflections). The shoebox has $(2/3)(2 i_0^3 + 3 i_0^2 + 4 i_0)$ audible images up to order `i0` (Kuttruff Equation (9.23)). Default 20. | | `speed_of_sound` | Speed of sound `c`, m/s (default [`DEFAULT_SPEED_OF_SOUND`](/phonometry/reference/api/materials/road-absorption/#default_speed_of_sound)). | -| `air_attenuation` | Air *intensity* attenuation constant `m`, in neper per metre (scalar or per-band); the pressure amplitude of each path is scaled by $e^{-m r / 2}$ (Kuttruff 4.1). Default 0 (air absorption neglected). Obtain a physical `m` from [`phonometry.air_absorption.air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). | +| `air_attenuation` | Air *intensity* attenuation constant `m`, in neper per metre (scalar or per-band); the pressure amplitude of each path is scaled by $e^{-m r / 2}$ (Kuttruff 4.1). Default 0 (air absorption neglected). Obtain a physical `m` from [`air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). | | `duration` | RIR length, s; default the latest image arrival rounded up to the next sample. | | `frequencies` | Optional band centre frequencies, Hz, labelling a per-band result. When given, its length must match the band count of `absorption` (or broadcast against it). | diff --git a/site/src/content/docs/reference/api/rooms/reverberation-prediction.md b/site/src/content/docs/reference/api/rooms/reverberation-prediction.md index 37ba98ba2..180b7271c 100644 --- a/site/src/content/docs/reference/api/rooms/reverberation-prediction.md +++ b/site/src/content/docs/reference/api/rooms/reverberation-prediction.md @@ -47,7 +47,7 @@ default $c_0 = 343$ m/s it takes the familiar textbook value Air absorption enters every model through the `air_attenuation` power coefficient `m` (in neper per metre) as the additive term $4 m V$; obtain a physical `m` from temperature and humidity with -[`phonometry.air_absorption.air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). +[`air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). Each model enforces its own mathematical domain on the absorption coefficients. Sabine's linear sum is finite for any non-negative coefficient, @@ -390,7 +390,7 @@ error (a percentage passed instead of a fraction). | :--- | :--- | | `volume` | Room volume `V`, m3. | | `surfaces` | Sequence of `(area, absorption_coefficient)` pairs; each coefficient a scalar or a per-band array in `[0, 2]`. | -| `air_attenuation` | Air power-attenuation coefficient `m`, in neper per metre (scalar or per-band); see [`phonometry.air_absorption.air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). Default `0` (air absorption neglected). | +| `air_attenuation` | Air power-attenuation coefficient `m`, in neper per metre (scalar or per-band); see [`air_attenuation_m`](/phonometry/reference/api/environment/air-absorption/#air_attenuation_m). Default `0` (air absorption neglected). | | `speed_of_sound` | Speed of sound `c0`, m/s (default [`DEFAULT_SPEED_OF_SOUND`](/phonometry/reference/api/materials/road-absorption/#default_speed_of_sound), giving the factor `0.161`). | **Returns:** The reverberation time `T`, s; a float for scalar inputs, otherwise a per-band array. diff --git a/site/src/content/docs/reference/api/signals/inversion.md b/site/src/content/docs/reference/api/signals/inversion.md index ff9ae8d95..a9bbf1010 100644 --- a/site/src/content/docs/reference/api/signals/inversion.md +++ b/site/src/content/docs/reference/api/signals/inversion.md @@ -176,7 +176,7 @@ Sec. 2.4). Both regularization levels are *relative* to the peak of $\lvert H \rvert^2$ -(like the scalar `regularization` of [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/), +(like the scalar `regularization` of [`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/#impulse_response), which this generalises): in-band the equalized magnitude deviates from unity by at most `regularization_inside * max|H|**2 / min|H|**2` -- the analytic residue diff --git a/site/src/content/docs/reference/api/signals/phase.md b/site/src/content/docs/reference/api/signals/phase.md index 7827eb799..ac654c8c8 100644 --- a/site/src/content/docs/reference/api/signals/phase.md +++ b/site/src/content/docs/reference/api/signals/phase.md @@ -30,7 +30,7 @@ phase. Sampling precautions (documented, and the reason for the `oversample` padding): the estimate operates on a *uniformly sampled* one-sided response (DC to Nyquist inclusive, the layout of `numpy.fft.rfft` and of -[`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/) spectra). The real cepstrum of the +[`phonometry.impulse_response`](/phonometry/reference/api/rooms/impulse-response/#impulse_response) spectra). The real cepstrum of the sampled log-magnitude is time-aliased when the grid is coarse relative to how sharp the response is, so the magnitude is resampled onto an `oversample` times denser grid by exact trigonometric (zero-padded diff --git a/src/phonometry/__init__.py b/src/phonometry/__init__.py index 8847e6484..d1c97e577 100644 --- a/src/phonometry/__init__.py +++ b/src/phonometry/__init__.py @@ -2851,7 +2851,7 @@ def __getattr__(name: str) -> Any: return globals()[canonical] -# Deprecated module-path aliases for the 3.2 package reorganization: importing -# the package installs sys.modules shims for every moved public module (see -# phonometry/_compat.py; removed in 4.0). +# Deprecated module-path aliases for the 4.0 taxonomy: importing the package +# installs sys.modules shims for every moved public module (see +# phonometry/_compat.py; removed in 5.0). from . import _compat as _compat diff --git a/src/phonometry/_compat.py b/src/phonometry/_compat.py index 2678f8bfd..10bc9beef 100644 --- a/src/phonometry/_compat.py +++ b/src/phonometry/_compat.py @@ -1,20 +1,20 @@ # Copyright (c) 2026. Jose Manuel Requena Plens """Deprecated module-path aliases for the phonometry package layout. -Two generations of aliases live here, each with its own removal date: - -* :data:`_MOVED_3X` covers the 3.2 modularization, which grouped the flat - top-level modules into domain subpackages (``phonometry.building``, - ``phonometry.underwater``, ...). Removed in 4.0. Its targets follow the - modules wherever they land, so a 3.x path always resolves in one hop. -* :data:`_MOVED_4X` covers the 4.0 taxonomy, which splits the oversized - subpackages into domain ones (``phonometry.metrology`` into - ``phonometry.filters``, ``phonometry.signals`` and a narrowed - ``phonometry.metrology``; the speech intelligibility of - ``phonometry.hearing`` into ``phonometry.speech``), gives the large domains - a second level (``phonometry.vibration`` into ``structural``, ``human`` and - ``machinery``) and renames ``phonometry.environmental`` to - ``phonometry.environment``. Removed in 5.0. +:data:`_MOVED_4X` covers the 4.0 taxonomy, which splits the oversized +subpackages into domain ones (``phonometry.metrology`` into +``phonometry.filters``, ``phonometry.signals`` and a narrowed +``phonometry.metrology``; the speech intelligibility of +``phonometry.hearing`` into ``phonometry.speech``), gives the large domains a +second level (``phonometry.vibration`` into ``structural``, ``human`` and +``machinery``) and renames ``phonometry.environmental`` to +``phonometry.environment``. Removed in 5.0. + +The 3.2 generation, which grouped the flat top-level modules into domain +subpackages, announced 4.0 as its removal and is gone: ``phonometry.levels`` +and its eighty-odd siblings raise ``ModuleNotFoundError`` now. Only the module +paths went: the names they held are still exported flat, so ``from phonometry +import leq`` reads as it always has. Every public module path that moved stays importable through the shims registered here: ``import phonometry.`` and ``from phonometry. @@ -27,9 +27,6 @@ documentation leads with. :func:`_namespace_shim` keeps those attribute reads working from the namespace they left, with the same notice. -This generalizes the former ``phonometry.loudness`` PEP 562 shim (that module -file is gone; its entry lives in the table below with its original 3.1 wording -preserved). """ from __future__ import annotations @@ -42,134 +39,10 @@ from ._internal.warnings import _warn_renamed -#: The one module NT ACOU 112 and ISO/PAS 1996-3 share since 4.0. Four old -#: paths land on it, from both generations of the table. +#: The one module NT ACOU 112 and ISO/PAS 1996-3 share since 4.0. Three old +#: paths land on it. _IMPULSIVE_SOUND = "phonometry.environment.assessment.impulsive_sound" -#: Old public module path -> relocated module path. One row per moved module. -_MOVED_3X: dict[str, str] = { - "phonometry.utils": "phonometry._internal.utils", - "phonometry._warnings": "phonometry._internal.warnings", - "phonometry.calibration": "phonometry.metrology.calibration", - "phonometry.compliance": "phonometry.filters.compliance", - "phonometry.core": "phonometry.filters.core", - "phonometry.filter_design": "phonometry.filters.design", - "phonometry.frequencies": "phonometry.filters.frequencies", - "phonometry.levels": "phonometry.signals.levels", - "phonometry.parametric_filters": "phonometry.filters.weighting", - "phonometry.uncertainty": "phonometry.metrology.uncertainty", - "phonometry.fluctuation_strength": "phonometry.psychoacoustics.quality.fluctuation_strength", - "phonometry.loudness_contours": "phonometry.psychoacoustics.loudness.contours", - "phonometry.loudness_ecma": "phonometry.psychoacoustics.loudness.ecma", - "phonometry.loudness_moore_glasberg": "phonometry.psychoacoustics.loudness.moore_glasberg", - "phonometry.loudness_moore_glasberg_time": "phonometry.psychoacoustics.loudness.moore_glasberg_time", - "phonometry.loudness_zwicker": "phonometry.psychoacoustics.loudness.zwicker", - "phonometry.psychoacoustic_annoyance": "phonometry.psychoacoustics.quality.annoyance", - "phonometry.roughness_ecma": "phonometry.psychoacoustics.quality.roughness_ecma", - "phonometry.sharpness": "phonometry.psychoacoustics.quality.sharpness", - "phonometry.tonality": "phonometry.psychoacoustics.quality.tonality", - "phonometry.tonality_ecma": "phonometry.psychoacoustics.quality.tonality_ecma", - "phonometry.tone_audibility": "phonometry.psychoacoustics.quality.tone_audibility", - "phonometry.noise_induced_hearing_loss": "phonometry.hearing.noise_induced_hearing_loss", - "phonometry.occupational_exposure": "phonometry.hearing.occupational_exposure", - "phonometry.sii": "phonometry.speech.sii", - "phonometry.sti": "phonometry.speech.sti", - "phonometry.intensity": "phonometry.emission.intensity", - "phonometry.sound_power": "phonometry.emission.sound_power", - "phonometry.sound_power_intensity": "phonometry.emission.sound_power_intensity", - "phonometry.sound_power_reverberation": "phonometry.emission.sound_power_reverberation", - "phonometry.vibration_sound_power": "phonometry.emission.vibration_sound_power", - "phonometry.absorption_rating": - "phonometry.materials.absorbers.rating", - "phonometry.absorption_uncertainty": - "phonometry.materials.absorbers.uncertainty", - "phonometry.airflow_resistance": - "phonometry.materials.absorbers.airflow_resistance", - "phonometry.dynamic_stiffness": - "phonometry.materials.resilient.dynamic_stiffness", - "phonometry.impedance_tube": - "phonometry.materials.absorbers.impedance_tube", - "phonometry.road_absorption": - "phonometry.materials.surfaces.road_absorption", - "phonometry.scattering_diffusion": - "phonometry.materials.diffusers.scattering_diffusion", - "phonometry.sound_absorption": - "phonometry.materials.absorbers.sound_absorption", - "phonometry.enclosed_space_absorption": "phonometry.room.enclosed_space_absorption", - "phonometry.open_plan": "phonometry.room.open_plan", - "phonometry.reverberation_prediction": "phonometry.room.reverberation_prediction", - "phonometry.room_acoustics": "phonometry.room.acoustics", - "phonometry.room_ir": "phonometry.room.impulse_response", - "phonometry.room_noise": "phonometry.room.noise_criteria", - "phonometry.building_prediction": - "phonometry.building.prediction.simplified_model", - "phonometry.building_uncertainty": - "phonometry.building.measurement.uncertainty", - "phonometry.facade_prediction": - "phonometry.building.prediction.facade", - "phonometry.flanking_transmission": - "phonometry.building.measurement.flanking_transmission", - "phonometry.floor_covering_improvement": - "phonometry.building.measurement.floor_covering_improvement", - "phonometry.installed_structure_borne": - "phonometry.building.prediction.installed_structure_borne", - "phonometry.insulation": - "phonometry.building.measurement.insulation", - "phonometry.intensity_insulation": - "phonometry.building.measurement.intensity_insulation", - "phonometry.lab_insulation": - "phonometry.building.measurement.lab_insulation", - "phonometry.structure_borne_power": - "phonometry.building.measurement.structure_borne_power", - "phonometry.survey_insulation": - "phonometry.building.measurement.survey_insulation", - "phonometry.human_vibration": "phonometry.vibration.human.exposure", - "phonometry.mechanical_mobility": - "phonometry.vibration.structural.mechanical_mobility", - "phonometry.multiple_shock_vibration": - "phonometry.vibration.human.multiple_shock", - "phonometry.transfer_stiffness": - "phonometry.vibration.structural.transfer_stiffness", - "phonometry.air_absorption": - "phonometry.environment.propagation.air_absorption", - "phonometry.environmental_measurement": - "phonometry.environment.assessment.measurement", - "phonometry.impulse_prominence": _IMPULSIVE_SOUND, - "phonometry.outdoor_propagation": - "phonometry.environment.propagation.outdoor_propagation", - "phonometry.wind_turbine_noise": - "phonometry.environment.sources.wind_turbine", - "phonometry.aircraft_atmospheric_absorption": "phonometry.aircraft.atmospheric_absorption", - "phonometry.aircraft_noise": "phonometry.aircraft.certification", - "phonometry.airport_noise": "phonometry.aircraft.airport_noise", - "phonometry.rotorcraft_noise": "phonometry.aircraft.rotorcraft_noise", - "phonometry.numerical_propagation": "phonometry.underwater.propagation.numerical", - "phonometry.ocean_ambient_noise": "phonometry.underwater.sources.ambient_noise", - "phonometry.pile_driving_noise": "phonometry.underwater.sources.pile_driving_noise", - "phonometry.seabed_reflection": "phonometry.underwater.propagation.seabed_reflection", - "phonometry.ship_radiated_noise": "phonometry.underwater.sources.ship_radiated_noise", - "phonometry.ship_traffic_noise": "phonometry.underwater.sources.ship_traffic_noise", - "phonometry.sonar_equation": "phonometry.underwater.sonar_equation", - "phonometry.underwater_acoustics": "phonometry.underwater.acoustics", - "phonometry.underwater_propagation": - "phonometry.underwater.propagation.closed_form", - "phonometry.underwater_sound_speed": "phonometry.underwater.propagation.sound_speed", - "phonometry.distortion": "phonometry.electroacoustics.distortion", - "phonometry.frequency_response": "phonometry.electroacoustics.frequency_response", - # -} - -#: Entries whose deprecation predates 3.2 keep their original wording. -_SINCE: dict[str, str] = { - "phonometry.loudness": "3.1", -} - -#: Renames that were already shimmed before 3.2 (target differs from a plain -#: package move). ``phonometry.loudness`` predates the reorganization and -#: lands wherever the Zwicker module currently lives, so it reads its target -#: from the row above instead of repeating it. -_MOVED_3X["phonometry.loudness"] = _MOVED_3X["phonometry.loudness_zwicker"] - #: Old module path -> relocated module path for the 4.0 taxonomy. The #: oversized ``metrology`` catch-all became three packages: the normalized #: frequency selectivity in ``filters``, the general signal analysis in @@ -364,10 +237,9 @@ # shadowing it is exactly what must not happen. } -#: The two generations, each with the release that deprecated it and the one -#: that removes it. Order matters only for readability; the paths are disjoint. +#: The generations in force, each with the release that deprecated it and the +#: one that removes it. The 3.2 generation was removed in 4.0, as announced. _GENERATIONS: tuple[tuple[dict[str, str], str, str], ...] = ( - (_MOVED_3X, "3.2", "4.0"), (_MOVED_4X, "4.0", "5.0"), ) @@ -404,7 +276,7 @@ def __getattr__(name: str) -> Any: _warn_renamed( f"the '{old}' module", f"'{new}'", - since=_SINCE.get(old, since), + since=since, removed_in=removed_in, ) return attr @@ -541,9 +413,9 @@ def _install() -> None: continue shim = _make_shim(old, new, since, removed_in) sys.modules[old] = shim - # `import phonometry.utils` also binds the attribute on the - # package; mirror that so `phonometry.utils` resolves without the - # import. Aliases below a subpackage are served by that package's + # `import phonometry.environmental` also binds the attribute on + # the package; mirror that so `phonometry.environmental` resolves + # without the import. Aliases below a subpackage are served by that package's # own shim (:func:`_namespace_shim`), which resolves the moved # public names first, so binding them here would shadow a function # with a module. diff --git a/src/phonometry/_plot/psychoacoustics.py b/src/phonometry/_plot/psychoacoustics.py index 54602ce4b..3f5a9f5c4 100644 --- a/src/phonometry/_plot/psychoacoustics.py +++ b/src/phonometry/_plot/psychoacoustics.py @@ -519,8 +519,8 @@ def plot_ecma_fluctuation_strength( ``ax`` is supplied only the time-dependent fluctuation strength is drawn on it and that single axes is returned. - :param result: An :class:`~phonometry.fluctuation_strength_ecma. - EcmaFluctuationStrength`. + :param result: An :class:`~phonometry.psychoacoustics.quality. + fluctuation_strength_ecma.EcmaFluctuationStrength`. :param ax: Existing axes to draw on, or ``None`` to create a figure. :param language: Label language, ``"en"`` (default) or ``"es"``. :param kwargs: Forwarded to the time-trace line ``plot`` call. diff --git a/src/phonometry/aircraft/atmospheric_absorption.py b/src/phonometry/aircraft/atmospheric_absorption.py index 5037bb0d9..b11bebd48 100644 --- a/src/phonometry/aircraft/atmospheric_absorption.py +++ b/src/phonometry/aircraft/atmospheric_absorption.py @@ -6,7 +6,7 @@ one-third-octave-band spectra, and correcting a measured flyover to reference atmospheric conditions requires the band attenuation over the propagation path. The pure-tone attenuation coefficient is the ISO 9613-1 one (identical, per ARP -5534 §3.1) already provided by :func:`phonometry.air_absorption.air_attenuation`; +5534 §3.1) already provided by :func:`~phonometry.environment.propagation.air_absorption.air_attenuation`; this module adds the **SAE Method** (ARP 5534 §3.2.2), a regression that turns the pure-tone mid-band path-length attenuation into the one-third-octave-band attenuation and stays consistent with the ISO/ANSI Exact Method well beyond the diff --git a/src/phonometry/building/measurement/uncertainty.py b/src/phonometry/building/measurement/uncertainty.py index 9ac5b6f42..c0f5f2021 100644 --- a/src/phonometry/building/measurement/uncertainty.py +++ b/src/phonometry/building/measurement/uncertainty.py @@ -621,7 +621,7 @@ def _warn_renamed(old: str, new: str) -> None: warnings.warn( f"phonometry {old} (ISO 12999-1) is deprecated since phonometry 3.1 " f"and will be removed in 4.0; use {new}. For the GUM function use " - f"phonometry.uncertainty.{old}.", + f"phonometry.metrology.uncertainty.{old}.", DeprecationWarning, stacklevel=3, ) diff --git a/src/phonometry/environment/propagation/air_absorption.py b/src/phonometry/environment/propagation/air_absorption.py index e3ee8a81f..42b63cfde 100644 --- a/src/phonometry/environment/propagation/air_absorption.py +++ b/src/phonometry/environment/propagation/air_absorption.py @@ -59,7 +59,7 @@ ``exact_midband=True`` to snap the requested frequencies onto that grid and reproduce Table 1 exactly. -This module closes the loop with :mod:`phonometry.materials.absorbers.sound_absorption` (ISO 354), +This module closes the loop with :mod:`~phonometry.materials.absorbers.sound_absorption` (ISO 354), whose air power-attenuation coefficient ``m`` (1/m) is defined only through the ISO 9613-1 ``alpha`` via :math:`m = \alpha / (10 \log_{10} e)`. :func:`air_attenuation_m` returns that ``m`` directly. @@ -223,8 +223,8 @@ def air_attenuation( ISO 354:2003 defers its air power-attenuation coefficient ``m`` (1/m) entirely to this ``alpha`` via :math:`m = \alpha / (10 \log_{10} e)`. Use :func:`air_attenuation_m` to obtain that ``m`` for - :func:`phonometry.sound_absorption.absorption_area` / - :func:`~phonometry.sound_absorption.absorption_coefficient`. + :func:`~phonometry.materials.absorbers.sound_absorption.absorption_area` / + :func:`~phonometry.materials.absorbers.sound_absorption.absorption_coefficient`. """ freqs = np.asarray(frequencies, dtype=np.float64) _validate(freqs, temperature, relative_humidity, pressure) @@ -266,10 +266,10 @@ def air_attenuation_m( Convenience composition of :func:`air_attenuation` (ISO 9613-1 ``alpha`` in dB/m) with the ISO 354:2003 (8.1.2.1) conversion :math:`m = \alpha / (10 \log_{10} e)` - (via :func:`phonometry.sound_absorption.attenuation_from_alpha`). It lets an + (via :func:`~phonometry.materials.absorbers.sound_absorption.attenuation_from_alpha`). It lets an ISO 354 caller feed real atmospheric conditions into - :func:`~phonometry.sound_absorption.absorption_area` / - :func:`~phonometry.sound_absorption.absorption_coefficient` instead of + :func:`~phonometry.materials.absorbers.sound_absorption.absorption_area` / + :func:`~phonometry.materials.absorbers.sound_absorption.absorption_coefficient` instead of hand-entering ``m``. :param frequencies: Frequency or frequencies ``f``, in hertz (array-like). diff --git a/src/phonometry/environment/propagation/outdoor_propagation.py b/src/phonometry/environment/propagation/outdoor_propagation.py index 5756e9a8c..5f5cc9720 100644 --- a/src/phonometry/environment/propagation/outdoor_propagation.py +++ b/src/phonometry/environment/propagation/outdoor_propagation.py @@ -25,7 +25,7 @@ * ``Adiv`` geometrical divergence, :math:`20 \log_{10}(d/d_0) + 11` (Eq. (7)); * ``Aatm`` atmospheric absorption, :math:`\alpha d` (Eq. (8)) with ``alpha`` - the ISO 9613-1 coefficient supplied by :mod:`phonometry.environment.propagation.air_absorption`; + the ISO 9613-1 coefficient supplied by :mod:`~phonometry.environment.propagation.air_absorption`; * ``Agr`` ground effect, both the general per-region method of 7.3.1 with the Table 3 functions ``a'/b'/c'/d'`` (Eq. (9)) and the alternative simplified method of 7.3.2 (Eq. (10)); @@ -333,7 +333,7 @@ def atmospheric_absorption( :math:`A_{atm} = \alpha d` with ``alpha`` the ISO 9613-1 atmospheric attenuation - coefficient (here in dB/m, from :func:`phonometry.air_absorption.air_attenuation`) + coefficient (here in dB/m, from :func:`~phonometry.environment.propagation.air_absorption.air_attenuation`) at each octave-band midband frequency. Eq. (8) writes ``alpha`` in dB/km with :math:`A_{atm} = \alpha_{\text{dB/km}} \, d / 1000`; the two forms are identical. diff --git a/src/phonometry/environment/sources/wind_turbine.py b/src/phonometry/environment/sources/wind_turbine.py index eb946c1f3..2628a0c9a 100644 --- a/src/phonometry/environment/sources/wind_turbine.py +++ b/src/phonometry/environment/sources/wind_turbine.py @@ -15,10 +15,10 @@ ``ΔL_a`` that decides whether a tone is audible. The tonal-audibility formula itself is the ISO 1996-2 Annex C one already in -:mod:`phonometry.environment.assessment.measurement`; what is specific to IEC 61400-11 is +:mod:`~phonometry.environment.assessment.measurement`; what is specific to IEC 61400-11 is how the tone and masking-noise levels and the (Zwicker) critical band are determined from the narrowband spectrum. The rating adjustment ``K_T`` is the -ISO 1996-2 :func:`~phonometry.environmental_measurement.tonal_adjustment`. The +ISO 1996-2 :func:`~phonometry.environment.assessment.measurement.tonal_adjustment`. The full measurement pipeline (binning, regression to standardised wind speeds, uncertainty budgets) is out of scope; these are the underlying closed forms. """ @@ -109,7 +109,7 @@ def apparent_sound_power_level( asterisk marking and the <= 3 dB not-reported rule, subclause 9.3) is out of scope here and must be applied beforehand; note its rule set differs from the ISO 1996-2 correction in - :func:`phonometry.environment.assessment.measurement.residual_sound_correction`. + :func:`~phonometry.environment.assessment.measurement.residual_sound_correction`. :param r1: Slant distance ``R1`` to the rotor centre, in m. :return: The apparent sound power level ``L_WA``, in dB re 1 pW. :raises ValueError: If the inputs are invalid. diff --git a/src/phonometry/hearing/occupational_exposure.py b/src/phonometry/hearing/occupational_exposure.py index c2306976e..b933b4e8a 100644 --- a/src/phonometry/hearing/occupational_exposure.py +++ b/src/phonometry/hearing/occupational_exposure.py @@ -647,5 +647,5 @@ def __getattr__(name: str) -> Any: _warn_renamed("ExposureWarning", "OccupationalExposureWarning") return OccupationalExposureWarning raise AttributeError( - f"module 'phonometry.occupational_exposure' has no attribute {name!r}" + f"module 'phonometry.hearing.occupational_exposure' has no attribute {name!r}" ) diff --git a/src/phonometry/materials/absorbers/rating.py b/src/phonometry/materials/absorbers/rating.py index 1eb1a87ef..1d8770290 100644 --- a/src/phonometry/materials/absorbers/rating.py +++ b/src/phonometry/materials/absorbers/rating.py @@ -481,7 +481,7 @@ def __getattr__(name: str) -> Any: canonical = _RENAMED_CONSTANTS[name] except KeyError: raise AttributeError( - f"module 'phonometry.absorption_rating' has no attribute {name!r}" + f"module 'phonometry.materials.absorbers.rating' has no attribute {name!r}" ) from None _warn_renamed(name, canonical) return globals()[canonical] diff --git a/src/phonometry/materials/diffusers/scattering_diffusion.py b/src/phonometry/materials/diffusers/scattering_diffusion.py index 95b982fbc..30437391d 100644 --- a/src/phonometry/materials/diffusers/scattering_diffusion.py +++ b/src/phonometry/materials/diffusers/scattering_diffusion.py @@ -1187,5 +1187,5 @@ def __getattr__(name: str) -> Any: _warn_renamed("BASE_PLATE_BANDS_HZ", "BASE_PLATE_BANDS") return BASE_PLATE_BANDS raise AttributeError( - f"module 'phonometry.scattering_diffusion' has no attribute {name!r}" + f"module 'phonometry.materials.diffusers.scattering_diffusion' has no attribute {name!r}" ) diff --git a/src/phonometry/materials/surfaces/road_absorption.py b/src/phonometry/materials/surfaces/road_absorption.py index 4bc672066..e287b8ef5 100644 --- a/src/phonometry/materials/surfaces/road_absorption.py +++ b/src/phonometry/materials/surfaces/road_absorption.py @@ -34,7 +34,7 @@ (measured ``alpha`` below ~0.15). Part 2 does not restate the transfer-function / reflection-factor / absorption mathematics; Clauses 4, 5.7 and 6.6 defer it to ISO 10534-2. The core computation therefore lives in - :func:`phonometry.impedance_tube.two_microphone_impedance` and is **not** + :func:`~phonometry.materials.absorbers.impedance_tube.two_microphone_impedance` and is **not** reimplemented here. This module contributes only the Part-2 tube geometry/validity helpers (upper usable frequency, microphone-spacing bounds, the 250-1600 Hz one-third-octave working range) and the Annex A internal-loss @@ -815,7 +815,7 @@ def msa_major_axis( # --------------------------------------------------------------------------- # # ISO 13472-2 spot method: tube geometry / validity helpers. # The core two-microphone DSP is NOT here: see -# phonometry.impedance_tube.two_microphone_impedance (ISO 10534-2, Clause 7). +# phonometry.materials.absorbers.impedance_tube.two_microphone_impedance (ISO 10534-2, Clause 7). # --------------------------------------------------------------------------- # def spot_tube_upper_frequency( diameter: float, speed_of_sound: float = DEFAULT_SPEED_OF_SOUND diff --git a/src/phonometry/psychoacoustics/quality/annoyance.py b/src/phonometry/psychoacoustics/quality/annoyance.py index bee66006f..a127e3741 100644 --- a/src/phonometry/psychoacoustics/quality/annoyance.py +++ b/src/phonometry/psychoacoustics/quality/annoyance.py @@ -173,7 +173,7 @@ def psychoacoustic_annoyance_from_signal( with :func:`psychoacoustic_annoyance`: ``N5`` from the ISO 532-1 Zwicker time-varying loudness, ``S`` from DIN 45692 sharpness, ``R`` from ECMA-418-2 roughness and ``F`` from - :func:`~phonometry.fluctuation_strength.fluctuation_strength`. + :func:`~phonometry.psychoacoustics.quality.fluctuation_strength.fluctuation_strength`. .. note:: This composite mixes model families (Zwicker ``N5``/``S``, Sottek @@ -185,7 +185,7 @@ def psychoacoustic_annoyance_from_signal( ``field`` selects the sound field for the loudness, sharpness and roughness front-ends; the fluctuation strength ``F`` is always computed in the free field, because the Osses 2016 model has no diffuse-field - variant (see :func:`~phonometry.fluctuation_strength.fluctuation_strength`). + variant (see :func:`~phonometry.psychoacoustics.quality.fluctuation_strength.fluctuation_strength`). :param x: Calibrated sound-pressure signal (1-D), in Pa after ``calibration_factor``. diff --git a/src/phonometry/room/image_source.py b/src/phonometry/room/image_source.py index b559d3e81..7db09a113 100644 --- a/src/phonometry/room/image_source.py +++ b/src/phonometry/room/image_source.py @@ -471,7 +471,7 @@ def image_source_rir( neper per metre (scalar or per-band); the pressure amplitude of each path is scaled by :math:`e^{-m r / 2}` (Kuttruff 4.1). Default 0 (air absorption neglected). Obtain a physical ``m`` from - :func:`phonometry.air_absorption.air_attenuation_m`. + :func:`~phonometry.environment.propagation.air_absorption.air_attenuation_m`. :param duration: RIR length, s; default the latest image arrival rounded up to the next sample. :param frequencies: Optional band centre frequencies, Hz, labelling a diff --git a/src/phonometry/room/reverberation_prediction.py b/src/phonometry/room/reverberation_prediction.py index b7fc0d02e..9bde68f88 100644 --- a/src/phonometry/room/reverberation_prediction.py +++ b/src/phonometry/room/reverberation_prediction.py @@ -42,7 +42,7 @@ Air absorption enters every model through the ``air_attenuation`` power coefficient ``m`` (in neper per metre) as the additive term :math:`4 m V`; obtain a physical ``m`` from temperature and humidity with -:func:`phonometry.air_absorption.air_attenuation_m`. +:func:`~phonometry.environment.propagation.air_absorption.air_attenuation_m`. Each model enforces its own mathematical domain on the absorption coefficients. Sabine's linear sum is finite for any non-negative coefficient, @@ -290,7 +290,7 @@ def sabine_reverberation_time( coefficient a scalar or a per-band array in ``[0, 2]``. :param air_attenuation: Air power-attenuation coefficient ``m``, in neper per metre (scalar or per-band); see - :func:`phonometry.air_absorption.air_attenuation_m`. Default ``0`` + :func:`~phonometry.environment.propagation.air_absorption.air_attenuation_m`. Default ``0`` (air absorption neglected). :param speed_of_sound: Speed of sound ``c0``, m/s (default :data:`DEFAULT_SPEED_OF_SOUND`, giving the factor ``0.161``). diff --git a/src/phonometry/speech/sii.py b/src/phonometry/speech/sii.py index eec0b37fe..b180e7add 100644 --- a/src/phonometry/speech/sii.py +++ b/src/phonometry/speech/sii.py @@ -877,4 +877,4 @@ def __getattr__(name: str) -> Any: if name == "BAND_CENTRES": _warn_renamed("BAND_CENTRES", "BAND_CENTERS") return BAND_CENTERS - raise AttributeError(f"module 'phonometry.sii' has no attribute {name!r}") + raise AttributeError(f"module 'phonometry.speech.sii' has no attribute {name!r}") diff --git a/tests/test_deprecated_aliases.py b/tests/test_deprecated_aliases.py index c2580583b..29e1f56a3 100644 --- a/tests/test_deprecated_aliases.py +++ b/tests/test_deprecated_aliases.py @@ -7,8 +7,9 @@ ``"deprecated"`` sentinel). Every alias must warn with the NEP 23 message and delegate to the canonical name. -Two generations coexist, each removed with its own release: the 3.1 renames -and the 3.2 module moves go in 4.0, the 4.0 taxonomy aliases in 5.0. +The 3.2 module moves were removed in 4.0, as announced; what is left here is +the 3.1 function and keyword renames and the 4.0 taxonomy aliases, which go in +5.0. """ from __future__ import annotations @@ -26,26 +27,6 @@ FS = 48_000.0 -# --------------------------------------------------------------------------- # -# Renamed module: phonometry.loudness -> phonometry.loudness_zwicker -# --------------------------------------------------------------------------- # -def test_loudness_module_attribute_access_warns_and_delegates() -> None: - import phonometry.loudness # noqa: F401 (PEP 562 shim; import is silent) - - shim = sys.modules["phonometry.loudness"] - target = sys.modules["phonometry.psychoacoustics.loudness.zwicker"] - with pytest.warns(DeprecationWarning, match=r"loudness\.zwicker"): - cls = shim.ZwickerLoudness - assert cls is target.ZwickerLoudness - with pytest.warns(DeprecationWarning, match="deprecated since phonometry 3.1"): - func = shim.loudness_zwicker - assert func is ph.loudness_zwicker - # __dir__ delegates (and does not warn). - assert "loudness_zwicker_from_spectrum" in dir(shim) - with pytest.raises(AttributeError, match="phonometry.loudness"): - _ = shim.does_not_exist - - # --------------------------------------------------------------------------- # # Legacy snake_case function aliases # --------------------------------------------------------------------------- # @@ -222,7 +203,7 @@ def test_room_volume_explicit_none_stays_silent() -> None: # the package root. # --------------------------------------------------------------------------- # def test_octave_bands_hz_warns_and_delegates() -> None: - from phonometry import absorption_rating + from phonometry.materials.absorbers import rating as absorption_rating with pytest.warns(DeprecationWarning, match="use OCTAVE_BANDS"): legacy = ph.OCTAVE_BANDS_HZ @@ -233,7 +214,7 @@ def test_octave_bands_hz_warns_and_delegates() -> None: def test_third_octave_bands_hz_warns_and_delegates() -> None: - from phonometry import absorption_rating + from phonometry.materials.absorbers import rating as absorption_rating with pytest.warns(DeprecationWarning, match="use THIRD_OCTAVE_BANDS"): legacy = ph.THIRD_OCTAVE_BANDS_HZ @@ -244,7 +225,7 @@ def test_third_octave_bands_hz_warns_and_delegates() -> None: def test_base_plate_bands_hz_warns_and_delegates() -> None: - from phonometry import scattering_diffusion + from phonometry.materials.diffusers import scattering_diffusion with pytest.warns(DeprecationWarning, match="use BASE_PLATE_BANDS"): legacy = ph.BASE_PLATE_BANDS_HZ @@ -255,7 +236,7 @@ def test_base_plate_bands_hz_warns_and_delegates() -> None: def test_band_centres_warns_and_delegates() -> None: - from phonometry import sii + from phonometry.speech import sii with pytest.warns(DeprecationWarning, match="use BAND_CENTERS"): legacy = sii.BAND_CENTRES @@ -263,7 +244,7 @@ def test_band_centres_warns_and_delegates() -> None: def test_exposure_warning_warns_and_delegates() -> None: - from phonometry import occupational_exposure + from phonometry.hearing import occupational_exposure with pytest.warns(DeprecationWarning, match="use OccupationalExposureWarning"): legacy = ph.ExposureWarning @@ -275,124 +256,56 @@ def test_exposure_warning_warns_and_delegates() -> None: def test_renamed_attribute_shims_reject_unknown_names() -> None: - from phonometry import absorption_rating, occupational_exposure + from phonometry.hearing import occupational_exposure + from phonometry.materials.absorbers import rating as absorption_rating with pytest.raises(AttributeError, match="phonometry"): _ = ph.does_not_exist - with pytest.raises(AttributeError, match="absorption_rating"): + with pytest.raises(AttributeError, match="absorbers.rating"): _ = absorption_rating.does_not_exist with pytest.raises(AttributeError, match="occupational_exposure"): _ = occupational_exposure.does_not_exist # --------------------------------------------------------------------------- # -# 3.2 package reorganization: every pre-move public module path must remain -# importable (silently) for one deprecation cycle. Frozen snapshot; do NOT -# regenerate from the live tree (that would defeat its purpose). +# 3.2 package reorganization: its flat module paths were removed in 4.0, as +# announced. A sample of them, frozen; the point is that they stay gone, and +# that a stale file left on disk would be caught rather than silently served. # --------------------------------------------------------------------------- # -_PRE_MOVE_MODULE_PATHS = [ - "phonometry.absorption_rating", - "phonometry.absorption_uncertainty", - "phonometry.air_absorption", - "phonometry.aircraft_atmospheric_absorption", - "phonometry.aircraft_noise", - "phonometry.airflow_resistance", - "phonometry.airport_noise", - "phonometry.building_prediction", - "phonometry.building_uncertainty", - "phonometry.calibration", - "phonometry.compliance", +_REMOVED_FLAT_MODULE_PATHS = [ "phonometry.core", - "phonometry.distortion", - "phonometry.dynamic_stiffness", - "phonometry.enclosed_space_absorption", - "phonometry.environmental", - "phonometry.environmental_measurement", - "phonometry.facade_prediction", - "phonometry.filter_design", - "phonometry.flanking_transmission", - "phonometry.floor_covering_improvement", - "phonometry.fluctuation_strength", - "phonometry.frequencies", - "phonometry.frequency_response", - "phonometry.hearing", - "phonometry.human_vibration", - "phonometry.impedance_tube", - "phonometry.impulse_prominence", - "phonometry.installed_structure_borne", "phonometry.insulation", - "phonometry.intensity", - "phonometry.intensity_insulation", - "phonometry.lab_insulation", "phonometry.levels", "phonometry.loudness", - "phonometry.loudness_contours", - "phonometry.loudness_ecma", - "phonometry.loudness_moore_glasberg", - "phonometry.loudness_moore_glasberg_time", - "phonometry.loudness_zwicker", - "phonometry.mechanical_mobility", - "phonometry.multiple_shock_vibration", - "phonometry.noise_induced_hearing_loss", - "phonometry.numerical_propagation", - "phonometry.occupational_exposure", - "phonometry.ocean_ambient_noise", - "phonometry.open_plan", - "phonometry.outdoor_propagation", - "phonometry.parametric_filters", - "phonometry.pile_driving_noise", - "phonometry._plotting", - "phonometry.psychoacoustic_annoyance", - "phonometry.reverberation_prediction", - "phonometry.road_absorption", - "phonometry.room_acoustics", "phonometry.room_ir", - "phonometry.room_noise", - "phonometry.rotorcraft_noise", - "phonometry.roughness_ecma", - "phonometry.scattering_diffusion", - "phonometry.seabed_reflection", - "phonometry.sharpness", - "phonometry.ship_radiated_noise", - "phonometry.ship_traffic_noise", - "phonometry.sii", - "phonometry.sonar_equation", - "phonometry.sound_absorption", - "phonometry.sound_power", - "phonometry.sound_power_intensity", - "phonometry.sound_power_reverberation", - "phonometry.sti", - "phonometry.structure_borne_power", - "phonometry.survey_insulation", - "phonometry.tonality", - "phonometry.tonality_ecma", - "phonometry.tone_audibility", - "phonometry.transfer_stiffness", - "phonometry.uncertainty", "phonometry.underwater_acoustics", - "phonometry.underwater_propagation", - "phonometry.underwater_sound_speed", "phonometry.utils", - "phonometry.vibration_sound_power", - "phonometry._warnings", - "phonometry.wind_turbine_noise", ] -@pytest.mark.parametrize("path", _PRE_MOVE_MODULE_PATHS) -def test_pre_move_module_path_still_imports(path: str) -> None: +def test_pre_split_module_alias_rejects_unknown_names() -> None: + """A 4.0 alias serves what its target has, and nothing else. + + The alias delegates by ``getattr`` on the relocated module, so a typo has + to come back as an ``AttributeError`` naming the path the caller wrote, + not as a silent ``None`` or a confusing message about the new module. + """ import importlib - import warnings - with warnings.catch_warnings(): - warnings.simplefilter("error", DeprecationWarning) - module = importlib.import_module(path) # import itself must be silent - assert module is sys.modules[path] - # A shim that imports but exposes nothing is as broken as an ImportError: - # every pre-move path must still surface its public names. ``dir()`` is - # silent on the PEP 562 shims, so this stays warning-free. - public = [name for name in dir(module) if not name.startswith("_")] - assert public, f"{path} imports but exposes no public names" + shim = importlib.import_module("phonometry.metrology.levels") + with pytest.raises(AttributeError, match="phonometry.metrology.levels"): + _ = shim.does_not_exist + + +@pytest.mark.parametrize("path", _REMOVED_FLAT_MODULE_PATHS) +def test_removed_flat_module_path_raises(path: str) -> None: + import importlib + + with pytest.raises(ModuleNotFoundError): + importlib.import_module(path) + assert path not in sys.modules + # The names themselves never moved: the flat API is what they were for. + assert hasattr(ph, "leq") # --------------------------------------------------------------------------- # @@ -535,7 +448,7 @@ def test_the_migration_table_names_real_aliases() -> None: import importlib import re - from phonometry._compat import _MOVED_3X, _MOVED_4X + from phonometry._compat import _MOVED_4X table = ( pathlib.Path(__file__).resolve().parent.parent @@ -554,10 +467,10 @@ def test_the_migration_table_names_real_aliases() -> None: f"no example row for {sorted(moved_from - documented)}" ) for old, new, removed_in in rows: - generation = _MOVED_3X if removed_in == "4.0" else _MOVED_4X - assert old in generation, f"{old} is not a deprecated path of {removed_in}" - assert generation[old] == new, ( - f"{old} resolves to {generation[old]}, not to {new}" + assert removed_in == "5.0", f"{old} names a removal that already happened" + assert old in _MOVED_4X, f"{old} is not a deprecated path" + assert _MOVED_4X[old] == new, ( + f"{old} resolves to {_MOVED_4X[old]}, not to {new}" ) importlib.import_module(new) @@ -797,9 +710,9 @@ def test_plotting_shim_re_exports_every_renderer() -> None: def test_moved_module_shims_warn_and_delegate() -> None: import importlib - from phonometry._compat import _MOVED_3X, _MOVED_4X + from phonometry._compat import _MOVED_4X - for old, new in {**_MOVED_3X, **_MOVED_4X}.items(): + for old, new in _MOVED_4X.items(): shim = importlib.import_module(old) target = importlib.import_module(new) public = [n for n in dir(target) if not n.startswith("_")] diff --git a/tests/test_utils.py b/tests/test_utils.py index 872d7756a..f5bea124b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,7 +4,8 @@ """ import numpy as np -from phonometry.utils import _resample_to_length, _typesignal + +from phonometry._internal.utils import _resample_to_length, _typesignal def test_typesignal_converts_int_arrays_to_float64() -> None: