bpod_core.misc

Miscellaneous tools that don’t fit the other categories.

Classes

class bpod_core.misc.ByteEnum

Bases: IntEnum

An IntEnum restricted to single-byte values (0–255).

Subclass this to define enums whose integer values fit in one unsigned byte. Each member additionally exposes its value as a bytes object via byte_value for zero-allocation wire encoding.

Raises:

OverflowError – If a member’s value is outside the range of a single, unsigned byte.

Examples

Subclass ByteEnum to create a custom enum type:

>>> class Color(ByteEnum):
...     RED = 1
...     GREEN = 2

It can be used like a regular IntEnum:

>>> Color.RED.value
1

Additionally, you can access it’s values as bytes objects:

>>> Color.RED.byte_value
b'\x01'
property byte_value: bytes

The member’s value as a bytes object.

class bpod_core.misc.SettingsDict

Bases: MutableMapping[str, Any]

A dictionary-like persistent settings storage backed by a JSON file.

This class implements the MutableMapping interface, storing key-value pairs that are automatically persisted to a JSON file on every write. It supports standard dictionary operations (get, set, delete, iterate) as well as nested key access.

File access is protected by a file lock for safe concurrent access from multiple processes.

Parameters:

json_path (PathLike | str) – Path to the JSON configuration file.

get_nested(keys, default=None)

Retrieve a nested value using a sequence of keys.

Parameters:
  • keys (Sequence[str]) – A sequence of keys representing the nested path.

  • default (Any | None, default: None) – The value to return if the path does not exist.

Returns:

The value at the nested path, or default if any key in the path is missing.

Return type:

Any

set_nested(keys, value)

Set a nested value using a sequence of keys.

Parameters:
  • keys (Sequence[str]) – A sequence of keys representing the nested path.

  • value (Any) – The value to set at the nested path.

class bpod_core.misc.SuggestionDict

Bases: dict[str, V]

A dictionary that suggests similar keys on failed lookup.

On KeyError, raises error_class with a message that includes the closest match from the existing keys via suggest_similar(), making typos and near-misses easier to diagnose.

Parameters:
  • dictionary (MutableMapping[str, TypeVar(V)]) – Initial key-value pairs.

  • name (str | None, default: None) – Human-readable label for the key type used in the error message.

  • error_class (type[Exception], default: <class 'KeyError'>) – Exception class to raise on failed lookup. Must accept a single string argument.

Examples

>>> d = SuggestionDict({'Port1': 1, 'Port2': 2}, name='channel')
>>> d['Port1']
1
>>> d['Prot1']
Traceback (most recent call last):
    ...
KeyError: "No such channel: 'Prot1' - did you mean 'Port1'?"
class bpod_core.misc.ValidatedDict

Bases: RootModel, MutableMapping[K, V]

A dict-like container with runtime validation for keys and values.

This class wraps a standard dict and integrates with Pydantic’s RootModel to validate keys and values upon mutation. It behaves like a mutable mapping for all common operations (get, set, delete, iterate, len) and compares equal to regular dicts with the same contents.

Parameters:

root (TypeVar(RootModelRootType), default: PydanticUndefined) – Initial key-value pairs. Defaults to an empty dict.

Examples

Subclass ValidatedDict to create a custom type with validation:

>>> class TestDict(ValidatedDict[str, int]):
...     pass

You can then instantiate your class TestDict like a regular dict:

>>> test_dict = TestDict()
>>> test_dict['foo'] = 1
>>> test_dict[42] = 2
Traceback (most recent call last):
   ...
pydantic_core._pydantic_core.ValidationError: 1 validation error for TestDict
42.[key]
  Input should be a valid string [type=string_type, input_value=42, input_type=int]
  ...

Alternatively, you can also instantiate a ValidatedDict directly:

>>> my_validated_dict = ValidatedDict[str, int]({'foo': 1, 'bar': 2})
>>> my_validated_dict['foo'] = 'bar'
Traceback (most recent call last):
   ...
pydantic_core._pydantic_core.ValidationError: 1 validation error ...
foo
  Input should be a valid integer, unable to parse string as an integer ...
  ...

Functions

bpod_core.misc.extend_packed(byte_array, values, fmt)

Extend a bytearray with packed binary values.

This function takes a sequence of integers, converts each one to bytes using the specified struct format character, and appends the result to the given bytearray. All values use the same format character and are packed in little-endian byte order.

Parameters:
  • byte_array (bytearray) – The bytearray that will be modified in-place by appending the packed binary data.

  • values (Sequence[int]) – Integer values to convert to binary. The number of values determines how many times the format character is repeated.

  • fmt (str) – A single struct format character that defines how each value is encoded. Common options: ‘b’ (int8), ‘h’ (int16), ‘i’ (int32), ‘q’ (int64), ‘B’ (uint8), ‘H’ (uint16), ‘I’ (uint32), ‘Q’ (uint64).

Examples

>>> from bpod_core.misc import extend_packed
>>> buffer = bytearray()
>>> extend_packed(buffer, [1, 2, 3], 'i')
>>> len(buffer)
12
>>> buffer.hex()
'010000000200000003000000'

See also

Format characters used by the struct module.

bpod_core.misc.get_local_ipv4()

Determine the primary local IPv4 address of the machine.

This function attempts to determine the IPv4 address of the local machine that would be used for an outbound connection to the internet. It does this by creating a UDP socket and connecting to a known public IP address (Google DNS at 8.8.8.8). No data is sent, but the OS uses the routing table to select the appropriate local interface.

Returns:

The local IPv4 address as a string. If the network is unreachable or unavailable, returns the loopback address 127.0.0.1.

Return type:

str

Raises:

OSError – If an unexpected socket error occurs during interface detection.

bpod_core.misc.get_nested(d, keys, default=None)

Retrieve a value from a nested dict using a Sequence of keys.

Parameters:
  • d (MutableMapping) – The dictionary from which to get a value.

  • keys (Sequence[Any]) – A sequence of keys representing the path to the desired value.

  • default (Any, default: None) – The value to return if the path does not exist.

Returns:

The value at the nested path, or default if any key in the path is missing.

Return type:

Any

Examples

>>> from bpod_core.misc import get_nested
>>> dictionary = {'a': {'b': {'c': 42}}}
>>> get_nested(dictionary, ['a', 'b', 'c'])
42
>>> get_nested(dictionary, ['a', 'x'], default='missing')
'missing'
bpod_core.misc.prune_empty_parent_directories(target_directory, root_directory, *, remove_root=False)

Remove empty parent directories recursively up to root directory.

Recursively removes the given directory if empty, then checks and removes parent directories up to (and optionally including) the root directory. Stops at the first non-empty directory encountered.

Parameters:
  • target_directory (PathLike | str) – Directory to check and remove if empty.

  • root_directory (PathLike | str) – Root directory to stop at. Must be a parent directory of target_directory.

  • remove_root (bool, default: False) – If True, also remove root_directory if it becomes empty.

Raises:
  • ValueError – If target_directory is not a subpath of root_directory.

  • FileNotFoundError – If target_directory or root_directory does not exist.

  • NotADirectoryError – If target_directory or root_directory is not a directory.

bpod_core.misc.set_nested(d, keys, value)

Set a value in a nested dict, creating intermediate dicts as needed.

Parameters:
  • d (MutableMapping) – The dictionary in which to set the value.

  • keys (Sequence[Any]) – A sequence of keys representing the nested path where the value should be set.

  • value (Any) – The value to set at the specified path.

Examples

>>> from bpod_core.misc import set_nested
>>> dictionary = {}
>>> set_nested(dictionary, ['a', 'b', 'c'], 42)
>>> dictionary
{'a': {'b': {'c': 42}}}
>>> set_nested(dictionary, ['a', 'b', 'x'], 99)
>>> dictionary
{'a': {'b': {'c': 42, 'x': 99}}}
bpod_core.misc.suggest_similar(invalid_string, valid_strings, format_string=" - did you mean '{}'?", cutoff=0.6)

Suggest a similar valid string based on the given invalid string.

This function uses a similarity matching algorithm to find the closest match from an iterable of valid strings. If a match is found above the specified cutoff, it returns a formatted suggestion string.

Parameters:
  • invalid_string (str) – The string that is invalid or misspelled.

  • valid_strings (Iterable[str]) – An iterable of valid strings to compare against.

  • format_string (str, default: " - did you mean '{}'?") – The format string for the suggestion.

  • cutoff (float, default: 0.6) – The similarity threshold for considering a match.

Returns:

A formatted suggestion string if a match is found, otherwise an empty string.

Return type:

str

Examples

>>> 'no such port' + suggest_similar('Prot1', ['Port1', 'Port2'])
"no such port - did you mean 'Port1'?"
>>> 'no such port' + suggest_similar('xyz', ['Port1', 'Port2'])
'no such port'
bpod_core.misc.suppress_logging(level=50)

Temporarily suppress logging up to and including the specified level.

The previous global logging disable level is restored when exiting the context, even if an exception is raised.

Parameters:

level (int, default: 50) – Logging level to suppress. Messages at this level and below will be ignored while the context is active. The default suppresses all standard logging messages.

Yields:

None

Return type:

Iterator[None]

bpod_core.misc.to_snake_case(string)

Convert a given string to snake_case.

Parameters:

string (str) – The input string to be converted.

Returns:

The converted snake_case string.

Return type:

str

Examples

>>> to_snake_case('CamelCase')
'camel_case'
>>> to_snake_case('HTMLParser')
'html_parser'
>>> to_snake_case('version2dot0')
'version_2_dot_0'

Attributes

bpod_core.misc.K = ~K

Key type variable for generic mappings such as ValidatedDict.

bpod_core.misc.V = ~V

Value type variable for generic mappings such as ValidatedDict.