Skip to content

new ver #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions codegreen_core/tools/carbon_emission.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ def compute_ce(
runtime_minutes: int,
) -> tuple[float, pd.DataFrame]:
"""
Calculates the carbon footprint of a job, given its hardware configuration, time, and location.
Calculates the carbon footprint of a job, given the server details , start time and runtime.
This method returns an hourly time series of the carbon emissions.

The methodology is defined in the documentation.

:param server: A dictionary containing the details about the server, including its hardware specifications.
Expand All @@ -37,7 +36,7 @@ def compute_ce(
"""

# Round to the nearest hour (in minutes)
# base valued taken from http://calculator.green-algorithms.org/
# base values taken from http://calculator.green-algorithms.org/

rounded_runtime_minutes = round(runtime_minutes / 60) * 60
end_time = start_time + timedelta(minutes=rounded_runtime_minutes)
Expand Down
192 changes: 51 additions & 141 deletions codegreen_core/utilities/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,97 +11,24 @@ class Config:
config_file_path = None
section_name = "codegreen"
all_keys = [
{
"name":"ENTSOE_token",
"default": "None",
"use":"To fetch data from ENTSOE portal",
"boolean":False,
},
{
"name":"default_energy_mode",
"default":"public_data",
"use":"Determines which type of data to use.",
"boolean":False,
},
{
"name":"enable_energy_caching",
"default":"False",
"use":"To indicate if data used by tools must be cached",
"boolean":True,
},
{
"name":"energy_redis_path",
"default":"None",
"boolean":False,
"use":"Path to redis server to cache data.required if enable_energy_caching is enabled "
},
{
"name":"enable_time_prediction_logging",
"default":"False",
"boolean":True,
"use":"To indicate if logs must me saved in a log file "
},
{
"name":"log_folder_path",
"default":" ",
"boolean":False,
"use":"Path of the folder where logs will be stored"
},
{
"name":"offline_data_dir_path",
"default":"",
"boolean":False,
"use":"Path of the folder where bulk energy data will be stored"
},
{
"name":"enable_offline_energy_generation",
"default":"False",
"boolean":True,
"use":"To enable storing energy production data for available countries locally and in cache for quick access"
},
{
"name":"offline_data_start_date",
"default":"",
"boolean":False,
"use":"The start date for offline energy generation download,YYYY-mm-dd format"
},
{
"name":"generation_cache_hour",
"default":"72",
"boolean":False,
"use":"Indicate the number of hours in the past the data will be stored in the cache "
},

{
"name":"cron_refresh_offline_files_hour",
"default":"6",
"boolean":False,
"use":"time to setup cron for updating offline energy files"
},
{
"name":"cron_refresh_cache_hour",
"default":"6",
"boolean":False,
"use":"time to setup CRON job to update the energy generation cache"
},

{
"name":"enable_logging",
"default":"False",
"boolean":True,
"use":"Indicates if logging is enabled for the whole package"
},
{
"name":"log_folder_path",
"default":"",
"boolean":False,
"use":"The folder where log files will be stored. Log files name are of the format: 'year-month' "
}
{"name": "ENTSOE_token", "default": "None", "use": "To fetch data from ENTSOE portal", "boolean": False},
{"name": "default_energy_mode", "default": "public_data", "use": "Determines which type of data to use.", "boolean": False},
{"name": "enable_energy_caching", "default": "False", "use": "To indicate if data used by tools must be cached", "boolean": True},
{"name": "energy_redis_path", "default": "None", "boolean": False, "use": "Path to redis server to cache data."},
{"name": "enable_time_prediction_logging", "default": "False", "boolean": True, "use": "To indicate if logs must be saved."},
{"name": "log_folder_path", "default": "", "boolean": False, "use": "Path of the folder where logs will be stored"},
{"name": "offline_data_dir_path", "default": "", "boolean": False, "use": "Path where bulk energy data will be stored"},
{"name": "enable_offline_energy_generation", "default": "False", "boolean": True, "use": "Enable storing energy data locally"},
{"name": "offline_data_start_date", "default": "", "boolean": False, "use": "Start date for offline energy data"},
{"name": "generation_cache_hour", "default": "72", "boolean": False, "use": "Number of hours data will be cached"},
{"name": "cron_refresh_offline_files_hour", "default": "6", "boolean": False, "use": "CRON schedule for updating offline files"},
{"name": "cron_refresh_cache_hour", "default": "6", "boolean": False, "use": "CRON job to update energy cache"},
{"name": "enable_logging", "default": "False", "boolean": True, "use": "Enable logging for the package"}
]

@classmethod
def load_config(self, file_path=None):
"""to load configurations from the user config file"""
def load_config(cls, file_path=None):
"""Load configurations from a config file or environment variables."""
config_file_name = ".codegreencore.config"
config_locations = [
os.path.join(os.path.expanduser("~"), config_file_name),
Expand All @@ -111,63 +38,46 @@ def load_config(self, file_path=None):
if os.path.isfile(loc):
file_path = loc
break
cls.config_data = configparser.ConfigParser()
if file_path:
cls.config_data.read(file_path)
cls.config_file_path = file_path

if file_path is None:
raise ConfigError("Could not find the '.codegreencore.config' file. Please ensure that this file is created in the root folder of your project.")

self.config_data = configparser.ConfigParser()
self.config_data.read(file_path)
self.config_file_path = file_path

if self.section_name not in self.config_data:
self.config_data[self.section_name] = {}
raise ConfigError("Invalid config file. The config file must have a section called codegreen")
if cls.section_name not in cls.config_data:
raise ConfigError(f"Invalid config file. Missing required section: {cls.section_name}")
else:
cls.config_data[cls.section_name] = {}

for ky in self.all_keys:
try :
value = self.config_data.get(self.section_name, ky["name"])
# print(value)
except configparser.NoOptionError:
# print(ky)
self.config_data.set(self.section_name, ky["name"],ky["default"])

if self.get("enable_energy_caching") == True:
if self.get("energy_redis_path") is None:
raise ConfigError(
"Invalid configuration. If 'enable_energy_caching' is set, 'energy_redis_path' is also required "
)
for ky in cls.all_keys:
if cls.config_data.has_option(cls.section_name, ky["name"]):
value = cls.config_data.get(cls.section_name, ky["name"])
else:
r = redis.from_url(self.get("energy_redis_path"))
r.ping()
# print("Connection to redis works")
env_key = f"cgc_{ky['name']}"
value = os.getenv(env_key, ky["default"])
cls.config_data.set(cls.section_name, ky["name"], value)

if cls.get("enable_energy_caching"):
if not cls.get("energy_redis_path"):
raise ConfigError("'energy_redis_path' is required when 'enable_energy_caching' is enabled.")
redis.from_url(cls.get("energy_redis_path")).ping()

if self.get("enable_logging") == True:
if self.get("log_folder_path") is None:
raise ConfigError(
"Invalid configuration. If 'enable_logging' is set, 'log_folder_path' is also required "
)
else:
base_dir = self.get("log_folder_path")
os.makedirs(base_dir, exist_ok=True)
if cls.get("enable_logging"):
if not cls.get("log_folder_path"):
raise ConfigError("'log_folder_path' is required when 'enable_logging' is enabled.")
os.makedirs(cls.get("log_folder_path"), exist_ok=True)

@classmethod
def get(self, key):
if not self.config_data.sections():
raise ConfigError(
"Configuration not loaded. Please call 'load_config' first."
)
try:
value = self.config_data.get(self.section_name, key)
config = next((d for d in self.all_keys if d.get("name") == key), None)
if config["boolean"]:
return value.lower() == "true"
return value
except (configparser.NoSectionError, configparser.NoOptionError) as e:
print("Config not found")
print(key)
raise e

def get(cls, key):
if not cls.config_data.sections():
raise ConfigError("Configuration not loaded. Call 'load_config' first.")

value = cls.config_data.get(cls.section_name, key, fallback=None)
config = next((d for d in cls.all_keys if d["name"] == key), None)
if config and config["boolean"]:
return value.lower() == "true"
return value

@classmethod
def get_config_file_path(self):
"""Returns the path of the config file"""
return self.config_file_path
def get_config_file_path(cls):
"""Returns the path of the config file."""
return cls.config_file_path
Loading