perf(deps): drop pandas and numpy from the default install - #1343
Open
davidberenstein1957 wants to merge 5 commits into
Open
perf(deps): drop pandas and numpy from the default install#1343davidberenstein1957 wants to merge 5 commits into
davidberenstein1957 wants to merge 5 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix/powermetrics-nan-totals #1343 +/- ##
============================================================
Coverage 91.43% 91.44%
============================================================
Files 49 49
Lines 5058 5094 +36
============================================================
+ Hits 4625 4658 +33
- Misses 433 436 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The measurement core only ever used pandas for `read_csv` plus equality filters and one mean, and numpy for four `mean`/`sum` calls. Between them they account for 61 MB of a 130 MB default install and 26% of cold import time, for work the stdlib `csv`, `statistics` and `math` modules do. - parse the bundled reference CSVs with `csv.DictReader` (utf-8-sig, since impact.csv carries a BOM), coercing `impact`/`offsetRatio` to float at the boundary and mapping empty fields to None - add `DataSource.find_cloud_region()` so the provider/region filter is written once instead of six times - rewrite `FileOutput` and `IntelPowerGadget.get_cpu_details` on stdlib csv - replace numpy in `powermetrics` with `statistics.fmean` / `math.fsum` - import `prometheus_client` only when Prometheus output is requested - move pandas to the `carbonboard` extra and add an `all` meta-extra; `codecarbon/viz/` builds its DataFrame from the returned rows Default install: 130 MB -> 68 MB, 39 -> 37 packages, cold `import codecarbon` 78.4 ms -> 37.8 ms (median of 7). Behaviour changes, both fixes: `get_cloud_geo_region` returned pandas' NaN for the 30 of 40 cloud regions that have a city but no state, and now returns the city; float means are now exactly rounded rather than matching one library's summation order. `DataSource.get_cloud_emissions_data()` and `get_cpu_power_data()` return `list[dict]` instead of `DataFrame` — undocumented internal surface, but worth a release note. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tput Also document why extrasaction="ignore" is unreachable.
davidberenstein1957
force-pushed
the
scaling/03-dependency-extras
branch
from
August 12, 2026 19:08
a7da11d to
7b58130
Compare
davidberenstein1957
changed the base branch from
master
to
fix/powermetrics-nan-totals
August 12, 2026 19:08
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…header The viz extras install pandas but not numpy, which `codecarbon/viz/components.py` imports directly; numpy used to arrive transitively through pandas in the default install, so `pip install codecarbon[viz-legacy]` now breaks on import. The CSV append path passed the row dict's key order as DictWriter fieldnames, while `has_valid_headers()` accepts any permutation of the columns already on disk. Read the header row from the file instead, so a reordered file gets correctly aligned rows; an empty/headerless file is rewritten with a header. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s installed Dropping pandas from the default install turned DataSource.get_cloud_emissions_data() and get_cpu_power_data() into list[dict] returns, which would break any external caller relying on the DataFrame they used to get. Internal callers now use new get_cloud_emissions_rows() / get_cpu_power_rows() helpers, so the default path stays pandas-free. The two public methods wrap those and lazily import pandas: a DataFrame when pandas is present, the rows otherwise (a user without pandas could not have been using the DataFrame anyway). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidberenstein1957
marked this pull request as ready for review
August 13, 2026 05:23
davidberenstein1957
requested review from
inimaz
and removed request for
a team
August 13, 2026 05:23
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.
Part of #1338.
pandas was used shallowly — CSV reading, a handful of row filters, one CSV writer — and pulled numpy in behind it. Both are now gone from the default install, replaced with
csv,statisticsandmath. Nothing a user writes changes.Measured on a clean 3.12 venv (
uv venv && uv pip install .)import codecarbonImport time is the median of 7
python -X importtimeruns (before: 73.5/74.5/75.8/78.4/79.2/80.8/111.4; after: 36.0/37.6/37.8/37.8/39.2/40.5/1258 — the outlier is the fresh venv's cold page cache).What actually loaded, traced by dumping
sys.modulesin a subprocess after a fresh import and after a default tracker run:import codecarbonon master pulled numpy, 20.2 ms of the 78 — viaimport numpy as npat the top ofcore/powermetrics.py. numpy was never a declared dependency; it arrived transitively through pandas.prometheus_clientwas imported before theif OutputMethod.PROMETHEUScheck; that import is now inside the branch.What this deliberately does not do
The CLI/auth extras split from the original proposal is not here. It is worth 23 MB and 8 packages with zero runtime benefit — those imports are already off the hot path — and it breaks
pip install codecarbon && codecarbon monitor, a documented headline feature. Its own mitigation is a two-release deprecation whose first half is a warning on every CLI invocation for no measurable gain. That belongs with the v4.0.0 removals, if ever.pycountry(21 MB, the next biggest) also stays: it sits on the live geolocation path, and a lazy import with an empty fallback would be a silentcountry_iso_code/country_nameregression. The bundled data cannot supply the alpha-2 → alpha-3 mapping.Correction to the original proposal's inventory
It listed six shallow call sites and "no vectorised arithmetic", and missed
output_methods/file.pyentirely — the writer for the user'semissions.csv, which does dtype-preserving in-place row updates byrun_idand all-NA column dropping. That is the real risk surface, not the reference-data parsing, and anyone costing this item off that inventory would have underestimated it. It is now oncsv.DictWriter.Tests
uv run pytest tests/ -q --ignore=tests/test_viz_data.py→ 630 passed, 21 skipped (on top of #1345).test_viz_data.pyfails to collect on master identically —dashnot installed.uv run pre-commit run --all-filespasses.Two tests failed mid-way on float precision only. A side-by-side script ran the old pandas path and the new one over
mock_intel_power_gadget_data.csv: all 22 columns agree to within 4.4e-16. Those two assertions were hardcoding pandas'/numpy's summation order in the last ulp, so they are now tolerance-based rather than having their expected numbers edited.New guard in
tests/test_package_integrity.py: runs a full offline tracker in a subprocess and assertspandas,numpyandprometheus_clientare absent fromsys.modules. End-to-end in the bare venv, twoupdate-mode runs produce the same 38-column, 2-rowemissions.csvas master.Compatibility
pip install codecarboninstalls less and behaves the same;codecarbon[carbonboard]and[viz-legacy]still get pandas; a newallextra pulls everything;pandasmoved to thedevgroup, since ten test modules read output CSVs with it.DataSource.get_cloud_emissions_data()andDataSource.get_cpu_power_data()now returnlist[dict]instead of apandas.DataFrame. Nothing in-tree breaks (three test modules andcodecarbon/viz/, all updated —vizbuilds its own frame), but these are importable, undecorated, documented-by-name methods, so any downstream code calling.query(),.iloc,[col]etc. on the result breaks at runtime.This repo has no
CHANGELOGfile — release notes are assembled by.github/release-drafter.ymlfrom PR titles and labels — so there is nowhere to land this except here. Please label this PRbreaking(or equivalent) so the drafter surfaces it, and consider holding it for the next minor at least.Behaviour changes, both fixes
Emissions.get_cloud_geo_regionreturned pandas'NaNfor 30 of 40 cloud regions that have acitybut nostate, becauseif state is not Noneis true forNaN. It now returns the city, as the code plainly intended.fmean/fsum) instead of matching numpy's pairwise order — differences at 1e-16.Risks
CSV float formatting now comes from
str(float)rather than pandas'to_csv. These agree on repr-shortest for normal values, but not on NaN:str(float("nan"))is the literal"nan"whereto_csvwrote an empty cell. That was a real output regression in an earlier revision of this branch and is now fixed —_as_csv_rowrenders any non-finite float as"", covered bytests/output_methods/test_file.py::test_non_finite_values_are_written_as_empty_cells(verified to fail when the guard is removed).Blanking infinities is a deliberate divergence from pandas:
to_csvwrote the literalinf, this writes an empty cell. An infinite energy or emissions figure is not a real measurement, so writinginfintoemissions.csvpropagates a garbage number into everything that reads the file, whereas an empty cell reads back as missing — which is what it actually is.appendmode previously calleddropna(axis=1, how="all")on the single new row, writing a short, column-misaligned row whenever a field wasNone; this writes an empty cell instead — correct, but not byte-identical to that old broken output. Three malformedTDPvalues incpu_power.csv(27.29.5,33.34.8,29.32.9) still raise onfloat()exactly as before; left alone, with a comment on why the column stays text.extrasaction="ignore"on theDictWriteris defensive only and now carries a comment saying so:out()backs the file up and rewrites it from scratch wheneverhas_valid_headers()reports a mismatch, so a row can never carry a key outsidefieldnames.Not included: the CI bare-install job (that is #1342) and the docs/README install-instruction sweep.
🤖 Generated with Claude Code