Skip to content

Commit

Permalink
Added documentation to inputs.py
Browse files Browse the repository at this point in the history
I also reformatted enums.py
  • Loading branch information
Robert Stephany committed Oct 28, 2024
1 parent 8dab79d commit 4bbd63a
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 42 deletions.
16 changes: 8 additions & 8 deletions src/lasdi/enums.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from enum import Enum

class NextStep(Enum):
Train = 1
PickSample = 2
RunSample = 3
CollectSample = 4
Train = 1
PickSample = 2
RunSample = 3
CollectSample = 4

class Result(Enum):
Unexecuted = 1
Success = 2
Fail = 3
Complete = 4
Unexecuted = 1
Success = 2
Fail = 3
Complete = 4
160 changes: 126 additions & 34 deletions src/lasdi/inputs.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,159 @@
# -------------------------------------------------------------------------------------------------
# Imports
# -------------------------------------------------------------------------------------------------

from warnings import warn

verbose = False
verbose : bool = False


# -------------------------------------------------------------------------------------------------
# Input Parser class
# -------------------------------------------------------------------------------------------------

class InputParser:
dict_ = None
name = ""
"""
A InputParser objects acts as a wrapper around a dictionary of settings. Thus, each setting is
a key and the corresponding value is the setting's value. Because one setting may itself be
a dictionary (we often group settings; each group has a name but several constituent settings),
the underlying dictionary is structured as a sequence of nested dictionaries. This class allows
the user to select a specific setting from that structure by specifying (via a list of strings)
where in that nested structure the desired setting lives.
"""
dict_ : dict = None
name : str = ""



def __init__(self, dict : dict, name : str = "") -> None:
""""
Initializes an InputParser object by setting the underlying dictionary of settings as an
attribute.
-------------------------------------------------------------------------------------------
Arguments
-------------------------------------------------------------------------------------------
dict: The dictionary of settings. To avoid the risk of the user accidentally changing one
of the settings after wrapping it, we store a deep copy of dict in self.
"""

def __init__(self, dict, name = ""):
# A shallow copy could cause issues if the user changes dict's keys/values after
# initializing this object. We store a deep copy to avoid this risk.
from copy import deepcopy
self.dict_ = deepcopy(dict)

self.name = name
return

def getInput(self, keys, fallback=None, datatype=None):


def getInput(self, keys : list, fallback = None, datatype = None):
'''
Find the value corresponding to the list of keys.
If the specified keys do not exist, use the fallback value.
If the fallback value does not exist, returns an error.
If the datatype is specified, enforce the output value has the right datatype.
A InputParser object acts as a wrapper around a dictionary of settings. That is, self.dict_
is structured as a nested family of dictionaries. Each setting corresponds to a key in
self.dict_. The setting's value is the corresponding value in self.dict_. In many cases,
a particular setting may be nested within others. That is, a setting's value may itself be
another dictionary housing various sub-settings. This function allows us to fetch a
specific setting from this nested structure.
Specifically, we specify a list of strings. keys[0] should be a key in self.dict_
If so, we set val = self.dict_[keys[0]]. If there are more keys, then val should be a
dictionary and keys[1] should be a key in this dictionary. In this case, we replace val
with val[key[1]] and so on. This continues until we have exhausted all keys. There is one
important exception:
If at some point in the process, there are more keys but val is not a dictionary, or if
there are more keys and val is a dictionary but the next key is not a key in that
dictionary, then we return the fallback value. If the fallback value does not exist,
returns an error.
-------------------------------------------------------------------------------------------
Arguments
-------------------------------------------------------------------------------------------
keys: A list of keys we want to fetch from self.dict. keys[0] should be a key in self.dict_
If so, we set val = self.dict_[keys[0]]. If there are more keys, then val should be a
dictionary and keys[1] should be a key in this dictionary. In this case, we replace val
with val[key[1]] and so on. This continues until we have exhausted all keys.
fallback: A sort of default value. If at some point, val is not a dictionary (and there are
more keys) or val is a dictionary but the next key is not a valid key in that dictionary,
then we return the fallback value.
datatype: If not None, then we require that the final val has this datatype. If the final
val does not have the desired datatype, we raise an exception.
-------------------------------------------------------------------------------------------
Returns
-------------------------------------------------------------------------------------------
The final val value as outlined by the process described above.
'''

# Concatenate the keys together. This is for debugging purposes.
keyString = ""
for key_ in keys:
keyString += key_ + "/"

# Begin by initializing val to self.dict_
val = self.dict_

# Cycle through the keys
for key in keys:

# Check if the current key is a key in val (this assumes val is a dictionary). If so,
# update val. Otherwise, return the fallback (if it is present) or raise an exception.
if key in val:
val = val[key]
elif (fallback != None):
return fallback
else:
raise RuntimeError("%s does not exist in the input dictionary %s!" % (keyString, self.name))


# Check if the fallback and final val have the same type.
if (fallback != None):
if (type(val) != type(fallback)):
warn("%s does not match the type with the fallback value %s!" % (str(type(val)), str(type(fallback))))


# Check thast the final val matches the desired datatype
if (datatype != None):
if (type(val) != datatype):
raise RuntimeError("%s does not match the specified datatype %s!" % (str(type(val)), str(datatype)))
else:
if verbose: warn("InputParser Warning: datatype is not checked.\n key: %s\n value type: %s" % (keys, type(val)))

# All done!
return val

def getDictFromList(list_, inputDict):
'''
get a dict with {key: val} from a list of dicts
NOTE: it returns only the first item in the list,
even if the list has more than one dict with {key: val}.
'''
dict_ = None
for item in list_:
isDict = True
for key, val in inputDict.items():
if key not in item:
isDict = False
break
if (item[key] != val):
isDict = False
break
if (isDict):
dict_ = item
break
if (dict_ == None):
raise RuntimeError('Given list does not have a dict with {%s: %s}!' % (key, val))
return dict_


# -------------------------------------------------------------------------------------------------
# Unused: getDictFromList function
# -------------------------------------------------------------------------------------------------

#def getDictFromList(list_, inputDict):
# '''
# get a dict with {key: val} from a list of dicts
# NOTE: it returns only the first item in the list,
# even if the list has more than one dict with {key: val}.
# '''
# dict_ = None
# for item in list_:
# isDict = True
# for key, val in inputDict.items():
# if key not in item:
# isDict = False
# break
# if (item[key] != val):
# isDict = False
# break
# if (isDict):
# dict_ = item
# break
# if (dict_ == None):
# raise RuntimeError('Given list does not have a dict with {%s: %s}!' % (key, val))
# return dict_

0 comments on commit 4bbd63a

Please sign in to comment.