# pylint: disable=redefined-builtin
from typing import Optional, Tuple
[docs]def split(name, *, strict=True) -> Tuple[Optional[str], str]:
"""Split name to its type and path.
:param name: the name to split
:param strict: raise ValueError if type not specified.
If False, returns None for unspecified type.
:returns: tuple (type, path)
"""
components = name.split('@')
if len(components) == 2:
return tuple(components)
elif len(components) == 1 and strict is False:
return None, components[0]
elif len(components) > 2:
raise ValueError(f'name "{name}" contains to many @')
else:
raise ValueError(f'type expected in name "{name}")')
[docs]def update(name, **kwargs) -> str:
"""Update some part of ``name`` with something else.
:param name: the input name
:param path: new path (optional)
:param type: new type (optional)
"""
type, path = split(name, strict=False)
if 'path' in kwargs:
path = kwargs.pop('path')
if 'type' in kwargs:
type = kwargs.pop('type')
return '@'.join([c for c in (type, path) if c])
[docs]def match(name, pattern, *, type=None) -> Optional[str]:
"""Match the name against a pattern.
:param name: the name to match
:param pattern: the name pattern
:param type: optional type to match against (overrides the one in pattern)
:returns: ``name`` on match, ``None`` otherwise
"""
# TODO: implement wildcard
ptype, ppath = split(pattern, strict=False)
ptype = type or ptype
ntype, npath = split(name, strict=ptype is not None)
if (ntype == ptype or ptype is None) and ppath == npath:
return name
else:
return None
[docs]def search(names, pattern, *, type=None):
"""Yield all names, that matched given pattern."""
for name in names:
m = match(name, pattern, type=type)
if m:
yield m