Source code for pygeodes.utils.config
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""This module allows users to configure pygeodes"""
# -----------------------------------------------------------------------------
# Copyright (c) 2024, CNES
#
# REFERENCES:
# https://cnes.fr/
# -----------------------------------------------------------------------------
# stdlib imports -------------------------------------------------------
import sys
from dataclasses import dataclass, fields, asdict
from typing import Literal
from pathlib import Path, PosixPath
import warnings
# third-party imports -----------------------------------------------
# local imports ---------------------------------------------------
from pygeodes.utils.io import load_json, file_exists
from pygeodes.utils.dataclasses_utils import class_from_args
from pygeodes.utils.logger import logger
from pygeodes.utils.consts import (
CONFIG_DEFAULT_FILENAME,
DEFAULT_LOGGING_LEVEL,
DEFAULT_S3_REGION_NAME,
)
from pygeodes.utils.exceptions import MissingConfParamException
[docs]def notebook_environment() -> bool:
"""Checks if pygeodes is being used in a notebook environment or not
Returns
-------
bool
wether we are in a notebook or not
"""
return "ipykernel" in sys.modules
[docs]@dataclass
class Config:
"""This class helps the user configuring Geodes"""
api_key: str = None # api_key not always required
logging_level: Literal["DEBUG", "INFO"] = DEFAULT_LOGGING_LEVEL
download_dir: str = "."
checksum_error: bool = True
use_async_requests: bool = True
aws_access_key_id: str = None
aws_secret_access_key: str = None
aws_session_token: str = None # ajouter profil à la place
region_name: str = DEFAULT_S3_REGION_NAME
@property
def s3_parameters(self) -> dict:
"""Returns all the conf params related to AWS S3
Returns
-------
dict
the parameters
"""
members_names = [
"aws_access_key_id",
"aws_secret_access_key",
"aws_session_token",
"region_name",
]
return {name: getattr(self, name) for name in members_names}
[docs] def has_s3_parameters(self) -> bool:
"""Returns wether the conf object has s3 parameters with not-None values
Returns
-------
bool
wether the conf has S3 parameters
"""
params = self.s3_parameters
for member_name, value in params.items():
if value is None:
return False
return True
[docs] def check_s3_config(self):
"""Checks if the current conf has s3 parameters
Raises
------
MissingConfParamException
"""
params = self.s3_parameters
for member_name, value in params.items():
if value is None:
raise MissingConfParamException(
f"To use S3 you need to specify these conf parameters : {', '.join(list(params.keys()))} ({member_name} is None)"
)
[docs] def to_dict(self) -> dict:
"""Returns the config in Python dict format
Returns
-------
dict
the config in dict
"""
return {
k: str(v) if isinstance(v, PosixPath) else v
for k, v in asdict(self).items()
}
def __post_init__(self):
"""This is executed after creating a Config object, to correct somethings"""
if self.download_dir is not None:
self.download_dir = str(Path(self.download_dir).resolve())
# to deactivate async requests if we are in a notebook environment
if notebook_environment():
self.use_async_requests = False
@property
def has_api_key(self) -> bool:
"""Returns wether the current config has an api key
Returns
-------
bool
Returns wether the current config has an api key
"""
return self.api_key is not None
@classmethod
def _check_config_file(cls, content: dict, filepath: str):
"""Opens a filepath to check if its content is suited to load a conf from
Parameters
----------
content : dict
the content of the file
filepath : str
the filepath of the file
"""
cls_fields = set([f.name for f in fields(cls) if f.init])
content_fields = set(content.keys())
if len(content_fields) > len(cls_fields):
useless_keys = content_fields - cls_fields
warnings.warn(
f"Config file {filepath} contains useless keys ({', '.join(list(useless_keys))})"
)
@classmethod
def _read_info_from_file(cls, file: str):
"""Reads info from a JSON filepath and returns a Config
Parameters
----------
file : str
the JSON filepath
Returns
-------
Config
the config object returned
"""
content = load_json(file)
cls._check_config_file(content, file)
logger.debug(f"Loaded conf from file {file}")
return class_from_args(Config, content)
[docs] @classmethod
def from_file(cls, file: str = CONFIG_DEFAULT_FILENAME):
"""Checks if a filepath exists and reads info from a it and returns a Config
Parameters
----------
file : str, optional
the filepath, by default CONFIG_DEFAULT_FILENAME
Returns
-------
Config
the config object
"""
if file_exists(file, True):
return cls._read_info_from_file(file)