Skip to content

Commit

Permalink
clean code
Browse files Browse the repository at this point in the history
  • Loading branch information
Joaopeuko committed Apr 27, 2024
1 parent 1d18adb commit 4730bcf
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 54 deletions.
24 changes: 12 additions & 12 deletions secured/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def __init__(self, *args, secure: bool = False, message: str = "<Sensitive data
Args:
*args: Variable length argument list for dictionary items.
secure (bool): If True, non-dict values will be wrapped by the Secure class with the given message.
message (str): Custom message used when values are secured.
secure: If True, non-dict values will be wrapped by the Secure class with the given message.
message: Custom message used when values are secured.
**kwargs: Arbitrary keyword arguments for dictionary items.
"""
super().__init__(*args, **kwargs)
Expand All @@ -43,31 +43,31 @@ def _convert_dicts(self) -> None:
for key, value in list(self.items()):
self[key] = self._convert_value(value)

def _convert_value(self, value: Any) -> Union[T, 'Secure']:
def _convert_value(self, value: Any) -> T | Secure:
"""
Converts and possibly secures the value based on its type and the secure setting.
Args:
value (Any): The value to be converted and possibly secured.
value: The value to be converted and possibly secured.
Returns:
Union[T, Secure]: The converted value, secured if `secure` is True and not a dictionary.
The converted value, secured if `secure` is True and not a dictionary.
"""
if isinstance(value, dict):
return AttrDict(value, secure=self.secure, message=self.message)
elif self.secure:
return Secure(value, self.message)
return value

def __getattr__(self, item: str) -> Union[T, 'Secure']:
def __getattr__(self, item: str) -> T | Secure:
"""
Enables attribute-style access to dictionary keys.
Args:
item (str): The attribute/key name to access.
item: The attribute/key name to access.
Returns:
Union[T, Secure]: The value associated with 'item'.
The value associated with 'item'.
Raises:
AttributeError: If the attribute does not exist.
Expand All @@ -82,8 +82,8 @@ def __setattr__(self, key: str, value: Any) -> None:
Sets the attribute or dictionary key to the specified value.
Args:
key (str): Attribute name or dictionary key.
value (Any): The value to set for the given key.
key: Attribute name or dictionary key.
value: The value to set for the given key.
This directly modifies the dictionary if `key` is not a special attribute.
"""
Expand All @@ -97,7 +97,7 @@ def __setitem__(self, key: str, value: Any) -> None:
Overrides the method to secure values when being set through item assignment.
Args:
key (str): The dictionary key where the value should be set.
value (Any): The value to set, which will be secured if applicable.
key: The dictionary key where the value should be set.
value: The value to set, which will be secured if applicable.
"""
super().__setitem__(key, self._convert_value(value))
14 changes: 14 additions & 0 deletions secured/log_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import logging

def setup_default_logger():
"""
Setup a default logger with basic configuration.
"""
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
if not logger.handlers:
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
return logger
15 changes: 7 additions & 8 deletions secured/secure.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from typing import Union

class Secure(str):
"""
Expand All @@ -9,7 +8,7 @@ class Secure(str):
with a specific message.
Attributes:
message (str): Custom message to represent the secured data when printed or logged.
message: Custom message to represent the secured data when printed or logged.
Example:
>>> DATABASE_URL = "your_actual_database_url"
Expand All @@ -23,8 +22,8 @@ def __new__(cls, original: str, message: str = "<Sensitive data secured>"):
Create a new Secure instance that appears as a custom message.
Args:
original (str): The original string to secure.
message (str): A placeholder message to display instead of the original content.
original: The original string to secure.
message: A placeholder message to display instead of the original content.
Returns:
Secure: A new Secure instance displaying the placeholder message.
Expand All @@ -38,8 +37,8 @@ def __init__(self, original: str, message: str = "<Sensitive data secured>"):
need to handle the data directly.
Args:
original (str): The original data to secure.
message (str): A custom message to use for representing the secured data.
original: The original data to secure.
message: A custom message to use for representing the secured data.
"""
super().__init__()
self.original = original
Expand All @@ -63,7 +62,7 @@ def __str__(self) -> str:
"""
return self.__repr__()

def to_int(self) -> Union[int, str]:
def to_int(self) -> int | str:
"""
Try converting the original secured data to an integer.
Expand All @@ -75,7 +74,7 @@ def to_int(self) -> Union[int, str]:
except ValueError:
return self.message

def to_float(self) -> Union[float, str]:
def to_float(self) -> float | str:
"""
Try converting the original secured data to a float.
Expand Down
65 changes: 31 additions & 34 deletions secured/secured.py
Original file line number Diff line number Diff line change
@@ -1,59 +1,60 @@
import os
import yaml
from typing import Union, List, Any
from typing import List

from .log_manager import setup_default_logger
from .secure import Secure
from pathlib import Path
from .attribute import AttrDict

class Secured:
def __init__(self, yaml_paths: Union[str, List[str]] = None, secure: bool = False,
as_attrdict: bool = True, message: str = "<Sensitive data secured>"):
def __init__(self, yaml_paths: str | List[str] = None, secure: bool = False,
as_attrdict: bool = True, message: str = "<Sensitive data secured>", logger=None):
"""
Initialize a Secured object to manage YAML configuration securely.
Args:
yaml_paths (Union[str, List[str]], optional): Paths to YAML files that should be loaded.
secure (bool, optional): Flag to determine if data should be secured. Defaults to False.
as_attrdict (bool, optional): If True, loaded data will be stored as AttrDict objects. Defaults to True.
message (str, optional): Custom message to use when data is secured. Defaults to "<Sensitive data secured>".
Loads YAML files, creates configuration as specified by flags, and handles data securely if requested.
yaml_paths: Paths to YAML files that should be loaded.
secure: Flag to determine if data should be secured. Defaults to False.
as_attrdict: If True, loaded data will be stored as AttrDict objects. Defaults to True.
message: Custom message to use when data is secured. Defaults to "<Sensitive data secured>".
logger: External logger for logging messages, can be None. If None, a default logger is created.
"""
self.as_attrdict = as_attrdict
self.secure = secure
self.message = message # Custom message for secured data
self.message = message
self.logger = logger or setup_default_logger()
self.load_yaml(yaml_paths=yaml_paths, secure=secure)

def load_yaml(self, yaml_paths: Union[str, List[str]], secure: bool) -> None:

def load_yaml(self, yaml_paths: str | List[str], secure: bool) -> None:
"""
Load and process YAML files from specified paths.
Args:
yaml_paths (Union[str, List[str]]): Paths to the YAML configuration files.
secure (bool): Indicates if the data should be secured.
yaml_paths: Paths to the YAML configuration files.
secure: Indicates if the data should be secured.
Processes each YAML file, converting content to AttrDict or secure data structures as required.
"""
if not yaml_paths:
return
if isinstance(yaml_paths, str):
yaml_paths = [yaml_paths]
return
yaml_paths = [yaml_paths] if isinstance(yaml_paths, str) else yaml_paths

for path in yaml_paths:
try:
with open(path, 'r') as file:
file_data = yaml.safe_load(file)
file_name = Path(path).stem.replace('-', '_')
setattr(self, file_name, self.create_config(file_data, secure=secure))
except FileNotFoundError:
print(f"Error: File {path} not found.")
self.logger.error(f"File {path} not found.")
continue
except yaml.YAMLError as e:
print(f"Error parsing YAML file {path}: {e}")
self.logger.error(f"Error parsing YAML file {path}: {e}")
continue

file_name = Path(path).stem.replace('-', '_')
setattr(self, file_name, self.create_config(file_data, secure=secure))

def create_config(self, data: dict, secure: bool) -> Union[AttrDict, dict]:
def create_config(self, data: dict, secure: bool) -> AttrDict | dict[str, Secure]:
"""
Create a configuration from data loaded from a YAML file.
Expand Down Expand Up @@ -82,29 +83,25 @@ def _recursive_dict(self, data: dict) -> dict:
"""
return {key: self._recursive_dict(val) if isinstance(val, dict) else val for key, val in data.items()}

def get(self, key: str, required: bool = False, secure: bool = False) -> Secure | None:
def get(self, key: str, required: bool = False) -> Secure | None:
"""
Retrieve configuration value by key, optionally securing it.
Retrieve configuration value by key, securing it.
Args:
key (str): The key for the configuration value.
required (bool, optional): Whether the key is required (raises an error if not found).
secure (bool, optional): Whether to secure the returned value.
Returns:
Any: The value associated with the key, optionally secured.
The value associated with the key, secured.
Raises:
ValueError: If the key is required but not found.
ValueError: If the key is required but not found.
"""
attr_value = getattr(self, key, None)
if attr_value is not None:
return Secure(attr_value, self.message) if secure and not isinstance(attr_value, (AttrDict, dict)) else attr_value
env_value = os.getenv(key)
if env_value is not None:
return Secure(env_value, self.message) if secure else env_value
return Secure(env_value, self.message)
if required:
raise ValueError(f"Key '{key}' not found in configuration or OS environment.")
self.logger.error(f"Key '{key}' not found in configuration or OS environment.")
raise ValueError(f"Key '{key}' not found.")
return None

def use_attrdict(self, use: bool) -> None:
Expand Down

0 comments on commit 4730bcf

Please sign in to comment.