mirror of
https://github.com/dtomlinson91/panaetius.git
synced 2025-12-22 04:55:44 +00:00
adding latest testing + docstrings
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
"""
|
||||||
|
panaetius - a utility library to read variables and provide convenient logging.
|
||||||
|
|
||||||
|
Author: Daniel Tomlinson (dtomlinson@panaetius.co.uk)
|
||||||
|
"""
|
||||||
|
|
||||||
from panaetius.config import Config
|
from panaetius.config import Config
|
||||||
from panaetius.library import set_config
|
from panaetius.library import set_config
|
||||||
from panaetius.logging import set_logger, SimpleLogger, AdvancedLogger, CustomLogger
|
from panaetius.logging import set_logger, SimpleLogger, AdvancedLogger, CustomLogger
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
"""
|
||||||
|
Access variables from a config file or an environment variable.
|
||||||
|
|
||||||
|
This module defines the `Config` class to interact and read variables from either a
|
||||||
|
`config.toml` or an environment variable.
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
@@ -11,9 +18,21 @@ from panaetius.exceptions import KeyErrorTooDeepException, InvalidPythonExceptio
|
|||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
"""docstring for Config()."""
|
"""The configuration class to access variables."""
|
||||||
|
|
||||||
def __init__(self, header_variable: str, config_path: str = "") -> None:
|
def __init__(self, header_variable: str, config_path: str = "") -> None:
|
||||||
|
"""
|
||||||
|
Create a Config object to set and access variables.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
header_variable (str): Your header variable name.
|
||||||
|
config_path (str, optional): The path where the header directory is stored.
|
||||||
|
Defaults to `~/.config`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
A header of `data_analysis` with a config_path of `~/myapps` will define
|
||||||
|
a config file in `~/myapps/data_analysis/config.toml`.
|
||||||
|
"""
|
||||||
self.header_variable = header_variable
|
self.header_variable = header_variable
|
||||||
self.config_path = (
|
self.config_path = (
|
||||||
pathlib.Path(config_path)
|
pathlib.Path(config_path)
|
||||||
@@ -29,6 +48,12 @@ class Config:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def config(self) -> dict:
|
def config(self) -> dict:
|
||||||
|
"""
|
||||||
|
Return the contents of the config file. If missing returns an empty dictionary.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The contents of the `.toml` loaded as a python dictionary.
|
||||||
|
"""
|
||||||
config_file_location = self.config_path / self.header_variable / "config.toml"
|
config_file_location = self.config_path / self.header_variable / "config.toml"
|
||||||
try:
|
try:
|
||||||
with open(config_file_location, "r", encoding="utf-8") as config_file:
|
with open(config_file_location, "r", encoding="utf-8") as config_file:
|
||||||
@@ -37,6 +62,36 @@ class Config:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_value(self, key: str, default: Any) -> Any:
|
def get_value(self, key: str, default: Any) -> Any:
|
||||||
|
"""
|
||||||
|
Get the value of a variable from the key name.
|
||||||
|
|
||||||
|
The key can either be one (`value`) or two (`data.value`) levels deep.
|
||||||
|
|
||||||
|
A key of (`value`) (with a header of `data_analysis`) would refer to a
|
||||||
|
`config.toml` of:
|
||||||
|
|
||||||
|
```
|
||||||
|
[data_analysis]
|
||||||
|
value = "some value"
|
||||||
|
```
|
||||||
|
|
||||||
|
or an environment variable of `DATA_ANALYSIS_VALUE="'some value'"`.
|
||||||
|
|
||||||
|
A key of (`data.value`) would refer to a `config.toml` of:
|
||||||
|
```
|
||||||
|
[data_analysis.data]
|
||||||
|
value = "some value"
|
||||||
|
```
|
||||||
|
or an environment variable of `DATA_ANALYSIS_DATA_VALUE="'some value'"`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key (str): The key of the variable.
|
||||||
|
default (Any): The default value if the key cannot be found in the config
|
||||||
|
file, or an environment variable.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: The value of the variable.
|
||||||
|
"""
|
||||||
env_key = f"{self.header_variable.upper()}_{key.upper().replace('.', '_')}"
|
env_key = f"{self.header_variable.upper()}_{key.upper().replace('.', '_')}"
|
||||||
|
|
||||||
if not self._missing_config:
|
if not self._missing_config:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
"""Exceptions for the module."""
|
||||||
|
|
||||||
|
|
||||||
class KeyErrorTooDeepException(Exception):
|
class KeyErrorTooDeepException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -5,5 +8,6 @@ class KeyErrorTooDeepException(Exception):
|
|||||||
class LoggingDirectoryDoesNotExistException(Exception):
|
class LoggingDirectoryDoesNotExistException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidPythonException(Exception):
|
class InvalidPythonException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"""Module to provide functionality when interacting with variables."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -9,6 +11,33 @@ def set_config(
|
|||||||
config_inst: Config,
|
config_inst: Config,
|
||||||
key: str,
|
key: str,
|
||||||
default: Any = None,
|
default: Any = None,
|
||||||
):
|
) -> None:
|
||||||
|
"""
|
||||||
|
Define a variable to be read from a `config.toml` or an environment variable.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_inst (Config): The instance of the `Config` class.
|
||||||
|
key (str): The key of the variable.
|
||||||
|
default (Any, optional): The default value if the key cannot be found in the config
|
||||||
|
file, or an environment variable. Defaults to None.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
`set_config(CONFIG, "value", default=[1, 2])` would look for a
|
||||||
|
`config.toml` with the following structure (with `CONFIG` having a header of
|
||||||
|
`data_analysis`):
|
||||||
|
|
||||||
|
```
|
||||||
|
[data_analysis]
|
||||||
|
value = "some value"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or an environment variable of `DATA_ANALYSIS_VALUE="'some value'"`.
|
||||||
|
|
||||||
|
If found, this value can be access with `CONFIG.value` which would return
|
||||||
|
`some_value`.
|
||||||
|
|
||||||
|
If neither the environment variable nor the `config.toml` are present, the
|
||||||
|
default of `[1, 2]` would be returned instead.
|
||||||
|
"""
|
||||||
config_var = key.lower().replace(".", "_")
|
config_var = key.lower().replace(".", "_")
|
||||||
setattr(config_inst, config_var, config_inst.get_value(key, default))
|
setattr(config_inst, config_var, config_inst.get_value(key, default))
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
"""Module to define a convenient logger instance with json formatted output."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
@@ -12,6 +14,50 @@ from panaetius.exceptions import LoggingDirectoryDoesNotExistException
|
|||||||
|
|
||||||
|
|
||||||
def set_logger(config_inst: Config, logging_format_inst: LoggingData) -> logging.Logger:
|
def set_logger(config_inst: Config, logging_format_inst: LoggingData) -> logging.Logger:
|
||||||
|
"""
|
||||||
|
Set and return a `logging.Logger` instance for quick logging.
|
||||||
|
|
||||||
|
`logging_format_inst` should be an instance of either SimpleLogger, AdvancedLogger,
|
||||||
|
or CustomLogger.
|
||||||
|
|
||||||
|
SimpleLogger and AdvancedLogger define a logging format and a logging level info.
|
||||||
|
|
||||||
|
CustomLogger defines a logging level info and should have a logging format passed
|
||||||
|
in.
|
||||||
|
|
||||||
|
Logging to a file is defined by a `logging.path` key set on `Config`. This path
|
||||||
|
should exist as it will not be created.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_inst (Config): The instance of the `Config` class.
|
||||||
|
logging_format_inst (LoggingData): The instance of the `LoggingData` class.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
LoggingDirectoryDoesNotExistException: If the logging directory specified does
|
||||||
|
not exist.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
logging.Logger: An configured instance of `logging.Logger` ready to be used.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
logger = set_logger(CONFIG, SimpleLogger())
|
||||||
|
|
||||||
|
logger.info("some logging message")
|
||||||
|
```
|
||||||
|
|
||||||
|
Would create a logging output of:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"time": "2021-10-18 02:26:24,037",
|
||||||
|
"logging_level":"INFO",
|
||||||
|
"message": "some logging message"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
"""
|
||||||
logger = logging.getLogger(config_inst.header_variable)
|
logger = logging.getLogger(config_inst.header_variable)
|
||||||
log_handler_sys = logging.StreamHandler(sys.stdout)
|
log_handler_sys = logging.StreamHandler(sys.stdout)
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ pylint:
|
|||||||
# disables TODO warnings
|
# disables TODO warnings
|
||||||
- fixme
|
- fixme
|
||||||
# !doc docstrings
|
# !doc docstrings
|
||||||
- missing-module-docstring
|
# - missing-module-docstring
|
||||||
- missing-class-docstring
|
# - missing-class-docstring
|
||||||
- missing-function-docstring
|
# - missing-function-docstring
|
||||||
# ! doc end of docstrings
|
# ! doc end of docstrings
|
||||||
# disables warnings about abstract methods not overridden
|
# disables warnings about abstract methods not overridden
|
||||||
- abstract-method
|
- abstract-method
|
||||||
@@ -67,23 +67,24 @@ pep257:
|
|||||||
disable:
|
disable:
|
||||||
# !doc docstrings
|
# !doc docstrings
|
||||||
# Missing docstring in __init__
|
# Missing docstring in __init__
|
||||||
- D107
|
# - D107
|
||||||
# Missing docstring in public module
|
# Missing docstring in public module
|
||||||
- D100
|
# - D100
|
||||||
# Missing docstring in public class
|
# Missing docstring in public class
|
||||||
- D101
|
# - D101
|
||||||
# Missing docstring in public method
|
# Missing docstring in public method
|
||||||
- D102
|
# - D102
|
||||||
# Missing docstring in public function
|
# Missing docstring in public function
|
||||||
- D103
|
# - D103
|
||||||
|
# Multi-line docstring summary should start at the second line
|
||||||
|
# - D213
|
||||||
|
# First word of the docstring should not be This
|
||||||
|
# - D404
|
||||||
|
# DEFAULT IGNORES
|
||||||
# 1 blank line required before class docstring
|
# 1 blank line required before class docstring
|
||||||
- D203
|
- D203
|
||||||
# Multi-line docstring summary should start at the first line
|
# Multi-line docstring summary should start at the first line
|
||||||
- D212
|
- D212
|
||||||
# Multi-line docstring summary should start at the second line
|
|
||||||
- D213
|
|
||||||
# First word of the docstring should not be This
|
|
||||||
- D404
|
|
||||||
# !doc end of docstrings
|
# !doc end of docstrings
|
||||||
# Section name should end with a newline
|
# Section name should end with a newline
|
||||||
- D406
|
- D406
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ Coding:
|
|||||||
✔ Check for a key > 2 levels, raise custom error, write test @done(21-10-17 23:30)
|
✔ Check for a key > 2 levels, raise custom error, write test @done(21-10-17 23:30)
|
||||||
|
|
||||||
Linting:
|
Linting:
|
||||||
☐ Check all functions and annotations.
|
✔ Check all functions and annotations. @done(21-10-18 01:07)
|
||||||
|
|
||||||
Docstrings:
|
Docstrings:
|
||||||
☐ Write the docstrings for public functions/methods.
|
✔ Write the docstrings for public functions/methods. @done(21-10-18 02:29)
|
||||||
|
|
||||||
Functionality:
|
Functionality:
|
||||||
✔ When both a config file and a env var is found, use the env var. @done(21-10-18 00:38)
|
✔ When both a config file and a env var is found, use the env var. @done(21-10-18 00:38)
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ if __name__ == "__main__":
|
|||||||
set_config(c, key="embedded.noexistbool", default=False)
|
set_config(c, key="embedded.noexistbool", default=False)
|
||||||
|
|
||||||
# logger = set_logger(c, SimpleLogger())
|
# logger = set_logger(c, SimpleLogger())
|
||||||
logger = set_logger(c, AdvancedLogger(logging_level="DEBUG"))
|
logger = set_logger(c, SimpleLogger(logging_level="DEBUG"))
|
||||||
logger.info("test logging message")
|
logger.info("some logging message")
|
||||||
logger.debug("debugging message")
|
logger.debug("debugging message")
|
||||||
for i in dir(c):
|
# for i in dir(c):
|
||||||
logger.debug(i + ": " + str(getattr(c, i)) + " - " + str(type(getattr(c, i))))
|
# logger.debug(i + ": " + str(getattr(c, i)) + " - " + str(type(getattr(c, i))))
|
||||||
|
|||||||
Reference in New Issue
Block a user