Repository navigation
A wrong type raises TypeError, a missing key KeyError, and every warning is a PhonometryWarning you can filter by topic - #979
Conversation
|
Important Review skippedToo many files! This PR contains 377 files, which is 277 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configuration
⛔ Files ignored due to path filters: 1
📒 Files selected for processing: 377
You can disable this status message by setting the
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
08cc45d to
babc6f7
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## fix/records-instead-of-tuples #979 +/- ##
================================================================
Coverage ? 92.02%
================================================================
Files ? 446
Lines ? 91127
Branches ? 0
================================================================
Hits ? 83862
Misses ? 7265
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Numerical conformance1893/1893 checks pass across 111 domains and 523 standards (227 normative designations, 125 further published sources). Used in the tables below is how much of that clause's published tolerance the deviation consumes: 100 % sits exactly on the limit, 5 % uses a twentieth of the allowance, and a dash means the clause states no two-sided tolerance for the quantity, so there is no budget to spend. It is reported and never used to decide a verdict, which is settled at full precision before any rounding. Renamed (4)
Closest to their published limit (top 5) The rows with the least room left, so the ones a change is most likely to push over.
|
…ing is a PhonometryWarning you can filter by topic The Python documentation draws the line between the two refusals a guard raises: `TypeError` is "raised when an operation or function is applied to an object of inappropriate type", and `ValueError` "when an operation or function receives an argument that has the right type but an inappropriate value". The library had it both ways. Seventy-six refusals asked an argument for its type and raised `ValueError`, nine of them behind a `# noqa: TRY004` that said so on purpose; thirty-two handlers caught a `TypeError` and raised it again as a `ValueError`; a few others raised `TypeError` for the same mistake; and about ninety parameters written as an `int` went through `int()` alone, which truncated `2.5` to `2` and took `True` as `1` without a word. A lookup that missed raised `KeyError` in one result and `ValueError` in the next for the same kind of question. And the promise the root makes, that one `filterwarnings` rule on `PhonometryWarning` reaches every advisory, did not hold: `RoadDeviceWarning` derived from `UserWarning` alone, seven calls warned as a plain `UserWarning` (two naming no class at all), and five as the bare root, so none of them could be silenced or escalated without every other advisory too.
babc6f7 to
25453c2
Compare
[Medium impact] Renames exception types and warning classes across the library. Fix stored source indices before merging; newly accepted whole floats currently crash simulations. Findings
Reviews (1) · Last reviewed commit: "A wrong type raises TypeError, a missing..." · Reviewed by Greptile |
| :class:`ValueError` for a number that is not whole. The bound each one | ||
| has is checked where it is read. | ||
| """ | ||
| return require_count(value, name, at_least=None) |
There was a problem hiding this comment.
Accepted sources crash when stepped
_integer now accepts whole floats, but source registration discards the converted indices and stores the original source. For example, GaussianPulse(ix=2.0, iy=3, half_width_s=1e-4) passes FDTD2D.add_source, then run(1) raises IndexError when step indexes self.p with src.ix. The same problem affects PlaneWaveSource.offset and elastic sources.
Store the converted integers before registering each source, and test that whole-float indices can complete a step.
There was a problem hiding this comment.
Fixed in #992, commit f1f5f18. Every source record holds its cell indices (and the plane wave its offset) as the ints they name when it is built, and refuses a half cell there. Tests over the six source types run a whole-float index through a step. The CuPy proof was re-run on the GPU in f043e3c: fields and phasors bit-identical, only the engine fingerprint moved.
|



The Python documentation draws the line between the two refusals a guard raises:
TypeErroris "raised when an operation or function is applied to an object of inappropriate type", andValueError"when an operation or function receives an argument that has the right type but an inappropriate value". The library had it both ways. Seventy-six refusals asked an argument for its type and raisedValueError, nine of them behind a# noqa: TRY004that said so on purpose; thirty-two handlers caught aTypeErrorand raised it again as aValueError; a few others raisedTypeErrorfor the same mistake; and about ninety parameters written as anintwent throughint()alone, which truncated2.5to2and tookTrueas1without a word. A lookup that missed raisedKeyErrorin one result andValueErrorin the next for the same kind of question. And the promise the root makes, that onefilterwarningsrule onPhonometryWarningreaches every advisory, did not hold:RoadDeviceWarningderived fromUserWarningalone, seven calls warned as a plainUserWarning(two naming no class at all), and five as the bare root, so none of them could be silenced or escalated without every other advisory too.What changes
A wrong type is a
TypeError, a right type with a wrong value aValueError. An array,Noneor an object that is not a number where one number belongs, a complex value where a real one does, an array of the wrong dtype (a mask that is not boolean, counts that are not integers), a bool where a count or a flag does, a number where a pair or a sequence does, a choice among named options given as something other than a text, and an object of the wrong class now raiseTypeError, naming the parameter. A text is the wrong type wherever a number belongs, whatever it reads as:"20"and"fifty"are both aTypeError, given alone or in an array, where one guard used to parse the first into a number and the next refused it as a value. A count that is not whole or is too small, an empty name, a choice that names none of the options and a value out of range stayValueError. Mixed conditions (if not isinstance(n, int) or n < 1) are two refusals, and a handler that rewords a refusal keeps its class. Every public function that raisesTypeErrorsays so under:raises TypeError:, so the API reference names the class a call raises.Every whole number goes through one check.
require_countreads every parameter written as anint: a whole float such as5.0is taken as5, a fraction is aValueError, and a bool, a text or an array is aTypeError. That coversstory_fundamental_frequency(n_stories),n_events=of the sound energy functions and results, uncertaintyn,oversample=, the FDTD grid indices and step counts,max_order=,n_level_ranges=,duration_days=and theReportMetadataposition counts, and alsosignals.window_metrics(window, n),n_points=ofsignals.zoom_fft(which truncated100.6to 100 points),oversample=ofsignals.min_phase,n_segments=ofmetrology.stationarity_test,n_harmonics=ofelectroacoustics.swept_sine_distortion, the step and arrival counts of theunderwaterray and mode solvers and the machinery diagnostics counts. The two private copies of the count check innoise_controlandvibration.machineryare gone, and so are the nine TRY004 suppressions, the one inscripts/fdtd_gpu.pyand the one inscripts/generate_api_docs.py.A band set, a window of record indices and a spectrogram channel are read by their type too.
fraction=, wherever a band set is chosen, refuses a word, a flag, a float orNonewithTypeErrorand an integer other than 1 or 3 withValueError.aircraft.EPNLIntegrationrefusesband_limitsthat are not whole record indices withTypeErrorand a window that is not a pair withValueError.OctaveSpectrogramResult.plot(channel=...)reads the channel throughrequire_count, sochannel=1.0draws channel 1,channel=1.5is aValueErrorandchannel=TrueaTypeError.filters.WeightingFilterdocuments theTypeErrorit raises forhigh_accuracy=None, andbuilding.RequirementConformitynames each of its three levels to the shared guard before it compares them.Three things stay
ValueErroron purpose, named as exemptions: the sidecar payload parser andCalibrationSidecar's own checks (a field of the wrong type in a file is a malformed file, and the refusal names the file), andCatalogueErrorcells.A guard that only compared a parameter written as one number (
if volume <= 0: raise, or a lookup that returns the row whose frequency matches and raises after the loop, aspsychoacoustics.loudness_leveldid) took a one-element array as its element and answered a longer one with numpy's anonymous "truth value is ambiguous". The 361 functions and dataclass fields with such a guard now ask the rank first, throughrequire_scalar, and so do the 104 public parameters that a call with an array still reached because the comparison sat in one function and the conversion in another (environment.lden,aircraft.noise_fraction,fluids.air(temperature_c=...),vibration.injury_risk(start_age=...)).aircraft.rotorcraft_event_levelrefuses a ground that holds an array for a single receiver withTypeError.A lookup that misses a key raises
KeyError; a number outside what a result covers raisesValueError.RegulationLimits["noon"]raisesKeyError, as a mapping does, and the key is matched exactly, as a mapping matches it:limits["Day"]andlimits[" night "], which were read as"day"and"night", raiseKeyErrortoo. The period ofenvironment.PeriodAssessment, a choice, keeps itsValueError.TrackDecayRate.rate_at,AcousticRoughnessSpectrum.level_atand the class branch ofFilterComplianceResult.binding_marginraiseValueError; a requirement the verdict did not grade stays aKeyError. The selectors of a plot (FilterComplianceResult.plot(requirement=...),BinauralIndicators.plot(parameter=...)) are choices and keepValueError.materials.ResilientLayer.natural_frequencyraisesValueErrorfor a row it cannot rate, asCatalogueRow.printeddoes, instead ofio.CatalogueError, on both refusals: a row without an airflow resistivity and a row whose s't cell holds only a declared bound.Every warning is a
PhonometryWarningwith a topic.environment.RoadDeviceWarningjoins the hierarchy, and its docstring says that the absorption ratio warns when it reaches 0,99 and the reflection ratio only above it.environment.BarrierInSituWarningnow says what it warns on, in its docstring and its row of the API reference: the NOTE to ISO 10847 7.2.2 thatreference_microphone_height_mcannot follow once the barrier top stands 80° or more above the near end of the source region, and receiver types that differ between the two campaigns ofmeasured_insertion_loss_indirect, which the NOTE to 8.2.2 advises against; the row named a distance past 250 m and three other conditions no code warns on. New topics:building.BuildingPredictionWarning(the extrapolations ofequivalent_impact_level,weighted_lining_improvementandlining_improvement),room.NoiseCriterionWarning(room_criterionon a spectrum missing a band),aircraft.FlightProfileWarning(the Doc 29 B7.1.4 altitude mismatches ofapproach_profile),signals.ToneBurstWarningandunderwater.NumericalPropagationWarning(normal_modes,eigenrays,gaussian_beams). The ISO 15186-1 element count emitsbuilding.LaboratoryInsulationWarning, and the filter bank's low sampling rate emitsfilters.FilterBankWarning, which moves to a module of its own so the band calculation can import it without the filter core; the pytest filter inpyproject.tomlnames it.vibration.evaluate_train_passagesilenced everyUserWarningwhile it built its third-octave bank and now silences only theFilterBankWarningit means, and four docstrings that listed a warning under:raiseslist it under:warns, so the API reference shows it in its own table by name. Each topic is still aUserWarning, so a filter on that class still matches. The topic guides (room noise, insulation prediction, speech transmission, getting started) name the topic class to filter on, and the notebook check in CI waits for theFilterBankWarningits warning cell provokes.aircraft.approach_profilewarns for both cases Doc 29 asks it to. ECAC Doc 29 5th edition, Volume 2, B7.1.4 (PDF pages 115 and 116, folios B-42 and B-43) asks the system to warn the user when a Level-Idle step starts at another altitude than the step after it, in Case 1 (a following Level-Idle step) and in Case 2 (any following step but Descend-Idle). Only Case 1 was checked. Both emitFlightProfileWarningnow, and the start CAS note of each case, which the clause states without asking for a warning, is reported with it as a consistency note.fluids.FluidPropertyUnavailableisfluids.FluidPropertyUnavailableError, still anAttributeError, sohasattrandgetattrwith a default behave as before.The survey grade of ISO 3746 serves its own positions for one, two and three planes.
emission.measurement_positions("hemisphere", ..., n_reflecting_planes=3, grade="survey")raisedNotImplementedError, and over one plane the survey grade returned positions 4, 5, 6 and 10 of ISO 3744 Table B.1, the array for a source with tones, so the four microphones sat at the wrong points. ISO 3746:2010 clause 8.2.1 takes them from its own tables, and both are now held as printed, as private read-only tables: Table B.1 (BS EN ISO 3746:2010, PDF page 34, printed folio 25), whose positions 4, 5, 6 and 10 are the broadband positions of the same numbers in ISO 3744 Table B.2, serves one plane, whatevertonessays, since ISO 3746 has one array; Table B.2 (PDF page 35, printed folio 26) serves positions 14, 15 and 18 for two planes (the same values as before) and 14, 21 and 22 for three. The docstring and the guide name the 3 m least radius the annex sets beside two or three planes, and say thatplot_microphone_positionsnumbers the points 1 to N rather than with the standard's position numbers.scripts/check_boundary_comparisons.pyfollowed a public parameter rebound to a value computed from itself (levels = np.asarray(levels)) as an opaque cycle and lost the comparison; it now reads the parameter the caller passed, and the comparisons that surfaced are settled with a reason each.CONTRIBUTING states the rules: the class of a refusal (citing the Python documentation), a text and a whole number by type, what a lookup that misses raises beside the judgement verbs,
<Topic>Warningand<Topic>Errorin the naming table. The migration guide (EN, site EN, site ES) lists every public call whose exception or warning class changed in 3.3.0 or 4.0.0rc1; the lookups that are newer than 4.0.0rc1 are in the CHANGELOG only.What breaks
Code that caught
ValueErrorto absorb any bad input should catch(TypeError, ValueError). A number given as a text ("5") is refused withTypeErrorwhere some guards used to parse it; pass a number. A fractional count is aValueErrorwhere it was truncated, and a bool count aTypeError.RegulationLimits[...]callers catchingValueErrorcatchKeyError, and pass the period in lower case.rate_at,level_atandbinding_marginclass callers catchingKeyErrorcatchValueError.fluids.FluidPropertyUnavailableis gone. A band set given as a word, a flag or a float (fraction="third",fraction=True,fraction=3.0) is aTypeError, where it was aValueError. The one-plane survey positions ofemission.measurement_positionschanged coordinates. A filter onUserWarningstill matches every warning that changed class.Guards, red before and green here
tests/test_error_kinds.pyreadssrcfor every shape a type refusal takes (anifthat asks only a type, dtype or rank question,np.isscalar,np.isrealobjandnp.issubdtypeincluded; anorjoining one to a value test; a chain of type dispatches falling through to a raise; anexcept TypeErrorthat raises another class) and fails on each that raises anything butTypeError, with the exemptions keyed by function and reason. It also fails on a parameter written as anintread throughint()withoutrequire_count, and on a public function that raisesTypeErrorwithout a:raises TypeError:field. Red on fc71c2180:and, for the three rules added on top, red on d1b0a9131, the commit before them:
tests/test_scalar_guards.py(compared_without_rank), red on fc71c2180 with 325 guards, and on d1b0a9131 with 36 more once it reads a comparison that returns before a raise and a comparison insideabs()or a difference:tests/test_scalar_guards.py::test_every_public_scalar_parameter_refuses_an_array_or_a_text_by_namecalls every public function whose parameters all take one number with a one-element array, a two-element array, the text of its number and a word in each parameter, and requires aTypeErrorthat names the parameter. Red on d1b0a9131 with 1967 cases:The same two files, run on the code that arrived beside these rules (the band set of
fraction=, the EPNL integration record, the spectrogram plot,WeightingFilter.high_accuracyandRequirementConformity), red with these rules applied over 075ac5e and before the fixes:tests/test_package_architecture.py, red on fc71c2180:tests/test_check_boundary_comparisons.py::test_a_parameter_rebound_to_a_value_of_itself_keeps_the_caller_value, red on fc71c2180:The value tests read the printed pages: ISO 3746:2010 Tables B.1 and B.2 (BS EN ISO 3746:2010, PDF pages 34 and 35, folios 25 and 26) pin the four one-plane survey rows, the two-plane and the three-plane rows times the radius; ISO 3744:2010 Table B.2 (BS EN ISO 3744:2010, PDF page 47, folio 38) prints the same four broadband positions. Doc 29 Volume 2, B-42 and B-43, gives the two altitude cases the new
approach_profiletests build. A mutation that raisesCatalogueErrorfrom the bounded s't refusal ofResilientLayer.natural_frequencynow fails its test.Gates
ruff check .,ruff format --check .: clean.mypy src scripts: no issues in 701 source files.bandit -q -r src: exit 0.pytest -q -n 8 tests/, Python 3.13): 29007 passed, 69 skipped.scripts/check_doc_snippets.py: 7565 blocks over 732 pages pass.pnpm install --frozen-lockfile,check:types(0 errors),buildandhtml-validate: green.scripts/check_notebook.pyon a real ipykernel: every tagged cell reads as it should, the warning cell with itsFilterBankWarning.make conformance: 1893/1893, no drift.make api-docs,make llmsand the site evidence pages: no drift;check_api_reference.pycovers all 3082 public names.check_frozen_constants,check_parameter_units,check_published_sources,check_em_dashes,check_digit_grouping,check_markdown_hazards,check_errata_evidence,check_spanish_accents,check_boundary_comparisons,check_raises_blocks,check_dead_constants,check_identifier_spelling,check_record_displayand the rest ofscripts/check_*.py: all pass.check_animation_freshnessreports onlyanim_epnl_flyover, stale with the same fingerprint on the base; this branch moves no clip.