fire2a

Hello World 👋🌎 This is Forest Fire Analytics 🌲🔥🧠

When developing fire2a, AVOID writing code like this:

from fire2a.module import function

Use this instead:

from .module import function

UNTIL WE CAN DISTRIBUTE ON PYPI!!

This is fire2a-lib distribution, fire2a package docstring More info on:

fire2a.github.io/fire2a-lib  
fire2a.github.io/docs  
www.fire2a.com
  1#!python3
  2"""Hello World 👋🌎
  3This is Forest Fire Analytics 🌲🔥🧠
  4
  5When developing fire2a, AVOID writing code like this: 
  6    
  7    from fire2a.module import function 
  8
  9Use this instead:
 10
 11    from .module import function
 12
 13UNTIL WE CAN DISTRIBUTE ON PYPI!!
 14 
 15This is fire2a-lib distribution, fire2a package docstring
 16More info on:
 17
 18    fire2a.github.io/fire2a-lib  
 19    fire2a.github.io/docs  
 20    www.fire2a.com  
 21"""  # fmt: skip
 22__author__ = "Fernando Badilla"
 23__revision__ = "$Format:%H$"
 24
 25import logging
 26from importlib.metadata import PackageNotFoundError, distribution
 27from pathlib import Path
 28from typing import Any, Dict, List, Tuple, Union
 29
 30logger = logging.getLogger(__name__)
 31
 32try:
 33    __version__ = distribution("fire2a-lib").version
 34    version_from = "importlib"
 35except PackageNotFoundError:
 36    if (Path(__file__).parent / "_version.py").exists():
 37        from ._version import __version__
 38
 39        version_from = "_version.py"
 40    else:
 41        __version__ = "0.0.0"
 42        version_from = "fallback"
 43
 44# logger.warning("%s Package version: %s, from %s", __name__, __version__, version_from)
 45
 46
 47
 48def setup_logger(name: str = __name__, verbosity: int = 0, logfile: Path = None):
 49    r"""Capture the logger and setup name, verbosity, stream handler & rotating logfile if provided.
 50    Args:
 51        name (str, optional): Name of the logger. Defaults to \__name __ 
 52        verbosity (str | int): Verbosity level, implemented, WARNING:1, INFO:2 (default), or DEBUG:3
 53        logfile (Path, optional): Create a -rotated- logfile (5 files, 25MB each).
 54    Returns:
 55        logger (Logger):  All code in this pkg uses logger.info("..."), logger.debug, etc.
 56
 57    ## Developers implementing their own logger
 58        * All fire2a modules uses `logger = logging.getLogger(__name__)`
 59
 60    # Regular Usage Guideline  
 61    logging.critical("Something went wrong, exception info?", exc_info=True)  
 62    logging.error("Something went wrong, but we keep going?")  
 63    logging.warning("Default message level")  
 64    logging.info("Something planned happened")  
 65    logging.debug("Details of the planned thing that happened")  
 66    print("Normal program output, not logged")
 67    """  # fmt: skip
 68    # Capture the logger
 69    if name:
 70        # specific logger
 71        logger = logging.getLogger(name)
 72    else:
 73        # root logger
 74        logger = logging.getLogger()
 75
 76    # Create a stream handler
 77    import sys
 78
 79    stream_handler = logging.StreamHandler(sys.stdout)
 80
 81    # Create a rotating file handler
 82    if logfile:
 83        from logging.handlers import RotatingFileHandler
 84
 85        rf_handler = RotatingFileHandler(logfile, maxBytes=25 * 1024, backupCount=5)
 86
 87    # Set the logs level
 88    if verbosity in ["CRITICAL", "FATAL"] or verbosity == -1:
 89        level = logging.CRITICAL
 90    elif verbosity == "ERROR" or verbosity == 0:
 91        level = logging.WARNING
 92    elif verbosity == "WARNING" or verbosity == 1:
 93        level = logging.WARNING
 94    elif verbosity == "INFO" or verbosity == 2:
 95        level = logging.INFO
 96    elif verbosity == "DEBUG" or verbosity == 3:
 97        level = logging.DEBUG
 98    else:
 99        level = logging.DEBUG
100    logger.setLevel(level)
101    stream_handler.setLevel(level)
102    if logfile:
103        rf_handler.setLevel(level)
104
105    # formatter
106    # "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)d %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
107    formatter = logging.Formatter(
108        "%(asctime)s %(levelname)s %(name)s %(message)s",
109        datefmt="%Y-%m-%d %H:%M:%S",
110    )
111    stream_handler.setFormatter(formatter)
112    if logfile:
113        rf_handler.setFormatter(formatter)
114
115    # Add the handlers to the logger
116    logger.addHandler(stream_handler)
117    if logfile:
118        logger.addHandler(rf_handler)
119    logger.debug("Logger initialized @level %s", logging.getLevelName(level))
120
121    return logger
122
123
124def setup_file(name="unknown", filepath=Path().cwd()):
125    """Setups the NAME and FILEPATH variables for modules
126    Tries getting them from __main__.__file__ and __main__.__package__
127    If it's the __main__ entry point, tries to use the package name
128    Args:
129        main: __main__ from the calling script
130        name: if fails, returns name (default "unknown")
131        here: if fails, returns here Path (default "cwd")
132    """
133    import __main__
134
135    if filestr := getattr(__main__, "__file__", None):
136        file = Path(filestr)
137        NAME = file.stem
138        if NAME == "__main__":
139            if package := getattr(__main__, "__package__", None):
140                NAME = package + "_main"
141            else:
142                NAME = name
143        FILEPATH = file.parent
144    else:
145        NAME = name
146        FILEPATH = filepath
147    logger.warning("setup_file(%s, %s) __main__:%s", NAME, FILEPATH, __main__)
148    return NAME, FILEPATH
logger = <Logger fire2a (WARNING)>
def setup_logger( name: str = 'fire2a', verbosity: int = 0, logfile: pathlib.Path = None):
 49def setup_logger(name: str = __name__, verbosity: int = 0, logfile: Path = None):
 50    r"""Capture the logger and setup name, verbosity, stream handler & rotating logfile if provided.
 51    Args:
 52        name (str, optional): Name of the logger. Defaults to \__name __ 
 53        verbosity (str | int): Verbosity level, implemented, WARNING:1, INFO:2 (default), or DEBUG:3
 54        logfile (Path, optional): Create a -rotated- logfile (5 files, 25MB each).
 55    Returns:
 56        logger (Logger):  All code in this pkg uses logger.info("..."), logger.debug, etc.
 57
 58    ## Developers implementing their own logger
 59        * All fire2a modules uses `logger = logging.getLogger(__name__)`
 60
 61    # Regular Usage Guideline  
 62    logging.critical("Something went wrong, exception info?", exc_info=True)  
 63    logging.error("Something went wrong, but we keep going?")  
 64    logging.warning("Default message level")  
 65    logging.info("Something planned happened")  
 66    logging.debug("Details of the planned thing that happened")  
 67    print("Normal program output, not logged")
 68    """  # fmt: skip
 69    # Capture the logger
 70    if name:
 71        # specific logger
 72        logger = logging.getLogger(name)
 73    else:
 74        # root logger
 75        logger = logging.getLogger()
 76
 77    # Create a stream handler
 78    import sys
 79
 80    stream_handler = logging.StreamHandler(sys.stdout)
 81
 82    # Create a rotating file handler
 83    if logfile:
 84        from logging.handlers import RotatingFileHandler
 85
 86        rf_handler = RotatingFileHandler(logfile, maxBytes=25 * 1024, backupCount=5)
 87
 88    # Set the logs level
 89    if verbosity in ["CRITICAL", "FATAL"] or verbosity == -1:
 90        level = logging.CRITICAL
 91    elif verbosity == "ERROR" or verbosity == 0:
 92        level = logging.WARNING
 93    elif verbosity == "WARNING" or verbosity == 1:
 94        level = logging.WARNING
 95    elif verbosity == "INFO" or verbosity == 2:
 96        level = logging.INFO
 97    elif verbosity == "DEBUG" or verbosity == 3:
 98        level = logging.DEBUG
 99    else:
100        level = logging.DEBUG
101    logger.setLevel(level)
102    stream_handler.setLevel(level)
103    if logfile:
104        rf_handler.setLevel(level)
105
106    # formatter
107    # "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)d %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
108    formatter = logging.Formatter(
109        "%(asctime)s %(levelname)s %(name)s %(message)s",
110        datefmt="%Y-%m-%d %H:%M:%S",
111    )
112    stream_handler.setFormatter(formatter)
113    if logfile:
114        rf_handler.setFormatter(formatter)
115
116    # Add the handlers to the logger
117    logger.addHandler(stream_handler)
118    if logfile:
119        logger.addHandler(rf_handler)
120    logger.debug("Logger initialized @level %s", logging.getLevelName(level))
121
122    return logger

Capture the logger and setup name, verbosity, stream handler & rotating logfile if provided. Args: name (str, optional): Name of the logger. Defaults to __name __ verbosity (str | int): Verbosity level, implemented, WARNING:1, INFO:2 (default), or DEBUG:3 logfile (Path, optional): Create a -rotated- logfile (5 files, 25MB each). Returns: logger (Logger): All code in this pkg uses logger.info("..."), logger.debug, etc.

Developers implementing their own logger

* All fire2a modules uses `logger = logging.getLogger(__name__)`

Regular Usage Guideline

logging.critical("Something went wrong, exception info?", exc_info=True)
logging.error("Something went wrong, but we keep going?")
logging.warning("Default message level")
logging.info("Something planned happened")
logging.debug("Details of the planned thing that happened")
print("Normal program output, not logged")

def setup_file(name='unknown', filepath=PosixPath('/__w/fire2a-lib/fire2a-lib')):
125def setup_file(name="unknown", filepath=Path().cwd()):
126    """Setups the NAME and FILEPATH variables for modules
127    Tries getting them from __main__.__file__ and __main__.__package__
128    If it's the __main__ entry point, tries to use the package name
129    Args:
130        main: __main__ from the calling script
131        name: if fails, returns name (default "unknown")
132        here: if fails, returns here Path (default "cwd")
133    """
134    import __main__
135
136    if filestr := getattr(__main__, "__file__", None):
137        file = Path(filestr)
138        NAME = file.stem
139        if NAME == "__main__":
140            if package := getattr(__main__, "__package__", None):
141                NAME = package + "_main"
142            else:
143                NAME = name
144        FILEPATH = file.parent
145    else:
146        NAME = name
147        FILEPATH = filepath
148    logger.warning("setup_file(%s, %s) __main__:%s", NAME, FILEPATH, __main__)
149    return NAME, FILEPATH

Setups the NAME and FILEPATH variables for modules Tries getting them from __main__.__file__ and __main__.__package__ If it's the __main__ entry point, tries to use the package name Args: main: __main__ from the calling script name: if fails, returns name (default "unknown") here: if fails, returns here Path (default "cwd")