diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml index c38f3e988..e8c662444 100644 --- a/.github/workflows/test-package.yml +++ b/.github/workflows/test-package.yml @@ -27,3 +27,7 @@ jobs: run: uv sync --python ${{ matrix.python-version }} - name: Test package run: uv run --python ${{ matrix.python-version }} task test-package + - name: Install carbonboard dependencies + run: uv pip install --python ${{ matrix.python-version }} dash 'dash_bootstrap_components>1.0.0' fire + - name: Test carbonboard visualization + run: uv run --python ${{ matrix.python-version }} pytest -vv tests/test_viz_data.py tests/test_viz_units.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91e38da94..1754c657e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -326,13 +326,15 @@ pytest test_package_integrity.py To run locally the dashboard application, you can use it out on a sample data file such as the one in `examples/emissions.csv`, and run it with the following command from the code base: ```bash -uv run --extra viz-legacy task carbonboard --filepath="examples/emissions.csv" +uv run --extra carbonboard task carbonboard --filepath="examples/emissions.csv" # or, if you don't want to use UV -pip install codecarbon["viz"] +pip install codecarbon[carbonboard] python codecarbon/viz/carbonboard.py --filepath="examples/emissions.csv" ``` +> **Note:** The `viz-legacy` extra is deprecated but still works for backwards compatibility. It will be removed in v4.0.0. Please use `carbonboard` instead. + If you have the package installed, you can run the CLI command: ```bash diff --git a/codecarbon/viz/carbonboard.py b/codecarbon/viz/carbonboard.py index 6c68407f2..ccbcd31c2 100644 --- a/codecarbon/viz/carbonboard.py +++ b/codecarbon/viz/carbonboard.py @@ -1,6 +1,32 @@ -import dash -import dash_bootstrap_components as dbc -import fire +import sys + +try: + import dash + import dash_bootstrap_components as dbc +except ImportError: + print( + "\n❌ Error: Carbonboard requires additional dependencies that are not installed.\n" + "\nTo install them, run:\n" + " pip install codecarbon[carbonboard]\n" + "\nOr if using uv:\n" + " uv pip install codecarbon[carbonboard]\n", + file=sys.stderr, + ) + sys.exit(1) + +try: + import fire +except ImportError: + print( + "\n❌ Error: Carbonboard requires 'fire' which is not installed.\n" + "\nTo install it, run:\n" + " pip install codecarbon[carbonboard]\n" + "\nOr if using uv:\n" + " uv pip install codecarbon[carbonboard]\n", + file=sys.stderr, + ) + sys.exit(1) + import pandas as pd from dash import dash_table as dt from dash import dcc diff --git a/docs/edit/visualize.rst b/docs/edit/visualize.rst index f4140d806..b1230cecb 100644 --- a/docs/edit/visualize.rst +++ b/docs/edit/visualize.rst @@ -8,6 +8,19 @@ Offline The package also comes with a ``Dash App`` containing illustrations to understand the emissions logged from various experiments across projects. The App currently consumes logged information from a CSV file, generated from an in-built logger in the package. +Installation +~~~~~~~~~~~~ +The carbonboard visualization tool requires additional dependencies. Install them with: + +.. code-block:: bash + + pip install codecarbon[carbonboard] + +.. note:: + The ``viz-legacy`` extra is deprecated but still works for backwards compatibility. It will be removed in v4.0.0. Please use ``carbonboard`` instead. + +Usage +~~~~~ The App can be run by executing the below CLI command that needs following arguments: - ``filepath`` - path to the CSV file containing logged information across experiments and projects @@ -107,6 +120,5 @@ The app also provides a visualization of regional carbon intensity of electricit :alt: carbon intensity carbon_map :width: 750px -Note that for now, all data sent to CodeCarbon API are public. diff --git a/pyproject.toml b/pyproject.toml index 2e8852d86..4c60612f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -98,22 +98,16 @@ doc = [ ] [project.optional-dependencies] -viz-legacy = [ +carbonboard = [ "dash", "dash_bootstrap_components > 1.0.0", "fire", ] - -viz = [ - "mock", - "pytest", - "responses", - "numpy<2.0.0;python_version<'3.9'", - "numpy;python_version>='3.9'", - "psutil", - "requests-mock", - "rapidfuzz", - "importlib_resources;python_version<'3.9'" +# Backwards compatibility alias - will be removed in v4.0.0 +viz-legacy = [ + "dash", + "dash_bootstrap_components > 1.0.0", + "fire", ] api = [ "alembic<2.0.0", diff --git a/uv.lock b/uv.lock index e7e329ae8..d2a32cc2b 100644 --- a/uv.lock +++ b/uv.lock @@ -1219,27 +1219,13 @@ api = [ { name = "uvicorn", version = "0.33.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version == '3.8.*'" }, { name = "uvicorn", version = "0.38.0", source = { registry = "https://pypi.org/simple" }, extra = ["standard"], marker = "python_full_version >= '3.9'" }, ] -viz = [ - { name = "importlib-resources", version = "5.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "importlib-resources", version = "6.4.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "mock" }, - { name = "numpy", version = "1.21.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "numpy", version = "1.24.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "numpy", version = "2.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "psutil" }, - { name = "pytest", version = "7.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "pytest", version = "9.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "rapidfuzz", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "rapidfuzz", version = "3.9.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, - { name = "rapidfuzz", version = "3.13.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "rapidfuzz", version = "3.14.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "requests-mock" }, - { name = "responses", version = "0.23.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, - { name = "responses", version = "0.25.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, +carbonboard = [ + { name = "dash", version = "2.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, + { name = "dash", version = "3.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, + { name = "dash-bootstrap-components", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, + { name = "dash-bootstrap-components", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.8.*'" }, + { name = "dash-bootstrap-components", version = "2.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "fire" }, ] viz-legacy = [ { name = "dash", version = "2.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, @@ -1294,21 +1280,20 @@ requires-dist = [ { name = "arrow" }, { name = "bcrypt", marker = "extra == 'api'", specifier = "<5.0.0" }, { name = "click" }, + { name = "dash", marker = "extra == 'carbonboard'" }, { name = "dash", marker = "extra == 'viz-legacy'" }, + { name = "dash-bootstrap-components", marker = "extra == 'carbonboard'", specifier = ">1.0.0" }, { name = "dash-bootstrap-components", marker = "extra == 'viz-legacy'", specifier = ">1.0.0" }, { name = "dependency-injector", marker = "extra == 'api'", specifier = "<5.0.0" }, { name = "fastapi", marker = "extra == 'api'", specifier = "<1.0.0" }, { name = "fastapi-pagination", marker = "extra == 'api'", specifier = "<1.0.0" }, { name = "fief-client", extras = ["cli"] }, { name = "fief-client", extras = ["fastapi"], marker = "extra == 'api'" }, + { name = "fire", marker = "extra == 'carbonboard'" }, { name = "fire", marker = "extra == 'viz-legacy'" }, { name = "httpx", marker = "extra == 'api'" }, - { name = "importlib-resources", marker = "python_full_version < '3.9' and extra == 'viz'" }, { name = "logfire", extras = ["fastapi"], marker = "extra == 'api'", specifier = ">=1.0.1" }, { name = "mock", marker = "extra == 'api'" }, - { name = "mock", marker = "extra == 'viz'" }, - { name = "numpy", marker = "python_full_version >= '3.9' and extra == 'viz'" }, - { name = "numpy", marker = "python_full_version < '3.9' and extra == 'viz'", specifier = "<2.0.0" }, { name = "numpy", marker = "extra == 'api'" }, { name = "nvidia-ml-py" }, { name = "pandas", marker = "python_full_version < '3.14'" }, @@ -1316,31 +1301,26 @@ requires-dist = [ { name = "prometheus-client" }, { name = "psutil", specifier = ">=6.0.0" }, { name = "psutil", marker = "extra == 'api'" }, - { name = "psutil", marker = "extra == 'viz'" }, { name = "psycopg2-binary", marker = "extra == 'api'", specifier = "<3.0.0" }, { name = "py-cpuinfo" }, { name = "pydantic" }, { name = "pydantic", extras = ["email"], marker = "extra == 'api'", specifier = "<2.0.0" }, { name = "pyjwt", marker = "extra == 'api'" }, { name = "pytest", marker = "extra == 'api'" }, - { name = "pytest", marker = "extra == 'viz'" }, { name = "python-dateutil", marker = "extra == 'api'", specifier = "<3.0.0" }, { name = "questionary" }, { name = "rapidfuzz" }, { name = "rapidfuzz", marker = "extra == 'api'" }, - { name = "rapidfuzz", marker = "extra == 'viz'" }, { name = "requests" }, { name = "requests", marker = "extra == 'api'", specifier = "<3.0.0" }, { name = "requests-mock", marker = "extra == 'api'" }, - { name = "requests-mock", marker = "extra == 'viz'" }, { name = "responses", marker = "extra == 'api'" }, - { name = "responses", marker = "extra == 'viz'" }, { name = "rich" }, { name = "sqlalchemy", marker = "extra == 'api'", specifier = "<2.0.0" }, { name = "typer" }, { name = "uvicorn", extras = ["standard"], marker = "extra == 'api'", specifier = "<1.0.0" }, ] -provides-extras = ["viz-legacy", "viz", "api"] +provides-extras = ["carbonboard", "viz-legacy", "api"] [package.metadata.requires-dev] dev = [