fix: attribute save_to_* deprecation to caller - #1346
Open
davidberenstein1957 wants to merge 2 commits into
Open
fix: attribute save_to_* deprecation to caller#1346davidberenstein1957 wants to merge 2 commits into
davidberenstein1957 wants to merge 2 commits into
Conversation
The warning was emitted with stacklevel=2 from _resolve_output_methods, which points at BaseEmissionsTracker.__init__ itself, so Python's default ignore::DeprecationWarning filter dropped it for every caller outside __main__. Compute the stack level dynamically instead, which also handles the extra frames added by OfflineEmissionsTracker and the @Suppress decorator. Migrate the CLI's own call sites to output_methods= so codecarbon no longer trips its own deprecation check. Closes #1323 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1346 +/- ##
==========================================
+ Coverage 91.39% 91.46% +0.06%
==========================================
Files 49 49
Lines 5056 5085 +29
==========================================
+ Hits 4621 4651 +30
+ Misses 435 434 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
output_methods= replaces where save_to_api= added, so a hardcoded [CSV, API] dropped configured outputs and --no-api became a no-op.
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.
What changed
codecarbon/emissions_tracker.py: thesave_to_*DeprecationWarningnow computes itsstackleveldynamically (_caller_stacklevel()) instead of hardcodingstacklevel=2, so it is attributed to the code that constructed the tracker.codecarbon/cli/monitor.py: droppedsave_to_logger=False, which was both the default and the only reason the CLI tripped its own deprecation check.codecarbon/cli/main.py:monitornow passes an explicitoutput_methods=list built from the user's configuration, withOutputMethod.APIadded or removed according to--api/--no-api;detectnow passesoutput_methods=[].Why
_resolve_output_methodsis called fromBaseEmissionsTracker.__init__, sostacklevel=2pointed atemissions_tracker.pyitself. Python's defaultignore::DeprecationWarningfilter then dropped the warning for every caller that is not a top-level__main__script — the users the deprecation was written for never saw it.A fixed
stacklevel=3would not work either:OfflineEmissionsTracker.__init__adds a frame, and its@suppress(Exception)decorator adds acontextlibframe on top of that. Walking the stack to the first frame outside the package handles all entry points, including@track_emissions.Because the corrected attribution makes the warning visible, the CLI's own deprecated call sites had to move to
output_methods=in the same change, otherwise everycodecarbon monitor/codecarbon detectinvocation would warn users about a choice the CLI made (and hard-fail under-W error::DeprecationWarning).Migrating the CLI off
save_to_api=is not a like-for-like swap, becauseoutput_methods=andsave_to_*do not compose the same way: whenoutput_methodsresolves to a non-empty value (from the constructor or from configuration),_resolve_output_methodsderives all fivesave_to_*flags from it and returns early. Sooutput_methodsreplaces, wheresave_to_api=Trueadded. Two consequences, both now handled:1.
--apimust stay additive. An earlier revision of this PR passed a hardcodedoutput_methods=[OutputMethod.CSV, OutputMethod.API]. That replaced the user's configuration outright: someone withsave_to_prometheus = true(oroutput_methods = prometheus) in.codecarbon.configrunningcodecarbon monitor --apiwould silently lose Prometheus and silently gain anemissions.csvthey never asked for. That is not whatsave_to_api=Truedid, so it is now built from the configuration instead, via a small_configured_output_methods()helper that mirrors the tracker's own config-only resolution.As a side effect this also fixes a pre-existing hole: on
master,--apiwas silently ignored wheneveroutput_methodswas set in configuration, because the explicitsave_to_api=Truelost to the early return. It now works.2.
--no-apihas to keep working.apidefaults toTrue, so--no-apiis the off switch.masterpassedsave_to_api=Falseunconditionally, which forced the API off regardless of configuration. Passing the flag only when it is set — as an earlier revision of this PR did — would have made--no-apia no-op for anyone withsave_to_api = truein their config file: plaincodecarbon monitorwould have started pushing to the API and there would have been no way to turn it off from the command line.monitortherefore always passesoutput_methods=, with API removed when--no-api.The same applies to
save_to_logger=False, dropped fromcodecarbon/cli/monitor.py: configuration now decides. Sincemonitorpasses an explicitoutput_methods=list on the online path, that list is authoritative there;run_and_monitorunder--offlineno longer forces the logger off, which is the intended "configuration wins" direction.Given that
--api/--no-apinow both map cleanly onto add/remove, a tri-stateOptional[bool]("unset = whatever the config says") is not proposed here: withapi=Trueas the default, an unset third state would be unreachable from the command line without also flipping the default, which is a separate, user-visible CLI change. Happy to do it as a follow-up if you would rathercodecarbon monitordefault to the configuration.How it was verified
tests/test_emissions_tracker.py::test_deprecation_warning_points_at_callerasserts the recorded warning'sfilenameis the test module for bothEmissionsTrackerandOfflineEmissionsTracker. It fails onmasterand passes here.tests/cli/test_monitor.py::test_run_and_monitor_does_not_pass_deprecated_flagsasserts the CLI passes nosave_to_*kwarg to the tracker. Also fails onmaster.tests/cli/test_cli_main.py::test_monitor_api_flag_adds_to_configured_output_methodspins the additive contract for a configuredoutput_methods = prometheus, forsave_to_file=false+save_to_logger=true, and for the already-contains-API no-duplicate case.--no-apitests now assertOutputMethod.API not in output_methodsrather than that nooutput_methodskwarg was passed._configured_output_methods()call back to the hardcoded[CSV, API]makes four of these tests fail, so they are real guards.uv run pytest tests/ -q --ignore=tests/test_viz_data.pyanduv run pre-commit run --all-filesboth pass.Closes #1323
🤖 Generated with Claude Code