pawnlib.config package
Submodules
pawnlib.config.configure module
from pawnlib.config import configure
- class Config(config_path=None, logger=None)[source]
Bases:
object- CONFIG_DEFAULT_FILE = 'configure.json'
- load_config(config_path)[source]
Load User configuration file. :type config_path:
Path:param config_path: The str path created with pathlib.Path is recommended.
pawnlib.config.globalconfig module
from pawnlib.config import globalconfig
- class ConfigHandler(config_file='config.ini', args=None, allowed_env_keys=None, env_prefix=None, section_pattern=None, defaults=None)[source]
Bases:
objectInitialize the ConfigHandler with a config file, command-line arguments, and environment variables. Only environment variables specified in allowed_env_keys or with env_prefix are considered. Additionally, environment variables corresponding to keys in args or config.ini are included.
- Parameters:
config_file (str) – Path to the configuration file. |default|
'config.ini'args (Namespace, optional) – Parsed command-line arguments. |default|
Noneallowed_env_keys (list, optional) – List of environment variable keys to allow (case-insensitive). |default|
Noneenv_prefix (str, optional) – Prefix for environment variables to include (case-insensitive). |default|
Nonesection_pattern (optional) – Regex for find a section name |default|
Nonedefaults (dict, optional) – Default values for configuration keys. |default|
None
- __init__(config_file='config.ini', args=None, allowed_env_keys=None, env_prefix=None, section_pattern=None, defaults=None)[source]
Initialize the ConfigHandler with a config file, command-line arguments, and environment variables. Only environment variables specified in allowed_env_keys or with env_prefix are considered. Additionally, environment variables corresponding to keys in args or config.ini are included.
- Parameters:
config_file (str) – Path to the configuration file. |default|
'config.ini'args (Namespace, optional) – Parsed command-line arguments. |default|
Noneallowed_env_keys (list, optional) – List of environment variable keys to allow (case-insensitive). |default|
Noneenv_prefix (str, optional) – Prefix for environment variables to include (case-insensitive). |default|
Nonesection_pattern (optional) – Regex for find a section name |default|
Nonedefaults (dict, optional) – Default values for configuration keys. |default|
None
- get(key, default=None)[source]
Get a value with the following priority: 1. Command-line arguments (args) 2. Environment variables (env) 3. Config file (config.ini) 4. Code defaults
- Parameters:
key (str) – The configuration key to retrieve.
default (optional) – The default value if the key is not found. |default|
None
- Returns:
The value associated with the key.
- as_dict()[source]
Returns the final merged configuration as a dictionary with all keys in lowercase. Priority: args > env > config.ini > code defaults
- Returns:
Merged configuration with lowercase keys.
- Return type:
dict
- as_namespace()[source]
Returns the final merged configuration as a Namespace object.
- Returns:
Merged configuration.
- Return type:
- get_source_chain(key)[source]
Returns the source chain of the value (e.g., ‘config.ini -> args (updated)’).
- Parameters:
key (str) – The configuration key.
- Returns:
Source chain of the value.
- Return type:
str
- get_source(key)[source]
Returns the latest source of the value (args, env, config.ini, or default).
- Parameters:
key (str) – The configuration key.
- Returns:
Latest source of the value.
- Return type:
str
- update(updates)[source]
Update multiple configuration values. These updates are treated as command-line arguments and have the highest priority.
- Parameters:
updates (dict) – A dictionary of key-value pairs to update.
- set(key, value)[source]
Update a single configuration value. This update is treated as a command-line argument and has the highest priority.
- Parameters:
key (str) – The configuration key to update.
value – The new value to set.
- get_all_sections(pattern=None)[source]
Returns sections and their key-value pairs as a dictionary of dictionaries based on a regex pattern.
- Parameters:
pattern (str, optional) – Regex pattern to match section names. If None, returns an empty dictionary. |default|
None- Returns:
A dictionary where keys are section names and values are dictionaries of key-value pairs.
- Return type:
dict
- print_config()[source]
Prints a table showing the key, value, and source (args, env, config.ini, default). Each row is colored based on the latest source for easy distinction. The source column displays the history of sources in the format “config.ini -> args (updated)”.
- class NestedNamespace(**kwargs)[source]
Bases:
SimpleNamespaceInitialize the NestedNamespace with nested dictionaries and lists converted to NestedNamespace instances.
- Parameters:
kwargs – Keyword arguments where values can be dictionaries or lists.
- __init__(**kwargs)[source]
Initialize the NestedNamespace with nested dictionaries and lists converted to NestedNamespace instances.
- Parameters:
kwargs – Keyword arguments where values can be dictionaries or lists.
- keys()[source]
Get a list of keys in the current namespace.
- Return type:
list- Returns:
List of keys.
- values()[source]
Get a list of values in the current namespace.
- Return type:
list- Returns:
List of values.
- as_dict()[source]
Convert the NestedNamespace to a dictionary, recursively converting all nested namespaces.
- Return type:
dict- Returns:
Dictionary representation of the NestedNamespace.
- get_nested(keys)[source]
Retrieve a nested value from the namespace using a list of keys.
- Parameters:
keys (
list) – List of keys to traverse the nested structure.- Returns:
The nested value if found, otherwise None.
Example
>>> ns = NestedNamespace(level1={'level2': {'level3': 'value'}}) >>> ns.get_nested(['level1', 'level2', 'level3']) 'value'
>>> ns.get_nested(['level1', 'nonexistent', 'level3']) None
- nestednamedtuple(dict_items, ignore_keys=[])[source]
Converts dictionary to a nested namedtuple recursively.
- Param:
dictionary: Dictionary to convert into a nested namedtuple.
- Example:
from pawnlib.config.globalconfig import nestednamedtuple nt = nestednamedtuple({"hello": {"ola": "mundo"}}) print(nt) # >>> namedtupled(hello=namedtupled(ola='mundo'))
- Return type:
namedtuple
- class fdict[source]
Bases:
dictForced dictionary. Prevents dictionary from becoming a nested namedtuple.
- Example:
from pawnlib.config.globalconfig import nestednamedtuple, fdict d = {"hello": "world"} nt = nestednamedtuple({"forced": fdict(d), "notforced": d}) print(nt.notforced) # >>> namedtupled(hello='world') print(nt.forced) # >>> {'hello': 'world'}
- class ConfigSectionMap[source]
Bases:
ConfigParseroverride configparser.ConfigParser
Example
config = ConfigSectionMap() config.read('config.ini') config_file = config.as_dict()
- class PawnlibConfig(*args, **kwargs)[source]
Bases:
objectThis class can share variables using globals().
- Parameters:
:example
# auto attach from pawnlib.config.globalconfig import pawnlib_config as pwn from pawnlib.output.file import get_real_path pwn.set( PAWN_LOGGER=dict( app_name="default_app", log_path=f"{get_script_path(__file__)}/logs", stdout=True, use_hook_exception=False, ), PAWN_DEBUG=True, app_name=APP_NAME, data={} # Global NameSpace )
# attach logger from pawnlib.config.globalconfig import pawnlib_config as pwn from pawnlib.output.file import get_real_path app_logger, error_logger = log.AppLogger( app_name="default_app", log_path=f"{get_real_path(__file__)}/logs", stdout=True, use_hook_exception=False, ).get_logger() pwn.set( PAWN_APP_LOGGER=app_logger, PAWN_ERROR_LOGGER=error_logger, PAWN_DEBUG=True, app_name=APP_NAME, data={} # Global NameSpace )
- __init__(global_name='pawnlib_global_config', app_logger=, error_logger=, timeout=6000, debug=False, use_global_namespace=True)[source]
This class can share variables using globals().
- Parameters:
:example
# auto attach from pawnlib.config.globalconfig import pawnlib_config as pwn from pawnlib.output.file import get_real_path pwn.set( PAWN_LOGGER=dict( app_name="default_app", log_path=f"{get_script_path(__file__)}/logs", stdout=True, use_hook_exception=False, ), PAWN_DEBUG=True, app_name=APP_NAME, data={} # Global NameSpace )
# attach logger from pawnlib.config.globalconfig import pawnlib_config as pwn from pawnlib.output.file import get_real_path app_logger, error_logger = log.AppLogger( app_name="default_app", log_path=f"{get_real_path(__file__)}/logs", stdout=True, use_hook_exception=False, ).get_logger() pwn.set( PAWN_APP_LOGGER=app_logger, PAWN_ERROR_LOGGER=error_logger, PAWN_DEBUG=True, app_name=APP_NAME, data={} # Global NameSpace )
- static inspect(*args, **kwargs)[source]
Inspect function which can produce a report on any Python object, such as class, instance, or builtin. :type args: :param args: :type kwargs: :param kwargs: :return:
- get_path(path='')[source]
Get Path from the directory where the configure.json file is.
- Parameters:
path (
str, optional) – file_name or path |default|''- Return type:
Path- Returns:
- static get_app_path()[source]
Get Path from the directory where the app file.
- Parameters:
path – file_name or path
- Returns:
- init_with_env(**kwargs)[source]
Initialize with environmental variables.
- Parameters:
kwargs – dict
- Returns:
- static str2bool(v)[source]
This function is intended to return a boolean value.
- Parameters:
v –
- Returns:
- fill_config_from_environment()[source]
Initialize with environmental variables.
# default environments PAWN_INI = False PAWN_DEBUG = False PAWN_VERBOSE = 0 PAWN_TIMEOUT = 7000 PAWN_APP_LOGGER = "" PAWN_ERROR_LOGGER = "" PAWN_VERSION = PAWN_GLOBAL_NAME = pawnlib_global_config_UUID
- Returns:
- make_config(dictionary=None, **kwargs)[source]
Creates a global configuration that can be accessed anywhere during runtime. This function is a useful replacement to passing configuration classes between classes. Instead of creating a Config object, one may use
make_config()to create a global runtime configuration that can be accessed by any module, function, or object.- Parameters:
dictionary (
Optional[dict], optional) – Dictionary to create global configuration with. |default|Nonekwargs – Arguments to make global configuration with.
- Return type:
None
Example
from pawnlib.config.globalconfig import PawnlibConfig PawnlibConfig.make_config(hello="world")
- get(key=None, default=None)[source]
This method is intended to return a key value
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.set(hello="world") pawnlib_config.get("hello")
- set(**kwargs)[source]
This method is intended to store key values.
- Parameters:
kwargs –
- Returns:
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.set(hello="world") pawnlib_config.get("hello")
- increase(**kwargs)[source]
Find the key and increment the number.
- Parameters:
kwargs –
- Returns:
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.increase(count=1) print(pawnlib_config.get("count")) # >> 1 pawnlib_config.increase(count=1) print(pawnlib_config.get("count")) # >> 2 pawnlib_config.increase(count=10) print(pawnlib_config.get("count")) # >> 12
- decrease(**kwargs)[source]
Find the key and decrement the number. :type kwargs: :param kwargs: :return:
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.set(count=100) print(pawnlib_config.get("count")) # >> 100 pawnlib_config.decrease(count=1) print(pawnlib_config.get("count")) # >> 99 pawnlib_config.decrease(count=10) print(pawnlib_config.get("count")) # >> 89
- append_list(**kwargs)[source]
Find the key and append the value to list. :type kwargs: :param kwargs: :return:
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.append_list(results="result1") pawnlib_config.append_list(results="result2") print(pawnlib_config.get("results")) # >> ['result1', 'result2']
- remove_list(**kwargs)[source]
Find the key and remove the value to list. :type kwargs: :param kwargs: :return:
Example
from pawnlib.config.globalconfig import pawnlib_config pawnlib_config.set(results=['result1', 'result2']) pawnlib_config.remove_list(results="result2") print(pawnlib_config.get("results")) # >> ['result1']
- conf()[source]
Access global configuration as a
pawnlib.config.globalconfig.PawnlibConfig.- Return type:
Example
from pawnlib.config.globalconfig import pawnlib_config print(pawnlib_config.conf().hello) # >>> 'world'
- pconf() NestedNamespace
Access global configuration as a
pawnlib.config.globalconfig.PawnlibConfig.Example
from pawnlib.config.globalconfig import pawnlib_config print(pawnlib_config.conf().hello) # >>> 'world'
pawnlib.config.first_run_checker module
from pawnlib.config import first_run_checker
- class FirstRunChecker(*args, **kwargs)[source]
Bases:
objectA class to check if it’s the first run of the program.
This class uses a file to keep track of whether it’s the first run of the program or not. The file path can be specified, and by default, it’s “.task_first_run.json”.
- Parameters:
Example
from pawnlib.config import FirstRunChecker, one_time_run checker = FirstRunChecker(file_path=".first_run.json", debug=True) if checker.is_first_run(): print("This is the first run.") else: print("This is not the first run.") # >> This is the first run. checker.mark_first_run() if checker.is_first_run(): print("This is the first run.") else: print("This is not the first run.") # >> This is not the first run. checker.clear_first_run() if checker.is_first_run(): print("This is the first run.") else: print("This is not the first run.") # >> This is the first run. if one_time_run(): print("one time run") #>> one time run
- one_time_run(key=None)
pawnlib.config.first_run_checker.one_time_run
from pawnlib.config import one_time_run
if one_time_run():
print("Just one time run")
pawnlib.config.globalconfig.pawnlib_config
from pawnlib.config.globalconfig import pawnlib_config
pawnlib_config.set(param=1)
result = pawnlib_config.get("params")
>> 1
print(pawnlib_config.to_dict())
>>
{
PAWN_INI: False
PAWN_VERBOSE: 0
PAWN_TIMEOUT: 7000
PAWN_APP_LOGGER:
PAWN_ERROR_LOGGER:
PAWN_VERSION: Pawnlib/0.0.2
PAWN_GLOBAL_NAME: pawnlib_global_config_P2707BP1-0VN1HJA9-DVWMRDS2-98L6IO0U,
params: 1
}
pawnlib.config.logging_config
from pawnlib.config import setup_app_logger
setup_app_logger(
log_type='console',
verbose=2,
app_name='my_app',
log_level='DEBUG'
)
- verbose_to_log_level(verbose, log_levels=None, clamp=True)[source]
Convert a numeric verbose value to a corresponding logging level.
- 기본 맵핑 (예시):
0 -> CRITICAL+1 (아무 로그도 출력되지 않게) 1 -> WARNING 2 -> INFO 3 -> DEBUG 4 -> TRACE
그 이상(>4)일 때도 4와 같은 취급 (clamp=True일 때)
- class PreciseTimeFormatter(fmt=None, datefmt=None, style='%', validate=True)[source]
Bases:
FormatterA custom logging formatter that overrides the formatTime method to include microseconds up to 4 decimal places in the timestamp.
- formatTime(record, datefmt=None)[source]
Formats the time of a log record, appending microseconds with 4 decimal places.
Example
import logging from datetime import datetime logger = logging.getLogger("example_logger") handler = logging.StreamHandler() formatter = PreciseTimeFormatter() handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) logger.info("This is an info message.")
Initialize the formatter with specified format strings.
Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.
Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting,
str.format()({}) formatting orstring.Templateformatting in your format string.Changed in version 3.2: Added the
styleparameter.- formatTime(record, datefmt=None)[source]
Override formatTime to include microseconds up to 4 decimal places.
- Parameters:
record (logging.LogRecord) – The log record containing the timestamp.
datefmt (str, optional) – Optional date format string. |default|
None
- Returns:
Formatted time string.
- Return type:
str
- class PawnConsoleHandler(level=0)[source]
Bases:
HandlerA custom logging handler that sends formatted log messages to pawn.console with appropriate styling based on the log level.
Example
import logging logger = logging.getLogger("example_logger") handler = PawnConsoleHandler() logger.addHandler(handler) logger.setLevel(logging.DEBUG) logger.debug("Debug message.") logger.info("Info message.") logger.warning("Warning message.") logger.error("Error message.") logger.critical("Critical message.")
Initializes the instance - basically setting the formatter to None and the filter list to empty.
- class ConsoleLoggerHandler(verbose=0, stdout=True, log_level_short=False, simple_format='minimal', exc_info=False, console=None)[source]
Bases:
HandlerA custom logging handler for enhanced console output with verbosity, formatting, and exception handling options.
- verbose
Verbosity level (0 for WARNING, 1 for INFO, 2 for DEBUG).
- Type:
int
- stdout
Whether to output logs to standard output.
- Type:
bool
- console
The console object used for output (default is pawn.console).
- Type:
object
- log_level_short
Whether to use short log level names.
- Type:
bool
- simple_format
Formatting level (“none”, “minimal”, “detailed”, “advanced”, “custom”).
- Type:
str
- exc_info
Whether to include exception information in logs.
- Type:
bool
Example
import logging logger = logging.getLogger("example_logger") # Initialize handler with verbosity level and other options handler = ConsoleLoggerHandler(verbose=2, stdout=True, log_level_short=True) formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) try: 1 / 0 except ZeroDivisionError as e: logger.error("An error occurred!", exc_info=True) logger.debug("Debugging details.")
Initialize the ConsoleLoggerHandler with customizable options.
- Parameters:
verbose (int) – Verbosity level (0 for WARNING, 1 for INFO, 2 for DEBUG). Default is 0. |default|
0stdout (bool) – Whether to output logs to standard output. Default is True. |default|
Truelog_level_short (bool) – Whether to use short log level names. Default is False. |default|
Falsesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'minimal'exc_info (bool) – Whether to include exception information in logs. Default is False. |default|
Falseconsole (object, optional) – The console object used for output. Default is pawn.console. If None, it defaults to pawn.console. |default|
None
- __init__(verbose=0, stdout=True, log_level_short=False, simple_format='minimal', exc_info=False, console=None)[source]
Initialize the ConsoleLoggerHandler with customizable options.
- Parameters:
verbose (int) – Verbosity level (0 for WARNING, 1 for INFO, 2 for DEBUG). Default is 0. |default|
0stdout (bool) – Whether to output logs to standard output. Default is True. |default|
Truelog_level_short (bool) – Whether to use short log level names. Default is False. |default|
Falsesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'minimal'exc_info (bool) – Whether to include exception information in logs. Default is False. |default|
Falseconsole (object, optional) – The console object used for output. Default is pawn.console. If None, it defaults to pawn.console. |default|
None
- class ConsoleLoggerAdapter(logger=None, logger_name='', verbose=False, stdout=False)[source]
Bases:
objectWrapper class to unify logging methods for logging.Logger and rich.Console.
- Parameters:
logger (
Union[Logger,Console,Null,None], optional) – The logger object (logging.Logger, rich.Console, or Null) |default|Nonelogger_name (
str, optional) – Name of the logger |default|''verbose (
Union[bool,int], optional) – Verbosity level (bool or int). If False: WARNING level (default) If True: INFO level If 1: INFO level If 2: DEBUG level |default|False
- __init__(logger=None, logger_name='', verbose=False, stdout=False)[source]
Wrapper class to unify logging methods for logging.Logger and rich.Console.
- Parameters:
logger (
Union[Logger,Console,Null,None], optional) – The logger object (logging.Logger, rich.Console, or Null) |default|Nonelogger_name (
str, optional) – Name of the logger |default|''verbose (
Union[bool,int], optional) – Verbosity level (bool or int). If False: WARNING level (default) If True: INFO level If 1: INFO level If 2: DEBUG level |default|False
- classmethod get_adapter_logger(name)[source]
Retrieve an adapter by name or create a new one if it does not exist.
- Return type:
- classmethod set_global_verbose(new_verbose)[source]
Update the verbosity level of all registered adapters.
- escape_non_tag_brackets(message)[source]
Escape ‘[’ and ‘]’ that are not part of a valid Rich tag.
- Parameters:
message (
str) – The log message.- Return type:
str- Returns:
The message with non-tag brackets escaped.
- class BaseFormatter(fmt=None, datefmt=None, log_level_short=False, simple_format='minimal')[source]
Bases:
FormatterA custom logging formatter that provides additional flexibility for log formatting.
This formatter allows customization of log level display, simple formatting, and time formatting. It also cleans the log message by removing rich tags.
- Parameters:
fmt (str, optional) – The format string for the log message. |default|
Nonedatefmt (str, optional) – The format string for the date/time in the log message. |default|
Nonelog_level_short (bool, optional) – Whether to use short names for log levels (e.g., “E” for “ERROR”). |default|
Falsesimple_format (bool, optional) – Whether to use a simplified format for the log record. |default|
'minimal'
- - formatTime(record, datefmt=None)
Formats the timestamp of the log record.
- - format(record)
Cleans and reformats the log record message.
Example
import logging # Define a custom formatter formatter = BaseFormatter( fmt="%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", log_level_short=True ) # Create a logger and handler logger = logging.getLogger("example_logger") handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) # Log messages logger.info("This is an info message.") logger.error("This is an error message with <rich> tags.")
Initialize the formatter with specified format strings.
Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.
Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting,
str.format()({}) formatting orstring.Templateformatting in your format string.Changed in version 3.2: Added the
styleparameter.- formatTime(record, datefmt=None)[source]
Format the timestamp of a log record.
If a custom datefmt is provided, it will be used to format the time. Otherwise, it defaults to “YYYY-MM-DD HH:MM:SS”.
- Parameters:
record (logging.LogRecord) – The log record containing the timestamp.
datefmt (str, optional) – Optional custom format string for the timestamp. |default|
None
- Returns:
The formatted timestamp as a string.
- Return type:
str
- format(record)[source]
Clean and reformat the log record message.
This method cleans the original message by removing rich tags and optionally modifies other attributes of the log record based on initialization parameters.
- Parameters:
record (logging.LogRecord) – The original log record to be formatted.
- Returns:
The formatted log message as a string.
- Return type:
str
- class CleanFormatter(fmt=None, datefmt=None, log_level_short=False, simple_format='minimal')[source]
Bases:
BaseFormatterA subclass of BaseFormatter with no additional functionality.
This class inherits all features from BaseFormatter without any modifications, making it suitable for cases where no further customization is required.
Example
import logging # Define a clean formatter formatter = CleanFormatter( fmt="%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) # Create a logger and handler logger = logging.getLogger("clean_logger") handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.INFO) # Log messages logger.info("This is a clean info message.")
Initialize the formatter with specified format strings.
Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.
Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting,
str.format()({}) formatting orstring.Templateformatting in your format string.Changed in version 3.2: Added the
styleparameter.
- class CleanAndDetailTimeFormatter(fmt=None, datefmt=None, log_level_short=False, simple_format='minimal', precision=4)[source]
Bases:
BaseFormatterA custom logging formatter that extends BaseFormatter to include detailed time formatting with fractional seconds precision.
This formatter allows customization of log level display, simple formatting, and time formatting, with the added ability to specify the number of decimal places for fractional seconds.
- Parameters:
fmt (str, optional) – The format string for the log message. |default|
Nonedatefmt (str, optional) – The format string for the date/time in the log message. |default|
Nonelog_level_short (bool, optional) – Whether to use short names for log levels (e.g., “E” for “ERROR”). |default|
Falsesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'minimal'precision (int, optional) – The number of decimal places for fractional seconds in the timestamp. Defaults to 4. |default|
4
- - formatTime(record, datefmt=None)
Formats the timestamp of the log record with fractional seconds.
Example
import logging # Define a custom formatter with fractional second precision formatter = CleanAndDetailTimeFormatter( fmt="%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S", precision=6 ) # Create a logger and handler logger = logging.getLogger("detailed_logger") handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.DEBUG) # Log messages logger.info("This is an info message.") logger.error("This is an error message with detailed time.")
Initialize the formatter with optional precision for fractional seconds.
- Parameters:
fmt (str, optional) – The format string for the log message. |default|
Nonedatefmt (str, optional) – The format string for the date/time in the log message. |default|
Nonelog_level_short (bool, optional) – Whether to use short names for log levels (e.g., “E” for “ERROR”). |default|
Falsesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'minimal'precision (int, optional) – The number of decimal places for fractional seconds in the timestamp. Defaults to 4. |default|
4
- __init__(fmt=None, datefmt=None, log_level_short=False, simple_format='minimal', precision=4)[source]
Initialize the formatter with optional precision for fractional seconds.
- Parameters:
fmt (str, optional) – The format string for the log message. |default|
Nonedatefmt (str, optional) – The format string for the date/time in the log message. |default|
Nonelog_level_short (bool, optional) – Whether to use short names for log levels (e.g., “E” for “ERROR”). |default|
Falsesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'minimal'precision (int, optional) – The number of decimal places for fractional seconds in the timestamp. Defaults to 4. |default|
4
- formatTime(record, datefmt=None)[source]
Format the timestamp of a log record with fractional seconds.
If a custom datefmt is provided, it will be used to format the time. Otherwise, it defaults to “YYYY-MM-DD HH:MM:SS” with fractional seconds formatted to the specified precision.
- Parameters:
record (logging.LogRecord) – The log record containing the timestamp.
datefmt (str, optional) – Optional custom format string for the timestamp. |default|
None
- Returns:
The formatted timestamp as a string.
- Return type:
str
- remove_rich_tags(message)[source]
Removes valid Rich tags from the given message while leaving invalid tags intact.
This function scans the input message for Rich-style tags (e.g., [tag] or [/tag]), validates them against a predefined list of valid tags, and removes only the valid ones. Invalid tags are preserved in the output.
- Parameters:
message (str) – The input string containing Rich-style tags.
- Returns:
The message with valid Rich tags removed.
- Return type:
str
Example
# Example usage message = "This is a [bold]bold[/bold] and [invalid]invalid[/invalid] tag example." clean_message = remove_rich_tags(message) print(clean_message) # Output: "This is a bold and [invalid]invalid[/invalid] tag example."
- class AppOrEnabledFilter(app_prefixes, enabled_list=None, name='')[source]
Bases:
FilterA logging filter that allows log records to pass if their logger name starts with a specified application name or exactly matches a logger name in an explicit enabled list.
Initializes the filter.
- Parameters:
app_prefixes (List[str]) – A list of application name prefixes. Loggers whose names exactly match any of these prefixes or start with any of these prefixes followed by a dot (e.g., ‘myapp’ or ‘myapp.module’) will be allowed.
enabled_list (list, optional) – An optional list of specific logger names that should always be enabled, regardless of the app_prefixes. |default|
Nonename (str, optional) – The name of the filter. This is passed to the parent logging.Filter class. |default|
''
Example
filter1 = AppOrEnabledFilter(app_prefixes=['my_app'], enabled_list=['httpx']) filter2 = AppOrEnabledFilter(app_prefixes=['my_app', 'another_app'])
- __init__(app_prefixes, enabled_list=None, name='')[source]
Initializes the filter.
- Parameters:
app_prefixes (List[str]) – A list of application name prefixes. Loggers whose names exactly match any of these prefixes or start with any of these prefixes followed by a dot (e.g., ‘myapp’ or ‘myapp.module’) will be allowed.
enabled_list (list, optional) – An optional list of specific logger names that should always be enabled, regardless of the app_prefixes. |default|
Nonename (str, optional) – The name of the filter. This is passed to the parent logging.Filter class. |default|
''
Example
filter1 = AppOrEnabledFilter(app_prefixes=['my_app'], enabled_list=['httpx']) filter2 = AppOrEnabledFilter(app_prefixes=['my_app', 'another_app'])
- filter(record)[source]
Determines whether the given log record should be output.
The record passes if: - The record’s logger name is exactly one of self.app_names (e.g., ‘oci_tools’), OR - The record’s logger name starts with one of self.app_prefixes_dot (e.g., ‘oci_tools.sub’), OR - The record’s logger name is found in self.enabled_list (e.g., ‘httpx’ if ‘httpx’ is in enabled_list).
- Parameters:
record (logging.LogRecord) – The log record to evaluate.
- Returns:
True if the record should be processed, False otherwise.
- Return type:
bool
Example
# Assuming filter initialized with app_prefixes=['my_app'], enabled_list=['external_lib'] record1 = logging.LogRecord(name='my_app', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record1) # >> True record2 = logging.LogRecord(name='my_app.sub_module', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record2) # >> True record3 = logging.LogRecord(name='external_lib', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record3) # >> True record4 = logging.LogRecord(name='another_lib', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record4) # >> False # Assuming filter initialized with app_prefixes=['appA', 'appB'] record5 = logging.LogRecord(name='appB', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record5) # >> True record6 = logging.LogRecord(name='appB.component', level=logging.INFO, pathname='', lineno=0, msg='Test', args=(), exc_info=None) filter.filter(record6) # >> True
- setup_app_logger(app_name, log_type='console', verbose=1, log_path='./logs', log_format=None, date_format=None, log_level=None, clear_existing_handlers=True, configure_root=False, propagate=False, enabled_third_party_loggers=None, log_all_third_party=False, log_level_short=True, simple_format='detailed', exc_info=False, rotate_time='midnight', rotate_interval=1, backup_count=7, handle_propagate=False, propagate_scope='all')[source]
Configures and sets up a Python logger for an application, addressing filtering and duplicate output issues while maintaining backward compatibility. The function operates in two modes based on the configure_root parameter.
- Parameters:
app_name (Union[str, List[str]]) – The name(s) of the application. Can be a single string or a list of strings. Used for naming the logger(s) and the log file. If a list, the first item is used for the log file name.
log_type (str) – Specifies where logs should be output. Can be ‘console’, ‘file’, or ‘both’. Defaults to ‘console’. |default|
'console'verbose (int) – Verbosity level, an integer from 0 to 5. Higher values mean more detailed logs. This is translated to a logging level if log_level is not explicitly set. Defaults to 1. |default|
1log_path (str) – The directory where log files will be stored if log_type includes ‘file’. Defaults to “./logs”. |default|
'./logs'log_format (str, optional) – The format string for log messages. If None, a default format is used. |default|
Nonedate_format (str, optional) – The format string for the date/time in log messages. If None, a default is used. |default|
Nonelog_level (Union[int, str, None]) – The logging level to set (e.g., logging.INFO, ‘DEBUG’). Overrides verbose if provided. |default|
Noneclear_existing_handlers (bool) – If True, clears all existing handlers from the logger before adding new ones. This primarily applies when configure_root is False. Defaults to True. |default|
Trueconfigure_root (bool) – If True, configures the root logger. This enables a centralized logging approach with filtering. If False, configures a named logger (based on app_name). Defaults to False. |default|
Falsepropagate (bool) – Whether messages from the app_name logger will be passed to ancestor loggers. Only applies when configure_root is False. Defaults to False. |default|
Falseenabled_third_party_loggers (Optional[List[str]]) – A list of names of specific third-party loggers that should always be enabled, even if log_all_third_party is False. Applies when configure_root is True. |default|
Nonelog_all_third_party (bool) – If True, all log messages from any logger (including third-party) will be processed by the handlers. If False and configure_root is True, only logs from app_name (or app_prefixes) and specified enabled_third_party_loggers will pass through the filter. Defaults to False. |default|
Falselog_level_short (bool) – If True, uses a short form for log levels in the console output (e.g., ‘D’ for DEBUG). |default|
Truesimple_format (Union[str, bool]) – Controls the detail level of the default format for console. Can be “detailed”, True (for a simpler format), or False (for the most basic format). |default|
'detailed'exc_info (bool) – If True, exception information is added to log records. This is passed to the ConsoleLoggerHandler. |default|
Falserotate_time (str) – When to rotate log files. Options like ‘midnight’, ‘H’ (hourly), ‘M’ (minutes). Only applies if log_type includes ‘file’. |default|
'midnight'rotate_interval (int) – The interval for log file rotation (e.g., 1 for daily rotation if rotate_time is ‘midnight’). Only applies if log_type includes ‘file’. |default|
1backup_count (int) – The number of old log files to keep. Only applies if log_type includes ‘file’. |default|
7handle_propagate (bool) – If True, automatically adjusts propagation settings for other loggers based on propagate_scope to prevent duplicate output. |default|
Falsepropagate_scope (str) – Defines the scope for handle_propagate. Can be ‘all’ or other specific scopes relevant to pawnlib. |default|
'all'
- Returns:
The configured logger instance, typically for the first app_name in the list if app_name is a list, or the single app_name string.
- Return type:
logging.Logger
Example
import logging import os # Assuming pawnlib.utils.log module is available or its components are imported # from pawnlib.utils.log import setup_app_logger, verbose_to_log_level, ConsoleLoggerHandler, CleanAndDetailTimeFormatter, AppOrEnabledFilter, change_propagate_setting # from logging.handlers import TimedRotatingFileHandler # Example 1: Basic console logger for a single app name logger1 = setup_app_logger(app_name="my_application", log_type="console", verbose=3) logger1.info("This is an informational message from my_application.") logging.getLogger("another_module").debug("This message will not show by default if configure_root is False.") # Example 2: File logger with rotation for a specific app logger2 = setup_app_logger( app_name="file_app", log_type="file", log_path="./my_logs", log_level="WARNING", rotate_time='D', # Daily rotation backup_count=5 ) logger2.warning("This warning goes to a file.") logger2.info("This info message will not appear due to WARNING level.") # Example 3: Centralized root logger with multiple app prefixes and third-party filtering # Logs for 'main_app', 'sub_component', and 'httpx' will be processed root_logger = setup_app_logger( app_name=["main_app", "sub_component"], log_type="console", configure_root=True, log_level="DEBUG", # Root logger gets DEBUG, effective level for 'main_app' and 'sub_component' is DEBUG enabled_third_party_loggers=['httpx', 'sqlalchemy'] ) logging.getLogger("main_app").info("Main app message.") logging.getLogger("sub_component.core").debug("Sub component debug message.") logging.getLogger("httpx").info("HTTPX library message.") logging.getLogger("requests").warning("Requests library message (should be filtered out).") logging.getLogger("sqlalchemy.engine").info("SQLAlchemy engine message.") # Example 4: Centralized root logger logging ALL messages all_logs_logger = setup_app_logger( app_name="catch_all_app", log_type="console", configure_root=True, log_level="INFO", log_all_third_party=True ) logging.getLogger("catch_all_app").info("My app's info.") logging.getLogger("any_library_name").debug("Debug from any library, will show because log_all_third_party is True and root is DEBUG.")
- setup_logger(logger=None, name='', verbose=False)[source]
Setup or reuse a logger.
This function will reuse an existing logger if provided, otherwise it will create a new one.
- Parameters:
- Returns:
A ConsoleLoggerAdapter instance.
- getPawnLogger(name=None, verbose=0)[source]
Return a logger with the specified name, creating it if necessary. It will reuse an existing logger if it exists.
- get_logger(name=None, level=20)[source]
Returns a logger instance. If name is not provided, it defaults to the caller’s module name.
- change_log_level(new_level, logger=None)[source]
Change the log level of the specified logger or the root logger.
- Parameters:
new_level – New log level (e.g., ‘DEBUG’, ‘INFO’).
logger (optional) – Logger instance to modify. If None, modifies the root logger. |default|
None
- class LoggerFactory[source]
Bases:
objectA factory class for creating and managing loggers with console and file output.
Supports configuration of loggers with console and/or file handlers, customizable log formats, and global settings for level and format. Handles propagation and temporary settings via context managers.
- Parameters:
_loggers (dict) – Dictionary of logger instances, keyed by logger name
_global_log_level (int or None) – Global logging level applied to all loggers if use_global_level is True
_use_global_level (bool) – Flag to enforce global log level across all loggers
_global_simple_format (str) – Default format style for console output (‘detailed’ or ‘minimal’)
_global_filters (list) – List of filter functions applied to all loggers
_global_handler_configs (list) – List of dictionaries containing handler type and configuration
_propagate (bool) – Whether log messages propagate to parent loggers
_propagate_scope (str) – Scope for applying propagation settings (‘all’ by default)
# Example usage import logging from import LoggerFactory # Basic logger with both console and file output logger = LoggerFactory.create_app_logger( log_type='both', verbose=2, app_name='MyApp', log_path='./logs' ) logger.info("Application started") logger.debug("Debug message") # Console Output: # [INF] <MyApp:XX> Application started # [DBG] <MyApp:XX> Debug message # File Output (./logs/MyApp.log): # [2025-03-12 10:00:00,123] INF::main.py/main(XX) Application started # [2025-03-12 10:00:00,124] DBG::main.py/main(XX) Debug message # Sub-logger with inherited settings sub_logger = LoggerFactory.get_logger('MyApp.sub', verbose=2) sub_logger.info("Sub logger message") # Console Output: # [INF] <MyApp.sub:XX> Sub logger message # Temporary settings with context manager with LoggerFactory.temporary_settings(log_level=1, simple_format='minimal'): temp_logger = LoggerFactory.get_logger('MyApp.temp') temp_logger.info("Temporary info message") temp_logger.debug("This debug won't appear") # Console Output: # [INF] Temporary info message # Adjust logger level LoggerFactory.adjust_logger_level('MyApp', verbose=1) logger.debug("This debug won't appear after level change")
- classmethod create_app_logger(log_type='console', verbose=1, log_path='./logs', app_name='default', log_format=None, date_format='%Y-%m-%d %H:%M:%S', log_level=None, log_level_short=True, simple_format='detailed', exc_info=False, rotate_time='midnight', rotate_interval=1, backup_count=7, clear_existing_handlers=True, propagate=None)[source]
Configure and return an application logger.
- Parameters:
log_type (str) – Type of logging (‘console’, ‘file’, or ‘both’) |default|
'console'verbose (int) – Verbosity level (0=WARNING, 1=INFO, 2=DEBUG) |default|
1log_path (str) – Directory path for log files |default|
'./logs'app_name (str) – Name of the logger |default|
'default'log_format (str, optional) – Custom log format string (default: detailed timestamp format) |default|
Nonedate_format (str) – Date format for log timestamps |default|
'%Y-%m-%d %H:%M:%S'log_level (int or str, optional) – Logging level as int or str (e.g., ‘INFO’) |default|
Nonelog_level_short (bool) – Use short level names (e.g., INF) |default|
Truesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'detailed'exc_info (bool) – Include exception info in logs |default|
Falserotate_time (str) – When to rotate logs (e.g., ‘midnight’) |default|
'midnight'rotate_interval (int) – Interval for log rotation |default|
1backup_count (int) – Number of backup log files to keep |default|
7clear_existing_handlers (bool) – Clear existing handlers before adding new ones |default|
Truepropagate (bool, optional) – Set propagation behavior (overrides class default if provided) |default|
None
- Returns:
Configured logger instance
- Return type:
logging.Logger
- Raises:
ValueError – If no handlers are added to the logger
Example
from pawnlib.config import create_app_logger # Set up a console logger with DEBUG level logger_console = create_app_logger( log_type='console', verbose=2, app_name='my_app', log_level='DEBUG' ) logger_console.info("Start [bold red]Important[/bold red] process") # Set up a file logger with INFO level and daily rotation logger = create_app_logger( log_type='file', verbose=1, log_path='./logs', app_name='my_app', rotate_time='midnight', rotate_interval=1, backup_count=10 ) logger.info("This is an info message.") logger.debug("This is a debug message.")
- classmethod set_global_log_level(verbose=0, use_global=True)[source]
Set global logging level and enforce it across all loggers.
- classmethod set_global_simple_format(simple_format)[source]
Set global simple format for console handlers.
- Parameters:
simple_format (str) – Format style (‘detailed’, ‘minimal’)
- classmethod add_global_filter(filter_func)[source]
Add a global filter to all loggers.
- Parameters:
filter_func (callable) – Filter function to apply to log records
- classmethod add_global_handler(handler_type, **kwargs)[source]
Add a global handler to all loggers.
- Parameters:
handler_type (type) – Type of handler to add (e.g., ConsoleLoggerHandler)
kwargs – Keyword arguments for handler initialization
- classmethod adjust_logger_level(name, verbose)[source]
Adjust the logging level for a specific logger.
- Parameters:
name (str) – Name of the logger to adjust
verbose (int) – Verbosity level (0=WARNING, 1=INFO, 2=DEBUG)
- Raises:
ValueError – If the logger is not found
- classmethod get_global_settings()[source]
Get current global settings of the factory.
- Returns:
Dictionary containing global settings
- Return type:
dict
- class LoggerMixinVerbose[source]
Bases:
objectA mixin class for initializing loggers in classes with customizable verbosity and format.
Provides a method to set up a logger either by inheriting an existing logger or creating a new one using LoggerFactory. Ensures the logger is properly configured with handlers, levels, and propagation settings.
Example
# Example usage from pawnlib.config import LoggerMixinVerbose, LoggerFactory # Define a class using the mixin class MyClass(LoggerMixinVerbose): def __init__(self, verbose=1): self.init_logger(verbose=verbose) # Basic usage with LoggerFactory obj = MyClass(verbose=2) obj.logger.info("Class initialized") # Output: # [INF] <__main__.MyClass:XX> Class initialized # Using an existing logger parent_logger = LoggerFactory.create_app_logger(log_type='console', verbose=1, app_name='Parent') obj_with_parent = MyClass(verbose=0) obj_with_parent.init_logger(logger=parent_logger) obj_with_parent.logger.info("Using parent logger") # Output: # [INF] <Parent:XX> Using parent logger
- change_propagate_setting(propagate=True, propagate_scope='all', log_level=None, pawnlib_level=None, third_party_level=None)[source]
Change the propagation settings and log levels for all registered loggers.
Allows modification of propagation behavior and log levels across all loggers, with scoping options to target all loggers, only pawnlib loggers, or third-party loggers.
- Parameters:
propagate (bool) – Whether loggers should propagate messages to parent loggers |default|
Truepropagate_scope (str) – Scope for applying propagation (‘all’, ‘pawnlib’, ‘third_party’) |default|
'all'log_level (int, optional) – Log level to apply when scope is ‘all’ |default|
Nonepawnlib_level (int, optional) – Log level for pawnlib loggers when scope is ‘pawnlib’ or ‘third_party’ |default|
Nonethird_party_level (int, optional) – Log level for non-pawnlib loggers when scope is ‘pawnlib’ or ‘third_party’ |default|
None
- Raises:
ValueError – If propagate_scope is not one of ‘all’, ‘pawnlib’, or ‘third_party’
Example
# Example usage from pawnlib.config import change_propagate_setting, LoggerFactory # Create some loggers app_logger = LoggerFactory.create_app_logger(log_type='console', verbose=1, app_name='MyApp') pawn_logger = LoggerFactory.get_logger('pawnlib.utils', verbose=2) third_logger = LoggerFactory.get_logger('external.lib', verbose=1) # Change propagation for all loggers change_propagate_setting(propagate=False, propagate_scope='all', log_level=20) app_logger.info("No propagation") # Output: # [INF] <MyApp:XX> No propagation # Change propagation for pawnlib loggers only change_propagate_setting(propagate=True, propagate_scope='pawnlib', pawnlib_level=10, third_party_level=30) pawn_logger.debug("Pawnlib debug with propagation") third_logger.debug("Third-party debug suppressed") # Output: # [DBG] <pawnlib.utils:XX> Pawnlib debug with propagation
- create_app_logger(log_type='console', verbose=1, log_path='./logs', app_name='default', log_format=None, date_format='%Y-%m-%d %H:%M:%S', log_level=None, log_level_short=True, simple_format='detailed', exc_info=False, rotate_time='midnight', rotate_interval=1, backup_count=7, clear_existing_handlers=True, propagate=None)
Configure and return an application logger.
- Parameters:
log_type (str) – Type of logging (‘console’, ‘file’, or ‘both’) |default|
'console'verbose (int) – Verbosity level (0=WARNING, 1=INFO, 2=DEBUG) |default|
1log_path (str) – Directory path for log files |default|
'./logs'app_name (str) – Name of the logger |default|
'default'log_format (str, optional) – Custom log format string (default: detailed timestamp format) |default|
Nonedate_format (str) – Date format for log timestamps |default|
'%Y-%m-%d %H:%M:%S'log_level (int or str, optional) – Logging level as int or str (e.g., ‘INFO’) |default|
Nonelog_level_short (bool) – Use short level names (e.g., INF) |default|
Truesimple_format (str) – Formatting code level (“none”, “minimal”, “detailed”, “advanced”, “custom”). Default is minimal. |default|
'detailed'exc_info (bool) – Include exception info in logs |default|
Falserotate_time (str) – When to rotate logs (e.g., ‘midnight’) |default|
'midnight'rotate_interval (int) – Interval for log rotation |default|
1backup_count (int) – Number of backup log files to keep |default|
7clear_existing_handlers (bool) – Clear existing handlers before adding new ones |default|
Truepropagate (bool, optional) – Set propagation behavior (overrides class default if provided) |default|
None
- Returns:
Configured logger instance
- Return type:
logging.Logger
- Raises:
ValueError – If no handlers are added to the logger
Example
from pawnlib.config import create_app_logger # Set up a console logger with DEBUG level logger_console = create_app_logger( log_type='console', verbose=2, app_name='my_app', log_level='DEBUG' ) logger_console.info("Start [bold red]Important[/bold red] process") # Set up a file logger with INFO level and daily rotation logger = create_app_logger( log_type='file', verbose=1, log_path='./logs', app_name='my_app', rotate_time='midnight', rotate_interval=1, backup_count=10 ) logger.info("This is an info message.") logger.debug("This is a debug message.")
pawnlib.config.settings_config
- class SettingDefinition(env_var, default=None, value_type=<class 'str'>, is_list=False, custom_converter=None)[source]
Bases:
object
- class BaseSettingsConfig[source]
Bases:
object- get_definitions()[source]
모든 설정 정의를 딕셔너리로 반환
- Return type:
Dict[str,SettingDefinition]
- load_environment_settings(args, settings_config=<class 'pawnlib.config.settings_config.BaseSettingsConfig'>)[source]
Load environment settings from command-line arguments or environment variables, prioritizing args if provided, otherwise using environment variables.
- Parameters:
args – Command-line arguments object
settings_config (
Type[TypeVar(T, bound=BaseSettingsConfig)], optional) – BaseSettingsConfig instance (or its subclass) containing setting definitions |default|<class 'pawnlib.config.settings_config.BaseSettingsConfig'>
- Return type:
Dict[str,Any]
- class AppConfig(network_info=None, extras=None, **settings)[source]
Bases:
NestedNamespaceA configuration class accessible in a namespace style. The settings are provided as a dictionary and converted to NestedNamespace for use.
- network
Network information (based on NetworkInfo, converted to NestedNamespace)
- extras
Additional settings or metadata (converted to NestedNamespace)
Initialize the NestedNamespace with nested dictionaries and lists converted to NestedNamespace instances.
- Parameters:
kwargs – Keyword arguments where values can be dictionaries or lists.