# =========================================================================
# Module: tools/parser_interface.py
# Author: Henry R. Winterbottom
# Email: henry.winterbottom@noaa.gov
# This program is free software: you can redistribute it and/or modify
# it under the terms of the respective public license published by the
# Free Software Foundation and included with the repository within
# which this application is contained.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# =========================================================================
"""
Module
------
parser_interface.py
Description
-----------
This module contains functions to perform various tasks which
involve the parsing of dictionaries, lists, and other Python type
comprehensions.
Functions
---------
dict_formatter(in_dict)
This function formats a Python dictionary; all UNICODE and
data-type conversions are performed within this function.
dict_key_remove(dict_in, key):
This function attempts to remove a Python dictionary key and
value pair.
dict_key_value(dict_in, key, force=False, max_value=False,
min_value=False, index_value=None, no_split=False)
This function ingests a Python dictionary and a dictionary key
and return the value(s) corresponding to the respective
dictionary key; if the optional variable `force` is `True` and
the dictionary key does not exist within the Python
dictionary, the function will return NoneType.
dict_merge(dict1, dict2)
This function merges two Python dictionaries and returns a
generator containing the merged Python dictionary relative to
the checks within the function.
dict_replace_value(in_dict, old, new)
This function replaces strings within a (nested) Python
dictionary and returns the updated (nested) Python dictionary.
dict_toobject(in_dict)
This funcction converts and returns the Python dictionary
`in_dict`, specified upon entry, to a Python Namespace
`out_obj`.
enviro_get(envvar)
This function retrieves the environment variable corresponding
to the specified string; if the environment variable is not
defined, NoneType is returned.
enviro_set(envvar, value)
This function defines the environment variable corresponding
to the supported specified value.
f90_bool(value)
This method will transform boolean type values to a FORTRAN 90
boolean format; if the variable `value` specified upon entry
is not of boolean format the value is returned unaltered.
find_commonprefix(strings_list)
This function returns the common prefix from a list of strings.
handler(func, handle: lambda errmsg: errmsg, return_none=False,
raise_exception=False, *args, **kwargs):
This method permits exceptions to raised(i.e., handled) within
Python list comprehensions.
list_get_type(in_list, dtype):
This function parses a list and returns a list of values in
accordance with the specified data type.
list_replace_value(in_list, old, new)
This function replaces strings within a Python list and
returns the updated Python list; this function adapted from
https://tinyurl.com/list-value-replace.
match_list(in_list, match_string, exact=False):
This function ingests a Python list and a Python string and
matches, either exact or partial, are sought for the string
within the provided; if `exact` is `True` upon entry, the
matching Python string is returned if a match is found;
otherwise NoneType is returned; if `exact` is `False` upon
entry, a list of matching Python strings is returned.
object_append(object_in, object_key, dict_in):
This function appends the contents of Python dictionary to
specified object key.
object_compare(obj1, obj2)
This function compares two Python objects.
object_deepcopy(object_in):
This function ingests a Python object and returns a deep copy of
the respective object.
object_define()
This function defines an empty Python object.
object_getattr(object_in, key, force=False)
This function ingests a Python object and a Python attribute
and returns the value of the respective attribute; if `force`
is `True` and the Python object attribute does not exist, this
function returns NoneType.
object_hasattr(object_in, key)
This function checks whether a Python object contains an
attribute and returns an appropriate boolean value indicating
the result of the inquiry.
object_setattr(object_in, key, value)
This function ingests a Python object and a Python key and value
pair and defines the attributes for the respective object.
object_todict(object_in)
This function ingests a Python object and returns a Python
dictionary containing the contents of the respective object.
str_to_bool(string)
This function converts a Python string to it's corresponding
boolean value; if a JSONDecodeError exception is encountered,
NoneType is returned.
string_parser(in_list)
This function ingests a Python list of variables and returns
Python list of appropriately formatted values.
true_or_false(argval)
This function checks whether an argument is a Boolean-type
value; if so, this function defines the appropriate Python
boolean-type; otherwise, this function returns NoneType.
unique_list(in_list)
This function ingests a list, possibly with duplicate values,
and returns a list of only unique values.
update_dict(default_dict, base_dict, update_none=False)
This function reads Python dictionaries containing default key
and value pairs (`default_dict`) and a base (optional or
changed values) Python dictionary containing key and value
pairs (`base_dict`); the output Python dictionary
`output_dict` is initialized with the base Python dictionary;
any key and value pairs within `default_dict` which are not in
`output_dict` are updated with those from `default_dict`.
Author(s)
---------
Henry R. Winterbottom; 21 August 2022
History
-------
2022-08-21: Henry Winterbottom -- Initial implementation.
"""
# ----
# pylint: disable=broad-except
# pylint: disable=keyword-arg-before-vararg
# pylint: disable=raise-missing-from
# pylint: disable=too-many-arguments
# pylint: disable=too-many-branches
# pylint: disable=too-many-lines
# pylint: disable=undefined-variable
# pylint: disable=unnecessary-comprehension
# ----
__author__ = "Henry R. Winterbottom"
__maintainer__ = "Henry R. Winterbottom"
__email__ = "henry.winterbottom@noaa.gov"
# ----
import collections
import copy
import json
import os
from json.decoder import JSONDecodeError
from types import SimpleNamespace
from typing import Any, Callable, Dict, Generator, List, Tuple, Union
import numpy
from utils.exceptions_interface import ParserInterfaceError
# ----
# Define all available functions.
__all__ = [
"dict_formatter",
"dict_key_remove",
"dict_key_value",
"dict_merge",
"dict_replace_value",
"dict_toobject",
"enviro_get",
"enviro_set",
"f90_bool",
"find_commonprefix",
"handler",
"list_get_type",
"list_replace_value",
"match_list",
"object_append",
"object_compare",
"object_deepcopy",
"object_define",
"object_getattr",
"object_hasattr",
"object_setattr",
"object_todict",
"str_to_bool",
"string_parser",
"true_or_false",
"unique_list",
"update_dict",
]
# ----
# ----
[docs]def dict_key_remove(dict_in: Dict, key: str) -> Dict:
"""
Description
-----------
This function attempts to remove a Python dictionary key and value
pair.
Parameters
----------
dict_in: Dict
A Python dictionary to be parsed.
key: str
A Python string indicating the dictionary key within the
Python dictionary (see above).
Returns
-------
dict_in: Dict
A Python dictionary from which the specified key and value
pair has been removed (if present in the Python dictionary on
entry).
"""
# Attempt to remove the dictionary value corresponding to the key
# specified upon entry.
try:
del dict_in[key]
except KeyError:
pass
return dict_in
# ----
[docs]def dict_key_value(
dict_in: Dict,
key: str,
force: bool = False,
max_value: bool = False,
min_value: bool = False,
index_value: int = None,
no_split: bool = False,
) -> Any:
"""
Description
-----------
This function ingests a Python dictionary and a dictionary key and
return the value(s) corresponding to the respective dictionary
key; if the optional variable `force` is True and the dictionary
key does not exist within the Python dictionary, the function will
return NoneType.
Parameters
----------
dict_in: Dict
A Python dictionary to be parsed.
key: str
A Python string indicating the dictionary key within the
Python dictionary (see above).
Keywords
--------
force: str, optional
A Python boolean variable; if True and in the absence of the
respective dictionary key within the Python dictionary,
NoneType is returned.
max_value: bool, optional
A Python boolean variable; if True, and a Python list yielded
via the Python dictionary key, the maximum value within the
Python list will be returned; the default value is False.
min_value: bool, optional
A Python boolean variable; if True, and a Python list yielded
via the Python dictionary key, the minimum value within the
Python list will be returned; the default value is False.
index_value: int, optional
A Python integer defining the index within the Python list (as
yielded by the Python dictionary key) to return; the default
value is NoneType.
no_split: bool, optional
A Python boolean variable; if True and if a string, the string
will not be split into and returned as a comma-delimited list.
Returns
-------
value: Any
A list of values collected from the ingested Python dictionary
and the respective dictionary key if `no_split` is False; a
string otherwise.
Raises
------
ParserInterfaceError:
- raised if both minimum and maximum values of a list are
requested; only minimum or only maximum may be requested
upon entry.
- raised if the keyword argument combinations passed upon
entry are incorrect.
"""
# Check that the parameter values are valid.
if max_value and min_value:
msg = (
"The user has requested both minimum and maximum list "
"value; please check that only one threshold value is "
"is to be sought from the list. Aborting!!!"
)
raise ParserInterfaceError(msg=msg)
if index_value is not None:
if max_value:
msg = (
"The user has selected both a single value (as per "
"the specified index) and the maximum list value; "
"please check which criteria to fulfill. Aborting!!!"
)
raise ParserInterfaceError(msg=msg)
if min_value:
msg = (
"The user has selected both a single value (as per "
"the specified index) and the minimum list value; "
"please check which criteria to fulfill. Aborting!!!"
)
raise ParserInterfaceError(msg=msg)
# Collect the dictionary attribute value; proceed accordingly.
try:
value = dict_in[key]
if no_split:
return value
try:
in_list = dict_in[key].split(",")
value = list(string_parser(in_list=in_list))
if max_value:
value = max(value)
if min_value:
value = min(value)
if index_value is not None:
value = value[index_value]
except AttributeError:
value = dict_in[key]
except KeyError:
if not force:
msg = (
f"Key {key} could not be found in user provided dictionary. "
"Aborting!!!"
)
raise ParserInterfaceError(msg=msg)
if force:
value = None
return value
# ----
[docs]def dict_merge(dict1: Dict, dict2: Dict) -> Generator[Dict, Dict, Dict]:
"""
Description
-----------
This function merges two Python dictionaries and returns a
generator containing the merged Python dictionary relative to the
checks within the function.
Parameters
----------
dict1: Dict
A Python dictionary to be merged.
dict2: Dict
A Python dictionary to be merged.
Yields
------
Dict:
A Python dictionary containing the contents of `dict1` and
`dict2`.
"""
# Define the attributes list containing the unique values from the
# respective Python dictionaries.
attrs_list = set(dict1.keys()).union(dict2.keys())
for k in attrs_list:
# For unique key values, merge the respective Python
# dictionaries.
if k in dict1 and k in dict2:
# If the respective Python dictionary key values are
# Python dictionaries, proceed accordingly.
if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
yield (k, dict(dict_merge(dict1[k], dict2[k])))
else:
# If one of the Python dictionary key values is not a
# Python dictionary, update the second dictionary and
# continue.
yield (k, dict2[k])
elif k in dict1:
# Update the first Python dictionary accordingly.
yield (k, dict1[k])
else:
# Update the second Python dictionary accordingly.
yield (k, dict2[k])
# ----
[docs]def dict_replace_value(in_dict: Dict, old: str, new: str) -> Dict:
"""
Description
-----------
This function replaces strings within a (nested) Python dictionary
and returns the updated (nested) Python dictionary; this function
adapted from https://tinyurl.com/dict-value-replace.
Parameters
----------
in_dict: Dict
A (nested) Python dictionary containing Python strings to be
replaced/updated.
old: str
A Python string value specifying the Python string instance to
be replaced.
new: str
A Python string value specifying the Python string to replace
the value specified by the `old` attribute.
Returns
-------
out_dict: Dict
A (nested) Python dictionary updated in accordance within the
attributes specified by the `old` and `new` attributes;
otherwise this Python dictionary is identical to that defined
by `in_dict`.
"""
# Parse the Python dictionary and proceed accordingly.
out_dict = {}
for key, value in in_dict.items():
# Update any Python dictionary instances.
if isinstance(value, dict):
value = dict_replace_value(value, old, new)
# Update any Python list instances.
elif isinstance(value, list):
value = list_replace_value(value, old, new)
# Update any remaining Python type instances.
elif isinstance(value, str):
value = value.replace(old, new)
out_dict[key] = value
return out_dict
# ----
[docs]def dict_toobject(in_dict: Dict) -> SimpleNamespace:
"""
Description
-----------
This funcction converts and returns the Python dictionary
`in_dict`, specified upon entry, to a Python Namespace `out_obj`.
Parameters
----------
in_dict: Dict
A Python dictionary containing the attribute key and value
pairs to be cast as a Python Namespace.
Returns
-------
out_obj: SimpleNamespace
A Python SimpleNamespace defined by casting the Python
dictionary `in_dict` specified upon input to the respective
Python SimpleNamespace.
"""
# Define the Python namespace
out_obj = SimpleNamespace(**in_dict)
return out_obj
# ----
[docs]def enviro_get(envvar: str) -> Union[bool, float, int, str]:
"""
Description
-----------
This function retrieves the environment variable corresponding to
the specified string; if the environment variable is not defined,
NoneType is returned.
Parameters
----------
envvar: str
A Python string specifying the environment variable name.
Returns
-------
envvarval: Union[bool, float, int, str]
A Python type that contains the query for the environment
variable.
"""
# Parse the run-time environment and return the attributes of the
# environment variable specified upon entry.
if envvar in os.environ:
envvarval = os.environ.get(envvar)
else:
envvarval = None
return envvarval
# ----
[docs]def enviro_set(envvar: str, value: Union[bool, float, int, str]) -> None:
"""
Description
-----------
This function defines the environment variable corresponding to
the supported specified value.
Parameters
----------
envvar: str
A Python string specifying the environment variable name.
value: Union[bool, float, int, str]
A Python value specifying the value of the environment
variable.
"""
# Define the run-time environment variable.
if isinstance(value, list):
os.environ[envvar] = ",".join([item for item in value])
if not isinstance(value, list):
os.environ[envvar] = value
# ----
[docs]def f90_bool(value: Any) -> Any:
"""
Description
-----------
This method will transform boolean type values to a FORTRAN 90
boolean format; if the variable `value` specified upon entry is
not of boolean format the value is returned unaltered.
Parameters
----------
value: Any
A Python variable to be evaluated as a boolean type value; if
a boolean type the corresponding value is returned as a
FORTRAN 90 boolean format.
Returns
-------
value: Any
An evaluated Python variable; if `value` was boolean type upon
entry the returned value is of FORTRAN 90 boolean format; if
not, the unaltered input value is returned.
"""
# Check the type for the respective input value; proceed
# accordingly.
if isinstance(value, bool):
if value:
value = "T"
if not value:
value = "F"
return value
# ----
[docs]def find_commonprefix(strings_list: List) -> str:
"""
Description
-----------
This function returns the common prefix from a list of strings.
Parameters
----------
strings_list: List
A Python list of strings
Returns
-------
common_prefix: str
A Python string specifying the common prefix determined from a
list of Python strings; NoneType if a common prefix cannot be
determined.
"""
# Seek common prefix values from the list of strings specified
# upon entry.
common_prefix = None
if strings_list:
common_prefix = os.path.commonprefix(strings_list)
return common_prefix
# ----
[docs]def handler(
func: Callable,
handle=lambda errmsg: errmsg,
return_none: bool = False,
raise_exception: bool = False,
*args,
**kwargs,
) -> Union[Any, None, Exception]:
"""
Description
-----------
This method permits exceptions to raised (i.e., handled) within
Python list comprehensions.
Parameters
----------
func: Callable
A Python function, often nested within a Python list
comprehension, to be evaluated.
handle: Callable
A Python lambda function to be evaluated within the list
comprehension.
Keywords
--------
return_none: bool, optional
A Python boolean valued variable specifying whether to return
None if an exception is encountered.
raise_exception: bool, optional
A Python boolean values variable specifying to whether to
raise the exception encountered while evaluating the function
within the Python list comprehension.
Other Parameters
----------------
args: Tuple, optional
Python type arguments to be passed to the respective Python
function `func`.
kwargs: Dict, optional
Python type keyword arguments to be passed to the respective
Python function `func`.
Returns
-------
value: Union[Any, None, Exception]
A Python variable type containing the returned expression from
the Python list evaluation of a function (`func`).
"""
# Evaluate the function nested within a Python list comprehension;
# proceed accordingly.
try:
value = func(*args, **kwargs)
except Exception as errmsg:
if return_none:
value = None
if raise_exception:
value = handle(errmsg)
return value
# ----
[docs]def list_get_type(in_list: List, dtype: str) -> List:
"""
Description
-----------
This function parses a list and returns a list of values in
accordance with the specified data type.
Parameters
----------
in_list: List
A Python list containing values possibly of various data
types.
dtype: str
A Python string specifying the data type to be sought.
Returns
-------
var_list: List
A Python list contain values collected from the input list but
of the specified data type.
"""
# Find all items within the list specified upon entry of a
# specified data type upon entry.
var_list = []
try:
for item in in_list:
if isinstance(item, dtype):
var_list.append(item)
except TypeError:
var_list.append(numpy.nan)
return var_list
# ----
[docs]def list_replace_value(in_list: List, old: str, new: str) -> List:
"""
Description
-----------
This function replaces strings within a Python list and returns
the updated Python list; this function adapted from
https://tinyurl.com/list-value-replace.
Parameters
----------
in_list: List
A Python list containing Python strings to be
replaced/updated.
old: str
A Python string value specifying the Python string instance to
be replaced.
new: str
A Python string value specifying the Python string to replace
the value specified by the `old` attribute.
Returns
-------
out_list: List
A Python list updated in accordance within the attributes
specified by the `old` and `new` attributes; otherwise this
Python list is identical to that defined by `in_list`.
"""
# Parse the Python dictionary and proceed accordingly.
out_list = []
for item in in_list:
# Update any Python list instances.
if isinstance(item, list):
item = list_replace_value(item, old, new)
# Update any Python dictionary instances.
elif isinstance(item, dict):
item = dict_replace_value(item, old, new)
# Update any Python string instances.
elif isinstance(item, str):
item = item.replace(old, new)
out_list.append(item)
return out_list
# ----
[docs]def object_append(object_in: object, object_key: str, dict_in: Dict) -> object:
"""
Description
-----------
This function appends the contents of Python dictionary to
specified object key.
Parameters
----------
object_in: object
A Python object to be appended.
object_key: str
A Python string value specifying the input Python object
attribute.
dict_in: Dict
A Python dictionary containing the key and value pairs to
append to the input Python object.
Returns
-------
object_out: object
An appended Python object containing the input Python
dictionary key and value pairs relative to the specified
Python object attribute.
"""
# Define the output object and the Python dictionary in accordance
# with the arguments provided upon entry.
object_out = object_in
object_dict = object_getattr(object_in=object_in, key=object_key)
# Build the Python dictionary.
for key in dict_in.keys():
value = dict_key_value(dict_in=dict_in, key=key, no_split=True)
object_dict[key] = value
# Build the output Python object.
object_out = object_setattr(object_in=object_out, key=object_key, value=object_dict)
return object_out
# ----
[docs]def object_compare(obj1: object, obj2: object) -> bool:
"""
Description
-----------
This function compares two Python objects.
Parameters
----------
obj1: object
A Python object against which to compare with another object.
obj2: object
A Python object to compare to `obj1` (above).
Returns
-------
compare: bool
A Python boolean variable specifying whether the respective
Python objects are identical.
"""
# Compare the Python objects provided upon entry.
compare = obj1 == obj2
return compare
# ----
[docs]def object_deepcopy(object_in: object) -> object:
"""
Description
-----------
This function ingests a Python object and returns a deep copy of
the respective object.
Parameters
----------
object_in: object
A Python object for which to create a deep copy.
Returns
-------
object_out: object
A Python object which is a deep copy of the specified input
object `object_in`.
"""
# Create and return a deep copy of the Python object provided upon
# entry.
object_out = copy.deepcopy(object_in)
return object_out
# ----
[docs]def object_define() -> object:
"""
Description
-----------
This function defines an empty Python object.
Returns
-------
empty_obj: object
An empty Python object.
"""
# Initialize an empty Python object/namespace.
empty_obj = SimpleNamespace()
return empty_obj
# ----
[docs]def object_getattr(object_in: object, key: str, force: bool = False) -> Any:
"""
Description
-----------
This function ingests a Python object and a Python attribute and
returns the value of the respective attribute; if `force` is
`True` and the Python object attribute does not exist, this
function returns NoneType.
Parameters
----------
object_in: object
A Python object within which to search for attributes.
key: str
A Python string value specifying the attribute to seek.
Keywords
--------
force: bool, optional
A Python boolean variable; if `True` and in the absence of the
respective attribute within the Python object, NoneType is
returned.
Returns
-------
value: Any
The result of the respective attribute search.
Raises
------
ParserInterfaceError:
- raised if `force` is `False` and the Python object attribute
does not exist.
"""
# Check whether the Python object passed upon entry contains the
# key specified upon entry.
if hasattr(object_in, key):
value = getattr(object_in, key)
# Return the value corresponding to the key or raise an exception
# accordingly.
if not hasattr(object_in, key):
if force:
value = None
if not force:
msg = (
f"The object {object_in} does not contain attribute "
f"{key}. Aborting!!!"
)
raise ParserInterfaceError(msg=msg)
return value
# ----
[docs]def match_list(
in_list: List, match_string: str, exact: bool = False
) -> Tuple[bool, str]:
"""
Description
-----------
This function ingests a Python list and a Python string and
matches, either exact or partial, are sought for the string within
the provided; if `exact` is True upon entry, the matching Python
string is returned if a match is found; otherwise NoneType is
returned; if `exact` is False upon entry, a list of matching
Python strings is returned.
Parameters
----------
in_list: List
A Python list of strings within matches will be sought.
match_string: str
A Python string for which to search for matches within the
ingested list.
Keywords
--------
exact: bool, optional
A Python boolean variable; if True, a Python string will be
returned assuming a match is made; if False, a Python list of
strings matching `match_string` will be returned assuming
matches can be made.
Returns
-------
match_chk: bool
A Python boolean variable indicating whether a match (or
matches) has (have) been made.
match_str: str
A Python string (if `exact` is True upon entry) or a Python
list of strings (if `exact` is False upon entry) containing
all matches to the input match string; if no matches can be
found, either NoneType (if `exact` is True upon entry) or an
empty list (if `exact` is False upon entry) is returned.
"""
# Define the local lists to be used for the matching application.
lower_list = [word for word in in_list if word.islower()]
upper_list = [word for word in in_list if word.isupper()]
mixed_list = [word for word in in_list if not word.islower() and not word.isupper()]
match_chk = False
# If appropriate, seek exact matches; proceed accordingly.
if exact:
match_str = None
for string in lower_list:
if match_string.lower() == string.lower():
match_chk = True
match_str = string
break
for string in upper_list:
if match_string.lower() in string.lower():
match_chk = True
match_str = string
break
for string in mixed_list:
if match_string.lower() == string.lower():
match_chk = True
match_str = string
break
# If appropriate, seek non-exact matches; proceed accordingly.
if not exact:
match_str = []
for string in lower_list:
if match_string.lower() in string.lower():
match_str.append(string)
for string in upper_list:
if match_string.lower() in string.lower():
match_str.append(string)
for string in mixed_list:
if match_string.lower() in string.lower():
match_str.append(string)
if len(match_str) > 0:
match_chk = True
return (match_chk, match_str)
# ----
[docs]def object_hasattr(object_in: object, key: str) -> bool:
"""
Description
-----------
This function checks whether a Python object contains an attribute
and returns an appropriate boolean value indicating the result of
the inquiry.
Parameters
----------
object_in: object
A Python object within which to inquire about attributes.
key: str
A Python string value specifying the attribute to inquire
about.
Returns
-------
chk_attr: bool
A Python boolean value containing the result of the attribute
inquiry.
"""
# Check whether the Python object specified upon entry contains
# the key specified upon entry.
chk_attr = hasattr(object_in, key)
return chk_attr
# ----
[docs]def object_setattr(
object_in: object,
key: str,
value: Any,
) -> object:
"""
Description
-----------
This function ingests a Python object and a Python key and value
pair and defines the attributes for the respective object.
Parameters
----------
object_in: object
A Python object within which to search for attributes.
key: str
A Python string value specifying the attribute to define.
value: Any
A Python variable value specifying the value to accompany the
Python object attribute (`key`).
Returns
-------
object_out: object
A Python object containing the specified key and value pair
(e.g., attribute).
"""
# Copy the Python object specified upon entry and define the new
# attribute using the key and value pair specified upon entry.
object_out = object_in
setattr(object_out, key, value)
return object_out
# ----
[docs]def object_todict(object_in: object) -> Dict:
"""
Description
-----------
This function ingests a Python object and returns a Python
dictionary containing the contents of the object.
Parameters
----------
object_in: object
A Python object containing specified content.
Returns
-------
dict_out: Dict
A Python dictionary containing the contents of the Python
object.
"""
# Build a Python dictionary containing the contents of the Python
# object specified upon entry.
dict_out = vars(object_in)
return dict_out
# ----
def singletrue(bool_list: List) -> bool:
"""
Description
-----------
This function ingests a list of boolean (e.g., logical) variables
(`bool_list`) and returns True if a single true value is in the
boolean list or False otherwise.
Parameters
----------
bool_list: List
A Python list of boolean type variables.
Returns
-------
check: bool
A Python boolean variable specifying whether only a single
True value is within the respective boolean list; if so, True
is returned; otherwise False is returned.
"""
# Build a generator function using the list of boolean variables
# specified upon entry.
iterator = iter(bool_list)
# Check the total number of True values within the list of boolean
# variables specified upon entry and proceed accordingly.
has_true = any(iterator)
has_another_true = any(iterator)
check = has_true and not has_another_true
return check
# ----
[docs]def str_to_bool(string: str) -> bool:
"""
Description
-----------
This function converts a Python string to it's corresponding
boolean value; if a JSONDecodeError exception is encountered,
NoneType is returned.
Parameters
----------
string: str
A Python string for which to convert to a corresponding
boolean value.
Returns
-------
boolval: bool
A Python boolean valued variable containing the boolean value
corresponding to the Python string specified upon entry; if a
JSONDecodeError is encounterd, NoneType is returned.
"""
# Convert the string value to it's corresponding boolean value;
# proceed accordingly.
try:
boolval = json.loads(string.lower())
except JSONDecodeError:
boolval = None
return boolval
# ----
[docs]def string_parser(in_list: List, remove_comma: bool = False) -> List:
"""
Description
-----------
This function ingests a Python list of variables and returns a
Python list of appropriately formatted values.
Parameters
----------
in_list: List
A Python list of variable values to be formatted.
Keywords
--------
remove_comma: bool, optional
A Python boolean variable specifying to remove any comma
string occurances in the returned list (see `out_list`).
Returns
-------
out_list: List
A Python list of appropriately formatted variable values.
"""
# Initialize the output list.
out_list = []
# Build the output list; proceed accordingly.
try:
for value in in_list:
test_value = value
try:
if isinstance(test_value, str):
test_value = test_value.encode("ascii", "ignore")
except NameError:
pass
# Boolean-type variable instances.
if isinstance(test_value, bool):
if test_value:
value = True
if not test_value:
value = False
# String-type variable instances.
if isinstance(test_value, str):
try:
dummy = float(test_value)
if "." in test_value:
value = float(test_value)
else:
value = int(test_value)
# Update any values passed as strings accordingly.
except ValueError:
if test_value.lower() == "none":
value = None
elif test_value.lower() == "true":
value = True
elif test_value.lower() == "false":
value = False
else:
value = str(test_value)
try:
value = value.rsplit()[0]
except AttributeError:
pass
out_list.append(value)
except TypeError:
value = None
out_list.append(value)
# Update the output list accordingly.
if remove_comma:
new_list = []
for item in out_list:
if item != ",":
new_list.append(item)
out_list = new_list
return out_list
# ----
[docs]def true_or_false(argval: Any) -> Union[bool, None]:
"""
Description
-----------
This function checks whether an argument is a Boolean-type value;
if so, this function defines the appropriate Python boolean-type;
otherwise, this function returns NoneType.
Parameters
----------
argval: Any
A value corresponding to an argument.
Returns
-------
pytype: Union[bool or None]
A Python boolean-type value if the argument is a boolean
variable; otherwise, NoneType.
"""
# Check the arguments provided upon entry and proceed accordingly.
string = str(argval).upper()
if "TRUE".startswith(string):
pytype = True
elif "FALSE".startswith(string):
pytype = False
else:
pytype = None
return pytype
# ----
[docs]def unique_list(in_list: List) -> List:
"""
Description
-----------
This function ingests a list, possibly with duplicate values, and
returns a list of only unique values.
Parameters
----------
in_list: List
A N-dimensional Python list containing strings.
Returns
-------
out_list: List
A Python list containing only uniquely-valued strings.
"""
out_list = []
out_dict = collections.OrderedDict.fromkeys(x for x in in_list if x not in out_list)
out_list = []
for key in sorted(out_dict.keys()):
out_list.append(key.replace(" ", ""))
return out_list
# ----
[docs]def update_dict(default_dict: Dict, base_dict: Dict, update_none: bool = False) -> Dict:
"""
Description
-----------
This function reads Python dictionaries containing default key and
value pairs (`default_dict`) and a base (optional or changed
values) Python dictionary containing key and value pairs
(`base_dict`); the output Python dictionary `output_dict` is
initialized with the base Python dictionary; any key and value
pairs within `default_dict` which are not in `output_dict` are
updated with those from `default_dict`.
Parameters
----------
default_dict: Dict
A Python dictionary containing default key and value pairs;
this Python dictionary contains all possible key and value
pairs to compute the output dictionary (`output_dict`).
base_dict: Dict
A Python dictionary containing either optional or changed key
and value pairs; this Python dictionary is used to initialize
the output Python dictionary `output_dict`.
Keywords
--------
update_none: bool, optional
A Python boolean valued variable specifying whether to update
the output Python dictionary `output_dict` with None-type
value occurances within the default Python dictionary
`default_dict`.
Returns
-------
output_dict: Dict
A Python dictionary containing the respective attributes from
the base and default Python dictionaries, `base_dict` and
`default_dict` respectively.
"""
# Initialize the output Python dictionary.
output_dict = base_dict
# For any keys missing from the base Python dictionary
# `base_dict`, update with the key and value pairs from the
# default Python dictionary `default_dict`.
for key in default_dict:
if key not in output_dict:
# Collect the key and value pair.
value = dict_key_value(
dict_in=default_dict, key=key, force=True, no_split=True
)
# Update the Python dictionary accordingly.
if update_none:
if value is None:
pass
if not update_none:
output_dict[key] = value
return output_dict