"""
templatest.utils
================
Additional tools for working with string variables.
"""
from __future__ import annotations
import random as _random
import string as _string
import typing as _t
from typing_extensions import Self
from ._abc import MutableStrSequence as _MutableStrSequence
ALPHA = tuple(_string.ascii_uppercase)
[docs]
class VarSeq(_MutableStrSequence):
"""Get string as instantiated name with the index as the suffix.
The instantiated object will always return the same string as per
the index. If index does not exist, strings will be generated up to
the selected index.
:param name: Name of the string to return.
:param suffix: Separator between str and index.
:example:
>>> from templatest.utils import VarSeq
>>> CONST = VarSeq("CONST")
>>> CONST[0]
'CONST_0'
>>> CONST
<VarSeq ['CONST_0']>
>>> CONST[1]
'CONST_1'
>>> CONST
<VarSeq ['CONST_0', 'CONST_1']>
>>> CONST[4]
'CONST_4'
>>> CONST
<VarSeq ['CONST_0', 'CONST_1', 'CONST_2', 'CONST_3', 'CONST_4']>
>>> name = VarSeq("package-name", suffix="-")
>>> name[0]
'package-name-0'
"""
def __init__(self, name: str, suffix: object = None) -> None:
super().__init__()
self._name = name
self._suffix = suffix if suffix is not None else "_"
def __setitem__(self, i: _t.Any, o: _t.Any) -> None:
raise NotImplementedError
def _string(self, index: int) -> str:
return f"{self._name}{self._suffix}{min(index, len(self))}"
[docs]
class VarSeqSuffix(VarSeq):
"""Get string as instantiated name with the index before suffix.
The instantiated object will always return the same string as per
the index. If index does not exist, strings will be generated up to
the selected index.
:param name: Name of the string to return.
:param suffix: Last string to return.
:param separator: Separator between str and index.
:example:
>>> from templatest.utils import VarSeqSuffix
>>> email = VarSeqSuffix("u", '@email.com')
>>> email[0]
'u_0@email.com'
>>> email
<VarSeqSuffix ['u_0@email.com']>
>>> email[2]
'u_2@email.com'
>>> email
<VarSeqSuffix ['u_0@email.com', 'u_1@email.com', 'u_2@email.com']>
"""
def __init__(
self, name: str, suffix: str, separator: object = None
) -> None:
super().__init__(name, suffix=separator)
self._new_suffix = suffix
def __setitem__(self, i: _t.Any, o: _t.Any) -> None:
raise NotImplementedError
def _string(self, index: int) -> str:
return f"{super()._string(index)}{self._new_suffix}"
[docs]
class RandStrLenSeq(_MutableStrSequence):
"""Get random string of varying length.
The instantiated object will always return the same string as per
the index. If index does not exist, strings will be generated up to
the selected index.
:param length: Length of string.
:example:
>>> from templatest.utils import RandStrLenSeq
>>> LEN_3 = RandStrLenSeq(3)
>>> len(LEN_3)
0
>>> str_1 = LEN_3[0]
>>> type(str_1)
<class 'str'>
>>> len(str_1)
3
>>> len(LEN_3)
1
>>> str_2 = LEN_3[1]
>>> len(LEN_3)
2
>>> assert str_1 != str_2
"""
def __setitem__(self, i: _t.Any, o: _t.Any) -> None:
raise NotImplementedError
def __init__(self, length: int) -> None:
super().__init__()
self._len = length
def _string(self, index: int) -> str:
return "".join(_random.choices(_string.ascii_lowercase, k=self._len))
[docs]
class VarPrefix:
"""Get string with prefix.
:param prefix: String to prefix attribute with.
:param slug: Separator between words.
:example:
>>> from templatest.utils import VarPrefix
>>> flag = VarPrefix("--")
>>> slugify = VarPrefix("--", slug="-")
>>> flag.src
'--src'
>>> flag.dst
'--dst'
>>> flag.exclude
'--exclude'
>>> flag
<VarPrefix ['--src', '--dst', '--exclude']>
>>> flag.force_remove
'--force_remove'
>>> slugify.force_remove
'--force-remove'
"""
def __init__(self, prefix: str, slug: str = "_") -> None:
self._prefix = prefix
self._slug = slug
def __repr__(self) -> str:
items = [
i
for i in self.__dict__.values()
if i not in (self._prefix, self._slug)
]
return f"<{self.__class__.__name__} {items}>"
def __getattr__(self, item: str) -> str:
while True:
try:
return super().__getattribute__(item)
except AttributeError:
self.__setattr__(
item, f"{self._prefix}{item.replace('_', self._slug)}"
)
[docs]
class PosArgs(_t.List[str]):
"""Get chain of strings as a list to represent positional arguments.
:example:
>>> from pathlib import Path
>>> from templatest.utils import PosArgs
>>> args = PosArgs('arg')
Traceback (most recent call last):
...
NotImplementedError: constructor cannot take args directly
>>> other_args = PosArgs()
>>> args = PosArgs(other_args)
Traceback (most recent call last):
...
NotImplementedError: constructor cannot take args directly
>>> args = PosArgs()
>>> args.path
['path']
>>> args("")
[]
>>> args("path")
['path']
>>> args.path.to
['path', 'to']
>>> args.path.to.another
['path', 'to', 'another']
>>> args.path.to.another.path
['path', 'to', 'another', 'path']
>>> args.path.to.another
['path', 'to', 'another']
>>> args.path.to
['path', 'to']
>>> args.path
['path']
>>> args.path.another
['path', 'another']
>>> args.path.another.new
['path', 'another', 'new']
>>> args.path.another.new.path
['path', 'another', 'new', 'path']
>>> args.src
['src']
>>> args.src.to
['src', 'to']
>>> args.src.to.another
['src', 'to', 'another']
>>> args.src.to.another.path
['src', 'to', 'another', 'path']
>>> args.src.to.another.path("")
['src', 'to', 'another', 'path']
>>> args.src.to.another.path("opt")
['src', 'to', 'another', 'path', 'opt']
>>> args.src.to.another.path("opt").another
['src', 'to', 'another', 'path', 'opt', 'another']
>>> path = Path("/tmp")
>>> args(path)
['/tmp']
:param args: Args passed to child classes, not to be used to
directly.
"""
__constructor__ = True
def __init__(self, args: _t.Any = None) -> None:
self._isparent = True
if isinstance(args, PosArgs) and not self.__constructor__:
self._isparent = False
super().__init__(args)
elif args is not None:
raise NotImplementedError("constructor cannot take args directly")
def _clear_parent(self) -> None:
if self._isparent:
self.clear()
def __getattr__(self, item: str) -> Self:
self._clear_parent()
self.append(item)
cls = self.__class__
cls.__constructor__ = False
return cls(self)
def __call__(self, arg: _t.Any) -> Self:
self._clear_parent()
return getattr(self, str(arg)) if arg else self