codecarbon 3.2.9__tar.gz → 3.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. {codecarbon-3.2.9 → codecarbon-3.3.0}/PKG-INFO +46 -16
  2. {codecarbon-3.2.9 → codecarbon-3.3.0}/README.md +45 -15
  3. codecarbon-3.3.0/codecarbon/_version.py +1 -0
  4. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/cli/main.py +46 -15
  5. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/api_client.py +52 -80
  6. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/hardware_cache.py +5 -0
  7. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/powermetrics.py +2 -4
  8. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/resource_tracker.py +26 -9
  9. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/util.py +1 -1
  10. codecarbon-3.3.0/codecarbon/core/windows_emi.py +625 -0
  11. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/emissions_tracker.py +7 -4
  12. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/hardware.py +13 -3
  13. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/ram.py +1 -3
  14. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/PKG-INFO +46 -16
  15. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/SOURCES.txt +2 -0
  16. {codecarbon-3.2.9 → codecarbon-3.3.0}/pyproject.toml +2 -2
  17. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_api_call.py +203 -16
  18. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_config.py +14 -28
  19. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_core_util.py +22 -0
  20. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_cpu_load.py +2 -0
  21. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_electricitymaps_config_backward_compatibility.py +4 -8
  22. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_hardware_cache.py +18 -0
  23. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_logger.py +1 -1
  24. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_ram.py +21 -12
  25. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_resource_tracker.py +53 -2
  26. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_tracking_inference.py +4 -1
  27. codecarbon-3.3.0/tests/test_windows_emi.py +672 -0
  28. codecarbon-3.2.9/codecarbon/_version.py +0 -1
  29. {codecarbon-3.2.9 → codecarbon-3.3.0}/LICENSE +0 -0
  30. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/__init__.py +0 -0
  31. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/cli/__init__.py +0 -0
  32. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/cli/auth.py +0 -0
  33. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/cli/cli_utils.py +0 -0
  34. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/cli/monitor.py +0 -0
  35. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/__init__.py +0 -0
  36. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/cloud.py +0 -0
  37. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/config.py +0 -0
  38. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/cpu.py +0 -0
  39. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/electricitymaps_api.py +0 -0
  40. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/emissions.py +0 -0
  41. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/gpu.py +0 -0
  42. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/gpu_amd.py +0 -0
  43. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/gpu_device.py +0 -0
  44. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/gpu_nvidia.py +0 -0
  45. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/measure.py +0 -0
  46. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/rapl.py +0 -0
  47. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/schemas.py +0 -0
  48. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/telemetry_client.py +0 -0
  49. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/telemetry_schemas.py +0 -0
  50. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/core/units.py +0 -0
  51. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/canada_provinces.geojson +0 -0
  52. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/cloud/impact.csv +0 -0
  53. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_scrapper.py +0 -0
  54. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_scrapper.py +0 -0
  55. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/hardware/cpu_dataset_builder/merge_scrapped_cpu_power.py +0 -0
  56. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/hardware/cpu_power.csv +0 -0
  57. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/private_infra/2016/usa_emissions.json +0 -0
  58. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/private_infra/2023/canada_energy_mix.json +0 -0
  59. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/private_infra/carbon_intensity_per_source.json +0 -0
  60. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/private_infra/global_energy_mix.json +0 -0
  61. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/data/private_infra/nordic_emissions.json +0 -0
  62. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/__init__.py +0 -0
  63. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/geography.py +0 -0
  64. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/logger.py +0 -0
  65. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/scheduler.py +0 -0
  66. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/external/task.py +0 -0
  67. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/input.py +0 -0
  68. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/lock.py +0 -0
  69. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output.py +0 -0
  70. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/__init__.py +0 -0
  71. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/base_output.py +0 -0
  72. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/boamps/__init__.py +0 -0
  73. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/boamps/mapper.py +0 -0
  74. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/boamps/models.py +0 -0
  75. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/boamps/output.py +0 -0
  76. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/emissions_data.py +0 -0
  77. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/file.py +0 -0
  78. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/http.py +0 -0
  79. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/logger.py +0 -0
  80. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/metrics/__init__.py +0 -0
  81. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/metrics/logfire.py +0 -0
  82. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/metrics/metric_docs.py +0 -0
  83. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/output_methods/metrics/prometheus.py +0 -0
  84. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/py.typed +0 -0
  85. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/__init__.py +0 -0
  86. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/assets/__init__.py +0 -0
  87. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/assets/car_icon.png +0 -0
  88. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/assets/house_icon.png +0 -0
  89. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/assets/tv_icon.png +0 -0
  90. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/carbonboard.py +0 -0
  91. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/carbonboard_on_api.py +0 -0
  92. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/components.py +0 -0
  93. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/data.py +0 -0
  94. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon/viz/units.py +0 -0
  95. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/dependency_links.txt +0 -0
  96. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/entry_points.txt +0 -0
  97. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/requires.txt +0 -0
  98. {codecarbon-3.2.9 → codecarbon-3.3.0}/codecarbon.egg-info/top_level.txt +0 -0
  99. {codecarbon-3.2.9 → codecarbon-3.3.0}/setup.cfg +0 -0
  100. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_boamps_output.py +0 -0
  101. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_cloud.py +0 -0
  102. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_cpu.py +0 -0
  103. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_custom_handler.py +0 -0
  104. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_docs_examples.py +0 -0
  105. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_electricitymaps_api.py +0 -0
  106. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_electricitymaps_backward_compatibility.py +0 -0
  107. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_emissions.py +0 -0
  108. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_emissions_tracker.py +0 -0
  109. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_emissions_tracker_constant.py +0 -0
  110. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_emissions_tracker_flush.py +0 -0
  111. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_energy.py +0 -0
  112. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_geography.py +0 -0
  113. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_gpu.py +0 -0
  114. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_gpu_amd.py +0 -0
  115. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_gpu_nvidia.py +0 -0
  116. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_input.py +0 -0
  117. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_lock.py +0 -0
  118. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_logging_output.py +0 -0
  119. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_offline_emissions_tracker.py +0 -0
  120. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_package_integrity.py +0 -0
  121. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_powermetrics.py +0 -0
  122. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_rapl_mmio_scanning.py +0 -0
  123. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_rapl_parameters.py +0 -0
  124. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_rapl_permissions.py +0 -0
  125. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_telemetry_client.py +0 -0
  126. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_unsupported_gpu.py +0 -0
  127. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_utilization_tracking.py +0 -0
  128. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_viz_data.py +0 -0
  129. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/test_viz_units.py +0 -0
  130. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/testdata.py +0 -0
  131. {codecarbon-3.2.9 → codecarbon-3.3.0}/tests/testutils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecarbon
3
- Version: 3.2.9
3
+ Version: 3.3.0
4
4
  Author: Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://codecarbon.io/
@@ -137,18 +137,19 @@ You can visualize your experiment emissions on the [dashboard](https://dashboard
137
137
 
138
138
  ## Quick links
139
139
 
140
- | Section | Description |
141
- |---------|-------------|
142
- | [Quickstart](https://docs.codecarbon.io/latest/tutorials/first-tracking/) | Get started in 5 minutes |
143
- | [Installation](https://docs.codecarbon.io/latest/how-to/installation/) | Install CodeCarbon |
144
- | [CLI Tutorial](https://docs.codecarbon.io/latest/tutorials/cli/) | Track emissions from the command line |
145
- | [Python API Tutorial](https://docs.codecarbon.io/latest/tutorials/python-api/) | Track emissions in Python code |
140
+ | Section | Description |
141
+ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------ |
142
+ | [Quickstart](https://docs.codecarbon.io/latest/tutorials/first-tracking/) | Get started in 5 minutes |
143
+ | [Installation](https://docs.codecarbon.io/latest/how-to/installation/) | Install CodeCarbon |
144
+ | [CLI Tutorial](https://docs.codecarbon.io/latest/tutorials/cli/) | Track emissions from the command line |
145
+ | [Python API Tutorial](https://docs.codecarbon.io/latest/tutorials/python-api/) | Track emissions in Python code |
146
146
  | [Comparing Model Efficiency](https://docs.codecarbon.io/latest/tutorials/comparing-model-efficiency/) | Measure carbon efficiency across ML models |
147
- | [API Reference](https://docs.codecarbon.io/latest/reference/api/) | Full parameter documentation |
148
- | [Framework examples (scikit-learn)](https://docs.codecarbon.io/latest/how-to/scikit-learn/) | Task-oriented ML framework examples |
149
- | [Methodology](https://docs.codecarbon.io/latest/explanation/methodology/) | How emissions are calculated |
150
- | [EcoLogits](https://ecologits.ai/) | Track emissions from GenAI API calls |
151
- | [Discord Community](https://discord.gg/GS9js2XkJR) | Chat with us and the community |
147
+ | [API Reference](https://docs.codecarbon.io/latest/reference/api/) | Full parameter documentation |
148
+ | [Framework examples (scikit-learn)](https://docs.codecarbon.io/latest/how-to/scikit-learn/) | Task-oriented ML framework examples |
149
+ | [Methodology](https://docs.codecarbon.io/latest/explanation/methodology/) | How emissions are calculated |
150
+ | [When to use CodeCarbon vs EcoLogits](https://docs.codecarbon.io/latest/explanation/when-to-use/) | Choose the right tool |
151
+ | [EcoLogits](https://ecologits.ai/) | Track emissions from GenAI API calls |
152
+ | [Discord Community](https://discord.gg/GS9js2XkJR) | Chat with us and the community |
152
153
 
153
154
  ## Links
154
155
 
@@ -156,6 +157,7 @@ You can visualize your experiment emissions on the [dashboard](https://dashboard
156
157
  - [Dashboard](https://dashboard.codecarbon.io/) to see your emissions.
157
158
  - [Documentation](https://docs.codecarbon.io/) to learn how to use the package and our methodology.
158
159
  - [EcoLogits](https://ecologits.ai/) to track emissions from GenAI API calls (OpenAI, Anthropic, etc.).
160
+ - [mlco2 on GitHub](https://github.com/mlco2) for our other open-source projects.
159
161
  - [GitHub](https://github.com/mlco2/codecarbon) to look at the source code and contribute.
160
162
  - [Discord](https://discord.gg/GS9js2XkJR) to chat with us.
161
163
 
@@ -210,7 +212,7 @@ If you find CodeCarbon useful for your research, you can find a citation under a
210
212
  MinervaBooks},
211
213
  title = {mlco2/codecarbon: v2.4.1},
212
214
  month = may,
213
- year = 2024,
215
+ year = {2024},
214
216
  publisher = {Zenodo},
215
217
  version = {v2.4.1},
216
218
  doi = {10.5281/zenodo.11171501},
@@ -228,6 +230,34 @@ Codecarbon was formerly developed by volunteers from [**Mila**](http://mila.queb
228
230
 
229
231
  Now CodeCarbon is supported by [**Code Carbon**](https://www.helloasso.com/associations/code-carbon), a French non-profit organization whose mission is to accelerate the development and adoption of CodeCarbon.
230
232
 
231
- ### Star History
232
-
233
- [![Star History Chart](https://api.star-history.com/svg?repos=mlco2/codecarbon,lfwa/carbontracker,sb-ai-lab/Eco2AI,fvaleye/tracarbon,Breakend/experiment-impact-tracker&type=Date)](https://star-history.com/#mlco2/codecarbon&lfwa/carbontracker&sb-ai-lab/Eco2AI&fvaleye/tracarbon&Breakend/experiment-impact-tracker&Date)
233
+ ## Sponsors
234
+
235
+ <div align="center">
236
+ <a href="https://www.clever-cloud.com/">
237
+ <picture>
238
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/clever_cloud.png">
239
+ <img src="https://cdn.clever-cloud.com/uploads/2023/03/logoonwhite.svg" alt="Clever Cloud" height="48">
240
+ </picture>
241
+ </a>
242
+ &nbsp;&nbsp;&nbsp;
243
+ <a href="https://dataforgood.fr/">
244
+ <picture>
245
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/dataforgood.png">
246
+ <img src="https://dataforgood.fr/images/dataforgood.svg" alt="Data For Good" height="48">
247
+ </picture>
248
+ </a>
249
+ &nbsp;&nbsp;&nbsp;
250
+ <a href="https://github.com/">
251
+ <picture>
252
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/GitHub.png">
253
+ <img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Logo.png" alt="GitHub" height="48">
254
+ </picture>
255
+ </a>
256
+ &nbsp;&nbsp;&nbsp;
257
+ <a href="https://www.mozilla.org/">
258
+ <picture>
259
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/mozilla.svg">
260
+ <img src="https://upload.wikimedia.org/wikipedia/commons/d/df/Mozilla_2024_logo.svg" alt="Mozilla" height="48">
261
+ </picture>
262
+ </a>
263
+ </div>
@@ -90,18 +90,19 @@ You can visualize your experiment emissions on the [dashboard](https://dashboard
90
90
 
91
91
  ## Quick links
92
92
 
93
- | Section | Description |
94
- |---------|-------------|
95
- | [Quickstart](https://docs.codecarbon.io/latest/tutorials/first-tracking/) | Get started in 5 minutes |
96
- | [Installation](https://docs.codecarbon.io/latest/how-to/installation/) | Install CodeCarbon |
97
- | [CLI Tutorial](https://docs.codecarbon.io/latest/tutorials/cli/) | Track emissions from the command line |
98
- | [Python API Tutorial](https://docs.codecarbon.io/latest/tutorials/python-api/) | Track emissions in Python code |
93
+ | Section | Description |
94
+ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------ |
95
+ | [Quickstart](https://docs.codecarbon.io/latest/tutorials/first-tracking/) | Get started in 5 minutes |
96
+ | [Installation](https://docs.codecarbon.io/latest/how-to/installation/) | Install CodeCarbon |
97
+ | [CLI Tutorial](https://docs.codecarbon.io/latest/tutorials/cli/) | Track emissions from the command line |
98
+ | [Python API Tutorial](https://docs.codecarbon.io/latest/tutorials/python-api/) | Track emissions in Python code |
99
99
  | [Comparing Model Efficiency](https://docs.codecarbon.io/latest/tutorials/comparing-model-efficiency/) | Measure carbon efficiency across ML models |
100
- | [API Reference](https://docs.codecarbon.io/latest/reference/api/) | Full parameter documentation |
101
- | [Framework examples (scikit-learn)](https://docs.codecarbon.io/latest/how-to/scikit-learn/) | Task-oriented ML framework examples |
102
- | [Methodology](https://docs.codecarbon.io/latest/explanation/methodology/) | How emissions are calculated |
103
- | [EcoLogits](https://ecologits.ai/) | Track emissions from GenAI API calls |
104
- | [Discord Community](https://discord.gg/GS9js2XkJR) | Chat with us and the community |
100
+ | [API Reference](https://docs.codecarbon.io/latest/reference/api/) | Full parameter documentation |
101
+ | [Framework examples (scikit-learn)](https://docs.codecarbon.io/latest/how-to/scikit-learn/) | Task-oriented ML framework examples |
102
+ | [Methodology](https://docs.codecarbon.io/latest/explanation/methodology/) | How emissions are calculated |
103
+ | [When to use CodeCarbon vs EcoLogits](https://docs.codecarbon.io/latest/explanation/when-to-use/) | Choose the right tool |
104
+ | [EcoLogits](https://ecologits.ai/) | Track emissions from GenAI API calls |
105
+ | [Discord Community](https://discord.gg/GS9js2XkJR) | Chat with us and the community |
105
106
 
106
107
  ## Links
107
108
 
@@ -109,6 +110,7 @@ You can visualize your experiment emissions on the [dashboard](https://dashboard
109
110
  - [Dashboard](https://dashboard.codecarbon.io/) to see your emissions.
110
111
  - [Documentation](https://docs.codecarbon.io/) to learn how to use the package and our methodology.
111
112
  - [EcoLogits](https://ecologits.ai/) to track emissions from GenAI API calls (OpenAI, Anthropic, etc.).
113
+ - [mlco2 on GitHub](https://github.com/mlco2) for our other open-source projects.
112
114
  - [GitHub](https://github.com/mlco2/codecarbon) to look at the source code and contribute.
113
115
  - [Discord](https://discord.gg/GS9js2XkJR) to chat with us.
114
116
 
@@ -163,7 +165,7 @@ If you find CodeCarbon useful for your research, you can find a citation under a
163
165
  MinervaBooks},
164
166
  title = {mlco2/codecarbon: v2.4.1},
165
167
  month = may,
166
- year = 2024,
168
+ year = {2024},
167
169
  publisher = {Zenodo},
168
170
  version = {v2.4.1},
169
171
  doi = {10.5281/zenodo.11171501},
@@ -181,6 +183,34 @@ Codecarbon was formerly developed by volunteers from [**Mila**](http://mila.queb
181
183
 
182
184
  Now CodeCarbon is supported by [**Code Carbon**](https://www.helloasso.com/associations/code-carbon), a French non-profit organization whose mission is to accelerate the development and adoption of CodeCarbon.
183
185
 
184
- ### Star History
185
-
186
- [![Star History Chart](https://api.star-history.com/svg?repos=mlco2/codecarbon,lfwa/carbontracker,sb-ai-lab/Eco2AI,fvaleye/tracarbon,Breakend/experiment-impact-tracker&type=Date)](https://star-history.com/#mlco2/codecarbon&lfwa/carbontracker&sb-ai-lab/Eco2AI&fvaleye/tracarbon&Breakend/experiment-impact-tracker&Date)
186
+ ## Sponsors
187
+
188
+ <div align="center">
189
+ <a href="https://www.clever-cloud.com/">
190
+ <picture>
191
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/clever_cloud.png">
192
+ <img src="https://cdn.clever-cloud.com/uploads/2023/03/logoonwhite.svg" alt="Clever Cloud" height="48">
193
+ </picture>
194
+ </a>
195
+ &nbsp;&nbsp;&nbsp;
196
+ <a href="https://dataforgood.fr/">
197
+ <picture>
198
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/dataforgood.png">
199
+ <img src="https://dataforgood.fr/images/dataforgood.svg" alt="Data For Good" height="48">
200
+ </picture>
201
+ </a>
202
+ &nbsp;&nbsp;&nbsp;
203
+ <a href="https://github.com/">
204
+ <picture>
205
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/GitHub.png">
206
+ <img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Logo.png" alt="GitHub" height="48">
207
+ </picture>
208
+ </a>
209
+ &nbsp;&nbsp;&nbsp;
210
+ <a href="https://www.mozilla.org/">
211
+ <picture>
212
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/mlco2/codecarbon-landing-page/main/public/assets/partners/mozilla.svg">
213
+ <img src="https://upload.wikimedia.org/wikipedia/commons/d/df/Mozilla_2024_logo.svg" alt="Mozilla" height="48">
214
+ </picture>
215
+ </a>
216
+ </div>
@@ -0,0 +1 @@
1
+ __version__ = "3.3.0"
@@ -40,6 +40,20 @@ def main():
40
40
  raise sys.exit(1)
41
41
 
42
42
 
43
+ def _api_call(action: str, func, *args, **kwargs):
44
+ """
45
+ Run a call to the Code Carbon API, turning the errors it now raises into a
46
+ readable message and a clean exit instead of a traceback.
47
+
48
+ :action: what was being attempted, used as the first part of the message.
49
+ """
50
+ try:
51
+ return func(*args, **kwargs)
52
+ except Exception as e:
53
+ print(f"[yellow]{action}[/yellow]. (error: {e})")
54
+ raise typer.Exit(1)
55
+
56
+
43
57
  def _version_callback(value: bool) -> None:
44
58
  if value:
45
59
  print(f"{__app_name__} v{__version__}")
@@ -116,7 +130,7 @@ def api_get():
116
130
  api_endpoint = get_api_endpoint()
117
131
  api = ApiClient(endpoint_url=api_endpoint)
118
132
  api.set_access_token(get_access_token())
119
- organizations = api.get_list_organizations()
133
+ organizations = _api_call("API request failed", api.get_list_organizations)
120
134
  print(organizations)
121
135
 
122
136
 
@@ -130,7 +144,7 @@ def login():
130
144
  api = ApiClient(endpoint_url=api_endpoint)
131
145
  access_token = get_access_token()
132
146
  api.set_access_token(access_token)
133
- api.check_auth()
147
+ _api_call("Authentication check failed", api.check_auth)
134
148
 
135
149
 
136
150
  def get_api_key(project_id: str):
@@ -149,6 +163,7 @@ def get_api_key(project_id: str):
149
163
  },
150
164
  headers={"Authorization": f"Bearer {get_access_token()}"},
151
165
  )
166
+ req.raise_for_status()
152
167
  api_key = req.json()["token"]
153
168
  return api_key
154
169
 
@@ -212,7 +227,10 @@ def config():
212
227
  overwrite_local_config("api_endpoint", api_endpoint, path=file_path)
213
228
  api = ApiClient(endpoint_url=api_endpoint)
214
229
  api.set_access_token(get_access_token())
215
- organizations = api.get_list_organizations()
230
+ organizations = _api_call(
231
+ "Could not list organizations from API. Please check your login and API endpoint",
232
+ api.get_list_organizations,
233
+ )
216
234
  org = questionary_prompt(
217
235
  "Pick existing organization from list or Create new organization ?",
218
236
  [org["name"] for org in organizations] + ["Create New Organization"],
@@ -229,18 +247,23 @@ def config():
229
247
  name=org_name,
230
248
  description=org_description,
231
249
  )
232
- organization = api.create_organization(organization=organization_create)
233
- if organization is None:
234
- print("Error creating organization")
235
- return
250
+ organization = _api_call(
251
+ "Could not create the organization",
252
+ api.create_organization,
253
+ organization=organization_create,
254
+ )
236
255
  print(f"Created organization : {organization}")
237
256
  else:
238
257
  organization = [orga for orga in organizations if orga["name"] == org][0]
239
258
  org_id = organization["id"]
240
259
  overwrite_local_config("organization_id", org_id, path=file_path)
241
260
 
242
- projects = api.list_projects_from_organization(org_id)
243
- project_names = [project["name"] for project in projects] if projects else []
261
+ projects = _api_call(
262
+ "Could not list projects from API",
263
+ api.list_projects_from_organization,
264
+ org_id,
265
+ )
266
+ project_names = [project["name"] for project in projects]
244
267
  project = questionary_prompt(
245
268
  "Pick existing project from list or Create new project ?",
246
269
  project_names + ["Create New Project"],
@@ -256,17 +279,21 @@ def config():
256
279
  description=project_description,
257
280
  organization_id=org_id,
258
281
  )
259
- project = api.create_project(project=project_create)
282
+ project = _api_call(
283
+ "Could not create the project", api.create_project, project=project_create
284
+ )
260
285
  print(f"Created project : {project}")
261
286
  else:
262
287
  project = [p for p in projects if p["name"] == project][0]
263
288
  project_id = project["id"]
264
289
  overwrite_local_config("project_id", project_id, path=file_path)
265
290
 
266
- experiments = api.list_experiments_from_project(project_id)
267
- experiments_names = (
268
- [experiment["name"] for experiment in experiments] if experiments else []
291
+ experiments = _api_call(
292
+ "Could not list experiments from API",
293
+ api.list_experiments_from_project,
294
+ project_id,
269
295
  )
296
+ experiments_names = [experiment["name"] for experiment in experiments]
270
297
 
271
298
  experiment = questionary_prompt(
272
299
  "Pick existing experiment from list or Create new experiment ?",
@@ -313,13 +340,17 @@ def config():
313
340
  cloud_provider=cloud_provider,
314
341
  cloud_region=cloud_region,
315
342
  )
316
- experiment = api.add_experiment(experiment=experiment_create)
343
+ experiment = _api_call(
344
+ "Could not create the experiment",
345
+ api.add_experiment,
346
+ experiment=experiment_create,
347
+ )
317
348
 
318
349
  else:
319
350
  experiment = [e for e in experiments if e["name"] == experiment][0]
320
351
 
321
352
  overwrite_local_config("experiment_id", experiment["id"], path=file_path)
322
- api_key = get_api_key(project_id)
353
+ api_key = _api_call("Could not get the project API key", get_api_key, project_id)
323
354
  overwrite_local_config("api_key", api_key, path=file_path)
324
355
  show_config(file_path)
325
356
  print(
@@ -70,6 +70,21 @@ class ApiClient: # (AsyncClient)
70
70
  headers["Authorization"] = f"Bearer {self.access_token}"
71
71
  return headers
72
72
 
73
+ def _request(self, method, url, payload=None, expected_status=200):
74
+ """
75
+ Call the API and return the response, raising on anything that is not
76
+ the status code the API answers on success.
77
+
78
+ :method: the requests function to call, for example requests.get
79
+ :payload: the JSON body to send, if any
80
+ :expected_status: the http code the API returns when the call succeeds
81
+ """
82
+ headers = self._get_headers()
83
+ response = method(url=url, json=payload, timeout=2, headers=headers)
84
+ if response.status_code != expected_status:
85
+ self._raise_api_error(url, payload or {}, response)
86
+ return response
87
+
73
88
  def set_access_token(self, token: str):
74
89
  """This method sets the access token to be used for the API.
75
90
  Args:
@@ -82,32 +97,20 @@ class ApiClient: # (AsyncClient)
82
97
  Check API access to user account
83
98
  """
84
99
  url = self.url + "/auth/check"
85
- headers = self._get_headers()
86
- r = requests.get(url=url, timeout=2, headers=headers)
87
- if r.status_code != 200:
88
- self._log_error(url, {}, r)
89
- return None
90
- return r.json()
100
+ return self._request(requests.get, url).json()
91
101
 
92
102
  def get_list_organizations(self):
93
103
  """
94
104
  List all organizations
95
105
  """
96
106
  url = self.url + "/organizations"
97
- headers = self._get_headers()
98
- r = requests.get(url=url, timeout=2, headers=headers)
99
- if r.status_code != 200:
100
- self._log_error(url, {}, r)
101
- return None
102
- return r.json()
107
+ return self._request(requests.get, url).json()
103
108
 
104
109
  def check_organization_exists(self, organization_name: str):
105
110
  """
106
111
  Check if an organization exists
107
112
  """
108
113
  organizations = self.get_list_organizations()
109
- if organizations is None:
110
- return False
111
114
  for organization in organizations:
112
115
  if organization["name"] == organization_name:
113
116
  return organization
@@ -125,49 +128,31 @@ class ApiClient: # (AsyncClient)
125
128
  )
126
129
  return organization
127
130
  else:
128
- headers = self._get_headers()
129
- r = requests.post(url=url, json=payload, timeout=2, headers=headers)
130
- if r.status_code != 201:
131
- self._log_error(url, payload, r)
132
- return None
133
- return r.json()
131
+ return self._request(
132
+ requests.post, url, payload=payload, expected_status=201
133
+ ).json()
134
134
 
135
135
  def get_organization(self, organization_id):
136
136
  """
137
137
  Get an organization
138
138
  """
139
- headers = self._get_headers()
140
139
  url = self.url + "/organizations/" + organization_id
141
- r = requests.get(url=url, timeout=2, headers=headers)
142
- if r.status_code != 200:
143
- self._log_error(url, {}, r)
144
- return None
145
- return r.json()
140
+ return self._request(requests.get, url).json()
146
141
 
147
142
  def update_organization(self, organization: OrganizationCreate):
148
143
  """
149
144
  Update an organization
150
145
  """
151
146
  payload = dataclasses.asdict(organization)
152
- headers = self._get_headers()
153
147
  url = self.url + "/organizations/" + organization.id
154
- r = requests.patch(url=url, json=payload, timeout=2, headers=headers)
155
- if r.status_code != 200:
156
- self._log_error(url, payload, r)
157
- return None
158
- return r.json()
148
+ return self._request(requests.patch, url, payload=payload).json()
159
149
 
160
150
  def list_projects_from_organization(self, organization_id):
161
151
  """
162
152
  List all projects
163
153
  """
164
154
  url = self.url + "/organizations/" + organization_id + "/projects"
165
- headers = self._get_headers()
166
- r = requests.get(url=url, timeout=2, headers=headers)
167
- if r.status_code != 200:
168
- self._log_error(url, {}, r)
169
- return None
170
- return r.json()
155
+ return self._request(requests.get, url).json()
171
156
 
172
157
  def create_project(self, project: ProjectCreate):
173
158
  """
@@ -175,24 +160,16 @@ class ApiClient: # (AsyncClient)
175
160
  """
176
161
  payload = dataclasses.asdict(project)
177
162
  url = self.url + "/projects"
178
- headers = self._get_headers()
179
- r = requests.post(url=url, json=payload, timeout=2, headers=headers)
180
- if r.status_code != 201:
181
- self._log_error(url, payload, r)
182
- return None
183
- return r.json()
163
+ return self._request(
164
+ requests.post, url, payload=payload, expected_status=201
165
+ ).json()
184
166
 
185
167
  def get_project(self, project_id):
186
168
  """
187
169
  Get a project
188
170
  """
189
171
  url = self.url + "/projects/" + project_id
190
- headers = self._get_headers()
191
- r = requests.get(url=url, timeout=2, headers=headers)
192
- if r.status_code != 200:
193
- self._log_error(url, {}, r)
194
- return None
195
- return r.json()
172
+ return self._request(requests.get, url).json()
196
173
 
197
174
  def add_emission(self, carbon_emission: dict):
198
175
  assert self.experiment_id is not None
@@ -233,15 +210,14 @@ class ApiClient: # (AsyncClient)
233
210
  try:
234
211
  payload = dataclasses.asdict(emission)
235
212
  url = self.url + "/emissions"
236
- headers = self._get_headers()
237
- r = requests.post(url=url, json=payload, timeout=2, headers=headers)
238
- if r.status_code != 201:
239
- self._log_error(url, payload, r)
240
- return False
213
+ self._request(requests.post, url, payload=payload, expected_status=201)
241
214
  logger.debug(f"ApiClient - Successful upload emission {payload} to {url}")
215
+ except requests.exceptions.HTTPError:
216
+ # Already logged by _raise_api_error, do not log it twice.
217
+ raise
242
218
  except Exception as e:
243
219
  logger.error(e, exc_info=True)
244
- return False
220
+ raise
245
221
  return True
246
222
 
247
223
  def _create_run(self, experiment_id: str):
@@ -275,11 +251,7 @@ class ApiClient: # (AsyncClient)
275
251
  )
276
252
  payload = dataclasses.asdict(run)
277
253
  url = self.url + "/runs"
278
- headers = self._get_headers()
279
- r = requests.post(url=url, json=payload, timeout=2, headers=headers)
280
- if r.status_code != 201:
281
- self._log_error(url, payload, r)
282
- return None
254
+ r = self._request(requests.post, url, payload=payload, expected_status=201)
283
255
  self.run_id = r.json()["id"]
284
256
  logger.info(
285
257
  "ApiClient Successfully registered your run on the API.\n\n"
@@ -292,20 +264,20 @@ class ApiClient: # (AsyncClient)
292
264
  f"Failed to connect to API, please check the configuration. {e}",
293
265
  exc_info=False,
294
266
  )
267
+ raise
268
+ except requests.exceptions.HTTPError:
269
+ # Already logged by _raise_api_error, do not log it twice.
270
+ raise
295
271
  except Exception as e:
296
272
  logger.error(e, exc_info=True)
273
+ raise
297
274
 
298
275
  def list_experiments_from_project(self, project_id: str):
299
276
  """
300
277
  List all experiments for a project
301
278
  """
302
279
  url = self.url + "/projects/" + project_id + "/experiments"
303
- headers = self._get_headers()
304
- r = requests.get(url=url, timeout=2, headers=headers)
305
- if r.status_code != 200:
306
- self._log_error(url, {}, r)
307
- return []
308
- return r.json()
280
+ return self._request(requests.get, url).json()
309
281
 
310
282
  def set_experiment(self, experiment_id: str):
311
283
  """
@@ -320,26 +292,21 @@ class ApiClient: # (AsyncClient)
320
292
  """
321
293
  payload = dataclasses.asdict(experiment)
322
294
  url = self.url + "/experiments"
323
- headers = self._get_headers()
324
- r = requests.post(url=url, json=payload, timeout=2, headers=headers)
325
- if r.status_code != 201:
326
- self._log_error(url, payload, r)
327
- return None
328
- return r.json()
295
+ return self._request(
296
+ requests.post, url, payload=payload, expected_status=201
297
+ ).json()
329
298
 
330
299
  def get_experiment(self, experiment_id):
331
300
  """
332
301
  Get an experiment by id
333
302
  """
334
303
  url = self.url + "/experiments/" + experiment_id
335
- headers = self._get_headers()
336
- r = requests.get(url=url, timeout=2, headers=headers)
337
- if r.status_code != 200:
338
- self._log_error(url, {}, r)
339
- return None
340
- return r.json()
304
+ return self._request(requests.get, url).json()
341
305
 
342
- def _log_error(self, url, payload, response):
306
+ def _raise_api_error(self, url, payload, response):
307
+ """
308
+ Log the failed call then always raise a requests.exceptions.HTTPError.
309
+ """
343
310
  if len(payload) > 0:
344
311
  logger.error(
345
312
  f"ApiClient Error when calling the API on {url} with : {json.dumps(payload)}"
@@ -349,6 +316,11 @@ class ApiClient: # (AsyncClient)
349
316
  logger.error(
350
317
  f"ApiClient API return http code {response.status_code} and answer : {response.text}"
351
318
  )
319
+ response.raise_for_status()
320
+ # 2xx/3xx that still isn't what the caller expected
321
+ raise requests.exceptions.HTTPError(
322
+ f"Unexpected status {response.status_code} from {url}", response=response
323
+ )
352
324
 
353
325
  def close_experiment(self):
354
326
  """
@@ -134,6 +134,10 @@ def _spec_from_hardware(hw) -> Dict[str, Any]:
134
134
  spec["rapl_include_dram"] = getattr(intel, "rapl_include_dram", False)
135
135
  spec["rapl_prefer_psys"] = getattr(intel, "rapl_prefer_psys", False)
136
136
  spec["rapl_dir"] = getattr(intel, "_lin_rapl_dir", DEFAULT_RAPL_DIR)
137
+ elif hw._mode == "windows_emi" and hasattr(hw, "_intel_interface"):
138
+ spec["rapl_include_dram"] = getattr(
139
+ hw._intel_interface, "emi_include_dram", False
140
+ )
137
141
  return spec
138
142
  if kind == HardwareKind.APPLE_CHIP:
139
143
  return {
@@ -238,6 +242,7 @@ def clear_cache() -> None:
238
242
  ("codecarbon.core.gpu_amd", "clear_rocm_system_cache"),
239
243
  ("codecarbon.core.cpu", "clear_powergadget_cache"),
240
244
  ("codecarbon.core.powermetrics", "clear_powermetrics_cache"),
245
+ ("codecarbon.core.windows_emi", "clear_emi_cache"),
241
246
  ):
242
247
  mod = sys.modules.get(mod_name)
243
248
  if mod is not None:
@@ -67,13 +67,11 @@ def _has_powermetrics_sudo() -> bool:
67
67
  _, stderr = process.communicate()
68
68
 
69
69
  if re.search(r"[sudo].*password", stderr):
70
- logger.debug(
71
- """Not using PowerMetrics, sudo password prompt detected.
70
+ logger.debug("""Not using PowerMetrics, sudo password prompt detected.
72
71
  If you want to enable Powermetrics please modify your sudoers file
73
72
  as described in :
74
73
  https://docs.codecarbon.io/latest/explanation/methodology/#power-usage
75
- """
76
- )
74
+ """)
77
75
  return False
78
76
  if process.returncode != 0:
79
77
  raise Exception("Return code != 0")