Source code for revscoring.scoring.model_info
from collections import OrderedDict
from ..errors import ModelInfoLookupError
from . import util
[docs]class ModelInfo:
def __init__(self, pairs=[], default_fields=None):
"""
Constructs a mapping of information about a model.
:class:`~revscoring.scoring.ModelInfo` objects are usually nested
within each other to provide a convenient tree structure for
:func:`~revscoring.scoring.ModelInfo.lookup` and
:func:`~revscoring.scoring.ModelInfo.format`.
"""
self._data = OrderedDict(pairs)
self._default_fields = set(default_fields) \
if default_fields is not None else None
def __len__(self):
return len(self.keys())
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __contains__(self, key):
try:
return (key in self._data or
key in ('true', 'false') and key == 'true' in self._data or
int(key) in self._data)
except ValueError:
return False
def keys(self):
return self._data.keys()
def get(self, key, default=None):
return self._data.get(key, default)
def values(self):
return self._data.values()
def items(self):
return self._data.items()
def __iter__(self):
return iter(self._data)
def move_to_end(self, key, last=True):
return self._data.move_to_end(key, last=last)
[docs] def lookup(self, path=None):
"""
Looks up a specific information value based on either a string pattern
or a path.
For example, the pattern "stats.roc_auc.labels.true" is the same as
the path ``['stats', 'roc_auc', 'labels', True]``.
:Parameters:
path : `str` | `list`
The location of the information to lookup.
"""
if isinstance(path, str):
path = util.parse_pattern(path)
elif path is None:
path = []
d = self
remaining_path = list(path) # Make sure we don't overwrite the input
while len(path) > 0:
key = path.pop(0)
d = try_key(key, d)
if hasattr(d, "lookup"):
return d.lookup(remaining_path)
else:
continue
return d
def format_str(self, path_tree, **kwargs):
formatted = "Model Information:\n"
for key in self.normalize_fields(path_tree):
key_val = try_key(key, self)
if hasattr(key_val, "format_str"):
sub_tree = path_tree.get(key, {})
formatted += util.tab_it_in(
key_val.format_str(sub_tree, **kwargs))
else:
formatted += util.tab_it_in(" - {0}: {1}"
.format(key, key_val))
return formatted
def format_json(self, path_tree, **kwargs):
d = OrderedDict()
for key in self.normalize_fields(path_tree):
key_val = try_key(key, self)
if hasattr(key_val, "format_json"):
sub_tree = path_tree.get(key, {})
d[key] = key_val.format_json(sub_tree, **kwargs)
else:
d[key] = key_val
return d
def normalize_fields(self, path_tree):
if len(path_tree) > 0:
yield from path_tree.keys()
else:
for field in self.keys():
if self._default_fields is None or \
field in self._default_fields:
yield field
def try_key(key, d):
try:
return d[key]
except KeyError:
try:
if key in ("true", "false"):
return d[key == 'true']
else:
try:
return d[int(key)]
except ValueError:
raise ModelInfoLookupError(key)
except KeyError:
raise ModelInfoLookupError(key)