Skip to content

Interface

netutils.interface

Functions for working with interface.

CCInt

Bases: CharacterClass

Ints must be sorted canonically because '11' < '5'.

Source code in netutils/interface.py
class CCInt(CharacterClass):
    """Ints must be sorted canonically because '11' < '5'."""

    def __lt__(self, other: "CharacterClass") -> bool:  # noqa: D105
        return self.weight < other.weight or int(self.val) < int(other.val)

    def __repr__(self) -> str:  # noqa: D105
        return f"CCInt({self.val}, {self.terminal})"

    @property
    def weight(self) -> int:  # noqa: D107,D102
        return 20

CCSeparator

Bases: CharacterClass

Separators require custom logic, so we sort them by arbitrary weight.

Source code in netutils/interface.py
class CCSeparator(CharacterClass):
    """Separators require custom logic, so we sort them by arbitrary weight."""

    weights: t.Dict[str, int] = {".": 10, "/": 20}

    def __lt__(self, other: "CharacterClass") -> bool:  # noqa: D105
        return self.weight < other.weight or self.weights.get(self.val, 0) < self.weights.get(other.val, 0)

    def __repr__(self) -> str:  # noqa: D105
        return f'CCSeparator("{self.val}", {self.terminal})'

    @property
    def weight(self) -> int:  # noqa: D102
        return 30

CCString

Bases: CharacterClass

Strings are sorted lexicographically.

Source code in netutils/interface.py
class CCString(CharacterClass):
    """Strings are sorted lexicographically."""

    def __lt__(self, other: "CharacterClass") -> bool:  # noqa: D105
        return self.weight < other.weight or self.val < other.val

    def __repr__(self) -> str:  # noqa: D105
        return f'CCString("{self.val}", {self.terminal})'

    @property
    def weight(self) -> int:  # noqa: D107,D102
        return 10

CharacterClass

Bases: ABC

CharacterClass embodies the state needed to sort interfaces.

Source code in netutils/interface.py
@total_ordering  # type: ignore
class CharacterClass(ABC):
    """CharacterClass embodies the state needed to sort interfaces."""

    def __init__(self, val: str, terminal: bool = False) -> None:  # noqa: D107
        self.val = val
        self._terminal = terminal
        super().__init__()

    @abstractmethod
    def __lt__(self, other: "CharacterClass") -> bool:  # noqa: D105
        ...

    def __eq__(self, other: t.Any) -> t.Any:  # noqa: D105
        return self.weight == other.weight and self.val == other.val

    @property
    @abstractmethod
    def weight(self) -> int:
        """Weight property."""

    @property
    def terminal(self) -> bool:
        """Flag whether a node is terminal."""
        return self._terminal

    @terminal.setter
    def terminal(self, val: bool) -> None:
        """This is a one-way switch to prevent overwriting a terminal node."""
        if not self._terminal:
            self._terminal = val

    def __str__(self) -> str:  # noqa: D105
        return str(self.val)

    def __hash__(self) -> int:  # noqa: D105
        return self.val.__hash__()

terminal: bool writable property

Flag whether a node is terminal.

weight: int abstractmethod property

Weight property.

abbreviated_interface_name(interface, addl_name_map=None, addl_reverse_map=None, verify=False)

Function to return an abbreviated representation of the interface name.

Parameters:

Name Type Description Default
interface str

The interface you are attempting to shorten.

required
addl_name_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.

None
addl_reverse_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the abbreviated mapping. Defaults to None.

None
verify bool

Whether or not to verify the interface matches a known interface standard. Defaults to False.

False

Returns:

Type Description
str

The name of the interface in the abbreviated form.

Examples:

>>> abbreviated_interface_name("GigabitEthernet1/0/1")
'Gi1/0/1'
>>> abbreviated_interface_name("Eth1")
'Et1'
>>>
Source code in netutils/interface.py
def abbreviated_interface_name(
    interface: str,
    addl_name_map: t.Optional[t.Dict[str, str]] = None,
    addl_reverse_map: t.Optional[t.Dict[str, str]] = None,
    verify: bool = False,
) -> str:
    """Function to return an abbreviated representation of the interface name.

    Args:
        interface: The interface you are attempting to shorten.
        addl_name_map: A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.
        addl_reverse_map: A dict containing key/value pairs that updates the abbreviated mapping. Defaults to None.
        verify: Whether or not to verify the interface matches a known interface standard. Defaults to False.

    Returns:
        The name of the interface in the abbreviated form.

    Examples:
        >>> abbreviated_interface_name("GigabitEthernet1/0/1")
        'Gi1/0/1'
        >>> abbreviated_interface_name("Eth1")
        'Et1'
        >>>
    """
    name_map = {}
    name_map.update(BASE_INTERFACES)
    interface_type, interface_number = split_interface(interface)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)

    rev_name_map = {}
    rev_name_map.update(REVERSE_MAPPING)

    if isinstance(addl_reverse_map, dict):
        rev_name_map.update(addl_reverse_map)

    # Try to ensure canonical type.
    canonical_type = name_map.get(interface_type, None)
    if not canonical_type:
        canonical_type = interface_type

    try:
        abbreviated_name = rev_name_map[canonical_type] + str(interface_number)
        return abbreviated_name

    except KeyError:
        pass

    if verify:
        raise ValueError(f"Verify interface on and no match found for {interface}")
    # If abbreviated name lookup fails, return original name
    return interface

abbreviated_interface_name_list(interfaces, addl_name_map=None, addl_reverse_map=None, verify=False, order=None, reverse=False)

Function to return a list of interface's abbreviated name.

Parameters:

Name Type Description Default
interfaces t.List[str]

List of interface names you are attempting to abbreviate.

required
addl_name_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.

None
addl_reverse_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the abbreviated mapping. Defaults to None.

None
verify bool

Whether or not to verify the interface matches a known interface standard. Defaults to False.

False
order t.Optional[str]

Determines what order the list of interfaces should be returned in. Defaults to None.

None
reverse bool

Specify if the order of the list should be reversed when setting an order. Defaults to None.

False

Returns:

Type Description
t.List[str]

List of the interfaces in their abbreviated form.

Raises:

Type Description
ValueError

Raised if any interface name in list cannot be converted to its abbreviated form and verify parameter is set to true.

Examples:

>>> from netutils.interface import abbreviated_interface_name_list
>>> abbreviated_interface_name_list(["GigabitEthernet1/0/1", "GigabitEthernet1/0/2", "Ethernet1"])
['Gi1/0/1', 'Gi1/0/2', 'Et1']
>>> abbreviated_interface_name_list(['GigabitEthernet1/0/1', 'Port-channel40', 'Loopback10'])
['Gi1/0/1', 'Po40', 'Lo10']
>>>
Source code in netutils/interface.py
def abbreviated_interface_name_list(  # pylint: disable=R0913, R0914
    interfaces: t.List[str],
    addl_name_map: t.Optional[t.Dict[str, str]] = None,
    addl_reverse_map: t.Optional[t.Dict[str, str]] = None,
    verify: bool = False,
    order: t.Optional[str] = None,
    reverse: bool = False,
) -> t.List[str]:
    """Function to return a list of interface's abbreviated name.

    Args:
        interfaces: List of interface names you are attempting to abbreviate.
        addl_name_map: A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.
        addl_reverse_map: A dict containing key/value pairs that updates the abbreviated mapping. Defaults to None.
        verify: Whether or not to verify the interface matches a known interface standard. Defaults to False.
        order: Determines what order the list of interfaces should be returned in. Defaults to None.
        reverse: Specify if the order of the list should be reversed when setting an order. Defaults to None.

    Returns:
        List of the interfaces in their abbreviated form.

    Raises:
        ValueError: Raised if any interface name in list cannot be converted to its abbreviated form and verify parameter is set to true.

    Examples:
        >>> from netutils.interface import abbreviated_interface_name_list
        >>> abbreviated_interface_name_list(["GigabitEthernet1/0/1", "GigabitEthernet1/0/2", "Ethernet1"])
        ['Gi1/0/1', 'Gi1/0/2', 'Et1']
        >>> abbreviated_interface_name_list(['GigabitEthernet1/0/1', 'Port-channel40', 'Loopback10'])
        ['Gi1/0/1', 'Po40', 'Lo10']
        >>>
    """
    name_map = {}
    name_map.update(BASE_INTERFACES)
    abbreviated_interface_list = []
    no_match_list = []

    if reverse and not order:
        raise ValueError("Order must be set to use reverse.")

    if order:
        _check_order_option_exists(order)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)

    rev_name_map = {}
    rev_name_map.update(REVERSE_MAPPING)

    if isinstance(addl_reverse_map, dict):
        rev_name_map.update(addl_reverse_map)

    for interface in interfaces:
        interface_type, interface_number = split_interface(interface)
        # Try to ensure canonical type.
        canonical_type = name_map.get(interface_type, None)
        if not canonical_type:
            canonical_type = interface_type

        try:
            abbreviated_name = rev_name_map[canonical_type] + str(interface_number)
            abbreviated_interface_list.append(abbreviated_name)
        except KeyError:
            abbreviated_interface_list.append(interface)
            no_match_list.append(interface)

    if verify:
        no_match_string = ", ".join(no_match_list)
        raise ValueError(f"Verify interface on and no match found for {no_match_string}")

    if order:
        order_function = INTERFACE_LIST_ORDERING_OPTIONS.get(order, None)
        if not order_function:
            raise ValueError(f"No order function available called {order}")
        abbreviated_interface_list = order_function(abbreviated_interface_list)

    if reverse:
        abbreviated_interface_list = _reverse_list(abbreviated_interface_list)

    return abbreviated_interface_list

canonical_interface_name(interface, addl_name_map=None, verify=False)

Function to return an interface's canonical name (fully expanded name).

Use of explicit matches used to indicate a clear understanding on any potential match. Regex and other looser matching methods were not implemented to avoid false positive matches. As an example, it would make sense to do "[P|p][O|o]" which would incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not easily troubleshot, found, or known.

Parameters:

Name Type Description Default
interface str

The interface you are attempting to expand.

required
addl_name_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.

None
verify bool

Whether or not to verify the interface matches a known interface standard. Defaults to False.

False

Returns:

Type Description
str

The name of the interface in the long form.

Examples:

>>> from netutils.interface import canonical_interface_name
>>> canonical_interface_name("Gi1/0/1")
'GigabitEthernet1/0/1'
>>> canonical_interface_name("Eth1")
'Ethernet1'
>>>
Source code in netutils/interface.py
def canonical_interface_name(
    interface: str, addl_name_map: t.Optional[t.Dict[str, str]] = None, verify: bool = False
) -> str:
    """Function to return an interface's canonical name (fully expanded name).

    Use of explicit matches used to indicate a clear understanding on any potential
    match. Regex and other looser matching methods were not implemented to avoid false
    positive matches. As an example, it would make sense to do "[P|p][O|o]" which would
    incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not
    easily troubleshot, found, or known.

    Args:
        interface: The interface you are attempting to expand.
        addl_name_map: A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.
        verify: Whether or not to verify the interface matches a known interface standard. Defaults to False.

    Returns:
        The name of the interface in the long form.

    Examples:
        >>> from netutils.interface import canonical_interface_name
        >>> canonical_interface_name("Gi1/0/1")
        'GigabitEthernet1/0/1'
        >>> canonical_interface_name("Eth1")
        'Ethernet1'
        >>>
    """
    name_map = {}
    name_map.update(BASE_INTERFACES)
    interface_type, interface_number = split_interface(interface)

    if isinstance(addl_name_map, dict):
        name_map.update(addl_name_map)
    # check in dict for mapping
    if interface_type in name_map:
        long_int = name_map[interface_type]
        return long_int + str(interface_number)
    if verify:
        raise ValueError(f"Verify interface on and no match found for {interface}")
    # if nothing matched, return the original name
    return interface

canonical_interface_name_list(interfaces, addl_name_map=None, verify=False, order=None, reverse=False)

Function to return a list of interface's canonical name (fully expanded name).

Use of explicit matches used to indicate a clear understanding on any potential match. Regex and other looser matching methods were not implmented to avoid false positive matches. As an example, it would make sense to do "[P|p][O|o]" which would incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not easily troubleshot, found, or known.

Parameters:

Name Type Description Default
interfaces t.List[str]

List of interfaces you are attempting to expand.

required
addl_name_map t.Optional[t.Dict[str, str]]

A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.

None
verify bool

Whether or not to verify the interface matches a known interface standard. Defaults to False.

False
order t.Optional[str]

Determines what order the list of interfaces should be returned in. Defaults to None.

None
reverse bool

Specify if the order of the list should be reversed when setting an order. Defaults to None.

False

Returns:

Type Description
t.List[str]

List of the interfaces in their long form.

Raises:

Type Description
ValueError

Raised if any interface name in list cannot be converted to its long form and verify parameter is set to true.

Examples:

>>> from netutils.interface import canonical_interface_name_list
>>> canonical_interface_name_list(["Gi1/0/1", "Gi1/0/2", "Eth1"])
['GigabitEthernet1/0/1', 'GigabitEthernet1/0/2', 'Ethernet1']
>>> canonical_interface_name_list(["Gi1/0/1", "Po40", "Lo10"])
['GigabitEthernet1/0/1', 'Port-channel40', 'Loopback10']
>>>
Source code in netutils/interface.py
def canonical_interface_name_list(
    interfaces: t.List[str],
    addl_name_map: t.Optional[t.Dict[str, str]] = None,
    verify: bool = False,
    order: t.Optional[str] = None,
    reverse: bool = False,
) -> t.List[str]:
    """Function to return a list of interface's canonical name (fully expanded name).

    Use of explicit matches used to indicate a clear understanding on any potential
    match. Regex and other looser matching methods were not implmented to avoid false
    positive matches. As an example, it would make sense to do "[P|p][O|o]" which would
    incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not
    easily troubleshot, found, or known.

    Args:
        interfaces: List of interfaces you are attempting to expand.
        addl_name_map: A dict containing key/value pairs that updates the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs {"Po": "Port-Channel"}. Defaults to None.
        verify: Whether or not to verify the interface matches a known interface standard. Defaults to False.
        order: Determines what order the list of interfaces should be returned in. Defaults to None.
        reverse: Specify if the order of the list should be reversed when setting an order. Defaults to None.

    Returns:
        List of the interfaces in their long form.

    Raises:
        ValueError: Raised if any interface name in list cannot be converted to its long form and verify parameter is set to true.

    Examples:
        >>> from netutils.interface import canonical_interface_name_list
        >>> canonical_interface_name_list(["Gi1/0/1", "Gi1/0/2", "Eth1"])
        ['GigabitEthernet1/0/1', 'GigabitEthernet1/0/2', 'Ethernet1']
        >>> canonical_interface_name_list(["Gi1/0/1", "Po40", "Lo10"])
        ['GigabitEthernet1/0/1', 'Port-channel40', 'Loopback10']
        >>>
    """
    name_map = {}
    name_map.update(BASE_INTERFACES)
    canonical_interface_list = []
    no_match_list = []

    if reverse and not order:
        raise ValueError("Order must be set to use reverse.")

    if order:
        _check_order_option_exists(order)

    for interface in interfaces:
        canonical_interface_list.append(canonical_interface_name(interface, addl_name_map=addl_name_map))
        if interface == canonical_interface_name(interface):
            no_match_list.append(interface)

    if verify:
        no_match_string = ", ".join(no_match_list)
        raise ValueError(f"Verify interface on and no match found for {no_match_string}")

    if order:
        order_function = INTERFACE_LIST_ORDERING_OPTIONS.get(order, None)
        if not order_function:
            raise ValueError(f"No order function available called {order}")
        canonical_interface_list = order_function(canonical_interface_list)

    if reverse:
        canonical_interface_list = _reverse_list(canonical_interface_list)

    return canonical_interface_list

interface_range_compress(interface_list)

Function which takes interfaces and return interface ranges.

Whitespace and special characters are ignored in the input. Input must contain only interfaces, there is no check against correct interface names! Also interface names must use the same abbreviation! E.g. Gi =! GigabitEthernet

Examples:

>>> interface_range_compress(["Gi1/0/1", "Gi1/0/2", "Gi1/0/3", "Gi1/0/5"])
['Gi1/0/1-3', 'Gi1/0/5']
>>> interface_range_compress(["Gi0/1", "Gi0/2", "Gi0/4", "Gi1/0", "Gi1/1"])
['Gi0/1-2', 'Gi0/4', 'Gi1/0-1']

Parameters:

Name Type Description Default
interface_list t.List[str]

list of interfaces

required

Returns:

Type Description
t.List[str]

list of interface ranges

Source code in netutils/interface.py
def interface_range_compress(interface_list: t.List[str]) -> t.List[str]:
    """Function which takes interfaces and return interface ranges.

    Whitespace and special characters are ignored in the input. Input must contain only interfaces,
    there is no check against correct interface names! Also interface names must use the same abbreviation!
    E.g. Gi =! GigabitEthernet

    Examples:
        >>> interface_range_compress(["Gi1/0/1", "Gi1/0/2", "Gi1/0/3", "Gi1/0/5"])
        ['Gi1/0/1-3', 'Gi1/0/5']
        >>> interface_range_compress(["Gi0/1", "Gi0/2", "Gi0/4", "Gi1/0", "Gi1/1"])
        ['Gi0/1-2', 'Gi0/4', 'Gi1/0-1']

    Args:
        interface_list: list of interfaces

    Returns:
        list of interface ranges
    """
    result_dict: t.Dict[str, t.List[int]] = {}
    final_result_list = []
    sorted_ints = [_split_interface_tuple(x) for x in sort_interface_list(interface_list)]
    if not sorted_ints:
        return []
    current_match = sorted_ints[0][0:-1]
    for interface in sorted_ints:
        if interface[0:-1] == current_match:
            module = "".join([x.val for x in current_match])
            if result_dict.get(module):
                result_dict[module] += [int(interface[-1].val)]
            else:
                result_dict[module] = [int(interface[-1].val)]
        else:
            current_match = interface[0:-1]
            result_dict["".join([x.val for x in current_match])] = [int(interface[-1].val)]
    for module, ports in result_dict.items():
        # find ranges in this port list
        ranges = _ranges_in_list(ports)
        # assemble module and port ranges
        for range_group in ranges:
            if len(range_group) > 1:
                final_result_list.append(f"{module}{range_group[0]}-{range_group[-1]}")
            else:
                final_result_list.append(f"{module}{range_group[0]}")
    return final_result_list

interface_range_expansion(interface_pattern)

Expand interface pattern into a list of interfaces.

Parameters:

Name Type Description Default
interface_pattern str

The string pattern that will be parsed to create the list of interfaces.

required

Returns:

Type Description
t.List[str]

Contains the expanded list of interfaces.

Examples:

>>> from netutils.interface import interface_range_expansion
>>> interface_range_expansion("Gi0/[1-4]")
['Gi0/1', 'Gi0/2', 'Gi0/3', 'Gi0/4']
>>> interface_range_expansion("FastEthernet[1-2]/0/[10-15]")
['FastEthernet1/0/10', 'FastEthernet1/0/11', 'FastEthernet1/0/12', 'FastEthernet1/0/13', 'FastEthernet1/0/14', 'FastEthernet1/0/15', 'FastEthernet2/0/10', 'FastEthernet2/0/11', 'FastEthernet2/0/12', 'FastEthernet2/0/13', 'FastEthernet2/0/14', 'FastEthernet2/0/15']
Source code in netutils/interface.py
def interface_range_expansion(interface_pattern: str) -> t.List[str]:
    """Expand interface pattern into a list of interfaces.

    Args:
        interface_pattern: The string pattern that will be parsed to create the list of interfaces.

    Returns:
        Contains the expanded list of interfaces.

    Examples:
        >>> from netutils.interface import interface_range_expansion
        >>> interface_range_expansion("Gi0/[1-4]")
        ['Gi0/1', 'Gi0/2', 'Gi0/3', 'Gi0/4']
        >>> interface_range_expansion("FastEthernet[1-2]/0/[10-15]")
        ['FastEthernet1/0/10', 'FastEthernet1/0/11', 'FastEthernet1/0/12', 'FastEthernet1/0/13', 'FastEthernet1/0/14', 'FastEthernet1/0/15', 'FastEthernet2/0/10', 'FastEthernet2/0/11', 'FastEthernet2/0/12', 'FastEthernet2/0/13', 'FastEthernet2/0/14', 'FastEthernet2/0/15']
    """

    def _range_expand(regex_match: str) -> t.List[int]:
        number_range: t.List[int] = []
        for value in regex_match.split(","):
            if "-" in value[1:]:
                first_number, second_number = value[1:].split("-", 1)
                number_range += range(int(value[0] + first_number), int(second_number) + 1)
            else:
                number_range.append(int(value))
        return number_range

    def _pairwise(interface_constant: t.List[int]) -> t.List[t.Tuple[int, int]]:
        interface_constant_it = iter(interface_constant)
        return list(zip(interface_constant_it, interface_constant_it))

    match_pattern = r"(\[(?:\d|,|-)+\])"
    re_compiled = re.compile(match_pattern)
    # Use case when sent without an actual range, e.g. Gi1
    if not re_compiled.search(interface_pattern):
        return [interface_pattern]

    cartesian_list = []
    interface_constant = [0]
    for match in re_compiled.finditer(interface_pattern):
        interface_constant.append(match.start())
        interface_constant.append(match.end())
        cartesian_list.append(_range_expand(match.group()[1:-1]))

    interface_constant_out = _pairwise(interface_constant)
    expanded_interfaces = []
    for element in itertools.product(*cartesian_list):
        current_interface = ""
        for count, item in enumerate(interface_constant_out):
            current_interface += interface_pattern[item[0] : item[1]]  # noqa: E203
            current_interface += str(element[count])
        expanded_interfaces.append(current_interface)

    return expanded_interfaces

sort_interface_list(interfaces)

This function sorts and cleans a list of interfaces.

Note that a new list of interfaces is returned and that duplicates nodes are removed.

Parameters:

Name Type Description Default
interfaces list[str]

A list of interfaces to be sorted. The input list is not mutated by this function.

required

Returns:

Type Description
t.List[str]

list[str]: A new sorted, unique list elements from the input.

Examples:

>>> sort_interface_list(["Gi1/0/1", "Gi1/0/3", "Gi1/0/3.100", "Gi1/0/2", "Gi1/0/2.50", "Gi2/0/2", "Po40", "Po160", "Lo10"])
['Gi1/0/1', 'Gi1/0/2', 'Gi1/0/2.50', 'Gi1/0/3', 'Gi1/0/3.100', 'Gi2/0/2', 'Lo10', 'Po40', 'Po160']
>>> sort_interface_list(['GigabitEthernet1/0/1', 'GigabitEthernet1/0/3', 'GigabitEthernet1/0/2', "GigabitEthernett3/0/5", 'GigabitEthernet3/0/7', 'GigabitEthernet2/0/8.5',  'Port-channel40', 'Vlan20', 'Loopback10'])
['GigabitEthernet1/0/1', 'GigabitEthernet1/0/2', 'GigabitEthernet1/0/3', 'GigabitEthernet2/0/8.5', 'GigabitEthernet3/0/7', 'GigabitEthernett3/0/5', 'Loopback10', 'Port-channel40', 'Vlan20']
Source code in netutils/interface.py
def sort_interface_list(interfaces: t.List[str]) -> t.List[str]:
    """This function sorts and cleans a list of interfaces.

    Note that a new list of interfaces is returned and that duplicates
    nodes are removed.

    Args:
        interfaces (list[str]): A list of interfaces to be sorted.  The input list is not mutated by this function.

    Returns:
        list[str]: A **new** sorted, unique list elements from the input.

    Examples:
        >>> sort_interface_list(["Gi1/0/1", "Gi1/0/3", "Gi1/0/3.100", "Gi1/0/2", "Gi1/0/2.50", "Gi2/0/2", "Po40", "Po160", "Lo10"])
        ['Gi1/0/1', 'Gi1/0/2', 'Gi1/0/2.50', 'Gi1/0/3', 'Gi1/0/3.100', 'Gi2/0/2', 'Lo10', 'Po40', 'Po160']
        >>> sort_interface_list(['GigabitEthernet1/0/1', 'GigabitEthernet1/0/3', 'GigabitEthernet1/0/2', "GigabitEthernett3/0/5", 'GigabitEthernet3/0/7', 'GigabitEthernet2/0/8.5',  'Port-channel40', 'Vlan20', 'Loopback10'])
        ['GigabitEthernet1/0/1', 'GigabitEthernet1/0/2', 'GigabitEthernet1/0/3', 'GigabitEthernet2/0/8.5', 'GigabitEthernet3/0/7', 'GigabitEthernett3/0/5', 'Loopback10', 'Port-channel40', 'Vlan20']
    """
    root: t.Dict[CharacterClass, t.Any] = {}
    for ifname in interfaces:
        _insert_nodes(root, _split_interface_tuple(ifname))
    return list(_iter_tree(root, []))

split_interface(interface)

Split an interface name based on first digit, slash, or space match.

Parameters:

Name Type Description Default
interface str

The interface you are attempting to split.

required

Returns:

Type Description
t.Tuple[str, str]

The split between the name of the interface the value.

Examples:

>>> from netutils.interface import split_interface
>>> split_interface("GigabitEthernet1/0/1")
('GigabitEthernet', '1/0/1')
>>> split_interface("Eth1")
('Eth', '1')
>>>
Source code in netutils/interface.py
def split_interface(interface: str) -> t.Tuple[str, str]:
    """Split an interface name based on first digit, slash, or space match.

    Args:
        interface: The interface you are attempting to split.

    Returns:
        The split between the name of the interface the value.

    Examples:
        >>> from netutils.interface import split_interface
        >>> split_interface("GigabitEthernet1/0/1")
        ('GigabitEthernet', '1/0/1')
        >>> split_interface("Eth1")
        ('Eth', '1')
        >>>
    """
    head = interface.rstrip(r"/\0123456789. ")
    tail = interface[len(head) :].lstrip()  # noqa: E203
    return (head, tail)