Spaces:
Paused
Paused
| import re | |
| from abc import ABCMeta, abstractmethod | |
| from typing import Iterator, Mapping, Optional, Pattern | |
| _posix_variable: Pattern[str] = re.compile( | |
| r""" | |
| \$\{ | |
| (?P<name>[^\}:]*) | |
| (?::- | |
| (?P<default>[^\}]*) | |
| )? | |
| \} | |
| """, | |
| re.VERBOSE, | |
| ) | |
| class Atom(metaclass=ABCMeta): | |
| def __ne__(self, other: object) -> bool: | |
| result = self.__eq__(other) | |
| if result is NotImplemented: | |
| return NotImplemented | |
| return not result | |
| def resolve(self, env: Mapping[str, Optional[str]]) -> str: ... | |
| class Literal(Atom): | |
| def __init__(self, value: str) -> None: | |
| self.value = value | |
| def __repr__(self) -> str: | |
| return f"Literal(value={self.value})" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, self.__class__): | |
| return NotImplemented | |
| return self.value == other.value | |
| def __hash__(self) -> int: | |
| return hash((self.__class__, self.value)) | |
| def resolve(self, env: Mapping[str, Optional[str]]) -> str: | |
| return self.value | |
| class Variable(Atom): | |
| def __init__(self, name: str, default: Optional[str]) -> None: | |
| self.name = name | |
| self.default = default | |
| def __repr__(self) -> str: | |
| return f"Variable(name={self.name}, default={self.default})" | |
| def __eq__(self, other: object) -> bool: | |
| if not isinstance(other, self.__class__): | |
| return NotImplemented | |
| return (self.name, self.default) == (other.name, other.default) | |
| def __hash__(self) -> int: | |
| return hash((self.__class__, self.name, self.default)) | |
| def resolve(self, env: Mapping[str, Optional[str]]) -> str: | |
| default = self.default if self.default is not None else "" | |
| result = env.get(self.name, default) | |
| return result if result is not None else "" | |
| def parse_variables(value: str) -> Iterator[Atom]: | |
| cursor = 0 | |
| for match in _posix_variable.finditer(value): | |
| (start, end) = match.span() | |
| name = match["name"] | |
| default = match["default"] | |
| if start > cursor: | |
| yield Literal(value=value[cursor:start]) | |
| yield Variable(name=name, default=default) | |
| cursor = end | |
| length = len(value) | |
| if cursor < length: | |
| yield Literal(value=value[cursor:length]) | |