Skip to content

Collections

Collection classes and utilities for working with collections of data.

Classes

DeepChainMap

A recursive capable deep chain map.

Tree

A subclass of dict for creating tree structures from sequences.

ValidatedStr

A class for creating validated strings based on regex patterns.

Mixins

PostInitMixin

A mixin class for handling post-initialization tasks.

PydanticStrMixin

A mixin for Pydantic models that provides a custom CoreSchema for string validation.

Enums

BaseEnum

A base class for creating enums.

OrderedEnum

A base class for creating ordered enums.

StrEnum

A base class for creating string enums.

OrderedStrEnum

A base class for creating ordered string enums.


BaseEnum

Bases: Enum

Enum extension class that makes string comparisons easier

class MyEnum(BaseEnum): BLARG = "blarg"

assert MyEnum.BLARG == "blarg"

values classmethod

values()

Return a list of all member values.

Returns:

Type Description
list[Any]

List of enum member values.

Source code in src/aibs_informatics_core/collections.py
511
512
513
514
515
516
517
518
@classmethod
def values(cls) -> list[Any]:
    """Return a list of all member values.

    Returns:
        List of enum member values.
    """
    return [c.value for c in cls]

BaseEnumMeta

Bases: EnumMeta

Metaclass for BaseEnum type

DeepChainMap

Bases: ChainMap

A recursive subclass of ChainMap Modified based on https://github.com/neutrinoceros/deep_chainmap solution

to_dict

to_dict()

Flatten all chained maps into a single dictionary.

Performs a depth-first merge of all maps, with earlier maps taking precedence over later ones.

Returns:

Type Description
dict

A single merged dictionary.

Source code in src/aibs_informatics_core/collections.py
71
72
73
74
75
76
77
78
79
80
81
82
83
def to_dict(self) -> dict:
    """Flatten all chained maps into a single dictionary.

    Performs a depth-first merge of all maps, with earlier maps taking
    precedence over later ones.

    Returns:
        A single merged dictionary.
    """
    d: dict = {}
    for mapping in reversed(self.maps):
        self._depth_first_update(d, cast(MutableMapping, mapping))
    return d

OrderedEnum

Bases: BaseEnum

An enum that supports ordering based on member definition order.

OrderedStrEnum

Bases: str, OrderedEnum

A string enum that supports ordering based on member definition order.

values classmethod

values()

Return a list of all member values as strings.

Returns:

Type Description
list[str]

List of enum member values.

Source code in src/aibs_informatics_core/collections.py
567
568
569
570
571
572
573
574
@classmethod
def values(cls) -> list[str]:
    """Return a list of all member values as strings.

    Returns:
        List of enum member values.
    """
    return [cast(str, c.value) for c in cls]

PostInitMixin

Mixin that adds __post_init__ hook support to classes.

When used with add_hook=True in __init_subclass__, automatically calls __post_init__ after __init__ completes. This is useful for adding validation or derived attribute computation after initialization.

PydanticStrMixin

Mixin for Pydantic models that provides a custom CoreSchema for string validation.

StrEnum

Bases: str, BaseEnum

An enum whose members are also strings, allowing direct string comparison.

values classmethod

values()

Return a list of all member values as strings.

Returns:

Type Description
list[str]

List of enum member values.

Source code in src/aibs_informatics_core/collections.py
553
554
555
556
557
558
559
560
@classmethod
def values(cls) -> list[str]:
    """Return a list of all member values as strings.

    Returns:
        List of enum member values.
    """
    return [cast(str, c.value) for c in cls]

Tree

Bases: dict[KT, 'Tree'], Generic[KT]

A recursive dictionary for building tree structures from sequences.

Each key maps to a child Tree, forming an n-ary tree. Provides methods to add, retrieve, and enumerate paths (sequences of keys) through the tree.

add_sequence

add_sequence(*keys)

Add a path of keys to the tree, creating intermediate nodes as needed.

Parameters:

Name Type Description Default
*keys KT

Ordered sequence of keys representing a path from root to leaf.

()
Source code in src/aibs_informatics_core/collections.py
112
113
114
115
116
117
118
119
120
121
122
def add_sequence(self: "Tree[KT]", *keys: KT):
    """Add a path of keys to the tree, creating intermediate nodes as needed.

    Args:
        *keys: Ordered sequence of keys representing a path from root to leaf.
    """
    __self = self
    for key in keys:
        if key not in __self:
            __self[key] = self.__class__()
        __self = __self[key]  # type: ignore

get_sequence

get_sequence(*keys)

Retrieve the subtree at the given path.

Parameters:

Name Type Description Default
*keys KT

Ordered sequence of keys to traverse.

()

Returns:

Type Description
Optional[Tree[KT]]

The subtree at the end of the path, or None if the path does not exist.

Source code in src/aibs_informatics_core/collections.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def get_sequence(self: "Tree[KT]", *keys: KT) -> Optional["Tree[KT]"]:
    """Retrieve the subtree at the given path.

    Args:
        *keys: Ordered sequence of keys to traverse.

    Returns:
        The subtree at the end of the path, or None if the path does not exist.
    """
    __self = self
    for key in keys:
        if key not in __self:
            return None
        __self = __self[key]  # type: ignore
    return __self  # type: ignore

has_sequence

has_sequence(*keys)

Check whether a path of keys exists in the tree.

Parameters:

Name Type Description Default
*keys KT

Ordered sequence of keys to look up.

()

Returns:

Type Description
bool

True if the path exists, False otherwise.

Source code in src/aibs_informatics_core/collections.py
140
141
142
143
144
145
146
147
148
149
def has_sequence(self: "Tree[KT]", *keys: KT) -> bool:
    """Check whether a path of keys exists in the tree.

    Args:
        *keys: Ordered sequence of keys to look up.

    Returns:
        True if the path exists, False otherwise.
    """
    return self.get_sequence(*keys) is not None

to_sequences

to_sequences()

Enumerate all root-to-leaf paths in the tree.

Returns:

Type Description
list[tuple[KT, ...]]

A list of tuples, each representing a path from root to leaf.

Source code in src/aibs_informatics_core/collections.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def to_sequences(self: "Tree[KT]") -> list[tuple[KT, ...]]:
    """Enumerate all root-to-leaf paths in the tree.

    Returns:
        A list of tuples, each representing a path from root to leaf.
    """
    sequences: list[tuple[KT, ...]] = []
    for key in self.keys():
        sub_sequences: list[tuple[KT, ...]] = self[key].to_sequences()  # type: ignore
        if not sub_sequences:
            sequences.append((key,))
        else:
            for sub_sequence in sub_sequences:
                sequences.append((key, *sub_sequence))
    return sequences

ValidatedStr

ValidatedStr(*args, **kwargs)

Bases: str, PostInitMixin, PydanticStrMixin

A string subclass with regex-based validation.

Subclasses should define a regex_pattern class variable to enforce a specific string format. Optional min_len and max_len class variables can constrain string length.

Attributes:

Name Type Description
regex_pattern Pattern

Compiled regex pattern used for validation.

min_len int | None

Minimum allowed string length, or None for no limit.

max_len int | None

Maximum allowed string length, or None for no limit.

Placeholder for subclass to override

Source code in src/aibs_informatics_core/collections.py
302
303
304
def __init__(self, *args, **kwargs):
    """Placeholder for subclass to override"""
    super().__init__()

find_prefix classmethod

find_prefix(string)

Find the first regex match at the start of the string.

Parameters:

Name Type Description Default
string str

The string to search.

required

Returns:

Type Description
S | None

A validated instance of the matched prefix, or None if no prefix matches.

Source code in src/aibs_informatics_core/collections.py
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
@classmethod
def find_prefix(cls: type[S], string: str) -> S | None:
    """Find the first regex match at the start of the string.

    Args:
        string: The string to search.

    Returns:
        A validated instance of the matched prefix, or None if no prefix matches.
    """
    cls.validate_regex_pattern()
    for match in regex_finditer(cls.regex_pattern, string):
        if match.span()[0] == 0:
            return cls(match.group(0))
    return None

find_suffix classmethod

find_suffix(string)

Find the first regex match at the end of the string.

Parameters:

Name Type Description Default
string str

The string to search.

required

Returns:

Type Description
S | None

A validated instance of the matched suffix, or None if no suffix matches.

Source code in src/aibs_informatics_core/collections.py
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
@classmethod
def find_suffix(cls: type[S], string: str) -> S | None:
    """Find the first regex match at the end of the string.

    Args:
        string: The string to search.

    Returns:
        A validated instance of the matched suffix, or None if no suffix matches.
    """
    cls.validate_regex_pattern()
    for match in regex_finditer(cls.regex_pattern, string):
        if match.span()[1] == len(string):
            return cls(match.group(0))
    return None

findall classmethod

findall(string)

Convenience method for re.findall

Parameters:

Name Type Description Default
cls Type[T]

ValidatedStr subclass

required
string str

string to find patterns within

required

Returns:

Type Description
list[S]

List of substrings matching pattern

Source code in src/aibs_informatics_core/collections.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
@classmethod
def findall(cls: type[S], string: str) -> list[S]:
    """Convenience method for re.findall

    Args:
        cls (Type[T]): ValidatedStr subclass
        string (str): string to find patterns within

    Raises:
        ValidationError - If no regex pattern is defined.

    Returns:
        List of substrings matching pattern
    """
    cls.validate_regex_pattern()
    return [cls(match.group(0)) for match in regex_finditer(cls.regex_pattern, string)]

get_match_groups

get_match_groups()

Return the captured groups from matching the regex pattern against this string.

Returns:

Type Description
Sequence[Any]

A sequence of matched groups.

Raises:

Type Description
ValidationError

If no regex pattern is defined.

Source code in src/aibs_informatics_core/collections.py
329
330
331
332
333
334
335
336
337
338
339
340
341
342
def get_match_groups(self) -> Sequence[Any]:
    """Return the captured groups from matching the regex pattern against this string.

    Returns:
        A sequence of matched groups.

    Raises:
        ValidationError: If no regex pattern is defined.
    """
    self.validate_regex_pattern()
    # self.validate_regex_pattern() guarantees a match
    match = cast(Match[Any], regex_fullmatch(self.regex_pattern, self))
    # regex_pattern may not specify any groups in which case `match` will be None
    return match.groups()

has_regex_pattern classmethod

has_regex_pattern()

Check if this class has a user-defined regex pattern.

Returns:

Type Description
bool

True if a regex pattern was explicitly provided.

Source code in src/aibs_informatics_core/collections.py
451
452
453
454
455
456
457
458
@classmethod
def has_regex_pattern(cls) -> bool:
    """Check if this class has a user-defined regex pattern.

    Returns:
        True if a regex pattern was explicitly provided.
    """
    return cls.regex_pattern is not None and cls._regex_pattern_provided

is_prefixed classmethod

is_prefixed(string)

Check if the string starts with a match of the regex pattern.

Parameters:

Name Type Description Default
string str

The string to check.

required

Returns:

Type Description
bool

True if a match is found at the start of the string.

Source code in src/aibs_informatics_core/collections.py
377
378
379
380
381
382
383
384
385
386
387
@classmethod
def is_prefixed(cls, string: str) -> bool:
    """Check if the string starts with a match of the regex pattern.

    Args:
        string: The string to check.

    Returns:
        True if a match is found at the start of the string.
    """
    return cls.find_prefix(string) is not None

is_suffixed classmethod

is_suffixed(string)

Check if the string ends with a match of the regex pattern.

Parameters:

Name Type Description Default
string str

The string to check.

required

Returns:

Type Description
bool

True if a match is found at the end of the string.

Source code in src/aibs_informatics_core/collections.py
405
406
407
408
409
410
411
412
413
414
415
@classmethod
def is_suffixed(cls, string: str) -> bool:
    """Check if the string ends with a match of the regex pattern.

    Args:
        string: The string to check.

    Returns:
        True if a match is found at the end of the string.
    """
    return cls.find_suffix(string) is not None

is_valid classmethod

is_valid(value)

Check if a string is a valid instance of this validated string type.

Parameters:

Name Type Description Default
value str

The string to validate.

required

Returns:

Type Description
bool

True if the value passes validation, False otherwise.

Source code in src/aibs_informatics_core/collections.py
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
@classmethod
def is_valid(cls, value: str) -> bool:
    """Check if a string is a valid instance of this validated string type.

    Args:
        value: The string to validate.

    Returns:
        True if the value passes validation, False otherwise.
    """
    if isinstance(value, cls):
        return True
    try:
        cls(value)
        return True
    except ValidationError:
        return False

suball classmethod

suball(string, repl)

Convenience method for running re.sub on string. If no regex pattern is defined, then return original. Args: cls (Type[T]): The ValidatedStr subclass s (str): String to find/replace repl (Union[str, Callable[[Match], str]]): replacement method Returns: string with replacements

Source code in src/aibs_informatics_core/collections.py
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
@classmethod
def suball(cls: type[S], string: str, repl: str | Callable[[Match], str]) -> str:
    """Convenience method for running re.sub on string.
    If no regex pattern is defined, then return original.
    Args:
        cls (Type[T]): The ValidatedStr subclass
        s (str): String to find/replace
        repl (Union[str, Callable[[Match], str]]): replacement method
    Returns:
        string with replacements
    """
    if not cls.has_regex_pattern():
        logger.warning(f"{cls.__name__} has no regex pattern. No substitutions can be made.")
        return string
    return regex_sub(cls.regex_pattern, repl, string)

validate_regex_pattern classmethod

validate_regex_pattern(raise_error=True)

Validate that a regex pattern is defined for this class.

Parameters:

Name Type Description Default
raise_error bool

If True, raise an error when no pattern is defined. If False, log a warning instead.

True

Raises:

Type Description
ValidationError

If raise_error is True and no regex pattern is defined.

Source code in src/aibs_informatics_core/collections.py
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
@classmethod
def validate_regex_pattern(cls, raise_error: bool = True):
    """Validate that a regex pattern is defined for this class.

    Args:
        raise_error: If True, raise an error when no pattern is defined.
            If False, log a warning instead.

    Raises:
        ValidationError: If ``raise_error`` is True and no regex pattern is defined.
    """
    if not cls.has_regex_pattern():
        msg = f"{cls.__name__} does not define a Regex Pattern."
        if raise_error:
            raise ValidationError(msg)
        logger.warning(msg)