Source code for elevaso_spine.environ.load

"""
.. module:: load
    :platform: Unix, Windows
    :synopsis: Load environment variables into memory/session
"""

# Python Standard Libraries
import logging
import os
import re
from typing import Tuple, Pattern

# 3rd Party Libraries


# Project Specific Libraries
from elevaso_spine.app import caller
from elevaso_spine.environ import var
from elevaso_spine.fobj import find_obj

LOGGER = logging.getLogger(__name__)

KEY_VALUE_REGEX = re.compile(r"^(?P<key>[\w\d]+)\s*=\s*(?P<value>[^#]+)")


[docs] def load_env( prefix: str = None, path: str = None, overwrite: bool = False, search_dirs: int = 4, ): """Load a .env file into Environment Variables Args: prefix (str, Optional): Prefix of the file, defaults to None .. note:: Useful if you want to have a dev.env, test.env, prod.env setup path (str, Optional): Base path to start searching for env files, defaults to None .. note:: If None, then will lookup the calling python functions path overwrite (bool, Optional): True/False if existing environment variables should be overwritten by .env file content, defaults to False search_dirs (int, Optional): Number of parent directories to traverse, defaults to 4 """ if not path: _, path = caller.get_caller() file_name = ".".join([prefix or "", "env"]) env_content = None file_path = find_obj.find(path, file_name, search_dirs) if file_path: with open(os.path.join(file_path, file_name), "r") as file: env_content = file.read() or "" for enum, item in enumerate(env_content.split("\n")): __check(item, enum, set_val=True, overwrite=overwrite)
def __check( content: str, line_num: int = None, set_val: bool = True, overwrite: bool = False, ) -> bool: """Check if environment variable should be set Args: content (str): String in <ENV>=<VAL> format line_num (int, Optional): Line number (if processing from file) set_val (bool, Optional): True/False to execute the set_env_var function if content is valid overwrite (bool, Optional): True/False if existing environment variables should be overwritten by .env file content, defaults to False Returns: bool: True/False if set """ line_num_text = f"Line number {line_num}" if line_num else "Content" content = content.strip() if __valid(content, line_num_text): key, value = split_key_val(content) if key: return var.set_var(key, value, overwrite, set_val) LOGGER.debug( "%(line_num_text)s does not match [\\w\\d]=[^#], skipping", {"line_num_text": line_num_text} ) return False def __valid(content: str, line_num_text: str) -> bool: """Checks if the content is valid for continuing Args: content (str): String in <ENV>=<VAL> format line_num_text (str): Text to display in logging Returns: bool: True/False if content is valid for continuing """ if len(content) == 0 or content is None: LOGGER.debug( "%(line_num_text)s is blank, skipping", {"line_num_text": line_num_text}, ) elif content[0] == "#": LOGGER.debug( "%(line_num_text)s is comment, skipping", {"line_num_text": line_num_text}, ) else: return True return False # TODO Move this to anvil for ANV-3 def split_key_val( content: str, pattern: Pattern = KEY_VALUE_REGEX ) -> Tuple[str, str]: """Function to split a string into Key/Value pair Args: content (str): String to split pattern (Pattern, Optional): Regular Expression Pattern for splitting string, defaults to KEY=VAL expression Returns: str, str: Tuple of Key and Value """ if pattern.match(content): match_set = pattern.match(content) return match_set.group("key").strip(), match_set.group("value").strip() return None, None