11import os
2+ import signal
23import sys
34import time
45from pathlib import Path
2324)
2425from codecarbon .core .api_client import ApiClient , get_datetime_with_timezone
2526from codecarbon .core .schemas import ExperimentCreate , OrganizationCreate , ProjectCreate
26- from codecarbon .emissions_tracker import EmissionsTracker
27+ from codecarbon .emissions_tracker import EmissionsTracker , OfflineEmissionsTracker
2728
2829AUTH_CLIENT_ID = os .environ .get (
2930 "AUTH_CLIENT_ID" ,
@@ -336,28 +337,55 @@ def monitor(
336337 api : Annotated [
337338 bool , typer .Option (help = "Choose to call Code Carbon API or not" )
338339 ] = True ,
340+ offline : Annotated [bool , typer .Option (help = "Run in offline mode" )] = False ,
341+ country_iso_code : Annotated [
342+ str , typer .Option (help = "3-letter country ISO code for offline mode" )
343+ ] = None ,
344+ region : Annotated [
345+ str , typer .Option (help = "Region/province for offline mode" )
346+ ] = None ,
339347):
340- """Monitor your machine's carbon emissions.
348+ """Monitor your machine's carbon emissions."""
349+ if offline :
350+ if not country_iso_code :
351+ print (
352+ "ERROR: country_iso_code is required for offline mode" , file = sys .stderr
353+ )
354+ raise typer .Exit (1 )
341355
342- Args:
343- measure_power_secs (Annotated[int, typer.Argument, optional): Interval between two measures. Defaults to 10.
344- api_call_interval (Annotated[int, typer.Argument, optional): Number of measures before calling API. Defaults to 30.
345- api (Annotated[bool, typer.Option, optional): Choose to call Code Carbon API or not. Defaults to True.
346- """
347- experiment_id = get_existing_local_exp_id ()
348- if api :
349- if experiment_id is None :
356+ tracker = OfflineEmissionsTracker (
357+ measure_power_secs = measure_power_secs ,
358+ country_iso_code = country_iso_code ,
359+ region = region ,
360+ )
361+ else :
362+ experiment_id = get_existing_local_exp_id ()
363+ if api and experiment_id is None :
350364 print (
351365 "ERROR: No experiment id, call 'codecarbon config' first." ,
352366 file = sys .stderr ,
353367 )
368+ raise typer .Exit (1 )
369+
370+ tracker = EmissionsTracker (
371+ measure_power_secs = measure_power_secs ,
372+ api_call_interval = api_call_interval ,
373+ save_to_api = api ,
374+ )
375+
376+ def signal_handler (signum , frame ):
377+ print ("\n Received signal to stop. Saving emissions data..." )
378+ tracker .stop ()
379+ sys .exit (0 )
380+
381+ signal .signal (signal .SIGINT , signal_handler )
382+ signal .signal (signal .SIGTERM , signal_handler )
383+
354384 print ("CodeCarbon is going in an infinite loop to monitor this machine." )
355- with EmissionsTracker (
356- measure_power_secs = measure_power_secs ,
357- api_call_interval = api_call_interval ,
358- save_to_api = api ,
359- ) as tracker :
360- # Infinite loop
385+ print ("Press Ctrl+C to stop and save emissions data." )
386+
387+ tracker .start ()
388+ try :
361389 while True :
362390 if (
363391 hasattr (tracker , "_another_instance_already_running" )
@@ -366,6 +394,10 @@ def monitor(
366394 print ("Another instance of CodeCarbon is already running. Exiting." )
367395 break
368396 time .sleep (300 )
397+ except Exception as e :
398+ print (f"\n Error occurred: { e } " )
399+ tracker .stop ()
400+ raise e
369401
370402
371403def questionary_prompt (prompt , list_options , default ):
0 commit comments