scriptharness.structures module

Data structures for configs.

There are two config dict models here:
  • LoggingDict logs any changes to the dict or its children. When debugging, config changes will be marked in the log. This is the default model.
  • ReadOnlyDict recursively locks the dictionary. This is to aid in debugging; one can assume the config hasn’t changed from the moment of locking. This is the original mozharness model.
scriptharness.structures.DEFAULT_LEVEL

int

the default logging level to set

scriptharness.structures.DEFAULT_LOGGER_NAME

str

the default logger name to use

scriptharness.structures.QUOTES

tuple

the order of quotes to use for key logging

scriptharness.structures.LOGGING_STRINGS

dict

a dict of strings to use for logging, for easier unittesting and potentially for future localization.

scriptharness.structures.MUTED_LOGGING_STRINGS

dict

a dict of strings to use for logging when the values in the list/dict shouldn’t be logged

scriptharness.structures.SUPPORTED_LOGGING_TYPES

dict

a non-logging to logging class map, e.g. dict: LoggingDict. Not currently supporting sets or collections.

class scriptharness.structures.LockedTuple

Bases: tuple

A tuple with its children recursively locked.

Tuples are read-only by nature, but we need to be able to recursively lock the contents of the tuple, since the tuple can contain dicts or lists.

Taken straight from mozharness.

__deepcopy__(memo)

Return a list on deepcopy.

class scriptharness.structures.LoggingClass

Bases: object

General logging methods for the Logging* classes to subclass.

level

int

the logging level for changes

logger_name

str

the logger name to use

name

str

the name of the class for logs

parent

str

the name of the parent, if applicable, for logs

ancestor_child_list(child_list=None)

Get the original ancestor of self, and the descending, linear list of descendents’ names leading up to (and including) self.

Parameters:child_list (list, automatically generated) – in a multi-level nested Logging* class, generate the list of children’s names. This list will be built by prepending our name and calling ancestor_child_list() on self.parent.
Returns:(ancestor, child_list) – for self.full_name and self.log_change support
Return type:LoggingClass, list
full_name()

Get the full name of self.

This will call self.ancestor_child_list to get the original ancestor + all the names of its descendents up to and including self, then build the name from that.

Parameters:
  • ancestor (Optional[LoggingClass]) – specify the ancestor
  • child_list (Optional[list]) – a list of descendents’ names, in order
Returns:

name – the full name of self.

Return type:

string

items()

Return dict.items() for dicts, and enumerate(self) for lists+tuples.

This both simplifies recursively_set_parent() and silences pylint complaining that LoggingClass doesn’t have an items() method.

The main negative here might be adding an attr items to non-dict data types.

level = None
log_change(message, repl_dict=None)

Log a change to self.

Parameters:message (str) – The message to log.
logger_name = None
name = None
parent = None
recursively_set_parent(name=None, parent=None)

Recursively set name + parent.

If our LoggingDict is a multi-level nested Logging* instance, then seeing a log message that something in one of the Logging* instances has changed can be confusing. If we know that it’s grandparent[parent][self][child] that has changed, then the log message is helpful.

For each child, set name automatically. For dicts, the name is the key. For everything else, the name is the index.

Parameters:
  • name (Optional[str]) – set self.name, for later logging purposes. Defaults to None.
  • parent (Optional[Logging*]) – set self.parent, for logging purposes. Defaults to None.
class scriptharness.structures.LoggingDict(items, level=20, muted=False, logger_name=u'scriptharness.data_structures')

Bases: scriptharness.structures.LoggingClass, dict

A dict that logs any changes, as do its children.

level

int

the logging level for changes

logger_name

str

the logger name to use

muted

bool

whether our logging messages are muted

strings

dict

a dict of strings to use for messages

__deepcopy__(memo)

Return a dict on deepcopy()

child_set_parent(key)

When the dict changes, we can just target the specific changed children. Very simple wrapper method.

Parameters:key (str) – the dict key to the child value.
clear()
log_update(key, value)

Helper method for update(): log one key/value pair at a time.

Parameters:
  • key (str) – key to update
  • value (any) – value to set
Returns:

key (str) if it doesn’t exist in self, else None

pop(key, default=None)
popitem()
setdefault(key, default=None)
update(args)
class scriptharness.structures.LoggingList(items, level=20, muted=False, logger_name=u'scriptharness.data_structures')

Bases: scriptharness.structures.LoggingClass, list

A list that logs any changes, as do its children.

level

int

the logging level for changes

logger_name

str

the logger name to use

muted

bool

whether our logging messages are muted

strings

dict

a dict of strings to use for messages

__deepcopy__(memo)

Return a list on deepcopy.

append(item)
child_set_parent(position=0)

When the list changes, we either want to change all of the children’s names (which correspond to indeces) or a subset of [position:]

extend(item)
insert(position, item)
log_self()

Log the current list.

Since some methods insert values or rearrange them, it’ll be easier to debug things if we log the list after those operations.

pop(position=None)
remove(item)
reverse()
sort(*args, **kwargs)
class scriptharness.structures.LoggingTuple

Bases: scriptharness.structures.LoggingClass, tuple

A tuple whose children log any changes.

__deepcopy__(memo)

Return a tuple on deepcopy.

class scriptharness.structures.ReadOnlyDict(*args, **kwargs)

Bases: dict

A dict that is lockable. When locked, any changes raise exceptions.

Slightly modified version of mozharness.base.config.ReadOnlyDict, largely for pylint.

_lock

bool

When locked, the dict is read-only and cannot be unlocked.

__deepcopy__(memo)

Create an unlocked ReadOnlyDict on deepcopy()

clear(*args)
lock()

Recursively lock the dictionary.

pop(*args)
popitem(*args)
setdefault(*args)
update(*args)
scriptharness.structures.add_logging_to_obj(item, **kwargs)

Recursively add logging to all contents of a LoggingDict.

Any children of supported types will also have logging enabled. Currently supported:: list, tuple, dict.

Parameters:item (object) – a child of a LoggingDict.
Returns:A logging version of item, when applicable, or item.
scriptharness.structures.get_strings(instance_type, muted=False)

Get the strings for LoggingClass instance, muted or unmuted

Parameters:
  • instance (obj) – LoggingClass instance or ‘list’ or ‘dict’
  • muted (Optional[bool]) – return the MUTED_LOGGING_STRINGS strings if True
scriptharness.structures.is_logging_class(item)

Determine if a class is one of the Logging* classes.

Parameters:item (object) – the object to check.
scriptharness.structures.iterate_pairs(data)

Iterate over pairs of a data structure.

Usage:: for key, value in iterate_pairs(data_structure):

:param data: a dict, iterable-of-iterable pairs
scriptharness.structures.make_immutable(item)

Recursively lock all contents of a ReadOnlyDict.

Any children of supported types will also be locked. Currently supported:: list, tuple, dict.

and we locked r on a shallow level, we could still r[‘b’].append() or r[‘c’][‘key2’] = ‘value2’. So to avoid that, we need to recursively lock r via make_immutable.

Parameters:item (object) – a child of a ReadOnlyDict.
Returns:A locked version of item, when applicable, or item.