Map HTTP failures to real exceptions, and make DRI lookups honest#11
Merged
Conversation
The follow-up to the v0.1.11 fixes. Same theme: APIs that were documented but not implemented, and comparisons made against the wrong scale. Errors: - FdcApiError and its subclasses now carry status_code. The docs have long told callers to branch on it, with a retry-on-5xx example that could never have run: nothing set the attribute, so hasattr() was always False. - An invalid API key raised a nondescript FdcApiError. FDC sits behind api.data.gov, which answers a bad key with 403 while only 401 was mapped, so the commonest caller mistake missed FdcAuthError entirely. - 404 now raises FdcResourceNotFoundError and 400 raises FdcValidationError. Both classes were defined, documented, and raised by nothing. A food that does not exist is an ordinary outcome of a lookup, not a breakdown. DRI: - Only DriType.RDA ever returned data. ul.json ships real upper limits under a different schema than get_dri could read, so every UL lookup was None. Both schemas are now understood. AI/EAR/AMDR ship no data and still return None, but say so once in a warning instead of leaving the column blank. - DRI percentages ignored units, and the data does not use one scale: iron's RDA is 8 mg, its UL is 0.045 g. Spinach against iron's upper limit reported 2802% of it rather than 2.8%. Amounts are now converted into the DRI's unit first, and an incomparable pair (vitamin A in IU against a µg allowance) yields no percentage instead of a confident wrong one. Verified against the live API; the 30 new tests do not even import on main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014avzoF5VnrUxwoy7m1aK6K
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The follow-up to v0.1.11 (issues #4 and #5 from the review), plus one more bug found on the way. Same theme throughout: APIs that were documented but never implemented, and numbers compared against the wrong scale.
Verified against the live FDC API. The 30 new tests do not even import on
main— the functions and exports they use don't exist there.Errors
status_codenever existed.docs/user/error_handling.rsttells callers to branch one.status_code, and ships a retry-on-5xx example built around it. Nothing ever set the attribute, sohasattr(e, 'status_code')was alwaysFalseand that retry loop could never fire. EveryFdcApiErrornow carries it, and it isNonefor failures that never reached the API (refused connection, timeout) — itself worth knowing.An invalid API key was a mystery. FDC sits behind api.data.gov, which rejects a bad key with 403, not 401 — and only 401 was mapped. So the single most common mistake a caller can make surfaced as a nondescript
FdcApiError. Confirmed against the live API:FdcApiErrorFdcAuthErrorFdcApiErrorFdcResourceNotFoundErrorpage_size=99999FdcApiErrorFdcValidationErrorFdcResourceNotFoundErrorandFdcValidationErrorhad been defined, documented, and raised by nothing. They are now also exported from the package root, which they never were. Everything still derives fromFdcApiError, so a broadexcept FdcApiErrorkeeps working.DRI
Only
DriType.RDAever returned data.ul.jsonships real Tolerable Upper Intake Levels, but under a different schema thanget_driknew how to read, so every UL lookup came backNone. Both schemas are now understood.AI,EARandAMDRship no data at all — they still returnNone, but log a warning once saying so, rather than leaving an unexplained empty column. The docs claimed data for all five types; they now say which two are real.DRI percentages ignored units — and the data does not use one scale. Iron's RDA is
8mg; its UL is0.045g. The percentage was a bare division, so 100g of spinach measured against iron's upper limit reported:Amounts are now converted into the DRI's own unit first. Where the two cannot be compared at all — vitamin A in IU against a µg allowance —
dri_percentisNonerather than a confident wrong number. Newget_dri_valuereturns the unit alongside the value so this can't be got wrong again;get_dristill returns the bare number for existing callers.Tests
30 new tests, in
tests/unit/test_error_mapping.pyandtests/unit/test_dri.py:status_codeis carried on all of them and isNonewhen the request never reached the API; a bad key is an auth error; the documented 5xx retry is actually reachable; everything is still catchable asFdcApiError.None; RDA percentages use the RDA's unit; a gram-denominated UL is not compared against milligrams; IU yields no percentage;get_dristill returns a bare number; age/gender still select the right RDA (iron: 18 mg for women 19–50, 8 mg after).Full suite: 87 passed, 8 skipped. Both docs examples I touched were executed rather than assumed.
🤖 Generated with Claude Code
https://claude.ai/code/session_014avzoF5VnrUxwoy7m1aK6K