From f6a78e24c24291f6c3905a0d5e34c25882aeeb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 07:08:59 +0200 Subject: [PATCH 1/3] Remove the pre-3.2 module paths, as 3.2 announced The flat module paths that the modularization grouped into domain subpackages were deprecated in 3.2 with 4.0 named as their removal, and phonometry.loudness since 3.1. They are gone, so _compat carries one table and the alias machinery drops the per-entry wording overrides that only the 3.1 entries needed. The flat API is untouched: from phonometry import leq reads the same. What the audit found on the way out is fixed too: fifteen docstring cross-references and one test import still named a path that only the table kept alive, and the documentation generator no longer has to alias the flat names. --- CHANGELOG.md | 16 ++ docs/api-reference.md | 11 +- llms-full.txt | 11 +- scripts/generate_api_docs.py | 29 --- .../aeroacoustics/atmospheric-absorption.md | 2 +- .../api/electroacoustics/swept-sine.md | 2 +- .../api/environment/air-absorption.md | 4 +- .../api/environment/outdoor-propagation.md | 2 +- .../api/materials/road-absorption.md | 2 +- .../docs/reference/api/rooms/acoustics.md | 2 +- .../docs/reference/api/rooms/image-source.md | 2 +- .../api/rooms/reverberation-prediction.md | 4 +- .../docs/reference/api/signals/inversion.md | 2 +- .../docs/reference/api/signals/phase.md | 2 +- src/phonometry/_compat.py | 165 ++---------------- .../aircraft/atmospheric_absorption.py | 2 +- .../building/measurement/uncertainty.py | 2 +- .../environment/propagation/air_absorption.py | 10 +- .../propagation/outdoor_propagation.py | 2 +- .../environment/sources/wind_turbine.py | 2 +- .../hearing/occupational_exposure.py | 2 +- src/phonometry/materials/absorbers/rating.py | 2 +- .../diffusers/scattering_diffusion.py | 2 +- .../materials/surfaces/road_absorption.py | 4 +- .../psychoacoustics/quality/annoyance.py | 4 +- src/phonometry/room/image_source.py | 2 +- .../room/reverberation_prediction.py | 4 +- src/phonometry/speech/sii.py | 2 +- tests/test_deprecated_aliases.py | 164 ++--------------- tests/test_utils.py | 3 +- 30 files changed, 96 insertions(+), 367 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31d1a1ff5..2d5b58ac2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1864,6 +1864,22 @@ 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 + ninety-odd siblings that the modularization grouped into domain subpackages + raise `ModuleNotFoundError` now, as does `phonometry.loudness`, deprecated + since 3.1. The flat API they were reached through is untouched: + `from phonometry import leq` reads the same as it always has, and so does + every other name in `phonometry.__all__`. Only the module paths are gone, + and only the generation whose removal this release was named for: the 4.0 + taxonomy aliases stay 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..940c28fdc 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 [`phonometry.environment.propagation.air_absorption.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..0e8b365b0 100644 --- a/site/src/content/docs/reference/api/environment/air-absorption.md +++ b/site/src/content/docs/reference/api/environment/air-absorption.md @@ -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) / +[`phonometry.materials.absorbers.sound_absorption.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 [`phonometry.materials.absorbers.sound_absorption.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..0d5e7eabe 100644 --- a/site/src/content/docs/reference/api/environment/outdoor-propagation.md +++ b/site/src/content/docs/reference/api/environment/outdoor-propagation.md @@ -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 [`phonometry.environment.propagation.air_absorption.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/materials/road-absorption.md b/site/src/content/docs/reference/api/materials/road-absorption.md index 25fc3f7f9..7d77b7023 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** + [`phonometry.materials.absorbers.impedance_tube.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..412451672 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 [`phonometry.environment.propagation.air_absorption.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..583443d69 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). +[`phonometry.environment.propagation.air_absorption.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 [`phonometry.environment.propagation.air_absorption.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/_compat.py b/src/phonometry/_compat.py index 2678f8bfd..a02f505bc 100644 --- a/src/phonometry/_compat.py +++ b/src/phonometry/_compat.py @@ -1,20 +1,19 @@ # 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 ninety-odd siblings raise ``ModuleNotFoundError`` now. The flat API +they were reached through, ``from phonometry import leq``, never moved. Every public module path that moved stays importable through the shims registered here: ``import phonometry.`` and ``from phonometry. @@ -27,9 +26,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 +38,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 +236,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 +275,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 diff --git a/src/phonometry/aircraft/atmospheric_absorption.py b/src/phonometry/aircraft/atmospheric_absorption.py index 5037bb0d9..56678e120 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..933264e13 100644 --- a/src/phonometry/environment/propagation/air_absorption.py +++ b/src/phonometry/environment/propagation/air_absorption.py @@ -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..0acae0352 100644 --- a/src/phonometry/environment/propagation/outdoor_propagation.py +++ b/src/phonometry/environment/propagation/outdoor_propagation.py @@ -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..95c0ce33f 100644 --- a/src/phonometry/environment/sources/wind_turbine.py +++ b/src/phonometry/environment/sources/wind_turbine.py @@ -18,7 +18,7 @@ :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. """ 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..7b89fdd3d 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..82bed2d46 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..490f9a3c1 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..8165d9076 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,126 +256,17 @@ 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). -# --------------------------------------------------------------------------- # -_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", - "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: - 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" - - # --------------------------------------------------------------------------- # # 4.0 taxonomy: metrology split into filters + signals + a narrowed metrology, # and the speech intelligibility of hearing into speech. @@ -535,7 +407,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 +426,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 +669,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: From 72096c93dbb6d26471fdd5288421ca94907869f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 07:27:20 +0200 Subject: [PATCH 2/3] Assert the removed flat paths stay removed --- tests/test_deprecated_aliases.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/test_deprecated_aliases.py b/tests/test_deprecated_aliases.py index 8165d9076..c6d9afac5 100644 --- a/tests/test_deprecated_aliases.py +++ b/tests/test_deprecated_aliases.py @@ -267,6 +267,33 @@ def test_renamed_attribute_shims_reject_unknown_names() -> None: _ = occupational_exposure.does_not_exist +# --------------------------------------------------------------------------- # +# 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. +# --------------------------------------------------------------------------- # +_REMOVED_FLAT_MODULE_PATHS = [ + "phonometry.core", + "phonometry.insulation", + "phonometry.levels", + "phonometry.loudness", + "phonometry.room_ir", + "phonometry.underwater_acoustics", + "phonometry.utils", +] + + +@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") + + # --------------------------------------------------------------------------- # # 4.0 taxonomy: metrology split into filters + signals + a narrowed metrology, # and the speech intelligibility of hearing into speech. From 28d044c52e14090d283fd348eb1edd782bbb4644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20M=2E=20Requena=20Plens?= Date: Mon, 3 Aug 2026 07:43:05 +0200 Subject: [PATCH 3/3] Answer the review of the compatibility cleanup The comment that introduces _compat still named the generation this release removes, the example in the install loop was itself a removed path, and the count was rounded the wrong way: the table held eighty-two paths. The pickle note says which pickles still resolve, an alias that never existed in either table now names the module it meant, and the alias shim keeps a test for the attribute it refuses. --- CHANGELOG.md | 15 +++++++++------ .../api/aeroacoustics/atmospheric-absorption.md | 2 +- .../reference/api/environment/air-absorption.md | 6 +++--- .../api/environment/outdoor-propagation.md | 4 ++-- .../reference/api/environment/wind-turbine.md | 4 ++-- .../reference/api/materials/road-absorption.md | 2 +- .../docs/reference/api/rooms/image-source.md | 2 +- .../api/rooms/reverberation-prediction.md | 4 ++-- src/phonometry/__init__.py | 6 +++--- src/phonometry/_compat.py | 11 ++++++----- src/phonometry/_plot/psychoacoustics.py | 4 ++-- src/phonometry/aircraft/atmospheric_absorption.py | 2 +- .../environment/propagation/air_absorption.py | 6 +++--- .../propagation/outdoor_propagation.py | 4 ++-- .../environment/sources/wind_turbine.py | 4 ++-- .../materials/surfaces/road_absorption.py | 2 +- src/phonometry/room/image_source.py | 2 +- src/phonometry/room/reverberation_prediction.py | 4 ++-- tests/test_deprecated_aliases.py | 14 ++++++++++++++ 19 files changed, 58 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d5b58ac2..408bb055e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1868,13 +1868,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/). - The flat pre-3.2 module paths, as 3.2 announced when it deprecated them: `phonometry.levels`, `phonometry.insulation`, `phonometry.room_ir` and the - ninety-odd siblings that the modularization grouped into domain subpackages + eighty-odd siblings that the modularization grouped into domain subpackages raise `ModuleNotFoundError` now, as does `phonometry.loudness`, deprecated - since 3.1. The flat API they were reached through is untouched: - `from phonometry import leq` reads the same as it always has, and so does - every other name in `phonometry.__all__`. Only the module paths are gone, - and only the generation whose removal this release was named for: the 4.0 - taxonomy aliases stay until 5.0. + 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 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 940c28fdc..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.environment.propagation.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/environment/air-absorption.md b/site/src/content/docs/reference/api/environment/air-absorption.md index 0e8b365b0..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.materials.absorbers.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.materials.absorbers.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 0d5e7eabe..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.environment.propagation.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 7d77b7023..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.materials.absorbers.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/image-source.md b/site/src/content/docs/reference/api/rooms/image-source.md index 412451672..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.environment.propagation.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 583443d69..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.environment.propagation.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.environment.propagation.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/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 a02f505bc..10bc9beef 100644 --- a/src/phonometry/_compat.py +++ b/src/phonometry/_compat.py @@ -12,8 +12,9 @@ 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 ninety-odd siblings raise ``ModuleNotFoundError`` now. The flat API -they were reached through, ``from phonometry import leq``, never moved. +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. @@ -412,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 56678e120..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.environment.propagation.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/environment/propagation/air_absorption.py b/src/phonometry/environment/propagation/air_absorption.py index 933264e13..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,7 +223,7 @@ 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.materials.absorbers.sound_absorption.absorption_area` / + :func:`~phonometry.materials.absorbers.sound_absorption.absorption_area` / :func:`~phonometry.materials.absorbers.sound_absorption.absorption_coefficient`. """ freqs = np.asarray(frequencies, dtype=np.float64) @@ -266,7 +266,7 @@ 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.materials.absorbers.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.materials.absorbers.sound_absorption.absorption_area` / :func:`~phonometry.materials.absorbers.sound_absorption.absorption_coefficient` instead of diff --git a/src/phonometry/environment/propagation/outdoor_propagation.py b/src/phonometry/environment/propagation/outdoor_propagation.py index 0acae0352..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.environment.propagation.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 95c0ce33f..2628a0c9a 100644 --- a/src/phonometry/environment/sources/wind_turbine.py +++ b/src/phonometry/environment/sources/wind_turbine.py @@ -15,7 +15,7 @@ ``Δ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.environment.assessment.measurement.tonal_adjustment`. The @@ -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/materials/surfaces/road_absorption.py b/src/phonometry/materials/surfaces/road_absorption.py index 7b89fdd3d..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.materials.absorbers.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 diff --git a/src/phonometry/room/image_source.py b/src/phonometry/room/image_source.py index 82bed2d46..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.environment.propagation.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 490f9a3c1..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.environment.propagation.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.environment.propagation.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/tests/test_deprecated_aliases.py b/tests/test_deprecated_aliases.py index c6d9afac5..29e1f56a3 100644 --- a/tests/test_deprecated_aliases.py +++ b/tests/test_deprecated_aliases.py @@ -283,6 +283,20 @@ def test_renamed_attribute_shims_reject_unknown_names() -> 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 + + 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